diff options
Diffstat (limited to 'lib/ip.c')
-rw-r--r-- | lib/ip.c | 376 |
1 files changed, 353 insertions, 23 deletions
@@ -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> * * Can be freely distributed and used under the terms of the GNU GPL. */ -#include "nest/bird.h" -#include "lib/ip.h" - /** * DOC: IP addresses * @@ -18,6 +15,333 @@ * 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 * @scope: scope (%SCOPE_xxx) @@ -25,7 +349,7 @@ * Returns a pointer to a textual name of the scope given. */ char * -ip_scope_text(unsigned scope) +ip_scope_text(uint scope) { static char *scope_table[] = { "host", "link", "site", "org", "univ", "undef" }; @@ -35,6 +359,23 @@ ip_scope_text(unsigned 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 /** * 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 } /** - * ipa_mkmask - calculate netmask length + * ipa_masklen - calculate netmask length * @x: IP address * * This function checks whether @x represents a valid netmask and * returns the size of the associate network prefix or -1 for invalid * mask. */ -int ipa_mklen(ip_addr x) { DUMMY } +int ipa_masklen(ip_addr x) { DUMMY } /** * ipa_hash - hash IP addresses @@ -151,8 +492,8 @@ void ipa_ntoh(ip_addr x) { DUMMY } int ipa_classify(ip_addr x) { DUMMY } /** - * ipa_class_mask - guess netmask according to address class - * @x: IP address + * ip4_class_mask - guess netmask according to address class + * @x: IPv4 address * * This function (available in IPv4 version only) returns a * 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 * 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 @@ -193,7 +534,7 @@ ip_addr ipa_to_u32(u32 x) { DUMMY } int ipa_compare(ip_addr x, ip_addr y) { DUMMY } /** - * ipa_build - build an IPv6 address from parts + * ipa_build6 - build an IPv6 address from parts * @a1: part #1 * @a2: part #2 * @a3: part #3 @@ -203,18 +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 * socket to a hard-wired multicast address. */ -ip_addr ipa_build(u32 a1, u32 a2, u32 a3, u32 a4) { DUMMY } - -/** - * ipa_absolutize - convert link scope IPv6 address to universe scope - * @x: link scope IPv6 address - * @y: universe scope IPv6 prefix of the interface - * - * This function combines a link-scope IPv6 address @x with the universe - * scope prefix @x of the network assigned to an interface to get a - * universe scope form of @x. - */ -ip_addr ipa_absolutize(ip_addr x, ip_addr y) { DUMMY } +ip_addr ipa_build6(u32 a1, u32 a2, u32 a3, u32 a4) { DUMMY } /** * ip_ntop - convert IP address to textual representation |