]> granicus.if.org Git - ipset/commitdiff
Prepare the ipset tool to handle multiple protocol versions
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Mon, 22 Oct 2018 18:01:14 +0000 (20:01 +0200)
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Mon, 22 Oct 2018 18:01:14 +0000 (20:01 +0200)
From now on the "version" command asks the kernel protocol version too
and reports if the userspace - kernel protocols do not match.

include/libipset/linux_ip_set.h
lib/ipset.c
lib/session.c

index 883922d3260dd31cc8291195c9fb70a69f676e1d..2096611ea45532b0f001a87e6e5a08ec1baeb398 100644 (file)
@@ -12,8 +12,9 @@
 
 #include <linux/types.h>
 
-/* The protocol version */
-#define IPSET_PROTOCOL         6
+/* The supported protocol versions */
+#define IPSET_PROTOCOL_MIN     6
+#define IPSET_PROTOCOL         7
 
 /* The max length of strings including NUL: set and type identifiers */
 #define IPSET_MAXNAMELEN       32
index 70189f96e2a06b0cd36aae76ce15c846246b4174..8d05b39e96708c93bc912e3b75481a3aa976a6a9 100644 (file)
@@ -1090,6 +1090,10 @@ ipset_parse_argv(struct ipset *ipset, int oargc, char *oargv[])
                        return 0;
                printf("%s v%s, protocol version: %u\n",
                       program_name, program_version, IPSET_PROTOCOL);
+               /* Check kernel protocol version */
+               ipset_cmd(session, IPSET_CMD_NONE, 0);
+               if (ipset_session_report_type(session) != IPSET_NO_ERROR)
+                       ipset->standard_error(ipset, p);
                if (ipset->interactive)
                        return 0;
                return ipset->custom_error(ipset, p, IPSET_NO_PROBLEM, NULL);
index a5a93da7a8516b20713bb671e5d09e62c1ab2ada..c19191a32fabf054a066dc8c374d640d0c54f20b 100644 (file)
@@ -44,6 +44,7 @@ struct ipset_session {
        const struct ipset_type *saved_type;    /* Saved type */
        struct nlattr *nested[IPSET_NEST_MAX];  /* Pointer to nest levels */
        uint8_t nestid;                         /* Current nest level */
+       uint8_t protocol;                       /* The protocol used */
        bool version_checked;                   /* Version checked */
        /* Output buffer */
        char outbuf[IPSET_OUTBUFLEN];           /* Output buffer */
@@ -1170,6 +1171,7 @@ callback_version(struct ipset_session *session, struct nlattr *nla[])
                           "while userspace supports protocol versions %u-%u",
                           min, max, IPSET_PROTOCOL_MIN, IPSET_PROTOCOL_MAX);
 
+       session->protocol = MIN(max, IPSET_PROTOCOL_MAX);
        session->version_checked = true;
 
        return MNL_CB_STOP;
@@ -1297,10 +1299,10 @@ callback_data(const struct nlmsghdr *nlh, void *data)
        proto = mnl_attr_get_u8(nla[IPSET_ATTR_PROTOCOL]);
 
        /* Check protocol */
-       if (cmd != IPSET_CMD_PROTOCOL && proto != IPSET_PROTOCOL)
+       if (cmd != IPSET_CMD_PROTOCOL && proto != session->protocol)
                FAILURE("Giving up: kernel protocol version %u "
                        "does not match our protocol version %u",
-                       proto, IPSET_PROTOCOL);
+                       proto, session->protocol);
 
        D("Message: %s", cmd2name[cmd]);
        switch (cmd) {
@@ -1602,8 +1604,8 @@ data2attr(struct ipset_session *session, struct nlmsghdr *nlh,
                            type, family, attrs);
 }
 
-#define ADDATTR_PROTOCOL(nlh)                                          \
-       mnl_attr_put_u8(nlh, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL)
+#define ADDATTR_PROTOCOL(nlh, protocol)                                        \
+       mnl_attr_put_u8(nlh, IPSET_ATTR_PROTOCOL, protocol)
 
 #define ADDATTR(session, nlh, data, type, family, attrs)               \
        data2attr(session, nlh, data, type, family, attrs)
@@ -1655,7 +1657,8 @@ build_send_private_msg(struct ipset_session *session, enum ipset_cmd cmd)
        /* Initialize header */
        session->transport->fill_hdr(session->handle, cmd, buffer, len, 0);
 
-       ADDATTR_PROTOCOL(nlh);
+       ADDATTR_PROTOCOL(nlh,
+               cmd == IPSET_CMD_PROTOCOL ? IPSET_PROTOCOL : session->protocol);
 
        switch (cmd) {
        case IPSET_CMD_PROTOCOL:
@@ -1719,7 +1722,7 @@ build_msg(struct ipset_session *session, bool aggregate)
                                             session->buffer,
                                             session->bufsize,
                                             session->envopts);
-               ADDATTR_PROTOCOL(nlh);
+               ADDATTR_PROTOCOL(nlh, session->protocol);
        }
        D("Protocol added, aggregate %s", aggregate ? "yes" : "no");
        switch (session->cmd) {
@@ -1965,7 +1968,7 @@ ipset_cmd(struct ipset_session *session, enum ipset_cmd cmd, uint32_t lineno)
 
        assert(session);
 
-       if (cmd <= IPSET_CMD_NONE || cmd >= IPSET_MSG_MAX)
+       if (cmd < IPSET_CMD_NONE || cmd >= IPSET_MSG_MAX)
                return 0;
 
        /* Initialize transport method if not done yet */
@@ -1979,7 +1982,14 @@ ipset_cmd(struct ipset_session *session, enum ipset_cmd cmd, uint32_t lineno)
        if (!session->version_checked) {
                if (build_send_private_msg(session, IPSET_CMD_PROTOCOL) < 0)
                        return -1;
+               if (ipset_session_report_type(session) == IPSET_WARNING &&
+                   cmd != IPSET_CMD_NONE)
+                       /* Suppress protocol warning */
+                       ipset_session_report_reset(session);
        }
+       /* IPSET_CMD_NONE: check protocol version only */
+       if (cmd == IPSET_CMD_NONE)
+               return 0;
 
        /* Private commands */
        if (cmd == IPSET_CMD_TYPE || cmd == IPSET_CMD_HEADER)
@@ -2111,6 +2121,7 @@ ipset_session_init(ipset_print_outfn print_outfn, void *p)
        session->buffer = session + 1;
        session->istream = stdin;
        session->ostream = stdout;
+       session->protocol = IPSET_PROTOCOL;
 
        /* The single transport method yet */
        session->transport = &ipset_mnl_transport;