--add-subnet option.
diff --git a/src/forward.c b/src/forward.c
index 6c9f646..adc4a0f 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -284,6 +284,7 @@
forward->fd = udpfd;
forward->crc = crc;
forward->forwardall = 0;
+ forward->flags = 0;
if (norebind)
forward->flags |= FREC_NOREBIND;
if (header->hb4 & HB4_CD)
@@ -331,6 +332,16 @@
if (option_bool(OPT_ADD_MAC))
plen = add_mac(header, plen, ((char *) header) + PACKETSZ, &forward->source);
+ if (option_bool(OPT_CLIENT_SUBNET))
+ {
+ size_t new = add_source_addr(header, plen, ((char *) header) + PACKETSZ, &forward->source);
+ if (new != plen)
+ {
+ plen = new;
+ forward->flags |= FREC_HAS_SUBNET;
+ }
+ }
+
while (1)
{
/* only send to servers dealing with our domain.
@@ -435,8 +446,8 @@
return 0;
}
-static size_t process_reply(struct dns_header *header, time_t now,
- struct server *server, size_t n, int check_rebind, int checking_disabled)
+static size_t process_reply(struct dns_header *header, time_t now, struct server *server, size_t n, int check_rebind,
+ int checking_disabled, int check_subnet, union mysockaddr *query_source)
{
unsigned char *pheader, *sizep;
char **sets = 0;
@@ -465,19 +476,29 @@
than we allow, trim it so that we don't get overlarge
requests for the client. We can't do this for signed packets. */
- if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)) && !is_sign)
+ if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)))
{
- unsigned short udpsz;
- unsigned char *psave = sizep;
+ if (!is_sign)
+ {
+ unsigned short udpsz;
+ unsigned char *psave = sizep;
+
+ GETSHORT(udpsz, sizep);
+ if (udpsz > daemon->edns_pktsz)
+ PUTSHORT(daemon->edns_pktsz, psave);
+ }
- GETSHORT(udpsz, sizep);
- if (udpsz > daemon->edns_pktsz)
- PUTSHORT(daemon->edns_pktsz, psave);
+ if (check_subnet && !check_source(header, plen, pheader, query_source))
+ {
+ my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
+ return 0;
+ }
}
+
/* RFC 4035 sect 4.6 para 3 */
if (!is_sign && !option_bool(OPT_DNSSEC))
- header->hb4 &= ~HB4_AD;
+ header->hb4 &= ~HB4_AD;
if (OPCODE(header) != QUERY || (RCODE(header) != NOERROR && RCODE(header) != NXDOMAIN))
return n;
@@ -632,7 +653,8 @@
if (!option_bool(OPT_NO_REBIND))
check_rebind = 0;
- if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, forward->flags & FREC_CHECKING_DISABLED)))
+ if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, forward->flags & FREC_CHECKING_DISABLED,
+ forward->flags & FREC_HAS_SUBNET, &forward->source)))
{
header->id = htons(forward->orig_id);
header->hb4 |= HB4_RA; /* recursion if available */
@@ -876,7 +898,7 @@
{
size_t size = 0;
int norebind = 0;
- int checking_disabled;
+ int checking_disabled, check_subnet;
size_t m;
unsigned short qtype;
unsigned int gotname;
@@ -906,6 +928,8 @@
if (size < (int)sizeof(struct dns_header))
continue;
+ check_subnet = 0;
+
/* save state of "cd" flag in query */
checking_disabled = header->hb4 & HB4_CD;
@@ -955,7 +979,17 @@
if (option_bool(OPT_ADD_MAC))
size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
-
+
+ if (option_bool(OPT_CLIENT_SUBNET))
+ {
+ size_t new = add_source_addr(header, size, ((char *) header) + 65536, &peer_addr);
+ if (size != new)
+ {
+ size = new;
+ check_subnet = 1;
+ }
+ }
+
if (gotname)
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
@@ -1056,7 +1090,8 @@
sending replies containing questions and bogus answers. */
if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff))
m = process_reply(header, now, last_server, (unsigned int)m,
- option_bool(OPT_NO_REBIND) && !norebind, checking_disabled);
+ option_bool(OPT_NO_REBIND) && !norebind, checking_disabled,
+ check_subnet, &peer_addr);
break;
}