-Wundef \
-Wwrite-strings \
-Wno-missing-field-initializers \
- -Werror \
- -g -ggdb -gdwarf-2 -g3
+ -Werror
endif
if ENABLE_DEBUG
-AM_CFLAGS += -DIPSET_DEBUG
+AM_CFLAGS += -g -ggdb -gdwarf-2 -g3 -DIPSET_DEBUG
endif
if ! ENABLE_VERBOSE
IPSET_OPT_NAMEREF,
IPSET_OPT_IP2,
IPSET_OPT_CIDR2,
+ IPSET_OPT_PROTO,
/* Swap/rename to */
IPSET_OPT_SETNAME2,
/* Flags */
| IPSET_FLAG(IPSET_OPT_NAMEREF) \
| IPSET_FLAG(IPSET_OPT_IP2) \
| IPSET_FLAG(IPSET_OPT_CIDR2) \
+ | IPSET_FLAG(IPSET_OPT_PROTO) \
| IPSET_FLAG(IPSET_OPT_CADT_FLAGS)\
| IPSET_FLAG(IPSET_OPT_BEFORE))
/* Message types and commands */
enum ipset_cmd {
IPSET_CMD_NONE,
- IPSET_CMD_CREATE, /* Create a new (empty) set */
- IPSET_CMD_DESTROY, /* Remove a (empty) set */
- IPSET_CMD_FLUSH, /* Remove all elements from a set */
- IPSET_CMD_RENAME, /* Rename a set */
- IPSET_CMD_SWAP, /* Swap two sets */
- IPSET_CMD_LIST, /* List sets */
- IPSET_CMD_SAVE, /* Save sets */
- IPSET_CMD_ADD, /* Add an element to a set */
- IPSET_CMD_DEL, /* Delete an element from a set */
- IPSET_CMD_TEST, /* Test an element in a set */
- IPSET_CMD_HEADER, /* Get set header data only */
- IPSET_CMD_TYPE, /* Get set type */
- IPSET_CMD_PROTOCOL, /* Return protocol version */
+ IPSET_CMD_CREATE, /* 1: Create a new (empty) set */
+ IPSET_CMD_DESTROY, /* 2: Remove a (empty) set */
+ IPSET_CMD_FLUSH, /* 3: Remove all elements from a set */
+ IPSET_CMD_RENAME, /* 4: Rename a set */
+ IPSET_CMD_SWAP, /* 5: Swap two sets */
+ IPSET_CMD_LIST, /* 6: List sets */
+ IPSET_CMD_SAVE, /* 7: Save sets */
+ IPSET_CMD_ADD, /* 8: Add an element to a set */
+ IPSET_CMD_DEL, /* 9: Delete an element from a set */
+ IPSET_CMD_TEST, /* 10: Test an element in a set */
+ IPSET_CMD_HEADER, /* 11: Get set header data only */
+ IPSET_CMD_TYPE, /* 12: Get set type */
+ IPSET_CMD_PROTOCOL, /* 13: Return protocol version */
IPSET_MSG_MAX, /* Netlink message commands */
/* Commands in userspace: */
- IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* Enter restore mode */
- IPSET_CMD_HELP, /* Get help */
- IPSET_CMD_VERSION, /* Get program version */
- IPSET_CMD_QUIT, /* Quit from interactive mode */
+ IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* 14: Enter restore mode */
+ IPSET_CMD_HELP, /* 15: Get help */
+ IPSET_CMD_VERSION, /* 16: Get program version */
+ IPSET_CMD_QUIT, /* 17: Quit from interactive mode */
IPSET_CMD_MAX,
- IPSET_CMD_COMMIT = IPSET_CMD_MAX, /* Commit buffered commands */
+ IPSET_CMD_COMMIT = IPSET_CMD_MAX, /* 18: Commit buffered commands */
};
/* Attributes at command level */
enum {
IPSET_ATTR_UNSPEC,
- IPSET_ATTR_PROTOCOL, /* Protocol version */
- IPSET_ATTR_SETNAME, /* Name of the set */
- IPSET_ATTR_TYPENAME, /* Typename */
+ IPSET_ATTR_PROTOCOL, /* 1: Protocol version */
+ IPSET_ATTR_SETNAME, /* 2: Name of the set */
+ IPSET_ATTR_TYPENAME, /* 3: Typename */
IPSET_ATTR_SETNAME2 = IPSET_ATTR_TYPENAME, /* rename/swap */
- IPSET_ATTR_REVISION, /* Settype revision */
- IPSET_ATTR_FAMILY, /* Settype family */
- IPSET_ATTR_FLAGS, /* Flags at command level */
- IPSET_ATTR_DATA, /* Nested attributes */
- IPSET_ATTR_ADT, /* Multiple data containers */
- IPSET_ATTR_LINENO, /* Restore lineno */
- IPSET_ATTR_PROTOCOL_MIN,/* Minimal supported version number */
- IPSET_ATTR_REVISION_MIN = IPSET_ATTR_PROTOCOL_MIN, /* type rev min */
+ IPSET_ATTR_REVISION, /* 4: Settype revision */
+ IPSET_ATTR_FAMILY, /* 5: Settype family */
+ IPSET_ATTR_FLAGS, /* 6: Flags at command level */
+ IPSET_ATTR_DATA, /* 7: Nested attributes */
+ IPSET_ATTR_ADT, /* 8: Multiple data containers */
+ IPSET_ATTR_LINENO, /* 9: Restore lineno */
+ IPSET_ATTR_PROTOCOL_MIN, /* 10: Minimal supported version number */
+ IPSET_ATTR_REVISION_MIN = IPSET_ATTR_PROTOCOL_MIN, /* type rev min */
__IPSET_ATTR_CMD_MAX,
};
#define IPSET_ATTR_CMD_MAX (__IPSET_ATTR_CMD_MAX - 1)
enum {
IPSET_ATTR_IP = IPSET_ATTR_UNSPEC + 1,
IPSET_ATTR_IP_FROM = IPSET_ATTR_IP,
- IPSET_ATTR_IP_TO,
- IPSET_ATTR_CIDR,
- IPSET_ATTR_PORT,
+ IPSET_ATTR_IP_TO, /* 2 */
+ IPSET_ATTR_CIDR, /* 3 */
+ IPSET_ATTR_PORT, /* 4 */
IPSET_ATTR_PORT_FROM = IPSET_ATTR_PORT,
- IPSET_ATTR_PORT_TO,
- IPSET_ATTR_TIMEOUT,
- IPSET_ATTR_CADT_FLAGS,
+ IPSET_ATTR_PORT_TO, /* 5 */
+ IPSET_ATTR_TIMEOUT, /* 6 */
+ IPSET_ATTR_PROTO, /* 7 */
+ IPSET_ATTR_CADT_FLAGS, /* 8 */
IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO,
/* Reserve empty slots */
IPSET_ATTR_CADT_MAX = 16,
IPSET_CADT_MAX,
};
+#define IPSET_IPPROTO_ANY 255
+#define IPSET_IPPROTO_TCPUDP 254
+
#endif /* __IP_SET_H */
enum {
IPSET_ERR_HASH_FULL = IPSET_ERR_TYPE_SPECIFIC,
IPSET_ERR_HASH_ELEM,
+ IPSET_ERR_INVALID_PROTO,
+ IPSET_ERR_MISSING_PROTO,
};
#endif /* __IP_SET_HASH_H */
#define IPSET_RANGE_SEPARATOR "-"
#define IPSET_ELEM_SEPARATOR ","
#define IPSET_NAME_SEPARATOR ","
+#define IPSET_PROTO_SEPARATOR ":"
struct ipset_session;
enum ipset_opt opt, const char *str);
extern int ipset_parse_port(struct ipset_session *session,
enum ipset_opt opt, const char *str);
+extern int ipset_parse_proto(struct ipset_session *session,
+ enum ipset_opt opt, const char *str);
+extern int ipset_parse_proto_port(struct ipset_session *session,
+ enum ipset_opt opt, const char *str);
extern int ipset_parse_family(struct ipset_session *session,
enum ipset_opt opt, const char *str);
extern int ipset_parse_ip(struct ipset_session *session,
extern int ipset_print_port(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);
+extern int ipset_print_proto_port(char *buf, unsigned int len,
+ const struct ipset_data *data,
+ enum ipset_opt opt, uint8_t env);
extern int ipset_print_flag(char *buf, unsigned int len,
const struct ipset_data *data, enum ipset_opt opt,
uint8_t env);
extern struct ipset_data * ipset_session_data(const struct ipset_session *session);
extern struct ipset_handle * ipset_session_handle(const struct ipset_session *session);
+extern const struct ipset_type * ipset_saved_type(const struct ipset_session *session);
enum ipset_err_type {
IPSET_ERROR,
/* Message types and commands */
enum ipset_cmd {
IPSET_CMD_NONE,
- IPSET_CMD_CREATE, /* Create a new (empty) set */
- IPSET_CMD_DESTROY, /* Remove a (empty) set */
- IPSET_CMD_FLUSH, /* Remove all elements from a set */
- IPSET_CMD_RENAME, /* Rename a set */
- IPSET_CMD_SWAP, /* Swap two sets */
- IPSET_CMD_LIST, /* List sets */
- IPSET_CMD_SAVE, /* Save sets */
- IPSET_CMD_ADD, /* Add an element to a set */
- IPSET_CMD_DEL, /* Delete an element from a set */
- IPSET_CMD_TEST, /* Test an element in a set */
- IPSET_CMD_HEADER, /* Get set header data only */
- IPSET_CMD_TYPE, /* Get set type */
- IPSET_CMD_PROTOCOL, /* Return protocol version */
+ IPSET_CMD_CREATE, /* 1: Create a new (empty) set */
+ IPSET_CMD_DESTROY, /* 2: Remove a (empty) set */
+ IPSET_CMD_FLUSH, /* 3: Remove all elements from a set */
+ IPSET_CMD_RENAME, /* 4: Rename a set */
+ IPSET_CMD_SWAP, /* 5: Swap two sets */
+ IPSET_CMD_LIST, /* 6: List sets */
+ IPSET_CMD_SAVE, /* 7: Save sets */
+ IPSET_CMD_ADD, /* 8: Add an element to a set */
+ IPSET_CMD_DEL, /* 9: Delete an element from a set */
+ IPSET_CMD_TEST, /* 10: Test an element in a set */
+ IPSET_CMD_HEADER, /* 11: Get set header data only */
+ IPSET_CMD_TYPE, /* 12: Get set type */
+ IPSET_CMD_PROTOCOL, /* 13: Return protocol version */
IPSET_MSG_MAX, /* Netlink message commands */
/* Commands in userspace: */
- IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* Enter restore mode */
- IPSET_CMD_HELP, /* Get help */
- IPSET_CMD_VERSION, /* Get program version */
- IPSET_CMD_QUIT, /* Quit from interactive mode */
+ IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* 14: Enter restore mode */
+ IPSET_CMD_HELP, /* 15: Get help */
+ IPSET_CMD_VERSION, /* 16: Get program version */
+ IPSET_CMD_QUIT, /* 17: Quit from interactive mode */
IPSET_CMD_MAX,
- IPSET_CMD_COMMIT = IPSET_CMD_MAX, /* Commit buffered commands */
+ IPSET_CMD_COMMIT = IPSET_CMD_MAX, /* 18: Commit buffered commands */
};
/* Attributes at command level */
enum {
IPSET_ATTR_UNSPEC,
- IPSET_ATTR_PROTOCOL, /* Protocol version */
- IPSET_ATTR_SETNAME, /* Name of the set */
- IPSET_ATTR_TYPENAME, /* Typename */
+ IPSET_ATTR_PROTOCOL, /* 1: Protocol version */
+ IPSET_ATTR_SETNAME, /* 2: Name of the set */
+ IPSET_ATTR_TYPENAME, /* 3: Typename */
IPSET_ATTR_SETNAME2 = IPSET_ATTR_TYPENAME, /* rename/swap */
- IPSET_ATTR_REVISION, /* Settype revision */
- IPSET_ATTR_FAMILY, /* Settype family */
- IPSET_ATTR_FLAGS, /* Flags at command level */
- IPSET_ATTR_DATA, /* Nested attributes */
- IPSET_ATTR_ADT, /* Multiple data containers */
- IPSET_ATTR_LINENO, /* Restore lineno */
- IPSET_ATTR_PROTOCOL_MIN,/* Minimal supported version number */
- IPSET_ATTR_REVISION_MIN = IPSET_ATTR_PROTOCOL_MIN, /* type rev min */
+ IPSET_ATTR_REVISION, /* 4: Settype revision */
+ IPSET_ATTR_FAMILY, /* 5: Settype family */
+ IPSET_ATTR_FLAGS, /* 6: Flags at command level */
+ IPSET_ATTR_DATA, /* 7: Nested attributes */
+ IPSET_ATTR_ADT, /* 8: Multiple data containers */
+ IPSET_ATTR_LINENO, /* 9: Restore lineno */
+ IPSET_ATTR_PROTOCOL_MIN, /* 10: Minimal supported version number */
+ IPSET_ATTR_REVISION_MIN = IPSET_ATTR_PROTOCOL_MIN, /* type rev min */
__IPSET_ATTR_CMD_MAX,
};
#define IPSET_ATTR_CMD_MAX (__IPSET_ATTR_CMD_MAX - 1)
enum {
IPSET_ATTR_IP = IPSET_ATTR_UNSPEC + 1,
IPSET_ATTR_IP_FROM = IPSET_ATTR_IP,
- IPSET_ATTR_IP_TO,
- IPSET_ATTR_CIDR,
- IPSET_ATTR_PORT,
+ IPSET_ATTR_IP_TO, /* 2 */
+ IPSET_ATTR_CIDR, /* 3 */
+ IPSET_ATTR_PORT, /* 4 */
IPSET_ATTR_PORT_FROM = IPSET_ATTR_PORT,
- IPSET_ATTR_PORT_TO,
- IPSET_ATTR_TIMEOUT,
- IPSET_ATTR_CADT_FLAGS,
+ IPSET_ATTR_PORT_TO, /* 5 */
+ IPSET_ATTR_TIMEOUT, /* 6 */
+ IPSET_ATTR_PROTO, /* 7 */
+ IPSET_ATTR_CADT_FLAGS, /* 8 */
IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO,
/* Reserve empty slots */
IPSET_ATTR_CADT_MAX = 16,
IPSET_CADT_MAX,
};
+#define IPSET_IPPROTO_ANY 255
+#define IPSET_IPPROTO_TCPUDP 254
+
#ifdef __KERNEL__
#include <linux/ip.h>
#include <linux/ipv6.h>
vfree(members);
}
+static inline bool
+ip_set_eexist(int ret, u32 flags)
+{
+ return ret == -IPSET_ERR_EXIST && (flags & IPSET_FLAG_EXIST);
+}
+
/* Useful converters */
static inline u32
ip_set_get_h32(const struct nlattr *attr)
#ifdef IP_SET_HASH_WITH_NETMASK
u8 netmask; /* netmask value for subnets to store */
#endif
+#ifdef IP_SET_HASH_WITH_PROTO
+ u8 proto; /* default protocol for SET target */
+#endif
#ifdef IP_SET_HASH_WITH_NETS
struct chash_nets nets[0]; /* book keeping of networks */
#endif
/* Flavour without timeout */
-#define chash_data(n, i) \
-(struct type_pf_elem *)((char *)(n) + sizeof(struct slist) + (i)*sizeof(struct type_pf_elem))
+#define chash_data(n, i) \
+(struct type_pf_elem *)((char *)(n) + sizeof(struct slist) \
+ + (i)*sizeof(struct type_pf_elem))
static int
type_pf_chash_readd(struct chash *h, struct slist *t, u8 htable_bits,
#ifdef IP_SET_HASH_WITH_NETMASK
if (h->netmask != HOST_MASK)
NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, h->netmask);
+#endif
+#ifdef IP_SET_HASH_WITH_PROTO
+ if (h->proto != IPSET_IPPROTO_TCPUDP)
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, h->proto);
#endif
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
htonl(atomic_read(&set->ref) - 1));
#define IPSET_INVALID_PORT 65536
/* We must handle non-linear skbs */
-static bool
-get_port(u8 pf, const struct sk_buff *skb, bool src, u16 *port)
-{
- unsigned short protocol;
- unsigned int protoff;
- int fragoff;
-
- switch (pf) {
- case AF_INET: {
- const struct iphdr *iph = ip_hdr(skb);
-
- protocol = iph->protocol;
- fragoff = ntohs(iph->frag_off) & IP_OFFSET;
- protoff = ip_hdrlen(skb);
- break;
- }
- case AF_INET6: {
- int protohdr;
- unsigned short frag_off;
-
- protohdr = ipv6_find_hdr(skb, &protoff, -1, &frag_off);
- if (protohdr < 0)
- return false;
-
- protocol = protohdr;
- fragoff = frag_off;
- break;
- }
- default:
- return false;
- }
-
- /* See comments at tcp_match in ip_tables.c */
- if (fragoff)
- return false;
+static inline bool
+get_port(const struct sk_buff *skb, int protocol, unsigned int protooff,
+ bool src, u16 *port, u8 *proto)
+{
switch (protocol) {
case IPPROTO_TCP: {
struct tcphdr _tcph;
const struct tcphdr *th;
- th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
+ th = skb_header_pointer(skb, protooff, sizeof(_tcph), &_tcph);
if (th == NULL)
/* No choice either */
return false;
*port = src ? th->source : th->dest;
break;
- }
+ }
case IPPROTO_UDP: {
struct udphdr _udph;
const struct udphdr *uh;
- uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
+ uh = skb_header_pointer(skb, protooff, sizeof(_udph), &_udph);
if (uh == NULL)
/* No choice either */
return false;
*port = src ? uh->source : uh->dest;
break;
- }
+ }
default:
- return false;
+ if (*proto == IPSET_IPPROTO_TCPUDP)
+ return false;
+ break;
}
+ if (*proto != IPSET_IPPROTO_TCPUDP)
+ *proto = protocol;
+
return true;
}
+
+static inline bool
+get_ip4_port(const struct sk_buff *skb, bool src, u16 *port, u8 *proto)
+{
+ const struct iphdr *iph = ip_hdr(skb);
+ unsigned int protooff = ip_hdrlen(skb);
+ int protocol = iph->protocol;
+
+ if (!(*proto >= IPSET_IPPROTO_TCPUDP || *proto == protocol))
+ return false;
+
+ /* See comments at tcp_match in ip_tables.c */
+ if (ntohs(iph->frag_off) & IP_OFFSET)
+ return false;
+
+ return get_port(skb, protocol, protooff, src, port, proto);
+}
+
+static inline bool
+get_ip6_port(const struct sk_buff *skb, bool src, u16 *port, u8 *proto)
+{
+ unsigned int *protooff = 0;
+ int protocol;
+ unsigned short fragoff;
+
+ protocol = ipv6_find_hdr(skb, protooff, -1, &fragoff);
+ if (protocol < 0 || fragoff)
+ return false;
+
+ if (!(*proto >= IPSET_IPPROTO_TCPUDP || *proto == protocol))
+ return false;
+
+ return get_port(skb, protocol, *protooff, src, port, proto);
+}
+
+static inline bool
+get_ip_port(const struct sk_buff *skb, u8 pf, bool src, u16 *port)
+{
+ u8 proto = IPSET_IPPROTO_TCPUDP;
+
+ if (pf == AF_INET)
+ return get_ip4_port(skb, src, port, &proto);
+ else
+ return get_ip6_port(skb, src, port, &proto);
+}
#endif /* __KERNEL__ */
#endif /*_IP_SET_GETPORT_H*/
enum {
IPSET_ERR_HASH_FULL = IPSET_ERR_TYPE_SPECIFIC,
IPSET_ERR_HASH_ELEM,
+ IPSET_ERR_INVALID_PROTO,
+ IPSET_ERR_MISSING_PROTO,
};
#ifdef __KERNEL__
.len = IPSET_MAXNAMELEN - 1},
[IPSET_ATTR_REVISION] = { .type = NLA_U8 },
[IPSET_ATTR_FAMILY] = { .type = NLA_U8 },
- [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
[IPSET_ATTR_DATA] = { .type = NLA_NESTED },
};
[IPSET_ATTR_IP_TO] = { .type = NLA_U32 },
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
};
static int
{
struct bitmap_ip *map = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX];
- bool eexist = flags & IPSET_FLAG_EXIST;
u32 ip, ip_to, id;
int ret = 0;
bitmap_ip_adt_policy))
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_LINENO])
+ *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
if (tb[IPSET_ATTR_IP])
ip = ip_set_get_h32(tb[IPSET_ATTR_IP]);
else
ret = adt == IPSET_ADD ? bitmap_ip_add(map, id)
: bitmap_ip_del(map, id);
- if (ret && !(ret == -IPSET_ERR_EXIST && eexist)) {
- if (tb[IPSET_ATTR_LINENO])
- *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+ if (ret && !ip_set_eexist(ret, flags))
return ret;
- }
+ else
+ ret = 0;
}
return ret;
}
{
struct bitmap_ip_timeout *map = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX];
- bool eexist = flags & IPSET_FLAG_EXIST;
u32 ip, ip_to, id, timeout = map->timeout;
int ret = 0;
bitmap_ip_adt_policy))
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_LINENO])
+ *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
if (tb[IPSET_ATTR_IP])
ip = ip_set_get_h32(tb[IPSET_ATTR_IP]);
else
? bitmap_ip_timeout_add(map, id, timeout)
: bitmap_ip_timeout_del(map, id);
- if (ret && !(ret == -IPSET_ERR_EXIST && eexist)) {
- if (tb[IPSET_ATTR_LINENO])
- *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+ if (ret && !ip_set_eexist(ret, flags))
return ret;
- }
+ else
+ ret = 0;
}
return ret;
}
[IPSET_ATTR_IP] = { .type = NLA_U32 },
[IPSET_ATTR_ETHER] = { .type = NLA_BINARY, .len = ETH_ALEN },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
};
static int
struct bitmap_ipmac *map = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX];
ipset_adtfn adtfn = set->variant->adt[adt];
- bool eexist = flags & IPSET_FLAG_EXIST;
struct ipmac data;
u32 timeout = map->timeout;
int ret = 0;
bitmap_ipmac_adt_policy))
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_LINENO])
+ *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
if (tb[IPSET_ATTR_IP])
data.id = ip_set_get_h32(tb[IPSET_ATTR_IP]);
else
ret = adtfn(set, &data, GFP_KERNEL, timeout);
- if (ret && !(ret == -IPSET_ERR_EXIST && eexist)) {
- if (tb[IPSET_ATTR_LINENO])
- *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- }
- return ret;
+ return ip_set_eexist(ret, flags) ? 0 : ret;
}
static void
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
{
struct bitmap_port *map = set->data;
- u16 port;
+ u16 port = 0;
- if (!get_port(pf, skb, flags & IPSET_DIM_ONE_SRC, &port))
+ if (!get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &port))
return -EINVAL;
port = ntohs(port);
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
[IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
};
static int
{
struct bitmap_port *map = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX];
- bool eexist = flags & IPSET_FLAG_EXIST;
u32 port; /* wraparound */
u16 id, port_to;
int ret = 0;
bitmap_port_adt_policy))
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_LINENO])
+ *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
if (tb[IPSET_ATTR_PORT])
port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
else
ret = adt == IPSET_ADD ? bitmap_port_add(map, id)
: bitmap_port_del(map, id);
- if (ret && !(ret == -IPSET_ERR_EXIST && eexist)) {
- if (tb[IPSET_ATTR_LINENO])
- *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+ if (ret && !ip_set_eexist(ret, flags))
return ret;
- }
+ else
+ ret = 0;
}
return ret;
}
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
{
struct bitmap_port_timeout *map = set->data;
- u16 port;
+ u16 port = 0;
- if (!get_port(pf, skb, flags & IPSET_DIM_ONE_SRC, &port))
+ if (!get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &port))
return -EINVAL;
port = ntohs(port);
{
const struct bitmap_port_timeout *map = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX];
- bool eexist = flags & IPSET_FLAG_EXIST;
u16 id, port_to;
u32 port, timeout = map->timeout; /* wraparound */
int ret = 0;
bitmap_port_adt_policy))
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_LINENO])
+ *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
if (tb[IPSET_ATTR_PORT])
port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
else
? bitmap_port_timeout_add(map, id, timeout)
: bitmap_port_timeout_del(map, id);
- if (ret && !(ret == -IPSET_ERR_EXIST && eexist)) {
- if (tb[IPSET_ATTR_LINENO])
- *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+ if (ret && !ip_set_eexist(ret, flags))
return ret;
- }
+ else
+ ret = 0;
}
return ret;
}
[IPSET_ATTR_IP_TO] = { .type = NLA_U32 },
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
};
static int
{
struct chash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX];
- bool eexist = flags & IPSET_FLAG_EXIST;
ipset_adtfn adtfn = set->variant->adt[adt];
u32 ip, nip, ip_to, hosts, timeout = h->timeout;
int ret = 0;
hash_ip4_adt_policy))
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_LINENO])
+ *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
if (tb[IPSET_ATTR_IP])
ip = ip_set_get_n32(tb[IPSET_ATTR_IP]);
else
nip = htonl(ip);
ret = adtfn(set, &nip, GFP_KERNEL, timeout);
- if (ret && !(ret == -IPSET_ERR_EXIST && eexist)) {
- if (tb[IPSET_ATTR_LINENO])
- *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+ if (ret && !ip_set_eexist(ret, flags))
return ret;
- }
+ else
+ ret = 0;
}
return ret;
}
return x->maxelem == y->maxelem
&& x->timeout == y->timeout
+ && x->netmask == y->netmask
&& x->htable_bits == y->htable_bits /* resizing ? */
&& x->array_size == y->array_size
- && x->chain_limit == y->chain_limit
- && x->netmask == y->netmask;
+ && x->chain_limit == y->chain_limit;
}
/* The type variant functions: IPv6 */
[IPSET_ATTR_IP] = { .type = NLA_BINARY,
.len = sizeof(struct in6_addr) },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
};
static int
ipset_adtfn adtfn = set->variant->adt[adt];
union nf_inet_addr *ip;
u32 timeout = h->timeout;
+ int ret;
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
hash_ip6_adt_policy))
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_LINENO])
+ *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
if (tb[IPSET_ATTR_IP])
ip = nla_data(tb[IPSET_ATTR_IP]);
else
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
- return adtfn(set, ip, GFP_KERNEL, timeout);
+ ret = adtfn(set, ip, GFP_KERNEL, timeout);
+
+ return ip_set_eexist(ret, flags) ? 0 : ret;
}
/* Create hash:ip type of sets */
struct hash_ipport4_elem {
u32 ip;
u16 port;
- u16 match;
+ u8 proto;
+ u8 padding;
};
/* Member elements with timeout support */
struct hash_ipport4_telem {
u32 ip;
u16 port;
- u16 match;
+ u8 proto;
+ u8 padding;
unsigned long timeout;
};
hash_ipport4_data_equal(const struct hash_ipport4_elem *ip1,
const struct hash_ipport4_elem *ip2)
{
- return ip1->ip == ip2->ip && ip1->port == ip2->port;
+ return ip1->ip == ip2->ip
+ && ip1->port == ip2->port
+ && ip1->proto == ip2->proto;
}
static inline bool
hash_ipport4_data_isnull(const struct hash_ipport4_elem *elem)
{
- return elem->match == 0;
+ return elem->proto == 0;
}
static inline void
{
dst->ip = src->ip;
dst->port = src->port;
- dst->match = 1;
+ dst->proto = src->proto;
}
static inline void
{
swap(dst->ip, src->ip);
swap(dst->port, src->port);
+ swap(dst->proto, src->proto);
}
static inline void
hash_ipport4_data_zero_out(struct hash_ipport4_elem *elem)
{
- elem->match = 0;
+ elem->proto = 0;
}
static inline bool
{
NLA_PUT_NET32(skb, IPSET_ATTR_IP, data->ip);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
+ if (data->proto != IPSET_IPPROTO_TCPUDP)
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
return 0;
nla_put_failure:
NLA_PUT_NET32(skb, IPSET_ATTR_IP, tdata->ip);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
+ if (data->proto != IPSET_IPPROTO_TCPUDP)
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(tdata->timeout)));
return 1;
}
+#define IP_SET_HASH_WITH_PROTO
+
#define PF 4
#define HOST_MASK 32
#include <linux/netfilter/ip_set_chash.h>
{
struct chash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipport4_elem data = {};
+ struct hash_ipport4_elem data = { .proto = h->proto };
- ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
- if (!get_port(AF_INET, skb, flags & IPSET_DIM_TWO_SRC, &data.port))
+ if (!get_ip4_port(skb, flags & IPSET_DIM_ONE_SRC,
+ &data.port, &data.proto))
return -EINVAL;
+ ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
+
return adtfn(set, &data, GFP_ATOMIC, h->timeout);
}
hash_ipport4_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
[IPSET_ATTR_IP] = { .type = NLA_U32 },
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
+ [IPSET_ATTR_PROTO] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
};
static int
{
struct chash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX];
- bool eexist = flags & IPSET_FLAG_EXIST;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipport4_elem data = {};
+ struct hash_ipport4_elem data = { .proto = h->proto };
u32 timeout = h->timeout;
int ret;
hash_ipport4_adt_policy))
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_LINENO])
+ *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
if (tb[IPSET_ATTR_IP])
data.ip = ip_set_get_n32(tb[IPSET_ATTR_IP]);
else
else
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_PROTO]) {
+ data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+
+ if (data.proto == 0 || data.proto >= IPSET_IPPROTO_TCPUDP)
+ return -IPSET_ERR_INVALID_PROTO;
+ } else if (data.proto == IPSET_IPPROTO_ANY)
+ return -IPSET_ERR_MISSING_PROTO;
+
+ switch (data.proto) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ case IPSET_IPPROTO_TCPUDP:
+ break;
+ default:
+ data.port = 0;
+ break;
+ }
+
if (tb[IPSET_ATTR_TIMEOUT]) {
if (!with_timeout(h->timeout))
return -IPSET_ERR_TIMEOUT;
ret = adtfn(set, &data, GFP_KERNEL, timeout);
- if (ret && !(ret == -IPSET_ERR_EXIST && eexist)) {
- if (tb[IPSET_ATTR_LINENO])
- *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- }
- return ret;
+ return ip_set_eexist(ret, flags) ? 0 : ret;
}
static bool
return x->maxelem == y->maxelem
&& x->timeout == y->timeout
+ && x->proto == y->proto
&& x->htable_bits == y->htable_bits /* resizing ? */
&& x->array_size == y->array_size
&& x->chain_limit == y->chain_limit;
struct hash_ipport6_elem {
union nf_inet_addr ip;
u16 port;
- u16 match;
+ u8 proto;
+ u8 padding;
};
struct hash_ipport6_telem {
union nf_inet_addr ip;
u16 port;
- u16 match;
+ u8 proto;
+ u8 padding;
unsigned long timeout;
};
const struct hash_ipport6_elem *ip2)
{
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0
- && ip1->port == ip2->port;
+ && ip1->port == ip2->port
+ && ip1->proto == ip2->proto;
}
static inline bool
hash_ipport6_data_isnull(const struct hash_ipport6_elem *elem)
{
- return elem->match == 0;
+ return elem->proto == 0;
}
static inline void
const struct hash_ipport6_elem *src)
{
memcpy(dst, src, sizeof(*dst));
- dst->match = 1;
}
static inline void
static inline void
hash_ipport6_data_zero_out(struct hash_ipport6_elem *elem)
{
- elem->match = 0;
+ elem->proto = 0;
}
static inline bool
{
NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &data->ip);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
+ if (data->proto != IPSET_IPPROTO_TCPUDP)
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
return 0;
nla_put_failure:
NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &e->ip);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
+ if (data->proto != IPSET_IPPROTO_TCPUDP)
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(e->timeout)));
return 0;
{
struct chash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipport6_elem data = {};
+ struct hash_ipport6_elem data = { .proto = h->proto };
- ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
- if (!get_port(AF_INET, skb, flags & IPSET_DIM_TWO_SRC, &data.port))
+ if (!get_ip6_port(skb, flags & IPSET_DIM_ONE_SRC,
+ &data.port, &data.proto))
return -EINVAL;
+ ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
+
return adtfn(set, &data, GFP_ATOMIC, h->timeout);
}
[IPSET_ATTR_IP] = { .type = NLA_BINARY,
.len = sizeof(struct in6_addr) },
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
+ [IPSET_ATTR_PROTO] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
};
static int
struct chash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX];
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipport6_elem data = {};
+ struct hash_ipport6_elem data = { .proto = h->proto };
u32 timeout = h->timeout;
+ int ret;
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
hash_ipport6_adt_policy))
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_LINENO])
+ *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
if (tb[IPSET_ATTR_IP])
memcpy(&data.ip, nla_data(tb[IPSET_ATTR_IP]),
sizeof(struct in6_addr));
else
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_PROTO]) {
+ data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+
+ if (data.proto == 0 || data.proto >= IPSET_IPPROTO_TCPUDP)
+ return -IPSET_ERR_INVALID_PROTO;
+ } else if (data.proto == IPSET_IPPROTO_ANY)
+ return -IPSET_ERR_MISSING_PROTO;
+
+ switch (data.proto) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ case IPSET_IPPROTO_TCPUDP:
+ break;
+ default:
+ data.port = 0;
+ break;
+ }
+
if (tb[IPSET_ATTR_TIMEOUT]) {
if (!with_timeout(h->timeout))
return -IPSET_ERR_TIMEOUT;
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
- return adtfn(set, &data, GFP_KERNEL, timeout);
+ ret = adtfn(set, &data, GFP_KERNEL, timeout);
+
+ return ip_set_eexist(ret, flags) ? 0 : ret;
}
/* Create hash:ip type of sets */
[IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
[IPSET_ATTR_PROBES] = { .type = NLA_U8 },
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
+ [IPSET_ATTR_PROTO] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
};
hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
{
struct nlattr *tb[IPSET_ATTR_CREATE_MAX];
- u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
struct chash *h;
+ u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
+ u8 proto = IPSET_IPPROTO_TCPUDP; /* Backward compatibility */
if (!(set->family == AF_INET || set->family == AF_INET6))
return -IPSET_ERR_INVALID_FAMILY;
if (tb[IPSET_ATTR_MAXELEM])
maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
+ if (tb[IPSET_ATTR_PROTO]) {
+ proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+ if (!proto)
+ return -IPSET_ERR_INVALID_PROTO;
+ }
+
h = kzalloc(sizeof(*h), GFP_KERNEL);
if (!h)
return -ENOMEM;
h->array_size = CHASH_DEFAULT_ARRAY_SIZE;
h->chain_limit = CHASH_DEFAULT_CHAIN_LIMIT;
get_random_bytes(&h->initval, sizeof(h->initval));
+ h->proto = proto;
h->timeout = IPSET_NO_TIMEOUT;
h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist),
u32 ip;
u32 ip2;
u16 port;
- u16 match;
+ u8 proto;
+ u8 padding;
};
/* Member elements with timeout support */
u32 ip;
u32 ip2;
u16 port;
- u16 match;
+ u8 proto;
+ u8 padding;
unsigned long timeout;
};
{
return ip1->ip == ip2->ip
&& ip1->ip2 == ip2->ip2
- && ip1->port == ip2->port;
+ && ip1->port == ip2->port
+ && ip1->proto == ip2->proto;
}
static inline bool
hash_ipportip4_data_isnull(const struct hash_ipportip4_elem *elem)
{
- return elem->match == 0;
+ return elem->proto == 0;
}
static inline void
const struct hash_ipportip4_elem *src)
{
memcpy(dst, src, sizeof(*dst));
- dst->match = 1;
}
static inline void
static inline void
hash_ipportip4_data_zero_out(struct hash_ipportip4_elem *elem)
{
- elem->match = 0;
+ elem->proto = 0;
}
static inline bool
NLA_PUT_NET32(skb, IPSET_ATTR_IP, data->ip);
NLA_PUT_NET32(skb, IPSET_ATTR_IP2, data->ip2);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
+ if (data->proto != IPSET_IPPROTO_TCPUDP)
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
return 0;
nla_put_failure:
NLA_PUT_NET32(skb, IPSET_ATTR_IP, tdata->ip);
NLA_PUT_NET32(skb, IPSET_ATTR_IP2, tdata->ip2);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
+ if (data->proto != IPSET_IPPROTO_TCPUDP)
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(tdata->timeout)));
return 1;
}
+#define IP_SET_HASH_WITH_PROTO
+
#define PF 4
#define HOST_MASK 32
#include <linux/netfilter/ip_set_chash.h>
{
struct chash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipportip4_elem data = {};
+ struct hash_ipportip4_elem data = { .proto = h->proto };
- ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
- if (!get_port(AF_INET, skb, flags & IPSET_DIM_TWO_SRC, &data.port))
+ if (!get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
+ &data.port, &data.proto))
return -EINVAL;
+
+ ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
return adtfn(set, &data, GFP_ATOMIC, h->timeout);
[IPSET_ATTR_IP] = { .type = NLA_U32 },
[IPSET_ATTR_IP2] = { .type = NLA_U32 },
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
+ [IPSET_ATTR_PROTO] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
};
static int
{
struct chash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX];
- bool eexist = flags & IPSET_FLAG_EXIST;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipportip4_elem data = {};
+ struct hash_ipportip4_elem data = { .proto = h->proto };
u32 timeout = h->timeout;
int ret;
hash_ipportip4_adt_policy))
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_LINENO])
+ *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
if (tb[IPSET_ATTR_IP])
data.ip = ip_set_get_n32(tb[IPSET_ATTR_IP]);
else
else
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_PROTO]) {
+ data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+
+ if (data.proto == 0 || data.proto >= IPSET_IPPROTO_TCPUDP)
+ return -IPSET_ERR_INVALID_PROTO;
+ } else if (data.proto == IPSET_IPPROTO_ANY)
+ return -IPSET_ERR_MISSING_PROTO;
+
+ switch (data.proto) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ case IPSET_IPPROTO_TCPUDP:
+ break;
+ default:
+ data.port = 0;
+ break;
+ }
+
if (tb[IPSET_ATTR_TIMEOUT]) {
if (!with_timeout(h->timeout))
return -IPSET_ERR_TIMEOUT;
ret = adtfn(set, &data, GFP_KERNEL, timeout);
- if (ret && !(ret == -IPSET_ERR_EXIST && eexist)) {
- if (tb[IPSET_ATTR_LINENO])
- *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- }
- return ret;
+ return ip_set_eexist(ret, flags) ? 0 : ret;
}
static bool
return x->maxelem == y->maxelem
&& x->timeout == y->timeout
+ && x->proto == y->proto
&& x->htable_bits == y->htable_bits /* resizing ? */
&& x->array_size == y->array_size
&& x->chain_limit == y->chain_limit;
union nf_inet_addr ip;
union nf_inet_addr ip2;
u16 port;
- u16 match;
+ u8 proto;
+ u8 padding;
};
struct hash_ipportip6_telem {
union nf_inet_addr ip;
union nf_inet_addr ip2;
u16 port;
- u16 match;
+ u8 proto;
+ u8 padding;
unsigned long timeout;
};
{
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0
&& ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0
- && ip1->port == ip2->port;
+ && ip1->port == ip2->port
+ && ip1->proto == ip2->proto;
}
static inline bool
hash_ipportip6_data_isnull(const struct hash_ipportip6_elem *elem)
{
- return elem->match == 0;
+ return elem->proto == 0;
}
static inline void
const struct hash_ipportip6_elem *src)
{
memcpy(dst, src, sizeof(*dst));
- dst->match = 1;
}
static inline void
static inline void
hash_ipportip6_data_zero_out(struct hash_ipportip6_elem *elem)
{
- elem->match = 0;
+ elem->proto = 0;
}
static inline bool
NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &data->ip);
NLA_PUT(skb, IPSET_ATTR_IP2, sizeof(struct in6_addr), &data->ip2);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
+ if (data->proto != IPSET_IPPROTO_TCPUDP)
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
return 0;
nla_put_failure:
NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &e->ip);
NLA_PUT(skb, IPSET_ATTR_IP2, sizeof(struct in6_addr), &data->ip2);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
+ if (data->proto != IPSET_IPPROTO_TCPUDP)
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(e->timeout)));
return 0;
{
struct chash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipportip6_elem data = {};
+ struct hash_ipportip6_elem data = { .proto = h->proto };
- ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
- if (!get_port(AF_INET, skb, flags & IPSET_DIM_TWO_SRC, &data.port))
+ if (!get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
+ &data.port, &data.proto))
return -EINVAL;
+
+ ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
return adtfn(set, &data, GFP_ATOMIC, h->timeout);
[IPSET_ATTR_IP2] = { .type = NLA_BINARY,
.len = sizeof(struct in6_addr) },
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
+ [IPSET_ATTR_PROTO] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
};
static int
struct chash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX];
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipportip6_elem data = {};
+ struct hash_ipportip6_elem data = { .proto = h->proto };
u32 timeout = h->timeout;
+ int ret;
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
hash_ipportip6_adt_policy))
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_LINENO])
+ *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
if (tb[IPSET_ATTR_IP])
memcpy(&data.ip, nla_data(tb[IPSET_ATTR_IP]),
sizeof(struct in6_addr));
else
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_PROTO]) {
+ data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+
+ if (data.proto == 0 || data.proto >= IPSET_IPPROTO_TCPUDP)
+ return -IPSET_ERR_INVALID_PROTO;
+ } else if (data.proto == IPSET_IPPROTO_ANY)
+ return -IPSET_ERR_MISSING_PROTO;
+
+ switch (data.proto) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ case IPSET_IPPROTO_TCPUDP:
+ break;
+ default:
+ data.port = 0;
+ break;
+ }
+
if (tb[IPSET_ATTR_TIMEOUT]) {
if (!with_timeout(h->timeout))
return -IPSET_ERR_TIMEOUT;
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
- return adtfn(set, &data, GFP_KERNEL, timeout);
+ ret = adtfn(set, &data, GFP_KERNEL, timeout);
+
+ return ip_set_eexist(ret, flags) ? 0 : ret;
}
/* Create hash:ip type of sets */
[IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
[IPSET_ATTR_PROBES] = { .type = NLA_U8 },
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
+ [IPSET_ATTR_PROTO] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
};
int len, u32 flags)
{
struct nlattr *tb[IPSET_ATTR_CREATE_MAX];
- u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
struct chash *h;
+ u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
+ u8 proto = IPSET_IPPROTO_TCPUDP; /* Backward compatibility */
if (!(set->family == AF_INET || set->family == AF_INET6))
return -IPSET_ERR_INVALID_FAMILY;
if (tb[IPSET_ATTR_MAXELEM])
maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
+ if (tb[IPSET_ATTR_PROTO]) {
+ proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+ if (!proto)
+ return -IPSET_ERR_INVALID_PROTO;
+ }
+
h = kzalloc(sizeof(*h), GFP_KERNEL);
if (!h)
return -ENOMEM;
h->array_size = CHASH_DEFAULT_ARRAY_SIZE;
h->chain_limit = CHASH_DEFAULT_CHAIN_LIMIT;
get_random_bytes(&h->initval, sizeof(h->initval));
+ h->proto = proto;
h->timeout = IPSET_NO_TIMEOUT;
h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist),
u32 ip2;
u16 port;
u8 cidr;
- u8 match;
+ u8 proto;
};
/* Member elements with timeout support */
u32 ip2;
u16 port;
u8 cidr;
- u8 match;
+ u8 proto;
unsigned long timeout;
};
return ip1->ip == ip2->ip
&& ip1->ip2 == ip2->ip2
&& ip1->cidr == ip2->cidr
- && ip1->port == ip2->port;
+ && ip1->port == ip2->port
+ && ip1->proto == ip2->proto;
}
static inline bool
hash_ipportnet4_data_isnull(const struct hash_ipportnet4_elem *elem)
{
- return elem->match == 0;
+ return elem->proto == 0;
}
static inline void
const struct hash_ipportnet4_elem *src)
{
memcpy(dst, src, sizeof(*dst));
- dst->match = 1;
}
static inline void
static inline void
hash_ipportnet4_data_zero_out(struct hash_ipportnet4_elem *elem)
{
- elem->match = 0;
+ elem->proto = 0;
}
static inline bool
NLA_PUT_NET32(skb, IPSET_ATTR_IP2, data->ip2);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
+ if (data->proto != IPSET_IPPROTO_TCPUDP)
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
return 0;
nla_put_failure:
NLA_PUT_NET32(skb, IPSET_ATTR_IP2, tdata->ip2);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
+ if (data->proto != IPSET_IPPROTO_TCPUDP)
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(tdata->timeout)));
return 1;
}
+#define IP_SET_HASH_WITH_PROTO
#define IP_SET_HASH_WITH_NETS
#define PF 4
struct chash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportnet4_elem data =
- { .cidr = h->nets[0].cidr || HOST_MASK };
-
+ { .cidr = h->nets[0].cidr || HOST_MASK,
+ .proto = h->proto };
+
if (data.cidr == 0)
return -EINVAL;
if (adt == IPSET_TEST)
data.cidr = HOST_MASK;
- ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
- if (!get_port(AF_INET, skb, flags & IPSET_DIM_TWO_SRC, &data.port))
+ if (!get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
+ &data.port, &data.proto))
return -EINVAL;
+
+ ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
data.ip2 &= NETMASK(data.cidr);
[IPSET_ATTR_IP2] = { .type = NLA_U32 },
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
[IPSET_ATTR_CIDR2] = { .type = NLA_U8 },
+ [IPSET_ATTR_PROTO] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
};
static int
{
struct chash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX];
- bool eexist = flags & IPSET_FLAG_EXIST;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipportnet4_elem data = { .cidr = HOST_MASK };
+ struct hash_ipportnet4_elem data = { .cidr = HOST_MASK,
+ .proto = h->proto };
u32 timeout = h->timeout;
int ret;
hash_ipportnet4_adt_policy))
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_LINENO])
+ *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
if (tb[IPSET_ATTR_IP])
data.ip = ip_set_get_n32(tb[IPSET_ATTR_IP]);
else
else
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_PROTO]) {
+ data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+
+ if (data.proto == 0 || data.proto >= IPSET_IPPROTO_TCPUDP)
+ return -IPSET_ERR_INVALID_PROTO;
+ } else if (data.proto == IPSET_IPPROTO_ANY)
+ return -IPSET_ERR_MISSING_PROTO;
+
+ switch (data.proto) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ case IPSET_IPPROTO_TCPUDP:
+ break;
+ default:
+ data.port = 0;
+ break;
+ }
+
if (tb[IPSET_ATTR_TIMEOUT]) {
if (!with_timeout(h->timeout))
return -IPSET_ERR_TIMEOUT;
ret = adtfn(set, &data, GFP_KERNEL, timeout);
- if (ret && !(ret == -IPSET_ERR_EXIST && eexist)) {
- if (tb[IPSET_ATTR_LINENO])
- *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- }
- return ret;
+ return ip_set_eexist(ret, flags) ? 0 : ret;
}
static bool
return x->maxelem == y->maxelem
&& x->timeout == y->timeout
+ && x->proto == y->proto
&& x->htable_bits == y->htable_bits /* resizing ? */
&& x->array_size == y->array_size
&& x->chain_limit == y->chain_limit;
union nf_inet_addr ip2;
u16 port;
u8 cidr;
- u8 match;
+ u8 proto;
};
struct hash_ipportnet6_telem {
union nf_inet_addr ip2;
u16 port;
u8 cidr;
- u8 match;
+ u8 proto;
unsigned long timeout;
};
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0
&& ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0
&& ip1->cidr == ip2->cidr
- && ip1->port == ip2->port;
+ && ip1->port == ip2->port
+ && ip1->proto == ip2->proto;
}
static inline bool
hash_ipportnet6_data_isnull(const struct hash_ipportnet6_elem *elem)
{
- return elem->match == 0;
+ return elem->proto == 0;
}
static inline void
const struct hash_ipportnet6_elem *src)
{
memcpy(dst, src, sizeof(*dst));
- dst->match = 1;
}
static inline void
static inline void
hash_ipportnet6_data_zero_out(struct hash_ipportnet6_elem *elem)
{
- elem->match = 0;
+ elem->proto = 0;
}
static inline void
NLA_PUT(skb, IPSET_ATTR_IP2, sizeof(struct in6_addr), &data->ip2);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
+ if (data->proto != IPSET_IPPROTO_TCPUDP)
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
return 0;
nla_put_failure:
NLA_PUT(skb, IPSET_ATTR_IP2, sizeof(struct in6_addr), &data->ip2);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
+ if (data->proto != IPSET_IPPROTO_TCPUDP)
+ NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(e->timeout)));
return 0;
struct chash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportnet6_elem data =
- { .cidr = h->nets[0].cidr || HOST_MASK };
+ { .cidr = h->nets[0].cidr || HOST_MASK,
+ .proto = h->proto };
if (data.cidr == 0)
return -EINVAL;
if (adt == IPSET_TEST)
data.cidr = HOST_MASK;
- ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
- if (!get_port(AF_INET, skb, flags & IPSET_DIM_TWO_SRC, &data.port))
+ if (!get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
+ &data.port, &data.proto))
return -EINVAL;
+
+ ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
ip6_netmask(&data.ip2, data.cidr);
.len = sizeof(struct in6_addr) },
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
[IPSET_ATTR_CIDR2] = { .type = NLA_U8 },
+ [IPSET_ATTR_PROTO] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
};
static int
struct chash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX];
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipportnet6_elem data = { .cidr = HOST_MASK };
+ struct hash_ipportnet6_elem data = { .cidr = HOST_MASK,
+ .proto = h->proto };
u32 timeout = h->timeout;
+ int ret;
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
hash_ipportnet6_adt_policy))
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_LINENO])
+ *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
if (tb[IPSET_ATTR_IP])
memcpy(&data.ip, nla_data(tb[IPSET_ATTR_IP]),
sizeof(struct in6_addr));
else
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_PROTO]) {
+ data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+
+ if (data.proto == 0 || data.proto >= IPSET_IPPROTO_TCPUDP)
+ return -IPSET_ERR_INVALID_PROTO;
+ } else if (data.proto == IPSET_IPPROTO_ANY)
+ return -IPSET_ERR_MISSING_PROTO;
+
+ switch (data.proto) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ case IPSET_IPPROTO_TCPUDP:
+ break;
+ default:
+ data.port = 0;
+ break;
+ }
+
if (tb[IPSET_ATTR_TIMEOUT]) {
if (!with_timeout(h->timeout))
return -IPSET_ERR_TIMEOUT;
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
- return adtfn(set, &data, GFP_KERNEL, timeout);
+ ret = adtfn(set, &data, GFP_KERNEL, timeout);
+
+ return ip_set_eexist(ret, flags) ? 0 : ret;
}
/* Create hash:ip type of sets */
[IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
[IPSET_ATTR_PROBES] = { .type = NLA_U8 },
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
+ [IPSET_ATTR_PROTO] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
};
int len, u32 flags)
{
struct nlattr *tb[IPSET_ATTR_CREATE_MAX];
- u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
struct chash *h;
+ u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
+ u8 proto = IPSET_IPPROTO_TCPUDP; /* Backward compatibility */
if (!(set->family == AF_INET || set->family == AF_INET6))
return -IPSET_ERR_INVALID_FAMILY;
if (tb[IPSET_ATTR_MAXELEM])
maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
+ if (tb[IPSET_ATTR_PROTO]) {
+ proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+ if (!proto)
+ return -IPSET_ERR_INVALID_PROTO;
+ }
h = kzalloc(sizeof(*h)
+ sizeof(struct chash_nets)
* (set->family == AF_INET ? 31 : 127), GFP_KERNEL);
h->array_size = CHASH_DEFAULT_ARRAY_SIZE;
h->chain_limit = CHASH_DEFAULT_CHAIN_LIMIT;
get_random_bytes(&h->initval, sizeof(h->initval));
+ h->proto = proto;
h->timeout = IPSET_NO_TIMEOUT;
h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist),
/* Member elements without timeout */
struct hash_net4_elem {
u32 ip;
- u8 cidr; /* Not hashed, zero for null value */
+ u16 padding0;
+ u8 padding1;
+ u8 cidr;
};
/* Member elements with timeout support */
struct hash_net4_telem {
u32 ip;
- u8 cidr; /* Not hashed, zero for null value */
+ u16 padding0;
+ u8 padding1;
+ u8 cidr;
unsigned long timeout;
};
hash_net4_data_equal(const struct hash_net4_elem *ip1,
const struct hash_net4_elem *ip2)
{
- /* We don't have to check the cidr equality
- * because overlapping nets cannot be added to the set
- */
- return ip1->ip == ip2->ip;
+ return ip1->ip == ip2->ip && ip1->cidr == ip2->cidr;
}
static inline bool
{
struct chash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX];
- bool eexist = flags & IPSET_FLAG_EXIST;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_net4_elem data = { .cidr = HOST_MASK };
u32 timeout = h->timeout;
hash_net4_adt_policy))
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_LINENO])
+ *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
if (tb[IPSET_ATTR_IP])
data.ip = ip_set_get_n32(tb[IPSET_ATTR_IP]);
else
ret = adtfn(set, &data, GFP_KERNEL, timeout);
- if (ret && !(ret == -IPSET_ERR_EXIST && eexist)) {
- if (tb[IPSET_ATTR_LINENO])
- *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- }
- return ret;
+ return ip_set_eexist(ret, flags) ? 0 : ret;
}
static bool
struct hash_net6_elem {
union nf_inet_addr ip;
- u8 cidr; /* Not hashed */
+ u16 padding0;
+ u8 padding1;
+ u8 cidr;
};
struct hash_net6_telem {
union nf_inet_addr ip;
- u8 cidr; /* Not hashed */
+ u16 padding0;
+ u8 padding1;
+ u8 cidr;
unsigned long timeout;
};
hash_net6_data_equal(const struct hash_net6_elem *ip1,
const struct hash_net6_elem *ip2)
{
- return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0;
+ return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0
+ && ip1->cidr == ip2->cidr;
}
static inline bool
.len = sizeof(struct in6_addr) },
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
};
static int
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_net6_elem data = { .cidr = HOST_MASK };
u32 timeout = h->timeout;
+ int ret;
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
hash_net6_adt_policy))
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_LINENO])
+ *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
if (tb[IPSET_ATTR_IP])
memcpy(&data.ip, nla_data(tb[IPSET_ATTR_IP]),
sizeof(struct in6_addr));
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
- return adtfn(set, &data, GFP_KERNEL, timeout);
+ ret = adtfn(set, &data, GFP_KERNEL, timeout);
+
+ return ip_set_eexist(ret, flags) ? 0 : ret;
}
/* Create hash:ip type of sets */
[IPSET_ATTR_NAMEREF] = { .type = NLA_STRING,
.len = IPSET_MAXNAMELEN },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
};
{
struct list_set *map = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX];
- bool eexist = flags & IPSET_FLAG_EXIST,
- with_timeout = with_timeout(map->timeout);
+ bool with_timeout = with_timeout(map->timeout);
int before = 0;
u32 timeout = map->timeout;
ip_set_id_t id, refid = IPSET_INVALID_ID;
list_set_adt_policy))
return -IPSET_ERR_PROTOCOL;
+ if (tb[IPSET_ATTR_LINENO])
+ *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
if (tb[IPSET_ATTR_NAME]) {
id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s);
if (id == IPSET_INVALID_ID)
if (adt != IPSET_ADD || ret)
ip_set_put_byindex(id);
- if (ret && !(ret == -IPSET_ERR_EXIST && eexist)) {
- if (tb[IPSET_ATTR_LINENO])
- *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- return ret;
- }
- return ret;
+ return ip_set_eexist(ret, flags) ? 0 : ret;
}
static void
static struct ip_set_type list_set_type = {
.name = "list:set",
.protocol = IPSET_PROTOCOL,
- .features = IPSET_TYPE_NAME,
+ .features = IPSET_TYPE_NAME | IPSET_DUMP_LAST,
.dimension = IPSET_DIM_ONE,
.family = AF_UNSPEC,
.revision = 0,
struct {
union nf_inet_addr ip2;
uint8_t cidr2;
+ uint8_t proto;
char ether[ETH_ALEN];
char name[IPSET_MAXNAMELEN];
char nameref[IPSET_MAXNAMELEN];
case IPSET_OPT_CIDR2:
data->u.adt.cidr2 = *(const uint8_t *) value;
break;
+ case IPSET_OPT_PROTO:
+ data->u.adt.proto = *(const uint8_t *) value;
+ break;
/* Swap/rename */
case IPSET_OPT_SETNAME2:
ipset_strncpy(data->u.setname2, value, IPSET_MAXNAMELEN);
return &data->u.adt.ip2;
case IPSET_OPT_CIDR2:
return &data->u.adt.cidr2;
+ case IPSET_OPT_PROTO:
+ return &data->u.adt.proto;
/* Swap/rename */
case IPSET_OPT_SETNAME2:
return data->u.setname2;
case IPSET_OPT_NETMASK:
case IPSET_OPT_PROBES:
case IPSET_OPT_RESIZE:
+ case IPSET_OPT_PROTO:
return sizeof(uint8_t);
case IPSET_OPT_ETHER:
return ETH_ALEN;
#define range_separator(str) ipset_strchr(str, IPSET_RANGE_SEPARATOR)
#define elem_separator(str) ipset_strchr(str, IPSET_ELEM_SEPARATOR)
#define name_separator(str) ipset_strchr(str, IPSET_NAME_SEPARATOR)
+#define proto_separator(str) ipset_strchr(str, IPSET_PROTO_SEPARATOR)
#define syntax_err(fmt, args...) \
ipset_err(session, "Syntax error: " fmt , ## args)
return err;
}
+/**
+ * ipset_parse_proto - parse protocol name
+ * @session: session structure
+ * @opt: option kind of the data
+ * @str: string to parse
+ *
+ * Parse string as a protocol name. "any" is supported
+ * as a special protocol name for ipset itself.
+ * The parsed protocol are stored in the data blob of the session.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int
+ipset_parse_proto(struct ipset_session *session,
+ enum ipset_opt opt, const char *str)
+{
+ uint8_t proto = 0;
+
+ assert(session);
+ assert(opt == IPSET_OPT_PROTO);
+ assert(str);
+
+ if (STREQ(str, "any"))
+ proto = IPSET_IPPROTO_ANY;
+ else {
+ struct protoent *protoent = getprotobyname(str);
+ if (protoent == NULL)
+ return syntax_err("cannot parse '%s' as a protocol name", str);
+ proto = protoent->p_proto;
+ }
+ if (!proto || proto == IPSET_IPPROTO_TCPUDP)
+ return syntax_err("invalid protocol '%s'", str);
+
+ return ipset_session_data_set(session, opt, &proto);
+}
+
+/**
+ * ipset_parse_proto_port - parse (optional) protocol and a single port
+ * @session: session structure
+ * @opt: option kind of the data
+ * @str: string to parse
+ *
+ * Parse string as a protocol and port, separated by a colon.
+ * The protocol part is optional.
+ * The parsed protocol and port numbers are stored in the data
+ * blob of the session.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int
+ipset_parse_proto_port(struct ipset_session *session,
+ enum ipset_opt opt, const char *str)
+{
+ char *a, *saved, *tmp;
+ int err = 0;
+
+ assert(session);
+ assert(opt == IPSET_OPT_PORT);
+ assert(str);
+
+ saved = tmp = strdup(str);
+ if (tmp == NULL)
+ return ipset_err(session,
+ "Cannot allocate memory to duplicate %s.",
+ str);
+
+ a = proto_separator(tmp);
+ if (a != NULL) {
+ /* proto:port */
+ *a++ = '\0';
+ err = ipset_parse_proto(session, IPSET_OPT_PROTO, tmp);
+ if (err)
+ goto error;
+ tmp = a;
+ }
+ err = ipset_parse_single_port(session, opt, tmp);
+
+error:
+ free(saved);
+ return err;
+}
+
/**
* ipset_parse_family - parse INET|INET6 family names
* @session: session structure
return offset;
}
+/**
+ * ipset_print_proto - print protocol name
+ * @buf: printing buffer
+ * @len: length of available buffer space
+ * @data: data blob
+ * @opt: the option kind
+ * @env: environment flags
+ *
+ * Print protocol name to output buffer.
+ *
+ * Return lenght of printed string or error size.
+ */
+int
+ipset_print_proto(char *buf, unsigned int len,
+ const struct ipset_data *data, enum ipset_opt opt,
+ uint8_t env UNUSED)
+{
+ struct protoent *protoent;
+ uint8_t proto;
+
+ assert(buf);
+ assert(len > 0);
+ assert(data);
+ assert(opt == IPSET_OPT_PROTO);
+
+ proto = *(uint8_t *) ipset_data_get(data, IPSET_OPT_PROTO);
+ assert(proto);
+
+ if (proto == IPSET_IPPROTO_ANY)
+ return snprintf(buf, len, "any");
+ protoent = getprotobynumber(proto);
+ if (protoent)
+ return snprintf(buf, len, "%s", protoent->p_name);
+
+ /* Should not happen */
+ return snprintf(buf, len, "%u", proto);
+}
+
+/**
+ * ipset_print_proto_port - print proto:port
+ * @buf: printing buffer
+ * @len: length of available buffer space
+ * @data: data blob
+ * @opt: the option kind
+ * @env: environment flags
+ *
+ * Print protocol and port to output buffer.
+ *
+ * Return lenght of printed string or error size.
+ */
+int
+ipset_print_proto_port(char *buf, unsigned int len,
+ const struct ipset_data *data, enum ipset_opt opt,
+ uint8_t env UNUSED)
+{
+ int size, offset = 0;
+
+ assert(buf);
+ assert(len > 0);
+ assert(data);
+ assert(opt == IPSET_OPT_PORT);
+
+ if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_PROTO))) {
+ size = ipset_print_proto(buf, len, data, IPSET_OPT_PROTO, env);
+ SNPRINTF_FAILURE(size, len, offset);
+ if (len < 2)
+ return -ENOSPC;
+ strcat(buf, ":");
+ SNPRINTF_FAILURE(1, len, offset);
+ }
+ return ipset_print_port(buf + offset, len, data, IPSET_OPT_PORT, env);
+}
+
#define print_second(data) \
ipset_data_flags_test(data, \
IPSET_FLAG(IPSET_OPT_PORT)|IPSET_FLAG(IPSET_OPT_ETHER))
enum ipset_cmd cmd; /* Current command */
uint32_t lineno; /* Current lineno in restore mode */
char saved_setname[IPSET_MAXNAMELEN]; /* Saved setname */
+ const struct ipset_type *saved_type; /* Saved type */
struct nlattr *nested[IPSET_NEST_MAX]; /* Pointer to nest levels */
uint8_t nestid; /* Current nest level */
bool version_checked; /* Version checked */
return session->handle;
}
+/**
+ * ipset_saved_type - return pointer to the saved type
+ * @session: session structure
+ *
+ * Returns the pointer to the saved type from the last ipset_cmd
+ * It is required to decode type-specific error codes in restore mode.
+ */
+const struct ipset_type *
+ipset_saved_type(const struct ipset_session *session)
+{
+ assert(session);
+ return session->saved_type;
+}
+
/*
* Environment options
*/
.type = MNL_TYPE_U32,
.opt = IPSET_OPT_TIMEOUT,
},
+ [IPSET_ATTR_PROTO] = {
+ .type = MNL_TYPE_U8,
+ .opt = IPSET_OPT_PROTO,
+ },
[IPSET_ATTR_CADT_FLAGS] = {
.type = MNL_TYPE_U32,
.opt = IPSET_OPT_CADT_FLAGS,
.type = MNL_TYPE_U16,
.opt = IPSET_OPT_PORT_TO,
},
+ [IPSET_ATTR_PROTO] = {
+ .type = MNL_TYPE_U8,
+ .opt = IPSET_OPT_PROTO,
+ },
[IPSET_ATTR_TIMEOUT] = {
.type = MNL_TYPE_U32,
.opt = IPSET_OPT_TIMEOUT,
goto cleanup;
D("past: build_msg");
+ /* We have to save the type for error handling */
+ session->saved_type = ipset_data_get(data, IPSET_OPT_TYPE);
/* Save setname for the next possible aggregated restore line */
if (session->lineno != 0
&& (cmd == IPSET_CMD_ADD || cmd == IPSET_CMD_DEL)) {
"Hash is full, cannot add more elements" },
{ IPSET_ERR_HASH_ELEM, 0,
"Null-valued element, cannot be stored in a hash type of set" },
+ { IPSET_ERR_INVALID_PROTO, 0,
+ "Invalid protocol specified" },
+ { IPSET_ERR_MISSING_PROTO, 0,
+ "Protocol missing, but must be specified" },
{ },
};
if (errcode >= IPSET_ERR_TYPE_SPECIFIC) {
const struct ipset_type *type;
- type = ipset_session_data_get(session, IPSET_OPT_TYPE);
+ type = ipset_saved_type(session);
if (type) {
if (MATCH_TYPENAME(type->name, "bitmap:"))
table = bitmap_errcode_table;
\fBlist\fP [ \fISETNAME\fP ]
List the header data and the entries for the specified set, or for
all sets if none is given. The
-\fB\-\-resolve\fP
+\fB\-resolve\fP
option can be used to force name lookups (which may be slow). When the
-\fB\-\-sorted\fP
+\fB\-sorted\fP
option is given, the entries are listed sorted (if the given set
type supports the operation). The option
-\fB\-\-output\fR
+\fB\-output\fR
can be used to control the format of the listing:
\fBplain\fR, \fBsave\fR or \fBxml\fR.
The default is
.PP
\fIDEL\-ENTRY\fR := { \fIipaddr\fR | \fIfromaddr\fR\-\fItoaddr\fR | \fIipaddr\fR/\fIcidr\fR }
.PP
-\fITEST\-ENTRY\fR := { \fIipaddr\fR }
+\fITEST\-ENTRY\fR := \fIipaddr\fR
.PP
Mandatory \fBcreate\fR options:
.TP
.PP
\fICREATE\-OPTIONS\fR := \fBrange\fP \fIfrom\-ip\fP\-\fIto\-ip\fR|\fIip\fR/\fIcidr\fR [ \fBtimeout\fR \fIvalue\fR ]
.PP
-\fIADD\-ENTRY\fR := { \fIipaddr\fR[,\fImac\-addr\fR] }
+\fIADD\-ENTRY\fR := \fIipaddr\fR[,\fImac\-addr\fR]
.PP
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
.PP
-\fIDEL\-ENTRY\fR := { \fIipaddr\fR[,\fImac\-addr\fR] }
+\fIDEL\-ENTRY\fR := \fIipaddr\fR[,\fImac\-addr\fR]
.PP
-\fITEST\-ENTRY\fR := { \fIipaddr\fR[,\fImac\-addr\fR] }
+\fITEST\-ENTRY\fR := \fIipaddr\fR[,\fImac\-addr\fR]
.PP
Mandatory options to use when creating a \fBbitmap:ip,mac\fR type of set:
.TP
.PP
\fIDEL\-ENTRY\fR := {\fIport\fR | \fIfrom\-port\fR\-\fIto\-port\fR }
.PP
-\fITEST\-ENTRY\fR := { \fIport\fR }
+\fITEST\-ENTRY\fR := \fIport\fR
.PP
Mandatory options to use when creating a \fBbitmap:port\fR type of set:
.TP
.PP
\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR|\fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBnetmask\fP \fIcidr\fP ] [ \fBtimeout\fR \fIvalue\fR ]
.PP
-\fIADD\-ENTRY\fR := { \fIipaddr\fR }
+\fIADD\-ENTRY\fR := \fIipaddr\fR
.PP
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
.PP
-\fIDEL\-ENTRY\fR := { \fIipaddr\fR }
+\fIDEL\-ENTRY\fR := \fIipaddr\fR
.PP
-\fITEST\-ENTRY\fR := { \fIipaddr\fR }
+\fITEST\-ENTRY\fR := \fIipaddr\fR
.PP
For the \fBinet\fR family one can add or delete multiple entries by specifying
a range or a network:
.PP
\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR|\fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
.PP
-\fIADD\-ENTRY\fR := { \fIipaddr\fR[/\fIcidr\fR] }
+\fIADD\-ENTRY\fR := \fIipaddr\fR[/\fIcidr\fR]
.PP
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
.PP
-\fIDEL\-ENTRY\fR := { \fIipaddr\fR[/\fIcidr\fR] }
+\fIDEL\-ENTRY\fR := \fIipaddr\fR[/\fIcidr\fR]
.PP
-\fITEST\-ENTRY\fR := { \fIipaddr\fR[/\fIcidr\fR] }
+\fITEST\-ENTRY\fR := \fIipaddr\fR[/\fIcidr\fR]
.PP
Optional \fBcreate\fR options:
.TP
In order to avoid clashes in the hash a limited number of chaining, and then
if that is exhausted, the doubling of the hash is performed.
.PP
-\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR|\fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
+\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR|\fBinet6\fR } ] | [ \fBproto\fR \fIvalue\fR ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
.PP
-\fIADD\-ENTRY\fR := { \fIipaddr\fR,\fIport\fR }
+\fIADD\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR
.PP
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
.PP
-\fIDEL\-ENTRY\fR := { \fIipaddr\fR,\fIport\fR }
+\fIDEL\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR
.PP
-\fITEST\-ENTRY\fR := { \fIipaddr\fR,\fIport\fR }
+\fITEST\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR
.PP
Optional \fBcreate\fR options:
.TP
The protocol family of the IP addresses to be stored in the set. The default is
\fBinet\fR, i.e IPv4.
.TP
+\fBproto\fR \fIvalue\fR
+The default protocol for the port to be stored in the set. If no protocol is specified,
+then TCP/UDP ports are assumed as backward compatibility. The default protocol
+also defines which kind of ports are to be added to the set when the \fBSET\fR
+target is used.
+.TP
\fBhashsize\fR \fIvalue\fR
The initial hash size for the set, default is 1024. The hash size must be a power
of two, the kernel automatically rounds up non power of two hash sizes to the first
\fBmaxelem\fR \fIvalue\fR
The maximal number of elements which can be stored in the set, default 65536.
.PP
-The \fBhash:ip,port\fR type of sets require two \fBsrc\fR/\fBdst\fR parameters of
-the \fBset\fR match and \fBSET\fR target kernel modules.
+When adding, deleting, testing entries the port value is interpreted
+for TCP and UDP only, for other protocols the port value currently is ignored and
+zeroed out, but must be specified. The \fBhash:ip,port\fR type of sets require
+two \fBsrc\fR/\fBdst\fR parameters of the \fBset\fR match and \fBSET\fR
+target kernel modules.
.PP
Examples:
.IP
-ipset create foo hash:ip,port
+ipset create foo hash:ip,port proto tcp
.IP
ipset add foo 192.168.1.1,80
.IP
+ipset add foo 192.168.1.1,udp:53
+.IP
+ipset add foo 192.168.1.1,ospf:0
+.IP
ipset test foo 192.168.1.1,80
.SS hash:ip,port,ip
The \fBhash:ip,port,ip\fR set type uses a hash to store IP address, port and
IP address triples. In order to avoid clashes in the hash a limited number of
chaining, and then if that is exhausted, the doubling of the hash is performed.
.PP
-\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR|\fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
+\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR|\fBinet6\fR } ] | [ \fBproto\fR \fIvalue\fR ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
.PP
-\fIADD\-ENTRY\fR := { \fIipaddr\fR,\fIport\fR,\fIipaddr\fR }
+\fIADD\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fIipaddr\fR
.PP
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
.PP
-\fIDEL\-ENTRY\fR := { \fIipaddr\fR,\fIport\fR,\fIipaddr\fR }
+\fIDEL\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fIipaddr\fR
.PP
-\fITEST\-ENTRY\fR := { \fIipaddr\fR,\fIport\fR,\fIipaddr\fR }
+\fITEST\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fIipaddr\fR
.PP
Optional \fBcreate\fR options:
.TP
The protocol family of the IP addresses to be stored in the set. The default is
\fBinet\fR, i.e IPv4.
.TP
+\fBproto\fR \fIvalue\fR
+The default protocol for the port to be stored in the set. If no protocol is specified,
+then TCP/UDP ports are assumed as backward compatibility. The default protocol
+also defines which kind of ports are to be added to the set when the \fBSET\fR
+target is used.
+.TP
\fBhashsize\fR \fIvalue\fR
The initial hash size for the set, default is 1024. The hash size must be a power
of two, the kernel automatically rounds up non power of two hash sizes to the first
\fBmaxelem\fR \fIvalue\fR
The maximal number of elements which can be stored in the set, default 65536.
.PP
-The \fBhash:ip,port,ip\fR type of sets require three \fBsrc\fR/\fBdst\fR parameters of
-the \fBset\fR match and \fBSET\fR target kernel modules.
+When adding, deleting, testing entries the port value is interpreted
+for TCP and UDP only, for other protocols the port value currently is ignored and
+zeroed out, but must be specified. The \fBhash:ip,port,ip\fR type of sets require
+three \fBsrc\fR/\fBdst\fR parameters of the \fBset\fR match and \fBSET\fR
+target kernel modules.
.PP
Examples:
.IP
.IP
ipset add foo 192.168.1.1,80,10.0.0.1
.IP
-ipset test foo 192.168.1.1,80,10.0.0.1
+ipset test foo 192.168.1.1,udp:53,10.0.0.1
.SS hash:ip,port,net
The \fBhash:ip,port,net\fR set type uses a hash to store IP address, port and
IP network triples.
In order to avoid clashes in the hash a limited number of chaining, and then
if that is exhausted, the doubling of the hash is performed.
.PP
-\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR|\fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
+\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR|\fBinet6\fR } ] | [ \fBproto\fR \fIvalue\fR ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
.PP
-\fIADD\-ENTRY\fR := { \fIipaddr\fR,\fIport\fR,\fIipaddr\fR[/\fIcidr\fR] }
+\fIADD\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fIipaddr\fR[/\fIcidr\fR]
.PP
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
.PP
-\fIDEL\-ENTRY\fR := { \fIipaddr\fR,\fIport\fR,\fIipaddr\fR[/\fIcidr\fR] }
+\fIDEL\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fIipaddr\fR[/\fIcidr\fR]
.PP
-\fITEST\-ENTRY\fR := { \fIipaddr\fR,\fIport\fR,\fIipaddr\fR[/\fIcidr\fR] }
+\fITEST\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fIipaddr\fR[/\fIcidr\fR]
.PP
Optional \fBcreate\fR options:
.TP
The protocol family of the IP addresses to be stored in the set. The default is
\fBinet\fR, i.e IPv4.
.TP
+\fBproto\fR \fIvalue\fR
+The default protocol for the port to be stored in the set. If no protocol is specified,
+then TCP/UDP ports are assumed as backward compatibility. The default protocol
+also defines which kind of ports are to be added to the set when the \fBSET\fR
+target is used.
+.TP
\fBhashsize\fR \fIvalue\fR
The initial hash size for the set, default is 1024. The hash size must be a power
of two, the kernel automatically rounds up non power of two hash sizes to the first
The maximal number of elements which can be stored in the set, default 65536.
.PP
When adding/deleting/testing entries, if the cidr parameter is not specified,
-then the host cidr value is assumed.
+then the host cidr value is assumed. The port value is interpreted
+for TCP and UDP only, for other protocols the port value currently is ignored and
+zeroed out, but must be specified.
.PP
From the \fBset\fR netfilter match point of view a triple will be in a \fBhash:ip,port,net\fR type of set (when the first IP and the port match)
if the second IP belongs to any of the netblocks added to the set.
}
static int
-call_parser(int argc, char *argv[], const struct ipset_arg *args)
+call_parser(int *argc, char *argv[], const struct ipset_arg *args)
{
int i = 1, ret = 0;
const struct ipset_arg *arg;
if (!args)
goto done;
for (arg = args; arg->opt; arg++) {
- for (i = 1; i < argc; ) {
- D("argc: %u, i: %u: %s vs %s", argc, i, argv[i], arg->name[0]);
+ for (i = 1; i < *argc; ) {
+ D("argc: %u, i: %u: %s vs %s", *argc, i, argv[i], arg->name[0]);
if (!(ipset_match_option(argv[i], arg->name))) {
i++;
continue;
optstr = argv[i];
/* Shift off matched option */
D("match %s", arg->name[0]);
- ipset_shift_argv(&argc, argv, i);
- D("argc: %u, i: %u", argc, i);
+ ipset_shift_argv(argc, argv, i);
+ D("argc: %u, i: %u", *argc, i);
switch (arg->has_arg) {
case IPSET_MANDATORY_ARG:
- if (i + 1 > argc)
+ if (i + 1 > *argc)
return exit_error(PARAMETER_PROBLEM,
"Missing mandatory argument of option `%s'",
arg->name[0]);
/* Fall through */
case IPSET_OPTIONAL_ARG:
- if (i + 1 <= argc) {
+ if (i + 1 <= *argc) {
ret = ipset_call_parser(session,
arg->parse,
optstr, arg->opt,
argv[i]);
if (ret < 0)
return ret;
- ipset_shift_argv(&argc, argv, i);
+ ipset_shift_argv(argc, argv, i);
break;
}
/* Fall through */
}
}
done:
- if (i < argc)
+ if (i < *argc)
return exit_error(PARAMETER_PROBLEM,
"Unknown argument: `%s'",
argv[i]);
}
return exit_error(NO_PROBLEM, NULL);
}
+ if (argc > 1)
+ return exit_error(PARAMETER_PROBLEM,
+ "No command specified: unknown argument %s", argv[1]);
return exit_error(PARAMETER_PROBLEM, "No command specified.");
case IPSET_CMD_VERSION:
printf("%s v%s.\n", program_name, program_version);
return handle_error();
/* Parse create options */
- ret = call_parser(argc, argv, type->args[IPSET_CREATE]);
+ ret = call_parser(&argc, argv, type->args[IPSET_CREATE]);
if (ret < 0)
return handle_error();
else if (ret)
case IPSET_CMD_RESTORE:
/* Restore mode */
+ if (argc > 1)
+ return exit_error(PARAMETER_PROBLEM,
+ "Unknown argument %s", argv[1]);
return restore(argv[0]);
case IPSET_CMD_ADD:
case IPSET_CMD_DEL:
return handle_error();
/* Parse additional ADT options */
- ret = call_parser(argc, argv, type->args[cmd2cmd(cmd)]);
+ ret = call_parser(&argc, argv, type->args[cmd2cmd(cmd)]);
if (ret < 0)
return handle_error();
else if (ret)
break;
}
+ if (argc > 1)
+ return exit_error(PARAMETER_PROBLEM,
+ "Unknown argument %s", argv[1]);
ret = ipset_cmd(session, cmd, restore_line);
D("ret %d", ret);
/* Special case for TEST and non-quiet mode */
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
.parse = ipset_parse_uint32, .print = ipset_print_number,
},
+ { .name = { "proto", NULL },
+ .has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PROTO,
+ .parse = ipset_parse_proto, .print = ipset_print_proto,
+ },
/* Backward compatibility */
{ .name = { "probes", NULL },
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PROBES,
static const char hash_ipport_usage[] =
"create SETNAME hash:ip,port\n"
-" [family inet|inet6]\n"
+" [family inet|inet6] [proto PROTO]\n"
" [hashsize VALUE] [maxelem VALUE]\n"
" [timeout VALUE]\n"
-"add SETNAME IP,PORT [timeout VALUE]\n"
-"del SETNAME IP,PORT\n"
-"test SETNAME IP,PORT\n";
+"add SETNAME IP,[PROTO:]PORT [timeout VALUE]\n"
+"del SETNAME IP,[PROTO:]PORT\n"
+"test SETNAME IP,[PROTO:]PORT\n";
struct ipset_type ipset_hash_ipport0 = {
.name = "hash:ip,port",
.opt = IPSET_OPT_IP
},
[IPSET_DIM_TWO] = {
- .parse = ipset_parse_single_port,
- .print = ipset_print_port,
+ .parse = ipset_parse_proto_port,
+ .print = ipset_print_proto_port,
.opt = IPSET_OPT_PORT
},
},
.full = {
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
| IPSET_FLAG(IPSET_OPT_MAXELEM)
+ | IPSET_FLAG(IPSET_OPT_PROTO)
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_PORT)
+ | IPSET_FLAG(IPSET_OPT_PROTO)
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
- | IPSET_FLAG(IPSET_OPT_PORT),
+ | IPSET_FLAG(IPSET_OPT_PORT)
+ | IPSET_FLAG(IPSET_OPT_PROTO),
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
- | IPSET_FLAG(IPSET_OPT_PORT),
+ | IPSET_FLAG(IPSET_OPT_PORT)
+ | IPSET_FLAG(IPSET_OPT_PROTO),
},
.usage = hash_ipport_usage,
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
.parse = ipset_parse_uint32, .print = ipset_print_number,
},
+ { .name = { "proto", NULL },
+ .has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PROTO,
+ .parse = ipset_parse_proto, .print = ipset_print_proto,
+ },
/* Backward compatibility */
{ .name = { "probes", NULL },
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PROBES,
static const char hash_ipportip_usage[] =
"create SETNAME hash:ip,port,ip\n"
-" [family inet|inet6]\n"
+" [family inet|inet6] [proto PROTO]\n"
" [hashsize VALUE] [maxelem VALUE]\n"
" [timeout VALUE]\n"
-"add SETNAME IP,PORT,IP [timeout VALUE]\n"
-"del SETNAME IP,PORT,IP\n"
-"test SETNAME IP,PORT,IP\n";
+"add SETNAME IP,[PROTO:]PORT,IP [timeout VALUE]\n"
+"del SETNAME IP,[PROTO:]PORT,IP\n"
+"test SETNAME IP,[PROTO:]PORT,IP\n";
struct ipset_type ipset_hash_ipportip0 = {
.name = "hash:ip,port,ip",
.opt = IPSET_OPT_IP
},
[IPSET_DIM_TWO] = {
- .parse = ipset_parse_single_port,
- .print = ipset_print_port,
+ .parse = ipset_parse_proto_port,
+ .print = ipset_print_proto_port,
.opt = IPSET_OPT_PORT
},
[IPSET_DIM_THREE] = {
.full = {
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
| IPSET_FLAG(IPSET_OPT_MAXELEM)
+ | IPSET_FLAG(IPSET_OPT_PROTO)
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_PORT)
+ | IPSET_FLAG(IPSET_OPT_PROTO)
| IPSET_FLAG(IPSET_OPT_IP2)
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_PORT)
+ | IPSET_FLAG(IPSET_OPT_PROTO)
| IPSET_FLAG(IPSET_OPT_IP2),
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_PORT)
+ | IPSET_FLAG(IPSET_OPT_PROTO)
| IPSET_FLAG(IPSET_OPT_IP2),
},
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
.parse = ipset_parse_uint32, .print = ipset_print_number,
},
+ { .name = { "proto", NULL },
+ .has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PROTO,
+ .parse = ipset_parse_proto, .print = ipset_print_proto,
+ },
/* Backward compatibility */
{ .name = { "probes", NULL },
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PROBES,
static const char hash_ipportnet_usage[] =
"create SETNAME hash:ip,port,net\n"
-" [family inet|inet6]\n"
+" [family inet|inet6] [proto PROTO]\n"
" [hashsize VALUE] [maxelem VALUE]\n"
" [timeout VALUE]\n"
-"add SETNAME IP,PORT,IP[/CIDR] [timeout VALUE]\n"
-"del SETNAME IP,PORT,IP[/CIDR]\n"
-"test SETNAME IP,PORT,IP[/CIDR]\n";
+"add SETNAME IP,[PROTO:]PORT,IP[/CIDR] [timeout VALUE]\n"
+"del SETNAME IP,[PROTO:]PORT,IP[/CIDR]\n"
+"test SETNAME IP,[PROTO:]PORT,IP[/CIDR]\n";
struct ipset_type ipset_hash_ipportnet0 = {
.name = "hash:ip,port,net",
.opt = IPSET_OPT_IP
},
[IPSET_DIM_TWO] = {
- .parse = ipset_parse_single_port,
- .print = ipset_print_port,
+ .parse = ipset_parse_proto_port,
+ .print = ipset_print_proto_port,
.opt = IPSET_OPT_PORT
},
[IPSET_DIM_THREE] = {
.full = {
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
| IPSET_FLAG(IPSET_OPT_MAXELEM)
+ | IPSET_FLAG(IPSET_OPT_PROTO)
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_PORT)
+ | IPSET_FLAG(IPSET_OPT_PROTO)
| IPSET_FLAG(IPSET_OPT_IP2)
| IPSET_FLAG(IPSET_OPT_CIDR2)
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_PORT)
+ | IPSET_FLAG(IPSET_OPT_PROTO)
| IPSET_FLAG(IPSET_OPT_IP2)
| IPSET_FLAG(IPSET_OPT_CIDR2),
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_PORT)
+ | IPSET_FLAG(IPSET_OPT_PROTO)
| IPSET_FLAG(IPSET_OPT_IP2)
| IPSET_FLAG(IPSET_OPT_CIDR2),
},
-# Range: Create a set with timeout
+# Create a set with timeout
0 ipset create test hash:ip,port,ip timeout 5
-# Range: Add partly zero valued element
+# Add partly zero valued element
0 ipset add test 2.0.0.1,0,0.0.0.0
-# Range: Test partly zero valued element
+# Test partly zero valued element
0 ipset test test 2.0.0.1,0,0.0.0.0
-# Range: Delete party zero valued element
+# Delete party zero valued element
0 ipset del test 2.0.0.1,0,0.0.0.0
-# Range: Add almost zero valued element
+# Add almost zero valued element
0 ipset add test 2.0.0.1,0,0.0.0.1
-# Range: Test almost zero valued element
+# Test almost zero valued element
0 ipset test test 2.0.0.1,0,0.0.0.1
-# Range: Delete almost zero valued element
+# Delete almost zero valued element
0 ipset del test 2.0.0.1,0,0.0.0.1
-# Range: Add lower boundary
+# Add lower boundary
0 ipset add test 2.0.0.1,5,1.1.1.1
-# Range: Add upper boundary
+# Add upper boundary
0 ipset add test 2.1.0.0,128,2.2.2.2
-# Range: Test lower boundary
+# Test lower boundary
0 ipset test test 2.0.0.1,5,1.1.1.1
-# Range: Test upper boundary
+# Test upper boundary
0 ipset test test 2.1.0.0,128,2.2.2.2
-# Range: Test value not added to the set
+# Test value not added to the set
1 ipset test test 2.0.0.1,5,1.1.1.2
-# Range: Test value not added to the set
+# Test value not added to the set
1 ipset test test 2.0.0.1,6,1.1.1.1
-# Range: Test value not added to the set
+# Test value not added to the set
1 ipset test test 2.0.0.2,6,1.1.1.1
-# Range: Test value before lower boundary
+# Test value before lower boundary
1 ipset test test 2.0.0.0,5,1.1.1.1
-# Range: Test value after upper boundary
+# Test value after upper boundary
1 ipset test test 2.1.0.1,128,2.2.2.2
-# Range: Try to add value before lower boundary
+# Try to add value before lower boundary
0 ipset add test 2.0.0.0,5,1.1.1.1
-# Range: Try to add value after upper boundary
+# Try to add value after upper boundary
0 ipset add test 2.1.0.1,128,2.2.2.2
-# Range: List set
+# List set
0 ipset list test | sed 's/timeout ./timeout x/' > .foo0 && ./sort.sh .foo0
-# Range: Check listing
+# Check listing
0 diff -I 'Size in memory.*' .foo hash:ip,port,ip.t.list0 && rm .foo
-# Range: Sleep 6s so that elements can time out
+# Sleep 6s so that elements can time out
0 sleep 6
-# Range: List set
+# List set
0 ipset list test > .foo0 && ./sort.sh .foo0
-# Range: Check listing
+# Check listing
0 diff -I 'Size in memory.*' .foo hash:ip,port,ip.t.list1 && rm .foo
-# Range: Flush test set
+# Flush test set
0 ipset flush test
-# Range: Delete test set
+# Delete test set
0 ipset destroy test
# eof
-# Range: Create a set with timeout
+# Create a set with timeout
0 ipset create test hash:ip,port timeout 5
-# Range: Add partly zero valued element
+# Add partly zero valued element
0 ipset add test 2.0.0.1,0
-# Range: Test partly zero valued element
+# Test partly zero valued element
0 ipset test test 2.0.0.1,0
-# Range: Delete partly zero valued element
+# Delete partly zero valued element
0 ipset del test 2.0.0.1,0
-# Range: Add lower boundary
+# Add lower boundary
0 ipset add test 2.0.0.1,5
-# Range: Add upper boundary
+# Add upper boundary
0 ipset add test 2.1.0.0,128
-# Range: Test lower boundary
+# Test lower boundary
0 ipset test test 2.0.0.1,5
-# Range: Test upper boundary
+# Test upper boundary
0 ipset test test 2.1.0.0,128
-# Range: Test value not added to the set
+# Test value not added to the set
1 ipset test test 2.0.0.1,4
-# Range: Delete value not added to the set
+# Delete value not added to the set
1 ipset del test 2.0.0.1,6
-# Range: Test value before lower boundary
+# Test value before lower boundary
1 ipset test test 2.0.0.0,5
-# Range: Test value after upper boundary
+# Test value after upper boundary
1 ipset test test 2.1.0.1,128
-# Range: Try to add value before lower boundary
+# Try to add value before lower boundary
0 ipset add test 2.0.0.0,5
-# Range: Try to add value after upper boundary
+# Try to add value after upper boundary
0 ipset add test 2.1.0.1,128
-# Range: List set
+# List set
0 ipset list test | sed 's/timeout ./timeout x/' > .foo0 && ./sort.sh .foo0
-# Range: Check listing
+# Check listing
0 diff -I 'Size in memory.*' .foo hash:ip,port.t.list0 && rm .foo
-# Range: Sleep 6s so that elements can time out
+# Sleep 6s so that elements can time out
0 sleep 6
-# Range: List set
+# List set
0 ipset list test > .foo0 && ./sort.sh .foo0
-# Range: Check listing
+# Check listing
0 diff -I 'Size in memory.*' .foo hash:ip,port.t.list1 && rm .foo
-# Range: Flush test set
+# Flush test set
0 ipset flush test
-# Range: Delete test set
+# Delete test set
+0 ipset destroy test
+# Create a set with default TCP protocol
+0 ipset create test hash:ip,port proto tcp
+# Add element without specifying protocol
+0 ipset add test 2.0.0.1,80
+# Add "same" element but with UDP protocol
+0 ipset add test 2.0.0.1,udp:80
+# Test element without specifying protocol
+0 ipset test test 2.0.0.1,80
+# Test element with TCP protocol
+0 ipset test test 2.0.0.1,tcp:80
+# Test element with UDP protocol
+0 ipset test test 2.0.0.1,udp:80
+# Add element with ospf
+0 ipset add test 2.0.0.1,ospf:0
+# Test element with ospf
+0 ipset test test 2.0.0.1,ospf:0
+# List set
+0 ipset list test > .foo0 && ./sort.sh .foo0
+# Check listing
+0 diff -I 'Size in memory.*' .foo hash:ip,port.t.list2 && rm .foo
+# Delete set
0 ipset destroy test
# eof
--- /dev/null
+Name: test
+Type: hash:ip,port
+Header: family inet hashsize 1024 maxelem 65536 proto tcp
+Size in memory: 8424
+References: 0
+Members:
+2.0.0.1,ospf:0
+2.0.0.1,tcp:80
+2.0.0.1,udp:80
+
-# Range: Create a set with timeout
+# Create a set with timeout
0 ipset create test hash:ip,port,ip family inet6 timeout 5
-# Range: Add partly zero valued element
+# Add partly zero valued element
0 ipset add test 2:0:0::1,0,0:0:0::0
-# Range: Test partly zero valued element
+# Test partly zero valued element
0 ipset test test 2:0:0::1,0,0:0:0::0
-# Range: Delete party zero valued element
+# Delete party zero valued element
0 ipset del test 2:0:0::1,0,0:0:0::0
-# Range: Add almost zero valued element
+# Add almost zero valued element
0 ipset add test 2:0:0::1,0,0:0:0::1
-# Range: Test almost zero valued element
+# Test almost zero valued element
0 ipset test test 2:0:0::1,0,0:0:0::1
-# Range: Delete almost zero valued element
+# Delete almost zero valued element
0 ipset del test 2:0:0::1,0,0:0:0::1
-# Range: Add lower boundary
+# Add lower boundary
0 ipset add test 2:0:0::1,5,1:1:1::1
-# Range: Add upper boundary
+# Add upper boundary
0 ipset add test 2:1:0::0,128,2:2:2::2
-# Range: Test lower boundary
+# Test lower boundary
0 ipset test test 2:0:0::1,5,1:1:1::1
-# Range: Test upper boundary
+# Test upper boundary
0 ipset test test 2:1:0::0,128,2:2:2::2
-# Range: Test value not added to the set
+# Test value not added to the set
1 ipset test test 2:0:0::1,5,1:1:1::2
-# Range: Test value not added to the set
+# Test value not added to the set
1 ipset test test 2:0:0::1,6,1:1:1::1
-# Range: Test value not added to the set
+# Test value not added to the set
1 ipset test test 2:0:0::2,6,1:1:1::1
-# Range: Test value before lower boundary
+# Test value before lower boundary
1 ipset test test 2:0:0::0,5,1:1:1::1
-# Range: Test value after upper boundary
+# Test value after upper boundary
1 ipset test test 2:1:0::1,128,2:2:2::2
-# Range: Try to add value before lower boundary
+# Try to add value before lower boundary
0 ipset add test 2:0:0::0,5,1:1:1::1
-# Range: Try to add value after upper boundary
+# Try to add value after upper boundary
0 ipset add test 2:1:0::1,128,2:2:2::2
-# Range: List set
+# List set
0 ipset list test | sed 's/timeout ./timeout x/' > .foo0 && ./sort.sh .foo0
-# Range: Check listing
+# Check listing
0 diff -I 'Size in memory.*' .foo hash:ip6,port,ip6.t.list0 && rm .foo
-# Range: Sleep 6s so that elements can time out
+# Sleep 6s so that elements can time out
0 sleep 6
-# Range: List set
+# List set
0 ipset list test > .foo0 && ./sort.sh .foo0
-# Range: Check listing
+# Check listing
0 diff -I 'Size in memory.*' .foo hash:ip6,port,ip6.t.list1 && rm .foo
-# Range: Flush test set
+# Flush test set
0 ipset flush test
-# Range: Delete test set
+# Delete test set
0 ipset destroy test
# eof
-# Range: Create a set with timeout
+# Create a set with timeout
0 ipset create test hash:ip,port family inet6 timeout 5
-# Range: Add partly zero valued element
+# Add partly zero valued element
0 ipset add test 2:0:0::1,0
-# Range: Test partly zero valued element
+# Test partly zero valued element
0 ipset test test 2:0:0::1,0
-# Range: Delete partly zero valued element
+# Delete partly zero valued element
0 ipset del test 2:0:0::1,0
-# Range: Add lower boundary
+# Add lower boundary
0 ipset add test 2:0:0::1,5
-# Range: Add upper boundary
+# Add upper boundary
0 ipset add test 2:1:0::0,128
-# Range: Test lower boundary
+# Test lower boundary
0 ipset test test 2:0:0::1,5
-# Range: Test upper boundary
+# Test upper boundary
0 ipset test test 2:1:0::0,128
-# Range: Test value not added to the set
+# Test value not added to the set
1 ipset test test 2:0:0::1,4
-# Range: Delete value not added to the set
+# Delete value not added to the set
1 ipset del test 2:0:0::1,6
-# Range: Test value before lower boundary
+# Test value before lower boundary
1 ipset test test 2:0:0::0,5
-# Range: Test value after upper boundary
+# Test value after upper boundary
1 ipset test test 2:1:0::1,128
-# Range: Try to add value before lower boundary
+# Try to add value before lower boundary
0 ipset add test 2:0:0::0,5
-# Range: Try to add value after upper boundary
+# Try to add value after upper boundary
0 ipset add test 2:1:0::1,128
-# Range: List set
+# List set
0 ipset list test | sed 's/timeout ./timeout x/' > .foo0 && ./sort.sh .foo0
-# Range: Check listing
+# Check listing
0 diff -I 'Size in memory.*' .foo hash:ip6,port.t.list0 && rm .foo
-# Range: Sleep 6s so that elements can time out
+# Sleep 6s so that elements can time out
0 sleep 6
-# Range: List set
+# List set
0 ipset list test > .foo0 && ./sort.sh .foo0
-# Range: Check listing
+# Check listing
0 diff -I 'Size in memory.*' .foo hash:ip6,port.t.list1 && rm .foo
-# Range: Flush test set
+# Flush test set
0 ipset flush test
-# Range: Delete test set
+# Delete test set
0 ipset destroy test
# eof
# Create a set with timeout
0 ipset create test nethash hashsize 128 timeout 6
-# Range: Add zero valued element
+# Add zero valued element
1 ipset add test 0.0.0.0/0
-# Range: Test zero valued element
+# Test zero valued element
1 ipset test test 0.0.0.0/0
-# Range: Delete zero valued element
+# Delete zero valued element
1 ipset del test 0.0.0.0/0
-# Range: Try to add /0
+# Try to add /0
1 ipset add test 1.1.1.1/0
-# Range: Try to add /32
+# Try to add /32
0 ipset add test 1.1.1.1/32
-# Range: Add almost zero valued element
+# Add almost zero valued element
0 ipset add test 0.0.0.0/1
-# Range: Test almost zero valued element
+# Test almost zero valued element
0 ipset test test 0.0.0.0/1
-# Range: Delete almost zero valued element
+# Delete almost zero valued element
0 ipset del test 0.0.0.0/1
-# Range: Test deleted element
+# Test deleted element
1 ipset test test 0.0.0.0/1
-# Range: Delete element not added to the set
+# Delete element not added to the set
1 ipset del test 0.0.0.0/1
-# Range: Add first random network
+# Add first random network
0 ipset add test 2.0.0.1/24
-# Range: Add second random network
+# Add second random network
0 ipset add test 192.168.68.69/27
-# Range: Test first random value
+# Test first random value
0 ipset test test 2.0.0.255
-# Range: Test second random value
+# Test second random value
0 ipset test test 192.168.68.95
-# Range: Test value not added to the set
+# Test value not added to the set
1 ipset test test 2.0.1.0
-# Range: Try to add IP address
+# Try to add IP address
0 ipset add test 2.0.0.1
-# Range: List set
+# List set
0 ipset list test | sed 's/timeout ./timeout x/' > .foo0 && ./sort.sh .foo0
-# Range: Check listing
+# Check listing
0 diff -I 'Size in memory.*' .foo hash:net.t.list0 && rm .foo
# Sleep 6s so that element can time out
0 sleep 6
# Create a set with timeout
0 ipset create test nethash family inet6 hashsize 128 timeout 6
-# Range: Add zero valued element
+# Add zero valued element
1 ipset add test ::/0
-# Range: Test zero valued element
+# Test zero valued element
1 ipset test test ::/0
-# Range: Delete zero valued element
+# Delete zero valued element
1 ipset del test ::/0
-# Range: Try to add /0
+# Try to add /0
1 ipset add test 1:1:1::1/0
-# Range: Try to add /32
+# Try to add /32
0 ipset add test 1:1:1::1/128
-# Range: Add almost zero valued element
+# Add almost zero valued element
0 ipset add test 0:0:0::0/1
-# Range: Test almost zero valued element
+# Test almost zero valued element
0 ipset test test 0:0:0::0/1
-# Range: Delete almost zero valued element
+# Delete almost zero valued element
0 ipset del test 0:0:0::0/1
-# Range: Test deleted element
+# Test deleted element
1 ipset test test 0:0:0::0/1
-# Range: Delete element not added to the set
+# Delete element not added to the set
1 ipset del test 0:0:0::0/1
-# Range: Add first random network
+# Add first random network
0 ipset add test 2:0:0::1/24
-# Range: Add second random network
+# Add second random network
0 ipset add test 192:168:68::69/27
-# Range: Test first random value
+# Test first random value
0 ipset test test 2:0:0::255
-# Range: Test second random value
+# Test second random value
0 ipset test test 192:168:68::95
-# Range: Test value not added to the set
+# Test value not added to the set
1 ipset test test 3:0:0::1
-# Range: Try to add IP address
+# Try to add IP address
0 ipset add test 3:0:0::1
-# Range: List set
+# List set
0 ipset list test | sed 's/timeout ./timeout x/' > .foo0 && ./sort.sh .foo0
-# Range: Check listing
+# Check listing
0 diff -I 'Size in memory.*' .foo hash:net6.t.list0 && rm .foo
# Sleep 6s so that element can time out
0 sleep 6
1 ipset -L test >/dev/null
# Delete our test set: the testsuite fails if it exists
1 ipset -X test
+# Check mandatory create arguments
+2 ipset -N test
# eof
+# Range: Check syntax error: missing range/from-to
+2 ipset -N test ipmap
+# Range: Check syntax error: missing --from
+2 ipset -N test ipmap --to 2.1.0.1
+# Range: Check syntax error: missing --to
+2 ipset -N test ipmap --from 2.1.0.1
+# Range: Catch invalid IPv4 address
+1 ipset -N test ipmap --from 2.0.0.256 --to 2.1.0.1
# Range: Try to create from an invalid range
1 ipset -N test ipmap --from 2.0.0.1 --to 2.1.0.1
# Range: Create a set from a valid range
0 ipset -D test 2.0.0.128
# Range: Add a range of elements
0 ipset -A test 2.0.0.128-2.0.0.131
+# Range: Save set
+0 ipset -S test > ipmap.t.restore
+# Range: Destroy set
+0 ipset -X test
+# Range: Restore set and catch error
+1 sed 's/2.0.0.131/222.0.0.131/' < ipmap.t.restore | ipset -R
+# Range: Destroy set
+0 ipset -X test
+# Range: Restore set
+0 ipset -R < ipmap.t.restore && rm ipmap.t.restore
# Range: List set
0 ipset -L test > .foo
# Range: Check listing
-# Range: Create a set from a range (range ignored)
+# Create a set from a range (range ignored)
0 ipset -N test ipporthash --from 2.0.0.1 --to 2.1.0.0
-# Range: Destroy set
+# Destroy set
0 ipset -X test
-# Range: Create a set
+# Create a set
0 ipset -N test ipporthash
-# Range: Add partly zero valued element
+# Add partly zero valued element
0 ipset -A test 2.0.0.1,0
-# Range: Test partly zero valued element
+# Test partly zero valued element
0 ipset -T test 2.0.0.1,0
-# Range: Delete partly zero valued element
+# Delete partly zero valued element
0 ipset -D test 2.0.0.1,0
-# Range: Add lower boundary
+# Add lower boundary
0 ipset -A test 2.0.0.1,5
-# Range: Add upper boundary
+# Add upper boundary
0 ipset -A test 2.1.0.0,128
-# Range: Test lower boundary
+# Test lower boundary
0 ipset -T test 2.0.0.1,5
-# Range: Test upper boundary
+# Test upper boundary
0 ipset -T test 2.1.0.0,128
-# Range: Test value not added to the set
+# Test value not added to the set
1 ipset -T test 2.0.0.1,4
-# Range: Delete value not added to the set
+# Delete value not added to the set
1 ipset -D test 2.0.0.1,6
-# Range: Test value before lower boundary
+# Test value before lower boundary
1 ipset -T test 2.0.0.0,5
-# Range: Test value after upper boundary
+# Test value after upper boundary
1 ipset -T test 2.1.0.1,128
-# Range: Try to add value before lower boundary
+# Try to add value before lower boundary
0 ipset -A test 2.0.0.0,5
-# Range: Try to add value after upper boundary
+# Try to add value after upper boundary
0 ipset -A test 2.1.0.1,128
-# Range: List set
+# List set
0 ipset -L test > .foo0 && ./sort.sh .foo0
-# Range: Check listing
+# Check listing
0 diff -I 'Size in memory.*' .foo ipporthash.t.list0 && rm .foo
-# Range: Flush test set
+# Flush test set
0 ipset -F test
-# Range: Delete test set
+# Delete test set
0 ipset -X test
-# Network: Create a set from a network (network ignored)
+# Create a set from a network (network ignored)
0 ipset -N test ipporthash --network 2.0.0.0/16
-# Network: Add lower boundary
+# Add lower boundary
0 ipset -A test 2.0.0.0,5
-# Network: Add upper boundary
+# Add upper boundary
0 ipset -A test 2.0.255.255,128
-# Network: Test lower boundary
+# Test lower boundary
0 ipset -T test 2.0.0.0,5
-# Network: Test upper boundary
+# Test upper boundary
0 ipset -T test 2.0.255.255,128
-# Network: Test value not added to the set
+# Test value not added to the set
1 ipset -T test 2.0.0.0,4
-# Network: Delete value not added to the set
+# Delete value not added to the set
1 ipset -D test 2.0.0.0,6
-# Network: Test value before lower boundary
+# Test value before lower boundary
1 ipset -T test 1.255.255.255,5
-# Network: Test value after upper boundary
+# Test value after upper boundary
1 ipset -T test 2.1.0.0,128
-# Network: Try to add value before lower boundary
+# Try to add value before lower boundary
0 ipset -A test 1.255.255.255,5
-# Network: Try to add value after upper boundary
+# Try to add value after upper boundary
0 ipset -A test 2.1.0.0,128
-# Network: List set
+# List set
0 ipset -L test > .foo0 && ./sort.sh .foo0
-# Network: Check listing
+# Check listing
0 diff -I 'Size in memory.*' .foo ipporthash.t.list1 && rm .foo
-# Network: Flush test set
+# Flush test set
0 ipset -F test
-# Network: Delete test set
+# Delete test set
0 ipset -X test
# eof
-# Range: Create a set from a range (range ignored)
+# Create a set from a range (range ignored)
0 ipset -N test ipportiphash --from 2.0.0.1 --to 2.1.0.0
-# Range: Destroy set
+# Destroy set
0 ipset -X test
-# Range: Create a set
+# Create a set
0 ipset -N test ipportiphash
-# Range: Add partly zero valued element
+# Add partly zero valued element
0 ipset -A test 2.0.0.1,0,0.0.0.0
-# Range: Test partly zero valued element
+# Test partly zero valued element
0 ipset -T test 2.0.0.1,0,0.0.0.0
-# Range: Delete party zero valued element
+# Delete party zero valued element
0 ipset -D test 2.0.0.1,0,0.0.0.0
-# Range: Add almost zero valued element
+# Add almost zero valued element
0 ipset -A test 2.0.0.1,0,0.0.0.1
-# Range: Test almost zero valued element
+# Test almost zero valued element
0 ipset -T test 2.0.0.1,0,0.0.0.1
-# Range: Delete almost zero valued element
+# Delete almost zero valued element
0 ipset -D test 2.0.0.1,0,0.0.0.1
-# Range: Add lower boundary
+# Add lower boundary
0 ipset -A test 2.0.0.1,5,1.1.1.1
-# Range: Add upper boundary
+# Add upper boundary
0 ipset -A test 2.1.0.0,128,2.2.2.2
-# Range: Test lower boundary
+# Test lower boundary
0 ipset -T test 2.0.0.1,5,1.1.1.1
-# Range: Test upper boundary
+# Test upper boundary
0 ipset -T test 2.1.0.0,128,2.2.2.2
-# Range: Test value not added to the set
+# Test value not added to the set
1 ipset -T test 2.0.0.1,5,1.1.1.2
-# Range: Test value not added to the set
+# Test value not added to the set
1 ipset -T test 2.0.0.1,6,1.1.1.1
-# Range: Test value not added to the set
+# Test value not added to the set
1 ipset -T test 2.0.0.2,6,1.1.1.1
-# Range: Test value before lower boundary
+# Test value before lower boundary
1 ipset -T test 2.0.0.0,5,1.1.1.1
-# Range: Test value after upper boundary
+# Test value after upper boundary
1 ipset -T test 2.1.0.1,128,2.2.2.2
-# Range: Try to add value before lower boundary
+# Try to add value before lower boundary
0 ipset -A test 2.0.0.0,5,1.1.1.1
-# Range: Try to add value after upper boundary
+# Try to add value after upper boundary
0 ipset -A test 2.1.0.1,128,2.2.2.2
-# Range: List set
+# List set
0 ipset -L test > .foo0 && ./sort.sh .foo0
-# Range: Check listing
+# Check listing
0 diff -I 'Size in memory.*' .foo ipportiphash.t.list0 && rm .foo
-# Range: Flush test set
+# Flush test set
0 ipset -F test
-# Range: Delete test set
+# Delete test set
0 ipset -X test
-# Network: Create a set from a valid network (network ignored)
+# Create a set from a valid network (network ignored)
0 ipset -N test ipportiphash --network 2.0.0.0/16
-# Network: Add lower boundary
+# Add lower boundary
0 ipset -A test 2.0.0.0,5,1.1.1.1
-# Network: Add upper boundary
+# Add upper boundary
0 ipset -A test 2.0.255.255,128,2.2.2.2
-# Network: Test lower boundary
+# Test lower boundary
0 ipset -T test 2.0.0.0,5,1.1.1.1
-# Network: Test upper boundary
+# Test upper boundary
0 ipset -T test 2.0.255.255,128,2.2.2.2
-# Network: Test value not added to the set
+# Test value not added to the set
1 ipset -T test 2.0.0.0,5,1.1.1.2
-# Network: Test value not added to the set
+# Test value not added to the set
1 ipset -T test 2.0.0.0,6,1.1.1.1
-# Network: Test value before lower boundary
+# Test value before lower boundary
1 ipset -T test 1.255.255.255,5,1.1.1.1
-# Network: Test value after upper boundary
+# Test value after upper boundary
1 ipset -T test 2.1.0.0,128,2.2.2.2
-# Network: Try to add value before lower boundary
+# Try to add value before lower boundary
0 ipset -A test 1.255.255.255,5,1.1.1.1
-# Network: Try to test value before lower boundary
+# Try to test value before lower boundary
0 ipset -T test 1.255.255.255,5,1.1.1.1
-# Network: Try to del value before lower boundary
+# Try to del value before lower boundary
0 ipset -D test 1.255.255.255,5,1.1.1.1
-# Network: List set
+# List set
0 ipset -L test > .foo0 && ./sort.sh .foo0
-# Network: Check listing
+# Check listing
0 diff -I 'Size in memory.*' .foo ipportiphash.t.list1 && rm .foo
-# Network: Flush test set
+# Flush test set
0 ipset -F test
-# Network: Delete test set
+# Delete test set
0 ipset -X test
# eof
# Create a set
0 ipset -N test nethash --hashsize 128
-# Range: Add zero valued element
+# Add zero valued element
1 ipset -A test 0.0.0.0/0
-# Range: Test zero valued element
+# Test zero valued element
1 ipset -T test 0.0.0.0/0
-# Range: Delete zero valued element
+# Delete zero valued element
1 ipset -D test 0.0.0.0/0
-# Range: Try to add /0
+# Try to add /0
1 ipset -A test 1.1.1.1/0
-# Range: Try to add /32
+# Try to add /32
0 ipset -A test 1.1.1.1/32
-# Range: Add almost zero valued element
+# Add almost zero valued element
0 ipset -A test 0.0.0.0/1
-# Range: Test almost zero valued element
+# Test almost zero valued element
0 ipset -T test 0.0.0.0/1
-# Range: Delete almost zero valued element
+# Delete almost zero valued element
0 ipset -D test 0.0.0.0/1
-# Range: Test deleted element
+# Test deleted element
1 ipset -T test 0.0.0.0/1
-# Range: Delete element not added to the set
+# Delete element not added to the set
1 ipset -D test 0.0.0.0/1
-# Range: Add first random network
+# Add first random network
0 ipset -A test 2.0.0.1/24
-# Range: Add second random network
+# Add second random network
0 ipset -A test 192.168.68.69/27
-# Range: Test first random value
+# Test first random value
0 ipset -T test 2.0.0.255
-# Range: Test second random value
+# Test second random value
0 ipset -T test 192.168.68.95
-# Range: Test value not added to the set
+# Test value not added to the set
1 ipset -T test 2.0.1.0
-# Range: Try to add IP address
+# Try to add IP address
0 ipset -A test 2.0.0.1
-# Range: List set
+# List set
0 ipset -L test > .foo0 && ./sort.sh .foo0
-# Range: Check listing
+# Check listing
0 diff -I 'Size in memory.*' .foo nethash.t.list0 && rm .foo
# Flush test set
0 ipset -F test
-# Setlist: Create dummy set
+# Create dummy set
0 ipset -N dummy list:set
-# Setlist: Create base set foo
+# Create base set foo
0 ipset -N foo ipmap --from 2.0.0.1 --to 2.1.0.0
-# Setlist: Create base set bar
+# Create base set bar
0 ipset -N bar iphash
-# Setlist: Create setlist kind of set
+# Create setlist kind of set
0 ipset -N test setlist
-# Setlist: Swap test and dumy sets
+# Swap test and dumy sets
0 ipset -W test dummy
-# Setlist: Destroy dummy set
+# Destroy dummy set
0 ipset -X dummy
-# Setlist: Add foo set to setlist
+# Add foo set to setlist
0 ipset -A test foo
-# Setlist: Test foo set in setlist
+# Test foo set in setlist
0 ipset -T test foo
-# Setlist: Test nonexistent set in setlist
+# Test nonexistent set in setlist
1 ipset -T test nonexistent
-# Setlist: Try to delete foo set
+# Try to delete foo set
1 ipset -X foo
-# Setlist: Add bar set to setlist, after foo
+# Add bar set to setlist, after foo
0 ipset -A test bar
-# Setlist: Test bar,after,foo
+# Test bar,after,foo
0 ipset -T test bar,after,foo
-# Setlist: Test foo,before,bar
+# Test foo,before,bar
0 ipset -T test foo,before,bar
-# Setlist: Test bar,before,foo
+# Test bar,before,foo
1 ipset -T test bar,before,foo
-# Setlist: Test foo,after,bar
+# Test foo,after,bar
1 ipset -T test foo,after,bar
-# Setlist: Save sets
+# Save sets
0 ipset -S > setlist.t.restore
-# Setlist: Delete bar,before,foo
+# Delete bar,before,foo
1 ipset -D test bar,before,foo
-# Setlist: Delete foo,after,bar
+# Delete foo,after,bar
1 ipset -D test foo,after,bar
-# Setlist: Delete bar,after,foo
+# Delete bar,after,foo
0 ipset -D test bar,after,foo
-# Setlist: Flush test set
+# Flush test set
0 ipset -F test
-# Setlist: Delete test set
+# Delete test set
0 ipset -X test
-# Setlist: Delete all sets
+# Delete all sets
0 ipset -X
-# Setlist: Restore saved sets
+# Restore saved sets
0 ipset -R < setlist.t.restore
-# Setlist: List set
+# List set
0 ipset -L test > .foo
-# Setlist: Check listing
+# Check listing
0 diff .foo setlist.t.list0 && rm .foo
-# Setlist: Flush all sets
+# Flush all sets
0 ipset -F
-# Setlist: Delete all sets
+# Delete all sets
0 ipset -X && rm setlist.t.restore
# eof