Nicolas Bernard's Toolbox - Networking Functions

Download: netmisc.h netmisc.c

netmisc.h

  1: /*
  2:  * Misc. network related functions
  3:  *
  4:  * Copyright 2004-2009 Nicolas Bernard <http://www.lafraze.net/nbernard/>
  5:  * All rights reserved.
  6:  *
  7:  * Permission to use, copy, modify, and distribute this software for any
  8:  * purpose with or without fee is hereby granted, provided that the above
  9:  * copyright notice and this permission notice appear in all copies.
 10:  *
 11:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 12:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 13:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 14:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 15:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 16:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 17:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 18:  *
 19:  */
 20: 
 21: #ifndef _NETMISC_H_
 22: #define _NETMISC_H_
 23: 
 24: #include <sys/types.h>
 25: #include <sys/socket.h>
 26: 
 27: /** returns 1 if addr is a loopback address, 0 else (or < 0 if an error occured,
 28:     e.g. addr is of an unsupported type (neither IPv4 nor IPv6). */
 29: extern int isloopback(const struct sockaddr* addr);
 30: 
 31: /** returns 1 if addr is a private (e.g. on a NAT) address, 0 else (or < 0 if
 32:     an error occured,     e.g. addr is of an unsupported type (neither IPv4 nor
 33:     IPv6). */
 34: extern int isprivateip(const struct sockaddr* addr);
 35: 
 36: /** returns 0 if IP(a) != IP(b), 1 if IP(a) == IP(b), <0 in case of error */
 37: extern int addreql(const struct sockaddr* a, const struct sockaddr* b);
 38: 
 39: /** returns 0 if Port(a) != Port(b), 1 if Port(a) == Port(b),
 40:     <0 in case of error */
 41: extern int porteql(const struct sockaddr* a, const struct sockaddr* b);
 42: 
 43: /** returns 1 if the upto first bits of the addresses are equal, 0 otherwise
 44:     <0 in case of error */
 45: extern int prefixeql(const struct sockaddr* a, const struct sockaddr* b, uint8_t upto);
 46: 
 47: /** prints addr on f */
 48: extern int echoip(FILE* f, const struct sockaddr* addr);
 49: 
 50: /** returns the assumed size of the struct sockaddr.
 51:     useful because GLIBC's sockaddr doesn't have a sa_len field */
 52: extern unsigned int addrsize(const struct sockaddr* addr);
 53: 
 54: /** put the string representation of sa in buffer. */
 55: /* Flawfinder: ignore */
 56: extern int string_ip(char buffer[47], const struct sockaddr_storage *sa);
 57: /** convert a string representation to a binary one */
 58: extern int read_ip(const char *string, struct sockaddr_storage *sa);
 59: 
 60: /** those 2 fcts wait for the whole bufsize. returns < 0 if a
 61:     fatal error occurs, 0 if all goes well */
 62: extern int writen(int desc, const void* buf, unsigned int bufsize);
 63: extern int readn(int desc, void* buf, unsigned int bufsize);
 64: 
 65: /** like readn buf don't try to much to read bufsize octets */
 66: extern int readunk(int desc, void* buf, unsigned int bufsize);
 67: 
 68: /* returns the port of the address in addr */
 69: extern uint16_t portof(const struct sockaddr* addr);
 70: 
 71: #endif /* ! _NETMISC_H_ */

