]> git.ipfire.org Git - thirdparty/bird.git/blob - lib/ipv6.c
Many changes in I/O and OSPF sockets and packet handling.
[thirdparty/bird.git] / lib / ipv6.c
1 /*
2 * BIRD Library -- IPv6 Address Manipulation Functions
3 *
4 * (c) 1999 Martin Mares <mj@ucw.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9 #include <stdlib.h>
10
11 #include "nest/bird.h"
12 #include "lib/ip.h"
13 #include "lib/bitops.h"
14 #include "lib/endian.h"
15 #include "lib/string.h"
16
17 /*
18 * See RFC 2373 for explanation of IPv6 addressing issues.
19 */
20
21 ip_addr
22 ipv6_mkmask(unsigned n)
23 {
24 ip_addr a;
25 int i;
26
27 for(i=0; i<4; i++)
28 {
29 if (!n)
30 a.addr[i] = 0;
31 else if (n >= 32)
32 {
33 a.addr[i] = ~0;
34 n -= 32;
35 }
36 else
37 {
38 a.addr[i] = u32_mkmask(n);
39 n = 0;
40 }
41 }
42 return a;
43 }
44
45 unsigned
46 ipv6_mklen(ip_addr *a)
47 {
48 int i, j, n;
49
50 for(i=0, n=0; i<4; i++, n+=32)
51 if (a->addr[i] != ~0U)
52 {
53 j = u32_masklen(a->addr[i]);
54 if (j < 0)
55 return j;
56 n += j;
57 while (++i < 4)
58 if (a->addr[i])
59 return -1;
60 break;
61 }
62 return n;
63 }
64
65 int
66 ipv6_classify(ip_addr *a)
67 {
68 u32 x = a->addr[0];
69
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 */
79 {
80 unsigned int scope = (x >> 16) & 0x0f;
81 switch (scope)
82 {
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;
89 }
90 }
91 if (!x && !a->addr[1] && !a->addr[2])
92 {
93 u32 y = a->addr[3];
94 if (y == 1)
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;
105 }
106 return IADDR_HOST | SCOPE_UNDEFINED;
107 }
108
109 void
110 ipv6_hton(ip_addr *a)
111 {
112 int i;
113
114 for(i=0; i<4; i++)
115 a->addr[i] = htonl(a->addr[i]);
116 }
117
118 void
119 ipv6_ntoh(ip_addr *a)
120 {
121 int i;
122
123 for(i=0; i<4; i++)
124 a->addr[i] = ntohl(a->addr[i]);
125 }
126
127 int
128 ipv6_compare(ip_addr X, ip_addr Y)
129 {
130 int i;
131 ip_addr *x = &X;
132 ip_addr *y = &Y;
133
134 for(i=0; i<4; i++)
135 if (x->addr[i] > y->addr[i])
136 return 1;
137 else if (x->addr[i] < y->addr[i])
138 return -1;
139 return 0;
140 }
141
142 /*
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.
146 */
147
148 char *
149 ip_ntop(ip_addr a, char *b)
150 {
151 u16 words[8];
152 int bestpos, bestlen, curpos, curlen, i;
153
154 /* First of all, preprocess the address and find the longest run of zeros */
155 bestlen = bestpos = curpos = curlen = 0;
156 for(i=0; i<8; i++)
157 {
158 u32 x = a.addr[i/2];
159 words[i] = ((i%2) ? x : (x >> 16)) & 0xffff;
160 if (words[i])
161 curlen = 0;
162 else
163 {
164 if (!curlen)
165 curpos = i;
166 curlen++;
167 if (curlen > bestlen)
168 {
169 bestpos = curpos;
170 bestlen = curlen;
171 }
172 }
173 }
174 if (bestlen < 2)
175 bestpos = -1;
176
177 /* Is it an encapsulated IPv4 address? */
178 if (!bestpos &&
179 (bestlen == 5 && a.addr[2] == 0xffff ||
180 bestlen == 6))
181 {
182 u32 x = a.addr[3];
183 b += bsprintf(b, "::%s%d.%d.%d.%d",
184 a.addr[2] ? "ffff:" : "",
185 ((x >> 24) & 0xff),
186 ((x >> 16) & 0xff),
187 ((x >> 8) & 0xff),
188 (x & 0xff));
189 return b;
190 }
191
192 /* Normal IPv6 formatting, compress the largest sequence of zeros */
193 for(i=0; i<8; i++)
194 {
195 if (i == bestpos)
196 {
197 i += bestlen - 1;
198 *b++ = ':';
199 if (i == 7)
200 *b++ = ':';
201 }
202 else
203 {
204 if (i)
205 *b++ = ':';
206 b += bsprintf(b, "%x", words[i]);
207 }
208 }
209 *b = 0;
210 return b;
211 }
212
213 char *
214 ip_ntox(ip_addr a, char *b)
215 {
216 int i;
217
218 for(i=0; i<4; i++)
219 {
220 if (i)
221 *b++ = '.';
222 b += bsprintf(b, "%08x", a.addr[i]);
223 }
224 return b;
225 }
226
227 int
228 ipv4_pton_u32(char *a, u32 *o)
229 {
230 int i;
231 unsigned long int l;
232 u32 ia = 0;
233
234 i=4;
235 while (i--)
236 {
237 char *d, *c = strchr(a, '.');
238 if (!c != !i)
239 return 0;
240 l = strtoul(a, &d, 10);
241 if (d != c && *d || l > 255)
242 return 0;
243 ia = (ia << 8) | l;
244 if (c)
245 c++;
246 a = c;
247 }
248 *o = ia;
249 return 1;
250 }
251
252 int
253 ip_pton(char *a, ip_addr *o)
254 {
255 u16 words[8];
256 int i, j, k, l, hfil;
257 char *start;
258
259 if (a[0] == ':') /* Leading :: */
260 {
261 if (a[1] != ':')
262 return 0;
263 a++;
264 }
265 hfil = -1;
266 i = 0;
267 while (*a)
268 {
269 if (*a == ':') /* :: */
270 {
271 if (hfil >= 0)
272 return 0;
273 hfil = i;
274 a++;
275 continue;
276 }
277 j = 0;
278 l = 0;
279 start = a;
280 for(;;)
281 {
282 if (*a >= '0' && *a <= '9')
283 k = *a++ - '0';
284 else if (*a >= 'A' && *a <= 'F')
285 k = *a++ - 'A' + 10;
286 else if (*a >= 'a' && *a <= 'f')
287 k = *a++ - 'a' + 10;
288 else
289 break;
290 j = (j << 4) + k;
291 if (j >= 0x10000 || ++l > 4)
292 return 0;
293 }
294 if (*a == ':' && a[1])
295 a++;
296 else if (*a == '.' && (i == 6 || i < 6 && hfil >= 0))
297 { /* Embedded IPv4 address */
298 u32 x;
299 if (!ipv4_pton_u32(start, &x))
300 return 0;
301 words[i++] = x >> 16;
302 words[i++] = x;
303 break;
304 }
305 else if (*a)
306 return 0;
307 if (i >= 8)
308 return 0;
309 words[i++] = j;
310 }
311
312 /* Replace :: with an appropriate number of zeros */
313 if (hfil >= 0)
314 {
315 j = 8 - i;
316 for(i=7; i-j >= hfil; i--)
317 words[i] = words[i-j];
318 for(; i>=hfil; i--)
319 words[i] = 0;
320 }
321
322 /* Convert the address to ip_addr format */
323 for(i=0; i<4; i++)
324 o->addr[i] = (words[2*i] << 16) | words[2*i+1];
325 return 1;
326 }
327
328 void ipv6_absolutize(ip_addr *a, ip_addr *ifa)
329 {
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 */
333 {
334 a->addr[0] = ifa->addr[0]; /* Copy the prefix, leave interface ID */
335 a->addr[1] = ifa->addr[1];
336 }
337 }
338
339 #ifdef TEST
340
341 #include "bitops.c"
342
343 static void test(char *x)
344 {
345 ip_addr a;
346 char c[STD_ADDRESS_P_LENGTH+1];
347
348 printf("%-40s ", x);
349 if (!ip_pton(x, &a))
350 {
351 puts("BAD");
352 return;
353 }
354 ip_ntop(a, c);
355 printf("%-40s %04x\n", c, ipv6_classify(&a));
356 }
357
358 int main(void)
359 {
360 puts("Positive tests:");
361 test("1:2:3:4:5:6:7:8");
362 test("dead:beef:DEAD:BEEF::f00d");
363 test("::");
364 test("::1");
365 test("1::");
366 test("::1.234.5.6");
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");
371 test("ff01::101");
372
373 puts("Negative tests:");
374 test(":::");
375 test("1:2:3:4:5:6:7:8:");
376 test("1::2::3");
377 test("::12345");
378 test("::1.2.3.4:5");
379 test(":1:2:3:4:5:6:7:8");
380 test("g:1:2:3:4:5:6:7");
381 return 0;
382 }
383
384 #endif