Statistics
| Branch: | Revision:

iof-bird-daemon / lib / ipv6.c @ 061ab802

History | View | Annotate | Download (6.87 KB)

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)                /* Aggregatable Global Unicast Address */
71
    return IADDR_HOST | SCOPE_UNIVERSE;
72
  if ((x & 0xffc00000) == 0xfe800000)                /* Link-Local Address */
73
    return IADDR_HOST | SCOPE_LINK;
74
  if ((x & 0xffc00000) == 0xfec00000)                /* Site-Local Address */
75
    return IADDR_HOST | SCOPE_SITE;
76
  if ((x & 0xff000000) == 0xff000000)                /* Multicast Address */
77
    {
78
      unsigned int scope = (x >> 16) & 0x0f;
79
      switch (scope)
80
        {
81
        case 1:         return IADDR_MULTICAST | SCOPE_HOST;
82
        case 2:  return IADDR_MULTICAST | SCOPE_LINK;
83
        case 5:  return IADDR_MULTICAST | SCOPE_SITE;
84
        case 8:  return IADDR_MULTICAST | SCOPE_ORGANIZATION;
85
        case 14: return IADDR_MULTICAST | SCOPE_UNIVERSE;
86
        }
87
    }
88
  if (!x && !a->addr[1] && !a->addr[2])
89
    {
90
      u32 y = a->addr[3];
91
      if (y == 1)
92
        return IADDR_HOST | SCOPE_HOST;                /* Loopback address */
93
      /* IPv4 compatible addresses */
94
      if (y >= 0x7f000000 && y < 0x80000000)
95
        return IADDR_HOST | SCOPE_HOST;
96
      if ((y & 0xff000000) == 0x0a000000 ||
97
          (y & 0xffff0000) == 0xc0a80000 ||
98
          (y & 0xfff00000) == 0xac100000)
99
        return IADDR_HOST | SCOPE_SITE;
100
      if (y >= 0x01000000 && y < 0xe0000000)
101
        return IADDR_HOST | SCOPE_UNIVERSE;
102
    }
103
  return IADDR_INVALID;
104
}
105

    
106
void
107
ipv6_hton(ip_addr *a)
108
{
109
  int i;
110

    
111
  for(i=0; i<4; i++)
112
    a->addr[i] = htonl(a->addr[i]);
113
}
114

    
115
void
116
ipv6_ntoh(ip_addr *a)
117
{
118
  int i;
119

    
120
  for(i=0; i<4; i++)
121
    a->addr[i] = ntohl(a->addr[i]);
122
}
123

    
124
int
125
ipv6_compare(ip_addr X, ip_addr Y)
126
{
127
  int i;
128
  ip_addr *x = &X;
129
  ip_addr *y = &Y;
130

    
131
  for(i=0; i<4; i++)
132
    if (x->addr[i] > y->addr[i])
133
      return 1;
134
    else if (x->addr[i] < y->addr[i])
135
      return -1;
136
  return 0;
137
}
138

    
139
/*
140
 *  Conversion of IPv6 address to presentation format and vice versa.
141
 *  Heavily inspired by routines written by Paul Vixie for the BIND project
142
 *  and of course by RFC 2373.
143
 */
