Basic support for IPv6. The system-dependent part doesn't work yet,
but the core routines are there and seem to be working. o lib/ipv6.[ch] written o Lexical analyser recognizes IPv6 addresses and when in IPv6 mode, treats pure IPv4 addresses as router IDs. o Router ID must be configured manually on IPv6 systems. o Added SCOPE_ORGANIZATION for org-scoped IPv6 multicasts. o Fixed few places where ipa_(hton|ntoh) was called as a function returning converted address.
This commit is contained in:
parent
707ef83378
commit
dce267832a
13 changed files with 438 additions and 48 deletions
19
TODO
19
TODO
|
@ -14,8 +14,7 @@ Core
|
||||||
- default preferences of protocols: prefer BGP over OSPF/RIP external routes?
|
- default preferences of protocols: prefer BGP over OSPF/RIP external routes?
|
||||||
|
|
||||||
- static: check validity of route destination?
|
- static: check validity of route destination?
|
||||||
|
- static: allow specifying a per-route filter program for setting route attributes?
|
||||||
- device: configuration of interface patterns
|
|
||||||
|
|
||||||
- rte_update: check whether all bits not covered by masklen are zero
|
- rte_update: check whether all bits not covered by masklen are zero
|
||||||
- rte_update: debug mode
|
- rte_update: debug mode
|
||||||
|
@ -31,6 +30,7 @@ Core
|
||||||
- config: executable config files
|
- config: executable config files
|
||||||
- config: when parsing prefix, check zero bits
|
- config: when parsing prefix, check zero bits
|
||||||
- config: reconfiguration
|
- config: reconfiguration
|
||||||
|
- config: useless rules when protocols disabled
|
||||||
|
|
||||||
- krt: rescan interfaces when route addition fails?
|
- krt: rescan interfaces when route addition fails?
|
||||||
- krt: does PERSIST mode have any sense if kernel syncer is shut down as last?
|
- krt: does PERSIST mode have any sense if kernel syncer is shut down as last?
|
||||||
|
@ -53,47 +53,41 @@ Cleanup
|
||||||
- replace all NUM, IPA and expr tokens by constant filter expressions
|
- replace all NUM, IPA and expr tokens by constant filter expressions
|
||||||
- try compiling with -Wunused
|
- try compiling with -Wunused
|
||||||
- does everybody test return value of sk_open?
|
- does everybody test return value of sk_open?
|
||||||
|
- add references to RFC's we did follow
|
||||||
|
|
||||||
Various ideas
|
Various ideas
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
- real multipath (doesn't seem to be simple at all :()
|
- real multipath (doesn't seem to be simple at all :()
|
||||||
- fake multipath (even less simple)
|
- fake multipath (even less simple)
|
||||||
- route recalculation timing and flap dampening [see RFC2439 for algorithms]
|
- route recalculation timing and flap dampening [see RFC2439 for algorithms]
|
||||||
- aggregate engine: standard route aggregation and summarization
|
- aggregate engine: standard route aggregation and summarization [RFC2519]
|
||||||
- aggregate engine: injection of manually configured pseudo-static routes
|
- aggregate engine: injection of manually configured pseudo-static routes
|
||||||
- generate default route if any working BGP connection exists (aggregate engine again?)
|
- generate default route if any working BGP connection exists (aggregate engine again?)
|
||||||
- generate default route to IGP's (aggregate engine yet another time?)
|
- generate default route to IGP's (aggregate engine yet another time?)
|
||||||
|
- look at RFC 2386 (QoS-based routing)
|
||||||
|
|
||||||
|
|
||||||
RIP
|
RIP
|
||||||
~~~
|
~~~
|
||||||
- RIP: export-only and import-only mode?
|
- export-only and import-only mode?
|
||||||
- drop RIPv1 (Historic protocol)?
|
- drop RIPv1 (Historic protocol)?
|
||||||
- Route Tag
|
- Route Tag
|
||||||
- limit routing table xfer (frequency, only to neighbors)
|
- limit routing table xfer (frequency, only to neighbors)
|
||||||
- multicast on/off (per interface)
|
|
||||||
|
|
||||||
OSPF
|
OSPF
|
||||||
~~~~
|
~~~~
|
||||||
- importing of device routes for networks where we don't run OSPF
|
- importing of device routes for networks where we don't run OSPF
|
||||||
- check incoming packets using neighbor cache
|
- check incoming packets using neighbor cache
|
||||||
- stub area: either no external routes or only default route
|
|
||||||
- RFC2328 appendix E: Use a better algorithm
|
- RFC2328 appendix E: Use a better algorithm
|
||||||
- automatic generation of external route tags (RFC1403)
|
- automatic generation of external route tags (RFC1403)
|
||||||
- RFC1587 NSSA areas
|
- RFC1587 NSSA areas
|
||||||
- RFC2370 opaque LSA's
|
- RFC2370 opaque LSA's
|
||||||
- RFC1793 Demand Circuit Support ??
|
|
||||||
- respect interface MTU and try not to create larger packets unless unavoidable
|
- respect interface MTU and try not to create larger packets unless unavoidable
|
||||||
|
|
||||||
|
|
||||||
BGP
|
BGP
|
||||||
~~~
|
~~~
|
||||||
- in, local, out RIB
|
|
||||||
- maxsize=4096
|
|
||||||
- detection of loops
|
|
||||||
- aggregation, ATOMIC_AGGREGATE
|
- aggregation, ATOMIC_AGGREGATE
|
||||||
- communities
|
- communities
|
||||||
- confederations
|
|
||||||
- attributes must be sorted!
|
- attributes must be sorted!
|
||||||
- re-export of NEXT_HOP attribute
|
- re-export of NEXT_HOP attribute
|
||||||
- BGP session over currently down interface
|
- BGP session over currently down interface
|
||||||
|
@ -104,7 +98,6 @@ BGP
|
||||||
- inter-advertisement delay???!
|
- inter-advertisement delay???!
|
||||||
- normalize (sort) incoming AS-SET's
|
- normalize (sort) incoming AS-SET's
|
||||||
- maximum length of AS paths
|
- maximum length of AS paths
|
||||||
|
|
||||||
- expected neighbor AS
|
- expected neighbor AS
|
||||||
- hold time
|
- hold time
|
||||||
- idle timer after error: initial value, exponential growth, maximum value
|
- idle timer after error: initial value, exponential growth, maximum value
|
||||||
|
|
|
@ -65,9 +65,25 @@ WHITE [ \t]
|
||||||
%%
|
%%
|
||||||
|
|
||||||
{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
|
{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
|
||||||
|
#ifdef IPV6
|
||||||
|
if (ipv4_pton_u32(yytext, &cf_lval.i32))
|
||||||
|
return RTRID;
|
||||||
|
cf_error("Invalid IPv4 address %s", yytext);
|
||||||
|
#else
|
||||||
if (ip_pton(yytext, &cf_lval.a))
|
if (ip_pton(yytext, &cf_lval.a))
|
||||||
return IPA;
|
return IPA;
|
||||||
cf_error("Invalid IP address");
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
0x{DIGIT}+ {
|
0x{DIGIT}+ {
|
||||||
|
|
|
@ -54,6 +54,10 @@ config_parse(struct config *c)
|
||||||
cf_parse();
|
cf_parse();
|
||||||
filters_postconfig(); /* FIXME: Do we really need this? */
|
filters_postconfig(); /* FIXME: Do we really need this? */
|
||||||
protos_postconfig(c);
|
protos_postconfig(c);
|
||||||
|
#ifdef IPV6
|
||||||
|
if (!c->router_id)
|
||||||
|
cf_error("Router ID must be configured manually on IPv6 routers");
|
||||||
|
#endif
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ CF_DECLS
|
||||||
|
|
||||||
%union {
|
%union {
|
||||||
int i;
|
int i;
|
||||||
|
u32 i32;
|
||||||
ip_addr a;
|
ip_addr a;
|
||||||
struct symbol *s;
|
struct symbol *s;
|
||||||
char *t;
|
char *t;
|
||||||
|
@ -35,6 +36,7 @@ CF_DECLS
|
||||||
|
|
||||||
%token END
|
%token END
|
||||||
%token <i> NUM
|
%token <i> NUM
|
||||||
|
%token <i32> RTRID
|
||||||
%token <a> IPA
|
%token <a> IPA
|
||||||
%token <s> SYM
|
%token <s> SYM
|
||||||
%token <t> TEXT
|
%token <t> TEXT
|
||||||
|
|
|
@ -2,7 +2,7 @@ birdlib.h
|
||||||
bitops.c
|
bitops.c
|
||||||
bitops.h
|
bitops.h
|
||||||
ip.h
|
ip.h
|
||||||
#ifdef CONFIG_IPV6
|
#ifdef IPV6
|
||||||
ipv6.c
|
ipv6.c
|
||||||
ipv6.h
|
ipv6.h
|
||||||
#else
|
#else
|
||||||
|
|
3
lib/ip.h
3
lib/ip.h
|
@ -35,7 +35,8 @@
|
||||||
#define SCOPE_HOST 0
|
#define SCOPE_HOST 0
|
||||||
#define SCOPE_LINK 1
|
#define SCOPE_LINK 1
|
||||||
#define SCOPE_SITE 2
|
#define SCOPE_SITE 2
|
||||||
#define SCOPE_UNIVERSE 3
|
#define SCOPE_ORGANIZATION 3
|
||||||
|
#define SCOPE_UNIVERSE 4
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Is it a valid network prefix?
|
* Is it a valid network prefix?
|
||||||
|
|
349
lib/ipv6.c
349
lib/ipv6.c
|
@ -1,12 +1,357 @@
|
||||||
/*
|
/*
|
||||||
* BIRD Library -- IPv6 Address Manipulation Functions
|
* BIRD Library -- IPv6 Address Manipulation Functions
|
||||||
*
|
*
|
||||||
* (c) 1998 Martin Mares <mj@ucw.cz>
|
* (c) 1999 Martin Mares <mj@ucw.cz>
|
||||||
*
|
*
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "nest/bird.h"
|
#include "nest/bird.h"
|
||||||
#include "lib/ip.h"
|
#include "lib/ip.h"
|
||||||
|
#include "lib/bitops.h"
|
||||||
|
#include "lib/endian.h"
|
||||||
|
|
||||||
#error "Ought to implement these."
|
/*
|
||||||
|
* 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];
|
||||||
|
|
||||||
|
/* FIXME: Relax these requirements? */
|
||||||
|
if ((x & 0xe0000000) == 0x20000000) /* Aggregatable Global Unicast Address */
|
||||||
|
return IADDR_HOST | SCOPE_UNIVERSE;
|
||||||
|
if ((x & 0xfc000000) == 0xe8000000) /* Link-Local Address */
|
||||||
|
return IADDR_HOST | SCOPE_LINK;
|
||||||
|
if ((x & 0xfc000000) == 0xec000000) /* Site-Local Address */
|
||||||
|
return IADDR_HOST | SCOPE_SITE;
|
||||||
|
if ((x & 0xff000000) == 0xff000000) /* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return IADDR_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
char *c;
|
||||||
|
|
||||||
|
/* 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 += sprintf(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 += sprintf(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 += sprintf(b, "%08x", a.addr[i]);
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ipv4_pton_u32(char *a, u32 *o)
|
||||||
|
{
|
||||||
|
int i,j;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
46
lib/ipv6.h
46
lib/ipv6.h
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* BIRD -- IP Addresses et Cetera for IPv6
|
* BIRD -- IP Addresses et Cetera for IPv6
|
||||||
*
|
*
|
||||||
* (c) 1998 Martin Mares <mj@ucw.cz>
|
* (c) 1999 Martin Mares <mj@ucw.cz>
|
||||||
*
|
*
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
@ -12,11 +12,11 @@
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
typedef struct ipv4_addr {
|
typedef struct ipv6_addr {
|
||||||
u32 addr[4];
|
u32 addr[4];
|
||||||
} ip_addr;
|
} ip_addr;
|
||||||
|
|
||||||
#define _MI(a,b,c,d) ((struct ip_addr) { a, b, c, d })
|
#define _MI(a,b,c,d) ((struct ipv6_addr) {{ a, b, c, d }})
|
||||||
#define _I0(a) ((a).addr[0])
|
#define _I0(a) ((a).addr[0])
|
||||||
#define _I1(a) ((a).addr[1])
|
#define _I1(a) ((a).addr[1])
|
||||||
#define _I2(a) ((a).addr[2])
|
#define _I2(a) ((a).addr[2])
|
||||||
|
@ -28,38 +28,50 @@ typedef struct ipv4_addr {
|
||||||
#define IPA_NONE _MI(0,0,0,0)
|
#define IPA_NONE _MI(0,0,0,0)
|
||||||
|
|
||||||
#define ipa_equal(x,y) (!memcmp(&(x),&(y),sizeof(ip_addr)))
|
#define ipa_equal(x,y) (!memcmp(&(x),&(y),sizeof(ip_addr)))
|
||||||
#define ipa_nonzero(x) (_I0(a) || _I1(a) || _I2(a) || _I3(a))
|
#define ipa_nonzero(x) ({ ip_addr _a=(x); (_I0(_a) || _I1(_a) || _I2(_a) || _I3(_a)); })
|
||||||
#define ipa_and(a,b) _MI(_I0(a) & _I0(b), \
|
#define ipa_and(x,y) ({ ip_addr _a=(x), _b=(y); \
|
||||||
_I1(a) & _I1(b), \
|
_MI(_I0(_a) & _I0(_b), \
|
||||||
_I2(a) & _I2(b), \
|
_I1(_a) & _I1(_b), \
|
||||||
_I3(a) & _I3(b))
|
_I2(_a) & _I2(_b), \
|
||||||
#define ipa_or(a,b) _MI(_I0(a) | _I0(b), \
|
_I3(_a) & _I3(_b)); })
|
||||||
_I1(a) | _I1(b), \
|
#define ipa_or(x,y) ({ ip_addr _a=(x), _b=(y); \
|
||||||
_I2(a) | _I2(b), \
|
_MI(_I0(_a) | _I0(_b), \
|
||||||
_I3(a) | _I3(b))
|
_I1(_a) | _I1(_b), \
|
||||||
#define ipa_xor(a,b) _MI(_I0(a) ^ _I0(b), \
|
_I2(_a) | _I2(_b), \
|
||||||
_I1(a) ^ _I1(b), \
|
_I3(_a) | _I3(_b)); })
|
||||||
_I2(a) ^ _I2(b), \
|
#define ipa_xor(x,y) ({ ip_addr _a=(x), _b=(y); \
|
||||||
_I3(a) ^ _I3(b))
|
_MI(_I0(_a) ^ _I0(_b), \
|
||||||
#define ipa_not(a) _MI(~_I0(a),~_I1(a),~_I2(a),~_I3(a))
|
_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_mkmask(x) ipv6_mkmask(x)
|
||||||
#define ipa_mklen(x) ipv6_mklen(&(x))
|
#define ipa_mklen(x) ipv6_mklen(&(x))
|
||||||
#define ipa_hash(x) ipv6_hash(&(x))
|
#define ipa_hash(x) ipv6_hash(&(x))
|
||||||
#define ipa_hton(x) ipv6_hton(&(x))
|
#define ipa_hton(x) ipv6_hton(&(x))
|
||||||
#define ipa_ntoh(x) ipv6_ntoh(&(x))
|
#define ipa_ntoh(x) ipv6_ntoh(&(x))
|
||||||
#define ipa_classify(x) ipv6_classify(&(x))
|
#define ipa_classify(x) ipv6_classify(&(x))
|
||||||
|
/* ipa_opposite and 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)
|
||||||
|
|
||||||
ip_addr ipv6_mkmask(unsigned);
|
ip_addr ipv6_mkmask(unsigned);
|
||||||
unsigned ipv6_mklen(ip_addr *);
|
unsigned ipv6_mklen(ip_addr *);
|
||||||
int ipv6_classify(ip_addr *);
|
int ipv6_classify(ip_addr *);
|
||||||
void ipv6_hton(ip_addr *);
|
void ipv6_hton(ip_addr *);
|
||||||
void ipv6_ntoh(ip_addr *);
|
void ipv6_ntoh(ip_addr *);
|
||||||
|
int ipv6_compare(ip_addr *, ip_addr *);
|
||||||
|
int ipv4_pton_u32(char *, u32 *);
|
||||||
|
|
||||||
/* FIXME: Is this hash function uniformly distributed over standard routing tables? */
|
/* FIXME: Is this hash function uniformly distributed over standard routing tables? */
|
||||||
static inline unsigned ipv6_hash(ip_addr *a)
|
static inline unsigned ipv6_hash(ip_addr *a)
|
||||||
{
|
{
|
||||||
|
/* Returns a 16-bit hash key */
|
||||||
u32 x = _I0(*a) ^ _I1(*a) ^ _I2(*a) ^ _I3(*a);
|
u32 x = _I0(*a) ^ _I1(*a) ^ _I2(*a) ^ _I3(*a);
|
||||||
return (x ^ (x >> 16) ^ (x >> 8)) & 0xffff;
|
return (x ^ (x >> 16) ^ (x >> 8)) & 0xffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define IP_PREC_INTERNET_CONTROL 0 /* FIXME: What's the right value? */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -20,7 +20,7 @@ CF_KEYWORDS(ROUTER, ID, PROTOCOL, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
|
||||||
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE)
|
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE)
|
||||||
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID)
|
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID)
|
||||||
|
|
||||||
%type <i> idval
|
%type <i32> idval
|
||||||
%type <f> imexport
|
%type <f> imexport
|
||||||
%type <r> rtable
|
%type <r> rtable
|
||||||
%type <p> password_list password_begin
|
%type <p> password_list password_begin
|
||||||
|
@ -37,8 +37,15 @@ rtrid: ROUTER ID idval ';' {
|
||||||
;
|
;
|
||||||
|
|
||||||
idval:
|
idval:
|
||||||
NUM
|
NUM { $$ = $1; }
|
||||||
| IPA { $$ = ipa_to_u32($1); }
|
| RTRID
|
||||||
|
| IPA {
|
||||||
|
#ifndef IPV6
|
||||||
|
$$ = ipa_to_u32($1);
|
||||||
|
#else
|
||||||
|
cf_error("Router IDs must be entered as hexadecimal numbers in IPv6 version");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
/* Creation of routing tables */
|
/* Creation of routing tables */
|
||||||
|
|
|
@ -549,8 +549,9 @@ ifa_delete(struct ifa *a)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
auto_router_id(void) /* FIXME: What if we run IPv6??? */
|
auto_router_id(void)
|
||||||
{
|
{
|
||||||
|
#ifndef IPV6
|
||||||
struct iface *i, *j;
|
struct iface *i, *j;
|
||||||
|
|
||||||
j = NULL;
|
j = NULL;
|
||||||
|
@ -564,6 +565,7 @@ auto_router_id(void) /* FIXME: What if we run IPv6??? */
|
||||||
die("Cannot determine router ID (no suitable network interface found), please configure it manually");
|
die("Cannot determine router ID (no suitable network interface found), please configure it manually");
|
||||||
debug("Guessed router ID %I (%s)\n", j->addr->ip, j->name);
|
debug("Guessed router ID %I (%s)\n", j->addr->ip, j->name);
|
||||||
config->router_id = ipa_to_u32(j->addr->ip);
|
config->router_id = ipa_to_u32(j->addr->ip);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -8,9 +8,16 @@
|
||||||
|
|
||||||
#define IPV6
|
#define IPV6
|
||||||
|
|
||||||
#define CONFIG_TOS
|
|
||||||
#define CONFIG_AUTO_ROUTES
|
#define CONFIG_AUTO_ROUTES
|
||||||
#define CONFIG_ALL_MULTICAST
|
#define CONFIG_ALL_MULTICAST
|
||||||
|
#define CONFIG_SELF_CONSCIOUS
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Netlink supports multiple tables, but kernel IPv6 code doesn't, so we
|
||||||
|
* treat it as a multiple table system with number of tables set to 1.
|
||||||
|
*/
|
||||||
|
#define CONFIG_MULTIPLE_TABLES
|
||||||
|
#define CONFIG_ALL_TABLES_AT_ONCE
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Link: sysdep/linux/netlink
|
Link: sysdep/linux/netlink
|
||||||
|
|
|
@ -242,7 +242,7 @@ nl_add_attr_ipa(struct nlmsghdr *h, unsigned maxsize, int code, ip_addr ipa)
|
||||||
a = (struct rtattr *)((char *)h + NLMSG_ALIGN(h->nlmsg_len));
|
a = (struct rtattr *)((char *)h + NLMSG_ALIGN(h->nlmsg_len));
|
||||||
a->rta_type = code;
|
a->rta_type = code;
|
||||||
a->rta_len = len;
|
a->rta_len = len;
|
||||||
ipa = ipa_hton(ipa);
|
ipa_hton(ipa);
|
||||||
memcpy(RTA_DATA(a), &ipa, sizeof(ipa));
|
memcpy(RTA_DATA(a), &ipa, sizeof(ipa));
|
||||||
h->nlmsg_len = NLMSG_ALIGN(h->nlmsg_len) + len;
|
h->nlmsg_len = NLMSG_ALIGN(h->nlmsg_len) + len;
|
||||||
}
|
}
|
||||||
|
@ -351,17 +351,18 @@ nl_parse_addr(struct nlmsghdr *h)
|
||||||
if (i->ifa_flags & IFA_F_SECONDARY)
|
if (i->ifa_flags & IFA_F_SECONDARY)
|
||||||
ifa.flags |= IA_SECONDARY;
|
ifa.flags |= IA_SECONDARY;
|
||||||
memcpy(&ifa.ip, RTA_DATA(a[IFA_LOCAL]), sizeof(ifa.ip));
|
memcpy(&ifa.ip, RTA_DATA(a[IFA_LOCAL]), sizeof(ifa.ip));
|
||||||
ifa.ip = ipa_ntoh(ifa.ip);
|
ipa_ntoh(ifa.ip);
|
||||||
ifa.pxlen = i->ifa_prefixlen;
|
ifa.pxlen = i->ifa_prefixlen;
|
||||||
if (ifi->flags & IF_UNNUMBERED)
|
if (ifi->flags & IF_UNNUMBERED)
|
||||||
{
|
{
|
||||||
memcpy(&ifa.opposite, RTA_DATA(a[IFA_ADDRESS]), sizeof(ifa.opposite));
|
memcpy(&ifa.opposite, RTA_DATA(a[IFA_ADDRESS]), sizeof(ifa.opposite));
|
||||||
ifa.opposite = ifa.brd = ipa_ntoh(ifa.opposite);
|
ipa_ntoh(ifa.opposite);
|
||||||
|
ifa.brd = ifa.opposite;
|
||||||
}
|
}
|
||||||
else if ((ifi->flags & IF_BROADCAST) && a[IFA_BROADCAST])
|
else if ((ifi->flags & IF_BROADCAST) && a[IFA_BROADCAST])
|
||||||
{
|
{
|
||||||
memcpy(&ifa.brd, RTA_DATA(a[IFA_BROADCAST]), sizeof(ifa.brd));
|
memcpy(&ifa.brd, RTA_DATA(a[IFA_BROADCAST]), sizeof(ifa.brd));
|
||||||
ifa.brd = ipa_ntoh(ifa.brd);
|
ipa_ntoh(ifa.brd);
|
||||||
}
|
}
|
||||||
/* else a NBMA link */
|
/* else a NBMA link */
|
||||||
ifa.prefix = ipa_and(ifa.ip, ipa_mkmask(ifa.pxlen));
|
ifa.prefix = ipa_and(ifa.ip, ipa_mkmask(ifa.pxlen));
|
||||||
|
@ -575,7 +576,7 @@ nl_parse_route(struct nlmsghdr *h, int scan)
|
||||||
if (a[RTA_DST])
|
if (a[RTA_DST])
|
||||||
{
|
{
|
||||||
memcpy(&dst, RTA_DATA(a[RTA_DST]), sizeof(dst));
|
memcpy(&dst, RTA_DATA(a[RTA_DST]), sizeof(dst));
|
||||||
dst = ipa_ntoh(dst);
|
ipa_ntoh(dst);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
dst = IPA_NONE;
|
dst = IPA_NONE;
|
||||||
|
@ -630,7 +631,7 @@ nl_parse_route(struct nlmsghdr *h, int scan)
|
||||||
neighbor *ng;
|
neighbor *ng;
|
||||||
ra.dest = RTD_ROUTER;
|
ra.dest = RTD_ROUTER;
|
||||||
memcpy(&ra.gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ra.gw));
|
memcpy(&ra.gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ra.gw));
|
||||||
ra.gw = ipa_ntoh(ra.gw);
|
ipa_ntoh(ra.gw);
|
||||||
ng = neigh_find(&p->p, &ra.gw, 0);
|
ng = neigh_find(&p->p, &ra.gw, 0);
|
||||||
if (ng)
|
if (ng)
|
||||||
ra.iface = ng->iface;
|
ra.iface = ng->iface;
|
||||||
|
|
|
@ -314,7 +314,7 @@ sk_new(pool *p)
|
||||||
static inline void
|
static inline void
|
||||||
set_inaddr(struct in_addr *ia, ip_addr a)
|
set_inaddr(struct in_addr *ia, ip_addr a)
|
||||||
{
|
{
|
||||||
a = ipa_hton(a);
|
ipa_hton(a);
|
||||||
memcpy(&ia->s_addr, &a, sizeof(a));
|
memcpy(&ia->s_addr, &a, sizeof(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,7 +334,7 @@ get_sockaddr(struct sockaddr_in *sa, ip_addr *a, unsigned *port)
|
||||||
if (port)
|
if (port)
|
||||||
*port = ntohs(sa->sin_port);
|
*port = ntohs(sa->sin_port);
|
||||||
memcpy(a, &sa->sin_addr.s_addr, sizeof(*a));
|
memcpy(a, &sa->sin_addr.s_addr, sizeof(*a));
|
||||||
*a = ipa_ntoh(*a);
|
ipa_ntoh(*a);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
|
|
Loading…
Reference in a new issue