1 /* $NetBSD: inet_addr_local.c,v 1.4 2017/02/14 01:16:49 christos Exp $ */
2
3 /*++
4 /* NAME
5 /* inet_addr_local 3
6 /* SUMMARY
7 /* determine if IP address is local
8 /* SYNOPSIS
9 /* #include <inet_addr_local.h>
10 /*
11 /* int inet_addr_local(addr_list, mask_list, addr_family_list)
12 /* INET_ADDR_LIST *addr_list;
13 /* INET_ADDR_LIST *mask_list;
14 /* unsigned *addr_family;
15 /* DESCRIPTION
16 /* inet_addr_local() determines all active IP interface addresses
17 /* of the local system. Any address found is appended to the
18 /* specified address list. The result value is the number of
19 /* active interfaces found.
20 /*
21 /* The mask_list is either a null pointer, or it is a list that
22 /* receives the netmasks of the interface addresses that were found.
23 /*
24 /* The addr_family_list specifies one or more of AF_INET or AF_INET6.
25 /* DIAGNOSTICS
26 /* Fatal errors: out of memory.
27 /* SEE ALSO
28 /* inet_addr_list(3) address list management
29 /* LICENSE
30 /* .ad
31 /* .fi
32 /* The Secure Mailer license must be distributed with this software.
33 /* AUTHOR(S)
34 /* Wietse Venema
35 /* IBM T.J. Watson Research
36 /* P.O. Box 704
37 /* Yorktown Heights, NY 10598, USA
38 /*
39 /* Dean C. Strik
40 /* Department ICT
41 /* Eindhoven University of Technology
42 /* P.O. Box 513
43 /* 5600 MB Eindhoven, Netherlands
44 /* E-mail: <dean@ipnet6.org>
45 /*--*/
46
47 /* System library. */
48
49 #include <sys_defs.h>
50 #include <sys/socket.h>
51 #include <sys/time.h>
52 #include <netinet/in.h>
53 #include <net/if.h>
54 #include <sys/ioctl.h>
55 #include <arpa/inet.h>
56 #include <unistd.h>
57 #ifdef USE_SYS_SOCKIO_H
58 #include <sys/sockio.h>
59 #endif
60 #include <errno.h>
61 #include <string.h>
62 #ifdef HAS_IPV6 /* Linux only? */
63 #include <netdb.h>
64 #include <stdio.h>
65 #endif
66 #ifdef HAVE_GETIFADDRS
67 #include <ifaddrs.h>
68 #endif
69
70 /* Utility library. */
71
72 #include <msg.h>
73 #include <mymalloc.h>
74 #include <vstring.h>
75 #include <inet_addr_list.h>
76 #include <inet_addr_local.h>
77 #include <myaddrinfo.h>
78 #include <sock_addr.h>
79 #include <mask_addr.h>
80 #include <hex_code.h>
81
82 /*
83 * Postfix needs its own interface address information to determine whether
84 * or not it is an MX host for some destination; without this information,
85 * mail would loop between MX hosts. Postfix also needs its interface
86 * addresses to figure out whether or not it is final destination for
87 * addresses of the form username@[ipaddress].
88 *
89 * Postfix needs its own interface netmask information when no explicit
90 * mynetworks setting is given in main.cf, and "mynetworks_style = subnet".
91 * The mynetworks parameter controls, among others, what mail clients are
92 * allowed to relay mail through Postfix.
93 *
94 * Different systems have different ways to find out this information. We will
95 * therefore use OS dependent methods. An overview:
96 *
97 * - Use getifaddrs() when available. This supports both IPv4/IPv6 addresses.
98 * The implementation however is not present in all major operating systems.
99 *
100 * - Use SIOCGLIFCONF when available. This supports both IPv4/IPv6 addresses.
101 * With SIOCGLIFNETMASK we can obtain the netmask for either address family.
102 * Again, this is not present in all major operating systems.
103 *
104 * - On Linux, glibc's getifaddrs(3) has returned IPv4 information for some
105 * time, but IPv6 information was not returned until 2.3.3. With older Linux
106 * versions we get IPv4 interface information with SIOCGIFCONF, and read
107 * IPv6 address/prefix information from a file in the /proc filesystem.
108 *
109 * - On other systems we expect SIOCGIFCONF to return IPv6 addresses. Since
110 * SIOCGIFNETMASK does not work reliably for IPv6 addresses, we always set
111 * the prefix length to /128 (host), and expect the user to configure a more
112 * appropriate mynetworks setting if needed.
113 *
114 * XXX: Each lookup method is implemented by its own function, so we duplicate
115 * some code. In this case, I think this is better than really drowning in
116 * the #ifdefs...
117 *
118 * -- Dean Strik (dcs)
119 */
120
121 #ifndef HAVE_GETIFADDRS
122
123 /* ial_socket - make socket for ioctl() operations */
124
ial_socket(int af)125 static int ial_socket(int af)
126 {
127 const char *myname = "inet_addr_local[socket]";
128 int sock;
129
130 /*
131 * The host may not be actually configured with IPv6. When IPv6 support
132 * is not actually in the kernel, don't consider failure to create an
133 * IPv6 socket as fatal. This could be tuned better though. For other
134 * families, the error is fatal.
135 *
136 * XXX Now that Postfix controls protocol support centrally with the
137 * inet_proto(3) module, this workaround should no longer be needed.
138 */
139 if ((sock = socket(af, SOCK_DGRAM, 0)) < 0) {
140 #ifdef HAS_IPV6
141 if (af == AF_INET6) {
142 if (msg_verbose)
143 msg_warn("%s: socket: %m", myname);
144 return (-1);
145 }
146 #endif
147 msg_fatal("%s: socket: %m", myname);
148 }
149 return (sock);
150 }
151
152 #endif
153
154 #ifdef HAVE_GETIFADDRS
155
156 /*
157 * The getifaddrs(3) function, introduced by BSD/OS, provides a
158 * platform-independent way of requesting interface addresses,
159 * including IPv6 addresses. The implementation however is not
160 * present in all major operating systems.
161 */
162
163 /* ial_getifaddrs - determine IP addresses using getifaddrs(3) */
164
ial_getifaddrs(INET_ADDR_LIST * addr_list,INET_ADDR_LIST * mask_list,int af)165 static int ial_getifaddrs(INET_ADDR_LIST *addr_list,
166 INET_ADDR_LIST *mask_list,
167 int af)
168 {
169 const char *myname = "inet_addr_local[getifaddrs]";
170 struct ifaddrs *ifap, *ifa;
171 struct sockaddr *sa, *sam;
172
173 if (getifaddrs(&ifap) < 0)
174 msg_fatal("%s: getifaddrs: %m", myname);
175
176 /*
177 * Get the address of each IP network interface. According to BIND we
178 * must include interfaces that are down because the machine may still
179 * receive packets for that address (yes, via some other interface).
180 * Having no way to verify this claim on every machine, I will give them
181 * the benefit of the doubt.
182 *
183 * FIX 200501: The IPv6 patch did not report NetBSD loopback interfaces;
184 * fixed by replacing IFF_RUNNING by IFF_UP.
185 *
186 * FIX 200501: The IPV6 patch did not skip wild-card interface addresses
187 * (tested on FreeBSD).
188 */
189 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
190 if (!(ifa->ifa_flags & IFF_UP) || ifa->ifa_addr == 0)
191 continue;
192 sa = ifa->ifa_addr;
193 if (af != AF_UNSPEC && sa->sa_family != af)
194 continue;
195 sam = ifa->ifa_netmask;
196 if (sam == 0) {
197 /* XXX In mynetworks, a null netmask would match everyone. */
198 msg_warn("ignoring interface with null netmask, address family %d",
199 sa->sa_family);
200 continue;
201 }
202 switch (sa->sa_family) {
203 case AF_INET:
204 if (SOCK_ADDR_IN_ADDR(sa).s_addr == INADDR_ANY)
205 continue;
206 break;
207 #ifdef HAS_IPV6
208 case AF_INET6:
209 if (IN6_IS_ADDR_UNSPECIFIED(&SOCK_ADDR_IN6_ADDR(sa)))
210 continue;
211 break;
212 #endif
213 default:
214 continue;
215 }
216
217 inet_addr_list_append(addr_list, sa);
218 if (mask_list != 0) {
219
220 /*
221 * Unfortunately, sa_len/sa_family may be broken in the netmask
222 * sockaddr structure. We must fix this manually to have correct
223 * addresses. --dcs
224 */
225 #ifdef HAS_SA_LEN
226 sam->sa_len = sa->sa_family == AF_INET6 ?
227 sizeof(struct sockaddr_in6) :
228 sizeof(struct sockaddr_in);
229 #endif
230 sam->sa_family = sa->sa_family;
231 inet_addr_list_append(mask_list, sam);
232 }
233 }
234 freeifaddrs(ifap);
235 return (0);
236 }
237
238 #elif defined(HAS_SIOCGLIF) /* HAVE_GETIFADDRS */
239
240 /*
241 * The SIOCLIF* ioctls are the successors of SIOCGIF* on the Solaris
242 * and HP/UX operating systems. The data is stored in sockaddr_storage
243 * structure. Both IPv4 and IPv6 addresses are returned though these
244 * calls.
245 */
246 #define NEXT_INTERFACE(lifr) (lifr + 1)
247 #define LIFREQ_SIZE(lifr) sizeof(lifr[0])
248
249 /* ial_siocglif - determine IP addresses using ioctl(SIOCGLIF*) */
250
ial_siocglif(INET_ADDR_LIST * addr_list,INET_ADDR_LIST * mask_list,int af)251 static int ial_siocglif(INET_ADDR_LIST *addr_list,
252 INET_ADDR_LIST *mask_list,
253 int af)
254 {
255 const char *myname = "inet_addr_local[siocglif]";
256 struct lifconf lifc;
257 struct lifreq *lifr;
258 struct lifreq *lifr_mask;
259 struct lifreq *the_end;
260 struct sockaddr *sa;
261 int sock;
262 VSTRING *buf;
263
264 /*
265 * See also comments in ial_siocgif()
266 */
267 if (af != AF_INET && af != AF_INET6)
268 msg_fatal("%s: address family was %d, must be AF_INET (%d) or "
269 "AF_INET6 (%d)", myname, af, AF_INET, AF_INET6);
270 sock = ial_socket(af);
271 if (sock < 0)
272 return (0);
273 buf = vstring_alloc(1024);
274 for (;;) {
275 memset(&lifc, 0, sizeof(lifc));
276 lifc.lifc_family = AF_UNSPEC; /* XXX Why??? */
277 lifc.lifc_len = vstring_avail(buf);
278 lifc.lifc_buf = vstring_str(buf);
279 if (ioctl(sock, SIOCGLIFCONF, (char *) &lifc) < 0) {
280 if (errno != EINVAL)
281 msg_fatal("%s: ioctl SIOCGLIFCONF: %m", myname);
282 } else if (lifc.lifc_len < vstring_avail(buf) / 2)
283 break;
284 VSTRING_SPACE(buf, vstring_avail(buf) * 2);
285 }
286
287 the_end = (struct lifreq *) (lifc.lifc_buf + lifc.lifc_len);
288 for (lifr = lifc.lifc_req; lifr < the_end;) {
289 sa = (struct sockaddr *) &lifr->lifr_addr;
290 if (sa->sa_family != af) {
291 lifr = NEXT_INTERFACE(lifr);
292 continue;
293 }
294 if (af == AF_INET) {
295 if (SOCK_ADDR_IN_ADDR(sa).s_addr == INADDR_ANY) {
296 lifr = NEXT_INTERFACE(lifr);
297 continue;
298 }
299 }
300 #ifdef HAS_IPV6
301 else if (af == AF_INET6) {
302 if (IN6_IS_ADDR_UNSPECIFIED(&SOCK_ADDR_IN6_ADDR(sa))) {
303 lifr = NEXT_INTERFACE(lifr);
304 continue;
305 }
306 }
307 #endif
308 inet_addr_list_append(addr_list, sa);
309 if (mask_list) {
310 lifr_mask = (struct lifreq *) mymalloc(sizeof(struct lifreq));
311 memcpy((void *) lifr_mask, (void *) lifr, sizeof(struct lifreq));
312 if (ioctl(sock, SIOCGLIFNETMASK, lifr_mask) < 0)
313 msg_fatal("%s: ioctl(SIOCGLIFNETMASK): %m", myname);
314 /* XXX: Check whether sa_len/family are honoured --dcs */
315 inet_addr_list_append(mask_list,
316 (struct sockaddr *) &lifr_mask->lifr_addr);
317 myfree((void *) lifr_mask);
318 }
319 lifr = NEXT_INTERFACE(lifr);
320 }
321 vstring_free(buf);
322 (void) close(sock);
323 return (0);
324 }
325
326 #else /* HAVE_SIOCGLIF */
327
328 /*
329 * The classic SIOCGIF* ioctls. Modern BSD operating systems will
330 * also return IPv6 addresses through these structure. Note however
331 * that recent versions of these operating systems have getifaddrs.
332 */
333 #if defined(_SIZEOF_ADDR_IFREQ)
334 #define NEXT_INTERFACE(ifr) ((struct ifreq *) \
335 ((char *) ifr + _SIZEOF_ADDR_IFREQ(*ifr)))
336 #define IFREQ_SIZE(ifr) _SIZEOF_ADDR_IFREQ(*ifr)
337 #elif defined(HAS_SA_LEN)
338 #define NEXT_INTERFACE(ifr) ((struct ifreq *) \
339 ((char *) ifr + sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len))
340 #define IFREQ_SIZE(ifr) (sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len)
341 #else
342 #define NEXT_INTERFACE(ifr) (ifr + 1)
343 #define IFREQ_SIZE(ifr) sizeof(ifr[0])
344 #endif
345
346 /* ial_siocgif - determine IP addresses using ioctl(SIOCGIF*) */
347
ial_siocgif(INET_ADDR_LIST * addr_list,INET_ADDR_LIST * mask_list,int af)348 static int ial_siocgif(INET_ADDR_LIST *addr_list,
349 INET_ADDR_LIST *mask_list,
350 int af)
351 {
352 const char *myname = "inet_addr_local[siocgif]";
353 struct in_addr addr;
354 struct ifconf ifc;
355 struct ifreq *ifr;
356 struct ifreq *ifr_mask;
357 struct ifreq *the_end;
358 int sock;
359 VSTRING *buf;
360
361 /*
362 * Get the network interface list. XXX The socket API appears to have no
363 * function that returns the number of network interfaces, so we have to
364 * guess how much space is needed to store the result.
365 *
366 * On BSD-derived systems, ioctl SIOCGIFCONF returns as much information as
367 * possible, leaving it up to the application to repeat the request with
368 * a larger buffer if the result caused a tight fit.
369 *
370 * Other systems, such as Solaris 2.5, generate an EINVAL error when the
371 * buffer is too small for the entire result. Workaround: ignore EINVAL
372 * errors and repeat the request with a larger buffer. The downside is
373 * that the program can run out of memory due to a non-memory problem,
374 * making it more difficult than necessary to diagnose the real problem.
375 */
376 sock = ial_socket(af);
377 if (sock < 0)
378 return (0);
379 buf = vstring_alloc(1024);
380 for (;;) {
381 ifc.ifc_len = vstring_avail(buf);
382 ifc.ifc_buf = vstring_str(buf);
383 if (ioctl(sock, SIOCGIFCONF, (char *) &ifc) < 0) {
384 if (errno != EINVAL)
385 msg_fatal("%s: ioctl SIOCGIFCONF: %m", myname);
386 } else if (ifc.ifc_len < vstring_avail(buf) / 2)
387 break;
388 VSTRING_SPACE(buf, vstring_avail(buf) * 2);
389 }
390
391 the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
392 for (ifr = ifc.ifc_req; ifr < the_end;) {
393 if (ifr->ifr_addr.sa_family != af) {
394 ifr = NEXT_INTERFACE(ifr);
395 continue;
396 }
397 if (af == AF_INET) {
398 addr = ((struct sockaddr_in *) & ifr->ifr_addr)->sin_addr;
399 if (addr.s_addr != INADDR_ANY) {
400 inet_addr_list_append(addr_list, &ifr->ifr_addr);
401 if (mask_list) {
402 ifr_mask = (struct ifreq *) mymalloc(IFREQ_SIZE(ifr));
403 memcpy((void *) ifr_mask, (void *) ifr, IFREQ_SIZE(ifr));
404 if (ioctl(sock, SIOCGIFNETMASK, ifr_mask) < 0)
405 msg_fatal("%s: ioctl SIOCGIFNETMASK: %m", myname);
406
407 /*
408 * Note that this SIOCGIFNETMASK has truly screwed up the
409 * contents of sa_len/sa_family. We must fix this
410 * manually to have correct addresses. --dcs
411 */
412 ifr_mask->ifr_addr.sa_family = af;
413 #ifdef HAS_SA_LEN
414 ifr_mask->ifr_addr.sa_len = sizeof(struct sockaddr_in);
415 #endif
416 inet_addr_list_append(mask_list, &ifr_mask->ifr_addr);
417 myfree((void *) ifr_mask);
418 }
419 }
420 }
421 #ifdef HAS_IPV6
422 else if (af == AF_INET6) {
423 struct sockaddr *sa;
424
425 sa = SOCK_ADDR_PTR(&ifr->ifr_addr);
426 if (!(IN6_IS_ADDR_UNSPECIFIED(&SOCK_ADDR_IN6_ADDR(sa)))) {
427 inet_addr_list_append(addr_list, sa);
428 if (mask_list) {
429 /* XXX Assume /128 for everything */
430 struct sockaddr_in6 mask6;
431
432 mask6 = *SOCK_ADDR_IN6_PTR(sa);
433 memset((void *) &mask6.sin6_addr, ~0,
434 sizeof(mask6.sin6_addr));
435 inet_addr_list_append(mask_list, SOCK_ADDR_PTR(&mask6));
436 }
437 }
438 }
439 #endif
440 ifr = NEXT_INTERFACE(ifr);
441 }
442 vstring_free(buf);
443 (void) close(sock);
444 return (0);
445 }
446
447 #endif /* HAVE_SIOCGLIF */
448
449 #ifdef HAS_PROCNET_IFINET6
450
451 /*
452 * Older Linux versions lack proper calls to retrieve IPv6 interface
453 * addresses. Instead, the addresses can be read from a file in the
454 * /proc tree. The most important issue with this approach however
455 * is that the /proc tree may not always be available, for example
456 * in a chrooted environment or in "hardened" (sic) installations.
457 */
458
459 /* ial_procnet_ifinet6 - determine IPv6 addresses using /proc/net/if_inet6 */
460
ial_procnet_ifinet6(INET_ADDR_LIST * addr_list,INET_ADDR_LIST * mask_list)461 static int ial_procnet_ifinet6(INET_ADDR_LIST *addr_list,
462 INET_ADDR_LIST *mask_list)
463 {
464 const char *myname = "inet_addr_local[procnet_ifinet6]";
465 FILE *fp;
466 char buf[BUFSIZ];
467 unsigned plen;
468 VSTRING *addrbuf;
469 struct sockaddr_in6 addr;
470 struct sockaddr_in6 mask;
471
472 /*
473 * Example: 00000000000000000000000000000001 01 80 10 80 lo
474 *
475 * Fields: address, interface index, prefix length, scope value
476 * (net/ipv6.h), interface flags (linux/rtnetlink.h), device name.
477 *
478 * FIX 200501 The IPv6 patch used fscanf(), which will hang on unexpected
479 * input. Use fgets() + sscanf() instead.
480 */
481 if ((fp = fopen(_PATH_PROCNET_IFINET6, "r")) != 0) {
482 addrbuf = vstring_alloc(MAI_V6ADDR_BYTES + 1);
483 memset((void *) &addr, 0, sizeof(addr));
484 addr.sin6_family = AF_INET6;
485 #ifdef HAS_SA_LEN
486 addr.sin6_len = sizeof(addr);
487 #endif
488 mask = addr;
489 while (fgets(buf, sizeof(buf), fp) != 0) {
490 /* 200501 hex_decode() is light-weight compared to getaddrinfo(). */
491 if (hex_decode(addrbuf, buf, MAI_V6ADDR_BYTES * 2) == 0
492 || sscanf(buf + MAI_V6ADDR_BYTES * 2, " %*x %x", &plen) != 1
493 || plen > MAI_V6ADDR_BITS) {
494 msg_warn("unexpected data in %s - skipping IPv6 configuration",
495 _PATH_PROCNET_IFINET6);
496 break;
497 }
498 /* vstring_str(addrbuf) has worst-case alignment. */
499 addr.sin6_addr = *(struct in6_addr *) vstring_str(addrbuf);
500 inet_addr_list_append(addr_list, SOCK_ADDR_PTR(&addr));
501
502 memset((void *) &mask.sin6_addr, ~0, sizeof(mask.sin6_addr));
503 mask_addr((unsigned char *) &mask.sin6_addr,
504 sizeof(mask.sin6_addr), plen);
505 inet_addr_list_append(mask_list, SOCK_ADDR_PTR(&mask));
506 }
507 vstring_free(addrbuf);
508 fclose(fp); /* FIX 200501 */
509 } else {
510 msg_warn("can't open %s (%m) - skipping IPv6 configuration",
511 _PATH_PROCNET_IFINET6);
512 }
513 return (0);
514 }
515
516 #endif /* HAS_PROCNET_IFINET6 */
517
518 /* inet_addr_local - find all IP addresses for this host */
519
inet_addr_local(INET_ADDR_LIST * addr_list,INET_ADDR_LIST * mask_list,unsigned * addr_family_list)520 int inet_addr_local(INET_ADDR_LIST *addr_list, INET_ADDR_LIST *mask_list,
521 unsigned *addr_family_list)
522 {
523 const char *myname = "inet_addr_local";
524 int initial_count = addr_list->used;
525 unsigned family;
526 int count;
527
528 while ((family = *addr_family_list++) != 0) {
529
530 /*
531 * IP Version 4
532 */
533 if (family == AF_INET) {
534 count = addr_list->used;
535 #if defined(HAVE_GETIFADDRS)
536 ial_getifaddrs(addr_list, mask_list, AF_INET);
537 #elif defined (HAS_SIOCGLIF)
538 ial_siocglif(addr_list, mask_list, AF_INET);
539 #else
540 ial_siocgif(addr_list, mask_list, AF_INET);
541 #endif
542 if (msg_verbose)
543 msg_info("%s: configured %d IPv4 addresses",
544 myname, addr_list->used - count);
545 }
546
547 /*
548 * IP Version 6
549 */
550 #ifdef HAS_IPV6
551 else if (family == AF_INET6) {
552 count = addr_list->used;
553 #if defined(HAVE_GETIFADDRS)
554 ial_getifaddrs(addr_list, mask_list, AF_INET6);
555 #elif defined(HAS_PROCNET_IFINET6)
556 ial_procnet_ifinet6(addr_list, mask_list);
557 #elif defined(HAS_SIOCGLIF)
558 ial_siocglif(addr_list, mask_list, AF_INET6);
559 #else
560 ial_siocgif(addr_list, mask_list, AF_INET6);
561 #endif
562 if (msg_verbose)
563 msg_info("%s: configured %d IPv6 addresses", myname,
564 addr_list->used - count);
565 }
566 #endif
567
568 /*
569 * Something's not right.
570 */
571 else
572 msg_panic("%s: unknown address family %d", myname, family);
573 }
574 return (addr_list->used - initial_count);
575 }
576
577 #ifdef TEST
578
579 #include <string.h>
580 #include <vstream.h>
581 #include <msg_vstream.h>
582 #include <inet_proto.h>
583
main(int unused_argc,char ** argv)584 int main(int unused_argc, char **argv)
585 {
586 INET_ADDR_LIST addr_list;
587 INET_ADDR_LIST mask_list;
588 MAI_HOSTADDR_STR hostaddr;
589 MAI_HOSTADDR_STR hostmask;
590 struct sockaddr *sa;
591 int i;
592 INET_PROTO_INFO *proto_info;
593
594 msg_vstream_init(argv[0], VSTREAM_ERR);
595 msg_verbose = 1;
596
597 proto_info = inet_proto_init(argv[0],
598 argv[1] ? argv[1] : INET_PROTO_NAME_ALL);
599 inet_addr_list_init(&addr_list);
600 inet_addr_list_init(&mask_list);
601 inet_addr_local(&addr_list, &mask_list, proto_info->ai_family_list);
602
603 if (addr_list.used == 0)
604 msg_fatal("cannot find any active network interfaces");
605
606 if (addr_list.used == 1)
607 msg_warn("found only one active network interface");
608
609 for (i = 0; i < addr_list.used; i++) {
610 sa = SOCK_ADDR_PTR(addr_list.addrs + i);
611 SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(sa), SOCK_ADDR_LEN(sa),
612 &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
613 sa = SOCK_ADDR_PTR(mask_list.addrs + i);
614 SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(sa), SOCK_ADDR_LEN(sa),
615 &hostmask, (MAI_SERVPORT_STR *) 0, 0);
616 vstream_printf("%s/%s\n", hostaddr.buf, hostmask.buf);
617 vstream_fflush(VSTREAM_OUT);
618 }
619 inet_addr_list_free(&addr_list);
620 inet_addr_list_free(&mask_list);
621 return (0);
622 }
623
624 #endif
625