netmisc.c

  1: /*
  2:  * Misc. network related functions
  3:  *
  4:  * Copyright 2004-2009 Nicolas Bernard <http://www.lafraze.net/nbernard/>
  5:  * All rights reserved.
  6:  *
  7:  * Permission to use, copy, modify, and distribute this software for any
  8:  * purpose with or without fee is hereby granted, provided that the above
  9:  * copyright notice and this permission notice appear in all copies.
 10:  *
 11:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 12:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 13:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 14:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 15:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 16:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 17:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 18:  *
 19:  */
 20: 
 21: /* On Linux/glibc systems, _BSD_SOURCE must be defined */
 22: 
 23: #include <sys/ioctl.h>
 24: #include <sys/types.h>
 25: #include <sys/socket.h>
 26: #include <net/if.h>
 27: 
 28: 
 29: #include <assert.h>
 30: #include <errno.h>
 31: #include <sys/types.h>
 32: #include <sys/socket.h>
 33: #include <sys/un.h>
 34: #include <netinet/in.h>
 35: #include <netdb.h>
 36: #include <arpa/inet.h>
 37: #include <stdbool.h>
 38: #include <stdio.h>
 39: #include <string.h>
 40: #include <unistd.h>
 41: 
 42: #include "debug.h"
 43: #include "netmisc.h"
 44: 
 45: static bool
 46: isloopbackip4(const struct sockaddr* addr)
 47: { /* all the 127.0.0.* addresses can be loopback */
 48:         unsigned long int ip = 0;
 49:         assert(((struct sockaddr_in*) addr)->sin_family == AF_INET);
 50: 
 51:         ip = (((struct sockaddr_in*) addr)->sin_addr.s_addr);
 52:         if (ip % 256 == 127 && (ip >> 8) % 256 == 0 && (ip >> 16) % 256 == 0)
 53:                 return true;
 54: 
 55:         return false;
 56: }
 57: 
 58: static int
 59: isloopbackip6(const struct sockaddr* addr)
 60: { /* 0000:0000:0000:0000:0000:0000:0000:0001 only ? */
 61:         /** \test test this function */
 62:         assert(((struct sockaddr_in6*) addr)->sin6_family == AF_INET6);
 63: 
 64:         struct in6_addr *tmp6 = &((struct sockaddr_in6*) addr)->sin6_addr;
 65: #ifdef __KAME__
 66:         for (int i = 0; i < 3; i++) {
 67:                 if (tmp6->__u6_addr.__u6_addr32[i])
 68:                         return false;
 69:         }
 70:         if (tmp6->__u6_addr.__u6_addr32[3] == htonl(1))
 71:                 return true;
 72: #elif (__GLIBC__ <= 2 && __GLIBC_MINOR__ < 8)/* ~ linux 2.4 systems ? */
 73:         for (int i = 0; i < 3; i++) {
 74:                 if (tmp6->in6_u.u6_addr32[i])
 75:                         return false;
 76:         }
 77:         if (tmp6->in6_u.u6_addr32[3] == htonl(1))
 78:                 return true;
 79: #else /* ~ linux 2.6+ systems ? */
 80:         for (int i = 0; i < 3; i++) {
 81:                 if (tmp6->__in6_u.__u6_addr32[i])
 82:                         return false;
 83:         }
 84:         if (tmp6->__in6_u.__u6_addr32[3] == htonl(1))
 85:                 return true;
 86: #endif
 87: 
 88:         return false;
 89: }
 90: 
 91: int
 92: isloopback(const struct sockaddr* addr)
 93: {
 94:         switch (((struct sockaddr_in*) addr)->sin_family) {
 95:         case AF_INET:
 96:                 return (int) isloopbackip4(addr);
 97:         case AF_INET6:
 98:                 return (int) isloopbackip6(addr);
 99:         default:
100:                 return -1;
101:         }
102: }
103: 
104: static int
105: isprivateip4(const struct sockaddr* addr)
106: {
107:         if (((struct sockaddr_in*) addr)->sin_family != AF_INET)
108:                 return -2;
109: 
110:         if (isloopbackip4(addr))
111:                 return 1;
112: 
113:         unsigned long int ip = 0;
114:         ip = (((struct sockaddr_in*) addr)->sin_addr.s_addr);
115:         if (ip % 256 == 10)
116:                 return 2;
117:         if ((ip % 256 == 192)
118:             && ((ip >> 8) % 256 == 168))
119:                 return 3;
120:         if ((ip % 256 == 172)
121:             && ((ip >> 8) % 256 >= 16)
122:             && ((ip >> 8) % 256 <= 31))
123:                 return 4;
124: 
125:         return 0;
126: }
127: 
128: static int
129: isprivateip6(const struct sockaddr* addr)
130: { ///\test to test
131:         if (((struct sockaddr_in6*) addr)->sin6_family != AF_INET6) return -3;
132:         if (isloopbackip6(addr)) return 5;
133: 
134:         struct in6_addr *tmp6 = &((struct sockaddr_in6*) addr)->sin6_addr;
135: #ifdef __KAME__
136:         if (tmp6->__u6_addr.__u6_addr8[0] == 0xFE
137:             && tmp6->__u6_addr.__u6_addr8[1] & 0x80)
138:                 return 6;
139: #elif (__GLIBC__ <= 2 && __GLIBC_MINOR__ < 8) /* linux 2.4 ? */
140:         if (tmp6->in6_u.u6_addr8[0] == 0xFE
141:             && tmp6->in6_u.u6_addr8[1] & 0x80)
142:                 return 6;
143: #else /* linux 2.6 ? */
144:         if (tmp6->__in6_u.__u6_addr8[0] == 0xFE
145:             && tmp6->__in6_u.__u6_addr8[1] & 0x80)
146:                 return 6;
147: #endif
148:         return 0;
149: }
150: 
151: int
152: isprivateip(const struct sockaddr* addr)
153: {
154:         switch (((struct sockaddr_in*) addr)->sin_family) {
155:         case AF_INET:
156:                 return isprivateip4(addr);
157:         case AF_INET6:
158:                 return isprivateip6(addr);
159:         default:
160:                 return -1;
161:         }
162: }
163: 
164: static int
165: prefixeql4(const struct sockaddr_in *a, const struct sockaddr_in *b,
166:            uint8_t upto)
167: {
168:         assert(a != NULL);
169:         assert(b != NULL);
170:         assert(upto < 32);
171: 
172:         uint32_t mask = 0xFFFFFFFF;
173:         mask <<= (32 - upto);
174:         mask >>= (32 - upto);
175: 
176:         assert(sizeof a->sin_addr.s_addr == sizeof mask);
177:         assert(sizeof b->sin_addr.s_addr == sizeof mask);
178: 
179:         return ((a->sin_addr.s_addr & mask) == (b->sin_addr.s_addr & mask));
180: }
181: 
182: static int
183: prefixeql6(const struct sockaddr_in6 *a, const struct sockaddr_in6 *b,
184:            uint8_t upto)
185: {
186:         assert(a != NULL);
187:         assert(b != NULL);
188:         assert(upto < 128);
189: 
190:         debug("not implemented");
191:         abort(); /* \todo [IPv6] not implemented yet */
192: 
193:         return -1;
194: }
195: 
196: /* are the address equals up to a prefix? */
197: int
198: prefixeql(const struct sockaddr* a, const struct sockaddr* b, uint8_t upto)
199: {
200:         assert(a != NULL);
201:         assert(b != NULL);
202: 
203:         if (a->sa_family != b->sa_family)
204:                 return 0;
205:         /* nb: returns false if both are IPv4 but one of them is mapped in an
206:            IPv6 address as anyway the size of the prefix won't be the same */
207: 
208:         switch (a->sa_family) {
209:         case AF_INET: {
210:                 if (upto >= 32)
211:                         return addreql(a, b);
212: 
213:                 const struct sockaddr_in *phonya, *phonyb;
214: #ifndef __GLIBC__
215:                 if (a->sa_len != 16 || b->sa_len != 16)
216:                         return -1;
217: #endif
218:                 phonya = (const struct sockaddr_in *) a;
219:                 phonyb = (const struct sockaddr_in *) b;
220:                 return prefixeql4(phonya, phonyb, upto);
221:         }
222:                 break;
223:         case AF_INET6: {
224:                 if (upto >= 128)
225:                         return addreql(a, b);
226: 
227:                 const struct sockaddr_in6 *phonya, *phonyb;
228: #ifndef __GLIBC__
229:                 if (a->sa_len != 28 || b->sa_len != 28)
230:                         return -1;
231: #endif
232:                 phonya = (const struct sockaddr_in6 *) a;
233:                 phonyb = (const struct sockaddr_in6 *) b;
234:                 return prefixeql6(phonya, phonyb, upto);
235:         }
236:                 break;
237:         default:
238:                 return -1;
239:         }
240:         return 0;
241: }
242: 
243: /* look if a contains an IPv4 address mapped in an IPv6 one equal to b. */
244: /* an IPv4 address mapped in an IPv6 one looks like an IPv6 address where
245:    the first 80 bits are 0, the 16 next are 1 and the last 32 ones are
246:    the IPv4 address. */
247: static int
248: addreql64(const struct sockaddr_in6* a, const struct sockaddr_in* b)
249: {
250:         assert(a != NULL);
251:         assert(b != NULL);
252:         assert(a->sin6_family == AF_INET6);
253:         assert(b->sin_family == AF_INET);
254: 
255: #ifndef __GLIBC__
256:         if (a->sin6_len != 28 || b->sin_len != 16)
257:                 return -1;
258: #endif
259: 
260: #ifdef __KAME__
261:         for (int i = 0; i < 2; i++) {
262:                 if (a->sin6_addr.__u6_addr.__u6_addr32[i])
263:                         return 0;
264:         }
265:         if (a->sin6_addr.__u6_addr.__u6_addr16[4]
266:             || a->sin6_addr.__u6_addr.__u6_addr16[5] != 0xFFFF)
267:                 return 0;
268: 
269:         if (a->sin6_addr.__u6_addr.__u6_addr32[3] == b->sin_addr.s_addr)
270:                 return true;
271: #elif (__GLIBC__ <= 2 && __GLIBC_MINOR__ < 8) /* linux 2.4 ? */
272:         for (int i = 0; i < 2; i++) {
273:                 if (a->sin6_addr.in6_u.u6_addr32[i])
274:                         return 0;
275:         }
276:         if (a->sin6_addr.in6_u.u6_addr16[4]
277:             || a->sin6_addr.in6_u.u6_addr16[5] != 0xFFFF)
278:                 return 0;
279: 
280:         if (a->sin6_addr.in6_u.u6_addr32[3] == b->sin_addr.s_addr)
281:                 return 1;
282: #else /* linux 2.6 ? */
283:         for (int i = 0; i < 2; i++) {
284:                 if (a->sin6_addr.__in6_u.__u6_addr32[i])
285:                         return 0;
286:         }
287:         if (a->sin6_addr.__in6_u.__u6_addr16[4]
288:             || a->sin6_addr.__in6_u.__u6_addr16[5] != 0xFFFF)
289:                 return 0;
290: 
291:         if (a->sin6_addr.__in6_u.__u6_addr32[3] == b->sin_addr.s_addr)
292:                 return 1;
293: #endif
294:         return 0;
295: }
296: 
297: int
298: addreql(const struct sockaddr* a, const struct sockaddr* b)
299: {
300:         assert(a != NULL);
301:         assert(b != NULL);
302: 
303:         if (a->sa_family == AF_INET6 && b->sa_family == AF_INET)
304:                 return addreql64((const struct sockaddr_in6*) a,
305:                                  (const struct sockaddr_in*)  b);
306: 
307:         if (a->sa_family == AF_INET && b->sa_family == AF_INET6)
308:                 return addreql64((const struct sockaddr_in6*) b,
309:                                  (const struct sockaddr_in*)  a);
310: 
311:         if (a->sa_family != b->sa_family)
312:                 return 0;
313: 
314:         switch (a->sa_family) {
315:         case AF_INET: {
316:                 const struct sockaddr_in *phonya, *phonyb;
317: #ifndef __GLIBC__
318:                 if (a->sa_len != 16 || b->sa_len != 16)
319:                         return -1;
320: #endif
321:                 phonya = (const struct sockaddr_in *) a;
322:                 phonyb = (const struct sockaddr_in *) b;
323:                 if (!memcmp(&phonya->sin_addr, &phonyb->sin_addr, 4))
324:                         return 1;
325:         }
326:                 break;
327:         case AF_INET6: {
328:                 const struct sockaddr_in6 *phonya, *phonyb;
329: #ifndef __GLIBC__
330:                 if (a->sa_len != 28 || b->sa_len != 28)
331:                         return -1;
332: #endif
333:                 phonya = (const struct sockaddr_in6 *) a;
334:                 phonyb = (const struct sockaddr_in6 *) b;
335:                 if (!memcmp(&phonya->sin6_addr, &phonyb->sin6_addr, 4))
336:                         return 1;
337:         }
338:                 break;
339:         default:
340:                 return -1;
341:         }
342:         return 0;
343: }
344: 
345: uint16_t
346: portof(const struct sockaddr* addr)
347: {
348:         assert(addr != NULL);
349:         switch (addr->sa_family) {
350:         case AF_INET:
351:                 return ((const struct sockaddr_in *) addr)->sin_port;
352:         case AF_INET6:
353:                 return ((const struct sockaddr_in6 *) addr)->sin6_port;
354:         default:
355:                 return 0;
356:         }
357:         return 0;
358: }
359: 
360: int
361: porteql(const struct sockaddr* a, const struct sockaddr* b)
362: {
363:         assert(a != NULL);
364:         assert(b != NULL);
365: 
366:         uint16_t porta = portof(a);
367:         uint16_t portb = portof(b);
368: 
369:         if (porta && porta == portb)
370:                 return 1;
371: 
372:         return 0;
373: }
374: 
375: int
376: echoip(FILE* restrict f, const struct sockaddr* addr)
377: {
378:         /* string_ip use at most 47 octets */
379:         char buf[47]; /* Flawfinder: ignore */
380:         if (string_ip(buf, (const struct sockaddr_storage*) addr) != 0)
381:                 return -1;
382:         fprintf(f, "%s", buf);
383:         return 0;
384: }
385: 
386: inline unsigned int
387: addrsize(const struct sockaddr* addr)
388: {
389: #ifndef __GLIBC__
390:         return addr->sa_len;
391: #else
392:         switch(addr->sa_family) {
393:         case AF_INET:
394:                 return sizeof(struct sockaddr_in);
395:         case AF_INET6:
396:                 return sizeof(struct sockaddr_in6);
397:         default:
398:                 return 0;
399:         }
400: #endif
401: }
402: 
403: int
404: read_ip(const char *string, struct sockaddr_storage *sa)
405: { /** \test */
406:         assert(string != NULL);
407:         assert(sa != NULL);
408: 
409:         memset(sa, 0, sizeof(struct sockaddr));
410:         sa->ss_family = AF_INET;
411:         int err = inet_pton(AF_INET, string,
412:                             &((struct sockaddr_in*) sa)->sin_addr);
413:         if (err == 1)
414:                 return 0;
415:         if (err < 0) {
416:                 stkdbg("inet_pton(AF_INET, ...) returned %d, errno: %s", err,
417:                        strerror(errno));
418:                 return -2;
419:         }
420:         assert(err == 0);
421:         sa->ss_family = AF_INET6;
422:         err = inet_pton(AF_INET6, string,
423:                         &((struct sockaddr_in6*) sa)->sin6_addr);
424:         if (err == 1)
425:                 return 0;
426:         if (err < 0) {
427:                 stkdbg("inet_pton(AF_INET6, ...) returned %d, errno: %s", err,
428:                        strerror(errno));
429:                 return -3;
430:         }
431:         return -1;
432: }
433: 
434: int
435: string_ip(char buffer[static 47] /* Flawfinder: ignore */,
436:           const struct sockaddr_storage *sa)
437: {
438:         assert(buffer != NULL);
439:         assert(sa != NULL);
440:         const char *err;
441: 
442:         if (((struct sockaddr_in*) sa)->sin_family == AF_INET6)
443:                 err = inet_ntop(AF_INET6,
444:                                 &(((struct sockaddr_in6*) sa)->sin6_addr),
445:                                 buffer, 46);
446:         else
447:                 err = inet_ntop(AF_INET,
448:                                 &(((struct sockaddr_in*) sa)->sin_addr),
449:                                 buffer, 46);
450:         buffer[46] = '\0';
451: 
452:         if (err == NULL) {
453:                 buffer[0] = '\0';
454:                 stkdbg("inet_ntop failed: %s", strerror(errno));
455:                 return -1;
456:         }
457: 
458:         return 0;
459: }
460: 
461: int
462: writen(int desc, const void* buf, unsigned int bufsize)
463: {
464:         int err = 0;
465:         uint16_t sent = 0;
466:         int counter = 0;
467:         if (bufsize == 0 || buf == NULL) {
468:                 debug("called writen(%d, %p, %u)", desc, buf, bufsize);
469:                 return -4;
470:         }
471:         do {
472:                 assert((int64_t) bufsize - sent > 0);
473:                 err = write(desc, (uint8_t*) buf + sent, bufsize - sent);
474:                 if (err == 0)
475:                         return -1;
476:                 if (err == -1) {
477:                         counter++;
478:                         if (errno == EAGAIN || errno == EINTR)
479:                                 continue;
480:                         debug("write error: %s", strerror(errno));
481:                         return -2;
482:                 }
483:                 sent += err;
484:                 counter = 0;
485:         } while (sent < bufsize && counter < 10);
486:         if (counter >= 10)
487:                 return -3;
488:         return 0;
489: }
490: 
491: int
492: readn(int desc, void* buf, unsigned int bufsize)
493: {
494:         int err = 0;
495:         uint16_t rcvd = 0;
496:         do {
497:                 assert((int64_t) bufsize - rcvd > 0);
498:                 /* Flawfinder: ignore */
499:                 err = read(desc, (uint8_t*) buf + rcvd, bufsize - rcvd);
500:                 if (err == 0)
501:                         return -1;
502:                 if (err == -1) {
503:                         if (errno == EAGAIN || errno == EINTR)
504:                                 continue;
505:                         stkdbg("read error: %s", strerror(errno));
506:                         return -2;
507:                 }
508:                 rcvd += err;
509:         } while (rcvd < bufsize);
510:         return 0;
511: }
512: 
513: int
514: readunk(int desc, void* buf, unsigned int bufsize)
515: {
516:         int err = 0;
517:         uint16_t rcvd = 0;
518:         do {
519:                 assert((int64_t) bufsize - rcvd > 0);
520:                 /* Flawfinder: ignore */
521:                 err = read(desc, (uint8_t*) buf + rcvd, bufsize - rcvd);
522:                 if (err == 0)
523:                         return (int) rcvd;
524:                 if (err == -1) {
525:                         if (errno == EAGAIN || errno == EINTR) {
526:                                 if (rcvd)
527:                                         return (int) rcvd;
528:                                 continue;
529:                         }
530:                         return -1;
531:                 }
532:                 rcvd += err;
533:         } while (rcvd < bufsize && err == -1);
534:         return (int) rcvd;
535: }
536: 
537: #if 0
538: // don't work yet
539: int
540: getlocaladdresses(struct sockaddr_storage **addrs, unsigned int nbif)
541: {
542:         debug(" ");
543: #ifdef SIOCGIFCONF
544:         if (nbif < 10)
545:                 nbif = 10;
546:         char ifr[nbif * sizeof(struct ifreq)]; /* Flawfinder: ignore */
547:         memset(&ifr, 0, sizeof ifr);
548: 
549:         struct ifconf ifc;
550:         ifc.ifc_len = sizeof ifr;
551:         ifc.ifc_buf = ifr;
552: 
553:         debug(" ");
554: 
555:         int foosock = socket(AF_INET, SOCK_STREAM, 0);
556:         if (foosock == -1) {
557:                 debug("socket failed: %s", strerror(errno));
558:                 return -1;
559:         }
560: 
561:         int err = listen(foosock, 1);
562:         if (err < 0) {
563:                 close(foosock);
564:                 debug("ioctl(SIOCGIFCONF) failed: %s", strerror(errno));
565:                 return -1;
566:         }
567:         err = ioctl(foosock, SIOCGIFCONF, &ifc);
568:         close(foosock);
569:         if (err < 0) {
570:                 debug("ioctl(SIOCGIFCONF) failed: %s", strerror(errno));
571:                 return -1;
572:         }
573:         if (ifc.ifc_len == sizeof ifr) // probable overflow
574:                 return getlocaladdresses(addrs, nbif * 2);
575: 
576:         debug("ifc.ifc_len: %d (was: %d)", ifc.ifc_len, sizeof ifr);
577:         for (int i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++) {
578:                 debug("(i: %d) interface: %s:", i, ifc.ifc_req[i].ifr_name);
579:                 echoip(stderr, &ifc.ifc_req[i].ifr_addr);
580:                 fprintf(stderr, "\n");
581:         }
582:         return 0;
583: #else
584:         return -1;
585: #endif /* SIOCGIFCONF */
586: }
587: #endif
588: 
589: #ifdef NETMISC_TESTS
590: int
591: main()
592: {
593:         int err = 0;
594: 
595:         struct sockaddr_in a;
596:         a.sin_family = AF_INET;
597:         err = inet_pton(AF_INET, "193.168.1.2", &a.sin_addr);
598:         assert(err == 1);
599: 
600:         struct sockaddr_in b;
601:         b.sin_family = AF_INET;
602:         err = inet_pton(AF_INET, "193.168.1.3", &b.sin_addr);
603:         assert(err == 1);
604: 
605:         struct sockaddr_in c;
606:         c.sin_family = AF_INET;
607:         err = inet_pton(AF_INET, "127.0.0.1", &c.sin_addr);
608:         assert(err == 1);
609: 
610:         struct sockaddr_in d;
611:         d.sin_family = AF_INET;
612:         err = inet_pton(AF_INET, "193.161.1.8", &d.sin_addr);
613:         assert(err == 1);
614: 
615:         printf("testing echoip...\n");
616:         echoip(stdout, (struct sockaddr*) &a);
617:         printf("\n");
618:         echoip(stdout, (struct sockaddr*) &b);
619:         printf("\n");
620:         echoip(stdout, (struct sockaddr*) &c);
621:         printf("\n");
622:         echoip(stdout, (struct sockaddr*) &d);
623:         printf("\n");
624: 
625:         printf("testing isloopbackip4...\n");
626:         if (isloopbackip4((struct sockaddr*) &a))
627:                 assert(0);
628: 
629:         if (isloopbackip4((struct sockaddr*) &b))
630:                 assert(0);
631: 
632:         if (!isloopbackip4((struct sockaddr*) &c))
633:                 assert(0);
634: 
635:         if (isloopbackip4((struct sockaddr*) &d))
636:                 assert(0);
637: 
638:         printf("testing prefixeql4...\n");
639:         if (!prefixeql4(&a, &b, 24))
640:                 assert(0);
641: 
642:         if (prefixeql4(&a, &c, 24))
643:                 assert(0);
644: 
645:         if (prefixeql4(&a, &d, 24))
646:                 assert(0);
647: 
648:         if (prefixeql4(&c, &d, 24))
649:                 assert(0);
650: 
651:         // todo: more tests
652: 
653:         printf("done\n");
654:         return 0;
655: }
656: #endif /* NETMISC_TESTS */