144

    
145
char *
146
ip_ntop(ip_addr a, char *b)
147
{
148
  u16 words[8];
149
  int bestpos, bestlen, curpos, curlen, i;
150

    
151
  /* First of all, preprocess the address and find the longest run of zeros */
152
  bestlen = bestpos = curpos = curlen = 0;
153
  for(i=0; i<8; i++)
154
    {
155
      u32 x = a.addr[i/2];
156
      words[i] = ((i%2) ? x : (x >> 16)) & 0xffff;
157
      if (words[i])
158
        curlen = 0;
159
      else
160
        {
161
          if (!curlen)
162
            curpos = i;
163
          curlen++;
164
          if (curlen > bestlen)
165
            {
166
              bestpos = curpos;
167
              bestlen = curlen;
168
            }
169
        }
170
    }
171
  if (bestlen < 2)
172
    bestpos = -1;
173

    
174
  /* Is it an encapsulated IPv4 address? */
175
  if (!bestpos &&
176
      (bestlen == 5 && a.addr[2] == 0xffff ||
177
       bestlen == 6))
178
    {
179
      u32 x = a.addr[3];
180
      b += bsprintf(b, "::%s%d.%d.%d.%d",
181
                    a.addr[2] ? "ffff:" : "",
182
                    ((x >> 24) & 0xff),
183
                    ((x >> 16) & 0xff),
184
                    ((x >> 8) & 0xff),
185
                    (x & 0xff));
186
      return b;
187
    }
188

    
189
  /* Normal IPv6 formatting, compress the largest sequence of zeros */
190
  for(i=0; i<8; i++)
191
    {
192
      if (i == bestpos)
193
        {
194
          i += bestlen - 1;
195
          *b++ = ':';
196
          if (i == 7)
197
            *b++ = ':';
198
        }
199
      else
200
        {
201
          if (i)
202
            *b++ = ':';
203
          b += bsprintf(b, "%x", words[i]);
204
        }
205
    }
206
  *b = 0;
207
  return b;
208
}
209

    
210
char *
211
ip_ntox(ip_addr a, char *b)
212
{
213
  int i;
214

    
215
  for(i=0; i<4; i++)
216
    {
217
      if (i)
218
        *b++ = '.';
219
      b += bsprintf(b, "%08x", a.addr[i]);
220
    }
221
  return b;
222
}
223

    
224
int
225
ipv4_pton_u32(char *a, u32 *o)
226
{
227
  int i;
228
  unsigned long int l;
229
  u32 ia = 0;
230

    
231
  i=4;
232
  while (i--)
233
    {
234
      char *d, *c = strchr(a, '.');
235
      if (!c != !i)
236
        return 0;
237
      l = strtoul(a, &d, 10);
238
      if (d != c && *d || l > 255)
239
        return 0;
240
      ia = (ia << 8) | l;
241
      if (c)
242
        c++;
243
      a = c;
244
    }
245
  *o = ia;
246
  return 1;
247
}
248

    
249
int
250
ip_pton(char *a, ip_addr *o)
251
{
252
  u16 words[8];
253
  int i, j, k, l, hfil;
254
  char *start;
255

    
256
  if (a[0] == ':')                        /* Leading :: */
257
    {
258
      if (a[1] != ':')
259
        return 0;
260
      a++;
261
    }
262
  hfil = -1;
263
  i = 0;
264
  while (*a)
265
    {
266
      if (*a == ':')                        /* :: */
267
        {
268
          if (hfil >= 0)
269
            return 0;
270
          hfil = i;
271
          a++;
272
          continue;
273
        }
274
      j = 0;
275
      l = 0;
276
      start = a;
277
      for(;;)
278
        {
279
          if (*a >= '0' && *a <= '9')
280
            k = *a++ - '0';
281
          else if (*a >= 'A' && *a <= 'F')
282
            k = *a++ - 'A' + 10;
283
          else if (*a >= 'a' && *a <= 'f')
284
            k = *a++ - 'a' + 10;
285
          else
286
            break;
287
          j = (j << 4) + k;
288
          if (j >= 0x10000 || ++l > 4)
289
            return 0;
290
        }
291
      if (*a == ':' && a[1])
292
        a++;
293
      else if (*a == '.' && (i == 6 || i < 6 && hfil >= 0))
294
        {                                /* Embedded IPv4 address */
295
          u32 x;
296
          if (!ipv4_pton_u32(start, &x))
297
            return 0;
298
          words[i++] = x >> 16;
299
          words[i++] = x;
300
          break;
301
        }
302
      else if (*a)
303
        return 0;
304
      if (i >= 8)
305
        return 0;
306
      words[i++] = j;
307
    }
308

    
309
  /* Replace :: with an appropriate number of zeros */
310
  if (hfil >= 0)
311
    {
312
      j = 8 - i;
313
      for(i=7; i-j >= hfil; i--)
314
        words[i] = words[i-j];
315
      for(; i>=hfil; i--)
316
        words[i] = 0;
317
    }
318

    
319
  /* Convert the address to ip_addr format */
320
  for(i=0; i<4; i++)
321
    o->addr[i] = (words[2*i] << 16) | words[2*i+1];
322
  return 1;
323
}
324

    
325
void ipv6_absolutize(ip_addr *a, ip_addr *ifa)
326
{
327
  if ((a->addr[0] & 0xffc00000) == 0xfe800000 &&        /* a is link-scope */
328
      ((ifa->addr[0] & 0xe0000000) == 0x20000000 |        /* ifa is AGU ... */
329
       (ifa->addr[0] & 0xffc00000) == 0xfec00000))        /* ... or site-scope */
330
    {
331
      a->addr[0] = ifa->addr[0];        /* Copy the prefix, leave interface ID */
332
      a->addr[1] = ifa->addr[1];
333
    }
334
}
335

    
336
#ifdef TEST
337

    
338
#include "bitops.c"
339

    
340
static void test(char *x)
341
{
342
  ip_addr a;
343
  char c[STD_ADDRESS_P_LENGTH+1];
344

    
345
  printf("%-40s ", x);
346
  if (!ip_pton(x, &a))
347
    {
348
      puts("BAD");
349
      return;
350
    }
351
  ip_ntop(a, c);
352
  printf("%-40s %04x\n", c, ipv6_classify(&a));
353
}
354

    
355
int main(void)
356
{
357
  puts("Positive tests:");
358
  test("1:2:3:4:5:6:7:8");
359
  test("dead:beef:DEAD:BEEF::f00d");
360
  test("::");
361
  test("::1");
362
  test("1::");
363
  test("::1.234.5.6");
364
  test("::ffff:1.234.5.6");
365
  test("::fffe:1.234.5.6");
366
  test("1:2:3:4:5:6:7::8");
367
  test("2080::8:800:200c:417a");
368
  test("ff01::101");
369

    
370
  puts("Negative tests:");
371
  test(":::");
372
  test("1:2:3:4:5:6:7:8:");
373
  test("1::2::3");
374
  test("::12345");
375
  test("::1.2.3.4:5");
376
  test(":1:2:3:4:5:6:7:8");
377
  test("g:1:2:3:4:5:6:7");
378
  return 0;
379
}
380

    
381
#endif