Commit 88a183c6 authored by Ondřej Zajíček's avatar Ondřej Zajíček
Browse files

Integrated IP functions.

parent f8fefde3
......@@ -124,22 +124,24 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
}
{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
ip4_addr a;
if (!ip4_pton(yytext, &a))
cf_error("Invalid IPv4 address %s", yytext);
#ifdef IPV6
if (ipv4_pton_u32(yytext, &cf_lval.i32))
return RTRID;
cf_error("Invalid IPv4 address %s", yytext);
cf_lval.i32 = ip4_to_u32(a);
return RTRID;
#else
if (ip_pton(yytext, &cf_lval.a))
return IPA;
cf_error("Invalid IP address %s", yytext);
cf_lval.a = ipa_from_ip4(a);
return IPA;
#endif
}
({XIGIT}*::|({XIGIT}*:){3,})({XIGIT}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+) {
#ifdef IPV6
if (ip_pton(yytext, &cf_lval.a))
if (ipa_pton(yytext, &cf_lval.a))
return IPA;
cf_error("Invalid IP address %s", yytext);
cf_error("Invalid IPv6 address %s", yytext);
#else
cf_error("This is an IPv4 router, therefore IPv6 addresses are not supported");
#endif
......
......@@ -187,7 +187,7 @@ pxlen:
$$ = $2;
}
| ':' ipa {
$$ = ipa_mklen($2);
$$ = ipa_masklen($2);
if ($$ < 0) cf_error("Invalid netmask %I", $2);
}
;
......
......@@ -3,13 +3,6 @@ bitops.c
bitops.h
ip.h
ip.c
#ifdef IPV6
ipv6.c
ipv6.h
#else
ipv4.c
ipv4.h
#endif
lists.c
lists.h
md5.c
......
/*
* 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
......
......@@ -9,59 +9,474 @@
#ifndef _BIRD_IP_H_
#define _BIRD_IP_H_
#ifndef IPV6
#include "ipv4.h"
#include "lib/endian.h"
#include "lib/string.h"
#include "lib/bitops.h"
#include "lib/unaligned.h"
#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
#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
/*
* Public constructors
*/
#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)); }