#include #include #include #include #include #include #include #include struct in_net { struct in_addr addr; struct in_addr mask; }; /* not needed begin */ #define POPCNT(y) int popcnt##x (uint##y##_t x) { \ int c = 0; \ for (int i = 0; i < y; i++) \ if (1 << i & x) \ c++; \ return c; \ } POPCNT(32) unsigned int power2[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648 }; /* ah yes, libmath */ /* not needed end */ struct in_net host (struct in_net n, unsigned long long int h /* number of host in the network */) { n.addr.s_addr = ntohl(n.addr.s_addr & n.mask.s_addr); n.mask.s_addr = ntohl(n.mask.s_addr); unsigned long long int c = 1; unsigned long int s = 0; for (unsigned long int i = 0; i < 32; i++) if (1 << i & ~n.mask.s_addr) { if (1 << s++ & h) n.addr.s_addr |= 1 << i; c *= 2; /* if we instead indicated error via addr and */ } /* returned just addr, it would be impossible to */ n.mask.s_addr = INADDR_BROADCAST; /* scan 0.0.0.0/0 without immediately detecting */ if (h >= c) /* this false "error" and address 0.0.0.0 would */ n.mask.s_addr = 0; /* in fact actually be correct. */ n.addr.s_addr = htonl(n.addr.s_addr); return n; /* \/= this means host h is outside network */ } /* returns struct in_net: if .mask is not 255.255.255.255 (INADDR_BROADCAST), .addr is incorrect */ int resolve (const char * d, uint32_t * r) { struct addrinfo hints = { .ai_family = AF_INET, .ai_socktype = SOCK_DGRAM, .ai_flags = 0, .ai_protocol = 0, .ai_canonname = NULL, .ai_addr = NULL, .ai_next = NULL }; struct addrinfo * result; int ret = getaddrinfo(d, NULL, &hints, &result); *r = ((struct sockaddr_in *) result->ai_addr)->sin_addr.s_addr; /* ah yes, C */ freeaddrinfo(result); return ret; } struct in_net str2net (char * s) { /* blocking, resolving */ struct in_net r = { .mask = { .s_addr = 0 }, .addr = { .s_addr = 0 } }; char * m = strchr(s, '/'); char o = '\0'; int e; if (m) { o = *m; *m++ = '\0'; } else m = "32"; fprintf(stderr, "str2net: resolving %s ... ", s); if ((e = resolve(s, &r.addr.s_addr))) { fprintf(stderr, "failed: %s\n", gai_strerror(e)); goto r; } fprintf(stderr, " %s mask %s ...", inet_ntoa(r.addr), m); char * p; int x = strtoll(m, &p, 10); r.mask.s_addr = 0; for (int j = 0; j < x && j < 32; j++) r.mask.s_addr = r.mask.s_addr >> 1 | 1 << 31; r.mask.s_addr = htonl(r.mask.s_addr); if (*p) if ((e = resolve(m, &r.mask.s_addr))) { fprintf(stderr, "no: %s\n", gai_strerror(e)); goto r; } fprintf(stderr, " %s\n", inet_ntoa(r.mask)); r: if (o) *--m = o; return r; }