From a733daccce972d7d8ca3701b810032abc4a6daea Mon Sep 17 00:00:00 2001 From: rusty Date: Sun, 27 Aug 2000 07:47:46 +0000 Subject: Patch-o-matic! now included. --- ippool/Makefile | 18 ++ ippool/ippool.c | 589 +++++++++++++++++++++++++++++++++++++++++++++++++++++ ippool/libippool.c | 72 +++++++ 3 files changed, 679 insertions(+) create mode 100644 ippool/Makefile create mode 100644 ippool/ippool.c create mode 100644 ippool/libippool.c (limited to 'ippool') diff --git a/ippool/Makefile b/ippool/Makefile new file mode 100644 index 0000000..100c2e4 --- /dev/null +++ b/ippool/Makefile @@ -0,0 +1,18 @@ +EXTRAS+=$(shell [ -f $(KERNEL_DIR)/include/linux/netfilter_ipv4/ip_pool.h ] && echo ippool/libippool.a ippool/ippool) + +ifndef TOPLEVEL_INCLUDED +local: + cd .. && $(MAKE) $(KERN_TARGETS) $(SHARED_LIBS) $(EXTRAS) + +else +EXTRA_DEPENDS+=$(shell [ -f $(KERNEL_DIR)/include/linux/netfilter_ipv4/ip_pool.h ] && echo ippool/libippool.d) + +ippool/libippool.a: ippool/libippool.a(ippool/libippool.o) + +ippool/libippool.d: %.d: %.c + @-$(CC) -M -MG $(CFLAGS) $< | sed -e 's@^.*\.o:@$*.d $*.a($*.o):@' > $@ + +ippool/ippool.o: ippool/ippool.c +ippool/ippool: ippool/ippool.o ippool/libippool.a + $(CC) $(CFLAGS) -o $@ $^ +endif diff --git a/ippool/ippool.c b/ippool/ippool.c new file mode 100644 index 0000000..3a680d3 --- /dev/null +++ b/ippool/ippool.c @@ -0,0 +1,589 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* translate errnos, as returned by our *sockopt() functions */ +static char *errno2msg(int op, int err) +{ + switch(err) { + case ERANGE: + return "Address out of pool range"; + } + return strerror(err); +} + +static void usage(char *msg) +{ + if (msg) fprintf(stderr, "ERROR: %s\n", msg); + fprintf(stderr, +"Usage: ippool [-LADCNF] [POOL] [args]\n" +"The POOL argument is either a number, or a name from %s\n" +, IPPOOL_CONF); + fprintf(stderr, +"ippool [-n] [-l|-L POOL] [-u] [-v]\n" + "\tLists all (-l), or a single (-L) pool.\n" + "\tWith -u, summarized usage counts are listed.\n" + "\tWith -v, each pool membership is shown, one per line.\n" +"ippool [-n] [-f|-F [POOL]]\n" + "\tflushes POOL (or all pools.)\n" +"ippool [-n] [-x|-X [POOL]]\n" + "\tremoves POOL (or all pools.)\n" +"ippool [-n] -B\n" + "\tcreates all fully specified pools found in the config file.\n" +"ippool [-n] -N POOL [-t type] [FIRST LAST]\n" + "\tcreates POOL of IP addresses FIRST to LAST (inclusive). If a\n" + "\tpool name from the config file %s is used, type and\n" + "\taddress information can be defined there. The -t argument\n" + "\tgives the type (default bitmap).\n" +"ippool [-n] -A POOL ADDR\n" + "\tadds ADDR to POOL\n" +"ippool [-n] -D POOL ADDR\n" + "\tremoves ADDR from POOL\n" +"ippool [-n] -C POOL ADDR\n" + "\ttests ADDR against membership in POOL\n" +, IPPOOL_CONF); + exit(1); +} + +/* config file parsing */ + +#define IP_POOL_T_NONE 0 +#define IP_POOL_T_BITMAP 1 + +static int conf_type = IP_POOL_T_NONE; +static unsigned long conf_addr = 0; +static unsigned long conf_addr2 = 0; + +#define SCAN_EOF (IP_POOL_NONE-1) + +static ip_pool_t get_index_line( + FILE *fp, + char **namep, + char **typep, + char **argp +) { + char *p; + ip_pool_t index; + static char buf[256]; + + if (namep) *namep = 0; + if (typep) *typep = 0; + if (argp) *argp = 0; + + if (!fgets(buf, sizeof(buf), fp)) return SCAN_EOF; + + p = strtok(buf, " \t\n"); + if (!p || *p == '#') return IP_POOL_NONE; + index = atoi(p); + + p = strtok(0, " \t\n"); + if (!p || *p == '#') return index; + if (namep) *namep = p; + + p = strtok(0, " \t\n"); + if (!p || *p == '#') return index; + if (typep) *typep = p; + + p = strtok(0, "#\n"); + if (argp) *argp = p; + + return index; +} + +static ip_pool_t get_index(char *name) +{ + FILE *fp; + char *poolname, *type, *arg, *p; + ip_pool_t res; + + if (isdigit(*name)) + return atoi(name); + fp = fopen(IPPOOL_CONF, "r"); + if (!fp) { + fprintf(stderr, "cannot open %s - no pool names", IPPOOL_CONF); + exit(1); + } + while (SCAN_EOF != (res=get_index_line(fp, &poolname, &type, &arg))) { + if (poolname && 0 == strcmp(poolname, name)) { + if (!type || (0 == strcmp(type, "bitmap"))) { + conf_type = IP_POOL_T_BITMAP; + p = strtok(arg, " \t"); + if (p) { + conf_addr = inet_addr(p); + p = strtok(0, " \t"); + if (p) + conf_addr2 = inet_addr(p); + else + conf_addr = 0; + } + } + break; + } + } + fclose(fp); + if (res == SCAN_EOF) { + fprintf(stderr, "pool '%s' not found in %s\n", + name, IPPOOL_CONF); + exit(1); + } + return res; +} + +static char *get_name(ip_pool_t index) +{ + FILE *fp; + static char sbuf[256]; + int ok = 0; + + fp = fopen(IPPOOL_CONF, "r"); + if (fp) { + while (fgets(sbuf, sizeof(sbuf), fp)) { + char *p = strtok(sbuf, " \t\n"); + + if (!p || *p == '#') continue; + if (index != atoi(p)) continue; + p = strtok(0, " \t\n"); + if (!p || *p == '#') continue; + memmove(sbuf, p, strlen(p)+1); + ok = 1; + break; + } + fclose(fp); + } + if (!ok) sprintf(sbuf, "%d", index); + return sbuf; +} + +/* user/kernel interaction */ + +static int fd = -1; +static int flag_n = 0; /* do not do anything; just brag about it */ +static int flag_v = 0; /* be verbose (list members) */ +static int flag_q = 0; /* be quiet */ +static int flag_u = 0; /* show usage counts in listings */ +static char *flag_t = "bitmap"; /* pool type */ + +static ip_pool_t high_nr(void) +{ + struct ip_pool_request req; + int reqlen = sizeof(req); + + req.op = IP_POOL_HIGH_NR; + if (0 > getsockopt(fd, SOL_IP, SO_IP_POOL, &req, &reqlen)) { + fprintf(stderr, + "IP_POOL_HIGH_NR failed: %s\n", + errno2msg(IP_POOL_HIGH_NR, errno)); + exit(1); + } + return req.index; +} + +static void do_list(ip_pool_t pool) +{ + struct ip_pool_request req; + int reqlen = sizeof(req); + u_int32_t first_ip; + u_int32_t last_ip; + + req.op = IP_POOL_LOOKUP; + req.index = pool; + req.addr = req.addr2 = 0; + reqlen = sizeof(req); + if (0 == getsockopt(fd, SOL_IP, SO_IP_POOL, &req, &reqlen)) { + struct in_addr ina; + ina.s_addr = req.addr; + printf("%s %s", get_name(req.index), inet_ntoa(ina)); + ina.s_addr = req.addr2; + printf(" %s", inet_ntoa(ina)); + first_ip = ntohl(req.addr); + last_ip = ntohl(req.addr2); + if (flag_u) { + req.op = IP_POOL_USAGE; + req.index = pool; + reqlen = sizeof(req); + if (0 == getsockopt(fd, SOL_IP, SO_IP_POOL, + &req, &reqlen)) { + printf(" %d %d", req.addr, req.addr2); + } else { + printf(" - -"); + } + } + printf("\n"); + if (flag_v) { + while (first_ip <= last_ip) { + req.op = IP_POOL_TEST_ADDR; + req.index = pool; + ina.s_addr = req.addr = htonl(first_ip); + reqlen = sizeof(req); + if (0 == getsockopt(fd, SOL_IP, SO_IP_POOL, + &req, &reqlen)) { + if (req.addr) printf("\t%s\n", + inet_ntoa(ina)); + } + first_ip++; + } + } + } +} + +static void do_list_all(void) +{ + ip_pool_t i, highest = high_nr(); + + for (i=0; i<=highest; i++) + do_list(i); +} + +static void do_flush(ip_pool_t pool) +{ + struct ip_pool_request req; + int reqlen = sizeof(req); + + req.op = IP_POOL_FLUSH; + req.index = pool; + if (flag_n) { + printf("ippool -F %d\n", req.index); + return; + } + if (0 > getsockopt(fd, SOL_IP, SO_IP_POOL, &req, &reqlen)) { + int err = errno; + fprintf(stderr, + "IP_POOL_FLUSH %s failed: %s\n", + get_name(pool), errno2msg(IP_POOL_FLUSH, err)); + exit(1); + } +} + +static void do_flush_all(void) +{ + ip_pool_t i, highest = high_nr(); + + for (i=0; i<=highest; i++) + do_flush(i); +} + +static void do_destroy(ip_pool_t pool) +{ + struct ip_pool_request req; + int reqlen = sizeof(req); + + req.op = IP_POOL_DESTROY; + req.index = pool; + if (flag_n) { + printf("ippool -X %d\n", req.index); + return; + } + if (0 > getsockopt(fd, SOL_IP, SO_IP_POOL, &req, &reqlen)) { + int err = errno; + fprintf(stderr, + "IP_POOL_DESTROY %s failed: %s\n", + get_name(pool), errno2msg(IP_POOL_DESTROY, err)); + exit(1); + } +} + +static void do_destroy_all(void) +{ + ip_pool_t i, highest = high_nr(); + + for (i=0; i<=highest; i++) + do_destroy(i); +} + +static int do_adddel(ip_pool_t pool, char *straddr, int op) +{ + struct ip_pool_request req; + int res; + int reqlen = sizeof(req); + + req.op = op; + req.index = pool; + req.addr = inet_addr(straddr); + req.addr2 = 0; + if (flag_n) { + printf("ippool -%c %s %s\n", + (op == IP_POOL_ADD_ADDR) ? 'A' : 'D', + get_name(req.index), straddr); + return 0; + } + res = getsockopt(fd, SOL_IP, SO_IP_POOL, &req, &reqlen); + if (0 > res) { + int err = errno; + fprintf(stderr, + "IP_POOL_ADD/DEL %s in %s failed: %s\n", + straddr, get_name(pool), errno2msg(op, err)); + exit(1); + } + if (!flag_q) + printf("%s %s %d %d\n", get_name(pool), straddr, req.addr, + op == IP_POOL_ADD_ADDR ? 1 : 0); + return req.addr; +} + +static int do_check(ip_pool_t pool, char *straddr) +{ + struct ip_pool_request req; + int reqlen = sizeof(req); + + req.op = IP_POOL_TEST_ADDR; + req.index = pool; + req.addr = inet_addr(straddr); + if (0 > getsockopt(fd, SOL_IP, SO_IP_POOL, &req, &reqlen)) { + int err = errno; + fprintf(stderr, + "IP_POOL_TEST_ADDR %s in %s failed: %s\n", + straddr, get_name(pool), + errno2msg(IP_POOL_TEST_ADDR, err)); + exit(1); + } + if (!flag_q) + printf("%s %s %d\n", get_name(req.index), straddr, req.addr); + return !req.addr; +} + +static void do_new(ip_pool_t pool, int argc, char **argv) +{ + struct ip_pool_request req; + int reqlen = sizeof(req); + + req.op = IP_POOL_INIT; + req.index = pool; + if (argc >= 2) { + conf_type = IP_POOL_T_BITMAP; + conf_addr = inet_addr(argv[0]); + conf_addr2 = inet_addr(argv[1]); + } + if (conf_type != IP_POOL_T_BITMAP || conf_addr == 0 || conf_addr2 == 0) + usage("bad pool specification"); + req.addr = conf_addr; + req.addr2 = conf_addr2; + if (flag_n) { + printf("ippool -N %s [-T %s] ...\n", get_name(pool), + conf_type == IP_POOL_T_BITMAP + ? "bitmap" + : "???"); + return; + } + if (0 > getsockopt(fd, SOL_IP, SO_IP_POOL, &req, &reqlen)) { + struct in_addr ina; + int err = errno; + ina.s_addr = conf_addr; + fprintf(stderr, + "IP_POOL_INIT %s [%s-", + get_name(pool), inet_ntoa(ina)); + ina.s_addr = conf_addr2; + fprintf(stderr, + "%s] failed: %s\n", + inet_ntoa(ina), errno2msg(IP_POOL_INIT, err)); + exit(1); + } +} + +static void do_new_all(void) +{ + FILE *fp; + char *poolname, *type, *arg, *p; + int res; + + fp = fopen(IPPOOL_CONF, "r"); + if (!fp) { + fprintf(stderr, "cannot open %s - no pool names", IPPOOL_CONF); + exit(1); + } + while (SCAN_EOF != (res=get_index_line(fp, &poolname, &type, &arg))) { + if (poolname && type && (0 == strcmp(type, "bitmap"))) { + conf_type = IP_POOL_T_BITMAP; + p = strtok(arg, " \t"); + if (p) { + conf_addr = inet_addr(p); + p = strtok(0, " \t"); + if (p) + conf_addr2 = inet_addr(p); + else + conf_addr = 0; + } + if (conf_addr != 0) { + if (flag_v) + printf("ippool -N %s (%s) [%s]\n", + poolname, type, arg); + do_new(res, 0, 0); + } + } + } + fclose(fp); +} + +int main(int argc, char **argv) +{ + int opt; + int op; +#define OP_NONE 0 +#define OP_LIST 1 +#define OP_LIST_ALL 2 +#define OP_FLUSH 3 +#define OP_FLUSH_ALL 4 +#define OP_DESTROY 5 +#define OP_DESTROY_ALL 6 +#define OP_ADD 7 +#define OP_DEL 8 +#define OP_CHECK 9 +#define OP_NEW 10 +#define OP_NEW_ALL 11 +#define OP_HIGHEST 12 + char *op_pool; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + fprintf(stderr, "cannot get DGRAM socket: %s\n", + strerror(errno)); + exit(1); + } + op_pool = 0; + op = OP_NONE; + /* GRRR. I thought getopt() would allow an "L*" specifier, for an -L + * taking an optional argument. Does not work. Bad. + * Adding -l for -L without argument, also -f/-F and -x/-X. + */ + while (EOF != (opt=getopt( argc, argv, "HhnvuqA:D:C:N:t:L:F:X:lfxB"))) + switch(opt) { + case 'l': + if (op != OP_NONE) usage("conflicting operations"); + op = OP_LIST_ALL; + break; + case 'L': + if (op != OP_NONE) usage("conflicting operations"); + op = OP_LIST; + op_pool = optarg; + break; + case 'f': + if (op != OP_NONE) usage("conflicting operations"); + op = OP_FLUSH_ALL; + break; + case 'F': + if (op != OP_NONE) usage("conflicting operations"); + op = OP_FLUSH; + op_pool = optarg; + break; + case 'x': + if (op != OP_NONE) usage("conflicting operations"); + op = OP_DESTROY_ALL; + break; + case 'X': + if (op != OP_NONE) usage("conflicting operations"); + op = OP_DESTROY; + op_pool = optarg; + break; + case 'A': + if (op != OP_NONE) usage("conflicting operations"); + op = OP_ADD; + op_pool = optarg; + break; + case 'D': + if (op != OP_NONE) usage("conflicting operations"); + op = OP_DEL; + op_pool = optarg; + break; + case 'C': + if (op != OP_NONE) usage("conflicting operations"); + op = OP_CHECK; + op_pool = optarg; + break; + case 'B': + if (op != OP_NONE) usage("conflicting operations"); + op = OP_NEW_ALL; + break; + case 'N': + if (op != OP_NONE) usage("conflicting operations"); + op = OP_NEW; + op_pool = optarg; + break; + case 'H': + if (op != OP_NONE) usage("conflicting operations"); + op = OP_HIGHEST; + break; + case 't': + flag_t = optarg; + break; + case 'n': + flag_n = 1; + break; + case 'v': + flag_v = 1; + break; + case 'u': + flag_u = 1; + break; + case 'q': + flag_q = 1; + break; + case 'h': + usage(0); + default: + usage("bad option"); + } + if (op == OP_NONE) + usage("no operation specified"); + if (op == OP_LIST_ALL) { + do_list_all(); + return 0; + } + if (op == OP_LIST) { + do_list(get_index(op_pool)); + return 0; + } + if (op == OP_FLUSH_ALL) { + do_flush_all(); + return 0; + } + if (op == OP_FLUSH) { + do_flush(get_index(op_pool)); + return 0; + } + if (op == OP_DESTROY_ALL) { + do_destroy_all(); + return 0; + } + if (op == OP_DESTROY) { + do_destroy(get_index(op_pool)); + return 0; + } + if (op == OP_CHECK) { + if (optind >= argc) + usage("missing address to check"); + return do_check(get_index(op_pool), argv[optind]); + } + if (op == OP_NEW_ALL) { + do_new_all(); + return 0; + } + if (op == OP_NEW) { + do_new(get_index(op_pool), argc-optind, argv+optind); + return 0; + } + if (op == OP_ADD) { + if (optind >= argc) + usage("missing address to add"); + return do_adddel(get_index(op_pool), + argv[optind], IP_POOL_ADD_ADDR); + } + if (op == OP_DEL) { + if (optind >= argc) + usage("missing address to delete"); + return do_adddel(get_index(op_pool), + argv[optind], IP_POOL_DEL_ADDR); + } + if (op == OP_HIGHEST) { + printf("%d\n", high_nr()); + return 0; + } + usage("no operation specified"); + return 0; +} diff --git a/ippool/libippool.c b/ippool/libippool.c new file mode 100644 index 0000000..7f3ac76 --- /dev/null +++ b/ippool/libippool.c @@ -0,0 +1,72 @@ +/* support functions for ip_pool modules */ + +#include +#include +#include +#include + +#include + +void ip_pool_init(void) +{ +} + +ip_pool_t ip_pool_get_index(char *name) +{ + FILE *fp; + char buf[256]; + + if (isdigit(*name)) + return atoi(name); + fp = fopen(IPPOOL_CONF, "r"); + if (!fp) exit_error(PARAMETER_PROBLEM, + "cannot open %s - no pool names", IPPOOL_CONF); + while (fgets(buf, sizeof(buf), fp)) { + char *p = strtok(buf, " \t\n"); + ip_pool_t index; + + if (!p || *p == '#') continue; + index = atoi(p); + p = strtok(0, " \t\n"); + if (p && 0 == strcmp(p, name)) { + fclose(fp); + return index; + } + } + exit_error(PARAMETER_PROBLEM, + "pool '%s' not found in %s\n", name, IPPOOL_CONF); +} + +char *ip_pool_get_name(char *buf, int size, ip_pool_t index, int numeric) +{ + FILE *fp; + int ok = 0; + + /* make sure we have enough room, at least for a %d */ + if (size < 16) + exit_error(PARAMETER_PROBLEM, + "ip_pool_support:get_name buf too small (%d vs. 16)\n", + size); + if (numeric) + goto do_numeric; + fp = fopen(IPPOOL_CONF, "r"); + if (fp) { + while (fgets(buf, size, fp)) { + char *p = strtok(buf, " \t\n"); + + if (!p || *p == '#') continue; + if (index != atoi(p)) continue; + p = strtok(0, " \t\n"); + if (!p || *p == '#') continue; + memmove(buf, p, strlen(p)+1); + ok = 1; + break; + } + fclose(fp); + } + if (!ok) { +do_numeric: + sprintf(buf, "%d", index); + } + return buf; +} -- cgit v1.2.3