ipset: update to 6.7-genl

This commit is contained in:
Jan Engelhardt
2011-05-31 22:53:12 +02:00
parent cfb72bf468
commit b2fc85c589
54 changed files with 1823 additions and 655 deletions

2
README
View File

@@ -19,7 +19,7 @@ simplified, and sped up.
Included in this package Included in this package
======================== ========================
- ipset 4.5 - ipset 4.5
- ipset 6.6a-genl - ipset 6.7-genl
- xt_ACCOUNT 1.16, libxt_ACCOUNT 1.3 - xt_ACCOUNT 1.16, libxt_ACCOUNT 1.3

View File

@@ -4,7 +4,7 @@ obj-m += xt_set.o
obj-m += ip_set.o ip_set_bitmap_ip.o ip_set_bitmap_ipmac.o obj-m += ip_set.o ip_set_bitmap_ip.o ip_set_bitmap_ipmac.o
obj-m += ip_set_bitmap_port.o ip_set_hash_ip.o ip_set_hash_ipport.o obj-m += ip_set_bitmap_port.o ip_set_hash_ip.o ip_set_hash_ipport.o
obj-m += ip_set_hash_ipportip.o ip_set_hash_ipportnet.o ip_set_hash_net.o obj-m += ip_set_hash_ipportip.o ip_set_hash_ipportnet.o ip_set_hash_net.o
obj-m += ip_set_hash_netport.o ip_set_list_set.o obj-m += ip_set_hash_netiface.o ip_set_hash_netport.o ip_set_list_set.o
ip_set-y := ip_set_core.o ip_set_getport.o pfxlen.o ip_set-y := ip_set_core.o ip_set_getport.o pfxlen.o

View File

@@ -17,7 +17,8 @@ ipset_SOURCES = src/ipset.c src/errcode.c src/ui.c src/ipset_bitmap_ip.c \
src/ipset_bitmap_ipmac.c src/ipset_bitmap_port.c \ src/ipset_bitmap_ipmac.c src/ipset_bitmap_port.c \
src/ipset_hash_ip.c src/ipset_hash_ipport.c \ src/ipset_hash_ip.c src/ipset_hash_ipport.c \
src/ipset_hash_ipportip.c src/ipset_hash_ipportnet.c \ src/ipset_hash_ipportip.c src/ipset_hash_ipportnet.c \
src/ipset_hash_net.c src/ipset_hash_netport.c \ src/ipset_hash_net.c src/ipset_hash_netiface.c \
src/ipset_hash_netport.c \
src/ipset_list_set.c src/ipset_list_set.c
ipset_LDADD = libipset.la ipset_LDADD = libipset.la

View File

@@ -46,11 +46,13 @@ enum ipset_opt {
IPSET_OPT_CIDR2, IPSET_OPT_CIDR2,
IPSET_OPT_IP2_TO, IPSET_OPT_IP2_TO,
IPSET_OPT_PROTO, IPSET_OPT_PROTO,
IPSET_OPT_IFACE,
/* Swap/rename to */ /* Swap/rename to */
IPSET_OPT_SETNAME2, IPSET_OPT_SETNAME2,
/* Flags */ /* Flags */
IPSET_OPT_EXIST, IPSET_OPT_EXIST,
IPSET_OPT_BEFORE, IPSET_OPT_BEFORE,
IPSET_OPT_PHYSDEV,
/* Internal options */ /* Internal options */
IPSET_OPT_FLAGS = 48, /* IPSET_FLAG_EXIST| */ IPSET_OPT_FLAGS = 48, /* IPSET_FLAG_EXIST| */
IPSET_OPT_CADT_FLAGS, /* IPSET_FLAG_BEFORE| */ IPSET_OPT_CADT_FLAGS, /* IPSET_FLAG_BEFORE| */
@@ -66,7 +68,7 @@ enum ipset_opt {
#define IPSET_FLAGS_ALL (~0LL) #define IPSET_FLAGS_ALL (~0LL)
#define IPSET_CREATE_FLAGS \ #define IPSET_CREATE_FLAGS \
( IPSET_FLAG(IPSET_OPT_FAMILY) \ (IPSET_FLAG(IPSET_OPT_FAMILY) \
| IPSET_FLAG(IPSET_OPT_TYPENAME)\ | IPSET_FLAG(IPSET_OPT_TYPENAME)\
| IPSET_FLAG(IPSET_OPT_TYPE) \ | IPSET_FLAG(IPSET_OPT_TYPE) \
| IPSET_FLAG(IPSET_OPT_IP) \ | IPSET_FLAG(IPSET_OPT_IP) \
@@ -84,7 +86,7 @@ enum ipset_opt {
| IPSET_FLAG(IPSET_OPT_SIZE)) | IPSET_FLAG(IPSET_OPT_SIZE))
#define IPSET_ADT_FLAGS \ #define IPSET_ADT_FLAGS \
( IPSET_FLAG(IPSET_OPT_IP) \ (IPSET_FLAG(IPSET_OPT_IP) \
| IPSET_FLAG(IPSET_OPT_IP_TO) \ | IPSET_FLAG(IPSET_OPT_IP_TO) \
| IPSET_FLAG(IPSET_OPT_CIDR) \ | IPSET_FLAG(IPSET_OPT_CIDR) \
| IPSET_FLAG(IPSET_OPT_PORT) \ | IPSET_FLAG(IPSET_OPT_PORT) \
@@ -96,8 +98,10 @@ enum ipset_opt {
| IPSET_FLAG(IPSET_OPT_IP2) \ | IPSET_FLAG(IPSET_OPT_IP2) \
| IPSET_FLAG(IPSET_OPT_CIDR2) \ | IPSET_FLAG(IPSET_OPT_CIDR2) \
| IPSET_FLAG(IPSET_OPT_PROTO) \ | IPSET_FLAG(IPSET_OPT_PROTO) \
| IPSET_FLAG(IPSET_OPT_IFACE) \
| IPSET_FLAG(IPSET_OPT_CADT_FLAGS)\ | IPSET_FLAG(IPSET_OPT_CADT_FLAGS)\
| IPSET_FLAG(IPSET_OPT_BEFORE)) | IPSET_FLAG(IPSET_OPT_BEFORE) \
| IPSET_FLAG(IPSET_OPT_PHYSDEV))
struct ipset_data; struct ipset_data;
@@ -110,7 +114,7 @@ extern bool ipset_data_ignored(struct ipset_data *data, enum ipset_opt opt);
extern int ipset_data_set(struct ipset_data *data, enum ipset_opt opt, extern int ipset_data_set(struct ipset_data *data, enum ipset_opt opt,
const void *value); const void *value);
extern const void * ipset_data_get(const struct ipset_data *data, extern const void *ipset_data_get(const struct ipset_data *data,
enum ipset_opt opt); enum ipset_opt opt);
static inline bool static inline bool
@@ -120,13 +124,13 @@ ipset_data_test(const struct ipset_data *data, enum ipset_opt opt)
} }
/* Shortcuts */ /* Shortcuts */
extern const char * ipset_data_setname(const struct ipset_data *data); extern const char *ipset_data_setname(const struct ipset_data *data);
extern uint8_t ipset_data_family(const struct ipset_data *data); extern uint8_t ipset_data_family(const struct ipset_data *data);
extern uint8_t ipset_data_cidr(const struct ipset_data *data); extern uint8_t ipset_data_cidr(const struct ipset_data *data);
extern uint64_t ipset_data_flags(const struct ipset_data *data); extern uint64_t ipset_data_flags(const struct ipset_data *data);
extern void ipset_data_reset(struct ipset_data *data); extern void ipset_data_reset(struct ipset_data *data);
extern struct ipset_data * ipset_data_init(void); extern struct ipset_data *ipset_data_init(void);
extern void ipset_data_fini(struct ipset_data *data); extern void ipset_data_fini(struct ipset_data *data);
extern size_t ipset_data_sizeof(enum ipset_opt opt, uint8_t family); extern size_t ipset_data_sizeof(enum ipset_opt opt, uint8_t family);

View File

@@ -12,7 +12,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#define D(fmt, args...) \ #define D(fmt, args...) \
fprintf(stderr, "%s: %s: " fmt "\n", __FILE__, __FUNCTION__ , ## args) fprintf(stderr, "%s: %s: " fmt "\n", __FILE__, __func__ , ## args)
#define IF_D(test, fmt, args...) \ #define IF_D(test, fmt, args...) \
if (test) \ if (test) \
D(fmt , ## args) D(fmt , ## args)

View File

@@ -9,8 +9,8 @@
#include <stdint.h> /* uintxx_t */ #include <stdint.h> /* uintxx_t */
extern const char * id_to_icmp(uint8_t id); extern const char *id_to_icmp(uint8_t id);
extern const char * icmp_to_name(uint8_t type, uint8_t code); extern const char *icmp_to_name(uint8_t type, uint8_t code);
extern int name_to_icmp(const char *str, uint16_t *typecode); extern int name_to_icmp(const char *str, uint16_t *typecode);
#endif /* LIBIPSET_ICMP_H */ #endif /* LIBIPSET_ICMP_H */

View File

@@ -9,8 +9,8 @@
#include <stdint.h> /* uintxx_t */ #include <stdint.h> /* uintxx_t */
extern const char * id_to_icmpv6(uint8_t id); extern const char *id_to_icmpv6(uint8_t id);
extern const char * icmpv6_to_name(uint8_t type, uint8_t code); extern const char *icmpv6_to_name(uint8_t type, uint8_t code);
extern int name_to_icmpv6(const char *str, uint16_t *typecode); extern int name_to_icmpv6(const char *str, uint16_t *typecode);
#endif /* LIBIPSET_ICMPV6_H */ #endif /* LIBIPSET_ICMPV6_H */

View File

@@ -105,6 +105,7 @@ enum {
IPSET_ATTR_IP2, IPSET_ATTR_IP2,
IPSET_ATTR_CIDR2, IPSET_ATTR_CIDR2,
IPSET_ATTR_IP2_TO, IPSET_ATTR_IP2_TO,
IPSET_ATTR_IFACE,
__IPSET_ATTR_ADT_MAX, __IPSET_ATTR_ADT_MAX,
}; };
#define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1) #define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1)
@@ -153,6 +154,8 @@ enum ipset_cmd_flags {
enum ipset_cadt_flags { enum ipset_cadt_flags {
IPSET_FLAG_BIT_BEFORE = 0, IPSET_FLAG_BIT_BEFORE = 0,
IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE), IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE),
IPSET_FLAG_BIT_PHYSDEV = 1,
IPSET_FLAG_PHYSDEV = (1 << IPSET_FLAG_BIT_PHYSDEV),
}; };
/* Commands with settype-specific attributes */ /* Commands with settype-specific attributes */

View File

@@ -80,6 +80,8 @@ extern int ipset_parse_flag(struct ipset_session *session,
enum ipset_opt opt, const char *str); enum ipset_opt opt, const char *str);
extern int ipset_parse_typename(struct ipset_session *session, extern int ipset_parse_typename(struct ipset_session *session,
enum ipset_opt opt, const char *str); enum ipset_opt opt, const char *str);
extern int ipset_parse_iface(struct ipset_session *session,
enum ipset_opt opt, const char *str);
extern int ipset_parse_output(struct ipset_session *session, extern int ipset_parse_output(struct ipset_session *session,
int opt, const char *str); int opt, const char *str);
extern int ipset_parse_ignored(struct ipset_session *session, extern int ipset_parse_ignored(struct ipset_session *session,

View File

@@ -12,7 +12,7 @@
{.ip6 = { \ {.ip6 = { \
__constant_htonl(a), __constant_htonl(b), \ __constant_htonl(a), __constant_htonl(b), \
__constant_htonl(c), __constant_htonl(d), \ __constant_htonl(c), __constant_htonl(d), \
}} } }
/* /*
* This table works for both IPv4 and IPv6; * This table works for both IPv4 and IPv6;

View File

@@ -37,6 +37,9 @@ extern int ipset_print_name(char *buf, unsigned int len,
extern int ipset_print_port(char *buf, unsigned int len, extern int ipset_print_port(char *buf, unsigned int len,
const struct ipset_data *data, const struct ipset_data *data,
enum ipset_opt opt, uint8_t env); enum ipset_opt opt, uint8_t env);
extern int ipset_print_iface(char *buf, unsigned int len,
const struct ipset_data *data,
enum ipset_opt opt, uint8_t env);
extern int ipset_print_proto(char *buf, unsigned int len, extern int ipset_print_proto(char *buf, unsigned int len,
const struct ipset_data *data, const struct ipset_data *data,
enum ipset_opt opt, uint8_t env); enum ipset_opt opt, uint8_t env);

View File

@@ -21,10 +21,14 @@ struct ipset_session;
struct ipset_data; struct ipset_data;
struct ipset_handle; struct ipset_handle;
extern struct ipset_data * ipset_session_data(const struct ipset_session *session); extern struct ipset_data *
extern struct ipset_handle * ipset_session_handle(const struct ipset_session *session); ipset_session_data(const struct ipset_session *session);
extern const struct ipset_type * ipset_saved_type(const struct ipset_session *session); extern struct ipset_handle *
extern void ipset_session_lineno(struct ipset_session *session, uint32_t lineno); ipset_session_handle(const struct ipset_session *session);
extern const struct ipset_type *
ipset_saved_type(const struct ipset_session *session);
extern void ipset_session_lineno(struct ipset_session *session,
uint32_t lineno);
enum ipset_err_type { enum ipset_err_type {
IPSET_ERROR, IPSET_ERROR,
@@ -47,8 +51,8 @@ extern int ipset_session_report(struct ipset_session *session,
}) })
extern void ipset_session_report_reset(struct ipset_session *session); extern void ipset_session_report_reset(struct ipset_session *session);
extern const char * ipset_session_error(const struct ipset_session *session); extern const char *ipset_session_error(const struct ipset_session *session);
extern const char * ipset_session_warning(const struct ipset_session *session); extern const char *ipset_session_warning(const struct ipset_session *session);
#define ipset_session_data_set(session, opt, value) \ #define ipset_session_data_set(session, opt, value) \
ipset_data_set(ipset_session_data(session), opt, value) ipset_data_set(ipset_session_data(session), opt, value)
@@ -93,7 +97,7 @@ extern int ipset_cmd(struct ipset_session *session, enum ipset_cmd cmd,
typedef int (*ipset_outfn)(const char *fmt, ...) typedef int (*ipset_outfn)(const char *fmt, ...)
__attribute__ ((format (printf, 1, 2))); __attribute__ ((format (printf, 1, 2)));
extern struct ipset_session * ipset_session_init(ipset_outfn outfn); extern struct ipset_session *ipset_session_init(ipset_outfn outfn);
extern int ipset_session_fini(struct ipset_session *session); extern int ipset_session_fini(struct ipset_session *session);
extern void ipset_debug_msg(const char *dir, void *buffer, int len); extern void ipset_debug_msg(const char *dir, void *buffer, int len);

View File

@@ -97,13 +97,14 @@ extern int ipset_cache_swap(const char *from, const char *to);
extern int ipset_cache_init(void); extern int ipset_cache_init(void);
extern void ipset_cache_fini(void); extern void ipset_cache_fini(void);
extern const struct ipset_type * ipset_type_get(struct ipset_session *session, extern const struct ipset_type *
enum ipset_cmd cmd); ipset_type_get(struct ipset_session *session, enum ipset_cmd cmd);
extern const struct ipset_type * ipset_type_check(struct ipset_session *session); extern const struct ipset_type *
ipset_type_check(struct ipset_session *session);
extern int ipset_type_add(struct ipset_type *type); extern int ipset_type_add(struct ipset_type *type);
extern const struct ipset_type * ipset_types(void); extern const struct ipset_type *ipset_types(void);
extern const char * ipset_typename_resolve(const char *str); extern const char *ipset_typename_resolve(const char *str);
extern bool ipset_match_typename(const char *str, extern bool ipset_match_typename(const char *str,
const struct ipset_type *t); const struct ipset_type *t);

View File

@@ -11,10 +11,10 @@
#include <netinet/in.h> /* struct in[6]_addr */ #include <netinet/in.h> /* struct in[6]_addr */
/* String equality tests */ /* String equality tests */
#define STREQ(a,b) (strcmp(a,b) == 0) #define STREQ(a, b) (strcmp(a, b) == 0)
#define STRNEQ(a,b,n) (strncmp(a,b,n) == 0) #define STRNEQ(a, b, n) (strncmp(a, b, n) == 0)
#define STRCASEQ(a,b) (strcasecmp(a,b) == 0) #define STRCASEQ(a, b) (strcasecmp(a, b) == 0)
#define STRNCASEQ(a,b,n) (strncasecmp(a,b,n) == 0) #define STRNCASEQ(a, b, n) (strncasecmp(a, b, n) == 0)
/* Stringify tokens */ /* Stringify tokens */
#define _STR(c) #c #define _STR(c) #c

View File

@@ -107,6 +107,7 @@ enum {
IPSET_ATTR_IP2, IPSET_ATTR_IP2,
IPSET_ATTR_CIDR2, IPSET_ATTR_CIDR2,
IPSET_ATTR_IP2_TO, IPSET_ATTR_IP2_TO,
IPSET_ATTR_IFACE,
__IPSET_ATTR_ADT_MAX, __IPSET_ATTR_ADT_MAX,
}; };
#define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1) #define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1)
@@ -155,6 +156,8 @@ enum ipset_cmd_flags {
enum ipset_cadt_flags { enum ipset_cadt_flags {
IPSET_FLAG_BIT_BEFORE = 0, IPSET_FLAG_BIT_BEFORE = 0,
IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE), IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE),
IPSET_FLAG_BIT_PHYSDEV = 1,
IPSET_FLAG_PHYSDEV = (1 << IPSET_FLAG_BIT_PHYSDEV),
}; };
/* Commands with settype-specific attributes */ /* Commands with settype-specific attributes */
@@ -214,6 +217,8 @@ enum ip_set_feature {
IPSET_TYPE_IP2 = (1 << IPSET_TYPE_IP2_FLAG), IPSET_TYPE_IP2 = (1 << IPSET_TYPE_IP2_FLAG),
IPSET_TYPE_NAME_FLAG = 4, IPSET_TYPE_NAME_FLAG = 4,
IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG), IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG),
IPSET_TYPE_IFACE_FLAG = 5,
IPSET_TYPE_IFACE = (1 << IPSET_TYPE_IFACE_FLAG),
/* Strictly speaking not a feature, but a flag for dumping: /* Strictly speaking not a feature, but a flag for dumping:
* this settype must be dumped last */ * this settype must be dumped last */
IPSET_DUMP_LAST_FLAG = 7, IPSET_DUMP_LAST_FLAG = 7,
@@ -328,7 +333,7 @@ struct ip_set {
/* register and unregister set references */ /* register and unregister set references */
extern ip_set_id_t ip_set_get_byname(const char *name, struct ip_set **set); extern ip_set_id_t ip_set_get_byname(const char *name, struct ip_set **set);
extern void ip_set_put_byindex(ip_set_id_t index); extern void ip_set_put_byindex(ip_set_id_t index);
extern const char * ip_set_name_byindex(ip_set_id_t index); extern const char *ip_set_name_byindex(ip_set_id_t index);
extern ip_set_id_t ip_set_nfnl_get(const char *name); extern ip_set_id_t ip_set_nfnl_get(const char *name);
extern ip_set_id_t ip_set_nfnl_get_byindex(ip_set_id_t index); extern ip_set_id_t ip_set_nfnl_get_byindex(ip_set_id_t index);
extern void ip_set_nfnl_put(ip_set_id_t index); extern void ip_set_nfnl_put(ip_set_id_t index);
@@ -346,7 +351,7 @@ extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb,
const struct ip_set_adt_opt *opt); const struct ip_set_adt_opt *opt);
/* Utility functions */ /* Utility functions */
extern void * ip_set_alloc(size_t size); extern void *ip_set_alloc(size_t size);
extern void ip_set_free(void *members); extern void ip_set_free(void *members);
extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr); extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr);
extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr); extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr);

