diff --git a/bin/named/config.c b/bin/named/config.c index 9472495214..6dda569921 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -599,30 +599,41 @@ isc_result_t named_config_getipandkeylist(const cfg_obj_t *config, const char *listtype, const cfg_obj_t *list, isc_mem_t *mctx, dns_ipkeylist_t *ipkl) { - uint32_t addrcount = 0, dscpcount = 0, keycount = 0, tlscount = 0, - i = 0; - uint32_t listcount = 0, l = 0, j; + uint32_t addrcount = 0, srccount = 0, dscpcount = 0; + uint32_t keycount = 0, tlscount = 0; + uint32_t listcount = 0, l = 0, i = 0; uint32_t stackcount = 0, pushed = 0; isc_result_t result; const cfg_listelt_t *element; const cfg_obj_t *addrlist; const cfg_obj_t *portobj; const cfg_obj_t *dscpobj; + const cfg_obj_t *src4obj; + const cfg_obj_t *src6obj; in_port_t port = (in_port_t)0; in_port_t def_port; in_port_t def_tlsport; + isc_sockaddr_t src4; + isc_sockaddr_t src6; isc_dscp_t dscp = -1; isc_sockaddr_t *addrs = NULL; + isc_sockaddr_t *sources = NULL; isc_dscp_t *dscps = NULL; dns_name_t **keys = NULL; dns_name_t **tlss = NULL; struct { const char *name; + in_port_t port; + isc_dscp_t dscp; + isc_sockaddr_t *src4s; + isc_sockaddr_t *src6s; } *lists = NULL; struct { const cfg_listelt_t *element; in_port_t port; isc_dscp_t dscp; + isc_sockaddr_t src4; + isc_sockaddr_t src6; } *stack = NULL; REQUIRE(ipkl != NULL); @@ -656,6 +667,8 @@ newlist: addrlist = cfg_tuple_get(list, "addresses"); portobj = cfg_tuple_get(list, "port"); dscpobj = cfg_tuple_get(list, "dscp"); + src4obj = cfg_tuple_get(list, "source"); + src6obj = cfg_tuple_get(list, "source-v6"); if (cfg_obj_isuint32(portobj)) { uint32_t val = cfg_obj_asuint32(portobj); @@ -679,6 +692,18 @@ newlist: dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj); } + if (src4obj != NULL && cfg_obj_issockaddr(src4obj)) { + src4 = *cfg_obj_assockaddr(src4obj); + } else { + isc_sockaddr_any(&src4); + } + + if (src6obj != NULL && cfg_obj_issockaddr(src6obj)) { + src6 = *cfg_obj_assockaddr(src6obj); + } else { + isc_sockaddr_any6(&src6); + } + result = ISC_R_NOMEMORY; element = cfg_list_first(addrlist); @@ -696,6 +721,7 @@ resume: if (!cfg_obj_issockaddr(addr)) { const char *listname = cfg_obj_asstring(addr); isc_result_t tresult; + uint32_t j; /* Grow lists? */ grow_array(mctx, lists, l, listcount); @@ -733,6 +759,8 @@ resume: stack[pushed].element = cfg_list_next(element); stack[pushed].port = port; stack[pushed].dscp = dscp; + stack[pushed].src4 = src4; + stack[pushed].src6 = src6; pushed++; goto newlist; } @@ -741,6 +769,7 @@ resume: grow_array(mctx, dscps, i, dscpcount); grow_array(mctx, keys, i, keycount); grow_array(mctx, tlss, i, tlscount); + grow_array(mctx, sources, i, srccount); addrs[i] = *cfg_obj_assockaddr(addr); dscps[i] = cfg_obj_getdscp(addr); @@ -778,6 +807,20 @@ resume: isc_sockaddr_setport(&addrs[i], addr_port); } + switch (isc_sockaddr_pf(&addrs[i])) { + case PF_INET: + sources[i] = src4; + break; + case PF_INET6: + sources[i] = src6; + break; + default: + i++; /* Increment here so that cleanup on error works. + */ + result = ISC_R_NOTIMPLEMENTED; + goto cleanup; + } + i++; } if (pushed != 0) { @@ -785,6 +828,8 @@ resume: element = stack[pushed].element; port = stack[pushed].port; dscp = stack[pushed].dscp; + src4 = stack[pushed].src4; + src6 = stack[pushed].src6; goto resume; } @@ -792,6 +837,7 @@ resume: shrink_array(mctx, dscps, i, dscpcount); shrink_array(mctx, keys, i, keycount); shrink_array(mctx, tlss, i, tlscount); + shrink_array(mctx, sources, i, srccount); if (lists != NULL) { isc_mem_put(mctx, lists, listcount * sizeof(lists[0])); @@ -803,12 +849,14 @@ resume: INSIST(dscpcount == addrcount); INSIST(keycount == addrcount); INSIST(tlscount == addrcount); + INSIST(srccount == addrcount); INSIST(keycount == dscpcount); ipkl->addrs = addrs; ipkl->dscps = dscps; ipkl->keys = keys; ipkl->tlss = tlss; + ipkl->sources = sources; ipkl->count = addrcount; ipkl->allocated = addrcount; @@ -822,7 +870,7 @@ cleanup: isc_mem_put(mctx, dscps, dscpcount * sizeof(dscps[0])); } if (keys != NULL) { - for (j = 0; j < i; j++) { + for (size_t j = 0; j < i; j++) { if (keys[j] == NULL) { continue; } @@ -834,7 +882,7 @@ cleanup: isc_mem_put(mctx, keys, keycount * sizeof(keys[0])); } if (tlss != NULL) { - for (j = 0; j < i; j++) { + for (size_t j = 0; j < i; j++) { if (tlss[j] == NULL) { continue; } @@ -845,6 +893,9 @@ cleanup: } isc_mem_put(mctx, tlss, tlscount * sizeof(tlss[0])); } + if (sources != NULL) { + isc_mem_put(mctx, sources, srccount * sizeof(sources[0])); + } if (lists != NULL) { isc_mem_put(mctx, lists, listcount * sizeof(lists[0])); } diff --git a/bin/named/zoneconf.c b/bin/named/zoneconf.c index 795db7bf6e..af017f3198 100644 --- a/bin/named/zoneconf.c +++ b/bin/named/zoneconf.c @@ -1268,12 +1268,13 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, RETERR(named_config_getipandkeylist(config, "primaries", obj, mctx, &ipkl)); - dns_zone_setalsonotify(zone, ipkl.addrs, ipkl.dscps, - ipkl.keys, ipkl.tlss, + dns_zone_setalsonotify(zone, ipkl.addrs, ipkl.sources, + ipkl.dscps, ipkl.keys, ipkl.tlss, ipkl.count); dns_ipkeylist_clear(mctx, &ipkl); } else { - dns_zone_setalsonotify(zone, NULL, NULL, NULL, NULL, 0); + dns_zone_setalsonotify(zone, NULL, NULL, NULL, NULL, + NULL, 0); } obj = NULL; @@ -1722,11 +1723,11 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, dns_ipkeylist_init(&ipkl); RETERR(named_config_getipandkeylist( config, "parental-agents", obj, mctx, &ipkl)); - dns_zone_setparentals(zone, ipkl.addrs, ipkl.keys, - ipkl.tlss, ipkl.count); + dns_zone_setparentals(zone, ipkl.addrs, ipkl.sources, + ipkl.keys, ipkl.tlss, ipkl.count); dns_ipkeylist_clear(mctx, &ipkl); } else { - dns_zone_setparentals(zone, NULL, NULL, NULL, 0); + dns_zone_setparentals(zone, NULL, NULL, NULL, NULL, 0); } } @@ -1890,12 +1891,14 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, RETERR(named_config_getipandkeylist(config, "primaries", obj, mctx, &ipkl)); - dns_zone_setprimaries(mayberaw, ipkl.addrs, ipkl.keys, + dns_zone_setprimaries(mayberaw, ipkl.addrs, + ipkl.sources, ipkl.keys, ipkl.tlss, ipkl.count); count = ipkl.count; dns_ipkeylist_clear(mctx, &ipkl); } else { - dns_zone_setprimaries(mayberaw, NULL, NULL, NULL, 0); + dns_zone_setprimaries(mayberaw, NULL, NULL, NULL, NULL, + 0); } multi = false; diff --git a/lib/dns/include/dns/ipkeylist.h b/lib/dns/include/dns/ipkeylist.h index 5a87cdb11a..e74f293fe8 100644 --- a/lib/dns/include/dns/ipkeylist.h +++ b/lib/dns/include/dns/ipkeylist.h @@ -26,6 +26,7 @@ struct dns_ipkeylist { isc_sockaddr_t *addrs; isc_dscp_t *dscps; + isc_sockaddr_t *sources; dns_name_t **keys; dns_name_t **tlss; dns_name_t **labels; diff --git a/lib/dns/include/dns/remote.h b/lib/dns/include/dns/remote.h index 3c25e155ad..47115b80ef 100644 --- a/lib/dns/include/dns/remote.h +++ b/lib/dns/include/dns/remote.h @@ -32,6 +32,7 @@ struct dns_remote { unsigned int magic; isc_mem_t *mctx; isc_sockaddr_t *addresses; + isc_sockaddr_t *sources; isc_dscp_t *dscps; dns_name_t **keynames; dns_name_t **tlsnames; @@ -49,6 +50,15 @@ dns_remote_addresses(dns_remote_t *remote); * 'remote' is a valid remote structure. */ +isc_sockaddr_t * +dns_remote_sources(dns_remote_t *remote); +/*%< + * Return the source addresses to be used for the remote server. + * + * Requires: + * 'remote' is a valid remote structure. + */ + unsigned int dns_remote_count(dns_remote_t *remote); /*%< @@ -78,15 +88,16 @@ dns_remote_tlsnames(dns_remote_t *remote); void dns_remote_init(dns_remote_t *remote, unsigned int count, - const isc_sockaddr_t *addrs, const isc_dscp_t *dscp, - dns_name_t **keynames, dns_name_t **tlsnames, bool mark, - isc_mem_t *mctx); + const isc_sockaddr_t *addrs, const isc_sockaddr_t *srcs, + const isc_dscp_t *dscp, dns_name_t **keynames, + dns_name_t **tlsnames, bool mark, isc_mem_t *mctx); /*%< * Initialize a remote server. Set the provided addresses (addrs), - * dscp's (dscp), key names (keynames) and tls names (tlsnames). Use the - * provided memory context (mctx) for allocations. If 'mark' is 'true', - * set up a list of boolean values to mark the server bad or good. + * source addresses (srcs), dscp's (dscp), key names (keynames) and + * tls names (tlsnames). Use the provided memory context (mctx) for + * allocations. If 'mark' is 'true', set up a list of boolean values to + * mark the server bad or good. * * Requires: * 'remote' is a valid remote structure. @@ -146,6 +157,16 @@ dns_remote_curraddr(dns_remote_t *remote); * 'remote->addresses' is not NULL. */ +isc_sockaddr_t +dns_remote_sourceaddr(dns_remote_t *remote); +/*%< + * Return the current source address. + * + * Requires: + * 'remote' is a valid remote structure. + * 'remote->sources' is not NULL. + */ + isc_sockaddr_t dns_remote_addr(dns_remote_t *remote, unsigned int i); /*%< diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index d077806e07..bbbf84d7e1 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -635,8 +635,8 @@ dns_zone_dumptostream(dns_zone_t *zone, FILE *fd, dns_masterformat_t format, void dns_zone_setprimaries(dns_zone_t *zone, isc_sockaddr_t *addresses, - dns_name_t **keynames, dns_name_t **tlsnames, - uint32_t count); + isc_sockaddr_t *sources, dns_name_t **keynames, + dns_name_t **tlsnames, uint32_t count); /*%< * Set the list of primary servers for the zone. * @@ -656,8 +656,8 @@ dns_zone_setprimaries(dns_zone_t *zone, isc_sockaddr_t *addresses, void dns_zone_setparentals(dns_zone_t *zone, isc_sockaddr_t *addresses, - dns_name_t **keynames, dns_name_t **tlsnames, - uint32_t count); + isc_sockaddr_t *sources, dns_name_t **keynames, + dns_name_t **tlsnames, uint32_t count); /*%< * Set the list of parental agents for the zone. * @@ -677,8 +677,9 @@ dns_zone_setparentals(dns_zone_t *zone, isc_sockaddr_t *addresses, void dns_zone_setalsonotify(dns_zone_t *zone, isc_sockaddr_t *addresses, - isc_dscp_t *dscps, dns_name_t **keynames, - dns_name_t **tlsnames, uint32_t count); + isc_sockaddr_t *sources, isc_dscp_t *dscps, + dns_name_t **keynames, dns_name_t **tlsnames, + uint32_t count); /*%< * Set the list of additional servers to be notified when * a zone changes. To clear the list use 'count = 0'. diff --git a/lib/dns/ipkeylist.c b/lib/dns/ipkeylist.c index f773c1b616..b12656b318 100644 --- a/lib/dns/ipkeylist.c +++ b/lib/dns/ipkeylist.c @@ -26,6 +26,7 @@ dns_ipkeylist_init(dns_ipkeylist_t *ipkl) { ipkl->count = 0; ipkl->allocated = 0; ipkl->addrs = NULL; + ipkl->sources = NULL; ipkl->dscps = NULL; ipkl->keys = NULL; ipkl->tlss = NULL; @@ -47,11 +48,21 @@ dns_ipkeylist_clear(isc_mem_t *mctx, dns_ipkeylist_t *ipkl) { ipkl->allocated * sizeof(isc_sockaddr_t)); } + if (ipkl->sources != NULL) { + isc_mem_put(mctx, ipkl->sources, + ipkl->allocated * sizeof(isc_sockaddr_t)); + } + if (ipkl->dscps != NULL) { isc_mem_put(mctx, ipkl->dscps, ipkl->allocated * sizeof(isc_dscp_t)); } + if (ipkl->addrs != NULL) { + isc_mem_put(mctx, ipkl->addrs, + ipkl->allocated * sizeof(isc_sockaddr_t)); + } + if (ipkl->keys != NULL) { for (i = 0; i < ipkl->allocated; i++) { if (ipkl->keys[i] == NULL) { @@ -118,6 +129,11 @@ dns_ipkeylist_copy(isc_mem_t *mctx, const dns_ipkeylist_t *src, memmove(dst->addrs, src->addrs, src->count * sizeof(isc_sockaddr_t)); + if (src->sources != NULL) { + memmove(dst->sources, src->sources, + src->count * sizeof(isc_sockaddr_t)); + } + if (src->dscps != NULL) { memmove(dst->dscps, src->dscps, src->count * sizeof(isc_dscp_t)); @@ -169,6 +185,7 @@ dns_ipkeylist_copy(isc_mem_t *mctx, const dns_ipkeylist_t *src, isc_result_t dns_ipkeylist_resize(isc_mem_t *mctx, dns_ipkeylist_t *ipkl, unsigned int n) { isc_sockaddr_t *addrs = NULL; + isc_sockaddr_t *sources = NULL; isc_dscp_t *dscps = NULL; dns_name_t **keys = NULL; dns_name_t **tlss = NULL; @@ -182,6 +199,7 @@ dns_ipkeylist_resize(isc_mem_t *mctx, dns_ipkeylist_t *ipkl, unsigned int n) { } addrs = isc_mem_get(mctx, n * sizeof(isc_sockaddr_t)); + sources = isc_mem_get(mctx, n * sizeof(isc_sockaddr_t)); dscps = isc_mem_get(mctx, n * sizeof(isc_dscp_t)); keys = isc_mem_get(mctx, n * sizeof(dns_name_t *)); tlss = isc_mem_get(mctx, n * sizeof(dns_name_t *)); @@ -197,6 +215,16 @@ dns_ipkeylist_resize(isc_mem_t *mctx, dns_ipkeylist_t *ipkl, unsigned int n) { memset(&ipkl->addrs[ipkl->allocated], 0, (n - ipkl->allocated) * sizeof(isc_sockaddr_t)); + if (ipkl->sources != NULL) { + memmove(sources, ipkl->sources, + ipkl->allocated * sizeof(isc_sockaddr_t)); + isc_mem_put(mctx, ipkl->sources, + ipkl->allocated * sizeof(isc_sockaddr_t)); + } + ipkl->sources = sources; + memset(&ipkl->sources[ipkl->allocated], 0, + (n - ipkl->allocated) * sizeof(isc_sockaddr_t)); + if (ipkl->dscps != NULL) { memmove(dscps, ipkl->dscps, ipkl->allocated * sizeof(isc_dscp_t)); @@ -241,6 +269,7 @@ dns_ipkeylist_resize(isc_mem_t *mctx, dns_ipkeylist_t *ipkl, unsigned int n) { return (ISC_R_SUCCESS); isc_mem_put(mctx, addrs, n * sizeof(isc_sockaddr_t)); + isc_mem_put(mctx, sources, n * sizeof(isc_sockaddr_t)); isc_mem_put(mctx, dscps, n * sizeof(isc_dscp_t)); isc_mem_put(mctx, tlss, n * sizeof(dns_name_t *)); isc_mem_put(mctx, keys, n * sizeof(dns_name_t *)); diff --git a/lib/dns/remote.c b/lib/dns/remote.c index 15b311743f..87974d885c 100644 --- a/lib/dns/remote.c +++ b/lib/dns/remote.c @@ -31,6 +31,12 @@ dns_remote_addresses(dns_remote_t *remote) { return (remote->addresses); } +isc_sockaddr_t * +dns_remote_sources(dns_remote_t *remote) { + REQUIRE(DNS_REMOTE_VALID(remote)); + return (remote->sources); +} + unsigned int dns_remote_count(dns_remote_t *remote) { REQUIRE(DNS_REMOTE_VALID(remote)); @@ -51,9 +57,9 @@ dns_remote_tlsnames(dns_remote_t *remote) { void dns_remote_init(dns_remote_t *remote, unsigned int count, - const isc_sockaddr_t *addrs, const isc_dscp_t *dscp, - dns_name_t **keynames, dns_name_t **tlsnames, bool mark, - isc_mem_t *mctx) { + const isc_sockaddr_t *addrs, const isc_sockaddr_t *srcs, + const isc_dscp_t *dscp, dns_name_t **keynames, + dns_name_t **tlsnames, bool mark, isc_mem_t *mctx) { unsigned int i; REQUIRE(DNS_REMOTE_VALID(remote)); @@ -74,6 +80,14 @@ dns_remote_init(dns_remote_t *remote, unsigned int count, remote->addresses = NULL; } + if (srcs != NULL) { + remote->sources = isc_mem_get(mctx, + count * sizeof(isc_sockaddr_t)); + memmove(remote->sources, srcs, count * sizeof(isc_sockaddr_t)); + } else { + remote->sources = NULL; + } + if (dscp != NULL) { remote->dscps = isc_mem_get(mctx, count * sizeof(isc_dscp_t)); memmove(remote->dscps, dscp, count * sizeof(isc_dscp_t)); @@ -219,6 +233,12 @@ dns_remote_clear(dns_remote_t *remote) { remote->addresses = NULL; } + if (remote->sources != NULL) { + isc_mem_put(mctx, remote->sources, + count * sizeof(isc_sockaddr_t)); + remote->sources = NULL; + } + if (remote->dscps != NULL) { isc_mem_put(mctx, remote->dscps, count * sizeof(isc_dscp_t)); remote->dscps = NULL; @@ -316,6 +336,15 @@ dns_remote_addr(dns_remote_t *remote, unsigned int i) { return (remote->addresses[i]); } +isc_sockaddr_t +dns_remote_sourceaddr(dns_remote_t *remote) { + REQUIRE(DNS_REMOTE_VALID(remote)); + REQUIRE(remote->sources != NULL); + REQUIRE(remote->curraddr < remote->addrcnt); + + return (remote->sources[remote->curraddr]); +} + isc_dscp_t dns_remote_dscp(dns_remote_t *remote) { REQUIRE(DNS_REMOTE_VALID(remote)); diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 898c1b2673..bd2baf489a 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -6260,8 +6260,9 @@ dns_zone_getnotifysrc6dscp(dns_zone_t *zone) { void dns_zone_setalsonotify(dns_zone_t *zone, isc_sockaddr_t *addresses, - isc_dscp_t *dscps, dns_name_t **keynames, - dns_name_t **tlsnames, uint32_t count) { + isc_sockaddr_t *sources, isc_dscp_t *dscps, + dns_name_t **keynames, dns_name_t **tlsnames, + uint32_t count) { dns_remote_t remote; REQUIRE(DNS_ZONE_VALID(zone)); @@ -6270,6 +6271,7 @@ dns_zone_setalsonotify(dns_zone_t *zone, isc_sockaddr_t *addresses, remote.magic = DNS_REMOTE_MAGIC; remote.addresses = addresses; + remote.sources = sources; remote.dscps = dscps; remote.keynames = keynames; remote.tlsnames = tlsnames; @@ -6291,8 +6293,8 @@ dns_zone_setalsonotify(dns_zone_t *zone, isc_sockaddr_t *addresses, /* * Now set up the notify address and key lists. */ - dns_remote_init(&zone->notify, count, addresses, dscps, keynames, - tlsnames, true, zone->mctx); + dns_remote_init(&zone->notify, count, addresses, sources, dscps, + keynames, tlsnames, true, zone->mctx); unlock: UNLOCK_ZONE(zone); @@ -6300,8 +6302,8 @@ unlock: void dns_zone_setprimaries(dns_zone_t *zone, isc_sockaddr_t *addresses, - dns_name_t **keynames, dns_name_t **tlsnames, - uint32_t count) { + isc_sockaddr_t *sources, dns_name_t **keynames, + dns_name_t **tlsnames, uint32_t count) { dns_remote_t remote; REQUIRE(DNS_ZONE_VALID(zone)); @@ -6310,6 +6312,7 @@ dns_zone_setprimaries(dns_zone_t *zone, isc_sockaddr_t *addresses, remote.magic = DNS_REMOTE_MAGIC; remote.addresses = addresses; + remote.sources = sources; remote.dscps = NULL; remote.keynames = keynames; remote.tlsnames = tlsnames; @@ -6341,8 +6344,8 @@ dns_zone_setprimaries(dns_zone_t *zone, isc_sockaddr_t *addresses, /* * Now set up the primaries and primary key lists. */ - dns_remote_init(&zone->primaries, count, addresses, NULL, keynames, - tlsnames, true, zone->mctx); + dns_remote_init(&zone->primaries, count, addresses, sources, NULL, + keynames, tlsnames, true, zone->mctx); DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOPRIMARIES); @@ -6352,8 +6355,8 @@ unlock: void dns_zone_setparentals(dns_zone_t *zone, isc_sockaddr_t *addresses, - dns_name_t **keynames, dns_name_t **tlsnames, - uint32_t count) { + isc_sockaddr_t *sources, dns_name_t **keynames, + dns_name_t **tlsnames, uint32_t count) { dns_remote_t remote; REQUIRE(DNS_ZONE_VALID(zone)); @@ -6362,6 +6365,7 @@ dns_zone_setparentals(dns_zone_t *zone, isc_sockaddr_t *addresses, remote.magic = DNS_REMOTE_MAGIC; remote.addresses = addresses; + remote.sources = sources; remote.dscps = NULL; remote.keynames = keynames; remote.tlsnames = tlsnames; @@ -6383,8 +6387,8 @@ dns_zone_setparentals(dns_zone_t *zone, isc_sockaddr_t *addresses, /* * Now set up the parentals and parental key lists. */ - dns_remote_init(&zone->parentals, count, addresses, NULL, keynames, - tlsnames, true, zone->mctx); + dns_remote_init(&zone->parentals, count, addresses, sources, NULL, + keynames, tlsnames, true, zone->mctx); dns_zone_log(zone, ISC_LOG_NOTICE, "checkds: set %u parentals", count);