]> granicus.if.org Git - ipset/commitdiff
ipset: Support comments in the userspace library.
authorOliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>
Sun, 22 Sep 2013 18:56:35 +0000 (20:56 +0200)
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Mon, 23 Sep 2013 12:03:58 +0000 (14:03 +0200)
This adds support to the userspace portion of ipset for handling ipsets
with the comment extension enabled. The library revision has been raised
accordingly.

Signed-off-by: Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
14 files changed:
Make_global.am
include/libipset/data.h
include/libipset/linux_ip_set.h
include/libipset/parse.h
include/libipset/print.h
kernel/include/uapi/linux/netfilter/ipset/ip_set.h
lib/data.c
lib/debug.c
lib/errcode.c
lib/libipset.map
lib/parse.c
lib/print.c
lib/session.c
lib/types.c

index 29b56789fe1afa7aa637f27894fa3c34a4805076..9c228cccce750cd210ca7fde78e15311f6d4045b 100644 (file)
@@ -69,7 +69,7 @@
 # interface. 
 
 #            curr:rev:age
-LIBVERSION = 4:0:1
+LIBVERSION = 4:1:2
 
 AM_CPPFLAGS = $(kinclude_CFLAGS) $(all_includes) -I$(top_srcdir)/include \
        -I/usr/local/include
index 2b6b8cdf0f84f604228478292bc78044011046c3..b6e75e8d57634ba37ff541877555ae020161b18e 100644 (file)
@@ -57,6 +57,8 @@ enum ipset_opt {
        IPSET_OPT_COUNTERS,
        IPSET_OPT_PACKETS,
        IPSET_OPT_BYTES,
+       IPSET_OPT_CREATE_COMMENT,
+       IPSET_OPT_ADT_COMMENT,
        /* Internal options */
        IPSET_OPT_FLAGS = 48,   /* IPSET_FLAG_EXIST| */
        IPSET_OPT_CADT_FLAGS,   /* IPSET_FLAG_BEFORE| */
@@ -87,7 +89,8 @@ enum ipset_opt {
        | IPSET_FLAG(IPSET_OPT_NETMASK) \
        | IPSET_FLAG(IPSET_OPT_PROBES)  \
        | IPSET_FLAG(IPSET_OPT_RESIZE)  \
-       | IPSET_FLAG(IPSET_OPT_SIZE))
+       | IPSET_FLAG(IPSET_OPT_SIZE)    \
+       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT))
 
 #define IPSET_ADT_FLAGS                        \
        (IPSET_FLAG(IPSET_OPT_IP)       \
@@ -106,11 +109,13 @@ enum ipset_opt {
        | IPSET_FLAG(IPSET_OPT_CADT_FLAGS)\
        | IPSET_FLAG(IPSET_OPT_BEFORE) \
        | IPSET_FLAG(IPSET_OPT_PHYSDEV) \
-       | IPSET_FLAG(IPSET_OPT_NOMATCH))
+       | IPSET_FLAG(IPSET_OPT_NOMATCH) \
+       | IPSET_FLAG(IPSET_OPT_ADT_COMMENT))
 
 struct ipset_data;
 
 extern void ipset_strlcpy(char *dst, const char *src, size_t len);
+extern void ipset_strlcat(char *dst, const char *src, size_t len);
 extern bool ipset_data_flags_test(const struct ipset_data *data,
                                  uint64_t flags);
 extern void ipset_data_flags_set(struct ipset_data *data, uint64_t flags);
index 8024cdf13b700560e9bd0c1f3df1bacbdd90b900..847bbfff437137d447aa6be3c9ae27af904d9ee2 100644 (file)
@@ -19,6 +19,9 @@
 /* The max length of strings including NUL: set and type identifiers */
 #define IPSET_MAXNAMELEN       32
 
