diff options
Diffstat (limited to 'accel-pppd/extra/ippool.c')
-rw-r--r-- | accel-pppd/extra/ippool.c | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/accel-pppd/extra/ippool.c b/accel-pppd/extra/ippool.c new file mode 100644 index 00000000..6136a14d --- /dev/null +++ b/accel-pppd/extra/ippool.c @@ -0,0 +1,208 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <arpa/inet.h> + +#include "ipdb.h" +#include "list.h" +#include "spinlock.h" + +#include "memdebug.h" + +struct ippool_item_t +{ + struct list_head entry; + struct ipdb_item_t it; +}; + +struct ipaddr_t +{ + struct list_head entry; + in_addr_t addr; +}; + +static LIST_HEAD(gw_list); +static LIST_HEAD(tunnel_list); +static LIST_HEAD(ippool); +static spinlock_t pool_lock = SPINLOCK_INITIALIZER; +static struct ipdb_t ipdb; + +static in_addr_t conf_gw_ip_address; +static int cnt; + +static void parse_gw_ip_address(const char *val) +{ + if (!val) + return; + + conf_gw_ip_address = inet_addr(val); +} + +//parses ranges like x.x.x.x/mask +static int parse1(const char *str, uint32_t *begin, uint32_t *end) +{ + int n, f1, f2, f3, f4, m, mask = 0; + + n = sscanf(str, "%u.%u.%u.%u/%u",&f1, &f2, &f3, &f4, &m); + if (n != 5) + return -1; + if (f1 > 255) + return -1; + if (f2 > 255) + return -1; + if (f3 > 255) + return -1; + if (f4 > 255) + return -1; + if (m == 0 || m > 32) + return -1; + + for (n = 0; n < m ; n++) + mask |= 1 << n; + + *begin = (f4 << 24) | (f3 << 16) | (f2 << 8) | f1; + *end = *begin | ~mask; + + return 0; +} + +//parses ranges like x.x.x.x-y +static int parse2(const char *str, uint32_t *begin, uint32_t *end) +{ + int n, f1, f2, f3, f4, m; + + n = sscanf(str, "%u.%u.%u.%u-%u",&f1, &f2, &f3, &f4, &m); + if (n != 5) + return -1; + if (f1 > 255) + return -1; + if (f2 > 255) + return -1; + if (f3 > 255) + return -1; + if (f4 > 255) + return -1; + if (m < f4 || m > 255) + return -1; + + *begin = (f4 << 24) | (f3 << 16) | (f2 << 8) | f1; + *end = (m << 24) | (f3 << 16) | (f2 << 8) | f1; + + return 0; +} + +static void add_range(struct list_head *list, const char *name) +{ + uint32_t i,startip, endip; + struct ipaddr_t *ip; + + if (parse1(name, &startip, &endip)) + if (parse2(name, &startip, &endip)) { + fprintf(stderr, "ippool: cann't parse '%s'\n", name); + _exit(EXIT_FAILURE); + } + + for (i = ntohl(startip); i <= ntohl(endip); i++) { + ip = malloc(sizeof(*ip)); + ip->addr = htonl(i); + list_add_tail(&ip->entry, list); + cnt++; + } +} + +static void generate_pool(void) +{ + struct ippool_item_t *it; + struct ipaddr_t *addr = NULL; + struct ipaddr_t *peer_addr; + + while (1) { + if (list_empty(&tunnel_list)) + break; + else { + peer_addr = list_entry(tunnel_list.next, typeof(*peer_addr), entry); + list_del(&peer_addr->entry); + } + + if (!conf_gw_ip_address) { + if (list_empty(&gw_list)) + break; + else { + addr = list_entry(gw_list.next, typeof(*addr), entry); + list_del(&addr->entry); + } + } + + it = malloc(sizeof(*it)); + if (!it) { + fprintf(stderr, "ippool: out of memory\n"); + break; + } + + it->it.owner = &ipdb; + if (conf_gw_ip_address) + it->it.addr = conf_gw_ip_address; + else + it->it.addr = addr->addr; + + it->it.peer_addr = peer_addr->addr; + + list_add_tail(&it->entry, &ippool); + } +} + +static struct ipdb_item_t *get_ip(struct ppp_t *ppp) +{ + struct ippool_item_t *it; + + spin_lock(&pool_lock); + if (!list_empty(&ippool)) { + it = list_entry(ippool.next, typeof(*it), entry); + list_del(&it->entry); + } else + it = NULL; + spin_unlock(&pool_lock); + + return it ? &it->it : NULL; +} + +static void put_ip(struct ppp_t *ppp, struct ipdb_item_t *it) +{ + struct ippool_item_t *pit = container_of(it, typeof(*pit), it); + + spin_lock(&pool_lock); + list_add_tail(&pit->entry, &ippool); + spin_unlock(&pool_lock); +} + +static struct ipdb_t ipdb = { + .get = get_ip, + .put = put_ip, +}; + +static void __init ipool_init(void) +{ + struct conf_sect_t *s = conf_get_section("ip-pool"); + struct conf_option_t *opt; + + if (!s) + return; + + list_for_each_entry(opt, &s->items, entry) { + if (!strcmp(opt->name, "gw-ip-address")) + parse_gw_ip_address(opt->val); + else if (!strcmp(opt->name, "gw")) + add_range(&gw_list, opt->val); + else if (!strcmp(opt->name, "tunnel")) + add_range(&tunnel_list, opt->val); + else if (!opt->val) + add_range(&tunnel_list, opt->name); + } + + generate_pool(); + + ipdb_register(&ipdb); +} + |