mirror of
https://gitlab.labs.nic.cz/labs/bird.git
synced 2024-05-11 16:54:54 +00:00
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:
349
lib/ipv6.c
349
lib/ipv6.c
@@ -1,12 +1,357 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "nest/bird.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
|
||||
|
Reference in New Issue
Block a user