📄 sf_ip.c
字号:
ip_p[1] |= ob_p[1]; ip_p[2] |= ob_p[2]; ip_p[3] |= ob_p[3];}/* Check if ip is contained within the network specified by net */ /* Returns SFIP_EQUAL if so. * XXX sfip_contains assumes that "ip" is * not less-specific than "net" XXX*/SFIP_RET sfip_contains(sfip_t *net, sfip_t *ip) { unsigned int bits, mask, temp, i; int net_fam, ip_fam; unsigned int *p1, *p2; /* SFIP_CONTAINS is returned here due to how IpAddrSetContains * handles zero'ed IPs" */ ARG_CHECK2(net, ip, SFIP_CONTAINS); bits = sfip_bits(net); net_fam = sfip_family(net); ip_fam = sfip_family(ip); /* If the families are mismatched, check if we're really comparing * an IPv4 with a mapped IPv4 (in IPv6) address. */ if(net_fam != ip_fam) { if(net_fam != AF_INET && !sfip_ismapped(ip)) return SFIP_NOT_CONTAINS; /* Both are really IPv4. Only compare last 4 bytes of 'ip'*/ p1 = net->ip32; p2 = &ip->ip32[3]; /* Mask off bits */ bits = 32 - bits; temp = (ntohl(*p2) >> bits) << bits; if(ntohl(*p1) == temp) return SFIP_CONTAINS; return SFIP_NOT_CONTAINS; } p1 = net->ip32; p2 = ip->ip32; /* Iterate over each 32 bit segment */ for(i=0; i < bits/32 && i < 4; i++, p1++, p2++) { if(*p1 != *p2) return SFIP_NOT_CONTAINS; } /* At this point, there are some number of remaining bits to check. * Mask the bits we don't care about off of "ip" so we can compare * the ints directly */ temp = ntohl(*p2); mask = 32 - (bits - 32*i); temp = (temp >> mask) << mask; /* If p1 was setup correctly through this library, there is no need to * mask off any bits of its own. */ if(ntohl(*p1) == temp) return SFIP_CONTAINS; return SFIP_NOT_CONTAINS;}void sfip_raw_ntop(int family, const void *ip_raw, char *buf, int bufsize) { int i; if(!ip_raw || !buf || !bufsize || (family != AF_INET && family != AF_INET6) || /* Make sure if it's IPv6 that the buf is large enough. */ /* Need atleast a max of 8 fields of 4 bytes plus 7 for colons in * between. Need 1 more byte for null. */ (family == AF_INET6 && bufsize < 8*4 + 7 + 1) || /* Make sure if it's IPv4 that the buf is large enough. */ /* 4 fields of 3 numbers, plus 3 dots and a null byte */ (family == AF_INET && bufsize < 3*4 + 4) ) { if(buf && bufsize > 0) buf[0] = 0; return; } /* 4 fields of at most 3 characters each */ if(family == AF_INET) { u_int8_t *p = (u_int8_t*)ip_raw; for(i=0; p < ((u_int8_t*)ip_raw) + 4; p++) { i += sprintf(&buf[i], "%d", *p); /* If this is the last iteration, this could technically cause one * extra byte to be written past the end. */ if(i < bufsize && ((p + 1) < ((u_int8_t*)ip_raw+4))) buf[i] = '.'; i++; } /* Check if this is really just an IPv4 address represented as 6, * in compatible format */#if 0 } else if(!field[0] && !field[1] && !field[2]) { unsigned char *p = (unsigned char *)(&ip->ip[12]); for(i=0; p < &ip->ip[16]; p++) i += sprintf(&buf[i], "%d.", *p);#endif } else { u_int16_t *p = (u_int16_t*)ip_raw; for(i=0; p < ((u_int16_t*)ip_raw) + 8; p++) { i += sprintf(&buf[i], "%04x", ntohs(*p)); /* If this is the last iteration, this could technically cause one * extra byte to be written past the end. */ if(i < bufsize && ((p + 1) < ((u_int16_t*)ip_raw) + 8)) buf[i] = ':'; i++; } }}/* Uses a static buffer to return a string representation of the IP */char *sfip_to_str(sfip_t *ip) { /* IPv6 addresses will be at most 8 fields, of 4 characters each, * with 7 colons inbetween, one NULL, and one fudge byte for sloppy use * in sfip_to_strbuf */ static char buf[8*4 + 7 + 1 + 1]; if(!ip) return NULL; sfip_raw_ntop(sfip_family(ip), ip->ip32, buf, sizeof(buf)); return buf;}void sfip_free(sfip_t *ip) { if(ip) free(ip);}/* Returns 1 if the IP is non-zero. 0 otherwise */int sfip_is_loopback(sfip_t *ip) { unsigned int *p; ARG_CHECK1(ip, 0); if(sfip_family(ip) == AF_INET) { return (ip->ip8[0] == 0x7f); } p = ip->ip32; /* Check the first two ints in an IPv6 address, * and verify they're NULL. If not, it's not a loopback */ if(p[0] || p[1]) return 0; /* Check if the 3rd int is a mapped IPv4 address or NULL */ /* If it's 0xffff, then we might be carrying an IPv4 loopback address */ if(p[2] != 0xffff && p[2] != 0) return 0; if(p[3] == 1 || /* IPv6 loopback */ ip->ip8[12] == 0x7f /* IPv4 loopback over compatible or mapped IPv6 */ ) return 1; return 0;}int sfip_ismapped(sfip_t *ip) { unsigned int *p; ARG_CHECK1(ip, 0); if(sfip_family(ip) == AF_INET) return 0; p = ip->ip32; if(p[0] || p[1] || (p[2] != 0xffff && p[2] != 0)) return 0; return 1;}#ifndef strndup char *strndup(const char *s, size_t n) { char *ret; size_t len = strlen(s); if(len < n) { n = len; } ret = (char*)malloc(n+1); if(!ret) return NULL; strncpy(ret, s, n); ret[n] = 0; return ret;}#endif#ifdef TESTER#include <stdio.h>#include <string.h>#define PASS 1#define FAIL 0int sf_ip_failures = 0;/* By using a macro, __LINE__ will be right */#define test(msg, result) { \ if(result == FAIL) { printf("\tFAILED:\t%s\tline %d\n", msg, __LINE__); sf_ip_failures++; } \ else printf("\tPassed:\t%s\n", msg);\}int test_str(sfip_t *ip, char *str) { char *s = sfip_to_str(ip); if(!strcmp( s, str) ) return PASS; printf("\tShould have seen: \"%s\"\n", str); printf("\tInstead saw: \"%s\"\n\t", s); return FAIL;}int sf_ip_unittest() { unsigned int i = 0xffffffff; sfip_t *ip[9]; sfip_t conv; /* Verify the simplest allocation method */ puts("*********************************************************************"); puts("Testing raw allocation:"); ip[0] = sfip_alloc_raw(&i, AF_INET); test("255.255.255.255", test_str(ip[0], "255.255.255.255")); /* The following lines verify parsing via sfip_alloc */ /* sfip_alloc should be able to recognize IPv4 and IPv6 addresses, * and extract and apply netmasks. IPv6 address can be specified in * any valid IPv6 notation as recognized by inet_pton. Netmasks can * either be specified in IP form or by using CIDR notation */ puts(""); puts("*********************************************************************"); puts("Testing parsing:"); ip[1] = sfip_alloc("192.168.0.1"); test("192.168.0.1", test_str(ip[1], "192.168.0.1")); ip[2] = sfip_alloc("255.255.255.255/21"); test("255.255.255.255/21", test_str(ip[2], "255.255.248.0")); ip[3] = sfip_alloc("1.1.255.255 255.255.248.0"); test("1.1.255.255 255.255.248.0", test_str(ip[3], "1.1.248.0")); ip[4] = sfip_alloc(" 2001:0db8:0000:0000:0000:0000:1428:57ab "); test(" 2001:0db8:0000:0000:0000:0000:1428:57ab ", test_str(ip[4], "2001:0db8:0000:0000:0000:0000:1428:57ab")); ip[5] = sfip_alloc("ffff:ffff::1"); test("ffff:ffff::1", test_str(ip[5], "ffff:ffff:0000:0000:0000:0000:0000:0001")); ip[6] = sfip_alloc("fFfF::FfFf:FFFF/127"); test("fFfF::FfFf:FFFF/127", test_str(ip[6], "ffff:0000:0000:0000:0000:0000:ffff:fffe")); ip[7] = sfip_alloc("ffff::ffff:1/8"); test("ffff::ffff:1/8", test_str(ip[7], "ff00:0000:0000:0000:0000:0000:0000:0000")); ip[8] = sfip_alloc("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ::3"); test("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ::3", test_str(ip[8], "c000:0000:0000:0000:0000:0000:0000:0000")); /* Free everything and reallocate it. */ /* This will atleast /imply/ memory is being handled somewhat properly. */ puts(""); puts("*********************************************************************"); puts("Verifying deletes:"); /* Make sure we can free: */ for(i=0; i<9; i++) { sfip_free(ip[i]); } i = 0xffffffff; /* Reallocate */ ip[0] = sfip_alloc_raw(&i, AF_INET); ip[1] = sfip_alloc("192.168.0.1"); ip[2] = sfip_alloc("255.255.255.255/21"); ip[3] = sfip_alloc("1.1.255.255 255.255.248.0"); ip[4] = sfip_alloc(" 2001:0db8:0000:0000:0000:0000:1428:57ab "); ip[5] = sfip_alloc("ffff:ffff::1"); ip[6] = sfip_alloc("ffff::ffff:FFFF/127"); ip[7] = sfip_alloc("ffff::ffff:1/8"); ip[8] = sfip_alloc("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ::3"); printf("\tPassed (as best I can tell, since there was no seg fault)\n"); /* The following lines verify that IPs can be converted to different families. */ puts(""); puts("*********************************************************************"); puts("Verifying IPv4<->IPv6 conversions:"); conv = sfip_4to6(ip[0]); test("ipv4 -> ipv6", test_str(&conv, "0000:0000:0000:0000:0000:ffff:ffff:ffff")); conv = sfip_6to4(&conv); /* Converting an IP from v4 to v6 and back to v4 should yield the same IP. */ test("ipv6 -> ipv4", test_str(&conv, "255.255.255.255")); conv = sfip_6to4(ip[4]); test("ipv6 -> ipv4", test_str(&conv, "20.40.87.171")); /* Comparisons can be byte-by-byte, effectively treating an IP that has * been masked as an unmasked IP (treats the masked bits as zeroed) */ puts(""); puts("*********************************************************************"); puts("Testing byte-by-byte comparisons:"); test("ip[0] > ip[1]", (sfip_cmp(ip[0], ip[1]) == SFIP_GREATER) ); test("ip[1] < ip[2]", (sfip_cmp(ip[1], ip[2]) == SFIP_LESSER) ); test("ip[5] > ip[8]", (sfip_cmp(ip[5], ip[8]) == SFIP_GREATER) ); /* Comparisons can also check if an IP is contained within a given network */ puts(""); puts("*********************************************************************"); puts("Testing network containment comparisons:"); test("ip[0] does not contain ip[1]", (sfip_contains(ip[0], ip[1]) == SFIP_NOT_CONTAINS) ); test("ip[1] does not contain ip[2]", (sfip_contains(ip[1], ip[2]) == SFIP_NOT_CONTAINS) ); test("ip[5] does not contain ip[7]", (sfip_contains(ip[5], ip[7]) == SFIP_NOT_CONTAINS) ); test("ip[7] does contain ip[5]", (sfip_contains(ip[7], ip[5]) == SFIP_CONTAINS) ); test("ip[2] does contain ip[0]", (sfip_contains(ip[2], ip[0]) == SFIP_CONTAINS) ); test("ip[0] does not contain ip[2]", (sfip_contains(ip[0], ip[2]) == SFIP_NOT_CONTAINS) ); test("ip[0] can't be compared to ip[4]", (sfip_contains(ip[0], ip[4]) == SFIP_ARG_ERR) ); puts("*********************************************************************"); puts(" ... Cleaning up"); for(i=0; i<9; i++) { sfip_free(ip[i]); } printf("\n\tTotal failures: %d\n\n", sf_ip_failures); return 1;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -