Commit Diff
Diff:
b6b96cfd7986f47f86aac38ac4a887c26d865a66
10133795a114a1387b2e7dbde3c41bc2581628c4
Commit:
10133795a114a1387b2e7dbde3c41bc2581628c4
Tree:
50e609c8b3df18a8b90b70191cab2cd07bc3fff7
Author:
pbug <pbug@delphinusdns.org>
Committer:
pbug <pbug@delphinusdns.org>
Date:
Sat Mar 27 10:25:03 2010 UTC
Message:
* allow region determination for IPv6 as well, this doesn't do split horizon for AAAA yet though. I have a nameserver that occasionally gets a query through a IPv6 source, this allows the region to be determined for this query. * a sample example4.conf file with IPv6 netblocks
blob - /dev/null
blob + e3274b37bf6f2afc87518d6469d2c2bbc350db04 (mode 644)
--- /dev/null
+++ example4.conf
@@ -0,0 +1,69 @@
+; sample config file that is in production.
+;
+version "2";
+
+; this is for the host dione.centroid.eu which is in Panama
+; it serves best for the Americas and Australia (?)
+
+region "LACNIC" {
+ 192.168.0.0/16;
+ 2001:A60:F074::/64;
+ ; arin below
+ 2001:0400::/23;
+ 2001:1800::/23;
+ 2001:4800::/23;
+ 2600:0000::/12;
+ 2610:0000::/23;
+ 2620:0000::/23;
+ ; lacnic
+ 2001:1200::/23;
+ 2800:0000::/12;
+}
+region "RIPE" {
+ ;
+ ; for RIPE we'll just put the prefix 0.0.0.0/0
+ ; this should work because the higher the prefix the more
+ ; precedence the region has, let's give it a shot.
+ ;
+ 0.0.0.0/0;
+ ::/0;
+ ; RIPE
+ 2001:0600::/23;
+ 2001:0800::/23;
+ 2001:0A00::/23;
+ 2001:1400::/23;
+ 2001:1600::/23;
+ 2001:1A00::/23;
+ 2001:1C00::/22;
+ 2001:2000::/20;
+ 2001:3000::/21;
+ 2001:3800::/22;
+ 2001:4000::/23;
+ 2001:4600::/23;
+ 2001:4A00::/23;
+ 2001:4C00::/23;
+ 2001:5000::/20;
+ 2003:0000::/18;
+ 2A00:0000::/12;
+ ; APNIC
+ 2001:0200::/23;
+ 2001:0C00::/23;
+ 2001:0E00::/23;
+ 2001:4400::/23;
+ 2001:8000::/19;
+ 2001:A000::/20;
+ 2001:B000::/20;
+ 2400:0000::/12;
+ ; AfriNIC
+ 2001:4200::/23;
+ 2C00:0000::/12;
+}
+zone "centroid.eu" {
+ centroid.eu,soa,3600,uranus.centroid.eu.,pjp.solarscale.de.,1258740680,3600,1800,7200,3600
+ centroid.eu,ns,3600,proteus.solarscale.de.
+ centroid.eu,ns,3600,uranus.centroid.eu.
+ centroid.eu,ns,3600,dione.solarscale.de.
+ ; balance these two
+ centroid.eu,balance,3600,62.75.160.180
+ centroid.eu,balance,3600,192.168.0.24
+}
blob - 790bce02cc7c565c15a1e72d5e34ffcda96b1fe2
blob + c8ce2bf2fd2c401817bc227e9b2c381f13479173
--- main.c
+++ main.c
@@ -49,7 +49,7 @@ extern void reply_ptr(struct sreply *);
extern void reply_cname(struct sreply *);
extern void reply_mx(struct sreply *, DB *);
extern void reply_ns(struct sreply *, DB *);
-extern u_int8_t find_region(in_addr_t);
+extern u_int8_t find_region(struct sockaddr_storage *sst, int family);
extern void collects_init(void);
char * dns_label(char *, int *);
@@ -103,7 +103,7 @@ struct tcps {
} *tn1, *tn2, *tnp;
-static const char rcsid[] = "$Id: main.c,v 1.43 2010/03/22 14:45:21 pbug Exp $";
+static const char rcsid[] = "$Id: main.c,v 1.44 2010/03/27 10:25:18 pbug Exp $";
/*
* MAIN - set up arguments, set up database, set up sockets, call mainloop
@@ -1466,13 +1466,14 @@ mainloop(int *udp, int *tcp, int sockcount, char **ide
fromlen = sizeof(struct sockaddr_in6);
sin6 = (struct sockaddr_in6 *)from;
inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, (char *)&address, sizeof(address));
+ aregion = find_region((struct sockaddr_storage *)sin6, AF_INET6);
} else if (from->sa_family == AF_INET) {
is_ipv6 = 0;
fromlen = sizeof(struct sockaddr_in);
sin = (struct sockaddr_in *)from;
inet_ntop(AF_INET, (void *)&sin->sin_addr, (char *)&address, sizeof(address));
- aregion = find_region(sin->sin_addr.s_addr);
+ aregion = find_region((struct sockaddr_storage *)sin, AF_INET);
} else {
syslog(LOG_INFO, "TCP packet received on descriptor %u interface \"%s\" had weird address family (%u), drop", so, ident[i], from->sa_family);
close(so);
@@ -1910,13 +1911,14 @@ tcpnxdomain:
fromlen = sizeof(struct sockaddr_in6);
sin6 = (struct sockaddr_in6 *)from;
inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, (char *)&address, sizeof(address));
+ aregion = find_region((struct sockaddr_storage *)sin6, AF_INET6);
} else if (from->sa_family == AF_INET) {
is_ipv6 = 0;
fromlen = sizeof(struct sockaddr_in);
sin = (struct sockaddr_in *)from;
inet_ntop(AF_INET, (void *)&sin->sin_addr, (char *)&address, sizeof(address));
- aregion = find_region(sin->sin_addr.s_addr);
+ aregion = find_region((struct sockaddr_storage *)sin, AF_INET);
} else {
syslog(LOG_INFO, "packet received on descriptor %u interface \"%s\" had weird address family (%u), drop", so, ident[i], from->sa_family);
goto drop;
blob - 8c4e6b17db1a512465ede4ca046f5aa87df69a39
blob + 90003d3a535eed13cbc00b9593b44efa8126f4f0
--- parse.c
+++ parse.c
@@ -30,9 +30,9 @@
#include "db.h"
extern char * dns_label(char *, int *);
-extern u_int8_t find_region(in_addr_t *);
+extern u_int8_t find_region(struct sockaddr_storage *sst, int family);
extern void init_region(void);
-extern void insert_region(char *address, char *prefix, u_int8_t region);
+extern int insert_region(char *address, char *prefix, u_int8_t region);
struct myrr_lookup {
char *name;
@@ -73,7 +73,7 @@ struct cmd_lookup {
static u_int32_t config = 0;
-static const char rcsid[] = "$Id: parse.c,v 1.18 2010/03/18 08:55:13 pbug Exp $";
+static const char rcsid[] = "$Id: parse.c,v 1.19 2010/03/27 10:25:20 pbug Exp $";
/*
* PARSE_FILE - parse the configfile XXX rewrite me in yacc :(
@@ -114,6 +114,7 @@ parse_file(DB *db, char *file)
struct in6_addr *ia6;
struct stat sb, sb0;
struct dirent *dp;
+ struct sockaddr_in sin;
fd = open(file, O_RDONLY, 0);
if (fd < 0) {
@@ -495,7 +496,9 @@ parse_file(DB *db, char *file)
if ((*ia = inet_addr(starttoken)) == INADDR_ANY)
sdomain.a_count--;
- region = find_region((in_addr_t *)*ia);
+ sin.sin_addr.s_addr = *ia;
+ sin.sin_family = AF_INET;
+ region = find_region((struct sockaddr_storage *)&sin, AF_INET);
sdomain.region[sdomain.a_count - 1] = region;
@@ -949,7 +952,11 @@ skip:
}
*p = '\0';
- insert_region(address, starttoken, region);
+ if (insert_region(address, starttoken, region) < 0) {
+ syslog(LOG_INFO, "address on line %d, is malformed", line);
+ fclose(f);
+ return (-1);
+ }
} /* CONFIG_REGION */
loop:
blob - 387c4cf23356f6414d8ade534dd56550961e1e93
blob + 8145315e7a7b76c9fcb705fe78e25e06bc5c61bb
--- region.c
+++ region.c
@@ -29,25 +29,31 @@
#include "dns.h"
#include "db.h"
-u_int8_t find_region(in_addr_t);
+u_int8_t find_region(struct sockaddr_storage *sst, int family);
void init_region(void);
-void insert_region(char *address, char *prefix, u_int8_t region);
-in_addr_t getmask(int prefix);
+int insert_region(char *address, char *prefixlen, u_int8_t region);
+in_addr_t getmask(int prefixlen);
+int getmask6(int prefixlen, struct sockaddr_in6 *sin6);
SLIST_HEAD(listhead, entry) head;
struct entry {
- char name[INET_ADDRSTRLEN];
- in_addr_t hostmask;
- in_addr_t netmask;
+ char name[INET6_ADDRSTRLEN];
+ int family;
+ struct sockaddr_storage hostmask;
+ struct sockaddr_storage netmask;
u_int8_t region;
- u_int8_t prefix;
+ u_int8_t prefixlen;
SLIST_ENTRY(entry) entries;
} *n1, *n2, *np;
-static const char rcsid[] = "$Id: region.c,v 1.3 2010/03/09 15:48:35 pbug Exp $";
+static const char rcsid[] = "$Id: region.c,v 1.4 2010/03/27 10:25:20 pbug Exp $";
+/*
+ * INIT_REGION - initialize the region singly linked list
+ */
+
void
init_region(void)
{
@@ -55,58 +61,189 @@ init_region(void)
return;
}
-void
-insert_region(char *address, char *prefix, u_int8_t region)
+/*
+ * INSERT_REGION - insert particular address and prefix length and region
+ * into the
+ * singly linked list at "head", if the address contains
+ * a colon then it is assumed to be an IPv6 address.
+ * return -1 on error, 0 on successful insertion
+ */
+
+int
+insert_region(char *address, char *prefixlen, u_int8_t region)
{
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
int pnum;
-
- pnum = atoi(prefix);
+ int ret;
+ pnum = atoi(prefixlen);
n2 = malloc(sizeof(struct entry)); /* Insert after. */
- n2->hostmask = inet_addr(address);
- n2->netmask = getmask(pnum);
- n2->region = region;
- n2->prefix = pnum;
+ if (strchr(address, ':') != NULL) {
+ n2->family = AF_INET6;
+ sin6 = (struct sockaddr_in6 *)&n2->hostmask;
+ if ((ret = inet_pton(AF_INET6, address, &sin6->sin6_addr.s6_addr)) != 1)
+ return (-1);
+ sin6->sin6_family = AF_INET6;
+ sin6 = (struct sockaddr_in6 *)&n2->netmask;
+ sin6->sin6_family = AF_INET6;
+ if (getmask6(pnum, sin6) < 0)
+ return(-1);
+ n2->region = region;
+ n2->prefixlen = pnum;
+ } else {
+ n2->family = AF_INET;
+ sin = (struct sockaddr_in *)&n2->hostmask;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = inet_addr(address);
+ sin = (struct sockaddr_in *)&n2->netmask;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = getmask(pnum);
+ n2->region = region;
+ n2->prefixlen = pnum;
+
+ }
+
SLIST_INSERT_HEAD(&head, n2, entries);
+
+ return (0);
}
/*
* FIND_REGION - walk the region list and find the correponding network with
- * the highest prefix, so that a /24 has more precedence than
- * a /8 for example.
+ * the highest prefix length, so that a /24 has more precedence
+ * than
+ * a /8 for example. IPv6 and IPv4 addresses are kept seperate
*/
u_int8_t
-find_region(in_addr_t address)
+find_region(struct sockaddr_storage *sst, int family)
{
+ struct sockaddr_in *sin, *sin0;
+ struct sockaddr_in6 *sin6, *sin60, *sin61;
u_int32_t hostmask, netmask;
- u_int32_t a = address;
+ u_int32_t a;
+#ifdef __amd64
+ u_int64_t *hm[2], *nm[2], *a6[2];
+#else
+ u_int32_t *hm[4], *nm[4], *a6[4];
+#endif
u_int8_t region = 0xff;
- u_int8_t prefix = 0;
+ u_int8_t prefixlen = 0;
SLIST_FOREACH(np, &head, entries) {
- hostmask = np->hostmask;
- netmask = np->netmask;
- if ((hostmask & netmask) == (a & netmask)) {
- if (np->prefix >= prefix) {
- region = np->region;
- prefix = np->prefix;
- }
- } /* if hostmask */
+ if (np->family == AF_INET) {
+ if (family != AF_INET)
+ continue;
+ sin = (struct sockaddr_in *)sst;
+ a = sin->sin_addr.s_addr;
+ sin = (struct sockaddr_in *)&np->hostmask;
+ sin0 = (struct sockaddr_in *)&np->netmask;
+ hostmask = sin->sin_addr.s_addr;
+ netmask = sin0->sin_addr.s_addr;
+ if ((hostmask & netmask) == (a & netmask)) {
+ if (np->prefixlen >= prefixlen) {
+ region = np->region;
+ prefixlen = np->prefixlen;
+ }
+ } /* if hostmask */
+ } else if (np->family == AF_INET6) {
+ if (family != AF_INET6)
+ continue;
+ sin6 = (struct sockaddr_in6 *)sst;
+ sin60 = (struct sockaddr_in6 *)&np->hostmask;
+ sin61 = (struct sockaddr_in6 *)&np->netmask;
+#ifdef __amd64
+ /*
+ * If this is on a 64 bit machine, we'll benefit
+ * by using 64 bit registers, this should make it
+ * a tad faster...
+ */
+ hm[0] = (u_int64_t *)&sin60->sin6_addr.s6_addr;
+ hm[1] = (hm[0] + 1);
+ nm[0] = (u_int64_t *)&sin61->sin6_addr.s6_addr;
+ nm[1] = (nm[0] + 1);
+ a6[0] = (u_int64_t *)&sin6->sin6_addr.s6_addr;
+ a6[1] = (a6[0] + 1);
+ if ( ((*hm[0] & *nm[0]) == (*a6[0] & *nm[0]))&&
+ ((*hm[1] & *nm[1]) == (*a6[1] & *nm[1]))) {
+#else
+ hm[0] = (u_int32_t *)&sin60->sin6_addr.s6_addr;
+ hm[1] = (hm[0] + 1); hm[2] = (hm[1] + 1);
+ hm[3] = (hm[2] + 1);
+ nm[0] = (u_int32_t *)&sin61->sin6_addr.s6_addr;
+ nm[1] = (nm[0] + 1); nm[2] = (nm[1] + 1);
+ nm[3] = (nm[2] + 1);
+ a6[0] = (u_int32_t *)&sin6->sin6_addr.s6_addr;
+ a6[1] = (a6[0] + 1); a6[2] = (a6[1] + 1);
+ a6[3] = (a6[2] + 1);
+ if ( ((*hm[0] & *nm[0]) == (*a6[0] & *nm[0]))&&
+ ((*hm[1] & *nm[1]) == (*a6[1] & *nm[1]))&&
+ ((*hm[2] & *nm[2]) == (*a6[2] & *nm[2]))&&
+ ((*hm[3] & *nm[3]) == (*a6[3] & *nm[3]))) {
+#endif
+
+ if (np->prefixlen >= prefixlen) {
+ region = np->region;
+ prefixlen = np->prefixlen;
+ }
+ } /* if ip6 address */
+
+ } /* if AF_INET6 */
} /* SLIST */
return (region);
}
+/*
+ * GETMASK - get the v4 netmask given by prefix length, return netmask in
+ * network byte order, function can't fail unless prefix length
+ * supplied is > 32
+ */
+
in_addr_t
-getmask(int prefix)
+getmask(int prefixlen)
{
in_addr_t ret = 0xffffffff;
- ret >>= prefix; /* 0x00ffffff */
+ ret >>= prefixlen; /* 0x00ffffff */
ret = ~ret; /* 0xff000000 */
return (htonl(ret));
+}
+
+/*
+ * GETMASK6 - like getmask() but works on a supplied sockaddr_in6 instead of
+ * returning results as return address. Function cannot fail
+ * unless prefix length supplied is > 128. At which point a buffer
+ * overflow is possible.
+ */
+
+int
+getmask6(int prefixlen, struct sockaddr_in6 *sin6)
+{
+ int i, j;
+ u_int32_t *nm[4];
+
+ if (prefixlen > 128 || prefixlen < 0)
+ return (-1);
+
+ memset(&sin6->sin6_addr.s6_addr, 0xff, sizeof(sin6->sin6_addr.s6_addr));
+ nm[0] = (u_int32_t *)sin6->sin6_addr.s6_addr;
+ nm[1] = (nm[0] + 1); nm[2] = (nm[1] + 1);
+ nm[3] = (nm[2] + 1);
+
+ for (i = 0, j = 0; j < prefixlen; j++) {
+ *nm[i] >>= 1;
+ if (*nm[i] == 0)
+ i++;
+ }
+ *nm[0] = htonl(~ *nm[0]);
+ *nm[1] = htonl(~ *nm[1]);
+ *nm[2] = htonl(~ *nm[2]);
+ *nm[3] = htonl(~ *nm[3]);
+
+ return (0);
}
repomaster@centroid.eu