0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 09:41:54 +00:00

Temporary integrated commit.

This commit is contained in:
Ondrej Zajicek 2012-06-22 13:38:52 +02:00
parent 95127cbbb7
commit b9c8061b19
25 changed files with 1159 additions and 1299 deletions

View File

@ -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}+ {

View File

@ -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;
}

View File

@ -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 <i> NUM ENUM
%token <i32> RTRID
%token <a> IPA
%token <a4> IP4
%token <a6> IP6
%token <s> SYM
%token <t> TEXT
%type <iface> ipa_scope
%type <i> expr bool pxlen
%type <time> datetime
%type <a> ipa
%type <a> ipa ipa_raw
%type <px> prefix prefix_or_ipa
%type <t> 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;

View File

@ -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.])
;;

View File

@ -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;
}

View File

@ -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

332
lib/ip.c
View File

@ -6,6 +6,8 @@
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include <stdlib.h>
#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

385
lib/ip.h
View File

@ -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

View File

@ -1,110 +0,0 @@
/*
* BIRD Library -- IPv4 Address Manipulation Functions
*
* (c) 1998 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include <stdlib.h>
#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;
}

View File

@ -1,107 +0,0 @@
/*
* BIRD -- IP Addresses et Cetera for IPv4
*
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
*
* 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

View File

@ -1,384 +0,0 @@
/*
* BIRD Library -- IPv6 Address Manipulation Functions
*
* (c) 1999 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include <stdlib.h>
#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

View File

@ -1,138 +0,0 @@
/*
* BIRD -- IP Addresses et Cetera for IPv6
*
* (c) 1999--2000 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#ifndef _BIRD_IPV6_H_
#define _BIRD_IPV6_H_
#include <sys/types.h>
#include <netinet/in.h>
#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

View File

@ -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;

View File

@ -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 */
/*

View File

@ -17,6 +17,7 @@
* if possible.
*/
#include "lib/endian.h"
#include "lib/string.h"
static inline u16

View File

@ -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); }
;

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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"

View File

@ -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");

View File

@ -6,9 +6,11 @@
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include <linux/socket.h>
#include <linux/tcp.h>
#include <net/if.h>
#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 <linux/socket.h>
#include <linux/tcp.h>
/* 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)
{

View File

@ -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);

View File

@ -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);

View File

@ -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: