#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netdb.h>
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;
}