diff --git a/doc/changelog.txt b/doc/changelog.txt index cf2f0ae..8fedf2c 100644 --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -21,6 +21,10 @@ Enhancements: * revision reporting fixes - update to ipset 6.2 * list:set timeout variant fixes +- update to ipset 6.3 + * bitmap:ip,mac type requires "src" for MAC, enforce it +- ipset-genl: handle EAGAIN return value emitted from autoloader +- ipset-genl: resolve nfgenmsg remains and fix spurious protocol abort v1.33 (2011-02-02) diff --git a/extensions/ipset-6/include/libipset/linux_ip_set.h b/extensions/ipset-6/include/libipset/linux_ip_set.h index d4b6308..d81a811 100644 --- a/extensions/ipset-6/include/libipset/linux_ip_set.h +++ b/extensions/ipset-6/include/libipset/linux_ip_set.h @@ -12,7 +12,7 @@ */ /* The protocol version */ -#define IPSET_PROTOCOL 60 +#define IPSET_PROTOCOL 6 /* The max length of strings including NUL: set and type identifiers */ #define IPSET_MAXNAMELEN 32 diff --git a/extensions/ipset-6/ip_set.h b/extensions/ipset-6/ip_set.h index 8026f1b..08f59eb 100644 --- a/extensions/ipset-6/ip_set.h +++ b/extensions/ipset-6/ip_set.h @@ -14,7 +14,7 @@ #include /* The protocol version */ -#define IPSET_PROTOCOL 60 +#define IPSET_PROTOCOL 6 /* The max length of strings including NUL: set and type identifiers */ #define IPSET_MAXNAMELEN 32 diff --git a/extensions/ipset-6/ip_set_bitmap_ipmac.c b/extensions/ipset-6/ip_set_bitmap_ipmac.c index 74bca4c..175d871 100644 --- a/extensions/ipset-6/ip_set_bitmap_ipmac.c +++ b/extensions/ipset-6/ip_set_bitmap_ipmac.c @@ -344,6 +344,10 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb, ipset_adtfn adtfn = set->variant->adt[adt]; struct ipmac data; + /* MAC can be src only */ + if (!(flags & IPSET_DIM_TWO_SRC)) + return 0; + data.id = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC)); if (data.id < map->first_ip || data.id > map->last_ip) return -IPSET_ERR_BITMAP_RANGE; diff --git a/extensions/ipset-6/ip_set_core.c b/extensions/ipset-6/ip_set_core.c index abf1c90..509a87c 100644 --- a/extensions/ipset-6/ip_set_core.c +++ b/extensions/ipset-6/ip_set_core.c @@ -26,6 +26,8 @@ #include #define GENLMSG_DEFAULT_SIZE (NLMSG_DEFAULT_SIZE - GENL_HDRLEN) +struct genlmsg_buf; + static LIST_HEAD(ip_set_type_list); /* all registered set types */ static DEFINE_MUTEX(ip_set_type_mutex); /* protects ip_set_type_list */ static DEFINE_RWLOCK(ip_set_ref_lock); /* protects the set refs */ @@ -82,14 +84,14 @@ find_set_type(const char *name, u8 family, u8 revision) static int try_to_load_type(const char *name) { - nfnl_unlock(); + genl_unlock(); pr_debug("try to load ip_set_%s\n", name); if (request_module("ip_set_%s", name) < 0) { pr_warning("Can't find ip_set type %s\n", name); - nfnl_lock(); + genl_lock(); return -IPSET_ERR_FIND_TYPE; } - nfnl_lock(); + genl_lock(); return -EAGAIN; } @@ -99,8 +101,10 @@ find_set_type_get(const char *name, u8 family, u8 revision, struct ip_set_type **found) { struct ip_set_type *type; + unsigned int retry = 0; int err; +retry: rcu_read_lock(); *found = find_set_type(name, family, revision); if (*found) { @@ -115,7 +119,10 @@ find_set_type_get(const char *name, u8 family, u8 revision, } rcu_read_unlock(); - return try_to_load_type(name); + err = try_to_load_type(name); + if (err == -EAGAIN && retry++ == 0) + goto retry; + return err; unlock: rcu_read_unlock(); @@ -131,7 +138,10 @@ find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max) { struct ip_set_type *type; bool found = false; + unsigned int retry = 0; + int err; +retry: *min = 255; *max = 0; rcu_read_lock(); list_for_each_entry_rcu(type, &ip_set_type_list, list) @@ -147,7 +157,10 @@ find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max) if (found) return 0; - return try_to_load_type(name); + err = try_to_load_type(name); + if (err == -EAGAIN && retry++ == 0) + goto retry; + return err; } #define family_name(f) ((f) == AF_INET ? "inet" : \ @@ -482,9 +495,9 @@ ip_set_nfnl_get(const char *name) struct ip_set *s; ip_set_id_t index; - nfnl_lock(); + genl_lock(); index = ip_set_get_byname(name, &s); - nfnl_unlock(); + genl_unlock(); return index; } @@ -502,12 +515,12 @@ ip_set_nfnl_get_byindex(ip_set_id_t index) if (index > ip_set_max) return IPSET_INVALID_ID; - nfnl_lock(); + genl_lock(); if (ip_set_list[index]) __ip_set_get(index); else index = IPSET_INVALID_ID; - nfnl_unlock(); + genl_unlock(); return index; } @@ -523,9 +536,9 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_get_byindex); void ip_set_nfnl_put(ip_set_id_t index) { - nfnl_lock(); + genl_lock(); ip_set_put_byindex(index); - nfnl_unlock(); + genl_unlock(); } EXPORT_SYMBOL_GPL(ip_set_nfnl_put); @@ -548,11 +561,11 @@ flag_exist(const struct genlmsghdr *ghdr) return ghdr->reserved & NLM_F_EXCL ? 0 : IPSET_FLAG_EXIST; } -static struct nlmsghdr * +static struct genlmsg_buf * start_msg(struct sk_buff *skb, u32 pid, u32 seq, unsigned int flags, enum ipset_cmd cmd) { - void *nlh; + struct genlmsg_buf *nlh; nlh = genlmsg_put(skb, pid, seq, &ip_set_netlink_subsys, flags, cmd); if (nlh == NULL) @@ -950,10 +963,11 @@ ip_set_dump_done(struct netlink_callback *cb) } static inline void -dump_attrs(void *phdr) +dump_attrs(struct genlmsg_buf *phdr) { const struct nlattr *attr; - const struct nlmsghdr *nlh = phdr - GENL_HDRLEN - NLMSG_HDRLEN; + const struct nlmsghdr *nlh = + (const void *)phdr - GENL_HDRLEN - NLMSG_HDRLEN; int rem; pr_debug("dump nlmsg\n"); @@ -999,14 +1013,14 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) { ip_set_id_t index = IPSET_INVALID_ID, max; struct ip_set *set = NULL; - struct nlmsghdr *nlh = NULL; + struct genlmsg_buf *nlh = NULL; unsigned int flags = NETLINK_CB(cb->skb).pid ? NLM_F_MULTI : 0; int ret = 0; if (cb->args[0] == DUMP_INIT) { ret = dump_init(cb); if (ret < 0) { - nlh = nlmsg_hdr(cb->skb); + struct nlmsghdr *nlh = nlmsg_hdr(cb->skb); /* We have to create and send the error message * manually :-( */ if (nlh->nlmsg_flags & NLM_F_ACK) @@ -1159,7 +1173,7 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set, struct sk_buff *skb2; struct nlmsgerr *errmsg; size_t payload = sizeof(*errmsg) + nlmsg_len(nlh); - int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); + int min_len = NLMSG_SPACE(sizeof(struct genlmsghdr)); struct nlattr *cda[IPSET_ATTR_CMD_MAX+1]; struct nlattr *cmdattr; u32 *errline; @@ -1342,7 +1356,7 @@ ip_set_header(struct sk_buff *skb, struct genl_info *info) struct nlattr *const *attr = info->attrs; const struct nlmsghdr *nlh = info->nlhdr; struct sk_buff *skb2; - struct nlmsghdr *nlh2; + struct genlmsg_buf *nlh2; ip_set_id_t index; int ret = 0; @@ -1355,7 +1369,7 @@ ip_set_header(struct sk_buff *skb, struct genl_info *info) return -ENOENT; set = ip_set_list[index]; - skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + skb2 = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (skb2 == NULL) return -ENOMEM; @@ -1377,7 +1391,7 @@ ip_set_header(struct sk_buff *skb, struct genl_info *info) return 0; nla_put_failure: - nlmsg_cancel(skb2, nlh2); + genlmsg_cancel(skb2, nlh2); nlmsg_failure: kfree_skb(skb2); return -EMSGSIZE; @@ -1399,7 +1413,7 @@ ip_set_type(struct sk_buff *skb, struct genl_info *info) const struct nlmsghdr *nlh = info->nlhdr; struct sk_buff *skb2; - void *nlh2; + struct genlmsg_buf *nlh2; u8 family, min, max; const char *typename; int ret = 0; @@ -1458,7 +1472,7 @@ ip_set_protocol(struct sk_buff *skb, struct genl_info *info) const struct nlmsghdr *nlh = info->nlhdr; struct sk_buff *skb2; - void *nlh2; + struct genlmsg_buf *nlh2; int ret = 0; if (unlikely(attr[IPSET_ATTR_PROTOCOL] == NULL)) @@ -1633,9 +1647,9 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len) goto done; } req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0'; - nfnl_lock(); + genl_lock(); req_get->set.index = find_set_id(req_get->set.name); - nfnl_unlock(); + genl_unlock(); goto copy; } case IP_SET_OP_GET_BYINDEX: { @@ -1646,12 +1660,12 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len) ret = -EINVAL; goto done; } - nfnl_lock(); + genl_lock(); strncpy(req_get->set.name, ip_set_list[req_get->set.index] ? ip_set_list[req_get->set.index]->name : "", IPSET_MAXNAMELEN); - nfnl_unlock(); + genl_unlock(); goto copy; } default: diff --git a/extensions/ipset-6/ip_set_list_set.c b/extensions/ipset-6/ip_set_list_set.c index c3643a0..e15f819 100644 --- a/extensions/ipset-6/ip_set_list_set.c +++ b/extensions/ipset-6/ip_set_list_set.c @@ -310,8 +310,8 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[], !id_eq(map, i + 1, refid)) || (before < 0 && (i == 0 || !id_eq(map, i - 1, refid)))) { - ret = -IPSET_ERR_EXIST; - goto finish; + ret = -IPSET_ERR_EXIST; + goto finish; } e->timeout = ip_set_timeout_set(timeout); ip_set_put_byindex(id); diff --git a/extensions/ipset-6/ipset.8 b/extensions/ipset-6/ipset.8 index 9603ddc..d9e5ff8 100644 --- a/extensions/ipset-6/ipset.8 +++ b/extensions/ipset-6/ipset.8 @@ -302,9 +302,10 @@ matched by the kernel, it will automatically fill out the missing MAC address wi source MAC address from the packet. If the entry was specified with a timeout value, the timer starts off when the IP and MAC address pair is complete. .PP -Please note, the \fBset\fR match and \fBSET\fR target netfilter kernel modules -\fBalways\fR use the source MAC address from the packet to match, add or delete -entries from a \fBbitmap:ip,mac\fR type of set. +The \fBbitmap:ip,mac\fR type of sets require two \fBsrc/dst\fR parameters of +the \fBset\fR match and \fBSET\fR target netfilter kernel modules and the second +one must be \fBsrc\fR to match, add or delete entries because the \fBset\fR match +and \fBSET\fR target have access to the source MAC address only. .PP Examples: .IP diff --git a/extensions/ipset-6/xt_set.c b/extensions/ipset-6/xt_set.c index f2a9088..93de81d 100644 --- a/extensions/ipset-6/xt_set.c +++ b/extensions/ipset-6/xt_set.c @@ -115,6 +115,7 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par) if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) { pr_warning("Protocol error: set match dimension " "is over the limit!\n"); + ip_set_nfnl_put(info->match_set.index); return CHECK_FAIL(-ERANGE); /* error */ } @@ -179,6 +180,8 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par) if (index == IPSET_INVALID_ID) { pr_warning("Cannot find del_set index %u as target\n", info->del_set.index); + if (info->add_set.index != IPSET_INVALID_ID) + ip_set_nfnl_put(info->add_set.index); return CHECK_FAIL(-ENOENT); /* error */ } } @@ -186,6 +189,10 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par) info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) { pr_warning("Protocol error: SET target dimension " "is over the limit!\n"); + if (info->add_set.index != IPSET_INVALID_ID) + ip_set_nfnl_put(info->add_set.index); + if (info->del_set.index != IPSET_INVALID_ID) + ip_set_nfnl_put(info->del_set.index); return CHECK_FAIL(-ERANGE); /* error */ } @@ -246,6 +253,7 @@ set_match_checkentry(const struct xt_mtchk_param *par) if (info->match_set.dim > IPSET_DIM_MAX) { pr_warning("Protocol error: set match dimension " "is over the limit!\n"); + ip_set_nfnl_put(info->match_set.index); return CHECK_FAIL(-ERANGE); /* error */ } @@ -278,7 +286,7 @@ set_target(struct sk_buff *skb, const struct xt_action_param *par) if (info->del_set.index != IPSET_INVALID_ID) ip_set_del(info->del_set.index, skb, par->family, - info->add_set.dim, + info->del_set.dim, info->del_set.flags); return XT_CONTINUE; @@ -309,13 +317,19 @@ set_target_checkentry(const struct xt_tgchk_param *par) if (index == IPSET_INVALID_ID) { pr_warning("Cannot find del_set index %u as target\n", info->del_set.index); + if (info->add_set.index != IPSET_INVALID_ID) + ip_set_nfnl_put(info->add_set.index); return CHECK_FAIL(-ENOENT); /* error */ } } if (info->add_set.dim > IPSET_DIM_MAX || - info->del_set.flags > IPSET_DIM_MAX) { + info->del_set.dim > IPSET_DIM_MAX) { pr_warning("Protocol error: SET target dimension " "is over the limit!\n"); + if (info->add_set.index != IPSET_INVALID_ID) + ip_set_nfnl_put(info->add_set.index); + if (info->del_set.index != IPSET_INVALID_ID) + ip_set_nfnl_put(info->del_set.index); return CHECK_FAIL(-ERANGE); /* error */ }