diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 8cd52c42..a4626227 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -106,25 +106,15 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*; {include} { if(cf_open_hook) new_include(); } {DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ { -#ifdef IPV6 - if (ipv4_pton_u32(yytext, &cf_lval.i32)) - return RTRID; + if (ip4_pton(yytext, &cf_lval.a4)) + return IP4; cf_error("Invalid IPv4 address %s", yytext); -#else - if (ip_pton(yytext, &cf_lval.a)) - return IPA; - cf_error("Invalid IP address %s", yytext); -#endif } ({XIGIT}*::|({XIGIT}*:){3,})({XIGIT}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+) { -#ifdef IPV6 - if (ip_pton(yytext, &cf_lval.a)) - return IPA; - cf_error("Invalid IP address %s", yytext); -#else - cf_error("This is an IPv4 router, therefore IPv6 addresses are not supported"); -#endif + if (ip6_pton(yytext, &cf_lval.a6)) + return IP6; + cf_error("Invalid IPv6 address %s", yytext); } 0x{XIGIT}+ { diff --git a/conf/conf.c b/conf/conf.c index 13049be4..47a0c0c1 100644 --- a/conf/conf.c +++ b/conf/conf.c @@ -117,10 +117,11 @@ config_parse(struct config *c) protos_postconfig(c); if (EMPTY_LIST(c->protos)) cf_error("No protocol is specified in the config file"); -#ifdef IPV6 + + /* if (!c->router_id) - cf_error("Router ID must be configured manually on IPv6 routers"); -#endif + cf_error("Router ID must be configured manually"); + */ return 1; } diff --git a/conf/confbase.Y b/conf/confbase.Y index dcb0719f..088c1e4f 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -39,6 +39,8 @@ CF_DECLS int i; u32 i32; ip_addr a; + ip4_addr a4; + ip6_addr a6; struct symbol *s; char *t; struct rtable_config *r; @@ -67,14 +69,15 @@ CF_DECLS %token PO PC %token NUM ENUM %token RTRID -%token IPA +%token IP4 +%token IP6 %token SYM %token TEXT %type ipa_scope %type expr bool pxlen %type ipa +%type ipa ipa_raw %type prefix prefix_or_ipa %type text_or_none @@ -119,7 +122,7 @@ definition: cf_define_symbol($2, SYM_NUMBER, NULL); $2->aux = $4; } - | DEFINE SYM '=' IPA ';' { + | DEFINE SYM '=' ipa_raw ';' { cf_define_symbol($2, SYM_IPA, cfg_alloc(sizeof(ip_addr))); *(ip_addr *)$2->def = $4; } @@ -137,9 +140,15 @@ bool: ; /* Addresses, prefixes and netmasks */ +// XXXX check users + +ipa_raw: + IP4 { $$ = ipa_from_ip4($1); } + | IP6 { $$ = ipa_from_ip6($1); } + ; ipa: - IPA + ipa_raw | SYM { if ($1->class != SYM_IPA) cf_error("IP address expected"); $$ = *(ip_addr *)$1->def; diff --git a/configure.in b/configure.in index dd57ab51..2fa474a3 100644 --- a/configure.in +++ b/configure.in @@ -9,8 +9,6 @@ AC_CONFIG_AUX_DIR(tools) AC_ARG_ENABLE(debug, [ --enable-debug enable internal debugging routines (default: disabled)],,enable_debug=no) AC_ARG_ENABLE(memcheck, [ --enable-memcheck check memory allocations when debugging (default: enabled)],,enable_memcheck=yes) AC_ARG_ENABLE(client, [ --enable-client enable building of BIRD client (default: enabled)],,enable_client=yes) -AC_ARG_ENABLE(ipv6, [ --enable-ipv6 enable building of IPv6 version (default: disabled)],,enable_ipv6=no) -AC_ARG_WITH(suffix, [ --with-suffix=STRING use specified suffix for BIRD files (default: 6 for IPv6 version)],[given_suffix="yes"]) AC_ARG_WITH(sysconfig, [ --with-sysconfig=FILE use specified BIRD system configuration file]) AC_ARG_WITH(protocols, [ --with-protocols=LIST include specified routing protocols (default: all)],,[with_protocols="all"]) AC_ARG_WITH(sysinclude, [ --with-sysinclude=PATH search for system includes on specified place]) @@ -44,31 +42,19 @@ AC_SUBST(exedir) AC_SUBST(srcdir_rel_mf) AC_SUBST(runtimedir) -if test "$enable_ipv6" = yes ; then - ip=ipv6 - SUFFIX=6 - all_protocols=bgp,ospf,pipe,radv,rip,static -else - ip=ipv4 - SUFFIX="" - all_protocols=bgp,ospf,pipe,rip,static -fi - -if test "$given_suffix" = yes ; then - SUFFIX="$with_suffix" -fi -AC_SUBST(SUFFIX) +# all_protocols=bgp,ospf,pipe,radv,rip,static +all_protocols=pipe,radv,rip,static if test "$with_protocols" = all ; then with_protocols="$all_protocols" fi if test "$enable_debug" = yes ; then - CONFIG_FILE="bird$SUFFIX.conf" - CONTROL_SOCKET="bird$SUFFIX.ctl" + CONFIG_FILE="bird.conf" + CONTROL_SOCKET="bird.ctl" else - CONFIG_FILE="\$(sysconfdir)/bird$SUFFIX.conf" - CONTROL_SOCKET="$runtimedir/bird$SUFFIX.ctl" + CONFIG_FILE="\$(sysconfdir)/bird.conf" + CONTROL_SOCKET="$runtimedir/bird.ctl" fi AC_SUBST(CONFIG_FILE) AC_SUBST(CONTROL_SOCKET) @@ -123,32 +109,19 @@ if test -n "$with_sysconfig" -a "$with_sysconfig" != no ; then elif test -f sysconfig.h ; then sysdesc=sysconfig else - case "$ip:$host_os" in - ipv6:linux*) sysdesc=linux-v6 + case "$host_os" in + linux*) sysdesc=linux default_iproutedir="/etc/iproute2" ;; - ipv4:linux*) sysdesc=linux - default_iproutedir="/etc/iproute2" + freebsd*) sysdesc=bsd ;; - ipv6:netbsd*) sysdesc=bsd-v6 + kfreebsd*) sysdesc=bsd + ;; + netbsd*) sysdesc=bsd CPPFLAGS="$CPPFLAGS -I/usr/pkg/include" LDFLAGS="$LDFLAGS -L/usr/pkg/lib -R/usr/pkg/lib" ;; - ipv4:netbsd*) sysdesc=bsd - CPPFLAGS="$CPPFLAGS -I/usr/pkg/include" - LDFLAGS="$LDFLAGS -L/usr/pkg/lib -R/usr/pkg/lib" - ;; - ipv6:freebsd*) sysdesc=bsd-v6 - ;; - ipv4:freebsd*) sysdesc=bsd - ;; - ipv6:kfreebsd*) sysdesc=bsd-v6 - ;; - ipv4:kfreebsd*) sysdesc=bsd - ;; - ipv6:openbsd*) sysdesc=bsd-v6 - ;; - ipv4:openbsd*) sysdesc=bsd + openbsd*) sysdesc=bsd ;; *) AC_MSG_ERROR([Cannot determine correct system configuration. Please use --with-sysconfig to set it manually.]) ;; diff --git a/filter/config.Y b/filter/config.Y index 0eeb2ce1..ea4ca9d1 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -452,7 +452,7 @@ block: * Complex types, their bison value is struct f_val */ fipa: - IPA %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.px.ip = $1; } + ipa_raw %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.px.ip = $1; } ; @@ -541,7 +541,7 @@ switch_items: ; fprefix_s: - IPA '/' NUM %prec '/' { + ipa_raw '/' NUM %prec '/' { if (($3 < 0) || ($3 > MAX_PREFIX_LENGTH) || !ip_is_prefix($1, $3)) cf_error("Invalid network prefix: %I/%d.", $1, $3); $$.type = T_PREFIX; $$.val.px.ip = $1; $$.val.px.len = $3; } diff --git a/lib/Modules b/lib/Modules index c585c9a8..01c9db7f 100644 --- a/lib/Modules +++ b/lib/Modules @@ -3,13 +3,6 @@ bitops.c bitops.h ip.h ip.c -#ifdef IPV6 -ipv6.c -ipv6.h -#else -ipv4.c -ipv4.h -#endif lists.c lists.h md5.c diff --git a/lib/ip.c b/lib/ip.c index aa61553e..3c959fea 100644 --- a/lib/ip.c +++ b/lib/ip.c @@ -6,6 +6,8 @@ * Can be freely distributed and used under the terms of the GNU GPL. */ +#include + #include "nest/bird.h" #include "lib/ip.h" @@ -18,6 +20,318 @@ * they must be manipulated using the following functions and macros. */ + + +int +ip6_compare(ip6_addr a, ip6_addr b) +{ + int i; + for(i=0; i<4; i++) + if (a.addr[i] > b.addr[i]) + return 1; + else if (a.addr[i] < b.addr[i]) + return -1; + return 0; +} + +ip6_addr +ip6_mkmask(unsigned n) +{ + ip_addr a; + int i; + + for(i=0; i<4; i++) + { + if (!n) + a.addr[i] = 0; + else if (n >= 32) + { + a.addr[i] = ~0; + n -= 32; + } + else + { + a.addr[i] = u32_mkmask(n); + n = 0; + } + } + return a; +} + +unsigned +ip6_masklen(ip_addr *a) +{ + int i, j, n; + + for(i=0, n=0; i<4; i++, n+=32) + if (a->addr[i] != ~0U) + { + j = u32_masklen(a->addr[i]); + if (j < 0) + return j; + n += j; + while (++i < 4) + if (a->addr[i]) + return -1; + break; + } + return n; +} + +int +ip4_classify(ip4_addr ad) +{ + u32 a = _I(ad); + u32 b = a >> 24U; + + if (b && b <= 0xdf) + { + if (b == 0x7f) + return IADDR_HOST | SCOPE_HOST; + else if (b == 0x0a || + (a & 0xffff0000) == 0xc0a80000 || + (a & 0xfff00000) == 0xac100000) + return IADDR_HOST | SCOPE_SITE; + else + return IADDR_HOST | SCOPE_UNIVERSE; + } + if (b >= 0xe0 && b <= 0xef) + return IADDR_MULTICAST | SCOPE_UNIVERSE; + if (a == 0xffffffff) + return IADDR_BROADCAST | SCOPE_LINK; + return IADDR_INVALID; +} + +int +ip6_classify(ip6_addr *a) +{ + u32 x = a->addr[0]; + + if ((x & 0xe0000000) == 0x20000000) /* 2000::/3 Aggregatable Global Unicast Address */ + return IADDR_HOST | SCOPE_UNIVERSE; + if ((x & 0xffc00000) == 0xfe800000) /* fe80::/10 Link-Local Address */ + return IADDR_HOST | SCOPE_LINK; + if ((x & 0xffc00000) == 0xfec00000) /* fec0::/10 Site-Local Address */ + return IADDR_HOST | SCOPE_SITE; + if ((x & 0xfe000000) == 0xfc000000) /* fc00::/7 Unique Local Unicast Address (RFC 4193) */ + return IADDR_HOST | SCOPE_SITE; + if ((x & 0xff000000) == 0xff000000) /* ff00::/8 Multicast Address */ + { + unsigned int scope = (x >> 16) & 0x0f; + switch (scope) + { + case 1: return IADDR_MULTICAST | SCOPE_HOST; + case 2: return IADDR_MULTICAST | SCOPE_LINK; + case 5: return IADDR_MULTICAST | SCOPE_SITE; + case 8: return IADDR_MULTICAST | SCOPE_ORGANIZATION; + case 14: return IADDR_MULTICAST | SCOPE_UNIVERSE; + default: return IADDR_MULTICAST | SCOPE_UNDEFINED; + } + } + if (!x && !a->addr[1]) + { + u32 a2 = a->addr[2]; + u32 a3 = a->addr[3]; + if (a2 == 0 && a3 == 1) + return IADDR_HOST | SCOPE_HOST; /* Loopback address */ + if (a2 == 0) + return ip4_classify(_MI4(a3)); /* IPv4 compatible addresses */ + if (a2 == 0xffff) + return ip4_classify(_MI4(a3)); /* IPv4 mapped addresses */ + + return IADDR_INVALID; + } + + return IADDR_HOST | SCOPE_UNDEFINED; +} + + + + + + +/* + * Conversion of IPv6 address to presentation format and vice versa. + * Heavily inspired by routines written by Paul Vixie for the BIND project + * and of course by RFC 2373. + */ + + +char * +ip4_ntop(ip4_addr a, char *b) +{ + u32 x = _I(a); + return b + bsprintf(b, "%d.%d.%d.%d", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); +} + + +char * +ip6_ntop(ip6_addr a, char *b) +{ + u16 words[8]; + int bestpos, bestlen, curpos, curlen, i; + + /* First of all, preprocess the address and find the longest run of zeros */ + bestlen = bestpos = curpos = curlen = 0; + for(i=0; i<8; i++) + { + u32 x = a.addr[i/2]; + words[i] = ((i%2) ? x : (x >> 16)) & 0xffff; + if (words[i]) + curlen = 0; + else + { + if (!curlen) + curpos = i; + curlen++; + if (curlen > bestlen) + { + bestpos = curpos; + bestlen = curlen; + } + } + } + if (bestlen < 2) + bestpos = -1; + + /* Is it an encapsulated IPv4 address? */ + if (!bestpos && + (bestlen == 5 && a.addr[2] == 0xffff || + bestlen == 6)) + { + u32 x = a.addr[3]; + b += bsprintf(b, "::%s%d.%d.%d.%d", + a.addr[2] ? "ffff:" : "", + (x >> 24) & 0xff, + (x >> 16) & 0xff, + (x >> 8) & 0xff, + x & 0xff); + return b; + } + + /* Normal IPv6 formatting, compress the largest sequence of zeros */ + for(i=0; i<8; i++) + { + if (i == bestpos) + { + i += bestlen - 1; + *b++ = ':'; + if (i == 7) + *b++ = ':'; + } + else + { + if (i) + *b++ = ':'; + b += bsprintf(b, "%x", words[i]); + } + } + *b = 0; + return b; +} + +int +ip4_pton(char *a, ip4_addr *o) +{ + int i; + unsigned long int l; + u32 ia = 0; + + i=4; + while (i--) + { + char *d, *c = strchr(a, '.'); + if (!c != !i) + return 0; + l = strtoul(a, &d, 10); + if (d != c && *d || l > 255) + return 0; + ia = (ia << 8) | l; + if (c) + c++; + a = c; + } + *o = ip4_from_u32(ia); + return 1; +} + +int +ip6_pton(char *a, ip6_addr *o) +{ + u16 words[8]; + int i, j, k, l, hfil; + char *start; + + if (a[0] == ':') /* Leading :: */ + { + if (a[1] != ':') + return 0; + a++; + } + hfil = -1; + i = 0; + while (*a) + { + if (*a == ':') /* :: */ + { + if (hfil >= 0) + return 0; + hfil = i; + a++; + continue; + } + j = 0; + l = 0; + start = a; + for(;;) + { + if (*a >= '0' && *a <= '9') + k = *a++ - '0'; + else if (*a >= 'A' && *a <= 'F') + k = *a++ - 'A' + 10; + else if (*a >= 'a' && *a <= 'f') + k = *a++ - 'a' + 10; + else + break; + j = (j << 4) + k; + if (j >= 0x10000 || ++l > 4) + return 0; + } + if (*a == ':' && a[1]) + a++; + else if (*a == '.' && (i == 6 || i < 6 && hfil >= 0)) + { /* Embedded IPv4 address */ + ip4_addr x; + if (!ip4_pton(start, &x)) + return 0; + words[i++] = _I(x) >> 16; + words[i++] = _I(x); + break; + } + else if (*a) + return 0; + if (i >= 8) + return 0; + words[i++] = j; + } + + /* Replace :: with an appropriate number of zeros */ + if (hfil >= 0) + { + j = 8 - i; + for(i=7; i-j >= hfil; i--) + words[i] = words[i-j]; + for(; i>=hfil; i--) + words[i] = 0; + } + + /* Convert the address to ip6_addr format */ + for(i=0; i<4; i++) + o->addr[i] = (words[2*i] << 16) | words[2*i+1]; + return 1; +} + + /** * ip_scope_text - get textual representation of address scope * @scope: scope (%SCOPE_xxx) @@ -35,6 +349,9 @@ ip_scope_text(unsigned scope) return scope_table[scope]; } + + + #if 0 /** * ipa_equal - compare two IP addresses for equality @@ -193,7 +510,7 @@ ip_addr ipa_to_u32(u32 x) { DUMMY } int ipa_compare(ip_addr x, ip_addr y) { DUMMY } /** - * ipa_build - build an IPv6 address from parts + * ipa_build6 - build an IPv6 address from parts * @a1: part #1 * @a2: part #2 * @a3: part #3 @@ -203,18 +520,7 @@ int ipa_compare(ip_addr x, ip_addr y) { DUMMY } * address. It's used for example when a protocol wants to bind its * socket to a hard-wired multicast address. */ -ip_addr ipa_build(u32 a1, u32 a2, u32 a3, u32 a4) { DUMMY } - -/** - * ipa_absolutize - convert link scope IPv6 address to universe scope - * @x: link scope IPv6 address - * @y: universe scope IPv6 prefix of the interface - * - * This function combines a link-scope IPv6 address @x with the universe - * scope prefix @x of the network assigned to an interface to get a - * universe scope form of @x. - */ -ip_addr ipa_absolutize(ip_addr x, ip_addr y) { DUMMY } +ip_addr ipa_build6(u32 a1, u32 a2, u32 a3, u32 a4) { DUMMY } /** * ip_ntop - convert IP address to textual representation diff --git a/lib/ip.h b/lib/ip.h index 023c1064..706bbcf5 100644 --- a/lib/ip.h +++ b/lib/ip.h @@ -9,32 +9,70 @@ #ifndef _BIRD_IP_H_ #define _BIRD_IP_H_ -#ifndef IPV6 -#include "ipv4.h" +#include "lib/endian.h" +#include "lib/string.h" +#include "lib/bitops.h" +#include "lib/unaligned.h" + + +#ifdef DEBUGGING + +/* + * Use the structural representation when you want to make sure + * nobody unauthorized attempts to handle ip_addr as number. + */ + +typedef struct ip4_addr { + u32 addr; +} ip4_addr; + +#define _MI4(x) ((struct ip4_addr) { x }) +#define _I(x) (x).addr + #else -#include "ipv6.h" + +typedef u32 ip4_addr; + +#define _MI4(x) (x) +#define _I(x) (x) + #endif -#define ipa_zero(x) (!ipa_nonzero(x)) -#define ip_is_prefix(a,l) (!ipa_nonzero(ipa_and(a, ipa_not(ipa_mkmask(l))))) -#define ipa_in_net(x,n,p) (ipa_zero(ipa_and(ipa_xor((n),(x)),ipa_mkmask(p)))) -#define net_in_net(n1,l1,n2,l2) (((l1) >= (l2)) && (ipa_zero(ipa_and(ipa_xor((n1),(n2)),ipa_mkmask(l2))))) + +typedef struct ip6_addr { + u32 addr[4]; +} ip6_addr; + +#define _MI6(a,b,c,d) ((struct ip6_addr) {{ a, b, c, d }}) +#define _I0(a) ((a).addr[0]) +#define _I1(a) ((a).addr[1]) +#define _I2(a) ((a).addr[2]) +#define _I3(a) ((a).addr[3]) + + +typedef ip6_addr ip_addr; + + + +#define IPA_NONE IP6_NONE +#define IP4_NONE _MI4(0) +#define IP6_NONE _MI6(0,0,0,0) + /* * ip_classify() returns either a negative number for invalid addresses * or scope OR'ed together with address type. */ - #define IADDR_INVALID -1 #define IADDR_SCOPE_MASK 0xfff #define IADDR_HOST 0x1000 #define IADDR_BROADCAST 0x2000 #define IADDR_MULTICAST 0x4000 + /* * Address scope */ - #define SCOPE_HOST 0 #define SCOPE_LINK 1 #define SCOPE_SITE 2 @@ -42,26 +80,341 @@ #define SCOPE_UNIVERSE 4 #define SCOPE_UNDEFINED 5 -char *ip_scope_text(unsigned); + + +#define ipa_equal(x,y) ip6_equal(x,y) +#define ipa_zero(x) ip6_zero(x) +#define ipa_nonzero(x) ip6_nonzero(x) +#define ipa_and(x,y) ip6_and(x,y) +#define ipa_or(x,y) ip6_or(x,y) +#define ipa_xor(x,y) ip6_xor(x,y) +#define ipa_not(x) ip6_not(x) + +#define ip4_equal(x,y) (_I(x) == _I(y)) +#define ip4_zero(x) (!_I(x)) +#define ip4_nonzero(x) _I(x) +#define ip4_and(x,y) _MI4(_I(x) & _I(y)) +#define ip4_or(x,y) _MI4(_I(x) | _I(y)) +#define ip4_xor(x,y) _MI4(_I(x) ^ _I(y)) +#define ip4_not(x) _MI4(~_I(x)) + +static inline int ip6_equal(ip6_addr a, ip6_addr b) +{ return _I0(a) == _I0(b) && _I1(a) == _I1(b) && _I2(a) == _I2(b) && _I3(a) == _I3(b); } + +static inline int ip6_zero(ip6_addr a) +{ return !_I0(a) && !_I1(a) && !_I2(a) && !_I3(a); } + +static inline int ip6_nonzero(ip6_addr a) +{ return _I0(a) || _I1(a) || _I2(a) || _I3(a); } + +static inline ip6_addr ip6_and(ip6_addr a, ip6_addr b) +{ return _MI6(_I0(a) & _I0(b), _I1(a) & _I1(b), _I2(a) & _I2(b), _I3(a) & _I3(b)); } + +static inline ip6_addr ip6_or(ip6_addr a, ip6_addr b) +{ return _MI6(_I0(a) | _I0(b), _I1(a) | _I1(b), _I2(a) | _I2(b), _I3(a) | _I3(b)); } + +static inline ip6_addr ip6_xor(ip6_addr a, ip6_addr b) +{ return _MI6(_I0(a) ^ _I0(b), _I1(a) ^ _I1(b), _I2(a) ^ _I2(b), _I3(a) ^ _I3(b)); } + +static inline ip6_addr ip6_not(ip6_addr a) +{ return _MI6(~_I0(a), ~_I1(a), ~_I2(a), ~_I3(a)); } + + + +#define ipa_from_ip4(x) _MI6(0,0,0xffff,_I(x)) +#define ipa_from_ip6(x) x + +#define ipa_to_ip4(x) _I3(x) +#define ipa_to_ip6(x) x + +#define ip4_from_u32(x) _MI4(x) +#define ip4_to_u32(x) _I(x) + +#define ipa_is_ip4(a) ip6_is_v4mapped(a) + +#define ipa_build4(a,b,c,d) ipa_from_ip4(ip4_build(a,b,c,d)) +#define ipa_build6(a,b,c,d) _MI6(a,b,c,d) + +#define ip4_build(a,b,c,d) _MI4(((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) +#define ip6_build(a,b,c,d) _MI6(a,b,c,d) + + + +#define ipa_hton(x) x = ip6_hton(x) +#define ipa_ntoh(x) x = ip6_ntoh(x) + +#define ip4_hton(x) _MI4(htonl(_I(x))) +#define ip4_ntoh(x) _MI4(ntohl(_I(x))) + +static inline ip6_addr ip6_hton(ip6_addr a) +{ return _MI6(htonl(_I0(a)), htonl(_I1(a)), htonl(_I2(a)), htonl(_I3(a))); } + +static inline ip6_addr ip6_ntoh(ip6_addr a) +{ return _MI6(ntohl(_I0(a)), ntohl(_I1(a)), ntohl(_I2(a)), ntohl(_I3(a))); } + + + +#define ipa_compare(a,b) ip6_compare(a,b) + +static inline int ip4_compare(ip4_addr a, ip4_addr b) +{ return (_I(a) > _I(b)) - (_I(a) < _I(b)); } + +int ip6_compare(ip6_addr a, ip6_addr b); + + + +#define ipa_hash(a) ip6_hash(a) + +static inline unsigned ip4_hash(ip4_addr a) +{ + /* Returns a 16-bit value */ + u32 x = _I(a); + x ^= x >> 16; + x ^= x << 10; + return x & 0xffff; +} /* - * Network prefixes + * This hash function looks well, but once IPv6 enters + * mainstream use, we need to check that it has good + * distribution properties on real routing tables. */ +static inline unsigned ip6_hash(ip6_addr a) +{ + /* Returns a 16-bit hash key */ + u32 x = _I0(a) ^ _I1(a) ^ _I2(a) ^ _I3(a); + return (x ^ (x >> 16) ^ (x >> 8)) & 0xffff; +} + + +#define ipa_classify(x) ip6_classify(&(x)) +int ip4_classify(ip4_addr ad); +int ip6_classify(ip6_addr *a); + +#define ipa_is_link_local(a) ip6_is_link_local(a) + +static inline int ip6_is_link_local(ip6_addr a) +{ return (_I0(a) & 0xffc00000) == 0xfe800000; } + +static inline int ip6_is_v4mapped(ip6_addr a) +{ return _I0(a) == 0 && _I1(a) == 0 && _I2(a) == 0xffff; } + + + +#define ipa_mkmask(x) ip6_mkmask(x) +#define ipa_mklen(x) ip6_masklen(&x) // XXXX: ipa_masklen() + +#define ip4_mkmask(x) _MI4(u32_mkmask(x)) +#define ip4_masklen(x) u32_masklen(_I(x)) + +ip6_addr ip6_mkmask(unsigned n); +unsigned ip6_masklen(ip_addr *a); // XXXX: int or unsigned? + + + +/* ipa_pxlen() requires that x != y */ +#define ipa_pxlen(a,b) ip6_pxlen(a,b) + +static inline u32 ip4_pxlen(ip4_addr a, ip4_addr b) +{ return 31 - u32_log2(_I(a) ^ _I(b)); } + +static inline u32 ip6_pxlen(ip6_addr a, ip6_addr b) +{ + int i = 0; + i+= (a.addr[i] == b.addr[i]); + i+= (a.addr[i] == b.addr[i]); + i+= (a.addr[i] == b.addr[i]); + i+= (a.addr[i] == b.addr[i]); + return 32 * i + 31 - u32_log2(a.addr[i] ^ b.addr[i]); +} + + + +#define ipa_opposite_m1(x) ip6_opposite_m1(x) +#define ipa_opposite_m2(x) ip6_opposite_m2(x) + +#define ip4_opposite_m1(x) _MI4(_I(x) ^ 1) +#define ip4_opposite_m2(x) _MI4(_I(x) ^ 3) + +static inline ip6_addr ip6_opposite_m1(ip6_addr a) +{ return _MI6(_I0(a), _I1(a), _I2(a), _I3(a) ^ 1); } + +static inline ip6_addr ip6_opposite_m2(ip6_addr a) +{ return _MI6(_I0(a), _I1(a), _I2(a), _I3(a) ^ 3); } + + + +// XXXX +#define ipa_getbit(a,y) ip6_getbit(a,y) + +static inline u32 ip4_getbit(ip4_addr a, u32 pos) +{ return _I(a) & (0x80000000 >> pos); } + +static inline u32 ip6_getbit(ip6_addr a, u32 pos) +{ return a.addr[pos / 32] & (0x80000000 >> (pos % 32)); } + + +// XXXX +#define ipa_put_addr(buf,a) ip6_put(buf,a) + +static inline void * ip4_put(void *buf, ip4_addr a) +{ + put_u32(buf, _I(a)); + return buf+4; +} + +static inline void * ip6_put(void *buf, ip6_addr a) +{ + a = ip6_hton(a); + memcpy(buf, &a, 16); + return buf+16; +} + +static inline ip4_addr ip4_get(void *buf) +{ + return _MI4(get_u32(buf)); +} + +static inline ip6_addr ip6_get(void *buf) +{ + ip6_addr a; + memcpy(&a, buf, 16); + return ip6_ntoh(a); +} + +static inline void * ip4_put32(void *buf, ip4_addr a) +{ + *(u32 *)buf = htonl(_I(a)); + return buf+4; +} + +static inline void * ip6_put32(void *buf, ip6_addr a) +{ + u32 *b = buf; + b[0] = htonl(_I0(a)); + b[1] = htonl(_I1(a)); + b[2] = htonl(_I2(a)); + b[3] = htonl(_I3(a)); + return buf+16; +} + +static inline void * ip6_put32_ip4(void *buf, ip6_addr a) +{ + *(u32 *)buf = htonl(_I3(a)); + return buf+4; +} + +static inline ip6_addr ipa_get_in4(struct in_addr *in) +{ return ipa_from_ip4(ip4_ntoh(*(ip4_addr *) in)); } + +static inline ip6_addr ipa_get_in6(struct in6_addr *in) +{ return ip6_ntoh(*(ip6_addr *) in); } + +// XXXX check callers +static inline void ipa_put_in4(struct in_addr *in, ip6_addr a) +{ ip6_put32_ip4(in, a); } + +static inline void ipa_put_in6(struct in6_addr *in, ip6_addr a) +{ ip6_put32(in, a); } + + + +/* + * Conversions between internal and string representation + */ + +char *ip4_ntop(ip4_addr a, char *b); +char *ip6_ntop(ip6_addr a, char *b); + +static inline char * ip4_ntox(ip4_addr a, char *b) +{ return b + bsprintf(b, "%08x", _I(a)); } + +static inline char * ip6_ntox(ip6_addr a, char *b) +{ return b + bsprintf(b, "%08x.%08x.%08x.%08x", _I0(a), _I1(a), _I2(a), _I3(a)); } + +int ip4_pton(char *a, ip4_addr *o); +int ip6_pton(char *a, ip6_addr *o); + + + + + + + + + + + + + + + + + + + + + +// XXXX process rest + struct prefix { ip_addr addr; unsigned int len; }; +#define ip_is_prefix(a,l) (!ipa_nonzero(ipa_and(a, ipa_not(ipa_mkmask(l))))) +#define ipa_in_net(x,n,p) (ipa_zero(ipa_and(ipa_xor((n),(x)),ipa_mkmask(p)))) +#define net_in_net(n1,l1,n2,l2) (((l1) >= (l2)) && (ipa_zero(ipa_and(ipa_xor((n1),(n2)),ipa_mkmask(l2))))) + +char *ip_scope_text(unsigned); + +/* + * Network prefixes + */ + static inline int ipa_classify_net(ip_addr a) { return ipa_zero(a) ? (IADDR_HOST | SCOPE_UNIVERSE) : ipa_classify(a); } /* - * Conversions between internal and string representation - */ +#define MAX_PREFIX_LENGTH 32 +#define BITS_PER_IP_ADDRESS 32 +#define STD_ADDRESS_P_LENGTH 15 +#define SIZE_OF_IP_HEADER 24 +*/ -char *ip_ntop(ip_addr a, char *); -char *ip_ntox(ip_addr a, char *); -int ip_pton(char *a, ip_addr *o); + + +#define MAX_PREFIX_LENGTH 128 +#define BITS_PER_IP_ADDRESS 128 +#define STD_ADDRESS_P_LENGTH 39 +#define SIZE_OF_IP_HEADER 40 + +#define ipa_class_mask(x) _MI4(ipv4_class_mask(_I(x))) + + +/* +#define ip_skip_header(x, y) ipv4_skip_header(x, y) + +#define IP_PREC_INTERNET_CONTROL 0xc0 +*/ + +u32 ipv4_class_mask(u32); +byte *ipv4_skip_header(byte *, int *); + + + + + +/* In IPv6, SOCK_RAW does not return packet header */ +#define ip_skip_header(x, y) x + + +/* + * RFC 1883 defines packet precendece, but RFC 2460 replaces it + * by generic Traffic Class ID with no defined semantics. Better + * not use it yet. + */ +#define IP_PREC_INTERNET_CONTROL -1 #endif diff --git a/lib/ipv4.c b/lib/ipv4.c deleted file mode 100644 index 751351ca..00000000 --- a/lib/ipv4.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * BIRD Library -- IPv4 Address Manipulation Functions - * - * (c) 1998 Martin Mares - * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -#include - -#include "nest/bird.h" -#include "lib/ip.h" -#include "lib/string.h" - -int -ipv4_classify(u32 a) -{ - u32 b = a >> 24U; - - if (b && b <= 0xdf) - { - if (b == 0x7f) - return IADDR_HOST | SCOPE_HOST; - else if (b == 0x0a || - (a & 0xffff0000) == 0xc0a80000 || - (a & 0xfff00000) == 0xac100000) - return IADDR_HOST | SCOPE_SITE; - else - return IADDR_HOST | SCOPE_UNIVERSE; - } - if (b >= 0xe0 && b <= 0xef) - return IADDR_MULTICAST | SCOPE_UNIVERSE; - if (a == 0xffffffff) - return IADDR_BROADCAST | SCOPE_LINK; - return IADDR_INVALID; -} - -char * -ip_ntop(ip_addr a, char *b) -{ - u32 x = _I(a); - - return b + bsprintf(b, "%d.%d.%d.%d", - ((x >> 24) & 0xff), - ((x >> 16) & 0xff), - ((x >> 8) & 0xff), - (x & 0xff)); -} - -char * -ip_ntox(ip_addr a, char *b) -{ - return b + bsprintf(b, "%08x", _I(a)); -} - -u32 -ipv4_class_mask(u32 a) -{ - u32 m; - - if (a < 0x80000000) - m = 0xff000000; - else if (a < 0xc0000000) - m = 0xffff0000; - else - m = 0xffffff00; - while (a & ~m) - m |= m >> 1; - return m; -} - -int -ip_pton(char *a, ip_addr *o) -{ - int i; - unsigned long int l; - u32 ia = 0; - - i=4; - while (i--) - { - char *d, *c = strchr(a, '.'); - if (!c != !i) - return 0; - l = strtoul(a, &d, 10); - if (d != c && *d || l > 255) - return 0; - ia = (ia << 8) | l; - if (c) - c++; - a = c; - } - *o = ipa_from_u32(ia); - return 1; -} - -byte * -ipv4_skip_header(byte *pkt, int *len) -{ - int l = *len; - int q; - - if (l < 20 || (*pkt & 0xf0) != 0x40) - return NULL; - q = (*pkt & 0x0f) * 4; - if (q > l) - return NULL; - *len -= q; - return pkt + q; -} diff --git a/lib/ipv4.h b/lib/ipv4.h deleted file mode 100644 index f258d37e..00000000 --- a/lib/ipv4.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * BIRD -- IP Addresses et Cetera for IPv4 - * - * (c) 1998--1999 Martin Mares - * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -#ifndef _BIRD_IPV4_H_ -#define _BIRD_IPV4_H_ - -#include "lib/endian.h" -#include "lib/bitops.h" -#include "lib/unaligned.h" - -#ifdef DEBUGGING - -/* - * Use the structural representation when you want to make sure - * nobody unauthorized attempts to handle ip_addr as number. - */ - -typedef struct ipv4_addr { - u32 addr; -} ip_addr; - -#define _I(x) (x).addr -#define _MI(x) ((struct ipv4_addr) { x }) - -#else - -typedef u32 ip_addr; - -#define _I(x) (x) -#define _MI(x) (x) - -#endif - -#define MAX_PREFIX_LENGTH 32 -#define BITS_PER_IP_ADDRESS 32 -#define STD_ADDRESS_P_LENGTH 15 -#define SIZE_OF_IP_HEADER 24 - -#define IPA_NONE (_MI(0)) - -#define ipa_equal(x,y) (_I(x) == _I(y)) -#define ipa_nonzero(x) _I(x) -#define ipa_and(x,y) _MI(_I(x) & _I(y)) -#define ipa_or(x,y) _MI(_I(x) | _I(y)) -#define ipa_xor(x,y) _MI(_I(x) ^ _I(y)) -#define ipa_not(x) _MI(~_I(x)) -#define ipa_mkmask(x) _MI(u32_mkmask(x)) -#define ipa_mklen(x) u32_masklen(_I(x)) -#define ipa_hash(x) ipv4_hash(_I(x)) -#define ipa_hton(x) x = _MI(htonl(_I(x))) -#define ipa_ntoh(x) x = _MI(ntohl(_I(x))) -#define ipa_classify(x) ipv4_classify(_I(x)) -#define ipa_has_link_scope(x) ipv4_has_link_scope(_I(x)) -#define ipa_opposite_m1(x) _MI(_I(x) ^ 1) -#define ipa_opposite_m2(x) _MI(_I(x) ^ 3) -#define ipa_class_mask(x) _MI(ipv4_class_mask(_I(x))) -#define ipa_from_u32(x) _MI(x) -#define ipa_to_u32(x) _I(x) -#define ipa_compare(x,y) ipv4_compare(_I(x),_I(y)) -/* ipa_pxlen() requires that x != y */ -#define ipa_pxlen(x, y) ipv4_pxlen(_I(x), _I(y)) -#define ipa_getbit(x, y) (_I(x) & (0x80000000 >> (y))) -#define ipa_put_addr(x, y) ipv4_put_addr(x, y) - -#define ip_skip_header(x, y) ipv4_skip_header(x, y) - -int ipv4_classify(u32); -u32 ipv4_class_mask(u32); -byte *ipv4_skip_header(byte *, int *); - -static inline int ipv4_has_link_scope(u32 a UNUSED) -{ - return 0; -} - -static inline unsigned ipv4_hash(u32 a) -{ - /* Returns a 16-bit value */ - a ^= a >> 16; - a ^= a << 10; - return a & 0xffff; -} - -static inline int ipv4_compare(u32 x, u32 y) -{ - return (x > y) - (x < y); -} - -static inline u32 ipv4_pxlen(u32 a, u32 b) -{ - return 31 - u32_log2(a ^ b); -} - -static inline byte * ipv4_put_addr(byte *buf, ip_addr a) -{ - put_u32(buf, _I(a)); - return buf+4; -} - -#define IP_PREC_INTERNET_CONTROL 0xc0 - -#endif diff --git a/lib/ipv6.c b/lib/ipv6.c deleted file mode 100644 index 623f6328..00000000 --- a/lib/ipv6.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * BIRD Library -- IPv6 Address Manipulation Functions - * - * (c) 1999 Martin Mares - * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -#include - -#include "nest/bird.h" -#include "lib/ip.h" -#include "lib/bitops.h" -#include "lib/endian.h" -#include "lib/string.h" - -/* - * See RFC 2373 for explanation of IPv6 addressing issues. - */ - -ip_addr -ipv6_mkmask(unsigned n) -{ - ip_addr a; - int i; - - for(i=0; i<4; i++) - { - if (!n) - a.addr[i] = 0; - else if (n >= 32) - { - a.addr[i] = ~0; - n -= 32; - } - else - { - a.addr[i] = u32_mkmask(n); - n = 0; - } - } - return a; -} - -unsigned -ipv6_mklen(ip_addr *a) -{ - int i, j, n; - - for(i=0, n=0; i<4; i++, n+=32) - if (a->addr[i] != ~0U) - { - j = u32_masklen(a->addr[i]); - if (j < 0) - return j; - n += j; - while (++i < 4) - if (a->addr[i]) - return -1; - break; - } - return n; -} - -int -ipv6_classify(ip_addr *a) -{ - u32 x = a->addr[0]; - - if ((x & 0xe0000000) == 0x20000000) /* 2000::/3 Aggregatable Global Unicast Address */ - return IADDR_HOST | SCOPE_UNIVERSE; - if ((x & 0xffc00000) == 0xfe800000) /* fe80::/10 Link-Local Address */ - return IADDR_HOST | SCOPE_LINK; - if ((x & 0xffc00000) == 0xfec00000) /* fec0::/10 Site-Local Address */ - return IADDR_HOST | SCOPE_SITE; - if ((x & 0xfe000000) == 0xfc000000) /* fc00::/7 Unique Local Unicast Address (RFC 4193) */ - return IADDR_HOST | SCOPE_SITE; - if ((x & 0xff000000) == 0xff000000) /* ff00::/8 Multicast Address */ - { - unsigned int scope = (x >> 16) & 0x0f; - switch (scope) - { - case 1: return IADDR_MULTICAST | SCOPE_HOST; - case 2: return IADDR_MULTICAST | SCOPE_LINK; - case 5: return IADDR_MULTICAST | SCOPE_SITE; - case 8: return IADDR_MULTICAST | SCOPE_ORGANIZATION; - case 14: return IADDR_MULTICAST | SCOPE_UNIVERSE; - default: return IADDR_MULTICAST | SCOPE_UNDEFINED; - } - } - if (!x && !a->addr[1] && !a->addr[2]) - { - u32 y = a->addr[3]; - if (y == 1) - return IADDR_HOST | SCOPE_HOST; /* Loopback address */ - /* IPv4 compatible addresses */ - if (y >= 0x7f000000 && y < 0x80000000) - return IADDR_HOST | SCOPE_HOST; - if ((y & 0xff000000) == 0x0a000000 || - (y & 0xffff0000) == 0xc0a80000 || - (y & 0xfff00000) == 0xac100000) - return IADDR_HOST | SCOPE_SITE; - if (y >= 0x01000000 && y < 0xe0000000) - return IADDR_HOST | SCOPE_UNIVERSE; - } - return IADDR_HOST | SCOPE_UNDEFINED; -} - -void -ipv6_hton(ip_addr *a) -{ - int i; - - for(i=0; i<4; i++) - a->addr[i] = htonl(a->addr[i]); -} - -void -ipv6_ntoh(ip_addr *a) -{ - int i; - - for(i=0; i<4; i++) - a->addr[i] = ntohl(a->addr[i]); -} - -int -ipv6_compare(ip_addr X, ip_addr Y) -{ - int i; - ip_addr *x = &X; - ip_addr *y = &Y; - - for(i=0; i<4; i++) - if (x->addr[i] > y->addr[i]) - return 1; - else if (x->addr[i] < y->addr[i]) - return -1; - return 0; -} - -/* - * Conversion of IPv6 address to presentation format and vice versa. - * Heavily inspired by routines written by Paul Vixie for the BIND project - * and of course by RFC 2373. - */ - -char * -ip_ntop(ip_addr a, char *b) -{ - u16 words[8]; - int bestpos, bestlen, curpos, curlen, i; - - /* First of all, preprocess the address and find the longest run of zeros */ - bestlen = bestpos = curpos = curlen = 0; - for(i=0; i<8; i++) - { - u32 x = a.addr[i/2]; - words[i] = ((i%2) ? x : (x >> 16)) & 0xffff; - if (words[i]) - curlen = 0; - else - { - if (!curlen) - curpos = i; - curlen++; - if (curlen > bestlen) - { - bestpos = curpos; - bestlen = curlen; - } - } - } - if (bestlen < 2) - bestpos = -1; - - /* Is it an encapsulated IPv4 address? */ - if (!bestpos && - (bestlen == 5 && a.addr[2] == 0xffff || - bestlen == 6)) - { - u32 x = a.addr[3]; - b += bsprintf(b, "::%s%d.%d.%d.%d", - a.addr[2] ? "ffff:" : "", - ((x >> 24) & 0xff), - ((x >> 16) & 0xff), - ((x >> 8) & 0xff), - (x & 0xff)); - return b; - } - - /* Normal IPv6 formatting, compress the largest sequence of zeros */ - for(i=0; i<8; i++) - { - if (i == bestpos) - { - i += bestlen - 1; - *b++ = ':'; - if (i == 7) - *b++ = ':'; - } - else - { - if (i) - *b++ = ':'; - b += bsprintf(b, "%x", words[i]); - } - } - *b = 0; - return b; -} - -char * -ip_ntox(ip_addr a, char *b) -{ - int i; - - for(i=0; i<4; i++) - { - if (i) - *b++ = '.'; - b += bsprintf(b, "%08x", a.addr[i]); - } - return b; -} - -int -ipv4_pton_u32(char *a, u32 *o) -{ - int i; - unsigned long int l; - u32 ia = 0; - - i=4; - while (i--) - { - char *d, *c = strchr(a, '.'); - if (!c != !i) - return 0; - l = strtoul(a, &d, 10); - if (d != c && *d || l > 255) - return 0; - ia = (ia << 8) | l; - if (c) - c++; - a = c; - } - *o = ia; - return 1; -} - -int -ip_pton(char *a, ip_addr *o) -{ - u16 words[8]; - int i, j, k, l, hfil; - char *start; - - if (a[0] == ':') /* Leading :: */ - { - if (a[1] != ':') - return 0; - a++; - } - hfil = -1; - i = 0; - while (*a) - { - if (*a == ':') /* :: */ - { - if (hfil >= 0) - return 0; - hfil = i; - a++; - continue; - } - j = 0; - l = 0; - start = a; - for(;;) - { - if (*a >= '0' && *a <= '9') - k = *a++ - '0'; - else if (*a >= 'A' && *a <= 'F') - k = *a++ - 'A' + 10; - else if (*a >= 'a' && *a <= 'f') - k = *a++ - 'a' + 10; - else - break; - j = (j << 4) + k; - if (j >= 0x10000 || ++l > 4) - return 0; - } - if (*a == ':' && a[1]) - a++; - else if (*a == '.' && (i == 6 || i < 6 && hfil >= 0)) - { /* Embedded IPv4 address */ - u32 x; - if (!ipv4_pton_u32(start, &x)) - return 0; - words[i++] = x >> 16; - words[i++] = x; - break; - } - else if (*a) - return 0; - if (i >= 8) - return 0; - words[i++] = j; - } - - /* Replace :: with an appropriate number of zeros */ - if (hfil >= 0) - { - j = 8 - i; - for(i=7; i-j >= hfil; i--) - words[i] = words[i-j]; - for(; i>=hfil; i--) - words[i] = 0; - } - - /* Convert the address to ip_addr format */ - for(i=0; i<4; i++) - o->addr[i] = (words[2*i] << 16) | words[2*i+1]; - return 1; -} - -void ipv6_absolutize(ip_addr *a, ip_addr *ifa) -{ - if ((a->addr[0] & 0xffc00000) == 0xfe800000 && /* a is link-scope */ - ((ifa->addr[0] & 0xe0000000) == 0x20000000 | /* ifa is AGU ... */ - (ifa->addr[0] & 0xffc00000) == 0xfec00000)) /* ... or site-scope */ - { - a->addr[0] = ifa->addr[0]; /* Copy the prefix, leave interface ID */ - a->addr[1] = ifa->addr[1]; - } -} - -#ifdef TEST - -#include "bitops.c" - -static void test(char *x) -{ - ip_addr a; - char c[STD_ADDRESS_P_LENGTH+1]; - - printf("%-40s ", x); - if (!ip_pton(x, &a)) - { - puts("BAD"); - return; - } - ip_ntop(a, c); - printf("%-40s %04x\n", c, ipv6_classify(&a)); -} - -int main(void) -{ - puts("Positive tests:"); - test("1:2:3:4:5:6:7:8"); - test("dead:beef:DEAD:BEEF::f00d"); - test("::"); - test("::1"); - test("1::"); - test("::1.234.5.6"); - test("::ffff:1.234.5.6"); - test("::fffe:1.234.5.6"); - test("1:2:3:4:5:6:7::8"); - test("2080::8:800:200c:417a"); - test("ff01::101"); - - puts("Negative tests:"); - test(":::"); - test("1:2:3:4:5:6:7:8:"); - test("1::2::3"); - test("::12345"); - test("::1.2.3.4:5"); - test(":1:2:3:4:5:6:7:8"); - test("g:1:2:3:4:5:6:7"); - return 0; -} - -#endif diff --git a/lib/ipv6.h b/lib/ipv6.h deleted file mode 100644 index 6f8e7b3c..00000000 --- a/lib/ipv6.h +++ /dev/null @@ -1,138 +0,0 @@ - -/* - * BIRD -- IP Addresses et Cetera for IPv6 - * - * (c) 1999--2000 Martin Mares - * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -#ifndef _BIRD_IPV6_H_ -#define _BIRD_IPV6_H_ - -#include -#include -#include "lib/string.h" -#include "lib/bitops.h" -#include "lib/unaligned.h" - -typedef struct ipv6_addr { - u32 addr[4]; -} ip_addr; - -#define _MI(a,b,c,d) ((struct ipv6_addr) {{ a, b, c, d }}) -#define _I0(a) ((a).addr[0]) -#define _I1(a) ((a).addr[1]) -#define _I2(a) ((a).addr[2]) -#define _I3(a) ((a).addr[3]) - -#define MAX_PREFIX_LENGTH 128 -#define BITS_PER_IP_ADDRESS 128 -#define STD_ADDRESS_P_LENGTH 39 -#define SIZE_OF_IP_HEADER 40 - -#define IPA_NONE _MI(0,0,0,0) - -#define ipa_equal(x,y) ({ ip_addr _a=(x), _b=(y); \ - _I0(_a) == _I0(_b) && \ - _I1(_a) == _I1(_b) && \ - _I2(_a) == _I2(_b) && \ - _I3(_a) == _I3(_b); }) -#define ipa_nonzero(x) ({ ip_addr _a=(x); (_I0(_a) || _I1(_a) || _I2(_a) || _I3(_a)); }) -#define ipa_and(x,y) ({ ip_addr _a=(x), _b=(y); \ - _MI(_I0(_a) & _I0(_b), \ - _I1(_a) & _I1(_b), \ - _I2(_a) & _I2(_b), \ - _I3(_a) & _I3(_b)); }) -#define ipa_or(x,y) ({ ip_addr _a=(x), _b=(y); \ - _MI(_I0(_a) | _I0(_b), \ - _I1(_a) | _I1(_b), \ - _I2(_a) | _I2(_b), \ - _I3(_a) | _I3(_b)); }) -#define ipa_xor(x,y) ({ ip_addr _a=(x), _b=(y); \ - _MI(_I0(_a) ^ _I0(_b), \ - _I1(_a) ^ _I1(_b), \ - _I2(_a) ^ _I2(_b), \ - _I3(_a) ^ _I3(_b)); }) -#define ipa_not(x) ({ ip_addr _a=(x); _MI(~_I0(_a),~_I1(_a),~_I2(_a),~_I3(_a)); }) -#define ipa_mkmask(x) ipv6_mkmask(x) -#define ipa_mklen(x) ipv6_mklen(&(x)) -#define ipa_hash(x) ipv6_hash(&(x)) -#define ipa_hton(x) ipv6_hton(&(x)) -#define ipa_ntoh(x) ipv6_ntoh(&(x)) -#define ipa_classify(x) ipv6_classify(&(x)) -#define ipa_has_link_scope(x) ipv6_has_link_scope(&(x)) -#define ipa_opposite_m1(x) ({ ip_addr _a=(x); _MI(_I0(_a),_I1(_a),_I2(_a),_I3(_a) ^ 1); }) -#define ipa_opposite_m2(x) ({ ip_addr _a=(x); _MI(_I0(_a),_I1(_a),_I2(_a),_I3(_a) ^ 3); }) -/* ipa_class_mask don't make sense with IPv6 */ -/* ipa_from_u32 and ipa_to_u32 replaced by ipa_build */ -#define ipa_build(a,b,c,d) _MI(a,b,c,d) -#define ipa_compare(x,y) ipv6_compare(x,y) -/* ipa_pxlen() requires that x != y */ -#define ipa_pxlen(x, y) ipv6_pxlen(x, y) -#define ipa_getbit(x, y) ipv6_getbit(x, y) -#define ipa_put_addr(x, y) ipv6_put_addr(x, y) -#define ipa_absolutize(x,y) ipv6_absolutize(x,y) - -/* In IPv6, SOCK_RAW does not return packet header */ -#define ip_skip_header(x, y) x - -ip_addr ipv6_mkmask(unsigned); -unsigned ipv6_mklen(ip_addr *); -int ipv6_classify(ip_addr *); -void ipv6_hton(ip_addr *); -void ipv6_ntoh(ip_addr *); -int ipv6_compare(ip_addr, ip_addr); -int ipv4_pton_u32(char *, u32 *); -void ipv6_absolutize(ip_addr *, ip_addr *); - -static inline int ipv6_has_link_scope(ip_addr *a) -{ - return ((a->addr[0] & 0xffc00000) == 0xfe800000); -} - -/* - * This hash function looks well, but once IPv6 enters - * mainstream use, we need to check that it has good - * distribution properties on real routing tables. - */ - -static inline unsigned ipv6_hash(ip_addr *a) -{ - /* Returns a 16-bit hash key */ - u32 x = _I0(*a) ^ _I1(*a) ^ _I2(*a) ^ _I3(*a); - return (x ^ (x >> 16) ^ (x >> 8)) & 0xffff; -} - -static inline u32 ipv6_getbit(ip_addr a, u32 y) -{ - return a.addr[y / 32] & (0x80000000 >> (y % 32)); -} - -static inline u32 ipv6_pxlen(ip_addr a, ip_addr b) -{ - int i = 0; - i+= (a.addr[i] == b.addr[i]); - i+= (a.addr[i] == b.addr[i]); - i+= (a.addr[i] == b.addr[i]); - i+= (a.addr[i] == b.addr[i]); - return 32 * i + 31 - u32_log2(a.addr[i] ^ b.addr[i]); -} - -static inline byte * ipv6_put_addr(byte *buf, ip_addr a) -{ - put_u32(buf+0, _I0(a)); - put_u32(buf+4, _I1(a)); - put_u32(buf+8, _I2(a)); - put_u32(buf+12, _I3(a)); - return buf+16; -} - -/* - * RFC 1883 defines packet precendece, but RFC 2460 replaces it - * by generic Traffic Class ID with no defined semantics. Better - * not use it yet. - */ -#define IP_PREC_INTERNET_CONTROL -1 - -#endif diff --git a/lib/printf.c b/lib/printf.c index 14af1062..562844b3 100644 --- a/lib/printf.c +++ b/lib/printf.c @@ -273,9 +273,10 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args) /* IP address */ case 'I': if (flags & SPECIAL) - ip_ntox(va_arg(args, ip_addr), ipbuf); + ip6_ntox(va_arg(args, ip_addr), ipbuf); else { - ip_ntop(va_arg(args, ip_addr), ipbuf); + // XXXX update IPv4 / IPv6 distinction + ip6_ntop(va_arg(args, ip_addr), ipbuf); if (field_width > 0) field_width = STD_ADDRESS_P_LENGTH; } @@ -300,11 +301,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args) /* Router/Network ID - essentially IPv4 address in u32 value */ case 'R': x = va_arg(args, u32); - bsprintf(ipbuf, "%d.%d.%d.%d", - ((x >> 24) & 0xff), - ((x >> 16) & 0xff), - ((x >> 8) & 0xff), - (x & 0xff)); + ip4_ntop(ip4_from_u32(x), ipbuf); s = ipbuf; goto str; diff --git a/lib/socket.h b/lib/socket.h index b0c3eda2..618e69b8 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -43,6 +43,7 @@ typedef struct birdsock { /* laddr and lifindex are valid only if SKF_LADDR_RX flag is set to request it */ int fd; /* System-dependent data */ + int af; /* Address family (AF_INET, AF_INET6 or 0 for non-IP) of fd */ node n; void *rbuf_alloc, *tbuf_alloc; char *password; /* Password for MD5 authentication */ @@ -66,25 +67,27 @@ int sk_setup_multicast(sock *s); int sk_join_group(sock *s, ip_addr maddr); int sk_leave_group(sock *s, ip_addr maddr); -#ifdef IPV6 int sk_set_ipv6_checksum(sock *s, int offset); -int sk_set_icmp_filter(sock *s, int p1, int p2); -#endif - +int sk_set_icmp6_filter(sock *s, int p1, int p2); int sk_set_broadcast(sock *s, int enable); -static inline int -sk_send_buffer_empty(sock *sk) -{ - return sk->tbuf == sk->tpos; -} +static inline int sk_send_buffer_empty(sock *sk) +{ return sk->tbuf == sk->tpos; } + +static inline int sk_is_ipv4(sock *sk) +{ return sk->af == AF_INET; } + +static inline int sk_is_ipv6(sock *sk) +{ return sk->af == AF_INET6; } + /* Socket flags */ -#define SKF_V6ONLY 1 /* Use IPV6_V6ONLY socket option */ -#define SKF_LADDR_RX 2 /* Report local address for RX packets */ -#define SKF_LADDR_TX 4 /* Allow to specify local address for TX packets */ +#define SKF_V4ONLY 1 /* Use IPv4 for IP sockets */ +#define SKF_V6ONLY 2 /* Use IPV6_V6ONLY socket option */ +#define SKF_LADDR_RX 4 /* Report local address for RX packets */ +#define SKF_LADDR_TX 6 /* Allow to specify local address for TX packets */ /* diff --git a/lib/unaligned.h b/lib/unaligned.h index af655204..1f418cd9 100644 --- a/lib/unaligned.h +++ b/lib/unaligned.h @@ -17,6 +17,7 @@ * if possible. */ +#include "lib/endian.h" #include "lib/string.h" static inline u16 diff --git a/nest/config.Y b/nest/config.Y index 14cff10a..420f0213 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -46,7 +46,7 @@ CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OF CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS) CF_KEYWORDS(LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE) CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES) -CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE, ROA, MAX, FLUSH) +CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE, ROA, AS, MAX, FLUSH) CF_KEYWORDS(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION) CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC) @@ -82,14 +82,7 @@ rtrid: ROUTER ID idval ';' { idval: NUM { $$ = $1; } - | RTRID - | IPA { -#ifndef IPV6 - $$ = ipa_to_u32($1); -#else - cf_error("Router IDs must be entered as hexadecimal numbers or IPv4 addresses in IPv6 version"); -#endif - } + | IP4 { $$ = ip4_to_u32($1); } ; diff --git a/proto/radv/packets.c b/proto/radv/packets.c index ac59ce94..a87b9689 100644 --- a/proto/radv/packets.c +++ b/proto/radv/packets.c @@ -245,7 +245,7 @@ radv_sk_open(struct radv_iface *ifa) sk->saddr = ifa->addr->ip; /* We want listen just to ICMPv6 messages of type RS and RA */ - if (sk_set_icmp_filter(sk, ICMPV6_RS, ICMPV6_RA) < 0) + if (sk_set_icmp6_filter(sk, ICMPV6_RS, ICMPV6_RA) < 0) goto err; if (sk_setup_multicast(sk) < 0) diff --git a/proto/radv/radv.h b/proto/radv/radv.h index 12bfe42e..3f88eac8 100644 --- a/proto/radv/radv.h +++ b/proto/radv/radv.h @@ -26,8 +26,8 @@ #define ICMPV6_PROTO 58 -#define AllNodes _MI(0xFF020000, 0, 0, 1) /* FF02::1 */ -#define AllRouters _MI(0xFF020000, 0, 0, 2) /* FF02::2 */ +#define AllNodes ipa_build6(0xFF020000, 0, 0, 1) /* FF02::1 */ +#define AllRouters ipa_build6(0xFF020000, 0, 0, 2) /* FF02::2 */ #define ICMPV6_RS 133 #define ICMPV6_RA 134 diff --git a/proto/rip/rip.c b/proto/rip/rip.c index 281296a5..9ec4ac74 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -718,7 +718,7 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_ #ifndef IPV6 rif->sock->daddr = ipa_from_u32(0xe0000009); #else - rif->sock->daddr = ipa_build(0xff020000, 0, 0, 9); + rif->sock->daddr = ipa_build6(0xff020000, 0, 0, 9); #endif } else { rif->sock->daddr = new->addr->brd; @@ -808,7 +808,7 @@ rip_if_notify(struct proto *p, unsigned c, struct iface *iface) #ifndef IPV6 lock->addr = ipa_from_u32(0xe0000009); #else - ip_pton("FF02::9", &lock->addr); + lock->addr = ipa_build6(0xff020000, 0, 0, 9); #endif else lock->addr = iface->addr->brd; diff --git a/sysdep/config.h b/sysdep/config.h index 8d93d381..c0154387 100644 --- a/sysdep/config.h +++ b/sysdep/config.h @@ -9,6 +9,9 @@ /* BIRD version */ #define BIRD_VERSION "1.3.7" +// XXXX temporary define +#define IPV1 1 + /* Include parameters determined by configure script */ #include "sysdep/autoconf.h" diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index eaaf048e..2c511519 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -94,7 +94,7 @@ nl_send(struct nl_sock *nl, struct nlmsghdr *nh) } static void -nl_request_dump(int cmd) +nl_request_dump(int pf, int cmd) { struct { struct nlmsghdr nh; @@ -103,9 +103,7 @@ nl_request_dump(int cmd) req.nh.nlmsg_type = cmd; req.nh.nlmsg_len = sizeof(req); req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; - /* Is it important which PF_* is used for link-level interface scan? - It seems that some information is available only when PF_INET is used. */ - req.g.rtgen_family = (cmd == RTM_GETLINK) ? PF_INET : BIRD_PF; + req.g.rtgen_family = pf; nl_send(&nl_scan, &req.nh); } @@ -239,6 +237,19 @@ nl_parse_attrs(struct rtattr *a, struct rtattr **k, int ksize) return 1; } +static inline ip4_addr rta4_get_ip4(struct rtattr *a) +{ return ip4_get(RTA_DATA(a)); } + +static inline ip6_addr rta6_get_ip6(struct rtattr *a) +{ return ip6_get(RTA_DATA(a)); } + +static inline ip_addr rta4_get_ipa(struct rtattr *a) +{ return ipa_from_ip4(ip4_get(RTA_DATA(a))); } + +static inline ip_addr rta6_get_ipa(struct rtattr *a) +{ return ipa_from_ip6(ip6_get(RTA_DATA(a))); } + + void nl_add_attr(struct nlmsghdr *h, unsigned bufsize, unsigned code, void *data, unsigned dlen) @@ -445,54 +456,58 @@ nl_parse_addr(struct nlmsghdr *h) { struct ifaddrmsg *i; struct rtattr *a[IFA_ANYCAST+1]; - int new = h->nlmsg_type == RTM_NEWADDR; + int new = (h->nlmsg_type == RTM_NEWADDR); struct ifa ifa; - struct iface *ifi; - int scope; + ip_addr addr; + int ipv4 = 0; if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFA_RTA(i), a, sizeof(a))) return; - if (i->ifa_family != BIRD_AF) - return; - if (!a[IFA_ADDRESS] || RTA_PAYLOAD(a[IFA_ADDRESS]) != sizeof(ip_addr) -#ifdef IPV6 - || a[IFA_LOCAL] && RTA_PAYLOAD(a[IFA_LOCAL]) != sizeof(ip_addr) -#else - || !a[IFA_LOCAL] || RTA_PAYLOAD(a[IFA_LOCAL]) != sizeof(ip_addr) - || (a[IFA_BROADCAST] && RTA_PAYLOAD(a[IFA_BROADCAST]) != sizeof(ip_addr)) -#endif - ) - { - log(L_ERR "nl_parse_addr: Malformed message received"); - return; - } - ifi = if_find_by_index(i->ifa_index); - if (!ifi) + bzero(&ifa, sizeof(ifa)); + + if (i->ifa_family == AF_INET) + { + if (!a[IFA_ADDRESS] || (RTA_PAYLOAD(a[IFA_ADDRESS]) != sizeof(ip4_addr)) || + !a[IFA_LOCAL] || (RTA_PAYLOAD(a[IFA_LOCAL]) != sizeof(ip4_addr))) + goto malformed; + + addr = rta4_get_ipa(a[IFA_ADDRESS]); + ifa.ip = rta4_get_ipa(a[IFA_LOCAL]); + ipv4 = 1; + } + else if (i->ifa_family == AF_INET6) + { + if (!a[IFA_ADDRESS] || (RTA_PAYLOAD(a[IFA_ADDRESS]) != sizeof(ip6_addr)) || + (a[IFA_LOCAL] && (RTA_PAYLOAD(a[IFA_LOCAL]) != sizeof(ip6_addr)))) + goto malformed; + + addr = rta6_get_ipa(a[IFA_ADDRESS]); + /* IFA_LOCAL can be unset for IPv6 interfaces */ + ifa.ip = a[IFA_LOCAL] ? rta6_get_ipa(a[IFA_LOCAL]) : addr; + } + else + return; /* Ignore unknown address families */ + + ifa.iface = if_find_by_index(i->ifa_index); + if (!ifa.iface) { log(L_ERR "KIF: Received address message for unknown interface %d", i->ifa_index); return; } - bzero(&ifa, sizeof(ifa)); - ifa.iface = ifi; if (i->ifa_flags & IFA_F_SECONDARY) ifa.flags |= IA_SECONDARY; - /* IFA_LOCAL can be unset for IPv6 interfaces */ - memcpy(&ifa.ip, RTA_DATA(a[IFA_LOCAL] ? : a[IFA_ADDRESS]), sizeof(ifa.ip)); - ipa_ntoh(ifa.ip); - ifa.pxlen = i->ifa_prefixlen; - if (i->ifa_prefixlen > BITS_PER_IP_ADDRESS) + ifa.pxlen = i->ifa_prefixlen + (ipv4 ? 96 : 0); // XXXXX: Hack + if (ifa.pxlen > BITS_PER_IP_ADDRESS) { - log(L_ERR "KIF: Invalid prefix length for interface %s: %d", ifi->name, i->ifa_prefixlen); - new = 0; + log(L_ERR "KIF: Received invalid pxlen %d on %s", i->ifa_prefixlen, ifa.iface->name); + return; } + if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS) { - ip_addr addr; - memcpy(&addr, RTA_DATA(a[IFA_ADDRESS]), sizeof(addr)); - ipa_ntoh(addr); ifa.prefix = ifa.brd = addr; /* It is either a host address or a peer address */ @@ -507,44 +522,36 @@ nl_parse_addr(struct nlmsghdr *h) else { ip_addr netmask = ipa_mkmask(ifa.pxlen); - ifa.prefix = ipa_and(ifa.ip, netmask); - ifa.brd = ipa_or(ifa.ip, ipa_not(netmask)); + ifa.prefix = ipa_and(addr, netmask); + ifa.brd = ipa_or(addr, ipa_not(netmask)); + if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS - 1) ifa.opposite = ipa_opposite_m1(ifa.ip); -#ifndef IPV6 - if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS - 2) + if ((i->ifa_prefixlen == BITS_PER_IP_ADDRESS - 2) && ipv4) ifa.opposite = ipa_opposite_m2(ifa.ip); - - if ((ifi->flags & IF_BROADCAST) && a[IFA_BROADCAST]) - { - ip_addr xbrd; - memcpy(&xbrd, RTA_DATA(a[IFA_BROADCAST]), sizeof(xbrd)); - ipa_ntoh(xbrd); - if (ipa_equal(xbrd, ifa.prefix) || ipa_equal(xbrd, ifa.brd)) - ifa.brd = xbrd; - else if (ifi->flags & IF_TMP_DOWN) /* Complain only during the first scan */ - log(L_ERR "KIF: Invalid broadcast address %I for %s", xbrd, ifi->name); - } -#endif } - scope = ipa_classify(ifa.ip); - if (scope < 0) + int scope = ipa_classify(ifa.ip); + if ((scope == IADDR_INVALID) || !(scope & IADDR_HOST)) { - log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, ifi->name); + log(L_ERR "KIF: Received invalid address %I on %s", ifa.ip, ifa.iface->name); return; } ifa.scope = scope & IADDR_SCOPE_MASK; DBG("KIF: IF%d(%s): %s IPA %I, flg %x, net %I/%d, brd %I, opp %I\n", - ifi->index, ifi->name, - new ? "added" : "removed", + ifa.iface->index, ifa.iface->name, new ? "added" : "removed", ifa.ip, ifa.flags, ifa.prefix, ifa.pxlen, ifa.brd, ifa.opposite); if (new) ifa_update(&ifa); else ifa_delete(&ifa); + return; + + malformed: + log(L_ERR "KIF: Received malformed address message"); + return; } void @@ -554,14 +561,24 @@ kif_do_scan(struct kif_proto *p UNUSED) if_start_update(); - nl_request_dump(RTM_GETLINK); + /* Is it important which PF_* is used for link-level interface scan? + It seems that some information is available only when PF_INET is used. */ + + nl_request_dump(PF_INET, RTM_GETLINK); while (h = nl_get_scan()) if (h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK) nl_parse_link(h, 1); else log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type); - nl_request_dump(RTM_GETADDR); + nl_request_dump(PF_INET, RTM_GETADDR); + while (h = nl_get_scan()) + if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) + nl_parse_addr(h); + else + log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type); + + nl_request_dump(PF_INET6, RTM_GETADDR); while (h = nl_get_scan()) if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) nl_parse_addr(h); @@ -944,7 +961,7 @@ krt_do_scan(struct krt_proto *p UNUSED) /* CONFIG_ALL_TABLES_AT_ONCE => p is NUL { struct nlmsghdr *h; - nl_request_dump(RTM_GETROUTE); + nl_request_dump(BIRD_PF, RTM_GETROUTE); while (h = nl_get_scan()) if (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE) nl_parse_route(h, 1); @@ -1055,11 +1072,9 @@ nl_open_async(void) bzero(&sa, sizeof(sa)); sa.nl_family = AF_NETLINK; -#ifdef IPV6 - sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE; -#else - sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE; -#endif + sa.nl_groups = RTMGRP_LINK | + RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE | + RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE; if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { log(L_ERR "Unable to bind asynchronous rtnetlink socket: %m"); diff --git a/sysdep/linux/sysio.h b/sysdep/linux/sysio.h index 90b3ebd9..90e164fb 100644 --- a/sysdep/linux/sysio.h +++ b/sysdep/linux/sysio.h @@ -6,9 +6,11 @@ * Can be freely distributed and used under the terms of the GNU GPL. */ +#include +#include + #include -#ifdef IPV6 #ifndef IPV6_UNICAST_HOPS /* Needed on glibc 2.0 systems */ @@ -16,22 +18,10 @@ #define CONFIG_IPV6_GLIBC_20 #endif -static inline void -set_inaddr(struct in6_addr *ia, ip_addr a) -{ - ipa_hton(a); - memcpy(ia, &a, sizeof(a)); -} -static inline void -get_inaddr(ip_addr *a, struct in6_addr *ia) -{ - memcpy(a, ia, sizeof(*a)); - ipa_ntoh(*a); -} static inline char * -sysio_bind_to_iface(sock *s) +sk_bind_to_iface(sock *s) { struct ifreq ifr; strcpy(ifr.ifr_name, s->iface->name); @@ -41,22 +31,6 @@ sysio_bind_to_iface(sock *s) return NULL; } -#else - -static inline void -set_inaddr(struct in_addr *ia, ip_addr a) -{ - ipa_hton(a); - memcpy(&ia->s_addr, &a, sizeof(a)); -} - -static inline void -get_inaddr(ip_addr *a, struct in_addr *ia) -{ - memcpy(a, &ia->s_addr, sizeof(*a)); - ipa_ntoh(*a); -} - #ifndef HAVE_STRUCT_IP_MREQN /* Several versions of glibc don't define this structure, so we have to do it ourselves */ @@ -73,12 +47,12 @@ static inline void fill_mreqn(struct ip_mreqn *m, struct iface *ifa, ip_addr sad { bzero(m, sizeof(*m)); m->imr_ifindex = ifa->index; - set_inaddr(&m->imr_address, saddr); - set_inaddr(&m->imr_multiaddr, maddr); + ipa_put_in4(&m->imr_address, saddr); + ipa_put_in4(&m->imr_multiaddr, maddr); } static inline char * -sysio_setup_multicast(sock *s) +sk_setup_multicast4(sock *s) { struct ip_mreqn m; int zero = 0; @@ -95,16 +69,11 @@ sysio_setup_multicast(sock *s) return "IP_MULTICAST_IF"; /* Is this necessary? */ - struct ifreq ifr; - strcpy(ifr.ifr_name, s->iface->name); - if (setsockopt(s->fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0) - return "SO_BINDTODEVICE"; - - return NULL; + return sk_bind_to_iface(s); } static inline char * -sysio_join_group(sock *s, ip_addr maddr) +sk_join_group4(sock *s, ip_addr maddr) { struct ip_mreqn m; @@ -117,7 +86,7 @@ sysio_join_group(sock *s, ip_addr maddr) } static inline char * -sysio_leave_group(sock *s, ip_addr maddr) +sk_leave_group4(sock *s, ip_addr maddr) { struct ip_mreqn m; @@ -129,12 +98,8 @@ sysio_leave_group(sock *s, ip_addr maddr) return NULL; } -#endif -#include -#include - /* For the case that we have older kernel headers */ /* Copied from Linux kernel file include/linux/tcp.h */ @@ -154,12 +119,12 @@ struct tcp_md5sig { #endif static int -sk_set_md5_auth_int(sock *s, sockaddr *sa, char *passwd) +sk_set_md5_auth_int(sock *s, struct sockaddr *sa, int sa_len, char *passwd) { struct tcp_md5sig md5; memset(&md5, 0, sizeof(md5)); - memcpy(&md5.tcpm_addr, (struct sockaddr *) sa, sizeof(*sa)); + memcpy(&md5.tcpm_addr, sa, sa_len); if (passwd) { @@ -182,57 +147,42 @@ sk_set_md5_auth_int(sock *s, sockaddr *sa, char *passwd) if (errno == ENOPROTOOPT) log(L_ERR "Kernel does not support TCP MD5 signatures"); else - log(L_ERR "sk_set_md5_auth_int: setsockopt: %m"); + log(L_ERR "sk_set_md5_auth_int: TCP_MD5SIG: %m"); } return rv; } -#ifndef IPV6 - /* RX/TX packet info handling for IPv4 */ /* Mostly similar to standardized IPv6 code */ -#define CMSG_RX_SPACE CMSG_SPACE(sizeof(struct in_pktinfo)) -#define CMSG_TX_SPACE CMSG_SPACE(sizeof(struct in_pktinfo)) +#define CMSG_SPACE_PKTINFO4 CMSG_SPACE(sizeof(struct in_pktinfo)) +#define CMSG_SPACE_PKTINFO6 CMSG_SPACE(sizeof(struct in6_pktinfo)) -static char * -sysio_register_cmsgs(sock *s) +#define CMSG_RX_SPACE MAX(CMSG_SPACE_PKTINFO4,CMSG_SPACE_PKTINFO6) +#define CMSG_TX_SPACE MAX(CMSG_SPACE_PKTINFO4,CMSG_SPACE_PKTINFO6) + +static inline char * +sk_request_pktinfo4(sock *s) { int ok = 1; - if ((s->flags & SKF_LADDR_RX) && - setsockopt(s->fd, IPPROTO_IP, IP_PKTINFO, &ok, sizeof(ok)) < 0) - return "IP_PKTINFO"; + if (s->flags & SKF_LADDR_RX) + if (setsockopt(s->fd, IPPROTO_IP, IP_PKTINFO, &ok, sizeof(ok)) < 0) + return "IP_PKTINFO"; return NULL; } -static void -sysio_process_rx_cmsgs(sock *s, struct msghdr *msg) +static inline void +sk_process_rx_cmsg4(sock *s, struct cmsghdr *cm) { - struct cmsghdr *cm; - struct in_pktinfo *pi = NULL; - - if (!(s->flags & SKF_LADDR_RX)) - return; - - for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm)) + if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_PKTINFO) { - if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_PKTINFO) - pi = (struct in_pktinfo *) CMSG_DATA(cm); + struct in_pktinfo *pi = (struct in_pktinfo *) CMSG_DATA(cm); + s->laddr = ipa_get_in4(&pi->ipi_addr); + s->lifindex = pi->ipi_ifindex; } - - if (!pi) - { - s->laddr = IPA_NONE; - s->lifindex = 0; - return; - } - - get_inaddr(&s->laddr, &pi->ipi_addr); - s->lifindex = pi->ipi_ifindex; - return; } /* @@ -261,8 +211,6 @@ sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) } */ -#endif - #ifndef IP_MINTTL #define IP_MINTTL 21 @@ -273,7 +221,8 @@ sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) #endif -#ifndef IPV6 +// XXXX +#if 0 static int sk_set_min_ttl4(sock *s, int ttl) @@ -291,8 +240,6 @@ sk_set_min_ttl4(sock *s, int ttl) return 0; } -#else - static int sk_set_min_ttl6(sock *s, int ttl) { diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 475d660c..de21f680 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -581,6 +581,77 @@ static struct resclass sk_class = { NULL }; +#define SOCKADDR_DEFINE(sa, len, af) struct sockaddr *sa; int len; sockaddr_init(sa, len, af) +#define sockaddr_init(sa, len, af) do { len=sockaddr_size(af); sa=alloca(len); sa->sa_family=af; } while(0) + +static inline int sockaddr_size(int af) +{ return (af == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); } + +static inline void +sockaddr_fill4(struct sockaddr_in *sa, ip_addr a, struct iface *ifa, unsigned port) +{ + sa->sin_port = htons(port); +#ifdef HAVE_SIN_LEN + sa->sin_len = sizeof(struct sockaddr_in); +#endif + ipa_put_in4(&sa->sin_addr, a); +} + +static inline void +sockaddr_fill6(struct sockaddr_in6 *sa, ip_addr a, struct iface *ifa, unsigned port) +{ + sa->sin6_port = htons(port); + sa->sin6_flowinfo = 0; +#ifdef SIN6_LEN + sa->sin6_len = sizeof(struct sockaddr_in6); +#endif + ipa_put_in6(&sa->sin6_addr, a); + sa->sin6_scope_id = (ifa && ipa_is_link_local(a)) ? ifa->index : 0; +} + +void +sockaddr_fill(struct sockaddr *sa, ip_addr a, struct iface *ifa, unsigned port) +{ + if (sa->sa_family == AF_INET) + sockaddr_fill4((struct sockaddr_in *) sa, a, ifa, port); + else if (sa->sa_family == AF_INET6) + sockaddr_fill6((struct sockaddr_in6 *) sa, a, ifa, port); + else + bug("%s called for wrong AF (%d)", "sockaddr_fill", sa->sa_family); +} + +static inline void +sockaddr_read4(struct sockaddr_in *sa, ip_addr *a, struct iface **ifa, unsigned *port) +{ + if (port) + *port = ntohs(sa->sin_port); + *a = ipa_get_in4(&sa->sin_addr); +} + +static inline void +sockaddr_read6(struct sockaddr_in6 *sa, ip_addr *a, struct iface **ifa, unsigned *port) +{ + if (port) + *port = ntohs(sa->sin6_port); + *a = ipa_get_in6(&sa->sin6_addr); + + if (ifa && ipa_is_link_local(*a)) + *ifa = if_find_by_index(sa->sin6_scope_id); +} + +void +sockaddr_read(struct sockaddr *sa, ip_addr *a, struct iface **ifa, unsigned *port, int check) +{ + if (sa->sa_family == AF_INET) + sockaddr_read4((struct sockaddr_in *) sa, a, ifa, port); + else if (sa->sa_family == AF_INET6) + sockaddr_read6((struct sockaddr_in6 *) sa, a, ifa, port); + else if (check) + bug("%s called for wrong AF (%d)", "sockaddr_read", sa->sa_family); +} + + + /** * sk_new - create a socket * @p: pool @@ -607,71 +678,9 @@ sk_insert(sock *s) sock_recalc_fdsets_p = 1; } -#ifdef IPV6 -void -fill_in_sockaddr(struct sockaddr_in6 *sa, ip_addr a, struct iface *ifa, unsigned port) -{ - memset(sa, 0, sizeof (struct sockaddr_in6)); - sa->sin6_family = AF_INET6; - sa->sin6_port = htons(port); - sa->sin6_flowinfo = 0; -#ifdef HAVE_SIN_LEN - sa->sin6_len = sizeof(struct sockaddr_in6); -#endif - set_inaddr(&sa->sin6_addr, a); - - if (ifa && ipa_has_link_scope(a)) - sa->sin6_scope_id = ifa->index; -} - -void -get_sockaddr(struct sockaddr_in6 *sa, ip_addr *a, struct iface **ifa, unsigned *port, int check) -{ - if (check && sa->sin6_family != AF_INET6) - bug("get_sockaddr called for wrong address family (%d)", sa->sin6_family); - if (port) - *port = ntohs(sa->sin6_port); - memcpy(a, &sa->sin6_addr, sizeof(*a)); - ipa_ntoh(*a); - - if (ifa && ipa_has_link_scope(*a)) - *ifa = if_find_by_index(sa->sin6_scope_id); -} - -#else - -void -fill_in_sockaddr(struct sockaddr_in *sa, ip_addr a, struct iface *ifa, unsigned port) -{ - memset (sa, 0, sizeof (struct sockaddr_in)); - sa->sin_family = AF_INET; - sa->sin_port = htons(port); -#ifdef HAVE_SIN_LEN - sa->sin_len = sizeof(struct sockaddr_in); -#endif - set_inaddr(&sa->sin_addr, a); -} - -void -get_sockaddr(struct sockaddr_in *sa, ip_addr *a, struct iface **ifa, unsigned *port, int check) -{ - if (check && sa->sin_family != AF_INET) - bug("get_sockaddr called for wrong address family (%d)", sa->sin_family); - if (port) - *port = ntohs(sa->sin_port); - memcpy(a, &sa->sin_addr.s_addr, sizeof(*a)); - ipa_ntoh(*a); -} - -#endif - - -#ifdef IPV6 /* PKTINFO handling is also standardized in IPv6 */ -#define CMSG_RX_SPACE CMSG_SPACE(sizeof(struct in6_pktinfo)) -#define CMSG_TX_SPACE CMSG_SPACE(sizeof(struct in6_pktinfo)) /* * RFC 2292 uses IPV6_PKTINFO for both the socket option and the cmsg @@ -683,42 +692,39 @@ get_sockaddr(struct sockaddr_in *sa, ip_addr *a, struct iface **ifa, unsigned *p #define IPV6_RECVPKTINFO IPV6_PKTINFO #endif -static char * -sysio_register_cmsgs(sock *s) +static inline char * +sk_request_pktinfo6(sock *s) { int ok = 1; - if ((s->flags & SKF_LADDR_RX) && - setsockopt(s->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &ok, sizeof(ok)) < 0) - return "IPV6_RECVPKTINFO"; + if (s->flags & SKF_LADDR_RX) + if (setsockopt(s->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &ok, sizeof(ok)) < 0) + return "IPV6_RECVPKTINFO"; return NULL; } static void -sysio_process_rx_cmsgs(sock *s, struct msghdr *msg) +sk_process_rx_cmsgs(sock *s, struct msghdr *msg) { struct cmsghdr *cm; - struct in6_pktinfo *pi = NULL; if (!(s->flags & SKF_LADDR_RX)) return; + s->laddr = IPA_NONE; + s->lifindex = 0; + for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm)) { if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO) - pi = (struct in6_pktinfo *) CMSG_DATA(cm); - } + { + struct in6_pktinfo *pi = (struct in6_pktinfo *) CMSG_DATA(cm); + s->laddr = ipa_get_in6(&pi->ipi6_addr); + s->lifindex = pi->ipi6_ifindex; + } - if (!pi) - { - s->laddr = IPA_NONE; - s->lifindex = 0; - return; + sk_process_rx_cmsg4(s, cm); } - - get_inaddr(&s->laddr, &pi->ipi6_addr); - s->lifindex = pi->ipi6_ifindex; - return; } /* @@ -747,25 +753,6 @@ sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) return; } */ -#endif - -static char * -sk_set_ttl_int(sock *s) -{ -#ifdef IPV6 - if (setsockopt(s->fd, SOL_IPV6, IPV6_UNICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0) - return "IPV6_UNICAST_HOPS"; -#else - if (setsockopt(s->fd, SOL_IP, IP_TTL, &s->ttl, sizeof(s->ttl)) < 0) - return "IP_TTL"; -#ifdef CONFIG_UNIX_DONTROUTE - int one = 1; - if (s->ttl == 1 && setsockopt(s->fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0) - return "SO_DONTROUTE"; -#endif -#endif - return NULL; -} #define ERR(x) do { err = x; goto bad; } while(0) #define WARN(x) log(L_WARN "sk_setup: %s: %m", x) @@ -773,28 +760,32 @@ sk_set_ttl_int(sock *s) static char * sk_setup(sock *s) { + int one = 1; int fd = s->fd; char *err = NULL; if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) ERR("fcntl(O_NONBLOCK)"); - if (s->type == SK_UNIX) + + if (!s->af) return NULL; -#ifndef IPV6 - if ((s->tos >= 0) && setsockopt(fd, SOL_IP, IP_TOS, &s->tos, sizeof(s->tos)) < 0) - WARN("IP_TOS"); -#endif -#ifdef IPV6 - int v = 1; - if ((s->flags & SKF_V6ONLY) && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &v, sizeof(v)) < 0) - WARN("IPV6_V6ONLY"); -#endif + if (sk_is_ipv4(s) && (s->tos >= 0)) + if (setsockopt(fd, SOL_IP, IP_TOS, &s->tos, sizeof(s->tos)) < 0) + WARN("IP_TOS"); + if (sk_is_ipv6(s) && (s->flags & SKF_V6ONLY)) + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0) + WARN("IPV6_V6ONLY"); + + // XXXX better error handling if (s->ttl >= 0) - err = sk_set_ttl_int(s); + sk_set_ttl(s, s->ttl); - sysio_register_cmsgs(s); + if (sk_is_ipv4(s)) + err = sk_request_pktinfo4(s); + else + err = sk_request_pktinfo6(s); bad: return err; } @@ -816,11 +807,30 @@ sk_set_ttl(sock *s, int ttl) { char *err; - s->ttl = ttl; - if (err = sk_set_ttl_int(s)) - log(L_ERR "sk_set_ttl: %s: %m", err); + if (sk_is_ipv4(s)) + { + if (setsockopt(s->fd, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) + ERR("IP_TTL"); - return (err ? -1 : 0); +#ifdef CONFIG_UNIX_DONTROUTE + int one = 1; + if (ttl == 1) + if (setsockopt(s->fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0) + ERR("SO_DONTROUTE"); +#endif + } + else + { + if (setsockopt(s->fd, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0) + ERR("IPV6_UNICAST_HOPS"); + } + + s->ttl = ttl; + return 0; + + bad: + log(L_ERR "sk_set_ttl: %s: %m", err); + return -1; } /** @@ -836,16 +846,30 @@ sk_set_ttl(sock *s, int ttl) int sk_set_min_ttl(sock *s, int ttl) { - int err; -#ifdef IPV6 - err = sk_set_min_ttl6(s, ttl); -#else - err = sk_set_min_ttl4(s, ttl); -#endif + char *err; - return err; + if (sk_is_ipv4(s)) + { + if (setsockopt(s->fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0) + ERR("IP_MINTTL"); + } + else + { + if (setsockopt(s->fd, IPPROTO_IPV6, IPV6_MINHOPCOUNT, &ttl, sizeof(ttl)) < 0) + ERR("IPV6_MINHOPCOUNT"); + } + + return 0; + + bad: + if (errno == ENOPROTOOPT) + log(L_ERR "Kernel does not support %s TTL security", sk_is_ipv4(s) ? "IPv4" : "IPv6"); + else + log(L_ERR "sk_set_min_ttl: %s: %m", err); + return -1; } + /** * sk_set_md5_auth - add / remove MD5 security association for given socket. * @s: socket @@ -868,9 +892,9 @@ sk_set_min_ttl(sock *s, int ttl) int sk_set_md5_auth(sock *s, ip_addr a, struct iface *ifa, char *passwd) { - sockaddr sa; - fill_in_sockaddr(&sa, a, ifa, 0); - return sk_set_md5_auth_int(s, &sa, passwd); + SOCKADDR_DEFINE(sa, sa_len, s->af); + sockaddr_fill(sa, a, ifa, 0); + return sk_set_md5_auth_int(s, sa, sa_len, passwd); } int @@ -885,9 +909,6 @@ sk_set_broadcast(sock *s, int enable) return 0; } - -#ifdef IPV6 - int sk_set_ipv6_checksum(sock *s, int offset) { @@ -901,7 +922,7 @@ sk_set_ipv6_checksum(sock *s, int offset) } int -sk_set_icmp_filter(sock *s, int p1, int p2) +sk_set_icmp6_filter(sock *s, int p1, int p2) { /* a bit of lame interface, but it is here only for Radv */ struct icmp6_filter f; @@ -912,86 +933,45 @@ sk_set_icmp_filter(sock *s, int p1, int p2) if (setsockopt(s->fd, IPPROTO_ICMPV6, ICMP6_FILTER, &f, sizeof(f)) < 0) { - log(L_ERR "sk_setup_icmp_filter: ICMP6_FILTER: %m"); + log(L_ERR "sk_set_icmp6_filter: ICMP6_FILTER: %m"); return -1; } return 0; } -int -sk_setup_multicast(sock *s) + +static inline void +fill_mreq6(struct ipv6_mreq *m, struct iface *ifa, ip_addr maddr) +{ + bzero(m, sizeof(*m)); + +#ifdef CONFIG_IPV6_GLIBC_20 + m->ipv6mr_ifindex = ifa->index; +#else + m->ipv6mr_interface = ifa->index; +#endif + + ipa_put_in6(&m->ipv6mr_multiaddr, maddr); +} + +static inline char * +sk_setup_multicast6(sock *s) { - char *err; int zero = 0; - int index; + int index = s->iface->index; - ASSERT(s->iface && s->iface->addr); - - index = s->iface->index; if (setsockopt(s->fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0) - ERR("IPV6_MULTICAST_HOPS"); + return "IPV6_MULTICAST_HOPS"; if (setsockopt(s->fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &zero, sizeof(zero)) < 0) - ERR("IPV6_MULTICAST_LOOP"); + return "IPV6_MULTICAST_LOOP"; if (setsockopt(s->fd, SOL_IPV6, IPV6_MULTICAST_IF, &index, sizeof(index)) < 0) - ERR("IPV6_MULTICAST_IF"); + return "IPV6_MULTICAST_IF"; - if (err = sysio_bind_to_iface(s)) - goto bad; - - return 0; - -bad: - log(L_ERR "sk_setup_multicast: %s: %m", err); - return -1; + /* Is this necessary? */ + return sk_bind_to_iface(s); } -int -sk_join_group(sock *s, ip_addr maddr) -{ - struct ipv6_mreq mreq; - - set_inaddr(&mreq.ipv6mr_multiaddr, maddr); - -#ifdef CONFIG_IPV6_GLIBC_20 - mreq.ipv6mr_ifindex = s->iface->index; -#else - mreq.ipv6mr_interface = s->iface->index; -#endif - - if (setsockopt(s->fd, SOL_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) - { - log(L_ERR "sk_join_group: IPV6_JOIN_GROUP: %m"); - return -1; - } - - return 0; -} - -int -sk_leave_group(sock *s, ip_addr maddr) -{ - struct ipv6_mreq mreq; - - set_inaddr(&mreq.ipv6mr_multiaddr, maddr); - -#ifdef CONFIG_IPV6_GLIBC_20 - mreq.ipv6mr_ifindex = s->iface->index; -#else - mreq.ipv6mr_interface = s->iface->index; -#endif - - if (setsockopt(s->fd, SOL_IPV6, IPV6_LEAVE_GROUP, &mreq, sizeof(mreq)) < 0) - { - log(L_ERR "sk_leave_group: IPV6_LEAVE_GROUP: %m"); - return -1; - } - - return 0; -} - -#else /* IPV4 */ - int sk_setup_multicast(sock *s) { @@ -999,7 +979,12 @@ sk_setup_multicast(sock *s) ASSERT(s->iface && s->iface->addr); - if (err = sysio_setup_multicast(s)) + if (sk_is_ipv4(s)) + err = sk_setup_multicast4(s); + else + err = sk_setup_multicast6(s); + + if (err) { log(L_ERR "sk_setup_multicast: %s: %m", err); return -1; @@ -1008,12 +993,29 @@ sk_setup_multicast(sock *s) return 0; } +static inline char * +sk_join_group6(sock *s, ip_addr maddr) +{ + struct ipv6_mreq m; + + fill_mreq6(&m, s->iface, maddr); + if (setsockopt(s->fd, SOL_IPV6, IPV6_JOIN_GROUP, &m, sizeof(m)) < 0) + return "IPV6_JOIN_GROUP"; + + return NULL; +} + int sk_join_group(sock *s, ip_addr maddr) { - char *err; + char *err; - if (err = sysio_join_group(s, maddr)) + if (sk_is_ipv4(s)) + err = sk_join_group4(s, maddr); + else + err = sk_join_group6(s, maddr); + + if (err) { log(L_ERR "sk_join_group: %s: %m", err); return -1; @@ -1022,12 +1024,29 @@ sk_join_group(sock *s, ip_addr maddr) return 0; } +static inline char * +sk_leave_group6(sock *s, ip_addr maddr) +{ + struct ipv6_mreq m; + + fill_mreq6(&m, s->iface, maddr); + if (setsockopt(s->fd, SOL_IPV6, IPV6_LEAVE_GROUP, &m, sizeof(m)) < 0) + return "IPV6_LEAVE_GROUP"; + + return NULL; +} + int sk_leave_group(sock *s, ip_addr maddr) { - char *err; + char *err; - if (err = sysio_leave_group(s, maddr)) + if (sk_is_ipv4(s)) + err = sk_leave_group4(s, maddr); + else + err = sk_leave_group6(s, maddr); + + if (err) { log(L_ERR "sk_leave_group: %s: %m", err); return -1; @@ -1036,16 +1055,15 @@ sk_leave_group(sock *s, ip_addr maddr) return 0; } -#endif static void sk_tcp_connected(sock *s) { - sockaddr lsa; - int lsa_len = sizeof(lsa); - if (getsockname(s->fd, (struct sockaddr *) &lsa, &lsa_len) == 0) - get_sockaddr(&lsa, &s->saddr, &s->iface, &s->sport, 1); + SOCKADDR_DEFINE(sa, sa_len, s->af); + + if (getsockname(s->fd, sa, &sa_len) == 0) + sockaddr_read(sa, &s->saddr, &s->iface, &s->sport, 1); s->type = SK_TCP; sk_alloc_bufs(s); @@ -1053,35 +1071,35 @@ sk_tcp_connected(sock *s) } static int -sk_passive_connected(sock *s, struct sockaddr *sa, int al, int type) +sk_passive_connected(sock *s, struct sockaddr *sa, int sa_len, int type) { - int fd = accept(s->fd, sa, &al); + int fd = accept(s->fd, sa, &sa_len); if (fd >= 0) { sock *t = sk_new(s->pool); char *err; t->type = type; t->fd = fd; + t->af = s->af; t->ttl = s->ttl; t->tos = s->tos; t->rbsize = s->rbsize; t->tbsize = s->tbsize; if (type == SK_TCP) { - sockaddr lsa; - int lsa_len = sizeof(lsa); - if (getsockname(fd, (struct sockaddr *) &lsa, &lsa_len) == 0) - get_sockaddr(&lsa, &t->saddr, &t->iface, &t->sport, 1); + SOCKADDR_DEFINE(lsa, lsa_len, t->af); + if (getsockname(fd, lsa, &lsa_len) == 0) // XXXX + sockaddr_read(lsa, &t->saddr, &t->iface, &t->sport, 1); - get_sockaddr((sockaddr *) sa, &t->daddr, &t->iface, &t->dport, 1); + sockaddr_read(sa, &t->daddr, &t->iface, &t->dport, 1); } - sk_insert(t); if (err = sk_setup(t)) { - log(L_ERR "Incoming connection: %s: %m", err); + log(L_ERR "sk_passive_connected: %s: %m", err); rfree(t); return 1; } + sk_insert(t); sk_alloc_bufs(t); s->rx_hook(t, 0); return 1; @@ -1106,9 +1124,6 @@ sk_passive_connected(sock *s, struct sockaddr *sa, int al, int type) int sk_open(sock *s) { - int fd; - sockaddr sa; - int one = 1; int type = s->type; int has_src = ipa_nonzero(s->saddr) || s->sport; char *err; @@ -1119,27 +1134,35 @@ sk_open(sock *s) s->ttx = ""; /* Force s->ttx != s->tpos */ /* Fall thru */ case SK_TCP_PASSIVE: - fd = socket(BIRD_PF, SOCK_STREAM, IPPROTO_TCP); + s->af = (s->flags & SKF_V4ONLY) ? AF_INET : AF_INET6; + s->fd = socket(s->af, SOCK_STREAM, IPPROTO_TCP); break; case SK_UDP: - fd = socket(BIRD_PF, SOCK_DGRAM, IPPROTO_UDP); + s->af = (s->flags & SKF_V4ONLY) ? AF_INET : AF_INET6; + s->fd = socket(s->af, SOCK_DGRAM, IPPROTO_UDP); break; case SK_IP: - fd = socket(BIRD_PF, SOCK_RAW, s->dport); + s->af = (s->flags & SKF_V4ONLY) ? AF_INET : AF_INET6; + s->fd = socket(s->af, SOCK_RAW, s->dport); break; case SK_MAGIC: - fd = s->fd; - break; + if (err = sk_setup(s)) + goto bad; + sk_insert(s); + return 0; default: bug("sk_open() called for invalid sock type %d", type); } + + int fd = s->fd; if (fd < 0) - die("sk_open: socket: %m"); - s->fd = fd; + ERR("socket"); if (err = sk_setup(s)) goto bad; + SOCKADDR_DEFINE(sa, sa_len, s->af); + if (has_src) { int port; @@ -1149,26 +1172,26 @@ sk_open(sock *s) else { port = s->sport; + + int one = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) ERR("SO_REUSEADDR"); } - fill_in_sockaddr(&sa, s->saddr, s->iface, port); - if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) + + sockaddr_fill(sa, s->saddr, s->iface, port); + if (bind(fd, sa, sa_len) < 0) ERR("bind"); } - fill_in_sockaddr(&sa, s->daddr, s->iface, s->dport); + sockaddr_fill(sa, s->daddr, s->iface, s->dport); if (s->password) - { - int rv = sk_set_md5_auth_int(s, &sa, s->password); - if (rv < 0) - goto bad_no_log; - } + if (sk_set_md5_auth_int(s, sa, sa_len, s->password) < 0) + goto bad_no_log; switch (type) { case SK_TCP_ACTIVE: - if (connect(fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0) + if (connect(fd, sa, sa_len) >= 0) sk_tcp_connected(s); else if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS && errno != ECONNREFUSED && errno != EHOSTUNREACH && errno != ENETUNREACH) @@ -1178,26 +1201,25 @@ sk_open(sock *s) if (listen(fd, 8)) ERR("listen"); break; - case SK_MAGIC: - break; default: sk_alloc_bufs(s); -#ifdef IPV6 -#ifdef IPV6_MTU_DISCOVER - { - int dont = IPV6_PMTUDISC_DONT; - if (setsockopt(fd, SOL_IPV6, IPV6_MTU_DISCOVER, &dont, sizeof(dont)) < 0) - ERR("IPV6_MTU_DISCOVER"); - } -#endif -#else + #ifdef IP_PMTUDISC - { - int dont = IP_PMTUDISC_DONT; - if (setsockopt(fd, SOL_IP, IP_PMTUDISC, &dont, sizeof(dont)) < 0) - ERR("IP_PMTUDISC"); - } + if (sk_is_ipv4(s)) + { + int dont = IP_PMTUDISC_DONT; + if (setsockopt(fd, SOL_IP, IP_PMTUDISC, &dont, sizeof(dont)) < 0) + ERR("IP_PMTUDISC"); + } #endif + +#ifdef IPV6_MTU_DISCOVER + if (sk_is_ipv6(s)) + { + int dont = IPV6_PMTUDISC_DONT; + if (setsockopt(fd, SOL_IPV6, IPV6_MTU_DISCOVER, &dont, sizeof(dont)) < 0) + ERR("IPV6_MTU_DISCOVER"); + } #endif } @@ -1207,7 +1229,8 @@ sk_open(sock *s) bad: log(L_ERR "sk_open: %s: %m", err); bad_no_log: - close(fd); + close(s->fd); + s->af = 0; s->fd = -1; return -1; } @@ -1278,15 +1301,15 @@ sk_maybe_write(sock *s) if (s->tbuf == s->tpos) return 1; - sockaddr sa; - fill_in_sockaddr(&sa, s->daddr, s->iface, s->dport); + SOCKADDR_DEFINE(sa, sa_len, s->af); + sockaddr_fill(sa, s->daddr, s->iface, s->dport); struct iovec iov = {s->tbuf, s->tpos - s->tbuf}; // byte cmsg_buf[CMSG_TX_SPACE]; struct msghdr msg = { - .msg_name = &sa, - .msg_namelen = sizeof(sa), + .msg_name = sa, + .msg_namelen = sa_len, .msg_iov = &iov, .msg_iovlen = 1}; @@ -1396,13 +1419,12 @@ sk_read(sock *s) { case SK_TCP_PASSIVE: { - sockaddr sa; - return sk_passive_connected(s, (struct sockaddr *) &sa, sizeof(sa), SK_TCP); + SOCKADDR_DEFINE(sa, sa_len, s->af); + return sk_passive_connected(s, sa, sa_len, SK_TCP); } case SK_UNIX_PASSIVE: { - struct sockaddr_un sa; - return sk_passive_connected(s, (struct sockaddr *) &sa, sizeof(sa), SK_UNIX); + return sk_passive_connected(s, NULL, 0, SK_UNIX); } case SK_TCP: case SK_UNIX: @@ -1433,15 +1455,15 @@ sk_read(sock *s) return s->rx_hook(s, 0); default: { - sockaddr sa; + SOCKADDR_DEFINE(sa, sa_len, s->af); int e; struct iovec iov = {s->rbuf, s->rbsize}; byte cmsg_buf[CMSG_RX_SPACE]; struct msghdr msg = { - .msg_name = &sa, - .msg_namelen = sizeof(sa), + .msg_name = sa, + .msg_namelen = sa_len, .msg_iov = &iov, .msg_iovlen = 1, .msg_control = cmsg_buf, @@ -1457,8 +1479,8 @@ sk_read(sock *s) return 0; } s->rpos = s->rbuf + e; - get_sockaddr(&sa, &s->faddr, NULL, &s->fport, 1); - sysio_process_rx_cmsgs(s, &msg); + sockaddr_read(sa, &s->faddr, NULL, &s->fport, 1); + sk_process_rx_cmsgs(s, &msg); s->rx_hook(s, e); return 1; @@ -1473,9 +1495,10 @@ sk_write(sock *s) { case SK_TCP_ACTIVE: { - sockaddr sa; - fill_in_sockaddr(&sa, s->daddr, s->iface, s->dport); - if (connect(s->fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0 || errno == EISCONN) + SOCKADDR_DEFINE(sa, sa_len, s->af); + sockaddr_fill(sa, s->daddr, s->iface, s->dport); + + if (connect(s->fd, sa, sa_len) >= 0 || errno == EISCONN) sk_tcp_connected(s); else if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS) s->err_hook(s, errno); diff --git a/sysdep/unix/unix.h b/sysdep/unix/unix.h index 3e85c85c..a9edbebc 100644 --- a/sysdep/unix/unix.h +++ b/sysdep/unix/unix.h @@ -28,17 +28,11 @@ volatile int async_config_flag; volatile int async_dump_flag; volatile int async_shutdown_flag; -#ifdef IPV6 +// XXXX #define BIRD_PF PF_INET6 #define BIRD_AF AF_INET6 -typedef struct sockaddr_in6 sockaddr; -static inline int sa_family_check(sockaddr *sa) { return sa->sin6_family == AF_INET6; } -#else -#define BIRD_PF PF_INET -#define BIRD_AF AF_INET -typedef struct sockaddr_in sockaddr; -static inline int sa_family_check(sockaddr *sa) { return sa->sin_family == AF_INET; } -#endif +static inline int sa_family_check(struct sockaddr *sa) { return sa->sa_family == AF_INET6; } + #ifndef SUN_LEN #define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) + strlen ((ptr)->sun_path)) @@ -49,8 +43,6 @@ struct iface; void io_init(void); void io_loop(void); -void fill_in_sockaddr(sockaddr *sa, ip_addr a, struct iface *ifa, unsigned port); -void get_sockaddr(sockaddr *sa, ip_addr *a, struct iface **ifa, unsigned *port, int check); void sk_open_unix(struct birdsock *s, char *name); void *tracked_fopen(struct pool *, char *name, char *mode); void test_old_bird(char *path); diff --git a/tools/Makefile.in b/tools/Makefile.in index 728e5797..182e97c9 100644 --- a/tools/Makefile.in +++ b/tools/Makefile.in @@ -57,14 +57,14 @@ tags: install: all $(INSTALL) -d $(DESTDIR)/$(sbindir) $(DESTDIR)/$(sysconfdir) $(DESTDIR)/@runtimedir@ - $(INSTALL_PROGRAM) -s $(exedir)/bird $(DESTDIR)/$(sbindir)/bird@SUFFIX@ + $(INSTALL_PROGRAM) -s $(exedir)/bird $(DESTDIR)/$(sbindir)/bird if test -n "@CLIENT@" ; then \ - $(INSTALL_PROGRAM) -s $(exedir)/birdc $(DESTDIR)/$(sbindir)/birdc@SUFFIX@ ; \ + $(INSTALL_PROGRAM) -s $(exedir)/birdc $(DESTDIR)/$(sbindir)/birdc ; \ fi if ! test -f $(DESTDIR)/@CONFIG_FILE@ ; then \ $(INSTALL_DATA) $(srcdir)/doc/bird.conf.example $(DESTDIR)/@CONFIG_FILE@ ; \ else \ - echo "Not overwriting old bird@SUFFIX@.conf" ; \ + echo "Not overwriting old bird.conf" ; \ fi install-docs: