Split EDNS0 stuff into its own source file.
diff --git a/Makefile b/Makefile
index b664160..dfb0347 100644
--- a/Makefile
+++ b/Makefile
@@ -74,7 +74,7 @@
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
- poll.o rrfilter.o
+ poll.o rrfilter.o edns0.o
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h ip6addr.h
diff --git a/bld/Android.mk b/bld/Android.mk
index 67b9c4b..87966d2 100644
--- a/bld/Android.mk
+++ b/bld/Android.mk
@@ -10,7 +10,7 @@
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
radv.c slaac.c auth.c ipset.c domain.c \
dnssec.c dnssec-openssl.c blockdata.c tables.c \
- loop.c inotify.c poll.c rrfilter.c
+ loop.c inotify.c poll.c rrfilter.c edns0.c
LOCAL_MODULE := dnsmasq
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index abb34c5..a41c8cc 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -1123,14 +1123,6 @@
unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
size_t resize_packet(struct dns_header *header, size_t plen,
unsigned char *pheader, size_t hlen);
-size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
- unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do);
-size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
-size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source);
-#ifdef HAVE_DNSSEC
-size_t add_do_bit(struct dns_header *header, size_t plen, char *limit);
-#endif
-int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
int add_resource_record(struct dns_header *header, char *limit, int *truncp,
int nameoffset, unsigned char **pp, unsigned long ttl,
int *offset, unsigned short type, unsigned short class, char *format, ...);
@@ -1521,3 +1513,12 @@
u16 *rrfilter_desc(int type);
int expand_workspace(unsigned char ***wkspc, int *szp, int new);
+/* edns0.c */
+size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
+ unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do);
+size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
+size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source);
+#ifdef HAVE_DNSSEC
+size_t add_do_bit(struct dns_header *header, size_t plen, char *limit);
+#endif
+int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
diff --git a/src/edns0.c b/src/edns0.c
new file mode 100644
index 0000000..f348b01
--- /dev/null
+++ b/src/edns0.c
@@ -0,0 +1,351 @@
+/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 dated June, 1991, or
+ (at your option) version 3 dated 29 June, 2007.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnsmasq.h"
+
+unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t *len, unsigned char **p, int *is_sign)
+{
+ /* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
+ also return length of pseudoheader in *len and pointer to the UDP size in *p
+ Finally, check to see if a packet is signed. If it is we cannot change a single bit before
+ forwarding. We look for SIG and TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
+
+ int i, arcount = ntohs(header->arcount);
+ unsigned char *ansp = (unsigned char *)(header+1);
+ unsigned short rdlen, type, class;
+ unsigned char *ret = NULL;
+
+ if (is_sign)
+ {
+ *is_sign = 0;
+
+ if (OPCODE(header) == QUERY)
+ {
+ for (i = ntohs(header->qdcount); i != 0; i--)
+ {
+ if (!(ansp = skip_name(ansp, header, plen, 4)))
+ return NULL;
+
+ GETSHORT(type, ansp);
+ GETSHORT(class, ansp);
+
+ if (class == C_IN && type == T_TKEY)
+ *is_sign = 1;
+ }
+ }
+ }
+ else
+ {
+ if (!(ansp = skip_questions(header, plen)))
+ return NULL;
+ }
+
+ if (arcount == 0)
+ return NULL;
+
+ if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
+ return NULL;
+
+ for (i = 0; i < arcount; i++)
+ {
+ unsigned char *save, *start = ansp;
+ if (!(ansp = skip_name(ansp, header, plen, 10)))
+ return NULL;
+
+ GETSHORT(type, ansp);
+ save = ansp;
+ GETSHORT(class, ansp);
+ ansp += 4; /* TTL */
+ GETSHORT(rdlen, ansp);
+ if (!ADD_RDLEN(header, ansp, plen, rdlen))
+ return NULL;
+ if (type == T_OPT)
+ {
+ if (len)
+ *len = ansp - start;
+ if (p)
+ *p = save;
+ ret = start;
+ }
+ else if (is_sign &&
+ i == arcount - 1 &&
+ class == C_ANY &&
+ type == T_TSIG)
+ *is_sign = 1;
+ }
+
+ return ret;
+}
+
+struct macparm {
+ unsigned char *limit;
+ struct dns_header *header;
+ size_t plen;
+ union mysockaddr *l3;
+};
+
+size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
+ unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do)
+{
+ unsigned char *lenp, *datap, *p;
+ int rdlen, is_sign;
+
+ if (!(p = find_pseudoheader(header, plen, NULL, NULL, &is_sign)))
+ {
+ if (is_sign)
+ return plen;
+
+ /* We are adding the pseudoheader */
+ if (!(p = skip_questions(header, plen)) ||
+ !(p = skip_section(p,
+ ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
+ header, plen)))
+ return plen;
+ *p++ = 0; /* empty name */
+ PUTSHORT(T_OPT, p);
+ PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
+ PUTSHORT(0, p); /* extended RCODE and version */
+ PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */
+ lenp = p;
+ PUTSHORT(0, p); /* RDLEN */
+ rdlen = 0;
+ if (((ssize_t)optlen) > (limit - (p + 4)))
+ return plen; /* Too big */
+ header->arcount = htons(ntohs(header->arcount) + 1);
+ datap = p;
+ }
+ else
+ {
+ int i;
+ unsigned short code, len, flags;
+
+ /* Must be at the end, if exists */
+ if (ntohs(header->arcount) != 1 ||
+ is_sign ||
+ (!(p = skip_name(p, header, plen, 10))))
+ return plen;
+
+ p += 6; /* skip UDP length and RCODE */
+ GETSHORT(flags, p);
+ if (set_do)
+ {
+ p -=2;
+ PUTSHORT(flags | 0x8000, p);
+ }
+
+ lenp = p;
+ GETSHORT(rdlen, p);
+ if (!CHECK_LEN(header, p, plen, rdlen))
+ return plen; /* bad packet */
+ datap = p;
+
+ /* no option to add */
+ if (optno == 0)
+ return plen;
+
+ /* check if option already there */
+ for (i = 0; i + 4 < rdlen; i += len + 4)
+ {
+ GETSHORT(code, p);
+ GETSHORT(len, p);
+ if (code == optno)
+ return plen;
+ p += len;
+ }
+
+ if (((ssize_t)optlen) > (limit - (p + 4)))
+ return plen; /* Too big */
+ }
+
+ if (optno != 0)
+ {
+ PUTSHORT(optno, p);
+ PUTSHORT(optlen, p);
+ memcpy(p, opt, optlen);
+ p += optlen;
+ }
+
+ PUTSHORT(p - datap, lenp);
+ return p - (unsigned char *)header;
+
+}
+
+static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
+{
+ struct macparm *parm = parmv;
+ int match = 0;
+
+ if (family == parm->l3->sa.sa_family)
+ {
+ if (family == AF_INET && memcmp(&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
+ match = 1;
+#ifdef HAVE_IPV6
+ else
+ if (family == AF_INET6 && memcmp(&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
+ match = 1;
+#endif
+ }
+
+ if (!match)
+ return 1; /* continue */
+
+ parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, PACKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0);
+
+ return 0; /* done */
+}
+
+size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
+{
+ struct macparm parm;
+
+ parm.header = header;
+ parm.limit = (unsigned char *)limit;
+ parm.plen = plen;
+ parm.l3 = l3;
+
+ iface_enumerate(AF_UNSPEC, &parm, filter_mac);
+
+ return parm.plen;
+}
+
+struct subnet_opt {
+ u16 family;
+ u8 source_netmask, scope_netmask;
+#ifdef HAVE_IPV6
+ u8 addr[IN6ADDRSZ];
+#else
+ u8 addr[INADDRSZ];
+#endif
+};
+
+static void *get_addrp(union mysockaddr *addr, const short family)
+{
+#ifdef HAVE_IPV6
+ if (family == AF_INET6)
+ return &addr->in6.sin6_addr;
+#endif
+
+ return &addr->in.sin_addr;
+}
+
+static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
+{
+ /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
+
+ int len;
+ void *addrp;
+ int sa_family = source->sa.sa_family;
+
+#ifdef HAVE_IPV6
+ if (source->sa.sa_family == AF_INET6)
+ {
+ opt->source_netmask = daemon->add_subnet6->mask;
+ if (daemon->add_subnet6->addr_used)
+ {
+ sa_family = daemon->add_subnet6->addr.sa.sa_family;
+ addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
+ }
+ else
+ addrp = &source->in6.sin6_addr;
+ }
+ else
+#endif
+ {
+ opt->source_netmask = daemon->add_subnet4->mask;
+ if (daemon->add_subnet4->addr_used)
+ {
+ sa_family = daemon->add_subnet4->addr.sa.sa_family;
+ addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
+ }
+ else
+ addrp = &source->in.sin_addr;
+ }
+
+ opt->scope_netmask = 0;
+ len = 0;
+
+ if (opt->source_netmask != 0)
+ {
+#ifdef HAVE_IPV6
+ opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
+#else
+ opt->family = htons(1);
+#endif
+ len = ((opt->source_netmask - 1) >> 3) + 1;
+ memcpy(opt->addr, addrp, len);
+ if (opt->source_netmask & 7)
+ opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
+ }
+
+ return len + 4;
+}
+
+size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source)
+{
+ /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
+
+ int len;
+ struct subnet_opt opt;
+
+ len = calc_subnet_opt(&opt, source);
+ return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
+}
+
+#ifdef HAVE_DNSSEC
+size_t add_do_bit(struct dns_header *header, size_t plen, char *limit)
+{
+ return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1);
+}
+#endif
+
+int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
+{
+ /* Section 9.2, Check that subnet option in reply matches. */
+
+
+ int len, calc_len;
+ struct subnet_opt opt;
+ unsigned char *p;
+ int code, i, rdlen;
+
+ calc_len = calc_subnet_opt(&opt, peer);
+
+ if (!(p = skip_name(pseudoheader, header, plen, 10)))
+ return 1;
+
+ p += 8; /* skip UDP length and RCODE */
+
+ GETSHORT(rdlen, p);
+ if (!CHECK_LEN(header, p, plen, rdlen))
+ return 1; /* bad packet */
+
+ /* check if option there */
+ for (i = 0; i + 4 < rdlen; i += len + 4)
+ {
+ GETSHORT(code, p);
+ GETSHORT(len, p);
+ if (code == EDNS0_OPTION_CLIENT_SUBNET)
+ {
+ /* make sure this doesn't mismatch. */
+ opt.scope_netmask = p[3];
+ if (len != calc_len || memcmp(p, &opt, len) != 0)
+ return 0;
+ }
+ p += len;
+ }
+
+ return 1;
+}
diff --git a/src/rfc1035.c b/src/rfc1035.c
index 18858a8..5d89287 100644
--- a/src/rfc1035.c
+++ b/src/rfc1035.c
@@ -408,340 +408,6 @@
return ansp - (unsigned char *)header;
}
-unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t *len, unsigned char **p, int *is_sign)
-{
- /* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
- also return length of pseudoheader in *len and pointer to the UDP size in *p
- Finally, check to see if a packet is signed. If it is we cannot change a single bit before
- forwarding. We look for SIG and TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
-
- int i, arcount = ntohs(header->arcount);
- unsigned char *ansp = (unsigned char *)(header+1);
- unsigned short rdlen, type, class;
- unsigned char *ret = NULL;
-
- if (is_sign)
- {
- *is_sign = 0;
-
- if (OPCODE(header) == QUERY)
- {
- for (i = ntohs(header->qdcount); i != 0; i--)
- {
- if (!(ansp = skip_name(ansp, header, plen, 4)))
- return NULL;
-
- GETSHORT(type, ansp);
- GETSHORT(class, ansp);
-
- if (class == C_IN && type == T_TKEY)
- *is_sign = 1;
- }
- }
- }
- else
- {
- if (!(ansp = skip_questions(header, plen)))
- return NULL;
- }
-
- if (arcount == 0)
- return NULL;
-
- if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
- return NULL;
-
- for (i = 0; i < arcount; i++)
- {
- unsigned char *save, *start = ansp;
- if (!(ansp = skip_name(ansp, header, plen, 10)))
- return NULL;
-
- GETSHORT(type, ansp);
- save = ansp;
- GETSHORT(class, ansp);
- ansp += 4; /* TTL */
- GETSHORT(rdlen, ansp);
- if (!ADD_RDLEN(header, ansp, plen, rdlen))
- return NULL;
- if (type == T_OPT)
- {
- if (len)
- *len = ansp - start;
- if (p)
- *p = save;
- ret = start;
- }
- else if (is_sign &&
- i == arcount - 1 &&
- class == C_ANY &&
- type == T_TSIG)
- *is_sign = 1;
- }
-
- return ret;
-}
-
-struct macparm {
- unsigned char *limit;
- struct dns_header *header;
- size_t plen;
- union mysockaddr *l3;
-};
-
-size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
- unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do)
-{
- unsigned char *lenp, *datap, *p;
- int rdlen, is_sign;
-
- if (!(p = find_pseudoheader(header, plen, NULL, NULL, &is_sign)))
- {
- if (is_sign)
- return plen;
-
- /* We are adding the pseudoheader */
- if (!(p = skip_questions(header, plen)) ||
- !(p = skip_section(p,
- ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
- header, plen)))
- return plen;
- *p++ = 0; /* empty name */
- PUTSHORT(T_OPT, p);
- PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
- PUTSHORT(0, p); /* extended RCODE and version */
- PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */
- lenp = p;
- PUTSHORT(0, p); /* RDLEN */
- rdlen = 0;
- if (((ssize_t)optlen) > (limit - (p + 4)))
- return plen; /* Too big */
- header->arcount = htons(ntohs(header->arcount) + 1);
- datap = p;
- }
- else
- {
- int i;
- unsigned short code, len, flags;
-
- /* Must be at the end, if exists */
- if (ntohs(header->arcount) != 1 ||
- is_sign ||
- (!(p = skip_name(p, header, plen, 10))))
- return plen;
-
- p += 6; /* skip UDP length and RCODE */
- GETSHORT(flags, p);
- if (set_do)
- {
- p -=2;
- PUTSHORT(flags | 0x8000, p);
- }
-
- lenp = p;
- GETSHORT(rdlen, p);
- if (!CHECK_LEN(header, p, plen, rdlen))
- return plen; /* bad packet */
- datap = p;
-
- /* no option to add */
- if (optno == 0)
- return plen;
-
- /* check if option already there */
- for (i = 0; i + 4 < rdlen; i += len + 4)
- {
- GETSHORT(code, p);
- GETSHORT(len, p);
- if (code == optno)
- return plen;
- p += len;
- }
-
- if (((ssize_t)optlen) > (limit - (p + 4)))
- return plen; /* Too big */
- }
-
- if (optno != 0)
- {
- PUTSHORT(optno, p);
- PUTSHORT(optlen, p);
- memcpy(p, opt, optlen);
- p += optlen;
- }
-
- PUTSHORT(p - datap, lenp);
- return p - (unsigned char *)header;
-
-}
-
-static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
-{
- struct macparm *parm = parmv;
- int match = 0;
-
- if (family == parm->l3->sa.sa_family)
- {
- if (family == AF_INET && memcmp(&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
- match = 1;
-#ifdef HAVE_IPV6
- else
- if (family == AF_INET6 && memcmp(&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
- match = 1;
-#endif
- }
-
- if (!match)
- return 1; /* continue */
-
- parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, PACKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0);
-
- return 0; /* done */
-}
-
-size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
-{
- struct macparm parm;
-
- parm.header = header;
- parm.limit = (unsigned char *)limit;
- parm.plen = plen;
- parm.l3 = l3;
-
- iface_enumerate(AF_UNSPEC, &parm, filter_mac);
-
- return parm.plen;
-}
-
-struct subnet_opt {
- u16 family;
- u8 source_netmask, scope_netmask;
-#ifdef HAVE_IPV6
- u8 addr[IN6ADDRSZ];
-#else
- u8 addr[INADDRSZ];
-#endif
-};
-
-static void *get_addrp(union mysockaddr *addr, const short family)
-{
-#ifdef HAVE_IPV6
- if (family == AF_INET6)
- return &addr->in6.sin6_addr;
-#endif
-
- return &addr->in.sin_addr;
-}
-
-static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
-{
- /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
-
- int len;
- void *addrp;
- int sa_family = source->sa.sa_family;
-
-#ifdef HAVE_IPV6
- if (source->sa.sa_family == AF_INET6)
- {
- opt->source_netmask = daemon->add_subnet6->mask;
- if (daemon->add_subnet6->addr_used)
- {
- sa_family = daemon->add_subnet6->addr.sa.sa_family;
- addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
- }
- else
- addrp = &source->in6.sin6_addr;
- }
- else
-#endif
- {
- opt->source_netmask = daemon->add_subnet4->mask;
- if (daemon->add_subnet4->addr_used)
- {
- sa_family = daemon->add_subnet4->addr.sa.sa_family;
- addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
- }
- else
- addrp = &source->in.sin_addr;
- }
-
- opt->scope_netmask = 0;
- len = 0;
-
- if (opt->source_netmask != 0)
- {
-#ifdef HAVE_IPV6
- opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
-#else
- opt->family = htons(1);
-#endif
- len = ((opt->source_netmask - 1) >> 3) + 1;
- memcpy(opt->addr, addrp, len);
- if (opt->source_netmask & 7)
- opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
- }
-
- return len + 4;
-}
-
-size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source)
-{
- /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
-
- int len;
- struct subnet_opt opt;
-
- len = calc_subnet_opt(&opt, source);
- return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
-}
-
-#ifdef HAVE_DNSSEC
-size_t add_do_bit(struct dns_header *header, size_t plen, char *limit)
-{
- return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1);
-}
-#endif
-
-int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
-{
- /* Section 9.2, Check that subnet option in reply matches. */
-
-
- int len, calc_len;
- struct subnet_opt opt;
- unsigned char *p;
- int code, i, rdlen;
-
- calc_len = calc_subnet_opt(&opt, peer);
-
- if (!(p = skip_name(pseudoheader, header, plen, 10)))
- return 1;
-
- p += 8; /* skip UDP length and RCODE */
-
- GETSHORT(rdlen, p);
- if (!CHECK_LEN(header, p, plen, rdlen))
- return 1; /* bad packet */
-
- /* check if option there */
- for (i = 0; i + 4 < rdlen; i += len + 4)
- {
- GETSHORT(code, p);
- GETSHORT(len, p);
- if (code == EDNS0_OPTION_CLIENT_SUBNET)
- {
- /* make sure this doesn't mismatch. */
- opt.scope_netmask = p[3];
- if (len != calc_len || memcmp(p, &opt, len) != 0)
- return 0;
- }
- p += len;
- }
-
- return 1;
-}
-
/* is addr in the non-globally-routed IP space? */
int private_net(struct in_addr addr, int ban_localhost)
{