]>
git.ipfire.org Git - thirdparty/bird.git/blob - lib/ipv6.c
2 * BIRD Library -- IPv6 Address Manipulation Functions
4 * (c) 1999 Martin Mares <mj@ucw.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL.
11 #include "nest/bird.h"
13 #include "lib/bitops.h"
14 #include "lib/endian.h"
15 #include "lib/string.h"
18 * See RFC 2373 for explanation of IPv6 addressing issues.
22 ipv6_mkmask(unsigned n
)
38 a
.addr
[i
] = u32_mkmask(n
);
46 ipv6_mklen(ip_addr
*a
)
50 for(i
=0, n
=0; i
<4; i
++, n
+=32)
51 if (a
->addr
[i
] != ~0U)
53 j
= u32_masklen(a
->addr
[i
]);
66 ipv6_classify(ip_addr
*a
)
70 if ((x
& 0xe0000000) == 0x20000000) /* 2000::/3 Aggregatable Global Unicast Address */
71 return IADDR_HOST
| SCOPE_UNIVERSE
;
72 if ((x
& 0xffc00000) == 0xfe800000) /* fe80::/10 Link-Local Address */
73 return IADDR_HOST
| SCOPE_LINK
;
74 if ((x
& 0xffc00000) == 0xfec00000) /* fec0::/10 Site-Local Address */
75 return IADDR_HOST
| SCOPE_SITE
;
76 if ((x
& 0xfe000000) == 0xfc000000) /* fc00::/7 Unique Local Unicast Address (RFC 4193) */
77 return IADDR_HOST
| SCOPE_SITE
;
78 if ((x
& 0xff000000) == 0xff000000) /* ff00::/8 Multicast Address */
80 unsigned int scope
= (x
>> 16) & 0x0f;
83 case 1: return IADDR_MULTICAST
| SCOPE_HOST
;
84 case 2: return IADDR_MULTICAST
| SCOPE_LINK
;
85 case 5: return IADDR_MULTICAST
| SCOPE_SITE
;
86 case 8: return IADDR_MULTICAST
| SCOPE_ORGANIZATION
;
87 case 14: return IADDR_MULTICAST
| SCOPE_UNIVERSE
;
88 default: return IADDR_MULTICAST
| SCOPE_UNDEFINED
;
91 if (!x
&& !a
->addr
[1] && !a
->addr
[2])
95 return IADDR_HOST
| SCOPE_HOST
; /* Loopback address */
96 /* IPv4 compatible addresses */
97 if (y
>= 0x7f000000 && y
< 0x80000000)
98 return IADDR_HOST
| SCOPE_HOST
;
99 if ((y
& 0xff000000) == 0x0a000000 ||
100 (y
& 0xffff0000) == 0xc0a80000 ||
101 (y
& 0xfff00000) == 0xac100000)
102 return IADDR_HOST
| SCOPE_SITE
;
103 if (y
>= 0x01000000 && y
< 0xe0000000)
104 return IADDR_HOST
| SCOPE_UNIVERSE
;
106 return IADDR_HOST
| SCOPE_UNDEFINED
;
110 ipv6_hton(ip_addr
*a
)
115 a
->addr
[i
] = htonl(a
->addr
[i
]);
119 ipv6_ntoh(ip_addr
*a
)
124 a
->addr
[i
] = ntohl(a
->addr
[i
]);
128 ipv6_compare(ip_addr X
, ip_addr Y
)
135 if (x
->addr
[i
] > y
->addr
[i
])
137 else if (x
->addr
[i
] < y
->addr
[i
])
143 * Conversion of IPv6 address to presentation format and vice versa.
144 * Heavily inspired by routines written by Paul Vixie for the BIND project
145 * and of course by RFC 2373.
149 ip_ntop(ip_addr a
, char *b
)
152 int bestpos
, bestlen
, curpos
, curlen
, i
;
154 /* First of all, preprocess the address and find the longest run of zeros */
155 bestlen
= bestpos
= curpos
= curlen
= 0;
159 words
[i
] = ((i
%2) ? x
: (x
>> 16)) & 0xffff;
167 if (curlen
> bestlen
)
177 /* Is it an encapsulated IPv4 address? */
179 (bestlen
== 5 && a
.addr
[2] == 0xffff ||
183 b
+= bsprintf(b
, "::%s%d.%d.%d.%d",
184 a
.addr
[2] ? "ffff:" : "",
192 /* Normal IPv6 formatting, compress the largest sequence of zeros */
206 b
+= bsprintf(b
, "%x", words
[i
]);
214 ip_ntox(ip_addr a
, char *b
)
222 b
+= bsprintf(b
, "%08x", a
.addr
[i
]);
228 ipv4_pton_u32(char *a
, u32
*o
)
237 char *d
, *c
= strchr(a
, '.');
240 l
= strtoul(a
, &d
, 10);
241 if (d
!= c
&& *d
|| l
> 255)
253 ip_pton(char *a
, ip_addr
*o
)
256 int i
, j
, k
, l
, hfil
;
259 if (a
[0] == ':') /* Leading :: */
269 if (*a
== ':') /* :: */
282 if (*a
>= '0' && *a
<= '9')
284 else if (*a
>= 'A' && *a
<= 'F')
286 else if (*a
>= 'a' && *a
<= 'f')
291 if (j
>= 0x10000 || ++l
> 4)
294 if (*a
== ':' && a
[1])
296 else if (*a
== '.' && (i
== 6 || i
< 6 && hfil
>= 0))
297 { /* Embedded IPv4 address */
299 if (!ipv4_pton_u32(start
, &x
))
301 words
[i
++] = x
>> 16;
312 /* Replace :: with an appropriate number of zeros */
316 for(i
=7; i
-j
>= hfil
; i
--)
317 words
[i
] = words
[i
-j
];
322 /* Convert the address to ip_addr format */
324 o
->addr
[i
] = (words
[2*i
] << 16) | words
[2*i
+1];
328 void ipv6_absolutize(ip_addr
*a
, ip_addr
*ifa
)
330 if ((a
->addr
[0] & 0xffc00000) == 0xfe800000 && /* a is link-scope */
331 ((ifa
->addr
[0] & 0xe0000000) == 0x20000000 | /* ifa is AGU ... */
332 (ifa
->addr
[0] & 0xffc00000) == 0xfec00000)) /* ... or site-scope */
334 a
->addr
[0] = ifa
->addr
[0]; /* Copy the prefix, leave interface ID */
335 a
->addr
[1] = ifa
->addr
[1];
343 static void test(char *x
)
346 char c
[STD_ADDRESS_P_LENGTH
+1];
355 printf("%-40s %04x\n", c
, ipv6_classify(&a
));
360 puts("Positive tests:");
361 test("1:2:3:4:5:6:7:8");
362 test("dead:beef:DEAD:BEEF::f00d");
367 test("::ffff:1.234.5.6");
368 test("::fffe:1.234.5.6");
369 test("1:2:3:4:5:6:7::8");
370 test("2080::8:800:200c:417a");
373 puts("Negative tests:");
375 test("1:2:3:4:5:6:7:8:");
379 test(":1:2:3:4:5:6:7:8");
380 test("g:1:2:3:4:5:6:7");