#include #include #include #include #include #include #include #include struct in_net { struct in_addr addr; struct in_addr mask; }; #define POPCNT(y) int popcnt##y (uint##y##_t x) { \ int c = 0; \ for (int i = 0; i < y; i++) \ if (1 << i & x) \ c++; \ return c; \ } POPCNT(32) 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); if (ret) return ret; *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; } unsigned long long int ri (unsigned long long int v, int s) { /* 000 100 010 110 001 101 011 111 */ int i = s-1; if (!(v & 1 << (s-1))) return v | 1 << (s-1); while (1) { if (!(v & 1 << i)) return v | 1 << i; if (!i) /* rollover */ return 0; v &= ~(1 << i--); } } unsigned long long int localnumber (struct in_net n) { unsigned long long int r = 0; for (int i = 31; i >= 0; i--) if (!(ntohl(n.mask.s_addr) & 1 << i) && ntohl(n.addr.s_addr) & 1 << i) r |= 1 << i; return r; }