From 6510a98f4139f112a0c76c71ff889ef93eac41fb Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 6 Nov 2012 17:06:39 +0100 Subject: api: add connlabel api and attribute adds new labelmap api to create a name <-> bit mapping from a text file (default: /etc/xtables/connlabel.conf). nfct_labelmap_new(filename) is used to create the map, nfct_labelmap_destroy() releases the resources allocated for the map. Two functions are added to make map lookups: nfct_labelmap_get_name(map, bit) returns the name of a bit, nfct_labelmap_get_bit returns the bit associated with a name. The connlabel attribute is represented by a nfct_bitmask object, the nfct_bitmask api can be used to test/set/get individual bits ("labels"). The exisiting nfct_attr_get/set interfaces can be used to read or replace the existing labels associated with a conntrack with a new set. Signed-off-by: Florian Westphal --- src/conntrack/labels.c | 243 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 src/conntrack/labels.c (limited to 'src/conntrack/labels.c') diff --git a/src/conntrack/labels.c b/src/conntrack/labels.c new file mode 100644 index 0000000..f7a2742 --- /dev/null +++ b/src/conntrack/labels.c @@ -0,0 +1,243 @@ +#include + +#include "internal/internal.h" + +#define MAX_BITS 1024 + +#define CONNLABEL_CFG "/etc/xtables/connlabel.conf" +#define HASH_SIZE 64 + +struct labelmap_bucket { + char *name; + unsigned int bit; + struct labelmap_bucket *next; +}; + +struct nfct_labelmap { + struct labelmap_bucket *map_name[HASH_SIZE]; + unsigned int namecount; + char **bit_to_name; +}; + +static struct labelmap_bucket* label_map_bucket_alloc(const char *n, unsigned int b) +{ + struct labelmap_bucket *bucket; + char *name = strdup(n); + + if (!name) + return NULL; + + bucket = malloc(sizeof(*bucket)); + if (!bucket) { + free(name); + return NULL; + } + bucket->name = name; + bucket->bit = b; + return bucket; +} + +static unsigned int hash_name(const char *name) +{ + unsigned int hash = 0; + + while (*name) { + hash = (hash << 5) - hash + *name; + name++; + } + return hash & (HASH_SIZE - 1); +} + +int __labelmap_get_bit(struct nfct_labelmap *m, const char *name) +{ + unsigned int i = hash_name(name); + struct labelmap_bucket *list = m->map_name[i]; + + while (list) { + if (strcmp(name, list->name) == 0) + return list->bit; + list = list->next; + } + return -1; +} + +const char *__labelmap_get_name(struct nfct_labelmap *m, unsigned int bit) +{ + if (bit < m->namecount) + return m->bit_to_name[bit] ? m->bit_to_name[bit] : ""; + return NULL; +} + +static int map_insert(struct nfct_labelmap *m, const char *n, unsigned int b) +{ + unsigned int i = hash_name(n); + struct labelmap_bucket *list = m->map_name[i]; + + while (list) { + if (strcmp(list->name, n) == 0) + return -1; + list = list->next; + } + + list = label_map_bucket_alloc(n, b); + if (!list) + return -1; + + if (m->map_name[i]) + list->next = m->map_name[i]; + else + list->next = NULL; + m->map_name[i] = list; + return 0; +} + +static int is_space_posix(int c) +{ + return c == ' ' || c == '\f' || c == '\r' || c == '\t' || c == '\v'; +} + +static char *trim_label(char *label) +{ + char *end; + + while (is_space_posix(*label)) + label++; + end = strchr(label, '\n'); + if (end) + *end = 0; + else + end = strchr(label, '\0'); + end--; + + while (is_space_posix(*end) && end > label) { + *end = 0; + end--; + } + + return *label ? label : NULL; +} + +static int +xtables_parse_connlabel_numerical(const char *s, char **end) +{ + unsigned long value; + + value = strtoul(s, end, 0); + if (value == 0 && s == *end) + return -1; + if (value < 0 || value >= MAX_BITS) + return -1; + return value; +} + +static void free_list(struct labelmap_bucket *b) +{ + struct labelmap_bucket *tmp; + + while (b) { + free(b->name); + + tmp = b; + b = b->next; + + free(tmp); + } +} + +void __labelmap_destroy(struct nfct_labelmap *map) +{ + unsigned int i; + struct labelmap_bucket *b; + + for (i = 0; i < HASH_SIZE; i++) { + b = map->map_name[i]; + free_list(b); + } + + free(map->bit_to_name); + free(map); +} + +static void make_name_table(struct nfct_labelmap *m) +{ + struct labelmap_bucket *b; + unsigned int i; + + for (i = 0; i < HASH_SIZE; i++) { + b = m->map_name[i]; + while (b) { + m->bit_to_name[b->bit] = b->name; + b = b->next; + } + } +} + +static struct nfct_labelmap *map_alloc(void) +{ + struct nfct_labelmap *map = malloc(sizeof(*map)); + if (map) { + unsigned int i; + for (i = 0; i < HASH_SIZE; i++) + map->map_name[i] = NULL; + } + map->bit_to_name = NULL; + return map; +} + +struct nfct_labelmap *__labelmap_new(const char *name) +{ + struct nfct_labelmap *map; + char label[1024]; + char *end; + FILE *fp; + int added = 0; + unsigned int maxbit = 0; + uint32_t bits_seen[MAX_BITS/32]; + + fp = fopen(name ? name : CONNLABEL_CFG, "re"); + if (!fp) + return NULL; + + memset(bits_seen, 0, sizeof(bits_seen)); + + map = map_alloc(); + if (!map) { + fclose(fp); + return NULL; + } + + while (fgets(label, sizeof(label), fp)) { + int bit; + + if (label[0] == '#') + continue; + + bit = xtables_parse_connlabel_numerical(label, &end); + if (bit < 0 || test_bit(bit, bits_seen)) + continue; + + end = trim_label(end); + if (!end) + continue; + if (map_insert(map, end, bit) == 0) { + added++; + if (maxbit < bit) + maxbit = bit; + set_bit(bit, bits_seen); + } + } + + fclose(fp); + + if (added) { + map->namecount = maxbit + 1; + map->bit_to_name = calloc(sizeof(char *), map->namecount); + if (!map->bit_to_name) + goto err; + make_name_table(map); + return map; + } + err: + __labelmap_destroy(map); + return NULL; +} -- cgit v1.2.3