/* these functions are useful for dealing with IPv4 */ #ifndef __ip4_h #define __ip4_h #include #include #include #include #include #include #include #include "str.h" #include "mem.h" #ifndef IP_LEN #define IP_LEN 4 #endif static int inline ipv4_null(unsigned char *ip) { int i; for (i = 0; ip[i] == 0 && i < 4; i++); return i == 4 ? 1 : 0; } static int inline ipv4_scan(const char *str, unsigned char ip[4]) { int p, v; ip[0] = ip[1] = ip[2] = ip[3] = 0; for (p = v = 0; *str && p < 4;) { switch (*str) { case '0': v *= 10; break; case '1': v *= 10; v ++; break; case '2': v *= 10; v += 2; break; case '3': v *= 10; v += 3; break; case '4': v *= 10; v += 4; break; case '5': v *= 10; v += 5; break; case '6': v *= 10; v += 6; break; case '7': v *= 10; v += 7; break; case '8': v *= 10; v += 8; break; case '9': v *= 10; v += 9; break; case '.': ip[p] = v; v = 0; p++; break; default: return 0; }; str++; } if (p == 4) return 0; ip[p] = v; return 4; } static int inline ipv4_in_subnet(unsigned char cidr[8], unsigned char ip[4]) { register int i; if (ipv4_null(cidr)) return 1; for (i = 0; i < 4; i++) { if (cidr[i] != (ip[i] & cidr[4+i])) return 0; } return 1; } static int inline ipv4_cidr(char *str, unsigned char cidr[8]) { int r; str_t s; char *p; /* like ipv4_scan but parses a CIDR number */ str_init(s); str_copy(s, str); for (p = str(s); *p && *p != '/'; p++); if (*p == '/') { *p = 0; p++; if (!ipv4_scan(str(s), cidr)) { mem_free(str(s)); return 0; } for (r = 0; p[r]; r++) if (p[r] == '.' && ipv4_scan(p, cidr+4)) { /* form of IN/IN */ mem_free(str(s)); return 8; } /* must be in cidr notation (really) */ r = atoi(p); if (r == -1) { mem_free(str(s)); return 0; } cidr[4] = cidr[5] = cidr[6] = cidr[7] = 0xFF; if (r < 8) { cidr[4] = (0xFF << (8 - r)); cidr[5] = cidr[6] = cidr[7] = 0x00; } else if (r < 16) { cidr[5] = (0xFF << (16 - r)); cidr[6] = cidr[7] = 0x00; } else if (r < 24) { cidr[6] = (0xFF << (24 - r)); cidr[7] = 0x00; } else { cidr[7] = (0xFF << (32 - r)); } mem_free(str(s)); return 8; } else { mem_free(str(s)); return 0; } } static int inline socket_bind4(int fd, unsigned char ip[4], int port) { struct sockaddr_in sin; memzero(&sin, sizeof(sin)); sin.sin_family = PF_INET; /* Clib */ sin.sin_port = htons(port); memcpy(&sin.sin_addr, ip, 4); return bind(fd, (struct sockaddr *)&sin, sizeof(sin)); } static int inline socket_bind4_reuse(int fd, unsigned char ip[4], int port) { int opt = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); return socket_bind4(fd, ip, port); } static int inline socket_peer4(int fd, unsigned char ip[4], int *port) { struct sockaddr_in sin; int silen; memzero(&sin, sizeof(sin)); silen = sizeof(sin); sin.sin_family = PF_INET; if (getpeername(fd, (struct sockaddr *)&sin, (int *)&silen) == -1) { return 0; } if (sin.sin_family != PF_INET) return 0; memcpy(ip, &sin.sin_addr, 4); *port = ntohs(sin.sin_port); return 1; } static int inline socket_local4(int fd, unsigned char ip[4], int *port) { struct sockaddr_in sin; int silen; memzero(&sin, sizeof(sin)); silen = sizeof(sin); sin.sin_family = PF_INET; if (getsockname(fd, (struct sockaddr *)&sin, (int *)&silen) == -1) { return 0; } if (sin.sin_family != PF_INET) return 0; memcpy(ip, &sin.sin_addr, 4); *port = ntohs(sin.sin_port); return 1; } static int inline socket_tcp4(void) { int fd; fd = socket(PF_INET, SOCK_STREAM, 0); if (fd == -1) return -1; if (ndelay_on(fd) == -1) { close(fd); return -1; } return fd; } static int inline socket_udp4(void) { int fd; fd = socket(PF_INET, SOCK_DGRAM, 0); if (fd == -1) return -1; if (ndelay_on(fd) == -1) { close(fd); return -1; } return fd; } static int inline socket_accept4(int s, unsigned char ip[4], int *port) { struct sockaddr_in sa; int dummy = sizeof sa; int r; memzero(&sa, sizeof(sa)); r = accept(s, (struct sockaddr *)&sa, &dummy); if (r == -1) return -1; memcpy(ip, &sa.sin_addr, 4); *port = ntohs(sa.sin_port); return r; } static int inline socket_recv4(int s, char *buf, int len, unsigned char ip[4], int *port) { struct sockaddr_in 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; memcpy(ip, &sa.sin_addr, 4); *port = ntohs(sa.sin_port); return r; } static int inline socket_send4(int s, const char *buf, int len, const unsigned char ip[4], int port) { struct sockaddr_in sa; memzero(&sa, sizeof(sa)); sa.sin_family = PF_INET; sa.sin_port = htons(port); memcpy(&sa.sin_addr, ip, 4); return sendto(s, buf, len, 0, (struct sockaddr *)&sa, sizeof(sa)); } #endif