+/* The maximum permissible length we will accept over netlink (inc. comments) */
+#define IPSET_MAX_COMMENT_SIZE 255
+
 /* Message types and commands */
 enum ipset_cmd {
        IPSET_CMD_NONE,
@@ -110,6 +113,7 @@ enum {
        IPSET_ATTR_IFACE,
        IPSET_ATTR_BYTES,
        IPSET_ATTR_PACKETS,
+       IPSET_ATTR_COMMENT,
        __IPSET_ATTR_ADT_MAX,
 };
 #define IPSET_ATTR_ADT_MAX     (__IPSET_ATTR_ADT_MAX - 1)
@@ -140,6 +144,7 @@ enum ipset_errno {
        IPSET_ERR_IPADDR_IPV4,
        IPSET_ERR_IPADDR_IPV6,
        IPSET_ERR_COUNTER,
+       IPSET_ERR_COMMENT,
 
        /* Type specific error codes */
        IPSET_ERR_TYPE_SPECIFIC = 4352,
@@ -176,6 +181,8 @@ enum ipset_cadt_flags {
        IPSET_FLAG_NOMATCH      = (1 << IPSET_FLAG_BIT_NOMATCH),
        IPSET_FLAG_BIT_WITH_COUNTERS = 3,
        IPSET_FLAG_WITH_COUNTERS = (1 << IPSET_FLAG_BIT_WITH_COUNTERS),
+       IPSET_FLAG_BIT_WITH_COMMENT = 4,
+       IPSET_FLAG_WITH_COMMENT = (1 << IPSET_FLAG_BIT_WITH_COMMENT),
        IPSET_FLAG_CADT_MAX     = 15,
 };
 
@@ -250,6 +257,14 @@ struct ip_set_req_get_set {
 #define IP_SET_OP_GET_BYINDEX  0x00000007      /* Get set name by index */
 /* Uses ip_set_req_get_set */
 
+#define IP_SET_OP_GET_FNAME    0x00000008      /* Get set index and family */
+struct ip_set_req_get_set_family {
+       unsigned int op;
+       unsigned int version;
+       unsigned int family;
+       union ip_set_name_index set;
+};
+
 #define IP_SET_OP_VERSION      0x00000100      /* Ask kernel version */
 struct ip_set_req_version {
        unsigned int op;
index 014c62f706015ec9e9eda8c489926f237aff440c..5c46a885b786493ed325a4fb46f9ea53774025f3 100644 (file)
@@ -90,6 +90,8 @@ extern int ipset_parse_typename(struct ipset_session *session,
                                enum ipset_opt opt, const char *str);
 extern int ipset_parse_iface(struct ipset_session *session,
                             enum ipset_opt opt, const char *str);
+extern int ipset_parse_comment(struct ipset_session *session,
+                            enum ipset_opt opt, const char *str);
 extern int ipset_parse_output(struct ipset_session *session,
                              int opt, const char *str);
 extern int ipset_parse_ignored(struct ipset_session *session,
index 1d537bd0c6592fb4518655556bd164672543ed0d..f2a6095a456cadb27ade9e3edf5acf23161d03eb 100644 (file)
@@ -40,6 +40,9 @@ extern int ipset_print_port(char *buf, unsigned int len,
 extern int ipset_print_iface(char *buf, unsigned int len,
                             const struct ipset_data *data,
                             enum ipset_opt opt, uint8_t env);
+extern int ipset_print_comment(char *buf, unsigned int len,
+                            const struct ipset_data *data,
+                            enum ipset_opt opt, uint8_t env);
 extern int ipset_print_proto(char *buf, unsigned int len,
                             const struct ipset_data *data,
                             enum ipset_opt opt, uint8_t env);
index f177d99d86ad5eda21cd29a571a009d1ab9ce92b..847bbfff437137d447aa6be3c9ae27af904d9ee2 100644 (file)
@@ -19,6 +19,9 @@
 /* The max length of strings including NUL: set and type identifiers */
 #define IPSET_MAXNAMELEN       32
 
+/* The maximum permissible length we will accept over netlink (inc. comments) */
+#define IPSET_MAX_COMMENT_SIZE 255
+
 /* Message types and commands */
 enum ipset_cmd {
        IPSET_CMD_NONE,
index 04a5997f35e3e00bb908501ba04c0b021c796074..ba4ed57ca735e313c2bdbd06a954e5075994a5dc 100644 (file)
@@ -75,6 +75,7 @@ struct ipset_data {
                        char iface[IFNAMSIZ];
                        uint64_t packets;
                        uint64_t bytes;
+                       char comment[IPSET_MAX_COMMENT_SIZE+1];
                } adt;
        };
 };
@@ -107,6 +108,25 @@ ipset_strlcpy(char *dst, const char *src, size_t len)
        dst[len - 1] = '\0';
 }
 
+/**
+ * ipset_strlcat - concatenate the string from src to the end of dst
+ * @dst: the target string buffer
+ * @src: the source string buffer
+ * @len: the length of bytes to concat, including the terminating null byte.
+ *
+ * Cooncatenate the string in src to destination, but at most len bytes are
+ * copied. The target is unconditionally terminated by the null byte.
+ */
+void
+ipset_strlcat(char *dst, const char *src, size_t len)
+{
+       assert(dst);
+       assert(src);
+
+       strncat(dst, src, len);
+       dst[len - 1] = '\0';
+}
+
 /**
  * ipset_data_flags_test - test option bits in the data blob
  * @data: data blob
@@ -278,6 +298,9 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
        case IPSET_OPT_COUNTERS:
                cadt_flag_type_attr(data, opt, IPSET_FLAG_WITH_COUNTERS);
                break;
+       case IPSET_OPT_CREATE_COMMENT:
+               cadt_flag_type_attr(data, opt, IPSET_FLAG_WITH_COMMENT);
+               break;
        /* Create-specific options, filled out by the kernel */
        case IPSET_OPT_ELEMENTS:
                data->create.elements = *(const uint32_t *) value;
@@ -336,6 +359,10 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
        case IPSET_OPT_BYTES:
                data->adt.bytes = *(const uint64_t *) value;
                break;
+       case IPSET_OPT_ADT_COMMENT:
+               ipset_strlcpy(data->adt.comment, value,
+                             IPSET_MAX_COMMENT_SIZE + 1);
+               break;
        /* Swap/rename */
        case IPSET_OPT_SETNAME2:
                ipset_strlcpy(data->setname2, value, IPSET_MAXNAMELEN);
@@ -370,6 +397,9 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
                if (data->cadt_flags & IPSET_FLAG_WITH_COUNTERS)
                        ipset_data_flags_set(data,
                                             IPSET_FLAG(IPSET_OPT_COUNTERS));
+               if (data->cadt_flags & IPSET_FLAG_WITH_COMMENT)
+                       ipset_data_flags_set(data,
+                                         IPSET_FLAG(IPSET_OPT_CREATE_COMMENT));
                break;
        default:
                return -1;
@@ -472,6 +502,8 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
                return &data->adt.packets;
        case IPSET_OPT_BYTES:
                return &data->adt.bytes;
+       case IPSET_OPT_ADT_COMMENT:
+               return &data->adt.comment;
        /* Swap/rename */
        case IPSET_OPT_SETNAME2:
                return data->setname2;
@@ -484,6 +516,7 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
        case IPSET_OPT_PHYSDEV:
        case IPSET_OPT_NOMATCH:
        case IPSET_OPT_COUNTERS:
+       case IPSET_OPT_CREATE_COMMENT:
                return &data->cadt_flags;
        default:
                return NULL;
@@ -543,6 +576,8 @@ ipset_data_sizeof(enum ipset_opt opt, uint8_t family)
        case IPSET_OPT_NOMATCH:
        case IPSET_OPT_COUNTERS:
                return sizeof(uint32_t);
+       case IPSET_OPT_ADT_COMMENT:
+               return IPSET_MAX_COMMENT_SIZE + 1;
        default:
                return 0;
        };
index 3aa5a99c0dc9f4315089edbfa6fb9580b1c67ae6..a204940c0155bbabb035f6f6de72aa3eb5b342bd 100644 (file)
@@ -64,6 +64,7 @@ static const struct ipset_attrname adtattr2name[] = {
        [IPSET_ATTR_CIDR2]      = { .name = "CIDR2" },
        [IPSET_ATTR_IP2_TO]     = { .name = "IP2_TO" },
        [IPSET_ATTR_IFACE]      = { .name = "IFACE" },
+       [IPSET_ATTR_COMMENT]    = { .name = "COMMENT" },
 };
 
 static void
index c93994938fb2140197c1972d415c8d46084fca26..160d9ad91fd3d47ea3636bb056c5fbe4f993580e 100644 (file)
@@ -72,6 +72,8 @@ static const struct ipset_errcode_table core_errcode_table[] = {
          "An IPv6 address is expected, but not received" },
        { IPSET_ERR_COUNTER, 0,
          "Packet/byte counters cannot be used: set was created without counter support" },
+       { IPSET_ERR_COMMENT, 0,
+         "Comment string is too long!" },
 
        /* ADD specific error codes */
        { IPSET_ERR_EXIST, IPSET_CMD_ADD,
index 271fe59b08dbe48c09bb364276c1483740459c16..ab0b96f47a27ad45c513232bbf19057a9407ba6e 100644 (file)
@@ -127,3 +127,10 @@ LIBIPSET_4.0 {
 global:
   ipset_parse_uint64;
 } LIBIPSET_3.0;
+
+LIBIPSET_4.1 {
+global:
+  ipset_parse_comment;
+  ipset_print_comment;
+  ipset_strlcat;
+} LIBIPSET_4.0;
index 112b27302100cc7a4cc1e40f8e902ab1ba4952fa..8ea8542a1a7090ea2481809e85329f62cc6888f8 100644 (file)
@@ -1738,6 +1738,35 @@ ipset_parse_iface(struct ipset_session *session,
        return ipset_data_set(data, opt, str + offset);
 }
 
+/**
+ * ipset_parse_comment - parse string as a comment
+ * @session: session structure
+ * @opt: option kind of the data
+ * @str: string to parse
+ *
+ * Parse string for use as a comment on an ipset entry.
+ * Gets stored in the data blob as usual.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int ipset_parse_comment(struct ipset_session *session,
+                      enum ipset_opt opt, const char *str)
+{
+       struct ipset_data *data;
+
+       assert(session);
+       assert(opt == IPSET_OPT_ADT_COMMENT);
+       assert(str);
+
+       data = ipset_session_data(session);
+       if (strchr(str, '"'))
+               return syntax_err("\" character is not permitted in comments");
+       if (strlen(str) > IPSET_MAX_COMMENT_SIZE)
+               return syntax_err("Comment is longer than the maximum allowed "
+                                 "%d characters", IPSET_MAX_COMMENT_SIZE);
+       return ipset_data_set(data, opt, str);
+}
+
 /**
  * ipset_parse_output - parse output format name
  * @session: session structure
index 86a76749fecf19d73f4004c7cd77f9d3d4c1cc4c..abdfd34697dab0382a642bbc7c42655d745607d1 100644 (file)
@@ -529,6 +529,37 @@ ipset_print_iface(char *buf, unsigned int len,
        return offset;
 }
 
+/**
+ * ipset_print_comment - print arbitrary parameter string
+ * @buf: printing buffer
+ * @len: length of available buffer space
+ * @data: data blob
+ * @opt: the option kind
+ * @env: environment flags
+ *
+ * Print arbitrary string to output buffer.
+ *
+ * Return length of printed string or error size.
+ */
+int ipset_print_comment(char *buf, unsigned int len,
+                      const struct ipset_data *data, enum ipset_opt opt,
+                      uint8_t env UNUSED)
+{
+       const char *comment;
+       int size, offset = 0;
+
+       assert(buf);
+       assert(len > 0);
+       assert(data);
+       assert(opt == IPSET_OPT_ADT_COMMENT);
+
+       comment = ipset_data_get(data, opt);
+       assert(comment);
+       size = snprintf(buf + offset, len, "\"%s\"", comment);
+       SNPRINTF_FAILURE(size, len, offset);
+       return offset;
+}
+
 /**
  * ipset_print_proto - print protocol name
  * @buf: printing buffer
index f1df5156d711c9be354b3d166faa7737c66df7ec..6f89281711c34dc40b86e1291f5d0ec724e40d9e 100644 (file)
@@ -488,6 +488,11 @@ static const struct ipset_attr_policy adt_attrs[] = {
                .type = MNL_TYPE_U64,
                .opt = IPSET_OPT_BYTES,
        },
+       [IPSET_ATTR_COMMENT] = {
+               .type = MNL_TYPE_NUL_STRING,
+               .opt = IPSET_OPT_ADT_COMMENT,
+               .len  = IPSET_MAX_COMMENT_SIZE + 1,
+       },
 };
 
 static const struct ipset_attr_policy ipaddr_attrs[] = {
@@ -522,7 +527,7 @@ generic_data_attr_cb(const struct nlattr *attr, void *data,
                return MNL_CB_ERROR;
        }
        if (policy[type].type == MNL_TYPE_NUL_STRING &&
-           mnl_attr_get_payload_len(attr) > IPSET_MAXNAMELEN)
+           mnl_attr_get_payload_len(attr) > policy[type].len)
                return MNL_CB_ERROR;
        tb[type] = attr;
        return MNL_CB_OK;
index adaba83460b250e66f264b530244f9f6dd1271fe..e2a41ad6b056b6f90e6dc0864b44f81234f6ef53 100644 (file)
@@ -607,7 +607,7 @@ ipset_load_types(void)
                len = snprintf(path, sizeof(path), "%.*s",
                               (unsigned int)(next - dir), dir);
 
-               if (len >= sizeof(path) || len < 0)
+               if (len >= (int)sizeof(path) || len < 0)
                        continue;
 
                n = scandir(path, &list, NULL, alphasort);
@@ -620,7 +620,7 @@ ipset_load_types(void)
 
                        len = snprintf(file, sizeof(file), "%s/%s",
                                       path, list[n]->d_name);
-                       if (len >= sizeof(file) || len < 0)
+                       if (len >= (int)sizeof(file) || len < (int)0)
                                goto nextf;
 
                        if (dlopen(file, RTLD_NOW) == NULL)