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_ */
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 */