View File

@@ -43,7 +43,7 @@ struct htable {
struct hbucket bucket[0]; /* hashtable buckets */ struct hbucket bucket[0]; /* hashtable buckets */
}; };
#define hbucket(h, i) &((h)->bucket[i]) #define hbucket(h, i) (&((h)->bucket[i]))
/* Book-keeping of the prefixes added to the set */ /* Book-keeping of the prefixes added to the set */
struct ip_set_hash_nets { struct ip_set_hash_nets {
@@ -63,6 +63,9 @@ struct ip_set_hash {
#ifdef IP_SET_HASH_WITH_NETMASK #ifdef IP_SET_HASH_WITH_NETMASK
u8 netmask; /* netmask value for subnets to store */ u8 netmask; /* netmask value for subnets to store */
#endif #endif
#ifdef IP_SET_HASH_WITH_RBTREE
struct rb_root rbtree;
#endif
#ifdef IP_SET_HASH_WITH_NETS #ifdef IP_SET_HASH_WITH_NETS
struct ip_set_hash_nets nets[0]; /* book-keeping of prefixes */ struct ip_set_hash_nets nets[0]; /* book-keeping of prefixes */
#endif #endif
@@ -200,6 +203,9 @@ ip_set_hash_destroy(struct ip_set *set)
del_timer_sync(&h->gc); del_timer_sync(&h->gc);
ahash_destroy(h->table); ahash_destroy(h->table);
#ifdef IP_SET_HASH_WITH_RBTREE
rbtree_destroy(&h->rbtree);
#endif
kfree(h); kfree(h);
set->data = NULL; set->data = NULL;

View File

@@ -635,7 +635,8 @@ static struct ip_set_type bitmap_ipmac_type = {
}, },
.adt_policy = { .adt_policy = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED }, [IPSET_ATTR_IP] = { .type = NLA_NESTED },
[IPSET_ATTR_ETHER] = { .type = NLA_BINARY, .len = ETH_ALEN }, [IPSET_ATTR_ETHER] = { .type = NLA_BINARY,
.len = ETH_ALEN },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
[IPSET_ATTR_LINENO] = { .type = NLA_U32 }, [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
}, },

View File

@@ -0,0 +1,762 @@
/* Copyright (C) 2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/* Kernel module implementing an IP set type: the hash:net,iface type */
#include "jhash.h"
#include <linux/module.h>
#include <linux/ip.h>
#include <linux/skbuff.h>
#include <linux/errno.h>
#include <linux/random.h>
#include <linux/rbtree.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/netlink.h>
#include <linux/netfilter.h>
#include "pfxlen.h"
#include "ip_set.h"
#include "ip_set_timeout.h"
#include "ip_set_hash.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("hash:net,iface type of IP sets");
MODULE_ALIAS("ip_set_hash:net,iface");
/* Interface name rbtree */
struct iface_node {
struct rb_node node;
char iface[IFNAMSIZ];
};
#define iface_data(n) (rb_entry(n, struct iface_node, node)->iface)
static inline long
ifname_compare(const char *_a, const char *_b)
{
const long *a = (const long *)_a;
const long *b = (const long *)_b;
BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long));
if (a[0] != b[0])
return a[0] - b[0];
if (IFNAMSIZ > sizeof(long)) {
if (a[1] != b[1])
return a[1] - b[1];
}
if (IFNAMSIZ > 2 * sizeof(long)) {
if (a[2] != b[2])
return a[2] - b[2];
}
if (IFNAMSIZ > 3 * sizeof(long)) {
if (a[3] != b[3])
return a[3] - b[3];
}
return 0;
}
static void
rbtree_destroy(struct rb_root *root)
{
struct rb_node *p, *n = root->rb_node;
struct iface_node *node;
/* Non-recursive destroy, like in ext3 */
while (n) {
if (n->rb_left) {
n = n->rb_left;
continue;
}
if (n->rb_right) {
n = n->rb_right;
continue;
}
p = rb_parent(n);
node = rb_entry(n, struct iface_node, node);
if (!p)
*root = RB_ROOT;
else if (p->rb_left == n)
p->rb_left = NULL;
else if (p->rb_right == n)
p->rb_right = NULL;
kfree(node);
n = p;
}
}
static int
iface_test(struct rb_root *root, const char **iface)
{
struct rb_node *n = root->rb_node;
while (n) {
const char *d = iface_data(n);
int res = ifname_compare(*iface, d);
if (res < 0)
n = n->rb_left;
else if (res > 0)
n = n->rb_right;
else {
*iface = d;
return 1;
}
}
return 0;
}
static int
iface_add(struct rb_root *root, const char **iface)
{
struct rb_node **n = &(root->rb_node), *p = NULL;
struct iface_node *d;
while (*n) {
char *ifname = iface_data(*n);
int res = ifname_compare(*iface, ifname);
p = *n;
if (res < 0)
n = &((*n)->rb_left);
else if (res > 0)
n = &((*n)->rb_right);
else {
*iface = ifname;
return 0;
}
}
d = kzalloc(sizeof(*d), GFP_ATOMIC);
if (!d)
return -ENOMEM;
strcpy(d->iface, *iface);
rb_link_node(&d->node, p, n);
rb_insert_color(&d->node, root);
*iface = d->iface;
return 0;
}
/* Type specific function prefix */
#define TYPE hash_netiface
static bool
hash_netiface_same_set(const struct ip_set *a, const struct ip_set *b);
#define hash_netiface4_same_set hash_netiface_same_set
#define hash_netiface6_same_set hash_netiface_same_set
#define STREQ(a, b) (strcmp(a, b) == 0)
/* The type variant functions: IPv4 */
/* Member elements without timeout */
struct hash_netiface4_elem {
__be32 ip;
const char *iface;
u8 physdev;
u8 cidr;
u16 padding;
};
/* Member elements with timeout support */
struct hash_netiface4_telem {
__be32 ip;
const char *iface;
u8 physdev;
u8 cidr;
u16 padding;
unsigned long timeout;
};
static inline bool
hash_netiface4_data_equal(const struct hash_netiface4_elem *ip1,
const struct hash_netiface4_elem *ip2)
{
return ip1->ip == ip2->ip &&
ip1->cidr == ip2->cidr &&
ip1->physdev == ip2->physdev &&
ip1->iface == ip2->iface;
}
static inline bool
hash_netiface4_data_isnull(const struct hash_netiface4_elem *elem)
{
return elem->cidr == 0;
}
static inline void
hash_netiface4_data_copy(struct hash_netiface4_elem *dst,
const struct hash_netiface4_elem *src) {
dst->ip = src->ip;
dst->cidr = src->cidr;
dst->physdev = src->physdev;
dst->iface = src->iface;
}
static inline void
hash_netiface4_data_netmask(struct hash_netiface4_elem *elem, u8 cidr)
{
elem->ip &= ip_set_netmask(cidr);
elem->cidr = cidr;
}
static inline void
hash_netiface4_data_zero_out(struct hash_netiface4_elem *elem)
{
elem->cidr = 0;
}
static bool
hash_netiface4_data_list(struct sk_buff *skb,
const struct hash_netiface4_elem *data)
{
u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
if (flags)
NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags);
return 0;
nla_put_failure:
return 1;
}
static bool
hash_netiface4_data_tlist(struct sk_buff *skb,
const struct hash_netiface4_elem *data)
{
const struct hash_netiface4_telem *tdata =
(const struct hash_netiface4_telem *)data;
u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
if (flags)
NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags);
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(tdata->timeout)));
return 0;
nla_put_failure:
return 1;
}
#define IP_SET_HASH_WITH_NETS
#define IP_SET_HASH_WITH_RBTREE
#define PF 4
#define HOST_MASK 32
#include "ip_set_ahash.h"
static inline void
hash_netiface4_data_next(struct ip_set_hash *h,
const struct hash_netiface4_elem *d)
{
h->next.ip = ntohl(d->ip);
}
static int
hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
{
struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netiface4_elem data = {
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
};
int ret;
if (data.cidr == 0)
return -EINVAL;
if (adt == IPSET_TEST)
data.cidr = HOST_MASK;
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
data.ip &= ip_set_netmask(data.cidr);
#define IFACE(dir) (par->dir ? par->dir->name : NULL)
#define PHYSDEV(dir) (nf_bridge->dir ? nf_bridge->dir->name : NULL)
#define SRCDIR (opt->flags & IPSET_DIM_TWO_SRC)
if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
#ifdef CONFIG_BRIDGE_NETFILTER
const struct nf_bridge_info *nf_bridge = skb->nf_bridge;
if (!nf_bridge)
return -EINVAL;
data.iface = SRCDIR ? PHYSDEV(physindev) : PHYSDEV(physoutdev);
data.physdev = 1;
#else
data.iface = NULL;
#endif
} else
data.iface = SRCDIR ? IFACE(in) : IFACE(out);
if (!data.iface)
return -EINVAL;
ret = iface_test(&h->rbtree, &data.iface);
if (adt == IPSET_ADD) {
if (!ret) {
ret = iface_add(&h->rbtree, &data.iface);
if (ret)
return ret;
}
} else if (!ret)
return ret;
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
}
static int
hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netiface4_elem data = { .cidr = HOST_MASK };
u32 ip = 0, ip_to, last;
u32 timeout = h->timeout;
char iface[IFNAMSIZ] = {};
int ret;
if (unlikely(!tb[IPSET_ATTR_IP] ||
!tb[IPSET_ATTR_IFACE] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
if (ret)
return ret;
if (tb[IPSET_ATTR_CIDR]) {
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
if (!data.cidr)
return -IPSET_ERR_INVALID_CIDR;
}
if (tb[IPSET_ATTR_TIMEOUT]) {
if (!with_timeout(h->timeout))
return -IPSET_ERR_TIMEOUT;
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
strcpy(iface, nla_data(tb[IPSET_ATTR_IFACE]));
data.iface = iface;
ret = iface_test(&h->rbtree, &data.iface);
if (adt == IPSET_ADD) {
if (!ret) {
ret = iface_add(&h->rbtree, &data.iface);
if (ret)
return ret;
}
} else if (!ret)
return ret;
if (tb[IPSET_ATTR_CADT_FLAGS]) {
u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
if (cadt_flags & IPSET_FLAG_PHYSDEV)
data.physdev = 1;
}
if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
data.ip = htonl(ip & ip_set_hostmask(data.cidr));
ret = adtfn(set, &data, timeout, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
if (tb[IPSET_ATTR_IP_TO]) {
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
if (ret)
return ret;
if (ip_to < ip)
swap(ip, ip_to);
if (ip + UINT_MAX == ip_to)
return -IPSET_ERR_HASH_RANGE;
} else {
ip_set_mask_from_to(ip, ip_to, data.cidr);
}
if (retried)
ip = h->next.ip;
while (!after(ip, ip_to)) {
data.ip = htonl(ip);
last = ip_set_range_to_cidr(ip, ip_to, &data.cidr);
ret = adtfn(set, &data, timeout, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
else
ret = 0;
ip = last + 1;
}
return ret;
}
static bool
hash_netiface_same_set(const struct ip_set *a, const struct ip_set *b)
{
const struct ip_set_hash *x = a->data;
const struct ip_set_hash *y = b->data;
/* Resizing changes htable_bits, so we ignore it */
return x->maxelem == y->maxelem &&
x->timeout == y->timeout;
}
/* The type variant functions: IPv6 */
struct hash_netiface6_elem {
union nf_inet_addr ip;
const char *iface;
u8 physdev;
u8 cidr;
u16 padding;
};
struct hash_netiface6_telem {
union nf_inet_addr ip;
const char *iface;
u8 physdev;
u8 cidr;
u16 padding;
unsigned long timeout;
};
static inline bool
hash_netiface6_data_equal(const struct hash_netiface6_elem *ip1,
const struct hash_netiface6_elem *ip2)
{
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
ip1->cidr == ip2->cidr &&
ip1->physdev == ip2->physdev &&
ip1->iface == ip2->iface;
}
static inline bool
hash_netiface6_data_isnull(const struct hash_netiface6_elem *elem)
{
return elem->cidr == 0;
}
static inline void
hash_netiface6_data_copy(struct hash_netiface6_elem *dst,
const struct hash_netiface6_elem *src)
{
memcpy(dst, src, sizeof(*dst));
}
static inline void
hash_netiface6_data_zero_out(struct hash_netiface6_elem *elem)
{
}
static inline void
ip6_netmask(union nf_inet_addr *ip, u8 prefix)
{
ip->ip6[0] &= ip_set_netmask6(prefix)[0];
ip->ip6[1] &= ip_set_netmask6(prefix)[1];
ip->ip6[2] &= ip_set_netmask6(prefix)[2];
ip->ip6[3] &= ip_set_netmask6(prefix)[3];
}
static inline void
hash_netiface6_data_netmask(struct hash_netiface6_elem *elem, u8 cidr)
{
ip6_netmask(&elem->ip, cidr);
elem->cidr = cidr;
}
static bool
hash_netiface6_data_list(struct sk_buff *skb,
const struct hash_netiface6_elem *data)
{
u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
if (flags)
NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags);
return 0;
nla_put_failure:
return 1;
}
static bool
hash_netiface6_data_tlist(struct sk_buff *skb,
const struct hash_netiface6_elem *data)
{
const struct hash_netiface6_telem *e =
(const struct hash_netiface6_telem *)data;
u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
if (flags)
NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags);
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(e->timeout)));
return 0;
nla_put_failure:
return 1;
}
#undef PF
#undef HOST_MASK
#define PF 6
#define HOST_MASK 128
#include "ip_set_ahash.h"
static inline void
hash_netiface6_data_next(struct ip_set_hash *h,
const struct hash_netiface6_elem *d)
{
}
static int
hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
{
struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netiface6_elem data = {
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
};
int ret;
if (data.cidr == 0)
return -EINVAL;
if (adt == IPSET_TEST)
data.cidr = HOST_MASK;
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
ip6_netmask(&data.ip, data.cidr);
if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
#ifdef CONFIG_BRIDGE_NETFILTER
const struct nf_bridge_info *nf_bridge = skb->nf_bridge;
if (!nf_bridge)
return -EINVAL;
data.iface = SRCDIR ? PHYSDEV(physindev) : PHYSDEV(physoutdev);
data.physdev = 1;
#else
data.iface = NULL;
#endif
} else
data.iface = SRCDIR ? IFACE(in) : IFACE(out);
if (!data.iface)
return -EINVAL;
ret = iface_test(&h->rbtree, &data.iface);
if (adt == IPSET_ADD) {
if (!ret) {
ret = iface_add(&h->rbtree, &data.iface);
if (ret)
return ret;
}
} else if (!ret)
return ret;
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
}
static int
hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netiface6_elem data = { .cidr = HOST_MASK };
u32 timeout = h->timeout;
char iface[IFNAMSIZ] = {};
int ret;
if (unlikely(!tb[IPSET_ATTR_IP] ||
!tb[IPSET_ATTR_IFACE] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
return -IPSET_ERR_PROTOCOL;
if (unlikely(tb[IPSET_ATTR_IP_TO]))
return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
if (ret)
return ret;
if (tb[IPSET_ATTR_CIDR])
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
if (!data.cidr)
return -IPSET_ERR_INVALID_CIDR;
ip6_netmask(&data.ip, data.cidr);
if (tb[IPSET_ATTR_TIMEOUT]) {
if (!with_timeout(h->timeout))
return -IPSET_ERR_TIMEOUT;
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
strcpy(iface, nla_data(tb[IPSET_ATTR_IFACE]));
data.iface = iface;
ret = iface_test(&h->rbtree, &data.iface);
if (adt == IPSET_ADD) {
if (!ret) {
ret = iface_add(&h->rbtree, &data.iface);
if (ret)
return ret;
}
} else if (!ret)
return ret;
if (tb[IPSET_ATTR_CADT_FLAGS]) {
u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
if (cadt_flags & IPSET_FLAG_PHYSDEV)
data.physdev = 1;
}
ret = adtfn(set, &data, timeout, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
/* Create hash:ip type of sets */
static int
hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
{
struct ip_set_hash *h;
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
u8 hbits;
if (!(set->family == AF_INET || set->family == AF_INET6))
return -IPSET_ERR_INVALID_FAMILY;
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_HASHSIZE]) {
hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
if (hashsize < IPSET_MIMINAL_HASHSIZE)
hashsize = IPSET_MIMINAL_HASHSIZE;
}
if (tb[IPSET_ATTR_MAXELEM])
maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
h = kzalloc(sizeof(*h)
+ sizeof(struct ip_set_hash_nets)
* (set->family == AF_INET ? 32 : 128), GFP_KERNEL);
if (!h)
return -ENOMEM;
h->maxelem = maxelem;
get_random_bytes(&h->initval, sizeof(h->initval));
h->timeout = IPSET_NO_TIMEOUT;
hbits = htable_bits(hashsize);
h->table = ip_set_alloc(
sizeof(struct htable)
+ jhash_size(hbits) * sizeof(struct hbucket));
if (!h->table) {
kfree(h);
return -ENOMEM;
}
h->table->htable_bits = hbits;
h->rbtree = RB_ROOT;
set->data = h;
if (tb[IPSET_ATTR_TIMEOUT]) {
h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
set->variant = set->family == AF_INET
? &hash_netiface4_tvariant : &hash_netiface6_tvariant;
if (set->family == AF_INET)
hash_netiface4_gc_init(set);
else
hash_netiface6_gc_init(set);
} else {
set->variant = set->family == AF_INET
? &hash_netiface4_variant : &hash_netiface6_variant;
}
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
set->name, jhash_size(h->table->htable_bits),
h->table->htable_bits, h->maxelem, set->data, h->table);
return 0;
}
static struct ip_set_type hash_netiface_type __read_mostly = {
.name = "hash:net,iface",
.protocol = IPSET_PROTOCOL,
.features = IPSET_TYPE_IP | IPSET_TYPE_IFACE,
.dimension = IPSET_DIM_TWO,
.family = AF_UNSPEC,
.revision_min = 0,
.create = hash_netiface_create,
.create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
[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 },
},
.adt_policy = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
[IPSET_ATTR_IFACE] = { .type = NLA_NUL_STRING,
.len = IPSET_MAXNAMELEN - 1 },
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
},
.me = THIS_MODULE,
};
static int __init
hash_netiface_init(void)
{
return ip_set_type_register(&hash_netiface_type);
}
static void __exit
hash_netiface_fini(void)
{
ip_set_type_unregister(&hash_netiface_type);
}
module_init(hash_netiface_init);
module_exit(hash_netiface_fini);

View File

@@ -7,6 +7,7 @@
#include <assert.h> /* assert */ #include <assert.h> /* assert */
#include <arpa/inet.h> /* ntoh* */ #include <arpa/inet.h> /* ntoh* */
#include <net/ethernet.h> /* ETH_ALEN */ #include <net/ethernet.h> /* ETH_ALEN */
#include <net/if.h> /* IFNAMSIZ */
#include <sys/socket.h> /* AF_ */ #include <sys/socket.h> /* AF_ */
#include <stdlib.h> /* malloc, free */ #include <stdlib.h> /* malloc, free */
#include <string.h> /* memset */ #include <string.h> /* memset */
@@ -72,6 +73,7 @@ struct ipset_data {
char ether[ETH_ALEN]; char ether[ETH_ALEN];
char name[IPSET_MAXNAMELEN]; char name[IPSET_MAXNAMELEN];
char nameref[IPSET_MAXNAMELEN]; char nameref[IPSET_MAXNAMELEN];
char iface[IFNAMSIZ];
} adt; } adt;
}; };
}; };
@@ -301,6 +303,9 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
case IPSET_OPT_PROTO: case IPSET_OPT_PROTO:
data->adt.proto = *(const uint8_t *) value; data->adt.proto = *(const uint8_t *) value;
break; break;
case IPSET_OPT_IFACE:
ipset_strlcpy(data->adt.iface, value, IFNAMSIZ);
break;
/* Swap/rename */ /* Swap/rename */
case IPSET_OPT_SETNAME2: case IPSET_OPT_SETNAME2:
ipset_strlcpy(data->setname2, value, IPSET_MAXNAMELEN); ipset_strlcpy(data->setname2, value, IPSET_MAXNAMELEN);
@@ -312,6 +317,9 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
case IPSET_OPT_BEFORE: case IPSET_OPT_BEFORE:
cadt_flag_type_attr(data, opt, IPSET_FLAG_BEFORE); cadt_flag_type_attr(data, opt, IPSET_FLAG_BEFORE);
break; break;
case IPSET_OPT_PHYSDEV:
cadt_flag_type_attr(data, opt, IPSET_FLAG_PHYSDEV);
break;
case IPSET_OPT_FLAGS: case IPSET_OPT_FLAGS:
data->flags = *(const uint32_t *)value; data->flags = *(const uint32_t *)value;
break; break;
@@ -413,6 +421,8 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
return &data->adt.cidr2; return &data->adt.cidr2;
case IPSET_OPT_PROTO: case IPSET_OPT_PROTO:
return &data->adt.proto; return &data->adt.proto;
case IPSET_OPT_IFACE:
return &data->adt.iface;
/* Swap/rename */ /* Swap/rename */
case IPSET_OPT_SETNAME2: case IPSET_OPT_SETNAME2:
return data->setname2; return data->setname2;
@@ -422,6 +432,7 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
return &data->flags; return &data->flags;
case IPSET_OPT_CADT_FLAGS: case IPSET_OPT_CADT_FLAGS:
case IPSET_OPT_BEFORE: case IPSET_OPT_BEFORE:
case IPSET_OPT_PHYSDEV:
return &data->cadt_flags; return &data->cadt_flags;
default: default:
return NULL; return NULL;
@@ -472,8 +483,9 @@ ipset_data_sizeof(enum ipset_opt opt, uint8_t family)
return sizeof(uint8_t); return sizeof(uint8_t);
case IPSET_OPT_ETHER: case IPSET_OPT_ETHER:
return ETH_ALEN; return ETH_ALEN;
/* Flags counted once */ /* Flags doesn't counted once :-( */
case IPSET_OPT_BEFORE: case IPSET_OPT_BEFORE:
case IPSET_OPT_PHYSDEV:
return sizeof(uint32_t); return sizeof(uint32_t);
default: default:
return 0; return 0;

View File

@@ -63,6 +63,7 @@ static const struct ipset_attrname adtattr2name[] = {
[IPSET_ATTR_IP2] = { .name = "IP2" }, [IPSET_ATTR_IP2] = { .name = "IP2" },
[IPSET_ATTR_CIDR2] = { .name = "CIDR2" }, [IPSET_ATTR_CIDR2] = { .name = "CIDR2" },
[IPSET_ATTR_IP2_TO] = { .name = "IP2_TO" }, [IPSET_ATTR_IP2_TO] = { .name = "IP2_TO" },
[IPSET_ATTR_IFACE] = { .name = "IFACE" },
}; };
static void static void
@@ -73,23 +74,24 @@ debug_cadt_attrs(int max, const struct ipset_attr_policy *policy,
uint32_t v; uint32_t v;
int i; int i;
fprintf(stderr,"\t\t%s attributes:\n", policy == create_attrs ? "CREATE" : "ADT"); fprintf(stderr, "\t\t%s attributes:\n",
policy == create_attrs ? "CREATE" : "ADT");
for (i = IPSET_ATTR_UNSPEC + 1; i <= max; i++) { for (i = IPSET_ATTR_UNSPEC + 1; i <= max; i++) {
if (!nla[i]) if (!nla[i])
continue; continue;
switch (policy[i].type) { switch (policy[i].type) {
case MNL_TYPE_U8: case MNL_TYPE_U8:
v = * (uint8_t *) mnl_attr_get_payload(nla[i]); v = *(uint8_t *) mnl_attr_get_payload(nla[i]);
fprintf(stderr, "\t\t%s: %u\n", fprintf(stderr, "\t\t%s: %u\n",
attr2name[i].name, v); attr2name[i].name, v);
break; break;
case MNL_TYPE_U16: case MNL_TYPE_U16:
v = * (uint16_t *) mnl_attr_get_payload(nla[i]); v = *(uint16_t *) mnl_attr_get_payload(nla[i]);
fprintf(stderr, "\t\t%s: %u\n", fprintf(stderr, "\t\t%s: %u\n",
attr2name[i].name, ntohs(v)); attr2name[i].name, ntohs(v));
break; break;
case MNL_TYPE_U32: case MNL_TYPE_U32:
v = * (uint32_t *) mnl_attr_get_payload(nla[i]); v = *(uint32_t *) mnl_attr_get_payload(nla[i]);
fprintf(stderr, "\t\t%s: %u\n", fprintf(stderr, "\t\t%s: %u\n",
attr2name[i].name, ntohl(v)); attr2name[i].name, ntohl(v));
break; break;
@@ -103,18 +105,23 @@ debug_cadt_attrs(int max, const struct ipset_attr_policy *policy,
char addr[INET6_ADDRSTRLEN]; char addr[INET6_ADDRSTRLEN];
void *d; void *d;
if (mnl_attr_parse_nested(nla[i], ipaddr_attr_cb, ipattr) < 0) { if (mnl_attr_parse_nested(nla[i], ipaddr_attr_cb,
fprintf(stderr, "\t\tIPADDR: cannot validate and parse attributes\n"); ipattr) < 0) {
fprintf(stderr,
"\t\tIPADDR: cannot validate "
"and parse attributes\n");
continue; continue;
} }
if (ipattr[IPSET_ATTR_IPADDR_IPV4]) { if (ipattr[IPSET_ATTR_IPADDR_IPV4]) {
d = mnl_attr_get_payload(ipattr[IPSET_ATTR_IPADDR_IPV4]); d = mnl_attr_get_payload(
ipattr[IPSET_ATTR_IPADDR_IPV4]);
inet_ntop(AF_INET, d, addr, INET6_ADDRSTRLEN); inet_ntop(AF_INET, d, addr, INET6_ADDRSTRLEN);
fprintf(stderr, "\t\t%s: %s\n", fprintf(stderr, "\t\t%s: %s\n",
attr2name[i].name, addr); attr2name[i].name, addr);
} else if (ipattr[IPSET_ATTR_IPADDR_IPV6]) { } else if (ipattr[IPSET_ATTR_IPADDR_IPV6]) {
d = mnl_attr_get_payload(ipattr[IPSET_ATTR_IPADDR_IPV6]); d = mnl_attr_get_payload(
ipattr[IPSET_ATTR_IPADDR_IPV6]);
inet_ntop(AF_INET6, d, addr, INET6_ADDRSTRLEN); inet_ntop(AF_INET6, d, addr, INET6_ADDRSTRLEN);
fprintf(stderr, "\t\t%s: %s\n", fprintf(stderr, "\t\t%s: %s\n",
@@ -137,23 +144,23 @@ debug_cmd_attrs(int cmd, struct nlattr *nla[])
uint32_t v; uint32_t v;
int i; int i;
fprintf(stderr,"\tCommand attributes:\n"); fprintf(stderr, "\tCommand attributes:\n");
for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_CMD_MAX; i++) { for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_CMD_MAX; i++) {
if (!nla[i]) if (!nla[i])
continue; continue;
switch (cmd_attrs[i].type) { switch (cmd_attrs[i].type) {
case MNL_TYPE_U8: case MNL_TYPE_U8:
v = * (uint8_t *) mnl_attr_get_payload(nla[i]); v = *(uint8_t *) mnl_attr_get_payload(nla[i]);
fprintf(stderr, "\t%s: %u\n", fprintf(stderr, "\t%s: %u\n",
cmdattr2name[i].name, v); cmdattr2name[i].name, v);
break; break;
case MNL_TYPE_U16: case MNL_TYPE_U16:
v = * (uint16_t *) mnl_attr_get_payload(nla[i]); v = *(uint16_t *) mnl_attr_get_payload(nla[i]);
fprintf(stderr, "\t%s: %u\n", fprintf(stderr, "\t%s: %u\n",
cmdattr2name[i].name, ntohs(v)); cmdattr2name[i].name, ntohs(v));
break; break;
case MNL_TYPE_U32: case MNL_TYPE_U32:
v = * (uint32_t *) mnl_attr_get_payload(nla[i]); v = *(uint32_t *) mnl_attr_get_payload(nla[i]);
fprintf(stderr, "\t%s: %u\n", fprintf(stderr, "\t%s: %u\n",
cmdattr2name[i].name, ntohl(v)); cmdattr2name[i].name, ntohl(v));
break; break;
@@ -168,8 +175,11 @@ debug_cmd_attrs(int cmd, struct nlattr *nla[])
case IPSET_CMD_ADD: case IPSET_CMD_ADD:
case IPSET_CMD_DEL: case IPSET_CMD_DEL:
case IPSET_CMD_TEST: case IPSET_CMD_TEST:
if (mnl_attr_parse_nested(nla[i], adt_attr_cb, adt) < 0) { if (mnl_attr_parse_nested(nla[i],
fprintf(stderr, "\tADT: cannot validate and parse attributes\n"); adt_attr_cb, adt) < 0) {
fprintf(stderr,
"\tADT: cannot validate "
"and parse attributes\n");
continue; continue;
} }
debug_cadt_attrs(IPSET_ATTR_ADT_MAX, debug_cadt_attrs(IPSET_ATTR_ADT_MAX,
@@ -178,8 +188,12 @@ debug_cmd_attrs(int cmd, struct nlattr *nla[])
adt); adt);
break; break;
default: default:
if (mnl_attr_parse_nested(nla[i], create_attr_cb, cattr) < 0) { if (mnl_attr_parse_nested(nla[i],
fprintf(stderr, "\tCREATE: cannot validate and parse attributes\n"); create_attr_cb,
cattr) < 0) {
fprintf(stderr,
"\tCREATE: cannot validate "
"and parse attributes\n");
continue; continue;
} }
debug_cadt_attrs(IPSET_ATTR_CREATE_MAX, debug_cadt_attrs(IPSET_ATTR_CREATE_MAX,
@@ -191,8 +205,11 @@ debug_cmd_attrs(int cmd, struct nlattr *nla[])
struct nlattr *tb; struct nlattr *tb;
mnl_attr_for_each_nested(tb, nla[i]) { mnl_attr_for_each_nested(tb, nla[i]) {
memset(adt, 0, sizeof(adt)); memset(adt, 0, sizeof(adt));
if (mnl_attr_parse_nested(tb, adt_attr_cb, adt) < 0) { if (mnl_attr_parse_nested(tb,
fprintf(stderr, "\tADT: cannot validate and parse attributes\n"); adt_attr_cb, adt) < 0) {
fprintf(stderr,
"\tADT: cannot validate "
"and parse attributes\n");
continue; continue;
} }
debug_cadt_attrs(IPSET_ATTR_ADT_MAX, debug_cadt_attrs(IPSET_ATTR_ADT_MAX,
@@ -227,7 +244,8 @@ ipset_debug_msg(const char *dir, void *buffer, int len)
"\tseq %u\n", "\tseq %u\n",
dir, dir,
nlh->nlmsg_type == NLMSG_NOOP ? "NOOP" : nlh->nlmsg_type == NLMSG_NOOP ? "NOOP" :
nlh->nlmsg_type == NLMSG_DONE ? "DONE" : "OVERRUN", nlh->nlmsg_type == NLMSG_DONE ? "DONE" :
"OVERRUN",
len, nlh->nlmsg_seq); len, nlh->nlmsg_seq);
goto next_msg; goto next_msg;
case NLMSG_ERROR: { case NLMSG_ERROR: {
@@ -256,8 +274,10 @@ ipset_debug_msg(const char *dir, void *buffer, int len)
if (cmd <= IPSET_CMD_NONE || cmd >= IPSET_CMD_MAX) if (cmd <= IPSET_CMD_NONE || cmd >= IPSET_CMD_MAX)
goto next_msg; goto next_msg;
memset(nla, 0, sizeof(nla)); memset(nla, 0, sizeof(nla));
if (mnl_attr_parse(nlh, nfmsglen, cmd_attr_cb, nla) < MNL_CB_STOP) { if (mnl_attr_parse(nlh, nfmsglen,
fprintf(stderr, "\tcannot validate and parse attributes\n"); cmd_attr_cb, nla) < MNL_CB_STOP) {
fprintf(stderr, "\tcannot validate "
"and parse attributes\n");
goto next_msg; goto next_msg;
} }
debug_cmd_attrs(cmd, nla); debug_cmd_attrs(cmd, nla);

View File

@@ -49,17 +49,18 @@ static const struct icmp_names icmp_typecodes[] = {
{ "address-mask-reply", 18, 0 }, { "address-mask-reply", 18, 0 },
}; };
const char * id_to_icmp(uint8_t id) const char *id_to_icmp(uint8_t id)
{ {
return id < ARRAY_SIZE(icmp_typecodes) ? icmp_typecodes[id].name : NULL; return id < ARRAY_SIZE(icmp_typecodes) ? icmp_typecodes[id].name : NULL;
} }
const char * icmp_to_name(uint8_t type, uint8_t code) const char *icmp_to_name(uint8_t type, uint8_t code)
{ {
unsigned int i; unsigned int i;
for (i = 0; i < ARRAY_SIZE(icmp_typecodes); i++) for (i = 0; i < ARRAY_SIZE(icmp_typecodes); i++)
if (icmp_typecodes[i].type == type && icmp_typecodes[i].code == code) if (icmp_typecodes[i].type == type &&
icmp_typecodes[i].code == code)
return icmp_typecodes[i].name; return icmp_typecodes[i].name;
return NULL; return NULL;
@@ -71,7 +72,8 @@ int name_to_icmp(const char *str, uint16_t *typecode)
for (i = 0; i < ARRAY_SIZE(icmp_typecodes); i++) for (i = 0; i < ARRAY_SIZE(icmp_typecodes); i++)
if (STRNCASEQ(icmp_typecodes[i].name, str, strlen(str))) { if (STRNCASEQ(icmp_typecodes[i].name, str, strlen(str))) {
*typecode = (icmp_typecodes[i].type << 8) | icmp_typecodes[i].code; *typecode = (icmp_typecodes[i].type << 8) |
icmp_typecodes[i].code;
return 0; return 0;
} }

View File

@@ -36,17 +36,19 @@ static const struct icmpv6_names icmpv6_typecodes[] = {
{ "redirect", 137, 0 }, { "redirect", 137, 0 },
}; };
const char * id_to_icmpv6(uint8_t id) const char *id_to_icmpv6(uint8_t id)
{ {
return id < ARRAY_SIZE(icmpv6_typecodes) ? icmpv6_typecodes[id].name : NULL; return id < ARRAY_SIZE(icmpv6_typecodes) ?
icmpv6_typecodes[id].name : NULL;
} }
const char * icmpv6_to_name(uint8_t type, uint8_t code) const char *icmpv6_to_name(uint8_t type, uint8_t code)
{ {
unsigned int i; unsigned int i;
for (i = 0; i < ARRAY_SIZE(icmpv6_typecodes); i++) for (i = 0; i < ARRAY_SIZE(icmpv6_typecodes); i++)
if (icmpv6_typecodes[i].type == type && icmpv6_typecodes[i].code == code) if (icmpv6_typecodes[i].type == type &&
icmpv6_typecodes[i].code == code)
return icmpv6_typecodes[i].name; return icmpv6_typecodes[i].name;
return NULL; return NULL;
@@ -58,7 +60,8 @@ int name_to_icmpv6(const char *str, uint16_t *typecode)
for (i = 0; i < ARRAY_SIZE(icmpv6_typecodes); i++) for (i = 0; i < ARRAY_SIZE(icmpv6_typecodes); i++)
if (STRNCASEQ(icmpv6_typecodes[i].name, str, strlen(str))) { if (STRNCASEQ(icmpv6_typecodes[i].name, str, strlen(str))) {
*typecode = (icmpv6_typecodes[i].type << 8) | icmpv6_typecodes[i].code; *typecode = (icmpv6_typecodes[i].type << 8) |
icmpv6_typecodes[i].code;
return 0; return 0;
} }

View File

@@ -38,7 +38,8 @@ struct ipset_handle {
/* Netlink flags of the commands */ /* Netlink flags of the commands */
static const uint16_t cmdflags[] = { static const uint16_t cmdflags[] = {
[IPSET_CMD_CREATE-1] = NLM_F_REQUEST|NLM_F_ACK|NLM_F_CREATE|NLM_F_EXCL, [IPSET_CMD_CREATE-1] = NLM_F_REQUEST|NLM_F_ACK|
NLM_F_CREATE|NLM_F_EXCL,
[IPSET_CMD_DESTROY-1] = NLM_F_REQUEST|NLM_F_ACK, [IPSET_CMD_DESTROY-1] = NLM_F_REQUEST|NLM_F_ACK,
[IPSET_CMD_FLUSH-1] = NLM_F_REQUEST|NLM_F_ACK, [IPSET_CMD_FLUSH-1] = NLM_F_REQUEST|NLM_F_ACK,
[IPSET_CMD_RENAME-1] = NLM_F_REQUEST|NLM_F_ACK, [IPSET_CMD_RENAME-1] = NLM_F_REQUEST|NLM_F_ACK,

View File

@@ -12,6 +12,7 @@
#include <sys/types.h> /* getaddrinfo */ #include <sys/types.h> /* getaddrinfo */
#include <sys/socket.h> /* getaddrinfo, AF_ */ #include <sys/socket.h> /* getaddrinfo, AF_ */
#include <net/ethernet.h> /* ETH_ALEN */ #include <net/ethernet.h> /* ETH_ALEN */
#include <net/if.h> /* IFNAMSIZ */
#include <netinet/in.h> /* IPPROTO_ */ #include <netinet/in.h> /* IPPROTO_ */
#include <libipset/debug.h> /* D() */ #include <libipset/debug.h> /* D() */
@@ -47,11 +48,13 @@ ipset_strchr(const char *str, const char *sep)
assert(str); assert(str);
assert(sep); assert(sep);
for (; *sep != '\0'; sep++) for (; *sep != '\0'; sep++) {
if ((match = strchr(str, sep[0])) != NULL match = strchr(str, sep[0]);
&& str[0] != sep[0] if (match != NULL &&
&& str[strlen(str)-1] != sep[0]) str[0] != sep[0] &&
str[strlen(str)-1] != sep[0])
return match; return match;
}
return NULL; return NULL;
} }
@@ -178,9 +181,9 @@ ipset_parse_ether(struct ipset_session *session,
number = strtol(str + i * 3, &end, 16); number = strtol(str + i * 3, &end, 16);
if (end == str + i * 3 + 2 if (end == str + i * 3 + 2 &&
&& (*end == ':' || *end == '\0') (*end == ':' || *end == '\0') &&
&& number >= 0 && number <= 255) number >= 0 && number <= 255)
ether[i] = number; ether[i] = number;
else else
goto error; goto error;
@@ -198,9 +201,9 @@ static int
parse_portname(struct ipset_session *session, const char *str, parse_portname(struct ipset_session *session, const char *str,
uint16_t *port, const char *proto) uint16_t *port, const char *proto)
{ {
struct servent *service; struct servent *service = getservbyname(str, proto);
if ((service = getservbyname(str, proto)) != NULL) { if (service != NULL) {
*port = ntohs((uint16_t) service->s_port); *port = ntohs((uint16_t) service->s_port);
return 0; return 0;
} }
@@ -232,8 +235,8 @@ ipset_parse_port(struct ipset_session *session,
assert(opt == IPSET_OPT_PORT || opt == IPSET_OPT_PORT_TO); assert(opt == IPSET_OPT_PORT || opt == IPSET_OPT_PORT_TO);
assert(str); assert(str);
if ((err = string_to_u16(session, str, &port)) == 0 if ((err = string_to_u16(session, str, &port)) == 0 ||
|| (err = parse_portname(session, str, &port, proto)) == 0) (err = parse_portname(session, str, &port, proto)) == 0)
err = ipset_session_data_set(session, opt, &port); err = ipset_session_data_set(session, opt, &port);
if (!err) if (!err)
@@ -384,11 +387,12 @@ parse_icmp_typecode(struct ipset_session *session,
if (a == NULL) { if (a == NULL) {
free(saved); free(saved);
return ipset_err(session, return ipset_err(session,
"Cannot parse %s as an %s type/code.", str, family); "Cannot parse %s as an %s type/code.",
str, family);
} }
*a++ = '\0'; *a++ = '\0';
if ((err = string_to_u8(session, a, &type)) != 0 if ((err = string_to_u8(session, a, &type)) != 0 ||
|| (err = string_to_u8(session, tmp, &code)) != 0) (err = string_to_u8(session, tmp, &code)) != 0)
goto error; goto error;
typecode = (type << 8) | code; typecode = (type << 8) | code;
@@ -508,21 +512,24 @@ ipset_parse_proto_port(struct ipset_session *session,
goto parse_port; goto parse_port;
case IPPROTO_ICMP: case IPPROTO_ICMP:
if (family != AF_INET) { if (family != AF_INET) {
syntax_err("Protocol ICMP can be used with family INET only"); syntax_err("Protocol ICMP can be used "
"with family INET only");
goto error; goto error;
} }
err = ipset_parse_icmp(session, opt, a); err = ipset_parse_icmp(session, opt, a);
break; break;
case IPPROTO_ICMPV6: case IPPROTO_ICMPV6:
if (family != AF_INET6) { if (family != AF_INET6) {
syntax_err("Protocol ICMPv6 can be used with family INET6 only"); syntax_err("Protocol ICMPv6 can be used "
"with family INET6 only");
goto error; goto error;
} }
err = ipset_parse_icmpv6(session, opt, a); err = ipset_parse_icmpv6(session, opt, a);
break; break;
default: default:
if (!STREQ(a, "0")) { if (!STREQ(a, "0")) {
syntax_err("Protocol %s can be used with pseudo port value 0 only."); syntax_err("Protocol %s can be used "
"with pseudo port value 0 only.");
goto error; goto error;
} }
ipset_data_flags_set(data, IPSET_FLAG(opt)); ipset_data_flags_set(data, IPSET_FLAG(opt));
@@ -633,13 +640,21 @@ get_addrinfo(struct ipset_session *session,
continue; continue;
if (found == 0) { if (found == 0) {
if (family == AF_INET) { if (family == AF_INET) {
/* Workaround: direct cast increases required alignment on Sparc */ /* Workaround: direct cast increases
const struct sockaddr_in *saddr = (void *)i->ai_addr; * required alignment on Sparc
err = ipset_session_data_set(session, opt, &saddr->sin_addr); */
const struct sockaddr_in *saddr =
(void *)i->ai_addr;
err = ipset_session_data_set(session,
opt, &saddr->sin_addr);
} else { } else {
/* Workaround: direct cast increases required alignment on Sparc */ /* Workaround: direct cast increases
const struct sockaddr_in6 *saddr = (void *)i->ai_addr; * required alignment on Sparc
err = ipset_session_data_set(session, opt, &saddr->sin6_addr); */
const struct sockaddr_in6 *saddr =
(void *)i->ai_addr;
err = ipset_session_data_set(session,
opt, &saddr->sin6_addr);
} }
} else if (found == 1) { } else if (found == 1) {
ipset_warn(session, ipset_warn(session,
@@ -685,8 +700,8 @@ parse_ipaddr(struct ipset_session *session,
/* IP/mask */ /* IP/mask */
*a++ = '\0'; *a++ = '\0';
if ((err = string_to_cidr(session, a, 0, m, &m)) != 0 if ((err = string_to_cidr(session, a, 0, m, &m)) != 0 ||
|| (err = ipset_session_data_set(session, copt, &m)) != 0) (err = ipset_session_data_set(session, copt, &m)) != 0)
goto out; goto out;
} else if ((a = range_separator(tmp)) != NULL) { } else if ((a = range_separator(tmp)) != NULL) {
/* IP-IP */ /* IP-IP */
@@ -694,8 +709,8 @@ parse_ipaddr(struct ipset_session *session,
D("range %s", a); D("range %s", a);
range++; range++;
} }
if ((aerr = get_addrinfo(session, opt, tmp, &info, family)) != 0 if ((aerr = get_addrinfo(session, opt, tmp, &info, family)) != 0 ||
|| !range) !range)
goto out; goto out;
freeaddrinfo(info); freeaddrinfo(info);
aerr = get_addrinfo(session, opt2, a, &info, family); aerr = get_addrinfo(session, opt2, a, &info, family);
@@ -739,10 +754,10 @@ parse_ip(struct ipset_session *session,
switch (addrtype) { switch (addrtype) {
case IPADDR_PLAIN: case IPADDR_PLAIN:
if (range_separator(str) if (range_separator(str) ||
|| (cidr_separator(str) && !cidr_hostaddr(str, family))) (cidr_separator(str) && !cidr_hostaddr(str, family)))
return syntax_err("plain IP address must be supplied: %s", return syntax_err("plain IP address must be supplied: "
str); "%s", str);
break; break;
case IPADDR_NET: case IPADDR_NET:
if (!cidr_separator(str) || range_separator(str)) if (!cidr_separator(str) || range_separator(str))
@@ -806,9 +821,9 @@ ipset_parse_single_ip(struct ipset_session *session,
enum ipset_opt opt, const char *str) enum ipset_opt opt, const char *str)
{ {
assert(session); assert(session);
assert(opt == IPSET_OPT_IP assert(opt == IPSET_OPT_IP ||
|| opt == IPSET_OPT_IP_TO opt == IPSET_OPT_IP_TO ||
|| opt == IPSET_OPT_IP2); opt == IPSET_OPT_IP2);
assert(str); assert(str);
return parse_ip(session, opt, str, IPADDR_PLAIN); return parse_ip(session, opt, str, IPADDR_PLAIN);
@@ -882,8 +897,8 @@ ipset_parse_netrange(struct ipset_session *session,
assert(str); assert(str);
if (!(range_separator(str) || cidr_separator(str))) if (!(range_separator(str) || cidr_separator(str)))
return syntax_err("IP/cidr or IP-IP range must be specified: %s", return syntax_err("IP/cidr or IP-IP range must be specified: "
str); "%s", str);
return parse_ip(session, opt, str, IPADDR_ANY); return parse_ip(session, opt, str, IPADDR_ANY);
} }
@@ -909,8 +924,8 @@ ipset_parse_iprange(struct ipset_session *session,
assert(str); assert(str);
if (cidr_separator(str)) if (cidr_separator(str))
return syntax_err("IP address or IP-IP range must be specified: %s", return syntax_err("IP address or IP-IP range must be "
str); "specified: %s", str);
return parse_ip(session, opt, str, IPADDR_ANY); return parse_ip(session, opt, str, IPADDR_ANY);
} }
@@ -1075,7 +1090,7 @@ do { \
if (strlen(str) > IPSET_MAXNAMELEN - 1) { \ if (strlen(str) > IPSET_MAXNAMELEN - 1) { \
if (saved != NULL) \ if (saved != NULL) \
free(saved); \ free(saved); \
return syntax_err("setname '%s' is longer than %u characters", \ return syntax_err("setname '%s' is longer than %u characters",\
str, IPSET_MAXNAMELEN - 1); \ str, IPSET_MAXNAMELEN - 1); \
} \ } \
} while (0) } while (0)
@@ -1122,8 +1137,8 @@ ipset_parse_name_compat(struct ipset_session *session,
*a++ = '\0'; *a++ = '\0';
if ((b = elem_separator(a)) != NULL) if ((b = elem_separator(a)) != NULL)
*b++ = '\0'; *b++ = '\0';
if (b == NULL if (b == NULL ||
|| !(STREQ(a, "before") || STREQ(a, "after"))) { !(STREQ(a, "before") || STREQ(a, "after"))) {
err = ipset_err(session, "you must specify elements " err = ipset_err(session, "you must specify elements "
"as setname%s[before|after]%ssetname", "as setname%s[before|after]%ssetname",
sep, sep); sep, sep);
@@ -1164,9 +1179,9 @@ ipset_parse_setname(struct ipset_session *session,
enum ipset_opt opt, const char *str) enum ipset_opt opt, const char *str)
{ {
assert(session); assert(session);
assert(opt == IPSET_SETNAME assert(opt == IPSET_SETNAME ||
|| opt == IPSET_OPT_NAME opt == IPSET_OPT_NAME ||
|| opt == IPSET_OPT_SETNAME2); opt == IPSET_OPT_SETNAME2);
assert(str); assert(str);
check_setname(str, NULL); check_setname(str, NULL);
@@ -1394,6 +1409,41 @@ ipset_parse_typename(struct ipset_session *session,
return ipset_session_data_set(session, IPSET_OPT_TYPE, type); return ipset_session_data_set(session, IPSET_OPT_TYPE, type);
} }
/**
* ipset_parse_iface - parse string as an interface name
* @session: session structure
* @opt: option kind of the data
* @str: string to parse
*
* Parse string as an interface name, optionally with 'physdev:' prefix.
* The value is stored in the data blob of the session.
*
* Returns 0 on success or a negative error code.
*/
int
ipset_parse_iface(struct ipset_session *session,
enum ipset_opt opt, const char *str)
{
struct ipset_data *data;
int offset = 0, err = 0;
assert(session);
assert(opt == IPSET_OPT_IFACE);
assert(str);
data = ipset_session_data(session);
if (STREQ(str, "physdev:")) {
offset = 8;
err = ipset_data_set(data, IPSET_OPT_PHYSDEV, str);
}
if (strlen(str + offset) > IFNAMSIZ - 1)
return syntax_err("interface name '%s' is longer "
"than %u characters",
str + offset, IFNAMSIZ - 1);
return ipset_data_set(data, opt, str + offset);
}
/** /**
* ipset_parse_output - parse output format name * ipset_parse_output - parse output format name
* @session: session structure * @session: session structure
@@ -1442,7 +1492,8 @@ ipset_parse_ignored(struct ipset_session *session,
if (!ipset_data_ignored(ipset_session_data(session), opt)) if (!ipset_data_ignored(ipset_session_data(session), opt))
ipset_warn(session, ipset_warn(session,
"Option %s is ignored. Please upgrade your syntax.", str); "Option %s is ignored. "
"Please upgrade your syntax.", str);
return 0; return 0;
} }

View File

@@ -12,6 +12,7 @@
#include <sys/socket.h> /* inet_ntop */ #include <sys/socket.h> /* inet_ntop */
#include <arpa/inet.h> /* inet_ntop */ #include <arpa/inet.h> /* inet_ntop */
#include <net/ethernet.h> /* ETH_ALEN */ #include <net/ethernet.h> /* ETH_ALEN */
#include <net/if.h> /* IFNAMSIZ */
#include <libipset/debug.h> /* D() */ #include <libipset/debug.h> /* D() */
#include <libipset/data.h> /* ipset_data_* */ #include <libipset/data.h> /* ipset_data_* */
@@ -142,31 +143,56 @@ ipset_print_type(char *buf, unsigned int len,
return snprintf(buf, len, "%s", type->name); return snprintf(buf, len, "%s", type->name);
} }
#define GETNAMEINFO(family, f, n) \ static inline int
static inline int \ __getnameinfo4(char *buf, unsigned int len,
__getnameinfo##f(char *buf, unsigned int len, \ int flags, const union nf_inet_addr *addr)
int flags, const union nf_inet_addr *addr) \ {
{ \ struct sockaddr_in saddr;
struct sockaddr_in##n saddr; \ int err;
int err; \
\ memset(&saddr, 0, sizeof(saddr));
memset(&saddr, 0, sizeof(saddr)); \ in4cpy(&saddr.sin_addr, &addr->in);
in##f##cpy(&saddr.sin##n##_addr, &addr->in##n); \ saddr.sin_family = AF_INET;
saddr.sin##n##_family = family; \
\ err = getnameinfo((const struct sockaddr *)&saddr,
err = getnameinfo((const struct sockaddr *)&saddr, \ sizeof(saddr),
sizeof(saddr), \ buf, len, NULL, 0, flags);
buf, len, NULL, 0, flags); \
\ if (!(flags & NI_NUMERICHOST) &&
if (!(flags & NI_NUMERICHOST) && \ (err == EAI_AGAIN || (err == 0 && strchr(buf, '-') != NULL)))
(err == EAI_AGAIN || (err == 0 && strchr(buf, '-') != NULL))) \ err = getnameinfo((const struct sockaddr *)&saddr,
err = getnameinfo((const struct sockaddr *)&saddr, \ sizeof(saddr),
sizeof(saddr), \ buf, len, NULL, 0,
buf, len, NULL, 0, \ flags | NI_NUMERICHOST);
flags | NI_NUMERICHOST); \ D("getnameinfo err: %i, errno %i", err, errno);
D("getnameinfo err: %i, errno %i", err, errno); \ return (err == 0 ? (int)strlen(buf) :
return (err == 0 ? (int)strlen(buf) : \ (err == EAI_OVERFLOW || err == EAI_SYSTEM) ? (int)len : -1);
(err == EAI_OVERFLOW || err == EAI_SYSTEM) ? (int)len : -1);\ }
static inline int
__getnameinfo6(char *buf, unsigned int len,
int flags, const union nf_inet_addr *addr)
{
struct sockaddr_in6 saddr;
int err;
memset(&saddr, 0, sizeof(saddr));
in6cpy(&saddr.sin6_addr, &addr->in6);
saddr.sin6_family = AF_INET6;
err = getnameinfo((const struct sockaddr *)&saddr,
sizeof(saddr),
buf, len, NULL, 0, flags);
if (!(flags & NI_NUMERICHOST) &&
(err == EAI_AGAIN || (err == 0 && strchr(buf, '-') != NULL)))
err = getnameinfo((const struct sockaddr *)&saddr,
sizeof(saddr),
buf, len, NULL, 0,
flags | NI_NUMERICHOST);
D("getnameinfo err: %i, errno %i", err, errno);
return (err == 0 ? (int)strlen(buf) :
(err == EAI_OVERFLOW || err == EAI_SYSTEM) ? (int)len : -1);
} }
#define SNPRINTF_IP(mask, f) \ #define SNPRINTF_IP(mask, f) \
@@ -189,10 +215,8 @@ snprintf_ipv##f(char *buf, unsigned int len, int flags, \
return offset; \ return offset; \
} }
GETNAMEINFO(AF_INET, 4, )
SNPRINTF_IP(32, 4) SNPRINTF_IP(32, 4)
GETNAMEINFO(AF_INET6, 6, 6)
SNPRINTF_IP(128, 6) SNPRINTF_IP(128, 6)
/** /**
@@ -287,9 +311,9 @@ ipset_print_ipaddr(char *buf, unsigned int len,
assert(buf); assert(buf);
assert(len > 0); assert(len > 0);
assert(data); assert(data);
assert(opt == IPSET_OPT_IP assert(opt == IPSET_OPT_IP ||
|| opt == IPSET_OPT_IP_TO opt == IPSET_OPT_IP_TO ||
|| opt == IPSET_OPT_IP2); opt == IPSET_OPT_IP2);
family = ipset_data_family(data); family = ipset_data_family(data);
cidropt = opt == IPSET_OPT_IP ? IPSET_OPT_CIDR : IPSET_OPT_CIDR2; cidropt = opt == IPSET_OPT_IP ? IPSET_OPT_CIDR : IPSET_OPT_CIDR2;
@@ -443,6 +467,45 @@ ipset_print_port(char *buf, unsigned int len,
return offset; return offset;
} }
/**
* ipset_print_iface - print interface element string
* @buf: printing buffer
* @len: length of available buffer space
* @data: data blob
* @opt: the option kind
* @env: environment flags
*
* Print interface element string to output buffer.
*
* Return lenght of printed string or error size.
*/
int
ipset_print_iface(char *buf, unsigned int len,
const struct ipset_data *data, enum ipset_opt opt,
uint8_t env UNUSED)
{
const char *name;
int size, offset = 0;
assert(buf);
assert(len > 0);
assert(data);
assert(opt == IPSET_OPT_IFACE);
if (len < IFNAMSIZ + strlen("physdev:"))
return -1;
if (ipset_data_test(data, IPSET_OPT_PHYSDEV)) {
size = snprintf(buf, len, "physdev:");
SNPRINTF_FAILURE(size, len, offset);
}
name = ipset_data_get(data, opt);
assert(name);
size = snprintf(buf, len, "%s", name);
SNPRINTF_FAILURE(size, len, offset);
return offset;
}
/** /**
* ipset_print_proto - print protocol name * ipset_print_proto - print protocol name
* @buf: printing buffer * @buf: printing buffer
@@ -511,7 +574,8 @@ ipset_print_icmp(char *buf, unsigned int len,
if (name != NULL) if (name != NULL)
return snprintf(buf, len, "%s", name); return snprintf(buf, len, "%s", name);
else else
return snprintf(buf, len, "%u/%u", typecode >> 8, typecode & 0xFF); return snprintf(buf, len, "%u/%u",
typecode >> 8, typecode & 0xFF);
} }
/** /**
@@ -545,7 +609,8 @@ ipset_print_icmpv6(char *buf, unsigned int len,
if (name != NULL) if (name != NULL)
return snprintf(buf, len, "%s", name); return snprintf(buf, len, "%s", name);
else else
return snprintf(buf, len, "%u/%u", typecode >> 8, typecode & 0xFF); return snprintf(buf, len, "%u/%u",
typecode >> 8, typecode & 0xFF);
} }
/** /**
@@ -645,9 +710,9 @@ ipset_print_elem(char *buf, unsigned int len,
SNPRINTF_FAILURE(size, len, offset); SNPRINTF_FAILURE(size, len, offset);
IF_D(ipset_data_test(data, type->elem[IPSET_DIM_TWO].opt), IF_D(ipset_data_test(data, type->elem[IPSET_DIM_TWO].opt),
"print second elem"); "print second elem");
if (type->dimension == IPSET_DIM_ONE if (type->dimension == IPSET_DIM_ONE ||
|| (type->last_elem_optional (type->last_elem_optional &&
&& !ipset_data_test(data, type->elem[IPSET_DIM_TWO].opt))) !ipset_data_test(data, type->elem[IPSET_DIM_TWO].opt)))
return offset; return offset;
size = snprintf(buf + offset, len, IPSET_ELEM_SEPARATOR); size = snprintf(buf + offset, len, IPSET_ELEM_SEPARATOR);
@@ -655,9 +720,9 @@ ipset_print_elem(char *buf, unsigned int len,
size = type->elem[IPSET_DIM_TWO].print(buf + offset, len, data, size = type->elem[IPSET_DIM_TWO].print(buf + offset, len, data,
type->elem[IPSET_DIM_TWO].opt, env); type->elem[IPSET_DIM_TWO].opt, env);
SNPRINTF_FAILURE(size, len, offset); SNPRINTF_FAILURE(size, len, offset);
if (type->dimension == IPSET_DIM_TWO if (type->dimension == IPSET_DIM_TWO ||
|| (type->last_elem_optional (type->last_elem_optional &&
&& !ipset_data_test(data, type->elem[IPSET_DIM_THREE].opt))) !ipset_data_test(data, type->elem[IPSET_DIM_THREE].opt)))
return offset; return offset;
size = snprintf(buf + offset, len, IPSET_ELEM_SEPARATOR); size = snprintf(buf + offset, len, IPSET_ELEM_SEPARATOR);
@@ -731,6 +796,9 @@ ipset_print_data(char *buf, unsigned int len,
case IPSET_OPT_PORT: case IPSET_OPT_PORT:
size = ipset_print_port(buf, len, data, opt, env); size = ipset_print_port(buf, len, data, opt, env);
break; break;
case IPSET_OPT_IFACE:
size = ipset_print_iface(buf, len, data, opt, env);
break;
case IPSET_OPT_GC: case IPSET_OPT_GC:
case IPSET_OPT_HASHSIZE: case IPSET_OPT_HASHSIZE:
case IPSET_OPT_MAXELEM: case IPSET_OPT_MAXELEM:

View File

@@ -13,6 +13,7 @@
#include <string.h> /* str* */ #include <string.h> /* str* */
#include <unistd.h> /* getpagesize */ #include <unistd.h> /* getpagesize */
#include <net/ethernet.h> /* ETH_ALEN */ #include <net/ethernet.h> /* ETH_ALEN */
#include <net/if.h> /* IFNAMSIZ */
#include <libipset/debug.h> /* D() */ #include <libipset/debug.h> /* D() */
#include <libipset/data.h> /* IPSET_OPT_* */ #include <libipset/data.h> /* IPSET_OPT_* */
@@ -199,7 +200,7 @@ ipset_session_output(struct ipset_session *session,
* *
* Returns -1. * Returns -1.
*/ */
int __attribute__((format(printf,3,4))) int __attribute__((format(printf, 3, 4)))
ipset_session_report(struct ipset_session *session, ipset_session_report(struct ipset_session *session,
enum ipset_err_type type, enum ipset_err_type type,
const char *fmt, ...) const char *fmt, ...)
@@ -475,6 +476,11 @@ static const struct ipset_attr_policy adt_attrs[] = {
.type = MNL_TYPE_NESTED, .type = MNL_TYPE_NESTED,
.opt = IPSET_OPT_IP2_TO, .opt = IPSET_OPT_IP2_TO,
}, },
[IPSET_ATTR_IFACE] = {
.type = MNL_TYPE_NUL_STRING,
.opt = IPSET_OPT_IFACE,
.len = IFNAMSIZ,
},
}; };
static const struct ipset_attr_policy ipaddr_attrs[] = { static const struct ipset_attr_policy ipaddr_attrs[] = {
@@ -508,8 +514,8 @@ generic_data_attr_cb(const struct nlattr *attr, void *data,
mnl_attr_get_payload_len(attr)); mnl_attr_get_payload_len(attr));
return MNL_CB_ERROR; return MNL_CB_ERROR;
} }
if (policy[type].type == MNL_TYPE_NUL_STRING if (policy[type].type == MNL_TYPE_NUL_STRING &&
&& mnl_attr_get_payload_len(attr) > IPSET_MAXNAMELEN) mnl_attr_get_payload_len(attr) > IPSET_MAXNAMELEN)
return MNL_CB_ERROR; return MNL_CB_ERROR;
tb[type] = attr; tb[type] = attr;
return MNL_CB_OK; return MNL_CB_OK;
@@ -659,7 +665,7 @@ call_outfn(struct ipset_session *session)
/* Handle printing failures */ /* Handle printing failures */
static jmp_buf printf_failure; static jmp_buf printf_failure;
static int __attribute__((format(printf,2,3))) static int __attribute__((format(printf, 2, 3)))
safe_snprintf(struct ipset_session *session, const char *fmt, ...) safe_snprintf(struct ipset_session *session, const char *fmt, ...)
{ {
va_list args; va_list args;
@@ -859,10 +865,10 @@ list_create(struct ipset_session *session, struct nlattr *nla[])
} }
for (arg = type->args[IPSET_CREATE]; arg != NULL && arg->opt; arg++) { for (arg = type->args[IPSET_CREATE]; arg != NULL && arg->opt; arg++) {
if (!arg->print if (!arg->print ||
|| !ipset_data_test(data, arg->opt) !ipset_data_test(data, arg->opt) ||
|| (arg->opt == IPSET_OPT_FAMILY (arg->opt == IPSET_OPT_FAMILY &&
&& family == type->family)) family == type->family))
continue; continue;
switch (session->mode) { switch (session->mode) {
case IPSET_LIST_SAVE: case IPSET_LIST_SAVE:
@@ -975,8 +981,8 @@ callback_list(struct ipset_session *session, struct nlattr *nla[],
if (STREQ(ipset_data_setname(data), session->saved_setname)) { if (STREQ(ipset_data_setname(data), session->saved_setname)) {
/* Header part already seen */ /* Header part already seen */
if (ipset_data_test(data, IPSET_OPT_TYPE) if (ipset_data_test(data, IPSET_OPT_TYPE) &&
&& nla[IPSET_ATTR_DATA] != NULL) nla[IPSET_ATTR_DATA] != NULL)
FAILURE("Broken %s kernel message: " FAILURE("Broken %s kernel message: "
"extra DATA received!", cmd2name[cmd]); "extra DATA received!", cmd2name[cmd]);
} else { } else {
@@ -992,13 +998,14 @@ callback_list(struct ipset_session *session, struct nlattr *nla[],
if (nla[IPSET_ATTR_DATA] != NULL) { if (nla[IPSET_ATTR_DATA] != NULL) {
struct nlattr *cattr[IPSET_ATTR_CREATE_MAX+1] = {}; struct nlattr *cattr[IPSET_ATTR_CREATE_MAX+1] = {};
if (!(nla[IPSET_ATTR_TYPENAME] if (!(nla[IPSET_ATTR_TYPENAME] &&
&& nla[IPSET_ATTR_FAMILY] nla[IPSET_ATTR_FAMILY] &&
&& nla[IPSET_ATTR_REVISION])) nla[IPSET_ATTR_REVISION]))
FAILURE("Broken %s kernel message: missing %s!", FAILURE("Broken %s kernel message: missing %s!",
cmd2name[cmd], cmd2name[cmd],
!nla[IPSET_ATTR_TYPENAME] ? "typename" : !nla[IPSET_ATTR_TYPENAME] ? "typename" :
!nla[IPSET_ATTR_FAMILY] ? "family" : "revision"); !nla[IPSET_ATTR_FAMILY] ? "family" :
"revision");
/* Reset CREATE specific flags */ /* Reset CREATE specific flags */
ipset_data_flags_unset(data, IPSET_CREATE_FLAGS); ipset_data_flags_unset(data, IPSET_CREATE_FLAGS);
@@ -1067,8 +1074,8 @@ callback_version(struct ipset_session *session, struct nlattr *nla[])
"while userspace supports protocol versions %u-%u", "while userspace supports protocol versions %u-%u",
min, max, IPSET_PROTOCOL_MIN, IPSET_PROTOCOL_MAX); min, max, IPSET_PROTOCOL_MIN, IPSET_PROTOCOL_MAX);
if (!(session->envopts & IPSET_ENV_QUIET) if (!(session->envopts & IPSET_ENV_QUIET) &&
&& max != IPSET_PROTOCOL_MAX) max != IPSET_PROTOCOL_MAX)
ipset_warn(session, ipset_warn(session,
"Kernel support protocol versions %u-%u " "Kernel support protocol versions %u-%u "
"while userspace supports protocol versions %u-%u", "while userspace supports protocol versions %u-%u",
@@ -1094,9 +1101,9 @@ callback_header(struct ipset_session *session, struct nlattr *nla[])
"does not match with received one `%s'!", "does not match with received one `%s'!",
ipset_data_setname(data), setname); ipset_data_setname(data), setname);
if (!(nla[IPSET_ATTR_TYPENAME] if (!(nla[IPSET_ATTR_TYPENAME] &&
&& nla[IPSET_ATTR_REVISION] nla[IPSET_ATTR_REVISION] &&
&& nla[IPSET_ATTR_FAMILY])) nla[IPSET_ATTR_FAMILY]))
FAILURE("Broken HEADER kernel message: " FAILURE("Broken HEADER kernel message: "
"missing attribute '%s'!", "missing attribute '%s'!",
!nla[IPSET_ATTR_TYPENAME] ? "typename" : !nla[IPSET_ATTR_TYPENAME] ? "typename" :
@@ -1117,9 +1124,9 @@ callback_type(struct ipset_session *session, struct nlattr *nla[])
const struct ipset_data *data = session->data; const struct ipset_data *data = session->data;
const char *typename, *orig; const char *typename, *orig;
if (!(nla[IPSET_ATTR_TYPENAME] if (!(nla[IPSET_ATTR_TYPENAME] &&
&& nla[IPSET_ATTR_REVISION] nla[IPSET_ATTR_REVISION] &&
&& nla[IPSET_ATTR_FAMILY])) nla[IPSET_ATTR_FAMILY]))
FAILURE("Broken TYPE kernel message: " FAILURE("Broken TYPE kernel message: "
"missing attribute '%s'!", "missing attribute '%s'!",
!nla[IPSET_ATTR_TYPENAME] ? "typename" : !nla[IPSET_ATTR_TYPENAME] ? "typename" :
@@ -1318,16 +1325,20 @@ callback_error(const struct nlmsghdr *nlh, void *cbdata)
break; break;
case IPSET_CMD_RENAME: case IPSET_CMD_RENAME:
ipset_cache_rename(ipset_data_setname(data), ipset_cache_rename(ipset_data_setname(data),
ipset_data_get(data, IPSET_OPT_SETNAME2)); ipset_data_get(data,
IPSET_OPT_SETNAME2));
break; break;
case IPSET_CMD_SWAP: case IPSET_CMD_SWAP:
ipset_cache_swap(ipset_data_setname(data), ipset_cache_swap(ipset_data_setname(data),
ipset_data_get(data, IPSET_OPT_SETNAME2)); ipset_data_get(data,
IPSET_OPT_SETNAME2));
break; break;
case IPSET_CMD_TEST: case IPSET_CMD_TEST:
if (!(session->envopts & IPSET_ENV_QUIET)) { if (!(session->envopts & IPSET_ENV_QUIET)) {
ipset_print_elem(session->report, IPSET_ERRORBUFLEN, ipset_print_elem(session->report,
session->data, IPSET_OPT_NONE, 0); IPSET_ERRORBUFLEN,
session->data,
IPSET_OPT_NONE, 0);
ipset_warn(session, " is in set %s.", ipset_warn(session, " is in set %s.",
ipset_data_setname(data)); ipset_data_setname(data));
} }
@@ -1341,7 +1352,8 @@ callback_error(const struct nlmsghdr *nlh, void *cbdata)
print_set_done(session); print_set_done(session);
break; break;
default: default:
FAILURE("ACK message received to command %s[%u], which is not expected", FAILURE("ACK message received to command %s[%u], "
"which is not expected",
session->cmd < IPSET_MSG_MAX session->cmd < IPSET_MSG_MAX
? cmd2name[session->cmd] : "unknown", ? cmd2name[session->cmd] : "unknown",
session->cmd); session->cmd);
@@ -1353,8 +1365,8 @@ callback_error(const struct nlmsghdr *nlh, void *cbdata)
/* Error messages */ /* Error messages */
/* Special case for IPSET_CMD_TEST */ /* Special case for IPSET_CMD_TEST */
if (session->cmd == IPSET_CMD_TEST if (session->cmd == IPSET_CMD_TEST &&
&& err->error == -IPSET_ERR_EXIST) { err->error == -IPSET_ERR_EXIST) {
if (!(session->envopts & IPSET_ENV_QUIET)) { if (!(session->envopts & IPSET_ENV_QUIET)) {
ipset_print_elem(session->report, IPSET_ERRORBUFLEN, ipset_print_elem(session->report, IPSET_ERRORBUFLEN,
session->data, IPSET_OPT_NONE, 0); session->data, IPSET_OPT_NONE, 0);
@@ -1419,7 +1431,8 @@ attr_len(const struct ipset_attr_policy *attr, uint8_t family, uint16_t *flags)
} }
#define BUFFER_FULL(bufsize, nlmsg_len, nestlen, attrlen) \ #define BUFFER_FULL(bufsize, nlmsg_len, nestlen, attrlen) \
(nlmsg_len + nestlen + MNL_ATTR_HDRLEN + MNL_ALIGN(alen) + MNL_ALIGN(sizeof(struct nlmsgerr)) > bufsize) (nlmsg_len + nestlen + MNL_ATTR_HDRLEN + MNL_ALIGN(alen) + \
MNL_ALIGN(sizeof(struct nlmsgerr)) > bufsize)
static int static int
rawdata2attr(struct ipset_session *session, struct nlmsghdr *nlh, rawdata2attr(struct ipset_session *session, struct nlmsghdr *nlh,
@@ -1439,7 +1452,8 @@ rawdata2attr(struct ipset_session *session, struct nlmsghdr *nlh,
: IPSET_ATTR_IPADDR_IPV6; : IPSET_ATTR_IPADDR_IPV6;
alen = attr_len(attr, family, &flags); alen = attr_len(attr, family, &flags);
if (BUFFER_FULL(session->bufsize, nlh->nlmsg_len, MNL_ATTR_HDRLEN, alen)) if (BUFFER_FULL(session->bufsize, nlh->nlmsg_len,
MNL_ATTR_HDRLEN, alen))
return 1; return 1;
nested = mnl_attr_nest_start(nlh, type); nested = mnl_attr_nest_start(nlh, type);
D("family: %s", family == AF_INET ? "INET" : D("family: %s", family == AF_INET ? "INET" :
@@ -1559,9 +1573,11 @@ build_send_private_msg(struct ipset_session *session, enum ipset_cmd cmd)
return ipset_err(session, return ipset_err(session,
"Invalid internal TYPE command: " "Invalid internal TYPE command: "
"missing settype"); "missing settype");
ADDATTR(session, nlh, data, IPSET_ATTR_TYPENAME, AF_INET, cmd_attrs); ADDATTR(session, nlh, data, IPSET_ATTR_TYPENAME,
AF_INET, cmd_attrs);
if (ipset_data_test(data, IPSET_OPT_FAMILY)) if (ipset_data_test(data, IPSET_OPT_FAMILY))
ADDATTR(session, nlh, data, IPSET_ATTR_FAMILY, AF_INET, cmd_attrs); ADDATTR(session, nlh, data, IPSET_ATTR_FAMILY,
AF_INET, cmd_attrs);
else else
/* bitmap:port and list:set types */ /* bitmap:port and list:set types */
mnl_attr_put_u8(nlh, IPSET_ATTR_FAMILY, AF_UNSPEC); mnl_attr_put_u8(nlh, IPSET_ATTR_FAMILY, AF_UNSPEC);
@@ -1582,10 +1598,10 @@ build_send_private_msg(struct ipset_session *session, enum ipset_cmd cmd)
static inline bool static inline bool
may_aggregate_ad(struct ipset_session *session, enum ipset_cmd cmd) may_aggregate_ad(struct ipset_session *session, enum ipset_cmd cmd)
{ {
return session->lineno != 0 return session->lineno != 0 &&
&& (cmd == IPSET_CMD_ADD || cmd == IPSET_CMD_DEL) (cmd == IPSET_CMD_ADD || cmd == IPSET_CMD_DEL) &&
&& cmd == session->cmd cmd == session->cmd &&
&& STREQ(ipset_data_setname(session->data), session->saved_setname); STREQ(ipset_data_setname(session->data), session->saved_setname);
} }
static int static int
@@ -1623,7 +1639,8 @@ build_msg(struct ipset_session *session, bool aggregate)
/* Core attributes: /* Core attributes:
* setname, typename, revision, family, flags (optional) */ * setname, typename, revision, family, flags (optional) */
ADDATTR_SETNAME(session, nlh, data); ADDATTR_SETNAME(session, nlh, data);
ADDATTR(session, nlh, data, IPSET_ATTR_TYPENAME, AF_INET, cmd_attrs); ADDATTR(session, nlh, data, IPSET_ATTR_TYPENAME,
AF_INET, cmd_attrs);
ADDATTR_RAW(session, nlh, &type->revision, ADDATTR_RAW(session, nlh, &type->revision,
IPSET_ATTR_REVISION, cmd_attrs); IPSET_ATTR_REVISION, cmd_attrs);
D("family: %u, type family %u", D("family: %u, type family %u",
@@ -1670,13 +1687,16 @@ build_msg(struct ipset_session *session, bool aggregate)
if (!ipset_data_test(data, IPSET_SETNAME)) if (!ipset_data_test(data, IPSET_SETNAME))
return ipset_err(session, return ipset_err(session,
"Invalid %s command: missing from-setname", "Invalid %s command: missing from-setname",
session->cmd == IPSET_CMD_SWAP ? "swap" : "rename"); session->cmd == IPSET_CMD_SWAP ? "swap" :
"rename");
if (!ipset_data_test(data, IPSET_OPT_SETNAME2)) if (!ipset_data_test(data, IPSET_OPT_SETNAME2))
return ipset_err(session, return ipset_err(session,
"Invalid %s command: missing to-setname", "Invalid %s command: missing to-setname",
session->cmd == IPSET_CMD_SWAP ? "swap" : "rename"); session->cmd == IPSET_CMD_SWAP ? "swap" :
"rename");
ADDATTR_SETNAME(session, nlh, data); ADDATTR_SETNAME(session, nlh, data);
ADDATTR_RAW(session, nlh, ipset_data_get(data, IPSET_OPT_SETNAME2), ADDATTR_RAW(session, nlh,
ipset_data_get(data, IPSET_OPT_SETNAME2),
IPSET_ATTR_SETNAME2, cmd_attrs); IPSET_ATTR_SETNAME2, cmd_attrs);
break; break;
case IPSET_CMD_ADD: case IPSET_CMD_ADD:
@@ -1688,12 +1708,14 @@ build_msg(struct ipset_session *session, bool aggregate)
if (!ipset_data_test(data, IPSET_SETNAME)) if (!ipset_data_test(data, IPSET_SETNAME))
return ipset_err(session, return ipset_err(session,
"Invalid %s command: missing setname", "Invalid %s command: missing setname",
session->cmd == IPSET_CMD_ADD ? "add" : "del"); session->cmd == IPSET_CMD_ADD ? "add" :
"del");
if (!ipset_data_test(data, IPSET_OPT_TYPE)) if (!ipset_data_test(data, IPSET_OPT_TYPE))
return ipset_err(session, return ipset_err(session,
"Invalid %s command: missing settype", "Invalid %s command: missing settype",
session->cmd == IPSET_CMD_ADD ? "add" : "del"); session->cmd == IPSET_CMD_ADD ? "add" :
"del");
/* Core options: setname */ /* Core options: setname */
ADDATTR_SETNAME(session, nlh, data); ADDATTR_SETNAME(session, nlh, data);
@@ -1711,11 +1733,12 @@ build_msg(struct ipset_session *session, bool aggregate)
D("open_nested failed"); D("open_nested failed");
return 1; return 1;
} }
if (addattr_adt(session, nlh, data, ipset_data_family(data)) if (addattr_adt(session, nlh, data, ipset_data_family(data)) ||
|| ADDATTR_RAW(session, nlh, &session->lineno, ADDATTR_RAW(session, nlh, &session->lineno,
IPSET_ATTR_LINENO, cmd_attrs)) { IPSET_ATTR_LINENO, cmd_attrs)) {
/* Cancel last, unfinished nested attribute */ /* Cancel last, unfinished nested attribute */
mnl_attr_nest_cancel(nlh, session->nested[session->nestid-1]); mnl_attr_nest_cancel(nlh,
session->nested[session->nestid-1]);
session->nested[--session->nestid] = NULL; session->nested[--session->nestid] = NULL;
return 1; return 1;
} }
@@ -1769,7 +1792,8 @@ ipset_commit(struct ipset_session *session)
assert(session); assert(session);
nlh = session->buffer; nlh = session->buffer;
D("send buffer: len %u, cmd %s", nlh->nlmsg_len, cmd2name[session->cmd]); D("send buffer: len %u, cmd %s",
nlh->nlmsg_len, cmd2name[session->cmd]);
if (nlh->nlmsg_len == 0) if (nlh->nlmsg_len == 0)
/* Nothing to do */ /* Nothing to do */
return 0; return 0;
@@ -1902,8 +1926,8 @@ ipset_cmd(struct ipset_session *session, enum ipset_cmd cmd, uint32_t lineno)
/* We have to save the type for error handling */ /* We have to save the type for error handling */
session->saved_type = ipset_data_get(data, IPSET_OPT_TYPE); session->saved_type = ipset_data_get(data, IPSET_OPT_TYPE);
if (session->lineno != 0 if (session->lineno != 0 &&
&& (cmd == IPSET_CMD_ADD || cmd == IPSET_CMD_DEL)) { (cmd == IPSET_CMD_ADD || cmd == IPSET_CMD_DEL)) {
/* Save setname for the next possible aggregated restore line */ /* Save setname for the next possible aggregated restore line */
strcpy(session->saved_setname, ipset_data_setname(data)); strcpy(session->saved_setname, ipset_data_setname(data));
ipset_data_reset(data); ipset_data_reset(data);

View File

@@ -28,8 +28,8 @@ struct ipset {
struct ipset *next; struct ipset *next;
}; };
static struct ipset_type *typelist = NULL; /* registered set types */ static struct ipset_type *typelist; /* registered set types */
static struct ipset *setlist = NULL; /* cached sets */ static struct ipset *setlist; /* cached sets */
/** /**
* ipset_cache_add - add a set to the cache * ipset_cache_add - add a set to the cache
@@ -178,7 +178,7 @@ ipset_cache_swap(const char *from, const char *to)
bool bool
ipset_match_typename(const char *name, const struct ipset_type *type) ipset_match_typename(const char *name, const struct ipset_type *type)
{ {
const char * const * alias = type->alias; const char * const *alias = type->alias;
if (STREQ(name, type->name)) if (STREQ(name, type->name))
return true; return true;
@@ -240,9 +240,11 @@ create_type_get(struct ipset_session *session)
if (ret != 0) if (ret != 0)
return NULL; return NULL;
kmin = kmax = *(const uint8_t *)ipset_data_get(data, IPSET_OPT_REVISION); kmin = kmax = *(const uint8_t *)ipset_data_get(data,
IPSET_OPT_REVISION);
if (ipset_data_test(data, IPSET_OPT_REVISION_MIN)) if (ipset_data_test(data, IPSET_OPT_REVISION_MIN))
kmin = *(const uint8_t *)ipset_data_get(data, IPSET_OPT_REVISION_MIN); kmin = *(const uint8_t *)ipset_data_get(data,
IPSET_OPT_REVISION_MIN);
if (MAX(tmin, kmin) > MIN(tmax, kmax)) { if (MAX(tmin, kmin) > MIN(tmax, kmax)) {
if (kmin > tmax) if (kmin > tmax)

View File

@@ -174,8 +174,8 @@ ipset_errcode(struct ipset_session *session, enum ipset_cmd cmd, int errcode)
retry: retry:
for (i = 0, generic = -1; table[i].errcode; i++) { for (i = 0, generic = -1; table[i].errcode; i++) {
if (table[i].errcode == errcode if (table[i].errcode == errcode &&
&& (table[i].cmd == cmd || table[i].cmd == 0)) { (table[i].cmd == cmd || table[i].cmd == 0)) {
if (table[i].cmd == 0) { if (table[i].cmd == 0) {
generic = i; generic = i;
continue; continue;

View File

@@ -214,8 +214,8 @@ command follows the syntax
where the current list of the methods are where the current list of the methods are
\fBbitmap\fR, \fBhash\fR, and \fBlist\fR and the possible data types \fBbitmap\fR, \fBhash\fR, and \fBlist\fR and the possible data types
are \fBip\fR, \fBnet\fR, \fBmac\fR and \fBport\fR. The dimension of a set are \fBip\fR, \fBnet\fR, \fBmac\fR, \fBport\fR and \fBiface\fR.
is equal to the number of data types in its type name. The dimension of a set is equal to the number of data types in its type name.
When adding, deleting or testing entries in a set, the same comma separated When adding, deleting or testing entries in a set, the same comma separated
data syntax must be used for the entry parameter of the commands, i.e data syntax must be used for the entry parameter of the commands, i.e
@@ -711,6 +711,73 @@ ipset add foo 192.168.1,80,10.0.0/24
ipset add foo 192.168.2,25,10.1.0.0/16 ipset add foo 192.168.2,25,10.1.0.0/16
.IP .IP
ipset test foo 192.168.1,80.10.0.0/24 ipset test foo 192.168.1,80.10.0.0/24
.SS hash:net,iface
The \fBhash:net,iface\fR set type uses a hash to store different sized IP network
address and interface name pairs. Network address with zero prefix size is not
accepted.
.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 := \fInetaddr\fR,[\fBphysdev\fR:]\fIiface\fR
.PP
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
.PP
\fIDEL\-ENTRY\fR := \fInetaddr\fR,[\fBphysdev\fR:]\fIiface\fR
.PP
\fITEST\-ENTRY\fR := \fInetaddr\fR,[\fBphysdev\fR:]\fIiface\fR
.PP
where
\fInetaddr\fR := \fIip\fR[/\fIcidr\fR]
.PP
Optional \fBcreate\fR options:
.TP
\fBfamily\fR { \fBinet\fR | \fBinet6\fR }
The protocol family of the IP addresses to be stored in the set. The default is
\fBinet\fR, i.e IPv4.
.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
correct value.
.TP
\fBmaxelem\fR \fIvalue\fR
The maximal number of elements which can be stored in the set, default 65536.
.PP
For the \fInetaddr\fR part of the elements
see the description at the \fBhash:net\fR set type.
.PP
When adding/deleting/testing entries, if the cidr prefix parameter is not specified,
then the host prefix value is assumed. When adding/deleting entries, the exact
element is added/deleted and overlapping elements are not checked by the kernel.
When testing entries, if a host address is tested, then the kernel tries to match
the host address in the networks added to the set and reports the result accordingly.
.PP
From the \fBset\fR netfilter match point of view the searching for a match
always starts from the smallest size of netblock (most specific
prefix) to the largest one (least specific prefix) added to the set.
When adding/deleting IP
addresses to the set by the \fBSET\fR netfilter target, it will be
added/deleted by the most specific prefix which can be found in the
set, or by the host prefix value if the set is empty.
.PP
The second direction parameter of the \fBset\fR match and
\fBSET\fR target modules corresponds to the incoming/outgoing interface
: \fBsrc\fR to the incoming, while \fBdst\fR to the outgoing. When
the interface is flagged with \fBphysdev:\fR, the interface is interpreted
as the incoming/outgoing bridge port.
.PP
The lookup time grows linearly with the number of the different prefix
values added to the set.
.PP
Examples:
.IP
ipset create foo hash:net,iface
.IP
ipset add foo 192.168.0/24,eth0
.IP
ipset add foo 10.1.0.0/16,eth1
.IP
ipset test foo 192.168.0/24,eth0
.SS list:set .SS list:set
The \fBlist:set\fR type uses a simple list in which you can store The \fBlist:set\fR type uses a simple list in which you can store
set names. set names.

View File

@@ -26,12 +26,12 @@
static char program_name[] = PACKAGE; static char program_name[] = PACKAGE;
static char program_version[] = PACKAGE_VERSION; static char program_version[] = PACKAGE_VERSION;
static struct ipset_session *session = NULL; static struct ipset_session *session;
static uint32_t restore_line = 0; static uint32_t restore_line;
static bool interactive = false; static bool interactive;
static char cmdline[1024]; static char cmdline[1024];
static char *newargv[255]; static char *newargv[255];
static int newargc = 0; static int newargc;
/* The known set types: (typename, revision, family) is unique */ /* The known set types: (typename, revision, family) is unique */
extern struct ipset_type ipset_bitmap_ip0; extern struct ipset_type ipset_bitmap_ip0;
@@ -42,6 +42,7 @@ extern struct ipset_type ipset_hash_net0;
extern struct ipset_type ipset_hash_net1; extern struct ipset_type ipset_hash_net1;
extern struct ipset_type ipset_hash_netport1; extern struct ipset_type ipset_hash_netport1;
extern struct ipset_type ipset_hash_netport2; extern struct ipset_type ipset_hash_netport2;
extern struct ipset_type ipset_hash_netiface0;
extern struct ipset_type ipset_hash_ipport1; extern struct ipset_type ipset_hash_ipport1;
extern struct ipset_type ipset_hash_ipportip1; extern struct ipset_type ipset_hash_ipportip1;
extern struct ipset_type ipset_hash_ipportnet1; extern struct ipset_type ipset_hash_ipportnet1;
@@ -56,12 +57,12 @@ enum exittype {
SESSION_PROBLEM, SESSION_PROBLEM,
}; };
static int __attribute__((format(printf,2,3))) static int __attribute__((format(printf, 2, 3)))
exit_error(int status, const char *msg, ...) exit_error(int status, const char *msg, ...)
{ {
bool quiet = !interactive bool quiet = !interactive &&
&& session session &&
&& ipset_envopt_test(session, IPSET_ENV_QUIET); ipset_envopt_test(session, IPSET_ENV_QUIET);
if (status && msg && !quiet) { if (status && msg && !quiet) {
va_list args; va_list args;
@@ -97,8 +98,8 @@ exit_error(int status, const char *msg, ...)
static int static int
handle_error(void) handle_error(void)
{ {
if (ipset_session_warning(session) if (ipset_session_warning(session) &&
&& !ipset_envopt_test(session, IPSET_ENV_QUIET)) !ipset_envopt_test(session, IPSET_ENV_QUIET))
fprintf(stderr, "Warning: %s\n", fprintf(stderr, "Warning: %s\n",
ipset_session_warning(session)); ipset_session_warning(session));
if (ipset_session_error(session)) if (ipset_session_error(session))
@@ -124,9 +125,8 @@ help(void)
"Usage: %s [options] COMMAND\n\nCommands:\n", "Usage: %s [options] COMMAND\n\nCommands:\n",
program_name, program_version, program_name); program_name, program_version, program_name);
for (c = ipset_commands; c->cmd; c++) { for (c = ipset_commands; c->cmd; c++)
printf("%s %s\n", c->name[0], c->help); printf("%s %s\n", c->name[0], c->help);
}
printf("\nOptions:\n"); printf("\nOptions:\n");
while (opt->flag) { while (opt->flag) {
@@ -236,7 +236,8 @@ call_parser(int *argc, char *argv[], const struct ipset_arg *args)
/* Fall through */ /* Fall through */
case IPSET_OPTIONAL_ARG: case IPSET_OPTIONAL_ARG:
if (*argc >= 2) { if (*argc >= 2) {
ret = ipset_call_parser(session, arg, argv[1]); ret = ipset_call_parser(session,
arg, argv[1]);
if (ret < 0) if (ret < 0)
return ret; return ret;
ipset_shift_argv(argc, argv, 1); ipset_shift_argv(argc, argv, 1);
@@ -262,7 +263,7 @@ err_unknown:
static enum ipset_adt static enum ipset_adt
cmd2cmd(int cmd) cmd2cmd(int cmd)
{ {
switch(cmd) { switch (cmd) {
case IPSET_CMD_ADD: case IPSET_CMD_ADD:
return IPSET_ADD; return IPSET_ADD;
case IPSET_CMD_DEL: case IPSET_CMD_DEL:
@@ -348,9 +349,9 @@ check_allowed(const struct ipset_type *type, enum ipset_cmd command)
allowed |= IPSET_FLAG(IPSET_OPT_CIDR); allowed |= IPSET_FLAG(IPSET_OPT_CIDR);
for (i = IPSET_OPT_IP; i < IPSET_OPT_FLAGS; i++) { for (i = IPSET_OPT_IP; i < IPSET_OPT_FLAGS; i++) {
if (!(cmdflags & IPSET_FLAG(i)) if (!(cmdflags & IPSET_FLAG(i)) ||
|| (allowed & IPSET_FLAG(i)) (allowed & IPSET_FLAG(i)) ||
|| !(flags & IPSET_FLAG(i))) !(flags & IPSET_FLAG(i)))
continue; continue;
/* Not allowed element-expressions */ /* Not allowed element-expressions */
switch (i) { switch (i) {
@@ -358,19 +359,22 @@ check_allowed(const struct ipset_type *type, enum ipset_cmd command)
exit_error(OTHER_PROBLEM, exit_error(OTHER_PROBLEM,
"IP/CIDR range is not allowed in command %s " "IP/CIDR range is not allowed in command %s "
"with set type %s and family %s", "with set type %s and family %s",
cmd2name(command), type->name, session_family()); cmd2name(command), type->name,
session_family());
return; return;
case IPSET_OPT_IP_TO: case IPSET_OPT_IP_TO:
exit_error(OTHER_PROBLEM, exit_error(OTHER_PROBLEM,
"FROM-TO IP range is not allowed in command %s " "FROM-TO IP range is not allowed in command %s "
"with set type %s and family %s", "with set type %s and family %s",
cmd2name(command), type->name, session_family()); cmd2name(command), type->name,
session_family());
return; return;
case IPSET_OPT_PORT_TO: case IPSET_OPT_PORT_TO:
exit_error(OTHER_PROBLEM, exit_error(OTHER_PROBLEM,
"FROM-TO port range is not allowed in command %s " "FROM-TO port range is not allowed in command %s "
"with set type %s and family %s", "with set type %s and family %s",
cmd2name(command), type->name, session_family()); cmd2name(command), type->name,
session_family());
return; return;
default: default:
break; break;
@@ -390,7 +394,8 @@ check_allowed(const struct ipset_type *type, enum ipset_cmd command)
"%s parameter is not allowed in command %s " "%s parameter is not allowed in command %s "
"with set type %s and family %s", "with set type %s and family %s",
arg->name[0], arg->name[0],
cmd2name(command), type->name, session_family()); cmd2name(command), type->name,
session_family());
return; return;
} }
exit_error(OTHER_PROBLEM, exit_error(OTHER_PROBLEM,
@@ -476,10 +481,10 @@ parse_commandline(int argc, char *argv[])
if (!ipset_match_cmd(argv[1], command->name)) if (!ipset_match_cmd(argv[1], command->name))
continue; continue;
if (restore_line != 0 if (restore_line != 0 &&
&& (command->cmd == IPSET_CMD_RESTORE (command->cmd == IPSET_CMD_RESTORE ||
|| command->cmd == IPSET_CMD_VERSION command->cmd == IPSET_CMD_VERSION ||
|| command->cmd == IPSET_CMD_HELP)) command->cmd == IPSET_CMD_HELP))
return exit_error(PARAMETER_PROBLEM, return exit_error(PARAMETER_PROBLEM,
"Command `%s' is invalid " "Command `%s' is invalid "
"in restore mode.", "in restore mode.",
@@ -564,8 +569,8 @@ parse_commandline(int argc, char *argv[])
case IPSET_CMD_HELP: case IPSET_CMD_HELP:
help(); help();
if (interactive if (interactive ||
|| !ipset_envopt_test(session, IPSET_ENV_QUIET)) { !ipset_envopt_test(session, IPSET_ENV_QUIET)) {
if (arg0) { if (arg0) {
/* Type-specific help, without kernel checking */ /* Type-specific help, without kernel checking */
type = type_find(arg0); type = type_find(arg0);
@@ -729,6 +734,7 @@ main(int argc, char *argv[])
ipset_type_add(&ipset_hash_net1); ipset_type_add(&ipset_hash_net1);
ipset_type_add(&ipset_hash_netport1); ipset_type_add(&ipset_hash_netport1);
ipset_type_add(&ipset_hash_netport2); ipset_type_add(&ipset_hash_netport2);
ipset_type_add(&ipset_hash_netiface0);
ipset_type_add(&ipset_hash_ipport1); ipset_type_add(&ipset_hash_ipport1);
ipset_type_add(&ipset_hash_ipportip1); ipset_type_add(&ipset_hash_ipportip1);
ipset_type_add(&ipset_hash_ipportnet1); ipset_type_add(&ipset_hash_ipportnet1);

View File

@@ -0,0 +1,120 @@
/* Copyright 2011 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <libipset/data.h> /* IPSET_OPT_* */
#include <libipset/parse.h> /* parser functions */
#include <libipset/print.h> /* printing functions */
#include <libipset/ui.h> /* ipset_port_usage */
#include <libipset/types.h> /* prototypes */
/* Parse commandline arguments */
static const struct ipset_arg hash_netiface_create_args[] = {
{ .name = { "family", NULL },
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_FAMILY,
.parse = ipset_parse_family, .print = ipset_print_family,
},
/* Alias: family inet */
{ .name = { "-4", NULL },
.has_arg = IPSET_NO_ARG, .opt = IPSET_OPT_FAMILY,
.parse = ipset_parse_family,
},
/* Alias: family inet6 */
{ .name = { "-6", NULL },
.has_arg = IPSET_NO_ARG, .opt = IPSET_OPT_FAMILY,
.parse = ipset_parse_family,
},
{ .name = { "hashsize", NULL },
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_HASHSIZE,
.parse = ipset_parse_uint32, .print = ipset_print_number,
},
{ .name = { "maxelem", NULL },
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_MAXELEM,
.parse = ipset_parse_uint32, .print = ipset_print_number,
},
{ .name = { "timeout", NULL },
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
.parse = ipset_parse_uint32, .print = ipset_print_number,
},
{ },
};
static const struct ipset_arg hash_netiface_add_args[] = {
{ .name = { "timeout", NULL },
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
.parse = ipset_parse_uint32, .print = ipset_print_number,
},
{ },
};
static const char hash_netiface_usage[] =
"create SETNAME hash:net,iface\n"
" [family inet|inet6]\n"
" [hashsize VALUE] [maxelem VALUE]\n"
" [timeout VALUE]\n"
"add SETNAME IP[/CIDR]|FROM-TO,[physdev:]IFACE [timeout VALUE]\n"
"del SETNAME IP[/CIDR]|FROM-TO,[physdev:]IFACE\n"
"test SETNAME IP[/CIDR],[physdev:]IFACE\n\n"
"where depending on the INET family\n"
" IP is a valid IPv4 or IPv6 address (or hostname),\n"
" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
" Adding/deleting multiple elements with IPv4 is supported.\n";
struct ipset_type ipset_hash_netiface0 = {
.name = "hash:net,iface",
.alias = { "netifacehash", NULL },
.revision = 0,
.family = AF_INET46,
.dimension = IPSET_DIM_TWO,
.elem = {
[IPSET_DIM_ONE] = {
.parse = ipset_parse_ip4_net6,
.print = ipset_print_ip,
.opt = IPSET_OPT_IP
},
[IPSET_DIM_TWO] = {
.parse = ipset_parse_iface,
.print = ipset_print_iface,
.opt = IPSET_OPT_IFACE
},
},
.args = {
[IPSET_CREATE] = hash_netiface_create_args,
[IPSET_ADD] = hash_netiface_add_args,
},
.mandatory = {
[IPSET_CREATE] = 0,
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_IFACE),
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_IFACE),
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_IFACE),
},
.full = {
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
| IPSET_FLAG(IPSET_OPT_MAXELEM)
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_CIDR)
| IPSET_FLAG(IPSET_OPT_IP_TO)
| IPSET_FLAG(IPSET_OPT_IFACE)
| IPSET_FLAG(IPSET_OPT_PHYSDEV)
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_CIDR)
| IPSET_FLAG(IPSET_OPT_IP_TO)
| IPSET_FLAG(IPSET_OPT_IFACE)
| IPSET_FLAG(IPSET_OPT_PHYSDEV),
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_CIDR)
| IPSET_FLAG(IPSET_OPT_IP_TO)
| IPSET_FLAG(IPSET_OPT_IFACE)
| IPSET_FLAG(IPSET_OPT_PHYSDEV),
},
.usage = hash_netiface_usage,
};

View File

@@ -149,7 +149,8 @@ ipset_match_cmd(const char *arg, const char * const name[])
return true; return true;
else if (len != 1) else if (len != 1)
return false; return false;
else return tolower(arg[0]) == name[0][0] || else
return tolower(arg[0]) == name[0][0] ||
(name[1] != NULL && tolower(arg[0]) == name[1][0]); (name[1] != NULL && tolower(arg[0]) == name[1][0]);
} }
@@ -215,8 +216,8 @@ ipset_match_option(const char *arg, const char * const name[])
if (arg[0] == '-' && arg[1] == '-') if (arg[0] == '-' && arg[1] == '-')
arg++, arg++; arg++, arg++;
return STREQ(arg, name[0]) return STREQ(arg, name[0]) ||
|| (name[1] != NULL && STREQ(arg, name[1])); (name[1] != NULL && STREQ(arg, name[1]));
} }
/* Strict envopt matching */ /* Strict envopt matching */
@@ -230,8 +231,8 @@ ipset_match_envopt(const char *arg, const char * const name[])
if (arg[0] == '-' && arg[1] == '-') if (arg[0] == '-' && arg[1] == '-')
arg++; arg++;
return STREQ(arg, name[0]) return STREQ(arg, name[0]) ||
|| (name[1] != NULL && STREQ(arg, name[1])); (name[1] != NULL && STREQ(arg, name[1]));
} }
/** /**
@@ -250,9 +251,8 @@ ipset_shift_argv(int *argc, char *argv[], int from)
assert(*argc >= from + 1); assert(*argc >= from + 1);
for (i = from + 1; i <= *argc; i++) { for (i = from + 1; i <= *argc; i++)
argv[i-1] = argv[i]; argv[i-1] = argv[i];
}
(*argc)--; (*argc)--;
return; return;
} }