Integrated IP functions.
This commit is contained in:
parent
f8fefde318
commit
88a183c6c9
25 changed files with 874 additions and 889 deletions
|
@ -124,22 +124,24 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
|
||||||
}
|
}
|
||||||
|
|
||||||
{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
|
{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
|
||||||
#ifdef IPV6
|
ip4_addr a;
|
||||||
if (ipv4_pton_u32(yytext, &cf_lval.i32))
|
if (!ip4_pton(yytext, &a))
|
||||||
return RTRID;
|
|
||||||
cf_error("Invalid IPv4 address %s", yytext);
|
cf_error("Invalid IPv4 address %s", yytext);
|
||||||
|
|
||||||
|
#ifdef IPV6
|
||||||
|
cf_lval.i32 = ip4_to_u32(a);
|
||||||
|
return RTRID;
|
||||||
#else
|
#else
|
||||||
if (ip_pton(yytext, &cf_lval.a))
|
cf_lval.a = ipa_from_ip4(a);
|
||||||
return IPA;
|
return IPA;
|
||||||
cf_error("Invalid IP address %s", yytext);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
({XIGIT}*::|({XIGIT}*:){3,})({XIGIT}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+) {
|
({XIGIT}*::|({XIGIT}*:){3,})({XIGIT}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+) {
|
||||||
#ifdef IPV6
|
#ifdef IPV6
|
||||||
if (ip_pton(yytext, &cf_lval.a))
|
if (ipa_pton(yytext, &cf_lval.a))
|
||||||
return IPA;
|
return IPA;
|
||||||
cf_error("Invalid IP address %s", yytext);
|
cf_error("Invalid IPv6 address %s", yytext);
|
||||||
#else
|
#else
|
||||||
cf_error("This is an IPv4 router, therefore IPv6 addresses are not supported");
|
cf_error("This is an IPv4 router, therefore IPv6 addresses are not supported");
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -187,7 +187,7 @@ pxlen:
|
||||||
$$ = $2;
|
$$ = $2;
|
||||||
}
|
}
|
||||||
| ':' ipa {
|
| ':' ipa {
|
||||||
$$ = ipa_mklen($2);
|
$$ = ipa_masklen($2);
|
||||||
if ($$ < 0) cf_error("Invalid netmask %I", $2);
|
if ($$ < 0) cf_error("Invalid netmask %I", $2);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
|
@ -3,13 +3,6 @@ bitops.c
|
||||||
bitops.h
|
bitops.h
|
||||||
ip.h
|
ip.h
|
||||||
ip.c
|
ip.c
|
||||||
#ifdef IPV6
|
|
||||||
ipv6.c
|
|
||||||
ipv6.h
|
|
||||||
#else
|
|
||||||
ipv4.c
|
|
||||||
ipv4.h
|
|
||||||
#endif
|
|
||||||
lists.c
|
lists.c
|
||||||
lists.h
|
lists.h
|
||||||
md5.c
|
md5.c
|
||||||
|
|
376
lib/ip.c
376
lib/ip.c
|
@ -1,14 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* BIRD Library -- IP address routines common for IPv4 and IPv6
|
* BIRD Library -- IP address functions
|
||||||
*
|
*
|
||||||
* (c) 1998--2000 Martin Mares <mj@ucw.cz>
|
* (c) 1998--2000 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 "nest/bird.h"
|
|
||||||
#include "lib/ip.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DOC: IP addresses
|
* DOC: IP addresses
|
||||||
*
|
*
|
||||||
|
@ -18,6 +15,333 @@
|
||||||
* they must be manipulated using the following functions and macros.
|
* they must be manipulated using the following functions and macros.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "nest/bird.h"
|
||||||
|
#include "lib/ip.h"
|
||||||
|
|
||||||
|
|
||||||
|
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(uint n)
|
||||||
|
{
|
||||||
|
ip6_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ip6_masklen(ip6_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 */
|
||||||
|
{
|
||||||
|
uint 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
|
* ip_scope_text - get textual representation of address scope
|
||||||
* @scope: scope (%SCOPE_xxx)
|
* @scope: scope (%SCOPE_xxx)
|
||||||
|
@ -25,7 +349,7 @@
|
||||||
* Returns a pointer to a textual name of the scope given.
|
* Returns a pointer to a textual name of the scope given.
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
ip_scope_text(unsigned scope)
|
ip_scope_text(uint scope)
|
||||||
{
|
{
|
||||||
static char *scope_table[] = { "host", "link", "site", "org", "univ", "undef" };
|
static char *scope_table[] = { "host", "link", "site", "org", "univ", "undef" };
|
||||||
|
|
||||||
|
@ -35,6 +359,23 @@ ip_scope_text(unsigned scope)
|
||||||
return scope_table[scope];
|
return scope_table[scope];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ip4_addr
|
||||||
|
ip4_class_mask(ip4_addr ad)
|
||||||
|
{
|
||||||
|
u32 m, a = _I(ad);
|
||||||
|
|
||||||
|
if (a < 0x80000000)
|
||||||
|
m = 0xff000000;
|
||||||
|
else if (a < 0xc0000000)
|
||||||
|
m = 0xffff0000;
|
||||||
|
else
|
||||||
|
m = 0xffffff00;
|
||||||
|
if (a & ~m)
|
||||||
|
m = 0xffffffff;
|
||||||
|
|
||||||
|
return _MI4(m);
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/**
|
/**
|
||||||
* ipa_equal - compare two IP addresses for equality
|
* ipa_equal - compare two IP addresses for equality
|
||||||
|
@ -102,14 +443,14 @@ ip_addr ipa_not(ip_addr x) { DUMMY }
|
||||||
ip_addr ipa_mkmask(int x) { DUMMY }
|
ip_addr ipa_mkmask(int x) { DUMMY }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ipa_mkmask - calculate netmask length
|
* ipa_masklen - calculate netmask length
|
||||||
* @x: IP address
|
* @x: IP address
|
||||||
*
|
*
|
||||||
* This function checks whether @x represents a valid netmask and
|
* This function checks whether @x represents a valid netmask and
|
||||||
* returns the size of the associate network prefix or -1 for invalid
|
* returns the size of the associate network prefix or -1 for invalid
|
||||||
* mask.
|
* mask.
|
||||||
*/
|
*/
|
||||||
int ipa_mklen(ip_addr x) { DUMMY }
|
int ipa_masklen(ip_addr x) { DUMMY }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ipa_hash - hash IP addresses
|
* ipa_hash - hash IP addresses
|
||||||
|
@ -151,8 +492,8 @@ void ipa_ntoh(ip_addr x) { DUMMY }
|
||||||
int ipa_classify(ip_addr x) { DUMMY }
|
int ipa_classify(ip_addr x) { DUMMY }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ipa_class_mask - guess netmask according to address class
|
* ip4_class_mask - guess netmask according to address class
|
||||||
* @x: IP address
|
* @x: IPv4 address
|
||||||
*
|
*
|
||||||
* This function (available in IPv4 version only) returns a
|
* This function (available in IPv4 version only) returns a
|
||||||
* network mask according to the address class of @x. Although
|
* network mask according to the address class of @x. Although
|
||||||
|
@ -160,7 +501,7 @@ int ipa_classify(ip_addr x) { DUMMY }
|
||||||
* routing protocols transferring no prefix lengths nor netmasks
|
* routing protocols transferring no prefix lengths nor netmasks
|
||||||
* and this function could be useful to them.
|
* and this function could be useful to them.
|
||||||
*/
|
*/
|
||||||
ip_addr ipa_class_mask(ip_addr x) { DUMMY }
|
ip4_addr ip4_class_mask(ip4_addr x) { DUMMY }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ipa_from_u32 - convert IPv4 address to an integer
|
* ipa_from_u32 - convert IPv4 address to an integer
|
||||||
|
@ -193,7 +534,7 @@ ip_addr ipa_to_u32(u32 x) { DUMMY }
|
||||||
int ipa_compare(ip_addr x, ip_addr y) { 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
|
* @a1: part #1
|
||||||
* @a2: part #2
|
* @a2: part #2
|
||||||
* @a3: part #3
|
* @a3: part #3
|
||||||
|
@ -203,18 +544,7 @@ int ipa_compare(ip_addr x, ip_addr y) { DUMMY }
|
||||||
* address. It's used for example when a protocol wants to bind its
|
* address. It's used for example when a protocol wants to bind its
|
||||||
* socket to a hard-wired multicast address.
|
* socket to a hard-wired multicast address.
|
||||||
*/
|
*/
|
||||||
ip_addr ipa_build(u32 a1, u32 a2, u32 a3, u32 a4) { DUMMY }
|
ip_addr ipa_build6(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_ntop - convert IP address to textual representation
|
* ip_ntop - convert IP address to textual representation
|
||||||
|
|
465
lib/ip.h
465
lib/ip.h
|
@ -9,32 +9,274 @@
|
||||||
#ifndef _BIRD_IP_H_
|
#ifndef _BIRD_IP_H_
|
||||||
#define _BIRD_IP_H_
|
#define _BIRD_IP_H_
|
||||||
|
|
||||||
#ifndef IPV6
|
#include "lib/endian.h"
|
||||||
#include "ipv4.h"
|
#include "lib/string.h"
|
||||||
|
#include "lib/bitops.h"
|
||||||
|
#include "lib/unaligned.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define IP4_OSPF_ALL_ROUTERS ipa_build4(224, 0, 0, 5)
|
||||||
|
#define IP4_OSPF_DES_ROUTERS ipa_build4(224, 0, 0, 6)
|
||||||
|
|
||||||
|
#define IP6_ALL_NODES ipa_build6(0xFF020000, 0, 0, 1)
|
||||||
|
#define IP6_ALL_ROUTERS ipa_build6(0xFF020000, 0, 0, 2)
|
||||||
|
#define IP6_OSPF_ALL_ROUTERS ipa_build6(0xFF020000, 0, 0, 5)
|
||||||
|
#define IP6_OSPF_DES_ROUTERS ipa_build6(0xFF020000, 0, 0, 6)
|
||||||
|
#define IP6_RIP_ROUTERS ipa_build6(0xFF020000, 0, 0, 9)
|
||||||
|
|
||||||
|
#define IP4_NONE _MI4(0)
|
||||||
|
#define IP6_NONE _MI6(0,0,0,0)
|
||||||
|
|
||||||
|
#define IP4_MIN_MTU 576
|
||||||
|
#define IP6_MIN_MTU 1280
|
||||||
|
|
||||||
|
#define IP_PREC_INTERNET_CONTROL 0xc0
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef IPV6
|
||||||
|
#define MAX_PREFIX_LENGTH 128
|
||||||
|
#define BITS_PER_IP_ADDRESS 128
|
||||||
|
#define STD_ADDRESS_P_LENGTH 39
|
||||||
|
#define SIZE_OF_IP_HEADER 40
|
||||||
#else
|
#else
|
||||||
#include "ipv6.h"
|
#define MAX_PREFIX_LENGTH 32
|
||||||
|
#define BITS_PER_IP_ADDRESS 32
|
||||||
|
#define STD_ADDRESS_P_LENGTH 15
|
||||||
|
#define SIZE_OF_IP_HEADER 24
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef DEBUGGING
|
||||||
|
|
||||||
|
typedef struct ip4_addr {
|
||||||
|
u32 addr;
|
||||||
|
} ip4_addr;
|
||||||
|
|
||||||
|
#define _MI4(x) ((struct ip4_addr) { x })
|
||||||
|
#define _I(x) (x).addr
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
typedef u32 ip4_addr;
|
||||||
|
|
||||||
|
#define _MI4(x) (x)
|
||||||
|
#define _I(x) (x)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
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])
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef IPV6
|
||||||
|
|
||||||
|
/* Structure ip_addr may contain both IPv4 and IPv6 addresses */
|
||||||
|
typedef ip6_addr ip_addr;
|
||||||
|
#define IPA_NONE IP6_NONE
|
||||||
|
|
||||||
|
#define ipa_from_ip4(x) _MI6(0,0,0xffff,_I(x))
|
||||||
|
#define ipa_from_ip6(x) x
|
||||||
|
#define ipa_from_u32(x) ipa_from_ip4(ip4_from_u32(x))
|
||||||
|
|
||||||
|
#define ipa_to_ip4(x) _MI4(_I3(x))
|
||||||
|
#define ipa_to_ip6(x) x
|
||||||
|
#define ipa_to_u32(x) ip4_to_u32(ipa_to_ip4(x))
|
||||||
|
|
||||||
|
#define ipa_is_ip4(a) ip6_is_v4mapped(a)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Provisionary ip_addr definition same as ip4_addr */
|
||||||
|
typedef ip4_addr ip_addr;
|
||||||
|
#define IPA_NONE IP4_NONE
|
||||||
|
|
||||||
|
#define ipa_from_ip4(x) x
|
||||||
|
#define ipa_from_ip6(x) IPA_NONE
|
||||||
|
#define ipa_from_u32(x) ipa_from_ip4(ip4_from_u32(x))
|
||||||
|
|
||||||
|
#define ipa_to_ip4(x) x
|
||||||
|
#define ipa_to_ip6(x) IP6_NONE
|
||||||
|
#define ipa_to_u32(x) ip4_to_u32(ipa_to_ip4(x))
|
||||||
|
|
||||||
|
#define ipa_is_ip4(a) 1
|
||||||
|
|
||||||
#endif
|
#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)))))
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ip_classify() returns either a negative number for invalid addresses
|
* Public constructors
|
||||||
* or scope OR'ed together with address type.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define ip4_from_u32(x) _MI4(x)
|
||||||
|
#define ip4_to_u32(x) _I(x)
|
||||||
|
|
||||||
|
#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_build4(a,b,c,d) ipa_from_ip4(ip4_build(a,b,c,d))
|
||||||
|
#define ipa_build6(a,b,c,d) ipa_from_ip6(ip6_build(a,b,c,d))
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Basic algebraic functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline int ip4_equal(ip4_addr a, ip4_addr b)
|
||||||
|
{ return _I(a) == _I(b); }
|
||||||
|
|
||||||
|
static inline int ip4_zero(ip4_addr a)
|
||||||
|
{ return _I(a) == 0; }
|
||||||
|
|
||||||
|
static inline int ip4_nonzero(ip4_addr a)
|
||||||
|
{ return _I(a) != 0; }
|
||||||
|
|
||||||
|
static inline ip4_addr ip4_and(ip4_addr a, ip4_addr b)
|
||||||
|
{ return _MI4(_I(a) & _I(b)); }
|
||||||
|
|
||||||
|
static inline ip4_addr ip4_or(ip4_addr a, ip4_addr b)
|
||||||
|
{ return _MI4(_I(a) | _I(b)); }
|
||||||
|
|
||||||
|
static inline ip4_addr ip4_xor(ip4_addr a, ip4_addr b)
|
||||||
|
{ return _MI4(_I(a) ^ _I(b)); }
|
||||||
|
|
||||||
|
static inline ip4_addr ip4_not(ip4_addr a)
|
||||||
|
{ return _MI4(~_I(a)); }
|
||||||
|
|
||||||
|
|
||||||
|
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)); }
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef IPV6
|
||||||
|
#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)
|
||||||
|
#else
|
||||||
|
#define ipa_equal(x,y) ip4_equal(x,y)
|
||||||
|
#define ipa_zero(x) ip4_zero(x)
|
||||||
|
#define ipa_nonzero(x) ip4_nonzero(x)
|
||||||
|
#define ipa_and(x,y) ip4_and(x,y)
|
||||||
|
#define ipa_or(x,y) ip4_or(x,y)
|
||||||
|
#define ipa_xor(x,y) ip4_xor(x,y)
|
||||||
|
#define ipa_not(x) ip4_not(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef IPV6
|
||||||
|
/*
|
||||||
|
* A zero address is either a token for invalid/unused, or the prefix of default
|
||||||
|
* routes. These functions should be used in the second case, where both IPv4
|
||||||
|
* and IPv6 zero addresses should be checked.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline int ipa_zero2(ip_addr a)
|
||||||
|
{ return !_I0(a) && !_I1(a) && ((_I2(a) == 0) || (_I2(a) == 0xffff)) && !_I3(a); }
|
||||||
|
|
||||||
|
static inline int ipa_nonzero2(ip_addr a)
|
||||||
|
{ return _I0(a) || _I1(a) || ((_I2(a) != 0) && (_I2(a) != 0xffff)) || _I3(a); }
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define ipa_zero2(x) ip4_zero(x)
|
||||||
|
#define ipa_nonzero2(x) ip4_nonzero(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hash and compare functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline uint ip4_hash(ip4_addr a)
|
||||||
|
{
|
||||||
|
/* Returns a 16-bit value */
|
||||||
|
u32 x = _I(a);
|
||||||
|
x ^= x >> 16;
|
||||||
|
x ^= x << 10;
|
||||||
|
return x & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 ip4_hash32(ip4_addr a)
|
||||||
|
{
|
||||||
|
/* Returns a 32-bit value, although low-order bits are not mixed */
|
||||||
|
u32 x = _I(a);
|
||||||
|
x ^= x << 16;
|
||||||
|
x ^= x << 12;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 ip6_hash32(ip6_addr a)
|
||||||
|
{
|
||||||
|
/* Returns a 32-bit hash key, although low-order bits are not mixed */
|
||||||
|
u32 x = _I0(a) ^ _I1(a) ^ _I2(a) ^ _I3(a);
|
||||||
|
return x ^ (x << 16) ^ (x << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef IPV6
|
||||||
|
#define ipa_hash(x) ip6_hash(x)
|
||||||
|
#define ipa_hash32(x) ip6_hash32(x)
|
||||||
|
#define ipa_compare(x,y) ip6_compare(x,y)
|
||||||
|
#else
|
||||||
|
#define ipa_hash(x) ip4_hash(x)
|
||||||
|
#define ipa_hash32(x) ip4_hash32(x)
|
||||||
|
#define ipa_compare(x,y) ip4_compare(x,y)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IP address classification
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Address class */
|
||||||
#define IADDR_INVALID -1
|
#define IADDR_INVALID -1
|
||||||
#define IADDR_SCOPE_MASK 0xfff
|
#define IADDR_SCOPE_MASK 0xfff
|
||||||
#define IADDR_HOST 0x1000
|
#define IADDR_HOST 0x1000
|
||||||
#define IADDR_BROADCAST 0x2000
|
#define IADDR_BROADCAST 0x2000
|
||||||
#define IADDR_MULTICAST 0x4000
|
#define IADDR_MULTICAST 0x4000
|
||||||
|
|
||||||
/*
|
/* Address scope */
|
||||||
* Address scope
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define SCOPE_HOST 0
|
#define SCOPE_HOST 0
|
||||||
#define SCOPE_LINK 1
|
#define SCOPE_LINK 1
|
||||||
#define SCOPE_SITE 2
|
#define SCOPE_SITE 2
|
||||||
|
@ -42,26 +284,199 @@
|
||||||
#define SCOPE_UNIVERSE 4
|
#define SCOPE_UNIVERSE 4
|
||||||
#define SCOPE_UNDEFINED 5
|
#define SCOPE_UNDEFINED 5
|
||||||
|
|
||||||
char *ip_scope_text(unsigned);
|
int ip4_classify(ip4_addr ad);
|
||||||
|
int ip6_classify(ip6_addr *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; }
|
||||||
|
|
||||||
|
#ifdef IPV6
|
||||||
|
#define ipa_classify(x) ip6_classify(&(x))
|
||||||
|
#define ipa_is_link_local(x) ip6_is_link_local(x)
|
||||||
|
#else
|
||||||
|
#define ipa_classify(x) ip4_classify(x)
|
||||||
|
#define ipa_is_link_local(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline int ipa_classify_net(ip_addr a)
|
||||||
|
{ return ipa_zero2(a) ? (IADDR_HOST | SCOPE_UNIVERSE) : ipa_classify(a); }
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Network prefixes
|
* Miscellaneous IP prefix manipulation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static inline ip4_addr ip4_mkmask(uint n)
|
||||||
|
{ return _MI4(u32_mkmask(n)); }
|
||||||
|
|
||||||
|
static inline int ip4_masklen(ip4_addr a)
|
||||||
|
{ return u32_masklen(_I(a)); }
|
||||||
|
|
||||||
|
ip6_addr ip6_mkmask(uint n);
|
||||||
|
int ip6_masklen(ip6_addr *a);
|
||||||
|
|
||||||
|
/* ipX_pxlen() requires that x != y */
|
||||||
|
static inline uint ip4_pxlen(ip4_addr a, ip4_addr b)
|
||||||
|
{ return 31 - u32_log2(_I(a) ^ _I(b)); }
|
||||||
|
|
||||||
|
static inline uint 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]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 ip4_getbit(ip4_addr a, uint pos)
|
||||||
|
{ return _I(a) & (0x80000000 >> pos); }
|
||||||
|
|
||||||
|
static inline u32 ip6_getbit(ip6_addr a, uint pos)
|
||||||
|
{ return a.addr[pos / 32] & (0x80000000 >> (pos % 32)); }
|
||||||
|
|
||||||
|
static inline ip4_addr ip4_opposite_m1(ip4_addr a)
|
||||||
|
{ return _MI4(_I(a) ^ 1); }
|
||||||
|
|
||||||
|
static inline ip4_addr ip4_opposite_m2(ip4_addr a)
|
||||||
|
{ return _MI4(_I(a) ^ 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); }
|
||||||
|
|
||||||
|
ip4_addr ip4_class_mask(ip4_addr ad);
|
||||||
|
|
||||||
|
#ifdef IPV6
|
||||||
|
#define ipa_mkmask(x) ip6_mkmask(x)
|
||||||
|
#define ipa_masklen(x) ip6_masklen(&x)
|
||||||
|
#define ipa_pxlen(x,y) ip6_pxlen(x,y)
|
||||||
|
#define ipa_getbit(x,n) ip6_getbit(x,n)
|
||||||
|
#define ipa_opposite_m1(x) ip6_opposite_m1(x)
|
||||||
|
#define ipa_opposite_m2(x) ip6_opposite_m2(x)
|
||||||
|
#else
|
||||||
|
#define ipa_mkmask(x) ip4_mkmask(x)
|
||||||
|
#define ipa_masklen(x) ip4_masklen(x)
|
||||||
|
#define ipa_pxlen(x,y) ip4_pxlen(x,y)
|
||||||
|
#define ipa_getbit(x,n) ip4_getbit(x,n)
|
||||||
|
#define ipa_opposite_m1(x) ip4_opposite_m1(x)
|
||||||
|
#define ipa_opposite_m2(x) ip4_opposite_m2(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Host/network order conversions
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline ip4_addr ip4_hton(ip4_addr a)
|
||||||
|
{ return _MI4(htonl(_I(a))); }
|
||||||
|
|
||||||
|
static inline ip4_addr ip4_ntoh(ip4_addr a)
|
||||||
|
{ return _MI4(ntohl(_I(a))); }
|
||||||
|
|
||||||
|
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))); }
|
||||||
|
|
||||||
|
#ifdef IPV6
|
||||||
|
#define ipa_hton(x) x = ip6_hton(x)
|
||||||
|
#define ipa_ntoh(x) x = ip6_ntoh(x)
|
||||||
|
#else
|
||||||
|
#define ipa_hton(x) x = ip4_hton(x)
|
||||||
|
#define ipa_ntoh(x) x = ip4_ntoh(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unaligned data access (in network order)
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline ip4_addr get_ip4(void *buf)
|
||||||
|
{
|
||||||
|
return _MI4(get_u32(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline ip6_addr get_ip6(void *buf)
|
||||||
|
{
|
||||||
|
ip6_addr a;
|
||||||
|
memcpy(&a, buf, 16);
|
||||||
|
return ip6_ntoh(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void * put_ip4(void *buf, ip4_addr a)
|
||||||
|
{
|
||||||
|
put_u32(buf, _I(a));
|
||||||
|
return buf+4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void * put_ip6(void *buf, ip6_addr a)
|
||||||
|
{
|
||||||
|
a = ip6_hton(a);
|
||||||
|
memcpy(buf, &a, 16);
|
||||||
|
return buf+16;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXXX these functions must be redesigned or removed
|
||||||
|
#ifdef IPV6
|
||||||
|
#define get_ipa(x) get_ip6(x)
|
||||||
|
#define put_ipa(x,y) put_ip6(x,y)
|
||||||
|
#else
|
||||||
|
#define get_ipa(x) get_ip4(x)
|
||||||
|
#define put_ipa(x,y) put_ip4(x,y)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Binary/text form conversions
|
||||||
|
*/
|
||||||
|
|
||||||
|
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 these functions must be redesigned or removed
|
||||||
|
#ifdef IPV6
|
||||||
|
#define ipa_ntop(x,y) ip6_ntop(x,y)
|
||||||
|
#define ipa_ntox(x,y) ip6_ntox(x,y)
|
||||||
|
#define ipa_pton(x,y) ip6_pton(x,y)
|
||||||
|
#else
|
||||||
|
#define ipa_ntop(x,y) ip4_ntop(x,y)
|
||||||
|
#define ipa_ntox(x,y) ip4_ntox(x,y)
|
||||||
|
#define ipa_pton(x,y) ip4_pton(x,y)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Miscellaneous
|
||||||
|
*/
|
||||||
|
|
||||||
|
// XXXX review this
|
||||||
|
|
||||||
|
#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);
|
||||||
|
|
||||||
struct prefix {
|
struct prefix {
|
||||||
ip_addr addr;
|
ip_addr addr;
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
};
|
};
|
||||||
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
|
|
||||||
char *ip_ntop(ip_addr a, char *);
|
|
||||||
char *ip_ntox(ip_addr a, char *);
|
|
||||||
int ip_pton(char *a, ip_addr *o);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
110
lib/ipv4.c
110
lib/ipv4.c
|
@ -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;
|
|
||||||
}
|
|
116
lib/ipv4.h
116
lib/ipv4.h
|
@ -1,116 +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_hash32(x) ipv4_hash32(_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 u32 ipv4_hash32(u32 a)
|
|
||||||
{
|
|
||||||
/* Returns a 32-bit value, although low-order bits are not mixed */
|
|
||||||
a ^= a << 16;
|
|
||||||
a ^= a << 12;
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
384
lib/ipv6.c
384
lib/ipv6.c
|
@ -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
|
|
141
lib/ipv6.h
141
lib/ipv6.h
|
@ -1,141 +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_hash32(x) ipv6_hash32(&(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_hash32(ip_addr *a)
|
|
||||||
{
|
|
||||||
/* Returns a 32-bit hash key, although low-order bits are not ixed */
|
|
||||||
u32 x = _I0(*a) ^ _I1(*a) ^ _I2(*a) ^ _I3(*a);
|
|
||||||
return x ^ (x << 16) ^ (x << 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define IP_PREC_INTERNET_CONTROL 0xc0
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -283,9 +283,9 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
|
||||||
/* IP address */
|
/* IP address */
|
||||||
case 'I':
|
case 'I':
|
||||||
if (flags & SPECIAL)
|
if (flags & SPECIAL)
|
||||||
ip_ntox(va_arg(args, ip_addr), ipbuf);
|
ipa_ntox(va_arg(args, ip_addr), ipbuf);
|
||||||
else {
|
else {
|
||||||
ip_ntop(va_arg(args, ip_addr), ipbuf);
|
ipa_ntop(va_arg(args, ip_addr), ipbuf);
|
||||||
if (field_width == 1)
|
if (field_width == 1)
|
||||||
field_width = STD_ADDRESS_P_LENGTH;
|
field_width = STD_ADDRESS_P_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,8 @@ int sk_set_ipv6_checksum(sock *s, int offset);
|
||||||
int sk_set_icmp6_filter(sock *s, int p1, int p2);
|
int sk_set_icmp6_filter(sock *s, int p1, int p2);
|
||||||
void sk_log_error(sock *s, const char *p);
|
void sk_log_error(sock *s, const char *p);
|
||||||
|
|
||||||
|
byte * sk_rx_buffer(sock *s, int *len); /* Temporary */
|
||||||
|
|
||||||
extern int sk_priority_control; /* Suggested priority for control traffic, should be sysdep define */
|
extern int sk_priority_control; /* Suggested priority for control traffic, should be sysdep define */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -991,7 +991,7 @@ bgp_create_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *p
|
||||||
if (p->cf->next_hop_self ||
|
if (p->cf->next_hop_self ||
|
||||||
rta->dest != RTD_ROUTER ||
|
rta->dest != RTD_ROUTER ||
|
||||||
ipa_equal(rta->gw, IPA_NONE) ||
|
ipa_equal(rta->gw, IPA_NONE) ||
|
||||||
ipa_has_link_scope(rta->gw) ||
|
ipa_is_link_local(rta->gw) ||
|
||||||
(!p->is_internal && !p->cf->next_hop_keep &&
|
(!p->is_internal && !p->cf->next_hop_keep &&
|
||||||
(!p->neigh || (rta->iface != p->neigh->iface))))
|
(!p->neigh || (rta->iface != p->neigh->iface))))
|
||||||
set_next_hop(z, p->source_addr);
|
set_next_hop(z, p->source_addr);
|
||||||
|
|
|
@ -689,7 +689,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c
|
||||||
s->password = p->cf->password;
|
s->password = p->cf->password;
|
||||||
s->tx_hook = bgp_connected;
|
s->tx_hook = bgp_connected;
|
||||||
BGP_TRACE(D_EVENTS, "Connecting to %I%J from local address %I%J", s->daddr, p->cf->iface,
|
BGP_TRACE(D_EVENTS, "Connecting to %I%J from local address %I%J", s->daddr, p->cf->iface,
|
||||||
s->saddr, ipa_has_link_scope(s->saddr) ? s->iface : NULL);
|
s->saddr, ipa_is_link_local(s->saddr) ? s->iface : NULL);
|
||||||
bgp_setup_conn(p, conn);
|
bgp_setup_conn(p, conn);
|
||||||
bgp_setup_sk(conn, s);
|
bgp_setup_sk(conn, s);
|
||||||
bgp_conn_set_state(conn, BS_CONNECT);
|
bgp_conn_set_state(conn, BS_CONNECT);
|
||||||
|
@ -735,7 +735,7 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED)
|
||||||
{
|
{
|
||||||
struct bgp_proto *p = (struct bgp_proto *) pc->proto;
|
struct bgp_proto *p = (struct bgp_proto *) pc->proto;
|
||||||
if (ipa_equal(p->cf->remote_ip, sk->daddr) &&
|
if (ipa_equal(p->cf->remote_ip, sk->daddr) &&
|
||||||
(!ipa_has_link_scope(sk->daddr) || (p->cf->iface == sk->iface)))
|
(!ipa_is_link_local(sk->daddr) || (p->cf->iface == sk->iface)))
|
||||||
{
|
{
|
||||||
/* We are in proper state and there is no other incoming connection */
|
/* We are in proper state and there is no other incoming connection */
|
||||||
int acc = (p->p.proto_state == PS_START || p->p.proto_state == PS_UP) &&
|
int acc = (p->p.proto_state == PS_START || p->p.proto_state == PS_UP) &&
|
||||||
|
@ -750,7 +750,7 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED)
|
||||||
}
|
}
|
||||||
|
|
||||||
BGP_TRACE(D_EVENTS, "Incoming connection from %I%J (port %d) %s",
|
BGP_TRACE(D_EVENTS, "Incoming connection from %I%J (port %d) %s",
|
||||||
sk->daddr, ipa_has_link_scope(sk->daddr) ? sk->iface : NULL,
|
sk->daddr, ipa_is_link_local(sk->daddr) ? sk->iface : NULL,
|
||||||
sk->dport, acc ? "accepted" : "rejected");
|
sk->dport, acc ? "accepted" : "rejected");
|
||||||
|
|
||||||
if (!acc)
|
if (!acc)
|
||||||
|
@ -779,7 +779,7 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED)
|
||||||
}
|
}
|
||||||
|
|
||||||
log(L_WARN "BGP: Unexpected connect from unknown address %I%J (port %d)",
|
log(L_WARN "BGP: Unexpected connect from unknown address %I%J (port %d)",
|
||||||
sk->daddr, ipa_has_link_scope(sk->daddr) ? sk->iface : NULL, sk->dport);
|
sk->daddr, ipa_is_link_local(sk->daddr) ? sk->iface : NULL, sk->dport);
|
||||||
reject:
|
reject:
|
||||||
rfree(sk);
|
rfree(sk);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1169,8 +1169,8 @@ bgp_check_config(struct bgp_config *c)
|
||||||
if (c->multihop && (c->gw_mode == GW_DIRECT))
|
if (c->multihop && (c->gw_mode == GW_DIRECT))
|
||||||
cf_error("Multihop BGP cannot use direct gateway mode");
|
cf_error("Multihop BGP cannot use direct gateway mode");
|
||||||
|
|
||||||
if (c->multihop && (ipa_has_link_scope(c->remote_ip) ||
|
if (c->multihop && (ipa_is_link_local(c->remote_ip) ||
|
||||||
ipa_has_link_scope(c->source_addr)))
|
ipa_is_link_local(c->source_addr)))
|
||||||
cf_error("Multihop BGP cannot be used with link-local addresses");
|
cf_error("Multihop BGP cannot be used with link-local addresses");
|
||||||
|
|
||||||
if (c->multihop && c->bfd && ipa_zero(c->source_addr))
|
if (c->multihop && c->bfd && ipa_zero(c->source_addr))
|
||||||
|
|
|
@ -63,7 +63,7 @@ bgp_proto:
|
||||||
| bgp_proto NEIGHBOR ipa ipa_scope ipa_port AS expr ';' {
|
| bgp_proto NEIGHBOR ipa ipa_scope ipa_port AS expr ';' {
|
||||||
if (ipa_nonzero(BGP_CFG->remote_ip))
|
if (ipa_nonzero(BGP_CFG->remote_ip))
|
||||||
cf_error("Only one neighbor per BGP instance is allowed");
|
cf_error("Only one neighbor per BGP instance is allowed");
|
||||||
if (!ipa_has_link_scope($3) != !$4)
|
if (!ipa_is_link_local($3) != !$4)
|
||||||
cf_error("Link-local address and interface scope must be used together");
|
cf_error("Link-local address and interface scope must be used together");
|
||||||
|
|
||||||
BGP_CFG->remote_ip = $3;
|
BGP_CFG->remote_ip = $3;
|
||||||
|
|
|
@ -69,8 +69,8 @@ mrt_put_bgp4_hdr(byte *buf, struct bgp_conn *conn, int as4)
|
||||||
put_u16(buf+0, (p->neigh && p->neigh->iface) ? p->neigh->iface->index : 0);
|
put_u16(buf+0, (p->neigh && p->neigh->iface) ? p->neigh->iface->index : 0);
|
||||||
put_u16(buf+2, BGP_AF);
|
put_u16(buf+2, BGP_AF);
|
||||||
buf+=4;
|
buf+=4;
|
||||||
buf = ipa_put_addr(buf, conn->sk ? conn->sk->daddr : IPA_NONE);
|
buf = put_ipa(buf, conn->sk ? conn->sk->daddr : IPA_NONE);
|
||||||
buf = ipa_put_addr(buf, conn->sk ? conn->sk->saddr : IPA_NONE);
|
buf = put_ipa(buf, conn->sk ? conn->sk->saddr : IPA_NONE);
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
@ -522,7 +522,7 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
|
||||||
*tmp++ = BGP_AF_IPV6;
|
*tmp++ = BGP_AF_IPV6;
|
||||||
*tmp++ = 1;
|
*tmp++ = 1;
|
||||||
|
|
||||||
if (ipa_has_link_scope(ip))
|
if (ipa_is_link_local(ip))
|
||||||
ip = IPA_NONE;
|
ip = IPA_NONE;
|
||||||
|
|
||||||
if (ipa_nonzero(ip_ll))
|
if (ipa_nonzero(ip_ll))
|
||||||
|
@ -1034,7 +1034,7 @@ bgp_set_next_hop(struct bgp_proto *p, rta *a)
|
||||||
int second = (nh->u.ptr->length == NEXT_HOP_LENGTH) && ipa_nonzero(nexthop[1]);
|
int second = (nh->u.ptr->length == NEXT_HOP_LENGTH) && ipa_nonzero(nexthop[1]);
|
||||||
|
|
||||||
/* First address should not be link-local, but may be zero in direct mode */
|
/* First address should not be link-local, but may be zero in direct mode */
|
||||||
if (ipa_has_link_scope(*nexthop))
|
if (ipa_is_link_local(*nexthop))
|
||||||
*nexthop = IPA_NONE;
|
*nexthop = IPA_NONE;
|
||||||
#else
|
#else
|
||||||
int second = 0;
|
int second = 0;
|
||||||
|
|
|
@ -37,36 +37,9 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define IP4_MIN_MTU 576
|
|
||||||
#define IP6_MIN_MTU 1280
|
|
||||||
|
|
||||||
#define IP4_OSPF_ALL_ROUTERS ipa_build4(224, 0, 0, 5)
|
|
||||||
#define IP4_OSPF_DES_ROUTERS ipa_build4(224, 0, 0, 6)
|
|
||||||
|
|
||||||
#define IP6_OSPF_ALL_ROUTERS ipa_build6(0xFF020000, 0, 0, 5)
|
|
||||||
#define IP6_OSPF_DES_ROUTERS ipa_build6(0xFF020000, 0, 0, 6)
|
|
||||||
|
|
||||||
#ifdef IPV6
|
#ifdef IPV6
|
||||||
#define ip4_addr u32
|
|
||||||
#define ip6_addr ip_addr
|
|
||||||
#define _MI6(x1,x2,x3,x4) _MI(x1, x2, x3, x4)
|
|
||||||
#define ipa_is_link_local(x) ipa_has_link_scope(x)
|
|
||||||
#define ipa_from_u32(x) _MI6(0,0,0xffff,x)
|
|
||||||
#define ipa_to_u32(x) _I3(x)
|
|
||||||
#define ipa_build4(a,b,c,d) IPA_NONE
|
|
||||||
#define ipa_build6(a,b,c,d) _MI6(a,b,c,d)
|
|
||||||
#define OSPF_IS_V2 0
|
#define OSPF_IS_V2 0
|
||||||
#else
|
#else
|
||||||
#define ip4_addr u32
|
|
||||||
#define ip6_addr ip_addr
|
|
||||||
#define _I0(X) 0
|
|
||||||
#define _I1(X) 0
|
|
||||||
#define _I2(X) 0
|
|
||||||
#define _I3(X) 0
|
|
||||||
#define _MI6(x1,x2,x3,x4) IPA_NONE
|
|
||||||
#define ipa_is_link_local(x) 0
|
|
||||||
#define ipa_build4(a,b,c,d) _MI(((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
|
|
||||||
#define ipa_build6(a,b,c,d) IPA_NONE
|
|
||||||
#define OSPF_IS_V2 1
|
#define OSPF_IS_V2 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -744,10 +717,12 @@ lsa_net_count(struct ospf_lsa_header *lsa)
|
||||||
#define ipa_from_rid(x) ipa_from_u32(x)
|
#define ipa_from_rid(x) ipa_from_u32(x)
|
||||||
#define ipa_to_rid(x) ipa_to_u32(x)
|
#define ipa_to_rid(x) ipa_to_u32(x)
|
||||||
|
|
||||||
|
|
||||||
#define IPV6_PREFIX_SPACE(x) ((((x) + 63) / 32) * 4)
|
#define IPV6_PREFIX_SPACE(x) ((((x) + 63) / 32) * 4)
|
||||||
#define IPV6_PREFIX_WORDS(x) (((x) + 63) / 32)
|
#define IPV6_PREFIX_WORDS(x) (((x) + 63) / 32)
|
||||||
|
|
||||||
|
/* FIXME: these four functions should be significantly redesigned w.r.t. integration,
|
||||||
|
also should be named as ospf3_* instead of *_ipv6_* */
|
||||||
|
|
||||||
static inline u32 *
|
static inline u32 *
|
||||||
lsa_get_ipv6_prefix(u32 *buf, ip_addr *addr, int *pxlen, u8 *pxopts, u16 *rest)
|
lsa_get_ipv6_prefix(u32 *buf, ip_addr *addr, int *pxlen, u8 *pxopts, u16 *rest)
|
||||||
{
|
{
|
||||||
|
@ -787,6 +762,7 @@ lsa_get_ipv6_addr(u32 *buf, ip_addr *addr)
|
||||||
static inline u32 *
|
static inline u32 *
|
||||||
put_ipv6_prefix(u32 *buf, ip_addr addr, u8 pxlen, u8 pxopts, u16 lh)
|
put_ipv6_prefix(u32 *buf, ip_addr addr, u8 pxlen, u8 pxopts, u16 lh)
|
||||||
{
|
{
|
||||||
|
#ifdef IPV6
|
||||||
*buf++ = ((pxlen << 24) | (pxopts << 16) | lh);
|
*buf++ = ((pxlen << 24) | (pxopts << 16) | lh);
|
||||||
|
|
||||||
if (pxlen > 0)
|
if (pxlen > 0)
|
||||||
|
@ -797,6 +773,7 @@ put_ipv6_prefix(u32 *buf, ip_addr addr, u8 pxlen, u8 pxopts, u16 lh)
|
||||||
*buf++ = _I2(addr);
|
*buf++ = _I2(addr);
|
||||||
if (pxlen > 96)
|
if (pxlen > 96)
|
||||||
*buf++ = _I3(addr);
|
*buf++ = _I3(addr);
|
||||||
|
#endif
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -265,7 +265,8 @@ ospf_rx_hook(sock *sk, int len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Second, we check packet length, checksum, and the protocol version */
|
/* Second, we check packet length, checksum, and the protocol version */
|
||||||
struct ospf_packet *pkt = (struct ospf_packet *) ip_skip_header(sk->rbuf, &len);
|
struct ospf_packet *pkt = (void *) sk_rx_buffer(sk, &len);
|
||||||
|
|
||||||
|
|
||||||
if (pkt == NULL)
|
if (pkt == NULL)
|
||||||
DROP("bad IP header", len);
|
DROP("bad IP header", len);
|
||||||
|
|
|
@ -1822,10 +1822,10 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
|
||||||
|
|
||||||
struct ospf_lsa_link *llsa = lhe->lsa_body;
|
struct ospf_lsa_link *llsa = lhe->lsa_body;
|
||||||
|
|
||||||
if (ipa_zero(llsa->lladdr))
|
if (ip6_zero(llsa->lladdr))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return new_nexthop(p, llsa->lladdr, pn->iface, pn->weight);
|
return new_nexthop(p, ipa_from_ip6(llsa->lladdr), pn->iface, pn->weight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1319,7 +1319,7 @@ prepare_link_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa)
|
||||||
ASSERT(p->lsab_used == 0);
|
ASSERT(p->lsab_used == 0);
|
||||||
ll = lsab_allocz(p, sizeof(struct ospf_lsa_link));
|
ll = lsab_allocz(p, sizeof(struct ospf_lsa_link));
|
||||||
ll->options = ifa->oa->options | (ifa->priority << 24);
|
ll->options = ifa->oa->options | (ifa->priority << 24);
|
||||||
ll->lladdr = ifa->addr->ip;
|
ll->lladdr = ipa_to_ip6(ifa->addr->ip);
|
||||||
ll = NULL; /* buffer might be reallocated later */
|
ll = NULL; /* buffer might be reallocated later */
|
||||||
|
|
||||||
struct ifa *a;
|
struct ifa *a;
|
||||||
|
|
|
@ -343,7 +343,7 @@ radv_send_ra(struct radv_iface *ifa, int shutdown)
|
||||||
}
|
}
|
||||||
|
|
||||||
RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name);
|
RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name);
|
||||||
sk_send_to(ifa->sk, ifa->plen, AllNodes, 0);
|
sk_send_to(ifa->sk, ifa->plen, IP6_ALL_NODES, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -432,7 +432,7 @@ radv_sk_open(struct radv_iface *ifa)
|
||||||
if (sk_setup_multicast(sk) < 0)
|
if (sk_setup_multicast(sk) < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (sk_join_group(sk, AllRouters) < 0)
|
if (sk_join_group(sk, IP6_ALL_ROUTERS) < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
ifa->sk = sk;
|
ifa->sk = sk;
|
||||||
|
|
|
@ -26,9 +26,6 @@
|
||||||
|
|
||||||
#define ICMPV6_PROTO 58
|
#define ICMPV6_PROTO 58
|
||||||
|
|
||||||
#define AllNodes _MI(0xFF020000, 0, 0, 1) /* FF02::1 */
|
|
||||||
#define AllRouters _MI(0xFF020000, 0, 0, 2) /* FF02::2 */
|
|
||||||
|
|
||||||
#define ICMPV6_RS 133
|
#define ICMPV6_RS 133
|
||||||
#define ICMPV6_RA 134
|
#define ICMPV6_RA 134
|
||||||
|
|
||||||
|
|
|
@ -305,7 +305,7 @@ advertise_entry( struct proto *p, struct rip_block *b, ip_addr whotoldme, struct
|
||||||
A.flags = 0;
|
A.flags = 0;
|
||||||
#ifndef IPV6
|
#ifndef IPV6
|
||||||
A.gw = ipa_nonzero(b->nexthop) ? b->nexthop : whotoldme;
|
A.gw = ipa_nonzero(b->nexthop) ? b->nexthop : whotoldme;
|
||||||
pxlen = ipa_mklen(b->netmask);
|
pxlen = ipa_masklen(b->netmask);
|
||||||
#else
|
#else
|
||||||
/* FIXME: next hop is in other packet for v6 */
|
/* FIXME: next hop is in other packet for v6 */
|
||||||
A.gw = whotoldme;
|
A.gw = whotoldme;
|
||||||
|
@ -365,7 +365,7 @@ process_block( struct proto *p, struct rip_block *block, ip_addr whotoldme, stru
|
||||||
|
|
||||||
#ifndef IPV6
|
#ifndef IPV6
|
||||||
metric = ntohl( block->metric );
|
metric = ntohl( block->metric );
|
||||||
pxlen = ipa_mklen(block->netmask);
|
pxlen = ipa_masklen(block->netmask);
|
||||||
#else
|
#else
|
||||||
metric = block->metric;
|
metric = block->metric;
|
||||||
pxlen = block->pxlen;
|
pxlen = block->pxlen;
|
||||||
|
@ -447,7 +447,7 @@ rip_process_packet( struct proto *p, struct rip_packet *packet, int num, ip_addr
|
||||||
ipa_ntoh( block->netmask );
|
ipa_ntoh( block->netmask );
|
||||||
ipa_ntoh( block->nexthop );
|
ipa_ntoh( block->nexthop );
|
||||||
if (packet->heading.version == RIP_V1) /* FIXME (nonurgent): switch to disable this? */
|
if (packet->heading.version == RIP_V1) /* FIXME (nonurgent): switch to disable this? */
|
||||||
block->netmask = ipa_class_mask(block->network);
|
block->netmask = ip4_class_mask(ipa_to_ip4(block->network));
|
||||||
#endif
|
#endif
|
||||||
process_block( p, block, whotoldme, iface );
|
process_block( p, block, whotoldme, iface );
|
||||||
}
|
}
|
||||||
|
@ -721,7 +721,7 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_
|
||||||
#ifndef IPV6
|
#ifndef IPV6
|
||||||
rif->sock->daddr = ipa_from_u32(0xe0000009);
|
rif->sock->daddr = ipa_from_u32(0xe0000009);
|
||||||
#else
|
#else
|
||||||
rif->sock->daddr = ipa_build(0xff020000, 0, 0, 9);
|
rif->sock->daddr = IP6_RIP_ROUTERS;
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
rif->sock->daddr = new->addr->brd;
|
rif->sock->daddr = new->addr->brd;
|
||||||
|
@ -812,7 +812,7 @@ rip_if_notify(struct proto *p, unsigned c, struct iface *iface)
|
||||||
#ifndef IPV6
|
#ifndef IPV6
|
||||||
lock->addr = ipa_from_u32(0xe0000009);
|
lock->addr = ipa_from_u32(0xe0000009);
|
||||||
#else
|
#else
|
||||||
ip_pton("FF02::9", &lock->addr);
|
lock->addr = IP6_RIP_ROUTERS;
|
||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
lock->addr = iface->addr->brd;
|
lock->addr = iface->addr->brd;
|
||||||
|
|
|
@ -382,7 +382,7 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
|
||||||
if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
|
if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
|
||||||
SKIP("strange class/scope\n");
|
SKIP("strange class/scope\n");
|
||||||
|
|
||||||
int pxlen = (flags & RTF_HOST) ? MAX_PREFIX_LENGTH : ipa_mklen(imask);
|
int pxlen = (flags & RTF_HOST) ? MAX_PREFIX_LENGTH : ipa_masklen(imask);
|
||||||
if (pxlen < 0)
|
if (pxlen < 0)
|
||||||
{ log(L_ERR "%s (%I) - netmask %I", errmsg, idst, imask); return; }
|
{ log(L_ERR "%s (%I) - netmask %I", errmsg, idst, imask); return; }
|
||||||
|
|
||||||
|
@ -653,7 +653,7 @@ krt_read_addr(struct ks_msg *msg, int scan)
|
||||||
ibrd = ipa_from_sa(&brd);
|
ibrd = ipa_from_sa(&brd);
|
||||||
|
|
||||||
|
|
||||||
if ((masklen = ipa_mklen(imask)) < 0)
|
if ((masklen = ipa_masklen(imask)) < 0)
|
||||||
{
|
{
|
||||||
log(L_ERR "KIF: Invalid masklen %I for %s", imask, iface->name);
|
log(L_ERR "KIF: Invalid masklen %I for %s", imask, iface->name);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -764,6 +764,29 @@ sk_set_tos6(sock *s, int tos)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline byte *
|
||||||
|
sk_skip_ip_header(byte *pkt, int *len)
|
||||||
|
{
|
||||||
|
if ((*len < 20) || ((*pkt & 0xf0) != 0x40))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
int hlen = (*pkt & 0x0f) * 4;
|
||||||
|
if ((hlen < 20) || (hlen > *len))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*len -= hlen;
|
||||||
|
return pkt + hlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte *
|
||||||
|
sk_rx_buffer(sock *s, int *len)
|
||||||
|
{
|
||||||
|
if (sk_is_ipv4(s) && (s->type == SK_IP))
|
||||||
|
return sk_skip_ip_header(s->rbuf, len);
|
||||||
|
else
|
||||||
|
return s->rbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Public socket functions
|
* Public socket functions
|
||||||
|
|
|
@ -47,19 +47,9 @@ typedef struct sockaddr_bird {
|
||||||
|
|
||||||
#ifdef IPV6
|
#ifdef IPV6
|
||||||
#define BIRD_AF AF_INET6
|
#define BIRD_AF AF_INET6
|
||||||
#define _MI6(x1,x2,x3,x4) _MI(x1, x2, x3, x4)
|
|
||||||
#define ipa_is_link_local(x) ipa_has_link_scope(x)
|
|
||||||
#define ipa_from_sa(x) ipa_from_sa6(x)
|
#define ipa_from_sa(x) ipa_from_sa6(x)
|
||||||
#define ipa_from_u32(x) _MI6(0,0,0xffff,x)
|
|
||||||
#define ipa_to_u32(x) _I3(x)
|
|
||||||
#else
|
#else
|
||||||
#define BIRD_AF AF_INET
|
#define BIRD_AF AF_INET
|
||||||
#define _I0(X) 0
|
|
||||||
#define _I1(X) 0
|
|
||||||
#define _I2(X) 0
|
|
||||||
#define _I3(X) 0
|
|
||||||
#define _MI6(x1,x2,x3,x4) IPA_NONE
|
|
||||||
#define ipa_is_link_local(x) 0
|
|
||||||
#define ipa_from_sa(x) ipa_from_sa4(x)
|
#define ipa_from_sa(x) ipa_from_sa4(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -75,7 +65,7 @@ static inline ip_addr ipa_from_in4(struct in_addr a)
|
||||||
{ return ipa_from_u32(ntohl(a.s_addr)); }
|
{ return ipa_from_u32(ntohl(a.s_addr)); }
|
||||||
|
|
||||||
static inline ip_addr ipa_from_in6(struct in6_addr a)
|
static inline ip_addr ipa_from_in6(struct in6_addr a)
|
||||||
{ return _MI6(ntohl(a.s6_addr32[0]), ntohl(a.s6_addr32[1]), ntohl(a.s6_addr32[2]), ntohl(a.s6_addr32[3])); }
|
{ return ipa_build6(ntohl(a.s6_addr32[0]), ntohl(a.s6_addr32[1]), ntohl(a.s6_addr32[2]), ntohl(a.s6_addr32[3])); }
|
||||||
|
|
||||||
static inline ip_addr ipa_from_sa4(sockaddr *sa)
|
static inline ip_addr ipa_from_sa4(sockaddr *sa)
|
||||||
{ return ipa_from_in4(((struct sockaddr_in *) sa)->sin_addr); }
|
{ return ipa_from_in4(((struct sockaddr_in *) sa)->sin_addr); }
|
||||||
|
@ -86,8 +76,14 @@ static inline ip_addr ipa_from_sa6(sockaddr *sa)
|
||||||
static inline struct in_addr ipa_to_in4(ip_addr a)
|
static inline struct in_addr ipa_to_in4(ip_addr a)
|
||||||
{ return (struct in_addr) { htonl(ipa_to_u32(a)) }; }
|
{ return (struct in_addr) { htonl(ipa_to_u32(a)) }; }
|
||||||
|
|
||||||
|
#ifdef IPV6
|
||||||
static inline struct in6_addr ipa_to_in6(ip_addr a)
|
static inline struct in6_addr ipa_to_in6(ip_addr a)
|
||||||
{ return (struct in6_addr) { .s6_addr32 = { htonl(_I0(a)), htonl(_I1(a)), htonl(_I2(a)), htonl(_I3(a)) } }; }
|
{ return (struct in6_addr) { .s6_addr32 = { htonl(_I0(a)), htonl(_I1(a)), htonl(_I2(a)), htonl(_I3(a)) } }; }
|
||||||
|
#else
|
||||||
|
/* Temporary dummy */
|
||||||
|
static inline struct in6_addr ipa_to_in6(ip_addr a)
|
||||||
|
{ return (struct in6_addr) { .s6_addr32 = { 0, 0, 0, 0 } }; }
|
||||||
|
#endif
|
||||||
|
|
||||||
void sockaddr_fill(sockaddr *sa, int af, ip_addr a, struct iface *ifa, uint port);
|
void sockaddr_fill(sockaddr *sa, int af, ip_addr a, struct iface *ifa, uint port);
|
||||||
int sockaddr_read(sockaddr *sa, int af, ip_addr *a, struct iface **ifa, uint *port);
|
int sockaddr_read(sockaddr *sa, int af, ip_addr *a, struct iface **ifa, uint *port);
|
||||||
|
|
Loading…
Reference in a new issue