- Re-cloned zonemaster-ldns with --recurse-submodules so the bundled ldns C library source (including Changelog and configure.ac) is present - Added autoconf, automake, libtool to Dockerfile.backend ldns-build stage so libtoolize + autoreconf can generate ldns/configure during make Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
194 lines
5.0 KiB
C
194 lines
5.0 KiB
C
#include "config.h"
|
|
#include "process.h"
|
|
#include "zones.h"
|
|
#include "zinfo.h"
|
|
#include "server.h"
|
|
|
|
ldns_pkt_rcode
|
|
process_pkts(struct socket_service* sv, ldns_pkt* q, ldns_pkt* r,
|
|
struct zones_t* zones)
|
|
{
|
|
if(ldns_pkt_edns(q)) {
|
|
ldns_pkt_set_edns_do(r, ldns_pkt_edns_do(q));
|
|
ldns_pkt_set_edns_udp_size(r, 4096);
|
|
}
|
|
if(ldns_pkt_tsig(q)) {
|
|
printf("tsig todo\n");
|
|
}
|
|
|
|
switch(ldns_pkt_get_opcode(q)) {
|
|
case LDNS_PACKET_QUERY:
|
|
return process_pkt_query(sv, q, r, zones);
|
|
case LDNS_PACKET_NOTIFY:
|
|
return process_pkt_notify(sv, q, r, zones);
|
|
default:
|
|
return LDNS_RCODE_NOTIMPL;
|
|
}
|
|
}
|
|
|
|
ldns_pkt_rcode
|
|
process_pkt_notify(struct socket_service* sv, ldns_pkt* q, ldns_pkt* r,
|
|
struct zones_t* zones)
|
|
{
|
|
(void)(sv); (void)(q); (void)(r); (void)zones;
|
|
return LDNS_RCODE_NOTIMPL;
|
|
}
|
|
|
|
ldns_pkt_rcode
|
|
process_pkt_query(struct socket_service* sv, ldns_pkt* q, ldns_pkt* r,
|
|
struct zones_t* zones)
|
|
{
|
|
ldns_rr *qrr;
|
|
struct zone_entry_t* entry ;
|
|
|
|
if(ldns_pkt_qdcount(q) != 1) /* one question */
|
|
return LDNS_RCODE_FORMERR;
|
|
qrr = ldns_rr_list_rr(ldns_pkt_question(q), 0);
|
|
|
|
/* find query name zone */
|
|
entry = zones_find_rdf(zones, ldns_rr_owner(qrr),
|
|
ldns_rr_get_class(qrr));
|
|
if(!entry) {
|
|
return LDNS_RCODE_REFUSED;
|
|
}
|
|
printf("Got zone for q. %s\n", entry->zstr);
|
|
|
|
/* copy question */
|
|
ldns_pkt_push_rr(r, LDNS_SECTION_QUESTION, ldns_rr_clone(qrr));
|
|
|
|
switch(ldns_rr_get_type(qrr)) {
|
|
case LDNS_RR_TYPE_ANY:
|
|
ldns_pkt_set_aa(r, false);
|
|
case LDNS_RR_TYPE_SOA:
|
|
return process_pkt_soa(sv, q, r, entry);
|
|
case LDNS_RR_TYPE_AXFR:
|
|
return process_pkt_axfr(sv, entry);
|
|
case LDNS_RR_TYPE_IXFR:
|
|
return process_pkt_ixfr(sv, q, r, entry);
|
|
default:
|
|
return LDNS_RCODE_REFUSED;
|
|
}
|
|
}
|
|
|
|
ldns_pkt_rcode
|
|
process_pkt_soa(struct socket_service* sv, ldns_pkt* q, ldns_pkt* r,
|
|
struct zone_entry_t* entry)
|
|
{
|
|
ldns_rr_list* soa = ldns_rr_list_clone(entry->zinfo->last_soa);
|
|
(void)sv; (void)q;
|
|
if(!soa) /* have zone but not soa; no data for zone */
|
|
return LDNS_RCODE_SERVFAIL;
|
|
/* put the answer into the packet */
|
|
ldns_pkt_push_rr_list(r, LDNS_SECTION_ANSWER, soa);
|
|
return LDNS_RCODE_NOERROR;
|
|
}
|
|
|
|
ldns_pkt_rcode
|
|
process_pkt_ixfr(struct socket_service* sv, ldns_pkt* q, ldns_pkt* r,
|
|
struct zone_entry_t* entry)
|
|
{
|
|
uint32_t serial_from, serial_to;
|
|
ldns_rr_list *rr_add=0, *rr_remove=0;
|
|
ldns_rr *soa_from=0;
|
|
ldns_rr_list *soa_to=0;
|
|
|
|
if(ldns_pkt_nscount(q) != 1 ||
|
|
ldns_rr_get_type(ldns_rr_list_rr(ldns_pkt_authority(q), 0))
|
|
!= LDNS_RR_TYPE_SOA) {
|
|
printf("ixfr without serial indication\n");
|
|
return LDNS_RCODE_FORMERR;
|
|
}
|
|
if(!entry->zinfo->is_present) {
|
|
printf("ixfr request for zone without data\n");
|
|
return LDNS_RCODE_SERVFAIL;
|
|
}
|
|
|
|
serial_to = entry->zinfo->last_serial;
|
|
serial_from = ldns_rdf2native_int32(ldns_rr_rdf(
|
|
ldns_rr_list_rr(ldns_pkt_authority(q), 0), 2));
|
|
|
|
soa_to = ldns_rr_list_clone(entry->zinfo->last_soa);
|
|
if(!soa_to) {
|
|
return LDNS_RCODE_SERVFAIL;
|
|
}
|
|
|
|
if(serial_to == serial_from) {
|
|
printf("ixfr request for latest version\n");
|
|
ldns_pkt_push_rr_list(r, LDNS_SECTION_ANSWER, soa_to);
|
|
return LDNS_RCODE_NOERROR;
|
|
}
|
|
|
|
/* if UDP - reply with SOA and TC indication */
|
|
if(!sv->is_tcp) {
|
|
ldns_pkt_set_tc(r, true);
|
|
ldns_pkt_push_rr_list(r, LDNS_SECTION_ANSWER, soa_to);
|
|
return LDNS_RCODE_NOERROR;
|
|
}
|
|
|
|
zinfo_get_zone_diff(entry, serial_from, serial_to, &rr_remove,
|
|
&rr_add, &soa_from, &soa_to);
|
|
if(!rr_remove || !rr_add || !soa_from || !soa_to) {
|
|
printf("get_zone_diff failed, fallback to AXFR\n");
|
|
return process_pkt_axfr(sv, entry);
|
|
}
|
|
|
|
/* create rrlist for reply */
|
|
if(sv->reply)
|
|
ldns_rr_list_deep_free(sv->reply);
|
|
sv->reply = ldns_rr_list_new();
|
|
if(!sv->reply) {
|
|
printf("out of memory\n");
|
|
return LDNS_RCODE_SERVFAIL;
|
|
}
|
|
/* a 'condensed' IXFR zone transfer (see RFC 1995) */
|
|
ldns_rr_list_push_rr(sv->reply, ldns_rr_clone(soa_to));
|
|
ldns_rr_list_push_rr(sv->reply, soa_from);
|
|
/* deletes */
|
|
ldns_rr_list_cat(sv->reply, rr_remove);
|
|
ldns_rr_list_push_rr(sv->reply, ldns_rr_clone(soa_to));
|
|
/* adds */
|
|
ldns_rr_list_cat(sv->reply, rr_add);
|
|
ldns_rr_list_push_rr(sv->reply, soa_to);
|
|
|
|
/* not deep free since rrs moved to the answer */
|
|
ldns_rr_list_free(rr_remove);
|
|
ldns_rr_list_free(rr_add);
|
|
/* do not need to delete soa_from, soa_to: they are in rrlist. */
|
|
|
|
return LDNS_RCODE_NOERROR;
|
|
}
|
|
|
|
ldns_pkt_rcode
|
|
process_pkt_axfr(struct socket_service* sv, struct zone_entry_t* entry)
|
|
{
|
|
uint32_t serial;
|
|
ldns_zone* z = 0;
|
|
|
|
serial = entry->zinfo->last_serial;
|
|
zinfo_get_zone_full(entry, serial, &z);
|
|
if(!z) {
|
|
/* no data for this zone! */
|
|
printf("Could not get latest zone info for zone %s %u\n",
|
|
entry->zstr, serial);
|
|
return LDNS_RCODE_SERVFAIL;
|
|
}
|
|
|
|
/* create list of RRs in sv->rrlist */
|
|
if(sv->reply)
|
|
ldns_rr_list_deep_free(sv->reply);
|
|
sv->reply = ldns_rr_list_new();
|
|
if(!sv->reply) {
|
|
printf("out of memory\n");
|
|
return LDNS_RCODE_SERVFAIL;
|
|
}
|
|
/* move zone contents over */
|
|
ldns_rr_list_push_rr(sv->reply, ldns_rr_clone(ldns_zone_soa(z)));
|
|
ldns_rr_list_cat(sv->reply, ldns_zone_rrs(z));
|
|
ldns_rr_list_push_rr(sv->reply, ldns_rr_clone(ldns_zone_soa(z)));
|
|
|
|
ldns_rr_list_set_rr_count(ldns_zone_rrs(z), 0);
|
|
ldns_zone_deep_free(z);
|
|
|
|
return LDNS_RCODE_NOERROR;
|
|
}
|