diff --git a/edns.c b/edns.c index 0e1caca2..035ce4f4 100644 --- a/edns.c +++ b/edns.c @@ -70,6 +70,7 @@ edns_init_record(edns_record_type *edns) edns->opt_reserved_space = 0; edns->dnssec_ok = 0; edns->nsid = 0; + edns->zoneversion = 0; edns->cookie_status = COOKIE_NOT_PRESENT; edns->cookie_len = 0; edns->ede = -1; /* -1 means no Extended DNS Error */ @@ -116,6 +117,11 @@ edns_handle_option(uint16_t optcode, uint16_t optlen, buffer_type* packet, buffer_skip(packet, optlen); } break; + case ZONEVERSION_CODE: + edns->zoneversion = 1; + if(optlen > 0) + return 0; + break; default: buffer_skip(packet, optlen); break; diff --git a/edns.h b/edns.h index 45d7c636..90ad848e 100644 --- a/edns.h +++ b/edns.h @@ -20,6 +20,7 @@ struct query; #define NSID_CODE 3 /* nsid option code */ #define COOKIE_CODE 10 /* COOKIE option code */ #define EDE_CODE 15 /* Extended DNS Errors option code */ +#define ZONEVERSION_CODE 19 /* ZONEVERSION option code */ #define DNSSEC_OK_MASK 0x8000U /* do bit mask */ struct edns_data @@ -59,6 +60,7 @@ struct edns_record size_t opt_reserved_space; int dnssec_ok; int nsid; + int zoneversion; cookie_status_type cookie_status; size_t cookie_len; uint8_t cookie[40]; diff --git a/query.c b/query.c index 8221f7b2..23070ed7 100644 --- a/query.c +++ b/query.c @@ -1780,6 +1780,17 @@ query_add_optional(query_type *q, nsd_type *nsd, uint32_t *now_p) 6 + ( q->edns.ede_text_len ? q->edns.ede_text_len : 0); + if(q->edns.zoneversion + && q->zone + && q->zone->soa_rrset + && q->zone->soa_rrset->rrs + && q->zone->soa_rrset->rrs->rdata_count >= 3) + q->edns.opt_reserved_space += sizeof(uint16_t) + + sizeof(uint16_t) + + sizeof(uint8_t) + + sizeof(uint8_t) + + sizeof(uint32_t); + if(q->edns.opt_reserved_space == 0 || !buffer_available( q->packet, 2+q->edns.opt_reserved_space)) { /* fill with NULLs */ @@ -1794,6 +1805,23 @@ query_add_optional(query_type *q, nsd_type *nsd, uint32_t *now_p) /* nsid payload */ buffer_write(q->packet, nsd->nsid, nsd->nsid_len); } + if(q->edns.zoneversion + && q->zone + && q->zone->soa_rrset + && q->zone->soa_rrset->rrs + && q->zone->soa_rrset->rrs->rdata_count >= 3) { + buffer_write_u16(q->packet, ZONEVERSION_CODE); + buffer_write_u16( q->packet + , sizeof(uint8_t) + + sizeof(uint8_t) + + sizeof(uint32_t)); + buffer_write_u8(q->packet, + domain_dname(q->zone->apex)->label_count - 1); + buffer_write_u8(q->packet, 0); + buffer_write_u32(q->packet, + read_uint32(rdata_atom_data( + q->zone->soa_rrset->rrs->rdatas[2]))); + } if(q->edns.cookie_status != COOKIE_NOT_PRESENT) { /* cookie opt header */ buffer_write(q->packet, edns->cookie, OPT_HDR);