blob: 61a278cae985ad36c037b5718c5efeaab6dc8ce0 [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. */
Stephen Hemminger2d362d12009-12-21 12:54:58 +030032static const u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
paul718e3742002-12-13 20:15:29 +000033 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
Michael Lambert4c9641b2010-07-22 13:20:55 -040044afi2family (afi_t afi)
paul718e3742002-12-13 20:15:29 +000045{
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
Michael Lambert4c9641b2010-07-22 13:20:55 -040055afi_t
paul718e3742002-12-13 20:15:29 +000056family2afi (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;
Paul Jakmad3583442010-01-24 21:41:02 +000073 const u_char *np, *pp;
paul718e3742002-12-13 20:15:29 +000074
75 /* If n's prefix is longer than p's one return 0. */
76 if (n->prefixlen > p->prefixlen)
77 return 0;
78
Paul Jakmad3583442010-01-24 21:41:02 +000079 /* Set both prefix's head pointer. */
80 np = (const u_char *)&n->u.prefix;
81 pp = (const u_char *)&p->u.prefix;
82
paul718e3742002-12-13 20:15:29 +000083 offset = n->prefixlen / PNBBY;
84 shift = n->prefixlen % PNBBY;
85
86 if (shift)
87 if (maskbit[shift] & (np[offset] ^ pp[offset]))
88 return 0;
89
90 while (offset--)
91 if (np[offset] != pp[offset])
92 return 0;
93 return 1;
94}
95
96/* Copy prefix from src to dest. */
97void
hassob04c6992004-10-04 19:10:31 +000098prefix_copy (struct prefix *dest, const struct prefix *src)
paul718e3742002-12-13 20:15:29 +000099{
100 dest->family = src->family;
101 dest->prefixlen = src->prefixlen;
102
103 if (src->family == AF_INET)
104 dest->u.prefix4 = src->u.prefix4;
105#ifdef HAVE_IPV6
106 else if (src->family == AF_INET6)
107 dest->u.prefix6 = src->u.prefix6;
108#endif /* HAVE_IPV6 */
109 else if (src->family == AF_UNSPEC)
110 {
111 dest->u.lp.id = src->u.lp.id;
112 dest->u.lp.adv_router = src->u.lp.adv_router;
113 }
114 else
115 {
ajsb9e70282004-12-08 17:14:45 +0000116 zlog (NULL, LOG_ERR, "prefix_copy(): Unknown address family %d",
paul718e3742002-12-13 20:15:29 +0000117 src->family);
118 assert (0);
119 }
120}
121
gdt9d24baa2004-01-13 14:55:40 +0000122/*
123 * Return 1 if the address/netmask contained in the prefix structure
124 * is the same, and else return 0. For this routine, 'same' requires
125 * that not only the prefix length and the network part be the same,
126 * but also the host part. Thus, 10.0.0.1/8 and 10.0.0.2/8 are not
127 * the same. Note that this routine has the same return value sense
128 * as '==' (which is different from prefix_cmp).
129 */
paul718e3742002-12-13 20:15:29 +0000130int
hassob04c6992004-10-04 19:10:31 +0000131prefix_same (const struct prefix *p1, const struct prefix *p2)
paul718e3742002-12-13 20:15:29 +0000132{
133 if (p1->family == p2->family && p1->prefixlen == p2->prefixlen)
134 {
135 if (p1->family == AF_INET)
136 if (IPV4_ADDR_SAME (&p1->u.prefix, &p2->u.prefix))
137 return 1;
138#ifdef HAVE_IPV6
139 if (p1->family == AF_INET6 )
140 if (IPV6_ADDR_SAME (&p1->u.prefix, &p2->u.prefix))
141 return 1;
142#endif /* HAVE_IPV6 */
143 }
144 return 0;
145}
146
gdt9d24baa2004-01-13 14:55:40 +0000147/*
148 * Return 0 if the network prefixes represented by the struct prefix
149 * arguments are the same prefix, and 1 otherwise. Network prefixes
150 * are considered the same if the prefix lengths are equal and the
151 * network parts are the same. Host bits (which are considered masked
152 * by the prefix length) are not significant. Thus, 10.0.0.1/8 and
153 * 10.0.0.2/8 are considered equivalent by this routine. Note that
154 * this routine has the same return sense as strcmp (which is different
155 * from prefix_same).
156 */
paul718e3742002-12-13 20:15:29 +0000157int
hassob04c6992004-10-04 19:10:31 +0000158prefix_cmp (const struct prefix *p1, const struct prefix *p2)
paul718e3742002-12-13 20:15:29 +0000159{
160 int offset;
161 int shift;
162
163 /* Set both prefix's head pointer. */
paul8cc41982005-05-06 21:25:49 +0000164 const u_char *pp1 = (const u_char *)&p1->u.prefix;
165 const u_char *pp2 = (const u_char *)&p2->u.prefix;
paul718e3742002-12-13 20:15:29 +0000166
167 if (p1->family != p2->family || p1->prefixlen != p2->prefixlen)
168 return 1;
169
170 offset = p1->prefixlen / 8;
171 shift = p1->prefixlen % 8;
172
173 if (shift)
174 if (maskbit[shift] & (pp1[offset] ^ pp2[offset]))
175 return 1;
176
177 while (offset--)
178 if (pp1[offset] != pp2[offset])
179 return 1;
180
181 return 0;
182}
183
184/* Return prefix family type string. */
hassob04c6992004-10-04 19:10:31 +0000185const char *
186prefix_family_str (const struct prefix *p)
paul718e3742002-12-13 20:15:29 +0000187{
188 if (p->family == AF_INET)
189 return "inet";
190#ifdef HAVE_IPV6
191 if (p->family == AF_INET6)
192 return "inet6";
193#endif /* HAVE_IPV6 */
194 return "unspec";
195}
196
197/* Allocate new prefix_ipv4 structure. */
198struct prefix_ipv4 *
199prefix_ipv4_new ()
200{
201 struct prefix_ipv4 *p;
202
ajs7907c6c2005-07-26 19:55:31 +0000203 /* Call prefix_new to allocate a full-size struct prefix to avoid problems
204 where the struct prefix_ipv4 is cast to struct prefix and unallocated
205 bytes were being referenced (e.g. in structure assignments). */
206 p = (struct prefix_ipv4 *)prefix_new();
paul718e3742002-12-13 20:15:29 +0000207 p->family = AF_INET;
208 return p;
209}
210
211/* Free prefix_ipv4 structure. */
212void
213prefix_ipv4_free (struct prefix_ipv4 *p)
214{
ajs7907c6c2005-07-26 19:55:31 +0000215 prefix_free((struct prefix *)p);
paul718e3742002-12-13 20:15:29 +0000216}
217
218/* When string format is invalid return 0. */
219int
hassob04c6992004-10-04 19:10:31 +0000220str2prefix_ipv4 (const char *str, struct prefix_ipv4 *p)
paul718e3742002-12-13 20:15:29 +0000221{
222 int ret;
223 int plen;
224 char *pnt;
225 char *cp;
226
227 /* Find slash inside string. */
228 pnt = strchr (str, '/');
229
230 /* String doesn't contail slash. */
231 if (pnt == NULL)
232 {
233 /* Convert string to prefix. */
234 ret = inet_aton (str, &p->prefix);
235 if (ret == 0)
236 return 0;
237
238 /* If address doesn't contain slash we assume it host address. */
239 p->family = AF_INET;
240 p->prefixlen = IPV4_MAX_BITLEN;
241
242 return ret;
243 }
244 else
245 {
246 cp = XMALLOC (MTYPE_TMP, (pnt - str) + 1);
247 strncpy (cp, str, pnt - str);
248 *(cp + (pnt - str)) = '\0';
249 ret = inet_aton (cp, &p->prefix);
250 XFREE (MTYPE_TMP, cp);
251
252 /* Get prefix length. */
253 plen = (u_char) atoi (++pnt);
hasso3fb9cd62004-10-19 19:44:43 +0000254 if (plen > IPV4_MAX_PREFIXLEN)
paul718e3742002-12-13 20:15:29 +0000255 return 0;
256
257 p->family = AF_INET;
258 p->prefixlen = plen;
259 }
260
261 return ret;
262}
263
264/* Convert masklen into IP address's netmask. */
265void
266masklen2ip (int masklen, struct in_addr *netmask)
267{
268 u_char *pnt;
269 int bit;
270 int offset;
271
272 memset (netmask, 0, sizeof (struct in_addr));
273 pnt = (unsigned char *) netmask;
274
275 offset = masklen / 8;
276 bit = masklen % 8;
277
278 while (offset--)
279 *pnt++ = 0xff;
280
281 if (bit)
282 *pnt = maskbit[bit];
283}
284
285/* Convert IP address's netmask into integer. We assume netmask is
286 sequential one. Argument netmask should be network byte order. */
287u_char
288ip_masklen (struct in_addr netmask)
289{
290 u_char len;
291 u_char *pnt;
292 u_char *end;
293 u_char val;
294
295 len = 0;
296 pnt = (u_char *) &netmask;
297 end = pnt + 4;
298
ajs330009f2005-07-26 14:35:37 +0000299 while ((pnt < end) && (*pnt == 0xff))
paul718e3742002-12-13 20:15:29 +0000300 {
301 len+= 8;
302 pnt++;
303 }
304
305 if (pnt < end)
306 {
307 val = *pnt;
308 while (val)
309 {
310 len++;
311 val <<= 1;
312 }
313 }
314 return len;
315}
316
317/* Apply mask to IPv4 prefix. */
318void
319apply_mask_ipv4 (struct prefix_ipv4 *p)
320{
321 u_char *pnt;
322 int index;
323 int offset;
324
325 index = p->prefixlen / 8;
326
327 if (index < 4)
328 {
329 pnt = (u_char *) &p->prefix;
330 offset = p->prefixlen % 8;
331
332 pnt[index] &= maskbit[offset];
333 index++;
334
335 while (index < 4)
336 pnt[index++] = 0;
337 }
338}
339
340/* If prefix is 0.0.0.0/0 then return 1 else return 0. */
341int
hassob04c6992004-10-04 19:10:31 +0000342prefix_ipv4_any (const struct prefix_ipv4 *p)
paul718e3742002-12-13 20:15:29 +0000343{
344 return (p->prefix.s_addr == 0 && p->prefixlen == 0);
345}
346
347#ifdef HAVE_IPV6
348
349/* Allocate a new ip version 6 route */
350struct prefix_ipv6 *
paul8cc41982005-05-06 21:25:49 +0000351prefix_ipv6_new (void)
paul718e3742002-12-13 20:15:29 +0000352{
353 struct prefix_ipv6 *p;
354
ajs7907c6c2005-07-26 19:55:31 +0000355 /* Allocate a full-size struct prefix to avoid problems with structure
356 size mismatches. */
357 p = (struct prefix_ipv6 *)prefix_new();
paul718e3742002-12-13 20:15:29 +0000358 p->family = AF_INET6;
359 return p;
360}
361
362/* Free prefix for IPv6. */
363void
364prefix_ipv6_free (struct prefix_ipv6 *p)
365{
ajs7907c6c2005-07-26 19:55:31 +0000366 prefix_free((struct prefix *)p);
paul718e3742002-12-13 20:15:29 +0000367}
368
369/* If given string is valid return pin6 else return NULL */
370int
hassob04c6992004-10-04 19:10:31 +0000371str2prefix_ipv6 (const char *str, struct prefix_ipv6 *p)
paul718e3742002-12-13 20:15:29 +0000372{
373 char *pnt;
374 char *cp;
375 int ret;
376
377 pnt = strchr (str, '/');
378
379 /* If string doesn't contain `/' treat it as host route. */
380 if (pnt == NULL)
381 {
382 ret = inet_pton (AF_INET6, str, &p->prefix);
Paul Jakmac4cf0952009-08-08 20:41:39 +0100383 if (ret == 0)
paul718e3742002-12-13 20:15:29 +0000384 return 0;
385 p->prefixlen = IPV6_MAX_BITLEN;
386 }
387 else
388 {
389 int plen;
390
391 cp = XMALLOC (0, (pnt - str) + 1);
392 strncpy (cp, str, pnt - str);
393 *(cp + (pnt - str)) = '\0';
394 ret = inet_pton (AF_INET6, cp, &p->prefix);
395 free (cp);
Paul Jakmac4cf0952009-08-08 20:41:39 +0100396 if (ret == 0)
paul718e3742002-12-13 20:15:29 +0000397 return 0;
398 plen = (u_char) atoi (++pnt);
399 if (plen > 128)
400 return 0;
401 p->prefixlen = plen;
402 }
403 p->family = AF_INET6;
404
405 return ret;
406}
407
hassob04c6992004-10-04 19:10:31 +0000408/* Convert struct in6_addr netmask into integer.
409 * FIXME return u_char as ip_maskleni() does. */
paul718e3742002-12-13 20:15:29 +0000410int
411ip6_masklen (struct in6_addr netmask)
412{
413 int len = 0;
414 unsigned char val;
415 unsigned char *pnt;
416
417 pnt = (unsigned char *) & netmask;
418
419 while ((*pnt == 0xff) && len < 128)
420 {
421 len += 8;
422 pnt++;
423 }
424
425 if (len < 128)
426 {
427 val = *pnt;
428 while (val)
429 {
430 len++;
431 val <<= 1;
432 }
433 }
434 return len;
435}
436
437void
438masklen2ip6 (int masklen, struct in6_addr *netmask)
439{
440 unsigned char *pnt;
441 int bit;
442 int offset;
443
444 memset (netmask, 0, sizeof (struct in6_addr));
445 pnt = (unsigned char *) netmask;
446
447 offset = masklen / 8;
448 bit = masklen % 8;
449
450 while (offset--)
451 *pnt++ = 0xff;
452
453 if (bit)
454 *pnt = maskbit[bit];
455}
456
457void
458apply_mask_ipv6 (struct prefix_ipv6 *p)
459{
460 u_char *pnt;
461 int index;
462 int offset;
463
464 index = p->prefixlen / 8;
465
466 if (index < 16)
467 {
468 pnt = (u_char *) &p->prefix;
469 offset = p->prefixlen % 8;
470
471 pnt[index] &= maskbit[offset];
472 index++;
473
474 while (index < 16)
475 pnt[index++] = 0;
476 }
477}
478
479void
hassob04c6992004-10-04 19:10:31 +0000480str2in6_addr (const char *str, struct in6_addr *addr)
paul718e3742002-12-13 20:15:29 +0000481{
482 int i;
483 unsigned int x;
484
485 /* %x must point to unsinged int */
486 for (i = 0; i < 16; i++)
487 {
488 sscanf (str + (i * 2), "%02x", &x);
489 addr->s6_addr[i] = x & 0xff;
490 }
491}
492#endif /* HAVE_IPV6 */
493
494void
495apply_mask (struct prefix *p)
496{
497 switch (p->family)
498 {
499 case AF_INET:
500 apply_mask_ipv4 ((struct prefix_ipv4 *)p);
501 break;
502#ifdef HAVE_IPV6
503 case AF_INET6:
504 apply_mask_ipv6 ((struct prefix_ipv6 *)p);
505 break;
506#endif /* HAVE_IPV6 */
507 default:
508 break;
509 }
510 return;
511}
512
hassob04c6992004-10-04 19:10:31 +0000513/* Utility function of convert between struct prefix <=> union sockunion.
514 * FIXME This function isn't used anywhere. */
paul718e3742002-12-13 20:15:29 +0000515struct prefix *
hassob04c6992004-10-04 19:10:31 +0000516sockunion2prefix (const union sockunion *dest,
517 const union sockunion *mask)
paul718e3742002-12-13 20:15:29 +0000518{
519 if (dest->sa.sa_family == AF_INET)
520 {
521 struct prefix_ipv4 *p;
522
523 p = prefix_ipv4_new ();
524 p->family = AF_INET;
525 p->prefix = dest->sin.sin_addr;
526 p->prefixlen = ip_masklen (mask->sin.sin_addr);
527 return (struct prefix *) p;
528 }
529#ifdef HAVE_IPV6
530 if (dest->sa.sa_family == AF_INET6)
531 {
532 struct prefix_ipv6 *p;
533
534 p = prefix_ipv6_new ();
535 p->family = AF_INET6;
536 p->prefixlen = ip6_masklen (mask->sin6.sin6_addr);
537 memcpy (&p->prefix, &dest->sin6.sin6_addr, sizeof (struct in6_addr));
538 return (struct prefix *) p;
539 }
540#endif /* HAVE_IPV6 */
541 return NULL;
542}
543
hassob04c6992004-10-04 19:10:31 +0000544/* Utility function of convert between struct prefix <=> union sockunion. */
paul718e3742002-12-13 20:15:29 +0000545struct prefix *
hassob04c6992004-10-04 19:10:31 +0000546sockunion2hostprefix (const union sockunion *su)
paul718e3742002-12-13 20:15:29 +0000547{
548 if (su->sa.sa_family == AF_INET)
549 {
550 struct prefix_ipv4 *p;
551
552 p = prefix_ipv4_new ();
553 p->family = AF_INET;
554 p->prefix = su->sin.sin_addr;
555 p->prefixlen = IPV4_MAX_BITLEN;
556 return (struct prefix *) p;
557 }
558#ifdef HAVE_IPV6
559 if (su->sa.sa_family == AF_INET6)
560 {
561 struct prefix_ipv6 *p;
562
563 p = prefix_ipv6_new ();
564 p->family = AF_INET6;
565 p->prefixlen = IPV6_MAX_BITLEN;
566 memcpy (&p->prefix, &su->sin6.sin6_addr, sizeof (struct in6_addr));
567 return (struct prefix *) p;
568 }
569#endif /* HAVE_IPV6 */
570 return NULL;
571}
572
573int
hassob04c6992004-10-04 19:10:31 +0000574prefix_blen (const struct prefix *p)
paul718e3742002-12-13 20:15:29 +0000575{
576 switch (p->family)
577 {
578 case AF_INET:
579 return IPV4_MAX_BYTELEN;
580 break;
581#ifdef HAVE_IPV6
582 case AF_INET6:
583 return IPV6_MAX_BYTELEN;
584 break;
585#endif /* HAVE_IPV6 */
586 }
587 return 0;
588}
589
590/* Generic function for conversion string to struct prefix. */
591int
hassob04c6992004-10-04 19:10:31 +0000592str2prefix (const char *str, struct prefix *p)
paul718e3742002-12-13 20:15:29 +0000593{
594 int ret;
595
596 /* First we try to convert string to struct prefix_ipv4. */
597 ret = str2prefix_ipv4 (str, (struct prefix_ipv4 *) p);
598 if (ret)
599 return ret;
600
601#ifdef HAVE_IPV6
602 /* Next we try to convert string to struct prefix_ipv6. */
603 ret = str2prefix_ipv6 (str, (struct prefix_ipv6 *) p);
604 if (ret)
605 return ret;
606#endif /* HAVE_IPV6 */
607
608 return 0;
609}
610
611int
hassob04c6992004-10-04 19:10:31 +0000612prefix2str (const struct prefix *p, char *str, int size)
paul718e3742002-12-13 20:15:29 +0000613{
614 char buf[BUFSIZ];
615
616 inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ);
617 snprintf (str, size, "%s/%d", buf, p->prefixlen);
618 return 0;
619}
620
621struct prefix *
622prefix_new ()
623{
624 struct prefix *p;
625
626 p = XCALLOC (MTYPE_PREFIX, sizeof *p);
627 return p;
628}
629
630/* Free prefix structure. */
631void
632prefix_free (struct prefix *p)
633{
634 XFREE (MTYPE_PREFIX, p);
635}
636
637/* Utility function. Check the string only contains digit
hassob04c6992004-10-04 19:10:31 +0000638 * character.
639 * FIXME str.[c|h] would be better place for this function. */
paul718e3742002-12-13 20:15:29 +0000640int
hassob04c6992004-10-04 19:10:31 +0000641all_digit (const char *str)
paul718e3742002-12-13 20:15:29 +0000642{
643 for (; *str != '\0'; str++)
644 if (!isdigit ((int) *str))
645 return 0;
646 return 1;
647}
648
649/* Utility function to convert ipv4 prefixes to Classful prefixes */
650void apply_classful_mask_ipv4 (struct prefix_ipv4 *p)
651{
652
653 u_int32_t destination;
654
655 destination = ntohl (p->prefix.s_addr);
656
hasso3fb9cd62004-10-19 19:44:43 +0000657 if (p->prefixlen == IPV4_MAX_PREFIXLEN);
paul718e3742002-12-13 20:15:29 +0000658 /* do nothing for host routes */
659 else if (IN_CLASSC (destination))
660 {
661 p->prefixlen=24;
662 apply_mask_ipv4(p);
663 }
664 else if (IN_CLASSB(destination))
665 {
666 p->prefixlen=16;
667 apply_mask_ipv4(p);
668 }
669 else
670 {
671 p->prefixlen=8;
672 apply_mask_ipv4(p);
673 }
674}
675
hasso3fb9cd62004-10-19 19:44:43 +0000676in_addr_t
677ipv4_network_addr (in_addr_t hostaddr, int masklen)
678{
679 struct in_addr mask;
680
681 masklen2ip (masklen, &mask);
682 return hostaddr & mask.s_addr;
683}
684
685in_addr_t
686ipv4_broadcast_addr (in_addr_t hostaddr, int masklen)
687{
688 struct in_addr mask;
689
690 masklen2ip (masklen, &mask);
691 return (masklen != IPV4_MAX_PREFIXLEN-1) ?
692 /* normal case */
693 (hostaddr | ~mask.s_addr) :
694 /* special case for /31 */
695 (hostaddr ^ ~mask.s_addr);
696}
697
paul718e3742002-12-13 20:15:29 +0000698/* Utility function to convert ipv4 netmask to prefixes
699 ex.) "1.1.0.0" "255.255.0.0" => "1.1.0.0/16"
700 ex.) "1.0.0.0" NULL => "1.0.0.0/8" */
701int
hassob04c6992004-10-04 19:10:31 +0000702netmask_str2prefix_str (const char *net_str, const char *mask_str,
703 char *prefix_str)
paul718e3742002-12-13 20:15:29 +0000704{
705 struct in_addr network;
706 struct in_addr mask;
707 u_char prefixlen;
708 u_int32_t destination;
709 int ret;
710
711 ret = inet_aton (net_str, &network);
712 if (! ret)
713 return 0;
714
715 if (mask_str)
716 {
717 ret = inet_aton (mask_str, &mask);
718 if (! ret)
719 return 0;
720
721 prefixlen = ip_masklen (mask);
722 }
723 else
724 {
725 destination = ntohl (network.s_addr);
726
727 if (network.s_addr == 0)
728 prefixlen = 0;
729 else if (IN_CLASSC (destination))
730 prefixlen = 24;
731 else if (IN_CLASSB (destination))
732 prefixlen = 16;
733 else if (IN_CLASSA (destination))
734 prefixlen = 8;
735 else
736 return 0;
737 }
738
739 sprintf (prefix_str, "%s/%d", net_str, prefixlen);
740
741 return 1;
742}
743
hasso59209902005-04-05 14:36:49 +0000744#ifdef HAVE_IPV6
745/* Utility function for making IPv6 address string. */
746const char *
hasso3a2ce6a2005-04-08 01:30:51 +0000747inet6_ntoa (struct in6_addr addr)
hasso59209902005-04-05 14:36:49 +0000748{
749 static char buf[INET6_ADDRSTRLEN];
750
hasso3a2ce6a2005-04-08 01:30:51 +0000751 inet_ntop (AF_INET6, &addr, buf, INET6_ADDRSTRLEN);
hasso59209902005-04-05 14:36:49 +0000752 return buf;
753}
754#endif /* HAVE_IPV6 */