#ifndef __ip6_h #define __ip6_h #include #include #include #include #include #include #include #include #include "mem.h" #include "str.h" #ifndef IP_LEN #define IP_LEN 16 #endif static int inline ipv6_null(unsigned char *ip) { int i; for (i = 0; ip[i] == 0 && i < 16; i++); return i == 16 ? 1 : 0; } static int inline ipv6_helper(const char *str, unsigned char ip[16], unsigned char *sub) { register int p, v, v4, v6, n; int x[8]; int c, s, d, saw_colon; /* and you thought ipv4 was bad... */ saw_colon = 0; for (p = s = d = v4 = v6 = n = 0, c = -1; p < 8 && *str; str++) { switch (*str) { case '0': v = 0; break; case '1': v = 1; break; case '2': v = 2; break; case '3': v = 3; break; case '4': v = 4; break; case '5': v = 5; break; case '6': v = 6; break; case '7': v = 7; break; case '8': v = 8; break; case '9': v = 9; break; case 'a': case 'A': v = 10; break; case 'b': case 'B': v = 11; break; case 'c': case 'C': v = 12; break; case 'd': case 'D': v = 13; break; case 'e': case 'E': v = 14; break; case 'f': case 'F': v = 15; break; case '/': /* cidr */ if (!sub) return 0; s = 1; if (d) { x[p] = v4; } else { x[p] = v6; } p++; v4 = v6 = n = 0; break; case ':': if (s || d) return 0; saw_colon = 1; x[p] = v6; p++; v4 = v6 = n = 0; if (str[1] == ':') { c = p; str++; } break; case '.': if (s) return 0; x[p] = v4; p++; v4 = v6 = n = 0; d = 1; break; default: return 0; }; v4 *= 10; v4 += v; v6 *= 16; v6 += v; n++; } if (!saw_colon) { /* could be ipv4... */ return 0; } if (n) { if (s) { if (!sub) return 0; /* last atom was subnet */ if (v4 < 0 || v4 > 128) return 0; /* invert */ v4 = 128 - v4; for (v6 = v = 0; v6 < 16; v += 8, v6++) { if (v4 < v) { sub[v6] = (0xFF << v4) & 0xFF; } else { sub[v6] = 0xFF; } } } else if (d) { x[p] = v4; p++; } else { x[p] = v6; p++; } } for (v = v4 = 0; v < c; v++, v4++, v4++) { ip[v4] = (x[v] & 0xFF00) >> 8; ip[v4+1] = (x[v] & 0x00FF); } v6 = (16 - p) + v4; if (!sub && v6 != 0 && c == -1) return 0; for (; v4 < v6; v4++) ip[v4] = 0; for (v = (c == -1 ? 0 : c); v < p; v++, v4++, v4++) { ip[v4] = (x[v] & 0xFF00) >> 8; ip[v4+1] = (x[v] & 0x00FF); } for (; v4 < 32; v4++) { ip[v4] = 0; /* set the rest of the bits to 0 */ } return 1; } static int inline ipv6_scan(const char *str, unsigned char ip[16]) { return ipv6_helper(str, ip, 0) ? 16 : 0; } static int inline ipv6_cidr(const char *str, unsigned char ip[32]) { return ipv6_helper(str, ip, ip+16) ? 32 : 0; } static int inline ipv6_in_subnet(unsigned char cidr[32], unsigned char ip[16]) { register int i; for (i = 0; i < 16 && cidr[i] == 0; i++); if (i == 16) return 1; for (i = 0; i < 16; i++) { if (cidr[i] != (ip[i] & cidr[16+i])) return 0; } return 1; } static int inline socket_bind6(int fd, unsigned char ip[16], int port) { struct sockaddr_in6 sin; memzero(&sin, sizeof(sin)); sin.sin6_family = PF_INET6; sin.sin6_port = htons(port); memcpy(&sin.sin6_addr, ip, 16); return bind(fd, (struct sockaddr *)&sin, sizeof(sin)); } static int inline socket_bind6_reuse(int fd, unsigned char ip[16], int port) { int opt = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); return socket_bind6(fd, ip, port); } static int inline socket_peer6(int fd, unsigned char ip[16], int *port) { struct sockaddr_in6 sin; int silen; memzero(&sin, sizeof(sin)); silen = sizeof(sin); sin.sin6_family = PF_INET6; if (getpeername(fd, (struct sockaddr *)&sin, (int *)&silen) == -1) { return 0; } if (sin.sin6_family != PF_INET6) return 0; /* Clib */ memcpy(ip, &sin.sin6_addr, 16); *port = ntohs(sin.sin6_port); return 1; } static int inline socket_local6(int fd, unsigned char ip[16], int *port) { struct sockaddr_in6 sin; int silen; memzero(&sin, sizeof(sin)); silen = sizeof(sin); sin.sin6_family = PF_INET6; if (getsockname(fd, (struct sockaddr *)&sin, (int *)&silen) == -1) { return 0; } if (sin.sin6_family != PF_INET6) return 0; /* Clib */ memcpy(ip, &sin.sin6_addr, 16); *port = ntohs(sin.sin6_port); return 1; } static int inline socket_tcp6(void) { int fd; fd = socket(PF_INET6, SOCK_STREAM, 0); if (fd == -1) return -1; if (ndelay_on(fd) == -1) { close(fd); return -1; } return fd; } static int inline socket_udp6(void) { int fd; fd = socket(PF_INET6, SOCK_DGRAM, 0); if (fd == -1) return -1; if (ndelay_on(fd) == -1) { close(fd); return -1; } return fd; } static int inline socket_accept6(int s, unsigned char ip[16], int *port) { struct sockaddr_in6 sa; int dummy = sizeof sa; int r; memzero(&sa, sizeof(sa)); r = accept(s, (struct sockaddr *)&sa, &dummy); if (r == -1) return -1; /* Clib */ memcpy(ip, &sa.sin6_addr, 16); *port = ntohs(sa.sin6_port); return r; } static int inline socket_recv6(int s, char *buf, int len, unsigned char ip[16], int *port) { struct sockaddr_in6 sa; int dummy = sizeof sa; int r; memzero(&sa, sizeof(sa)); r = recvfrom(s, buf, len, 0, (struct sockaddr *)&sa, &dummy); if (r == -1) return -1; /* Clib */ memcpy(ip, &sa.sin6_addr, 16); *port = ntohs(sa.sin6_port); return r; } static int inline socket_send6(int s, const char *buf, int len, const unsigned char ip[16], int port) { struct sockaddr_in6 sa; memzero(&sa, sizeof(sa)); sa.sin6_family = PF_INET6; /* Clib */ sa.sin6_port = htons(port); memcpy(&sa.sin6_addr, ip, 16); return sendto(s, buf, len, 0, (struct sockaddr *)&sa, sizeof(sa)); } #endif