From 8e0608d31d988333ff04f3faaa6e851c0ecdbc6e Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Thu, 22 Apr 2010 16:52:29 +0200 Subject: Fourth stage to ipset-5 Add new userspace files: include/, lib/ and plus new files in src/. --- lib/data.c | 505 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 505 insertions(+) create mode 100644 lib/data.c (limited to 'lib/data.c') diff --git a/lib/data.c b/lib/data.c new file mode 100644 index 0000000..0de91a1 --- /dev/null +++ b/lib/data.c @@ -0,0 +1,505 @@ +/* Copyright 2007-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include /* assert */ +#include /* ntoh* */ +#include /* ETH_ALEN */ +#include /* AF_ */ +#include /* malloc, free */ +#include /* memset */ + +#include /* IPSET_MAXNAMELEN */ +#include /* struct ipset_type */ +#include /* inXcpy */ +#include /* prototypes */ + +/* Internal data structure to hold + * a) input data entered by the user or + * b) data received from kernel + * + * We always store the data in host order, *except* IP addresses. + */ + +struct ipset_data { + /* Option bits: which fields are set */ + uint64_t bits; + /* Setname */ + char setname[IPSET_MAXNAMELEN]; + const struct ipset_type *type; + /* Common CADT options */ + uint8_t cidr; + uint8_t family; + uint32_t flags; + uint32_t timeout; + union nf_inet_addr ip; + union nf_inet_addr ip_to; + uint16_t port; + uint16_t port_to; + union { + /* RENAME/SWAP */ + char setname2[IPSET_MAXNAMELEN]; + /* CREATE/LIST/SAVE */ + struct { + uint8_t probes; + uint8_t resize; + uint8_t netmask; + uint32_t hashsize; + uint32_t maxelem; + uint32_t gc; + uint32_t size; + /* Filled out by kernel */ + uint32_t references; + uint32_t elements; + uint32_t memsize; + char typename[IPSET_MAXNAMELEN]; + uint8_t revision_min; + uint8_t revision; + } create; + /* ADT/LIST/SAVE */ + struct { + union nf_inet_addr ip2; + uint8_t cidr2; + char ether[ETH_ALEN]; + char name[IPSET_MAXNAMELEN]; + char nameref[IPSET_MAXNAMELEN]; + } adt; + } u; +}; + +static void +copy_addr(uint8_t family, union nf_inet_addr *ip, const void *value) +{ + if (family == AF_INET) + in4cpy(&ip->in, (const struct in_addr *)value); + else + in6cpy(&ip->in6, (const struct in6_addr *)value); +} + +/** + * ipset_data_flags_test - test option bits in the data blob + * @data: data blob + * @flags: the option flags to test + * + * Returns true if the options are already set in the data blob. + */ +bool +ipset_data_flags_test(const struct ipset_data *data, uint64_t flags) +{ + assert(data); + return !!(data->bits & flags); +} + +/** + * ipset_data_flags_set - set option bits in the data blob + * @data: data blob + * @flags: the option flags to set + * + * The function sets the flags in the data blob so that + * the corresponding fields are regarded as if filled with proper data. + */ +void +ipset_data_flags_set(struct ipset_data *data, uint64_t flags) +{ + assert(data); + data->bits |= flags; +} + +/** + * ipset_data_flags_unset - unset option bits in the data blob + * @data: data blob + * @flags: the option flags to unset + * + * The function unsets the flags in the data blob. + * This is the quick way to clear specific fields. + */ +void +ipset_data_flags_unset(struct ipset_data *data, uint64_t flags) +{ + assert(data); + data->bits &= ~flags; +} + +#define flag_type_attr(data, opt, flag) \ +do { \ + data->flags |= (1 << flag); \ + opt = IPSET_OPT_FLAGS; \ +} while (0) + +/** + * ipset_data_set - put data into the data blob + * @data: data blob + * @opt: the option kind of the data + * @value: the value of the data + * + * Put a given kind of data into the data blob and mark the + * option kind as already set in the blob. + * + * Returns 0 on success or a negative error code. + */ +int +ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value) +{ + assert(data); + assert(opt != IPSET_OPT_NONE); + assert(value); + + switch (opt) { + /* Common ones */ + case IPSET_SETNAME: + ipset_strncpy(data->setname, value, IPSET_MAXNAMELEN); + break; + case IPSET_OPT_TYPE: + data->type = value; + break; + case IPSET_OPT_FAMILY: + data->family = *(const uint8_t *) value; + break; + /* CADT options */ + case IPSET_OPT_IP: + if (!(data->family == AF_INET || data->family == AF_INET6)) + return -1; + copy_addr(data->family, &data->ip, value); + break; + case IPSET_OPT_IP_TO: + if (!(data->family == AF_INET || data->family == AF_INET6)) + return -1; + copy_addr(data->family, &data->ip_to, value); + break; + case IPSET_OPT_CIDR: + data->cidr = *(const uint8_t *) value; + break; + case IPSET_OPT_PORT: + data->port = *(const uint16_t *) value; + break; + case IPSET_OPT_PORT_TO: + data->port_to = *(const uint16_t *) value; + break; + case IPSET_OPT_TIMEOUT: + data->timeout = *(const uint32_t *) value; + break; + /* Create-specific options */ + case IPSET_OPT_GC: + data->u.create.gc = *(const uint32_t *) value; + break; + case IPSET_OPT_HASHSIZE: + data->u.create.hashsize = *(const uint32_t *) value; + break; + case IPSET_OPT_MAXELEM: + data->u.create.maxelem = *(const uint32_t *) value; + break; + case IPSET_OPT_NETMASK: + data->u.create.netmask = *(const uint8_t *) value; + break; + case IPSET_OPT_PROBES: + data->u.create.probes = *(const uint8_t *) value; + break; + case IPSET_OPT_RESIZE: + data->u.create.resize = *(const uint8_t *) value; + break; + case IPSET_OPT_SIZE: + data->u.create.size = *(const uint32_t *) value; + break; + /* Create-specific options, filled out by the kernel */ + case IPSET_OPT_ELEMENTS: + data->u.create.elements = *(const uint32_t *) value; + break; + case IPSET_OPT_REFERENCES: + data->u.create.references = *(const uint32_t *) value; + break; + case IPSET_OPT_MEMSIZE: + data->u.create.memsize = *(const uint32_t *) value; + break; + /* Create-specific options, type */ + case IPSET_OPT_TYPENAME: + ipset_strncpy(data->u.create.typename, value, IPSET_MAXNAMELEN); + break; + case IPSET_OPT_REVISION: + data->u.create.revision = *(const uint8_t *) value; + break; + case IPSET_OPT_REVISION_MIN: + data->u.create.revision_min = *(const uint8_t *) value; + break; + /* ADT-specific options */ + case IPSET_OPT_ETHER: + memcpy(data->u.adt.ether, value, ETH_ALEN); + break; + case IPSET_OPT_NAME: + ipset_strncpy(data->u.adt.name, value, IPSET_MAXNAMELEN); + break; + case IPSET_OPT_NAMEREF: + ipset_strncpy(data->u.adt.nameref, value, IPSET_MAXNAMELEN); + break; + case IPSET_OPT_IP2: + if (!(data->family == AF_INET || data->family == AF_INET6)) + return -1; + copy_addr(data->family, &data->u.adt.ip2, value); + break; + case IPSET_OPT_CIDR2: + data->u.adt.cidr2 = *(const uint8_t *) value; + break; + /* Swap/rename */ + case IPSET_OPT_SETNAME2: + ipset_strncpy(data->u.setname2, value, IPSET_MAXNAMELEN); + break; + /* flags */ + case IPSET_OPT_EXIST: + flag_type_attr(data, opt, IPSET_FLAG_EXIST); + break; + case IPSET_OPT_BEFORE: + flag_type_attr(data, opt, IPSET_FLAG_BEFORE); + break; + case IPSET_OPT_FLAGS: + data->flags = *(const uint32_t *)value; + break; + default: + return -1; + }; + + ipset_data_flags_set(data, IPSET_FLAG(opt)); + return 0; +} + +/** + * ipset_data_get - get data from the data blob + * @data: data blob + * @opt: option kind of the requested data + * + * Returns the pointer to the requested kind of data from the data blob + * if it is set. If the option kind is not set or is an unkown type, + * NULL is returned. + */ +const void * +ipset_data_get(const struct ipset_data *data, enum ipset_opt opt) +{ + assert(data); + assert(opt != IPSET_OPT_NONE); + + if (opt != IPSET_OPT_TYPENAME && !ipset_data_test(data, opt)) + return NULL; + + switch (opt) { + /* Common ones */ + case IPSET_SETNAME: + return data->setname; + case IPSET_OPT_TYPE: + return data->type; + case IPSET_OPT_TYPENAME: + if (ipset_data_test(data, IPSET_OPT_TYPE)) + return data->type->name; + else if (ipset_data_test(data, IPSET_OPT_TYPENAME)) + return data->u.create.typename; + return NULL; + case IPSET_OPT_FAMILY: + return &data->family; + /* CADT options */ + case IPSET_OPT_IP: + return &data->ip; + case IPSET_OPT_IP_TO: + return &data->ip_to; + case IPSET_OPT_CIDR: + return &data->cidr; + case IPSET_OPT_PORT: + return &data->port; + case IPSET_OPT_PORT_TO: + return &data->port_to; + case IPSET_OPT_TIMEOUT: + return &data->timeout; + /* Create-specific options */ + case IPSET_OPT_GC: + return &data->u.create.gc; + case IPSET_OPT_HASHSIZE: + return &data->u.create.hashsize; + case IPSET_OPT_MAXELEM: + return &data->u.create.maxelem; + case IPSET_OPT_NETMASK: + return &data->u.create.netmask; + case IPSET_OPT_PROBES: + return &data->u.create.probes; + case IPSET_OPT_RESIZE: + return &data->u.create.resize; + case IPSET_OPT_SIZE: + return &data->u.create.size; + /* Create-specific options, filled out by the kernel */ + case IPSET_OPT_ELEMENTS: + return &data->u.create.elements; + case IPSET_OPT_REFERENCES: + return &data->u.create.references; + case IPSET_OPT_MEMSIZE: + return &data->u.create.memsize; + /* Create-specific options, TYPE */ + case IPSET_OPT_REVISION: + return &data->u.create.revision; + case IPSET_OPT_REVISION_MIN: + return &data->u.create.revision_min; + /* ADT-specific options */ + case IPSET_OPT_ETHER: + return data->u.adt.ether; + case IPSET_OPT_NAME: + return data->u.adt.name; + case IPSET_OPT_NAMEREF: + return data->u.adt.nameref; + case IPSET_OPT_IP2: + return &data->u.adt.ip2; + case IPSET_OPT_CIDR2: + return &data->u.adt.cidr2; + /* Swap/rename */ + case IPSET_OPT_SETNAME2: + return data->u.setname2; + /* flags */ + case IPSET_OPT_FLAGS: + case IPSET_OPT_EXIST: + case IPSET_OPT_BEFORE: + return &data->flags; + default: + return NULL; + } +} + +/** + * ipset_data_sizeof - calculates the size for the type of data + * @opt: option kind of the data + * @family: INET family + * + * Returns the size required to store the given option kind. + */ +size_t +ipset_data_sizeof(enum ipset_opt opt, uint8_t family) +{ + assert(opt != IPSET_OPT_NONE); + + switch (opt) { + case IPSET_OPT_IP: + case IPSET_OPT_IP_TO: + case IPSET_OPT_IP2: + return family == AF_INET ? sizeof(uint32_t) + : sizeof(struct in6_addr); + case IPSET_OPT_PORT: + case IPSET_OPT_PORT_TO: + return sizeof(uint16_t); + case IPSET_SETNAME: + case IPSET_OPT_NAME: + case IPSET_OPT_NAMEREF: + return IPSET_MAXNAMELEN; + case IPSET_OPT_TIMEOUT: + case IPSET_OPT_GC: + case IPSET_OPT_HASHSIZE: + case IPSET_OPT_MAXELEM: + case IPSET_OPT_SIZE: + case IPSET_OPT_ELEMENTS: + case IPSET_OPT_REFERENCES: + case IPSET_OPT_MEMSIZE: + return sizeof(uint32_t); + case IPSET_OPT_CIDR: + case IPSET_OPT_CIDR2: + case IPSET_OPT_NETMASK: + case IPSET_OPT_PROBES: + case IPSET_OPT_RESIZE: + return sizeof(uint8_t); + case IPSET_OPT_ETHER: + return ETH_ALEN; + /* Flags counted once */ + case IPSET_OPT_BEFORE: + return sizeof(uint32_t); + default: + return 0; + }; +} + +/** + * ipset_setname - return the name of the set from the data blob + * @data: data blob + * + * Return the name of the set from the data blob or NULL if the + * name not set yet. + */ +const char * +ipset_data_setname(const struct ipset_data *data) +{ + assert(data); + return ipset_data_test(data, IPSET_SETNAME) ? data->setname : NULL; +} + +/** + * ipset_family - return the INET family of the set from the data blob + * @data: data blob + * + * Return the INET family supported by the set from the data blob. + * If the family is not set yet, AF_UNSPEC is returned. + */ +uint8_t +ipset_data_family(const struct ipset_data *data) +{ + assert(data); + return ipset_data_test(data, IPSET_OPT_FAMILY) + ? data->family : AF_UNSPEC; +} + +/** + * ipset_data_cidr - return the value of IPSET_OPT_CIDR + * @data: data blob + * + * Return the value of IPSET_OPT_CIDR stored in the data blob. + * If it is not set, the the returned value corresponds to + * the default one according to the family type or zero. + */ +uint8_t +ipset_data_cidr(const struct ipset_data *data) +{ + assert(data); + return ipset_data_test(data, IPSET_OPT_CIDR) ? data->cidr : + data->family == AF_INET ? 32 : + data->family == AF_INET6 ? 128 : 0; +} + +/** + * ipset_flags - return which fields are set in the data blob + * @data: data blob + * + * Returns the value of the bit field which elements are set. + */ +uint64_t +ipset_data_flags(const struct ipset_data *data) +{ + assert(data); + return data->bits; +} + +/** + * ipset_data_reset - reset the data blob to unset + * @data: data blob + * + * Resets the data blob to the unset state for every field. + */ +void +ipset_data_reset(struct ipset_data *data) +{ + assert(data); + memset(data, 0, sizeof(*data)); +} + +/** + * ipset_data_init - create a new data blob + * + * Return the new data blob initialized to empty. In case of + * an error, NULL is retured. + */ +struct ipset_data * +ipset_data_init(void) +{ + return calloc(1, sizeof(struct ipset_data)); +} + +/** + * ipset_data_fini - release a data blob created by ipset_data_init + * + * Release the data blob created by ipset_data_init previously. + */ +void +ipset_data_fini(struct ipset_data *data) +{ + assert(data); + free(data); +} -- cgit v1.2.3