blob: d9751e3ff48cfffde7721c5e36d8e308da32d1b6 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/*
2 * Prefix related functions.
3 * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
4 *
5 * This file is part of GNU Zebra.
6 *
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Zebra; see the file COPYING. If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 */
22
23#include <zebra.h>
24
25#include "prefix.h"
26#include "vty.h"
27#include "sockunion.h"
28#include "memory.h"
29#include "log.h"
30
31/* Maskbit. */
32static u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
33 0xf8, 0xfc, 0xfe, 0xff};
34
35/* Number of bits in prefix type. */
36#ifndef PNBBY
37#define PNBBY 8
38#endif /* PNBBY */
39
40#define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff)
41
42/* Address Famiy Identifier to Address Family converter. */
43int
44afi2family (int afi)
45{
46 if (afi == AFI_IP)
47 return AF_INET;
48#ifdef HAVE_IPV6
49 else if (afi == AFI_IP6)
50 return AF_INET6;
51#endif /* HAVE_IPV6 */
52 return 0;
53}
54
55int
56family2afi (int family)
57{
58 if (family == AF_INET)
59 return AFI_IP;
60#ifdef HAVE_IPV6
61 else if (family == AF_INET6)
62 return AFI_IP6;
63#endif /* HAVE_IPV6 */
64 return 0;
65}
66
67/* If n includes p prefix then return 1 else return 0. */
68int
hassob04c6992004-10-04 19:10:31 +000069prefix_match (const struct prefix *n, const struct prefix *p)
paul718e3742002-12-13 20:15:29 +000070{
71 int offset;
72 int shift;
73
74 /* Set both prefix's head pointer. */
75 u_char *np = (u_char *)&n->u.prefix;
76 u_char *pp = (u_char *)&p->u.prefix;
77
78 /* If n's prefix is longer than p's one return 0. */
79 if (n->prefixlen > p->prefixlen)
80 return 0;
81
82 offset = n->prefixlen / PNBBY;
83 shift = n->prefixlen % PNBBY;
84
85 if (shift)
86 if (maskbit[shift] & (np[offset] ^ pp[offset]))
87 return 0;
88
89 while (offset--)
90 if (np[offset] != pp[offset])
91 return 0;
92 return 1;
93}
94
95/* Copy prefix from src to dest. */
96void
hassob04c6992004-10-04 19:10:31 +000097prefix_copy (struct prefix *dest, const struct prefix *src)
paul718e3742002-12-13 20:15:29 +000098{
99 dest->family = src->family;
100 dest->prefixlen = src->prefixlen;
101
102 if (src->family == AF_INET)
103 dest->u.prefix4 = src->u.prefix4;
104#ifdef HAVE_IPV6
105 else if (src->family == AF_INET6)
106 dest->u.prefix6 = src->u.prefix6;
107#endif /* HAVE_IPV6 */
108 else if (src->family == AF_UNSPEC)
109 {
110 dest->u.lp.id = src->u.lp.id;
111 dest->u.lp.adv_router = src->u.lp.adv_router;
112 }
113 else
114 {
115 zlog (NULL, LOG_INFO, "prefix_copy(): Unknown address family %d",
116 src->family);
117 assert (0);
118 }
119}
120
gdt9d24baa2004-01-13 14:55:40 +0000121/*
122 * Return 1 if the address/netmask contained in the prefix structure
123 * is the same, and else return 0. For this routine, 'same' requires
124 * that not only the prefix length and the network part be the same,
125 * but also the host part. Thus, 10.0.0.1/8 and 10.0.0.2/8 are not
126 * the same. Note that this routine has the same return value sense
127 * as '==' (which is different from prefix_cmp).
128 */
paul718e3742002-12-13 20:15:29 +0000129int
hassob04c6992004-10-04 19:10:31 +0000130prefix_same (const struct prefix *p1, const struct prefix *p2)
paul718e3742002-12-13 20:15:29 +0000131{
132 if (p1->family == p2->family && p1->prefixlen == p2->prefixlen)
133 {
134 if (p1->family == AF_INET)
135 if (IPV4_ADDR_SAME (&p1->u.prefix, &p2->u.prefix))
136 return 1;
137#ifdef HAVE_IPV6
138 if (p1->family == AF_INET6 )
139 if (IPV6_ADDR_SAME (&p1->u.prefix, &p2->u.prefix))
140 return 1;
141#endif /* HAVE_IPV6 */
142 }
143 return 0;
144}
145
gdt9d24baa2004-01-13 14:55:40 +0000146/*
147 * Return 0 if the network prefixes represented by the struct prefix
148 * arguments are the same prefix, and 1 otherwise. Network prefixes
149 * are considered the same if the prefix lengths are equal and the
150 * network parts are the same. Host bits (which are considered masked
151 * by the prefix length) are not significant. Thus, 10.0.0.1/8 and
152 * 10.0.0.2/8 are considered equivalent by this routine. Note that
153 * this routine has the same return sense as strcmp (which is different
154 * from prefix_same).
155 */
paul718e3742002-12-13 20:15:29 +0000156int
hassob04c6992004-10-04 19:10:31 +0000157prefix_cmp (const struct prefix *p1, const struct prefix *p2)
paul718e3742002-12-13 20:15:29 +0000158{
159 int offset;
160 int shift;
161
162 /* Set both prefix's head pointer. */
163 u_char *pp1 = (u_char *)&p1->u.prefix;
164 u_char *pp2 = (u_char *)&p2->u.prefix;
165
166 if (p1->family != p2->family || p1->prefixlen != p2->prefixlen)
167 return 1;
168
169 offset = p1->prefixlen / 8;
170 shift = p1->prefixlen % 8;
171
172 if (shift)
173 if (maskbit[shift] & (pp1[offset] ^ pp2[offset]))
174 return 1;
175
176 while (offset--)
177 if (pp1[offset] != pp2[offset])
178 return 1;
179
180 return 0;
181}
182
183/* Return prefix family type string. */
hassob04c6992004-10-04 19:10:31 +0000184const char *
185prefix_family_str (const struct prefix *p)
paul718e3742002-12-13 20:15:29 +0000186{
187 if (p->family == AF_INET)
188 return "inet";
189#ifdef HAVE_IPV6
190 if (p->family == AF_INET6)
191 return "inet6";
192#endif /* HAVE_IPV6 */
193 return "unspec";
194}
195
196/* Allocate new prefix_ipv4 structure. */
197struct prefix_ipv4 *
198prefix_ipv4_new ()
199{
200 struct prefix_ipv4 *p;
201
202 p = XCALLOC (MTYPE_PREFIX_IPV4, sizeof *p);
203 p->family = AF_INET;
204 return p;
205}
206
207/* Free prefix_ipv4 structure. */
208void
209prefix_ipv4_free (struct prefix_ipv4 *p)
210{
211 XFREE (MTYPE_PREFIX_IPV4, p);
212}
213
214/* When string format is invalid return 0. */
215int
hassob04c6992004-10-04 19:10:31 +0000216str2prefix_ipv4 (const char *str, struct prefix_ipv4 *p)
paul718e3742002-12-13 20:15:29 +0000217{
218 int ret;
219 int plen;
220 char *pnt;
221 char *cp;
222
223 /* Find slash inside string. */
224 pnt = strchr (str, '/');
225
226 /* String doesn't contail slash. */
227 if (pnt == NULL)
228 {
229 /* Convert string to prefix. */
230 ret = inet_aton (str, &p->prefix);
231 if (ret == 0)
232 return 0;
233
234 /* If address doesn't contain slash we assume it host address. */
235 p->family = AF_INET;
236 p->prefixlen = IPV4_MAX_BITLEN;
237
238 return ret;
239 }
240 else
241 {
242 cp = XMALLOC (MTYPE_TMP, (pnt - str) + 1);
243 strncpy (cp, str, pnt - str);
244 *(cp + (pnt - str)) = '\0';
245 ret = inet_aton (cp, &p->prefix);
246 XFREE (MTYPE_TMP, cp);
247
248 /* Get prefix length. */
249 plen = (u_char) atoi (++pnt);
250 if (plen > 32)
251 return 0;
252
253 p->family = AF_INET;
254 p->prefixlen = plen;
255 }
256
257 return ret;
258}
259
260/* Convert masklen into IP address's netmask. */
261void
262masklen2ip (int masklen, struct in_addr *netmask)
263{
264 u_char *pnt;
265 int bit;
266 int offset;
267
268 memset (netmask, 0, sizeof (struct in_addr));
269 pnt = (unsigned char *) netmask;
270
271 offset = masklen / 8;
272 bit = masklen % 8;
273
274 while (offset--)
275 *pnt++ = 0xff;
276
277 if (bit)
278 *pnt = maskbit[bit];
279}
280
281/* Convert IP address's netmask into integer. We assume netmask is
282 sequential one. Argument netmask should be network byte order. */
283u_char
284ip_masklen (struct in_addr netmask)
285{
286 u_char len;
287 u_char *pnt;
288 u_char *end;
289 u_char val;
290
291 len = 0;
292 pnt = (u_char *) &netmask;
293 end = pnt + 4;
294
295 while ((*pnt == 0xff) && pnt < end)
296 {
297 len+= 8;
298 pnt++;
299 }
300
301 if (pnt < end)
302 {
303 val = *pnt;
304 while (val)
305 {
306 len++;
307 val <<= 1;
308 }
309 }
310 return len;
311}
312
313/* Apply mask to IPv4 prefix. */
314void
315apply_mask_ipv4 (struct prefix_ipv4 *p)
316{
317 u_char *pnt;
318 int index;
319 int offset;
320
321 index = p->prefixlen / 8;
322
323 if (index < 4)
324 {
325 pnt = (u_char *) &p->prefix;
326 offset = p->prefixlen % 8;
327
328 pnt[index] &= maskbit[offset];
329 index++;
330
331 while (index < 4)
332 pnt[index++] = 0;
333 }
334}
335
336/* If prefix is 0.0.0.0/0 then return 1 else return 0. */
337int
hassob04c6992004-10-04 19:10:31 +0000338prefix_ipv4_any (const struct prefix_ipv4 *p)
paul718e3742002-12-13 20:15:29 +0000339{
340 return (p->prefix.s_addr == 0 && p->prefixlen == 0);
341}
342
343#ifdef HAVE_IPV6
344
345/* Allocate a new ip version 6 route */
346struct prefix_ipv6 *
347prefix_ipv6_new ()
348{
349 struct prefix_ipv6 *p;
350
351 p = XCALLOC (MTYPE_PREFIX_IPV6, sizeof (struct prefix_ipv6));
352 p->family = AF_INET6;
353 return p;
354}
355
356/* Free prefix for IPv6. */
357void
358prefix_ipv6_free (struct prefix_ipv6 *p)
359{
360 XFREE (MTYPE_PREFIX_IPV6, p);
361}
362
363/* If given string is valid return pin6 else return NULL */
364int
hassob04c6992004-10-04 19:10:31 +0000365str2prefix_ipv6 (const char *str, struct prefix_ipv6 *p)
paul718e3742002-12-13 20:15:29 +0000366{
367 char *pnt;
368 char *cp;
369 int ret;
370
371 pnt = strchr (str, '/');
372
373 /* If string doesn't contain `/' treat it as host route. */
374 if (pnt == NULL)
375 {
376 ret = inet_pton (AF_INET6, str, &p->prefix);
377 if (ret != 1)
378 return 0;
379 p->prefixlen = IPV6_MAX_BITLEN;
380 }
381 else
382 {
383 int plen;
384
385 cp = XMALLOC (0, (pnt - str) + 1);
386 strncpy (cp, str, pnt - str);
387 *(cp + (pnt - str)) = '\0';
388 ret = inet_pton (AF_INET6, cp, &p->prefix);
389 free (cp);
390 if (ret != 1)
391 return 0;
392 plen = (u_char) atoi (++pnt);
393 if (plen > 128)
394 return 0;
395 p->prefixlen = plen;
396 }
397 p->family = AF_INET6;
398
399 return ret;
400}
401
hassob04c6992004-10-04 19:10:31 +0000402/* Convert struct in6_addr netmask into integer.
403 * FIXME return u_char as ip_maskleni() does. */
paul718e3742002-12-13 20:15:29 +0000404int
405ip6_masklen (struct in6_addr netmask)
406{
407 int len = 0;
408 unsigned char val;
409 unsigned char *pnt;
410
411 pnt = (unsigned char *) & netmask;
412
413 while ((*pnt == 0xff) && len < 128)
414 {
415 len += 8;
416 pnt++;
417 }
418
419 if (len < 128)
420 {
421 val = *pnt;
422 while (val)
423 {
424 len++;
425 val <<= 1;
426 }
427 }
428 return len;
429}
430
431void
432masklen2ip6 (int masklen, struct in6_addr *netmask)
433{
434 unsigned char *pnt;
435 int bit;
436 int offset;
437
438 memset (netmask, 0, sizeof (struct in6_addr));
439 pnt = (unsigned char *) netmask;
440
441 offset = masklen / 8;
442 bit = masklen % 8;
443
444 while (offset--)
445 *pnt++ = 0xff;
446
447 if (bit)
448 *pnt = maskbit[bit];
449}
450
451void
452apply_mask_ipv6 (struct prefix_ipv6 *p)
453{
454 u_char *pnt;
455 int index;
456 int offset;
457
458 index = p->prefixlen / 8;
459
460 if (index < 16)
461 {
462 pnt = (u_char *) &p->prefix;
463 offset = p->prefixlen % 8;
464
465 pnt[index] &= maskbit[offset];
466 index++;
467
468 while (index < 16)
469 pnt[index++] = 0;
470 }
471}
472
473void
hassob04c6992004-10-04 19:10:31 +0000474str2in6_addr (const char *str, struct in6_addr *addr)
paul718e3742002-12-13 20:15:29 +0000475{
476 int i;
477 unsigned int x;
478
479 /* %x must point to unsinged int */
480 for (i = 0; i < 16; i++)
481 {
482 sscanf (str + (i * 2), "%02x", &x);
483 addr->s6_addr[i] = x & 0xff;
484 }
485}
486#endif /* HAVE_IPV6 */
487
488void
489apply_mask (struct prefix *p)
490{
491 switch (p->family)
492 {
493 case AF_INET:
494 apply_mask_ipv4 ((struct prefix_ipv4 *)p);
495 break;
496#ifdef HAVE_IPV6
497 case AF_INET6:
498 apply_mask_ipv6 ((struct prefix_ipv6 *)p);
499 break;
500#endif /* HAVE_IPV6 */
501 default:
502 break;
503 }
504 return;
505}
506
hassob04c6992004-10-04 19:10:31 +0000507/* Utility function of convert between struct prefix <=> union sockunion.
508 * FIXME This function isn't used anywhere. */
paul718e3742002-12-13 20:15:29 +0000509struct prefix *
hassob04c6992004-10-04 19:10:31 +0000510sockunion2prefix (const union sockunion *dest,
511 const union sockunion *mask)
paul718e3742002-12-13 20:15:29 +0000512{
513 if (dest->sa.sa_family == AF_INET)
514 {
515 struct prefix_ipv4 *p;
516
517 p = prefix_ipv4_new ();
518 p->family = AF_INET;
519 p->prefix = dest->sin.sin_addr;
520 p->prefixlen = ip_masklen (mask->sin.sin_addr);
521 return (struct prefix *) p;
522 }
523#ifdef HAVE_IPV6
524 if (dest->sa.sa_family == AF_INET6)
525 {
526 struct prefix_ipv6 *p;
527
528 p = prefix_ipv6_new ();
529 p->family = AF_INET6;
530 p->prefixlen = ip6_masklen (mask->sin6.sin6_addr);
531 memcpy (&p->prefix, &dest->sin6.sin6_addr, sizeof (struct in6_addr));
532 return (struct prefix *) p;
533 }
534#endif /* HAVE_IPV6 */
535 return NULL;
536}
537
hassob04c6992004-10-04 19:10:31 +0000538/* Utility function of convert between struct prefix <=> union sockunion. */
paul718e3742002-12-13 20:15:29 +0000539struct prefix *
hassob04c6992004-10-04 19:10:31 +0000540sockunion2hostprefix (const union sockunion *su)
paul718e3742002-12-13 20:15:29 +0000541{
542 if (su->sa.sa_family == AF_INET)
543 {
544 struct prefix_ipv4 *p;
545
546 p = prefix_ipv4_new ();
547 p->family = AF_INET;
548 p->prefix = su->sin.sin_addr;
549 p->prefixlen = IPV4_MAX_BITLEN;
550 return (struct prefix *) p;
551 }
552#ifdef HAVE_IPV6
553 if (su->sa.sa_family == AF_INET6)
554 {
555 struct prefix_ipv6 *p;
556
557 p = prefix_ipv6_new ();
558 p->family = AF_INET6;
559 p->prefixlen = IPV6_MAX_BITLEN;
560 memcpy (&p->prefix, &su->sin6.sin6_addr, sizeof (struct in6_addr));
561 return (struct prefix *) p;
562 }
563#endif /* HAVE_IPV6 */
564 return NULL;
565}
566
567int
hassob04c6992004-10-04 19:10:31 +0000568prefix_blen (const struct prefix *p)
paul718e3742002-12-13 20:15:29 +0000569{
570 switch (p->family)
571 {
572 case AF_INET:
573 return IPV4_MAX_BYTELEN;
574 break;
575#ifdef HAVE_IPV6
576 case AF_INET6:
577 return IPV6_MAX_BYTELEN;
578 break;
579#endif /* HAVE_IPV6 */
580 }
581 return 0;
582}
583
584/* Generic function for conversion string to struct prefix. */
585int
hassob04c6992004-10-04 19:10:31 +0000586str2prefix (const char *str, struct prefix *p)
paul718e3742002-12-13 20:15:29 +0000587{
588 int ret;
589
590 /* First we try to convert string to struct prefix_ipv4. */
591 ret = str2prefix_ipv4 (str, (struct prefix_ipv4 *) p);
592 if (ret)
593 return ret;
594
595#ifdef HAVE_IPV6
596 /* Next we try to convert string to struct prefix_ipv6. */
597 ret = str2prefix_ipv6 (str, (struct prefix_ipv6 *) p);
598 if (ret)
599 return ret;
600#endif /* HAVE_IPV6 */
601
602 return 0;
603}
604
605int
hassob04c6992004-10-04 19:10:31 +0000606prefix2str (const struct prefix *p, char *str, int size)
paul718e3742002-12-13 20:15:29 +0000607{
608 char buf[BUFSIZ];
609
610 inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ);
611 snprintf (str, size, "%s/%d", buf, p->prefixlen);
612 return 0;
613}
614
615struct prefix *
616prefix_new ()
617{
618 struct prefix *p;
619
620 p = XCALLOC (MTYPE_PREFIX, sizeof *p);
621 return p;
622}
623
624/* Free prefix structure. */
625void
626prefix_free (struct prefix *p)
627{
628 XFREE (MTYPE_PREFIX, p);
629}
630
631/* Utility function. Check the string only contains digit
hassob04c6992004-10-04 19:10:31 +0000632 * character.
633 * FIXME str.[c|h] would be better place for this function. */
paul718e3742002-12-13 20:15:29 +0000634int
hassob04c6992004-10-04 19:10:31 +0000635all_digit (const char *str)
paul718e3742002-12-13 20:15:29 +0000636{
637 for (; *str != '\0'; str++)
638 if (!isdigit ((int) *str))
639 return 0;
640 return 1;
641}
642
643/* Utility function to convert ipv4 prefixes to Classful prefixes */
644void apply_classful_mask_ipv4 (struct prefix_ipv4 *p)
645{
646
647 u_int32_t destination;
648
649 destination = ntohl (p->prefix.s_addr);
650
651 if (p->prefixlen == 32);
652 /* do nothing for host routes */
653 else if (IN_CLASSC (destination))
654 {
655 p->prefixlen=24;
656 apply_mask_ipv4(p);
657 }
658 else if (IN_CLASSB(destination))
659 {
660 p->prefixlen=16;
661 apply_mask_ipv4(p);
662 }
663 else
664 {
665 p->prefixlen=8;
666 apply_mask_ipv4(p);
667 }
668}
669
670/* Utility function to convert ipv4 netmask to prefixes
671 ex.) "1.1.0.0" "255.255.0.0" => "1.1.0.0/16"
672 ex.) "1.0.0.0" NULL => "1.0.0.0/8" */
673int
hassob04c6992004-10-04 19:10:31 +0000674netmask_str2prefix_str (const char *net_str, const char *mask_str,
675 char *prefix_str)
paul718e3742002-12-13 20:15:29 +0000676{
677 struct in_addr network;
678 struct in_addr mask;
679 u_char prefixlen;
680 u_int32_t destination;
681 int ret;
682
683 ret = inet_aton (net_str, &network);
684 if (! ret)
685 return 0;
686
687 if (mask_str)
688 {
689 ret = inet_aton (mask_str, &mask);
690 if (! ret)
691 return 0;
692
693 prefixlen = ip_masklen (mask);
694 }
695 else
696 {
697 destination = ntohl (network.s_addr);
698
699 if (network.s_addr == 0)
700 prefixlen = 0;
701 else if (IN_CLASSC (destination))
702 prefixlen = 24;
703 else if (IN_CLASSB (destination))
704 prefixlen = 16;
705 else if (IN_CLASSA (destination))
706 prefixlen = 8;
707 else
708 return 0;
709 }
710
711 sprintf (prefix_str, "%s/%d", net_str, prefixlen);
712
713 return 1;
714}
715