Commit ed4c0767 authored by Simon Kelley's avatar Simon Kelley

--add-subnet option.

parent 043c271f
...@@ -132,6 +132,9 @@ version 2.67 ...@@ -132,6 +132,9 @@ version 2.67
Update Spanish transalation. Thanks to Vicente Soriano. Update Spanish transalation. Thanks to Vicente Soriano.
Add --add-subnet configuration, to tell upstream DNS
servers where the original client is.
version 2.66 version 2.66
Add the ability to act as an authoritative DNS Add the ability to act as an authoritative DNS
......
...@@ -543,7 +543,20 @@ server. The MAC address can only be added if the requestor is on the same ...@@ -543,7 +543,20 @@ server. The MAC address can only be added if the requestor is on the same
subnet as the dnsmasq server. Note that the mechanism used to achieve this (an EDNS0 option) subnet as the dnsmasq server. Note that the mechanism used to achieve this (an EDNS0 option)
is not yet standardised, so this should be considered is not yet standardised, so this should be considered
experimental. Also note that exposing MAC addresses in this way may experimental. Also note that exposing MAC addresses in this way may
have security and privacy implications. have security and privacy implications. The warning about caching
given for --add-subnet applies to --add-mac too.
.TP
.B --add-subnet[[=<IPv4 prefix length>],<IPv6 prefix length>]
Add the subnet address of the requestor to the DNS queries which are
forwarded upstream. The amount of the address forwarded depends on the
prefix length parameter: 32 (128 for IPv6) forwards the whole address,
zero forwards none of it but still marks the request so that no
upstream nameserver will add client address information either. The
default is zero for both IPv4 and IPv6. Note that upstream nameservers
may be configured to return different results based on this
information, but the dnsmasq cache does not take account. If a dnsmasq
instance is configured such that different results may be encountered,
caching should be disabled.
.TP .TP
.B \-c, --cache-size=<cachesize> .B \-c, --cache-size=<cachesize>
Set the size of dnsmasq's cache. The default is 150 names. Setting the cache size to zero disables caching. Set the size of dnsmasq's cache. The default is 150 names. Setting the cache size to zero disables caching.
......
...@@ -39,7 +39,6 @@ ...@@ -39,7 +39,6 @@
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */ #define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
#define LOG_MAX 5 /* log-queue length */ #define LOG_MAX 5 /* log-queue length */
#define RANDFILE "/dev/urandom" #define RANDFILE "/dev/urandom"
#define EDNS0_OPTION_MAC 5 /* dyndns.org temporary assignment */
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* Default - may be overridden by config */ #define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* Default - may be overridden by config */
#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq" #define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
#define AUTH_TTL 600 /* default TTL for auth DNS */ #define AUTH_TTL 600 /* default TTL for auth DNS */
......
...@@ -56,6 +56,10 @@ ...@@ -56,6 +56,10 @@
#define T_MAILB 253 #define T_MAILB 253
#define T_ANY 255 #define T_ANY 255
#define EDNS0_OPTION_MAC 65001 /* dyndns.org temporary assignment */
#define EDNS0_OPTION_CLIENT_SUBNET 5 /* IANA */
struct dns_header { struct dns_header {
u16 id; u16 id;
u8 hb3,hb4; u8 hb3,hb4;
......
...@@ -222,7 +222,8 @@ struct event_desc { ...@@ -222,7 +222,8 @@ struct event_desc {
#define OPT_CLEVERBIND 39 #define OPT_CLEVERBIND 39
#define OPT_TFTP 40 #define OPT_TFTP 40
#define OPT_FAST_RA 41 #define OPT_FAST_RA 41
#define OPT_LAST 42 #define OPT_CLIENT_SUBNET 42
#define OPT_LAST 43
/* extra flags for my_syslog, we use a couple of facilities since they are known /* extra flags for my_syslog, we use a couple of facilities since they are known
not to occupy the same bits as priorities, no matter how syslog.h is set up. */ not to occupy the same bits as priorities, no matter how syslog.h is set up. */
...@@ -487,6 +488,7 @@ struct hostsfile { ...@@ -487,6 +488,7 @@ struct hostsfile {
#define FREC_NOREBIND 1 #define FREC_NOREBIND 1
#define FREC_CHECKING_DISABLED 2 #define FREC_CHECKING_DISABLED 2
#define FREC_HAS_SUBNET 4
struct frec { struct frec {
union mysockaddr source; union mysockaddr source;
...@@ -802,6 +804,8 @@ extern struct daemon { ...@@ -802,6 +804,8 @@ extern struct daemon {
struct auth_zone *auth_zones; struct auth_zone *auth_zones;
struct interface_name *int_names; struct interface_name *int_names;
char *mxtarget; char *mxtarget;
int addr4_netmask;
int addr6_netmask;
char *lease_file; char *lease_file;
char *username, *groupname, *scriptuser; char *username, *groupname, *scriptuser;
char *luascript; char *luascript;
...@@ -962,6 +966,8 @@ unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff); ...@@ -962,6 +966,8 @@ unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
size_t resize_packet(struct dns_header *header, size_t plen, size_t resize_packet(struct dns_header *header, size_t plen,
unsigned char *pheader, size_t hlen); unsigned char *pheader, size_t hlen);
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3); 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);
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 add_resource_record(struct dns_header *header, char *limit, int *truncp,
int nameoffset, unsigned char **pp, unsigned long ttl, int nameoffset, unsigned char **pp, unsigned long ttl,
int *offset, unsigned short type, unsigned short class, char *format, ...); int *offset, unsigned short type, unsigned short class, char *format, ...);
......
...@@ -284,6 +284,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, ...@@ -284,6 +284,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
forward->fd = udpfd; forward->fd = udpfd;
forward->crc = crc; forward->crc = crc;
forward->forwardall = 0; forward->forwardall = 0;
forward->flags = 0;
if (norebind) if (norebind)
forward->flags |= FREC_NOREBIND; forward->flags |= FREC_NOREBIND;
if (header->hb4 & HB4_CD) if (header->hb4 & HB4_CD)
...@@ -331,6 +332,16 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, ...@@ -331,6 +332,16 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
if (option_bool(OPT_ADD_MAC)) if (option_bool(OPT_ADD_MAC))
plen = add_mac(header, plen, ((char *) header) + PACKETSZ, &forward->source); 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) while (1)
{ {
/* only send to servers dealing with our domain. /* only send to servers dealing with our domain.
...@@ -435,8 +446,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, ...@@ -435,8 +446,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
return 0; return 0;
} }
static size_t process_reply(struct dns_header *header, time_t now, static size_t process_reply(struct dns_header *header, time_t now, struct server *server, size_t n, int check_rebind,
struct server *server, size_t n, int check_rebind, int checking_disabled) int checking_disabled, int check_subnet, union mysockaddr *query_source)
{ {
unsigned char *pheader, *sizep; unsigned char *pheader, *sizep;
char **sets = 0; char **sets = 0;
...@@ -465,19 +476,29 @@ static size_t process_reply(struct dns_header *header, time_t now, ...@@ -465,19 +476,29 @@ static size_t process_reply(struct dns_header *header, time_t now,
than we allow, trim it so that we don't get overlarge than we allow, trim it so that we don't get overlarge
requests for the client. We can't do this for signed packets. */ 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; if (!is_sign)
unsigned char *psave = sizep; {
unsigned short udpsz;
unsigned char *psave = sizep;
GETSHORT(udpsz, sizep);
if (udpsz > daemon->edns_pktsz)
PUTSHORT(daemon->edns_pktsz, psave);
}
GETSHORT(udpsz, sizep); if (check_subnet && !check_source(header, plen, pheader, query_source))
if (udpsz > daemon->edns_pktsz) {
PUTSHORT(daemon->edns_pktsz, psave); my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
return 0;
}
} }
/* RFC 4035 sect 4.6 para 3 */ /* RFC 4035 sect 4.6 para 3 */
if (!is_sign && !option_bool(OPT_DNSSEC)) 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)) if (OPCODE(header) != QUERY || (RCODE(header) != NOERROR && RCODE(header) != NXDOMAIN))
return n; return n;
...@@ -632,7 +653,8 @@ void reply_query(int fd, int family, time_t now) ...@@ -632,7 +653,8 @@ void reply_query(int fd, int family, time_t now)
if (!option_bool(OPT_NO_REBIND)) if (!option_bool(OPT_NO_REBIND))
check_rebind = 0; 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->id = htons(forward->orig_id);
header->hb4 |= HB4_RA; /* recursion if available */ header->hb4 |= HB4_RA; /* recursion if available */
...@@ -876,7 +898,7 @@ unsigned char *tcp_request(int confd, time_t now, ...@@ -876,7 +898,7 @@ unsigned char *tcp_request(int confd, time_t now,
{ {
size_t size = 0; size_t size = 0;
int norebind = 0; int norebind = 0;
int checking_disabled; int checking_disabled, check_subnet;
size_t m; size_t m;
unsigned short qtype; unsigned short qtype;
unsigned int gotname; unsigned int gotname;
...@@ -906,6 +928,8 @@ unsigned char *tcp_request(int confd, time_t now, ...@@ -906,6 +928,8 @@ unsigned char *tcp_request(int confd, time_t now,
if (size < (int)sizeof(struct dns_header)) if (size < (int)sizeof(struct dns_header))
continue; continue;
check_subnet = 0;
/* save state of "cd" flag in query */ /* save state of "cd" flag in query */
checking_disabled = header->hb4 & HB4_CD; checking_disabled = header->hb4 & HB4_CD;
...@@ -955,7 +979,17 @@ unsigned char *tcp_request(int confd, time_t now, ...@@ -955,7 +979,17 @@ unsigned char *tcp_request(int confd, time_t now,
if (option_bool(OPT_ADD_MAC)) if (option_bool(OPT_ADD_MAC))
size = add_mac(header, size, ((char *) header) + 65536, &peer_addr); 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) if (gotname)
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind); flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
...@@ -1056,7 +1090,8 @@ unsigned char *tcp_request(int confd, time_t now, ...@@ -1056,7 +1090,8 @@ unsigned char *tcp_request(int confd, time_t now,
sending replies containing questions and bogus answers. */ sending replies containing questions and bogus answers. */
if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff)) if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff))
m = process_reply(header, now, last_server, (unsigned int)m, 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; break;
} }
......
...@@ -134,6 +134,7 @@ struct myoption { ...@@ -134,6 +134,7 @@ struct myoption {
#endif #endif
#define LOPT_FAST_RA 322 #define LOPT_FAST_RA 322
#define LOPT_RELAY 323 #define LOPT_RELAY 323
#define LOPT_ADD_SBNET 324
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
static const struct option opts[] = static const struct option opts[] =
...@@ -251,6 +252,7 @@ static const struct myoption opts[] = ...@@ -251,6 +252,7 @@ static const struct myoption opts[] =
{ "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES }, { "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES },
{ "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND }, { "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND },
{ "add-mac", 0, 0, LOPT_ADD_MAC }, { "add-mac", 0, 0, LOPT_ADD_MAC },
{ "add-subnet", 2, 0, LOPT_ADD_SBNET },
{ "proxy-dnssec", 0, 0, LOPT_DNSSEC }, { "proxy-dnssec", 0, 0, LOPT_DNSSEC },
{ "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR }, { "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR },
{ "conntrack", 0, 0, LOPT_CONNTRACK }, { "conntrack", 0, 0, LOPT_CONNTRACK },
...@@ -397,6 +399,7 @@ static struct { ...@@ -397,6 +399,7 @@ static struct {
{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL }, { LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
{ LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL }, { LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
{ LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL }, { LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
{ LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add requestor's IP subnet to forwarded DNS queries."), NULL },
{ LOPT_DNSSEC, OPT_DNSSEC, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL }, { LOPT_DNSSEC, OPT_DNSSEC, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
{ LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL }, { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
{ LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL }, { LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
...@@ -1424,6 +1427,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -1424,6 +1427,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
break; break;
} }
case LOPT_ADD_SBNET: /* --add-subnet */
set_option_bool(OPT_CLIENT_SUBNET);
if (arg)
{
comma = split(arg);
if (!atoi_check(arg, &daemon->addr4_netmask) ||
(comma && !atoi_check(comma, &daemon->addr6_netmask)))
ret_err(gen_err);
}
break;
case '1': /* --enable-dbus */ case '1': /* --enable-dbus */
set_option_bool(OPT_DBUS); set_option_bool(OPT_DBUS);
if (arg) if (arg)
......
...@@ -513,46 +513,30 @@ struct macparm { ...@@ -513,46 +513,30 @@ struct macparm {
size_t plen; size_t plen;
union mysockaddr *l3; union mysockaddr *l3;
}; };
static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
{
struct macparm *parm = parmv;
int match = 0;
unsigned short rdlen;
struct dns_header *header = parm->header;
unsigned char *lenp, *datap, *p;
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) static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
return 1; /* continue */ int optno, unsigned char *opt, size_t optlen)
{
unsigned char *lenp, *datap, *p;
int rdlen;
if (ntohs(header->arcount) == 0) if (ntohs(header->arcount) == 0)
{ {
/* We are adding the pseudoheader */ /* We are adding the pseudoheader */
if (!(p = skip_questions(header, parm->plen)) || if (!(p = skip_questions(header, plen)) ||
!(p = skip_section(p, !(p = skip_section(p,
ntohs(header->ancount) + ntohs(header->nscount), ntohs(header->ancount) + ntohs(header->nscount),
header, parm->plen))) header, plen)))
return 0; return plen;
*p++ = 0; /* empty name */ *p++ = 0; /* empty name */
PUTSHORT(T_OPT, p); PUTSHORT(T_OPT, p);
PUTSHORT(PACKETSZ, p); /* max packet length - is 512 suitable default for non-EDNS0 resolvers? */ PUTSHORT(daemon->edns_pktsz, p); /* max packet length */
PUTLONG(0, p); /* extended RCODE */ PUTLONG(0, p); /* extended RCODE */
lenp = p; lenp = p;
PUTSHORT(0, p); /* RDLEN */ PUTSHORT(0, p); /* RDLEN */
rdlen = 0; rdlen = 0;
if (((ssize_t)maclen) > (parm->limit - (p + 4))) if (((ssize_t)optlen) > (limit - (p + 4)))
return 0; /* Too big */ return plen; /* Too big */
header->arcount = htons(1); header->arcount = htons(1);
datap = p; datap = p;
} }
...@@ -562,17 +546,17 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p ...@@ -562,17 +546,17 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
unsigned short code, len; unsigned short code, len;
if (ntohs(header->arcount) != 1 || if (ntohs(header->arcount) != 1 ||
!(p = find_pseudoheader(header, parm->plen, NULL, NULL, &is_sign)) || !(p = find_pseudoheader(header, plen, NULL, NULL, &is_sign)) ||
is_sign || is_sign ||
(!(p = skip_name(p, header, parm->plen, 10)))) (!(p = skip_name(p, header, plen, 10))))
return 0; return plen;
p += 8; /* skip UDP length and RCODE */ p += 8; /* skip UDP length and RCODE */
lenp = p; lenp = p;
GETSHORT(rdlen, p); GETSHORT(rdlen, p);
if (!CHECK_LEN(header, p, parm->plen, rdlen)) if (!CHECK_LEN(header, p, plen, rdlen))
return 0; /* bad packet */ return plen; /* bad packet */
datap = p; datap = p;
/* check if option already there */ /* check if option already there */
...@@ -580,27 +564,49 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p ...@@ -580,27 +564,49 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
{ {
GETSHORT(code, p); GETSHORT(code, p);
GETSHORT(len, p); GETSHORT(len, p);
if (code == EDNS0_OPTION_MAC) if (code == optno)
return 0; return plen;
p += len; p += len;
} }
if (((ssize_t)maclen) > (parm->limit - (p + 4))) if (((ssize_t)optlen) > (limit - (p + 4)))
return 0; /* Too big */ return plen; /* Too big */
} }
PUTSHORT(EDNS0_OPTION_MAC, p); PUTSHORT(optno, p);
PUTSHORT(maclen, p); PUTSHORT(optlen, p);
memcpy(p, mac, maclen); memcpy(p, opt, optlen);
p += maclen; p += optlen;
PUTSHORT(p - datap, lenp); PUTSHORT(p - datap, lenp);
parm->plen = p - (unsigned char *)header; 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, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen);
return 0; /* done */ return 0; /* done */
} }
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3) size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
{ {
struct macparm parm; struct macparm parm;
...@@ -621,7 +627,102 @@ size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysock ...@@ -621,7 +627,102 @@ size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysock
return parm.plen; return parm.plen;
} }
struct subnet_opt {
u16 family;
u8 source_netmask, scope_netmask;
#ifdef HAVE_IPV6
u8 addr[IN6ADDRSZ];
#else
u8 addr[INADDRSZ];
#endif
};
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;
if (source->sa.sa_family == AF_INET)
{
opt->family = htons(1);
opt->source_netmask = daemon->addr4_netmask;
addrp = &source->in.sin_addr;
}
#ifdef HAVE_IPV6
else
{
opt->family = htons(2);
opt->source_netmask = daemon->addr6_netmask;
addrp = &source->in6.sin6_addr;
}
#endif
opt->scope_netmask = 0;
len = 0;
if (opt->source_netmask != 0)
{
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, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len);
}
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? */ /* is addr in the non-globally-routed IP space? */
static int private_net(struct in_addr addr, int ban_localhost) static int private_net(struct in_addr addr, int ban_localhost)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment