Commit 1226cfe3 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

Merge branch 'master' of git://blackhole.kfki.hu/nf-next

Jozsef Kadlecsik says:

====================
- Introduction of new commands and thus protocol version 7. The
  new commands makes possible to eliminate the getsockopt interface
  of ipset and use solely netlink to communicate with the kernel.
  Due to the strict attribute checking both in user/kernel space,
  a new protocol number was introduced. Both the kernel/userspace is
  fully backward compatible.
- Make invalid MAC address checks consisten, from Stefano Brivio.
  The patch depends on the next one.
- Allow matching on destination MAC address for mac and ipmac sets,
  also from Stefano Brivio.
====================
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parents 30beabb3 23c42a40
...@@ -303,11 +303,11 @@ ip_set_put_flags(struct sk_buff *skb, struct ip_set *set) ...@@ -303,11 +303,11 @@ ip_set_put_flags(struct sk_buff *skb, struct ip_set *set)
/* Netlink CB args */ /* Netlink CB args */
enum { enum {
IPSET_CB_NET = 0, /* net namespace */ IPSET_CB_NET = 0, /* net namespace */
IPSET_CB_PROTO, /* ipset protocol */
IPSET_CB_DUMP, /* dump single set/all sets */ IPSET_CB_DUMP, /* dump single set/all sets */
IPSET_CB_INDEX, /* set index */ IPSET_CB_INDEX, /* set index */
IPSET_CB_PRIVATE, /* set private data */ IPSET_CB_PRIVATE, /* set private data */
IPSET_CB_ARG0, /* type specific */ IPSET_CB_ARG0, /* type specific */
IPSET_CB_ARG1,
}; };
/* register and unregister set references */ /* register and unregister set references */
......
...@@ -13,8 +13,9 @@ ...@@ -13,8 +13,9 @@
#include <linux/types.h> #include <linux/types.h>
/* The protocol version */ /* The protocol versions */
#define IPSET_PROTOCOL 6 #define IPSET_PROTOCOL 7
#define IPSET_PROTOCOL_MIN 6
/* The max length of strings including NUL: set and type identifiers */ /* The max length of strings including NUL: set and type identifiers */
#define IPSET_MAXNAMELEN 32 #define IPSET_MAXNAMELEN 32
...@@ -38,17 +39,19 @@ enum ipset_cmd { ...@@ -38,17 +39,19 @@ enum ipset_cmd {
IPSET_CMD_TEST, /* 11: Test an element in a set */ IPSET_CMD_TEST, /* 11: Test an element in a set */
IPSET_CMD_HEADER, /* 12: Get set header data only */ IPSET_CMD_HEADER, /* 12: Get set header data only */
IPSET_CMD_TYPE, /* 13: Get set type */ IPSET_CMD_TYPE, /* 13: Get set type */
IPSET_CMD_GET_BYNAME, /* 14: Get set index by name */
IPSET_CMD_GET_BYINDEX, /* 15: Get set name by index */
IPSET_MSG_MAX, /* Netlink message commands */ IPSET_MSG_MAX, /* Netlink message commands */
/* Commands in userspace: */ /* Commands in userspace: */
IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* 14: Enter restore mode */ IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* 16: Enter restore mode */
IPSET_CMD_HELP, /* 15: Get help */ IPSET_CMD_HELP, /* 17: Get help */
IPSET_CMD_VERSION, /* 16: Get program version */ IPSET_CMD_VERSION, /* 18: Get program version */
IPSET_CMD_QUIT, /* 17: Quit from interactive mode */ IPSET_CMD_QUIT, /* 19: Quit from interactive mode */
IPSET_CMD_MAX, IPSET_CMD_MAX,
IPSET_CMD_COMMIT = IPSET_CMD_MAX, /* 18: Commit buffered commands */ IPSET_CMD_COMMIT = IPSET_CMD_MAX, /* 20: Commit buffered commands */
}; };
/* Attributes at command level */ /* Attributes at command level */
...@@ -66,6 +69,7 @@ enum { ...@@ -66,6 +69,7 @@ enum {
IPSET_ATTR_LINENO, /* 9: Restore lineno */ IPSET_ATTR_LINENO, /* 9: Restore lineno */
IPSET_ATTR_PROTOCOL_MIN, /* 10: Minimal supported version number */ IPSET_ATTR_PROTOCOL_MIN, /* 10: Minimal supported version number */
IPSET_ATTR_REVISION_MIN = IPSET_ATTR_PROTOCOL_MIN, /* type rev min */ IPSET_ATTR_REVISION_MIN = IPSET_ATTR_PROTOCOL_MIN, /* type rev min */
IPSET_ATTR_INDEX, /* 11: Kernel index of set */
__IPSET_ATTR_CMD_MAX, __IPSET_ATTR_CMD_MAX,
}; };
#define IPSET_ATTR_CMD_MAX (__IPSET_ATTR_CMD_MAX - 1) #define IPSET_ATTR_CMD_MAX (__IPSET_ATTR_CMD_MAX - 1)
...@@ -223,6 +227,7 @@ enum ipset_adt { ...@@ -223,6 +227,7 @@ enum ipset_adt {
/* Sets are identified by an index in kernel space. Tweak with ip_set_id_t /* Sets are identified by an index in kernel space. Tweak with ip_set_id_t
* and IPSET_INVALID_ID if you want to increase the max number of sets. * and IPSET_INVALID_ID if you want to increase the max number of sets.
* Also, IPSET_ATTR_INDEX must be changed.
*/ */
typedef __u16 ip_set_id_t; typedef __u16 ip_set_id_t;
......
...@@ -219,10 +219,6 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb, ...@@ -219,10 +219,6 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
u32 ip; u32 ip;
/* MAC can be src only */
if (!(opt->flags & IPSET_DIM_TWO_SRC))
return 0;
ip = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC)); ip = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC));
if (ip < map->first_ip || ip > map->last_ip) if (ip < map->first_ip || ip > map->last_ip)
return -IPSET_ERR_BITMAP_RANGE; return -IPSET_ERR_BITMAP_RANGE;
...@@ -233,7 +229,14 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb, ...@@ -233,7 +229,14 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
return -EINVAL; return -EINVAL;
e.id = ip_to_id(map, ip); e.id = ip_to_id(map, ip);
memcpy(e.ether, eth_hdr(skb)->h_source, ETH_ALEN);
if (opt->flags & IPSET_DIM_ONE_SRC)
ether_addr_copy(e.ether, eth_hdr(skb)->h_source);
else
ether_addr_copy(e.ether, eth_hdr(skb)->h_dest);
if (is_zero_ether_addr(e.ether))
return -EINVAL;
return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
} }
......
...@@ -771,11 +771,21 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_put); ...@@ -771,11 +771,21 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_put);
* The commands are serialized by the nfnl mutex. * The commands are serialized by the nfnl mutex.
*/ */
static inline u8 protocol(const struct nlattr * const tb[])
{
return nla_get_u8(tb[IPSET_ATTR_PROTOCOL]);
}
static inline bool static inline bool
protocol_failed(const struct nlattr * const tb[]) protocol_failed(const struct nlattr * const tb[])
{ {
return !tb[IPSET_ATTR_PROTOCOL] || return !tb[IPSET_ATTR_PROTOCOL] || protocol(tb) != IPSET_PROTOCOL;
nla_get_u8(tb[IPSET_ATTR_PROTOCOL]) != IPSET_PROTOCOL; }
static inline bool
protocol_min_failed(const struct nlattr * const tb[])
{
return !tb[IPSET_ATTR_PROTOCOL] || protocol(tb) < IPSET_PROTOCOL_MIN;
} }
static inline u32 static inline u32
...@@ -889,7 +899,7 @@ static int ip_set_create(struct net *net, struct sock *ctnl, ...@@ -889,7 +899,7 @@ static int ip_set_create(struct net *net, struct sock *ctnl,
u32 flags = flag_exist(nlh); u32 flags = flag_exist(nlh);
int ret = 0; int ret = 0;
if (unlikely(protocol_failed(attr) || if (unlikely(protocol_min_failed(attr) ||
!attr[IPSET_ATTR_SETNAME] || !attr[IPSET_ATTR_SETNAME] ||
!attr[IPSET_ATTR_TYPENAME] || !attr[IPSET_ATTR_TYPENAME] ||
!attr[IPSET_ATTR_REVISION] || !attr[IPSET_ATTR_REVISION] ||
...@@ -1027,7 +1037,7 @@ static int ip_set_destroy(struct net *net, struct sock *ctnl, ...@@ -1027,7 +1037,7 @@ static int ip_set_destroy(struct net *net, struct sock *ctnl,
ip_set_id_t i; ip_set_id_t i;
int ret = 0; int ret = 0;
if (unlikely(protocol_failed(attr))) if (unlikely(protocol_min_failed(attr)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
/* Must wait for flush to be really finished in list:set */ /* Must wait for flush to be really finished in list:set */
...@@ -1105,7 +1115,7 @@ static int ip_set_flush(struct net *net, struct sock *ctnl, struct sk_buff *skb, ...@@ -1105,7 +1115,7 @@ static int ip_set_flush(struct net *net, struct sock *ctnl, struct sk_buff *skb,
struct ip_set *s; struct ip_set *s;
ip_set_id_t i; ip_set_id_t i;
if (unlikely(protocol_failed(attr))) if (unlikely(protocol_min_failed(attr)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (!attr[IPSET_ATTR_SETNAME]) { if (!attr[IPSET_ATTR_SETNAME]) {
...@@ -1147,7 +1157,7 @@ static int ip_set_rename(struct net *net, struct sock *ctnl, ...@@ -1147,7 +1157,7 @@ static int ip_set_rename(struct net *net, struct sock *ctnl,
ip_set_id_t i; ip_set_id_t i;
int ret = 0; int ret = 0;
if (unlikely(protocol_failed(attr) || if (unlikely(protocol_min_failed(attr) ||
!attr[IPSET_ATTR_SETNAME] || !attr[IPSET_ATTR_SETNAME] ||
!attr[IPSET_ATTR_SETNAME2])) !attr[IPSET_ATTR_SETNAME2]))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
...@@ -1196,7 +1206,7 @@ static int ip_set_swap(struct net *net, struct sock *ctnl, struct sk_buff *skb, ...@@ -1196,7 +1206,7 @@ static int ip_set_swap(struct net *net, struct sock *ctnl, struct sk_buff *skb,
ip_set_id_t from_id, to_id; ip_set_id_t from_id, to_id;
char from_name[IPSET_MAXNAMELEN]; char from_name[IPSET_MAXNAMELEN];
if (unlikely(protocol_failed(attr) || if (unlikely(protocol_min_failed(attr) ||
!attr[IPSET_ATTR_SETNAME] || !attr[IPSET_ATTR_SETNAME] ||
!attr[IPSET_ATTR_SETNAME2])) !attr[IPSET_ATTR_SETNAME2]))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
...@@ -1291,6 +1301,7 @@ dump_init(struct netlink_callback *cb, struct ip_set_net *inst) ...@@ -1291,6 +1301,7 @@ dump_init(struct netlink_callback *cb, struct ip_set_net *inst)
nla_parse(cda, IPSET_ATTR_CMD_MAX, attr, nlh->nlmsg_len - min_len, nla_parse(cda, IPSET_ATTR_CMD_MAX, attr, nlh->nlmsg_len - min_len,
ip_set_setname_policy, NULL); ip_set_setname_policy, NULL);
cb->args[IPSET_CB_PROTO] = nla_get_u8(cda[IPSET_ATTR_PROTOCOL]);
if (cda[IPSET_ATTR_SETNAME]) { if (cda[IPSET_ATTR_SETNAME]) {
struct ip_set *set; struct ip_set *set;
...@@ -1392,7 +1403,8 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1392,7 +1403,8 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
ret = -EMSGSIZE; ret = -EMSGSIZE;
goto release_refcount; goto release_refcount;
} }
if (nla_put_u8(skb, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL) || if (nla_put_u8(skb, IPSET_ATTR_PROTOCOL,
cb->args[IPSET_CB_PROTO]) ||
nla_put_string(skb, IPSET_ATTR_SETNAME, set->name)) nla_put_string(skb, IPSET_ATTR_SETNAME, set->name))
goto nla_put_failure; goto nla_put_failure;
if (dump_flags & IPSET_FLAG_LIST_SETNAME) if (dump_flags & IPSET_FLAG_LIST_SETNAME)
...@@ -1407,6 +1419,9 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1407,6 +1419,9 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
nla_put_u8(skb, IPSET_ATTR_REVISION, nla_put_u8(skb, IPSET_ATTR_REVISION,
set->revision)) set->revision))
goto nla_put_failure; goto nla_put_failure;
if (cb->args[IPSET_CB_PROTO] > IPSET_PROTOCOL_MIN &&
nla_put_net16(skb, IPSET_ATTR_INDEX, htons(index)))
goto nla_put_failure;
ret = set->variant->head(set, skb); ret = set->variant->head(set, skb);
if (ret < 0) if (ret < 0)
goto release_refcount; goto release_refcount;
...@@ -1466,7 +1481,7 @@ static int ip_set_dump(struct net *net, struct sock *ctnl, struct sk_buff *skb, ...@@ -1466,7 +1481,7 @@ static int ip_set_dump(struct net *net, struct sock *ctnl, struct sk_buff *skb,
const struct nlattr * const attr[], const struct nlattr * const attr[],
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
if (unlikely(protocol_failed(attr))) if (unlikely(protocol_min_failed(attr)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
{ {
...@@ -1560,7 +1575,7 @@ static int ip_set_uadd(struct net *net, struct sock *ctnl, struct sk_buff *skb, ...@@ -1560,7 +1575,7 @@ static int ip_set_uadd(struct net *net, struct sock *ctnl, struct sk_buff *skb,
bool use_lineno; bool use_lineno;
int ret = 0; int ret = 0;
if (unlikely(protocol_failed(attr) || if (unlikely(protocol_min_failed(attr) ||
!attr[IPSET_ATTR_SETNAME] || !attr[IPSET_ATTR_SETNAME] ||
!((attr[IPSET_ATTR_DATA] != NULL) ^ !((attr[IPSET_ATTR_DATA] != NULL) ^
(attr[IPSET_ATTR_ADT] != NULL)) || (attr[IPSET_ATTR_ADT] != NULL)) ||
...@@ -1615,7 +1630,7 @@ static int ip_set_udel(struct net *net, struct sock *ctnl, struct sk_buff *skb, ...@@ -1615,7 +1630,7 @@ static int ip_set_udel(struct net *net, struct sock *ctnl, struct sk_buff *skb,
bool use_lineno; bool use_lineno;
int ret = 0; int ret = 0;
if (unlikely(protocol_failed(attr) || if (unlikely(protocol_min_failed(attr) ||
!attr[IPSET_ATTR_SETNAME] || !attr[IPSET_ATTR_SETNAME] ||
!((attr[IPSET_ATTR_DATA] != NULL) ^ !((attr[IPSET_ATTR_DATA] != NULL) ^
(attr[IPSET_ATTR_ADT] != NULL)) || (attr[IPSET_ATTR_ADT] != NULL)) ||
...@@ -1667,7 +1682,7 @@ static int ip_set_utest(struct net *net, struct sock *ctnl, struct sk_buff *skb, ...@@ -1667,7 +1682,7 @@ static int ip_set_utest(struct net *net, struct sock *ctnl, struct sk_buff *skb,
struct nlattr *tb[IPSET_ATTR_ADT_MAX + 1] = {}; struct nlattr *tb[IPSET_ATTR_ADT_MAX + 1] = {};
int ret = 0; int ret = 0;
if (unlikely(protocol_failed(attr) || if (unlikely(protocol_min_failed(attr) ||
!attr[IPSET_ATTR_SETNAME] || !attr[IPSET_ATTR_SETNAME] ||
!attr[IPSET_ATTR_DATA] || !attr[IPSET_ATTR_DATA] ||
!flag_nested(attr[IPSET_ATTR_DATA]))) !flag_nested(attr[IPSET_ATTR_DATA])))
...@@ -1704,7 +1719,7 @@ static int ip_set_header(struct net *net, struct sock *ctnl, ...@@ -1704,7 +1719,7 @@ static int ip_set_header(struct net *net, struct sock *ctnl,
struct nlmsghdr *nlh2; struct nlmsghdr *nlh2;
int ret = 0; int ret = 0;
if (unlikely(protocol_failed(attr) || if (unlikely(protocol_min_failed(attr) ||
!attr[IPSET_ATTR_SETNAME])) !attr[IPSET_ATTR_SETNAME]))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
...@@ -1720,7 +1735,7 @@ static int ip_set_header(struct net *net, struct sock *ctnl, ...@@ -1720,7 +1735,7 @@ static int ip_set_header(struct net *net, struct sock *ctnl,
IPSET_CMD_HEADER); IPSET_CMD_HEADER);
if (!nlh2) if (!nlh2)
goto nlmsg_failure; goto nlmsg_failure;
if (nla_put_u8(skb2, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL) || if (nla_put_u8(skb2, IPSET_ATTR_PROTOCOL, protocol(attr)) ||
nla_put_string(skb2, IPSET_ATTR_SETNAME, set->name) || nla_put_string(skb2, IPSET_ATTR_SETNAME, set->name) ||
nla_put_string(skb2, IPSET_ATTR_TYPENAME, set->type->name) || nla_put_string(skb2, IPSET_ATTR_TYPENAME, set->type->name) ||
nla_put_u8(skb2, IPSET_ATTR_FAMILY, set->family) || nla_put_u8(skb2, IPSET_ATTR_FAMILY, set->family) ||
...@@ -1761,7 +1776,7 @@ static int ip_set_type(struct net *net, struct sock *ctnl, struct sk_buff *skb, ...@@ -1761,7 +1776,7 @@ static int ip_set_type(struct net *net, struct sock *ctnl, struct sk_buff *skb,
const char *typename; const char *typename;
int ret = 0; int ret = 0;
if (unlikely(protocol_failed(attr) || if (unlikely(protocol_min_failed(attr) ||
!attr[IPSET_ATTR_TYPENAME] || !attr[IPSET_ATTR_TYPENAME] ||
!attr[IPSET_ATTR_FAMILY])) !attr[IPSET_ATTR_FAMILY]))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
...@@ -1780,7 +1795,7 @@ static int ip_set_type(struct net *net, struct sock *ctnl, struct sk_buff *skb, ...@@ -1780,7 +1795,7 @@ static int ip_set_type(struct net *net, struct sock *ctnl, struct sk_buff *skb,
IPSET_CMD_TYPE); IPSET_CMD_TYPE);
if (!nlh2) if (!nlh2)
goto nlmsg_failure; goto nlmsg_failure;
if (nla_put_u8(skb2, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL) || if (nla_put_u8(skb2, IPSET_ATTR_PROTOCOL, protocol(attr)) ||
nla_put_string(skb2, IPSET_ATTR_TYPENAME, typename) || nla_put_string(skb2, IPSET_ATTR_TYPENAME, typename) ||
nla_put_u8(skb2, IPSET_ATTR_FAMILY, family) || nla_put_u8(skb2, IPSET_ATTR_FAMILY, family) ||
nla_put_u8(skb2, IPSET_ATTR_REVISION, max) || nla_put_u8(skb2, IPSET_ATTR_REVISION, max) ||
...@@ -1831,6 +1846,111 @@ static int ip_set_protocol(struct net *net, struct sock *ctnl, ...@@ -1831,6 +1846,111 @@ static int ip_set_protocol(struct net *net, struct sock *ctnl,
goto nlmsg_failure; goto nlmsg_failure;
if (nla_put_u8(skb2, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL)) if (nla_put_u8(skb2, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL))
goto nla_put_failure; goto nla_put_failure;
if (nla_put_u8(skb2, IPSET_ATTR_PROTOCOL_MIN, IPSET_PROTOCOL_MIN))
goto nla_put_failure;
nlmsg_end(skb2, nlh2);
ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
if (ret < 0)
return ret;
return 0;
nla_put_failure:
nlmsg_cancel(skb2, nlh2);
nlmsg_failure:
kfree_skb(skb2);
return -EMSGSIZE;
}
/* Get set by name or index, from userspace */
static int ip_set_byname(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{
struct ip_set_net *inst = ip_set_pernet(net);
struct sk_buff *skb2;
struct nlmsghdr *nlh2;
ip_set_id_t id = IPSET_INVALID_ID;
const struct ip_set *set;
int ret = 0;
if (unlikely(protocol_failed(attr) ||
!attr[IPSET_ATTR_SETNAME]))
return -IPSET_ERR_PROTOCOL;
set = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]), &id);
if (id == IPSET_INVALID_ID)
return -ENOENT;
skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!skb2)
return -ENOMEM;
nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
IPSET_CMD_GET_BYNAME);
if (!nlh2)
goto nlmsg_failure;
if (nla_put_u8(skb2, IPSET_ATTR_PROTOCOL, protocol(attr)) ||
nla_put_u8(skb2, IPSET_ATTR_FAMILY, set->family) ||
nla_put_net16(skb2, IPSET_ATTR_INDEX, htons(id)))
goto nla_put_failure;
nlmsg_end(skb2, nlh2);
ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
if (ret < 0)
return ret;
return 0;
nla_put_failure:
nlmsg_cancel(skb2, nlh2);
nlmsg_failure:
kfree_skb(skb2);
return -EMSGSIZE;
}
static const struct nla_policy ip_set_index_policy[IPSET_ATTR_CMD_MAX + 1] = {
[IPSET_ATTR_PROTOCOL] = { .type = NLA_U8 },
[IPSET_ATTR_INDEX] = { .type = NLA_U16 },
};
static int ip_set_byindex(struct net *net, struct sock *ctnl,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const attr[],
struct netlink_ext_ack *extack)
{
struct ip_set_net *inst = ip_set_pernet(net);
struct sk_buff *skb2;
struct nlmsghdr *nlh2;
ip_set_id_t id = IPSET_INVALID_ID;
const struct ip_set *set;
int ret = 0;
if (unlikely(protocol_failed(attr) ||
!attr[IPSET_ATTR_INDEX]))
return -IPSET_ERR_PROTOCOL;
id = ip_set_get_h16(attr[IPSET_ATTR_INDEX]);
if (id >= inst->ip_set_max)
return -ENOENT;
set = ip_set(inst, id);
if (set == NULL)
return -ENOENT;
skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!skb2)
return -ENOMEM;
nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
IPSET_CMD_GET_BYINDEX);
if (!nlh2)
goto nlmsg_failure;
if (nla_put_u8(skb2, IPSET_ATTR_PROTOCOL, protocol(attr)) ||
nla_put_string(skb, IPSET_ATTR_SETNAME, set->name))
goto nla_put_failure;
nlmsg_end(skb2, nlh2); nlmsg_end(skb2, nlh2);
ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT); ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
...@@ -1916,6 +2036,16 @@ static const struct nfnl_callback ip_set_netlink_subsys_cb[IPSET_MSG_MAX] = { ...@@ -1916,6 +2036,16 @@ static const struct nfnl_callback ip_set_netlink_subsys_cb[IPSET_MSG_MAX] = {
.attr_count = IPSET_ATTR_CMD_MAX, .attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_protocol_policy, .policy = ip_set_protocol_policy,
}, },
[IPSET_CMD_GET_BYNAME] = {
.call = ip_set_byname,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname_policy,
},
[IPSET_CMD_GET_BYINDEX] = {
.call = ip_set_byindex,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_index_policy,
},
}; };
static struct nfnetlink_subsystem ip_set_netlink_subsys __read_mostly = { static struct nfnetlink_subsystem ip_set_netlink_subsys __read_mostly = {
...@@ -1961,7 +2091,7 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len) ...@@ -1961,7 +2091,7 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
goto done; goto done;
} }
if (req_version->version != IPSET_PROTOCOL) { if (req_version->version < IPSET_PROTOCOL_MIN) {
ret = -EPROTO; ret = -EPROTO;
goto done; goto done;
} }
......
...@@ -36,9 +36,6 @@ MODULE_ALIAS("ip_set_hash:ip,mac"); ...@@ -36,9 +36,6 @@ MODULE_ALIAS("ip_set_hash:ip,mac");
/* Type specific function prefix */ /* Type specific function prefix */
#define HTYPE hash_ipmac #define HTYPE hash_ipmac
/* Zero valued element is not supported */
static const unsigned char invalid_ether[ETH_ALEN] = { 0 };
/* IPv4 variant */ /* IPv4 variant */
/* Member elements */ /* Member elements */
...@@ -103,8 +100,12 @@ hash_ipmac4_kadt(struct ip_set *set, const struct sk_buff *skb, ...@@ -103,8 +100,12 @@ hash_ipmac4_kadt(struct ip_set *set, const struct sk_buff *skb,
(skb_mac_header(skb) + ETH_HLEN) > skb->data) (skb_mac_header(skb) + ETH_HLEN) > skb->data)
return -EINVAL; return -EINVAL;
memcpy(e.ether, eth_hdr(skb)->h_source, ETH_ALEN); if (opt->flags & IPSET_DIM_ONE_SRC)
if (ether_addr_equal(e.ether, invalid_ether)) ether_addr_copy(e.ether, eth_hdr(skb)->h_source);
else
ether_addr_copy(e.ether, eth_hdr(skb)->h_dest);
if (is_zero_ether_addr(e.ether))
return -EINVAL; return -EINVAL;
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip); ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
...@@ -140,7 +141,7 @@ hash_ipmac4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -140,7 +141,7 @@ hash_ipmac4_uadt(struct ip_set *set, struct nlattr *tb[],
if (ret) if (ret)
return ret; return ret;
memcpy(e.ether, nla_data(tb[IPSET_ATTR_ETHER]), ETH_ALEN); memcpy(e.ether, nla_data(tb[IPSET_ATTR_ETHER]), ETH_ALEN);
if (ether_addr_equal(e.ether, invalid_ether)) if (is_zero_ether_addr(e.ether))
return -IPSET_ERR_HASH_ELEM; return -IPSET_ERR_HASH_ELEM;
return adtfn(set, &e, &ext, &ext, flags); return adtfn(set, &e, &ext, &ext, flags);
...@@ -211,16 +212,16 @@ hash_ipmac6_kadt(struct ip_set *set, const struct sk_buff *skb, ...@@ -211,16 +212,16 @@ hash_ipmac6_kadt(struct ip_set *set, const struct sk_buff *skb,
}; };
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
/* MAC can be src only */
if (!(opt->flags & IPSET_DIM_TWO_SRC))
return 0;
if (skb_mac_header(skb) < skb->head || if (skb_mac_header(skb) < skb->head ||
(skb_mac_header(skb) + ETH_HLEN) > skb->data) (skb_mac_header(skb) + ETH_HLEN) > skb->data)
return -EINVAL; return -EINVAL;
memcpy(e.ether, eth_hdr(skb)->h_source, ETH_ALEN); if (opt->flags & IPSET_DIM_ONE_SRC)
if (ether_addr_equal(e.ether, invalid_ether)) ether_addr_copy(e.ether, eth_hdr(skb)->h_source);
else
ether_addr_copy(e.ether, eth_hdr(skb)->h_dest);
if (is_zero_ether_addr(e.ether))
return -EINVAL; return -EINVAL;
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6); ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
...@@ -260,7 +261,7 @@ hash_ipmac6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -260,7 +261,7 @@ hash_ipmac6_uadt(struct ip_set *set, struct nlattr *tb[],
return ret; return ret;
memcpy(e.ether, nla_data(tb[IPSET_ATTR_ETHER]), ETH_ALEN); memcpy(e.ether, nla_data(tb[IPSET_ATTR_ETHER]), ETH_ALEN);
if (ether_addr_equal(e.ether, invalid_ether)) if (is_zero_ether_addr(e.ether))
return -IPSET_ERR_HASH_ELEM; return -IPSET_ERR_HASH_ELEM;
return adtfn(set, &e, &ext, &ext, flags); return adtfn(set, &e, &ext, &ext, flags);
......
...@@ -81,15 +81,15 @@ hash_mac4_kadt(struct ip_set *set, const struct sk_buff *skb, ...@@ -81,15 +81,15 @@ hash_mac4_kadt(struct ip_set *set, const struct sk_buff *skb,
struct hash_mac4_elem e = { { .foo[0] = 0, .foo[1] = 0 } }; struct hash_mac4_elem e = { { .foo[0] = 0, .foo[1] = 0 } };
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
/* MAC can be src only */
if (!(opt->flags & IPSET_DIM_ONE_SRC))
return 0;
if (skb_mac_header(skb) < skb->head || if (skb_mac_header(skb) < skb->head ||
(skb_mac_header(skb) + ETH_HLEN) > skb->data) (skb_mac_header(skb) + ETH_HLEN) > skb->data)
return -EINVAL; return -EINVAL;
if (opt->flags & IPSET_DIM_ONE_SRC)
ether_addr_copy(e.ether, eth_hdr(skb)->h_source); ether_addr_copy(e.ether, eth_hdr(skb)->h_source);
else
ether_addr_copy(e.ether, eth_hdr(skb)->h_dest);
if (is_zero_ether_addr(e.ether)) if (is_zero_ether_addr(e.ether))
return -EINVAL; return -EINVAL;
return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment