mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-09-08 05:34:58 +02:00
ipset: update to 6.7-genl
This commit is contained in:
2
README
2
README
@@ -19,7 +19,7 @@ simplified, and sped up.
|
||||
Included in this package
|
||||
========================
|
||||
- ipset 4.5
|
||||
- ipset 6.6a-genl
|
||||
- ipset 6.7-genl
|
||||
- xt_ACCOUNT 1.16, libxt_ACCOUNT 1.3
|
||||
|
||||
|
||||
|
@@ -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_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_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
|
||||
|
||||
|
@@ -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_hash_ip.c src/ipset_hash_ipport.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
|
||||
ipset_LDADD = libipset.la
|
||||
|
||||
|
@@ -46,11 +46,13 @@ enum ipset_opt {
|
||||
IPSET_OPT_CIDR2,
|
||||
IPSET_OPT_IP2_TO,
|
||||
IPSET_OPT_PROTO,
|
||||
IPSET_OPT_IFACE,
|
||||
/* Swap/rename to */
|
||||
IPSET_OPT_SETNAME2,
|
||||
/* Flags */
|
||||
IPSET_OPT_EXIST,
|
||||
IPSET_OPT_BEFORE,
|
||||
IPSET_OPT_PHYSDEV,
|
||||
/* Internal options */
|
||||
IPSET_OPT_FLAGS = 48, /* IPSET_FLAG_EXIST| */
|
||||
IPSET_OPT_CADT_FLAGS, /* IPSET_FLAG_BEFORE| */
|
||||
@@ -66,7 +68,7 @@ enum ipset_opt {
|
||||
#define IPSET_FLAGS_ALL (~0LL)
|
||||
|
||||
#define IPSET_CREATE_FLAGS \
|
||||
( IPSET_FLAG(IPSET_OPT_FAMILY) \
|
||||
(IPSET_FLAG(IPSET_OPT_FAMILY) \
|
||||
| IPSET_FLAG(IPSET_OPT_TYPENAME)\
|
||||
| IPSET_FLAG(IPSET_OPT_TYPE) \
|
||||
| IPSET_FLAG(IPSET_OPT_IP) \
|
||||
@@ -84,7 +86,7 @@ enum ipset_opt {
|
||||
| IPSET_FLAG(IPSET_OPT_SIZE))
|
||||
|
||||
#define IPSET_ADT_FLAGS \
|
||||
( IPSET_FLAG(IPSET_OPT_IP) \
|
||||
(IPSET_FLAG(IPSET_OPT_IP) \
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO) \
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR) \
|
||||
| IPSET_FLAG(IPSET_OPT_PORT) \
|
||||
@@ -96,8 +98,10 @@ enum ipset_opt {
|
||||
| IPSET_FLAG(IPSET_OPT_IP2) \
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR2) \
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO) \
|
||||
| IPSET_FLAG(IPSET_OPT_IFACE) \
|
||||
| IPSET_FLAG(IPSET_OPT_CADT_FLAGS)\
|
||||
| IPSET_FLAG(IPSET_OPT_BEFORE))
|
||||
| IPSET_FLAG(IPSET_OPT_BEFORE) \
|
||||
| IPSET_FLAG(IPSET_OPT_PHYSDEV))
|
||||
|
||||
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,
|
||||
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);
|
||||
|
||||
static inline bool
|
||||
@@ -120,13 +124,13 @@ ipset_data_test(const struct ipset_data *data, enum ipset_opt opt)
|
||||
}
|
||||
|
||||
/* 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_cidr(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 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 size_t ipset_data_sizeof(enum ipset_opt opt, uint8_t family);
|
||||
|
@@ -12,7 +12,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <linux/netlink.h>
|
||||
#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...) \
|
||||
if (test) \
|
||||
D(fmt , ## args)
|
||||
|
@@ -9,8 +9,8 @@
|
||||
|
||||
#include <stdint.h> /* uintxx_t */
|
||||
|
||||
extern const char * id_to_icmp(uint8_t id);
|
||||
extern const char * icmp_to_name(uint8_t type, uint8_t code);
|
||||
extern const char *id_to_icmp(uint8_t id);
|
||||
extern const char *icmp_to_name(uint8_t type, uint8_t code);
|
||||
extern int name_to_icmp(const char *str, uint16_t *typecode);
|
||||
|
||||
#endif /* LIBIPSET_ICMP_H */
|
||||
|
@@ -9,8 +9,8 @@
|
||||
|
||||
#include <stdint.h> /* uintxx_t */
|
||||
|
||||
extern const char * id_to_icmpv6(uint8_t id);
|
||||
extern const char * icmpv6_to_name(uint8_t type, uint8_t code);
|
||||
extern const char *id_to_icmpv6(uint8_t id);
|
||||
extern const char *icmpv6_to_name(uint8_t type, uint8_t code);
|
||||
extern int name_to_icmpv6(const char *str, uint16_t *typecode);
|
||||
|
||||
#endif /* LIBIPSET_ICMPV6_H */
|
||||
|
@@ -105,6 +105,7 @@ enum {
|
||||
IPSET_ATTR_IP2,
|
||||
IPSET_ATTR_CIDR2,
|
||||
IPSET_ATTR_IP2_TO,
|
||||
IPSET_ATTR_IFACE,
|
||||
__IPSET_ATTR_ADT_MAX,
|
||||
};
|
||||
#define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1)
|
||||
@@ -153,6 +154,8 @@ enum ipset_cmd_flags {
|
||||
enum ipset_cadt_flags {
|
||||
IPSET_FLAG_BIT_BEFORE = 0,
|
||||
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 */
|
||||
|
@@ -80,6 +80,8 @@ extern int ipset_parse_flag(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_typename(struct ipset_session *session,
|
||||
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,
|
||||
int opt, const char *str);
|
||||
extern int ipset_parse_ignored(struct ipset_session *session,
|
||||
|
@@ -12,7 +12,7 @@
|
||||
{.ip6 = { \
|
||||
__constant_htonl(a), __constant_htonl(b), \
|
||||
__constant_htonl(c), __constant_htonl(d), \
|
||||
}}
|
||||
} }
|
||||
|
||||
/*
|
||||
* This table works for both IPv4 and IPv6;
|
||||
|
@@ -37,6 +37,9 @@ extern int ipset_print_name(char *buf, unsigned int len,
|
||||
extern int ipset_print_port(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt, uint8_t env);
|
||||
extern int ipset_print_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,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt, uint8_t env);
|
||||
|
@@ -21,10 +21,14 @@ struct ipset_session;
|
||||
struct ipset_data;
|
||||
struct ipset_handle;
|
||||
|
||||
extern struct ipset_data * ipset_session_data(const struct ipset_session *session);
|
||||
extern struct ipset_handle * ipset_session_handle(const struct ipset_session *session);
|
||||
extern const struct ipset_type * ipset_saved_type(const struct ipset_session *session);
|
||||
extern void ipset_session_lineno(struct ipset_session *session, uint32_t lineno);
|
||||
extern struct ipset_data *
|
||||
ipset_session_data(const struct ipset_session *session);
|
||||
extern struct ipset_handle *
|
||||
ipset_session_handle(const struct ipset_session *session);
|
||||
extern const struct ipset_type *
|
||||
ipset_saved_type(const struct ipset_session *session);
|
||||
extern void ipset_session_lineno(struct ipset_session *session,
|
||||
uint32_t lineno);
|
||||
|
||||
enum ipset_err_type {
|
||||
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 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_error(const struct ipset_session *session);
|
||||
extern const char *ipset_session_warning(const struct ipset_session *session);
|
||||
|
||||
#define ipset_session_data_set(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, ...)
|
||||
__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 void ipset_debug_msg(const char *dir, void *buffer, int len);
|
||||
|
@@ -97,13 +97,14 @@ extern int ipset_cache_swap(const char *from, const char *to);
|
||||
extern int ipset_cache_init(void);
|
||||
extern void ipset_cache_fini(void);
|
||||
|
||||
extern const struct ipset_type * 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_get(struct ipset_session *session, enum ipset_cmd cmd);
|
||||
extern const struct ipset_type *
|
||||
ipset_type_check(struct ipset_session *session);
|
||||
|
||||
extern int ipset_type_add(struct ipset_type *type);
|
||||
extern const struct ipset_type * ipset_types(void);
|
||||
extern const char * ipset_typename_resolve(const char *str);
|
||||
extern const struct ipset_type *ipset_types(void);
|
||||
extern const char *ipset_typename_resolve(const char *str);
|
||||
extern bool ipset_match_typename(const char *str,
|
||||
const struct ipset_type *t);
|
||||
|
||||
|
@@ -11,10 +11,10 @@
|
||||
#include <netinet/in.h> /* struct in[6]_addr */
|
||||
|
||||
/* String equality tests */
|
||||
#define STREQ(a,b) (strcmp(a,b) == 0)
|
||||
#define STRNEQ(a,b,n) (strncmp(a,b,n) == 0)
|
||||
#define STRCASEQ(a,b) (strcasecmp(a,b) == 0)
|
||||
#define STRNCASEQ(a,b,n) (strncasecmp(a,b,n) == 0)
|
||||
#define STREQ(a, b) (strcmp(a, b) == 0)
|
||||
#define STRNEQ(a, b, n) (strncmp(a, b, n) == 0)
|
||||
#define STRCASEQ(a, b) (strcasecmp(a, b) == 0)
|
||||
#define STRNCASEQ(a, b, n) (strncasecmp(a, b, n) == 0)
|
||||
|
||||
/* Stringify tokens */
|
||||
#define _STR(c) #c
|
||||
|
@@ -107,6 +107,7 @@ enum {
|
||||
IPSET_ATTR_IP2,
|
||||
IPSET_ATTR_CIDR2,
|
||||
IPSET_ATTR_IP2_TO,
|
||||
IPSET_ATTR_IFACE,
|
||||
__IPSET_ATTR_ADT_MAX,
|
||||
};
|
||||
#define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1)
|
||||
@@ -155,6 +156,8 @@ enum ipset_cmd_flags {
|
||||
enum ipset_cadt_flags {
|
||||
IPSET_FLAG_BIT_BEFORE = 0,
|
||||
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 */
|
||||
@@ -214,6 +217,8 @@ enum ip_set_feature {
|
||||
IPSET_TYPE_IP2 = (1 << IPSET_TYPE_IP2_FLAG),
|
||||
IPSET_TYPE_NAME_FLAG = 4,
|
||||
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:
|
||||
* this settype must be dumped last */
|
||||
IPSET_DUMP_LAST_FLAG = 7,
|
||||
@@ -328,7 +333,7 @@ struct ip_set {
|
||||
/* register and unregister set references */
|
||||
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 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_byindex(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);
|
||||
|
||||
/* 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 int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr);
|
||||
extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr);
|
||||
|
@@ -43,7 +43,7 @@ struct htable {
|
||||
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 */
|
||||
struct ip_set_hash_nets {
|
||||
@@ -63,6 +63,9 @@ struct ip_set_hash {
|
||||
#ifdef IP_SET_HASH_WITH_NETMASK
|
||||
u8 netmask; /* netmask value for subnets to store */
|
||||
#endif
|
||||
#ifdef IP_SET_HASH_WITH_RBTREE
|
||||
struct rb_root rbtree;
|
||||
#endif
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
struct ip_set_hash_nets nets[0]; /* book-keeping of prefixes */
|
||||
#endif
|
||||
@@ -200,6 +203,9 @@ ip_set_hash_destroy(struct ip_set *set)
|
||||
del_timer_sync(&h->gc);
|
||||
|
||||
ahash_destroy(h->table);
|
||||
#ifdef IP_SET_HASH_WITH_RBTREE
|
||||
rbtree_destroy(&h->rbtree);
|
||||
#endif
|
||||
kfree(h);
|
||||
|
||||
set->data = NULL;
|
||||
|
@@ -635,7 +635,8 @@ static struct ip_set_type bitmap_ipmac_type = {
|
||||
},
|
||||
.adt_policy = {
|
||||
[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_LINENO] = { .type = NLA_U32 },
|
||||
},
|
||||
|
762
extensions/ipset-6/ip_set_hash_netiface.c
Normal file
762
extensions/ipset-6/ip_set_hash_netiface.c
Normal 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);
|
@@ -7,6 +7,7 @@
|
||||
#include <assert.h> /* assert */
|
||||
#include <arpa/inet.h> /* ntoh* */
|
||||
#include <net/ethernet.h> /* ETH_ALEN */
|
||||
#include <net/if.h> /* IFNAMSIZ */
|
||||
#include <sys/socket.h> /* AF_ */
|
||||
#include <stdlib.h> /* malloc, free */
|
||||
#include <string.h> /* memset */
|
||||
@@ -72,6 +73,7 @@ struct ipset_data {
|
||||
char ether[ETH_ALEN];
|
||||
char name[IPSET_MAXNAMELEN];
|
||||
char nameref[IPSET_MAXNAMELEN];
|
||||
char iface[IFNAMSIZ];
|
||||
} adt;
|
||||
};
|
||||
};
|
||||
@@ -301,6 +303,9 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
|
||||
case IPSET_OPT_PROTO:
|
||||
data->adt.proto = *(const uint8_t *) value;
|
||||
break;
|
||||
case IPSET_OPT_IFACE:
|
||||
ipset_strlcpy(data->adt.iface, value, IFNAMSIZ);
|
||||
break;
|
||||
/* Swap/rename */
|
||||
case IPSET_OPT_SETNAME2:
|
||||
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:
|
||||
cadt_flag_type_attr(data, opt, IPSET_FLAG_BEFORE);
|
||||
break;
|
||||
case IPSET_OPT_PHYSDEV:
|
||||
cadt_flag_type_attr(data, opt, IPSET_FLAG_PHYSDEV);
|
||||
break;
|
||||
case IPSET_OPT_FLAGS:
|
||||
data->flags = *(const uint32_t *)value;
|
||||
break;
|
||||
@@ -413,6 +421,8 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
|
||||
return &data->adt.cidr2;
|
||||
case IPSET_OPT_PROTO:
|
||||
return &data->adt.proto;
|
||||
case IPSET_OPT_IFACE:
|
||||
return &data->adt.iface;
|
||||
/* Swap/rename */
|
||||
case IPSET_OPT_SETNAME2:
|
||||
return data->setname2;
|
||||
@@ -422,6 +432,7 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
|
||||
return &data->flags;
|
||||
case IPSET_OPT_CADT_FLAGS:
|
||||
case IPSET_OPT_BEFORE:
|
||||
case IPSET_OPT_PHYSDEV:
|
||||
return &data->cadt_flags;
|
||||
default:
|
||||
return NULL;
|
||||
@@ -472,8 +483,9 @@ ipset_data_sizeof(enum ipset_opt opt, uint8_t family)
|
||||
return sizeof(uint8_t);
|
||||
case IPSET_OPT_ETHER:
|
||||
return ETH_ALEN;
|
||||
/* Flags counted once */
|
||||
/* Flags doesn't counted once :-( */
|
||||
case IPSET_OPT_BEFORE:
|
||||
case IPSET_OPT_PHYSDEV:
|
||||
return sizeof(uint32_t);
|
||||
default:
|
||||
return 0;
|
||||
|
@@ -63,6 +63,7 @@ static const struct ipset_attrname adtattr2name[] = {
|
||||
[IPSET_ATTR_IP2] = { .name = "IP2" },
|
||||
[IPSET_ATTR_CIDR2] = { .name = "CIDR2" },
|
||||
[IPSET_ATTR_IP2_TO] = { .name = "IP2_TO" },
|
||||
[IPSET_ATTR_IFACE] = { .name = "IFACE" },
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -73,23 +74,24 @@ debug_cadt_attrs(int max, const struct ipset_attr_policy *policy,
|
||||
uint32_t v;
|
||||
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++) {
|
||||
if (!nla[i])
|
||||
continue;
|
||||
switch (policy[i].type) {
|
||||
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",
|
||||
attr2name[i].name, v);
|
||||
break;
|
||||
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",
|
||||
attr2name[i].name, ntohs(v));
|
||||
break;
|
||||
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",
|
||||
attr2name[i].name, ntohl(v));
|
||||
break;
|
||||
@@ -103,18 +105,23 @@ debug_cadt_attrs(int max, const struct ipset_attr_policy *policy,
|
||||
char addr[INET6_ADDRSTRLEN];
|
||||
void *d;
|
||||
|
||||
if (mnl_attr_parse_nested(nla[i], ipaddr_attr_cb, ipattr) < 0) {
|
||||
fprintf(stderr, "\t\tIPADDR: cannot validate and parse attributes\n");
|
||||
if (mnl_attr_parse_nested(nla[i], ipaddr_attr_cb,
|
||||
ipattr) < 0) {
|
||||
fprintf(stderr,
|
||||
"\t\tIPADDR: cannot validate "
|
||||
"and parse attributes\n");
|
||||
continue;
|
||||
}
|
||||
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);
|
||||
fprintf(stderr, "\t\t%s: %s\n",
|
||||
attr2name[i].name, addr);
|
||||
} 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);
|
||||
fprintf(stderr, "\t\t%s: %s\n",
|
||||
@@ -137,23 +144,23 @@ debug_cmd_attrs(int cmd, struct nlattr *nla[])
|
||||
uint32_t v;
|
||||
int i;
|
||||
|
||||
fprintf(stderr,"\tCommand attributes:\n");
|
||||
fprintf(stderr, "\tCommand attributes:\n");
|
||||
for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_CMD_MAX; i++) {
|
||||
if (!nla[i])
|
||||
continue;
|
||||
switch (cmd_attrs[i].type) {
|
||||
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",
|
||||
cmdattr2name[i].name, v);
|
||||
break;
|
||||
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",
|
||||
cmdattr2name[i].name, ntohs(v));
|
||||
break;
|
||||
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",
|
||||
cmdattr2name[i].name, ntohl(v));
|
||||
break;
|
||||
@@ -168,8 +175,11 @@ debug_cmd_attrs(int cmd, struct nlattr *nla[])
|
||||
case IPSET_CMD_ADD:
|
||||
case IPSET_CMD_DEL:
|
||||
case IPSET_CMD_TEST:
|
||||
if (mnl_attr_parse_nested(nla[i], adt_attr_cb, adt) < 0) {
|
||||
fprintf(stderr, "\tADT: cannot validate and parse attributes\n");
|
||||
if (mnl_attr_parse_nested(nla[i],
|
||||
adt_attr_cb, adt) < 0) {
|
||||
fprintf(stderr,
|
||||
"\tADT: cannot validate "
|
||||
"and parse attributes\n");
|
||||
continue;
|
||||
}
|
||||
debug_cadt_attrs(IPSET_ATTR_ADT_MAX,
|
||||
@@ -178,8 +188,12 @@ debug_cmd_attrs(int cmd, struct nlattr *nla[])
|
||||
adt);
|
||||
break;
|
||||
default:
|
||||
if (mnl_attr_parse_nested(nla[i], create_attr_cb, cattr) < 0) {
|
||||
fprintf(stderr, "\tCREATE: cannot validate and parse attributes\n");
|
||||
if (mnl_attr_parse_nested(nla[i],
|
||||
create_attr_cb,
|
||||
cattr) < 0) {
|
||||
fprintf(stderr,
|
||||
"\tCREATE: cannot validate "
|
||||
"and parse attributes\n");
|
||||
continue;
|
||||
}
|
||||
debug_cadt_attrs(IPSET_ATTR_CREATE_MAX,
|
||||
@@ -191,8 +205,11 @@ debug_cmd_attrs(int cmd, struct nlattr *nla[])
|
||||
struct nlattr *tb;
|
||||
mnl_attr_for_each_nested(tb, nla[i]) {
|
||||
memset(adt, 0, sizeof(adt));
|
||||
if (mnl_attr_parse_nested(tb, adt_attr_cb, adt) < 0) {
|
||||
fprintf(stderr, "\tADT: cannot validate and parse attributes\n");
|
||||
if (mnl_attr_parse_nested(tb,
|
||||
adt_attr_cb, adt) < 0) {
|
||||
fprintf(stderr,
|
||||
"\tADT: cannot validate "
|
||||
"and parse attributes\n");
|
||||
continue;
|
||||
}
|
||||
debug_cadt_attrs(IPSET_ATTR_ADT_MAX,
|
||||
@@ -227,7 +244,8 @@ ipset_debug_msg(const char *dir, void *buffer, int len)
|
||||
"\tseq %u\n",
|
||||
dir,
|
||||
nlh->nlmsg_type == NLMSG_NOOP ? "NOOP" :
|
||||
nlh->nlmsg_type == NLMSG_DONE ? "DONE" : "OVERRUN",
|
||||
nlh->nlmsg_type == NLMSG_DONE ? "DONE" :
|
||||
"OVERRUN",
|
||||
len, nlh->nlmsg_seq);
|
||||
goto next_msg;
|
||||
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)
|
||||
goto next_msg;
|
||||
memset(nla, 0, sizeof(nla));
|
||||
if (mnl_attr_parse(nlh, nfmsglen, cmd_attr_cb, nla) < MNL_CB_STOP) {
|
||||
fprintf(stderr, "\tcannot validate and parse attributes\n");
|
||||
if (mnl_attr_parse(nlh, nfmsglen,
|
||||
cmd_attr_cb, nla) < MNL_CB_STOP) {
|
||||
fprintf(stderr, "\tcannot validate "
|
||||
"and parse attributes\n");
|
||||
goto next_msg;
|
||||
}
|
||||
debug_cmd_attrs(cmd, nla);
|
||||
|
@@ -49,17 +49,18 @@ static const struct icmp_names icmp_typecodes[] = {
|
||||
{ "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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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 NULL;
|
||||
@@ -71,7 +72,8 @@ int name_to_icmp(const char *str, uint16_t *typecode)
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(icmp_typecodes); i++)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@@ -36,17 +36,19 @@ static const struct icmpv6_names icmpv6_typecodes[] = {
|
||||
{ "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;
|
||||
|
||||
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 NULL;
|
||||
@@ -58,7 +60,8 @@ int name_to_icmpv6(const char *str, uint16_t *typecode)
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(icmpv6_typecodes); i++)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@@ -38,7 +38,8 @@ struct ipset_handle {
|
||||
|
||||
/* Netlink flags of the commands */
|
||||
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_FLUSH-1] = NLM_F_REQUEST|NLM_F_ACK,
|
||||
[IPSET_CMD_RENAME-1] = NLM_F_REQUEST|NLM_F_ACK,
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include <sys/types.h> /* getaddrinfo */
|
||||
#include <sys/socket.h> /* getaddrinfo, AF_ */
|
||||
#include <net/ethernet.h> /* ETH_ALEN */
|
||||
#include <net/if.h> /* IFNAMSIZ */
|
||||
#include <netinet/in.h> /* IPPROTO_ */
|
||||
|
||||
#include <libipset/debug.h> /* D() */
|
||||
@@ -47,11 +48,13 @@ ipset_strchr(const char *str, const char *sep)
|
||||
assert(str);
|
||||
assert(sep);
|
||||
|
||||
for (; *sep != '\0'; sep++)
|
||||
if ((match = strchr(str, sep[0])) != NULL
|
||||
&& str[0] != sep[0]
|
||||
&& str[strlen(str)-1] != sep[0])
|
||||
for (; *sep != '\0'; sep++) {
|
||||
match = strchr(str, sep[0]);
|
||||
if (match != NULL &&
|
||||
str[0] != sep[0] &&
|
||||
str[strlen(str)-1] != sep[0])
|
||||
return match;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -178,9 +181,9 @@ ipset_parse_ether(struct ipset_session *session,
|
||||
|
||||
number = strtol(str + i * 3, &end, 16);
|
||||
|
||||
if (end == str + i * 3 + 2
|
||||
&& (*end == ':' || *end == '\0')
|
||||
&& number >= 0 && number <= 255)
|
||||
if (end == str + i * 3 + 2 &&
|
||||
(*end == ':' || *end == '\0') &&
|
||||
number >= 0 && number <= 255)
|
||||
ether[i] = number;
|
||||
else
|
||||
goto error;
|
||||
@@ -198,9 +201,9 @@ static int
|
||||
parse_portname(struct ipset_session *session, const char *str,
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
@@ -232,8 +235,8 @@ ipset_parse_port(struct ipset_session *session,
|
||||
assert(opt == IPSET_OPT_PORT || opt == IPSET_OPT_PORT_TO);
|
||||
assert(str);
|
||||
|
||||
if ((err = string_to_u16(session, str, &port)) == 0
|
||||
|| (err = parse_portname(session, str, &port, proto)) == 0)
|
||||
if ((err = string_to_u16(session, str, &port)) == 0 ||
|
||||
(err = parse_portname(session, str, &port, proto)) == 0)
|
||||
err = ipset_session_data_set(session, opt, &port);
|
||||
|
||||
if (!err)
|
||||
@@ -384,11 +387,12 @@ parse_icmp_typecode(struct ipset_session *session,
|
||||
if (a == NULL) {
|
||||
free(saved);
|
||||
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';
|
||||
if ((err = string_to_u8(session, a, &type)) != 0
|
||||
|| (err = string_to_u8(session, tmp, &code)) != 0)
|
||||
if ((err = string_to_u8(session, a, &type)) != 0 ||
|
||||
(err = string_to_u8(session, tmp, &code)) != 0)
|
||||
goto error;
|
||||
|
||||
typecode = (type << 8) | code;
|
||||
@@ -508,21 +512,24 @@ ipset_parse_proto_port(struct ipset_session *session,
|
||||
goto parse_port;
|
||||
case IPPROTO_ICMP:
|
||||
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;
|
||||
}
|
||||
err = ipset_parse_icmp(session, opt, a);
|
||||
break;
|
||||
case IPPROTO_ICMPV6:
|
||||
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;
|
||||
}
|
||||
err = ipset_parse_icmpv6(session, opt, a);
|
||||
break;
|
||||
default:
|
||||
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;
|
||||
}
|
||||
ipset_data_flags_set(data, IPSET_FLAG(opt));
|
||||
@@ -633,13 +640,21 @@ get_addrinfo(struct ipset_session *session,
|
||||
continue;
|
||||
if (found == 0) {
|
||||
if (family == AF_INET) {
|
||||
/* Workaround: direct cast increases required alignment on Sparc */
|
||||
const struct sockaddr_in *saddr = (void *)i->ai_addr;
|
||||
err = ipset_session_data_set(session, opt, &saddr->sin_addr);
|
||||
/* Workaround: direct cast increases
|
||||
* required alignment on Sparc
|
||||
*/
|
||||
const struct sockaddr_in *saddr =
|
||||
(void *)i->ai_addr;
|
||||
err = ipset_session_data_set(session,
|
||||
opt, &saddr->sin_addr);
|
||||
} else {
|
||||
/* Workaround: direct cast increases required alignment on Sparc */
|
||||
const struct sockaddr_in6 *saddr = (void *)i->ai_addr;
|
||||
err = ipset_session_data_set(session, opt, &saddr->sin6_addr);
|
||||
/* Workaround: direct cast increases
|
||||
* required alignment on Sparc
|
||||
*/
|
||||
const struct sockaddr_in6 *saddr =
|
||||
(void *)i->ai_addr;
|
||||
err = ipset_session_data_set(session,
|
||||
opt, &saddr->sin6_addr);
|
||||
}
|
||||
} else if (found == 1) {
|
||||
ipset_warn(session,
|
||||
@@ -685,8 +700,8 @@ parse_ipaddr(struct ipset_session *session,
|
||||
/* IP/mask */
|
||||
*a++ = '\0';
|
||||
|
||||
if ((err = string_to_cidr(session, a, 0, m, &m)) != 0
|
||||
|| (err = ipset_session_data_set(session, copt, &m)) != 0)
|
||||
if ((err = string_to_cidr(session, a, 0, m, &m)) != 0 ||
|
||||
(err = ipset_session_data_set(session, copt, &m)) != 0)
|
||||
goto out;
|
||||
} else if ((a = range_separator(tmp)) != NULL) {
|
||||
/* IP-IP */
|
||||
@@ -694,8 +709,8 @@ parse_ipaddr(struct ipset_session *session,
|
||||
D("range %s", a);
|
||||
range++;
|
||||
}
|
||||
if ((aerr = get_addrinfo(session, opt, tmp, &info, family)) != 0
|
||||
|| !range)
|
||||
if ((aerr = get_addrinfo(session, opt, tmp, &info, family)) != 0 ||
|
||||
!range)
|
||||
goto out;
|
||||
freeaddrinfo(info);
|
||||
aerr = get_addrinfo(session, opt2, a, &info, family);
|
||||
@@ -739,10 +754,10 @@ parse_ip(struct ipset_session *session,
|
||||
|
||||
switch (addrtype) {
|
||||
case IPADDR_PLAIN:
|
||||
if (range_separator(str)
|
||||
|| (cidr_separator(str) && !cidr_hostaddr(str, family)))
|
||||
return syntax_err("plain IP address must be supplied: %s",
|
||||
str);
|
||||
if (range_separator(str) ||
|
||||
(cidr_separator(str) && !cidr_hostaddr(str, family)))
|
||||
return syntax_err("plain IP address must be supplied: "
|
||||
"%s", str);
|
||||
break;
|
||||
case IPADDR_NET:
|
||||
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)
|
||||
{
|
||||
assert(session);
|
||||
assert(opt == IPSET_OPT_IP
|
||||
|| opt == IPSET_OPT_IP_TO
|
||||
|| opt == IPSET_OPT_IP2);
|
||||
assert(opt == IPSET_OPT_IP ||
|
||||
opt == IPSET_OPT_IP_TO ||
|
||||
opt == IPSET_OPT_IP2);
|
||||
assert(str);
|
||||
|
||||
return parse_ip(session, opt, str, IPADDR_PLAIN);
|
||||
@@ -882,8 +897,8 @@ ipset_parse_netrange(struct ipset_session *session,
|
||||
assert(str);
|
||||
|
||||
if (!(range_separator(str) || cidr_separator(str)))
|
||||
return syntax_err("IP/cidr or IP-IP range must be specified: %s",
|
||||
str);
|
||||
return syntax_err("IP/cidr or IP-IP range must be specified: "
|
||||
"%s", str);
|
||||
return parse_ip(session, opt, str, IPADDR_ANY);
|
||||
}
|
||||
|
||||
@@ -909,8 +924,8 @@ ipset_parse_iprange(struct ipset_session *session,
|
||||
assert(str);
|
||||
|
||||
if (cidr_separator(str))
|
||||
return syntax_err("IP address or IP-IP range must be specified: %s",
|
||||
str);
|
||||
return syntax_err("IP address or IP-IP range must be "
|
||||
"specified: %s", str);
|
||||
return parse_ip(session, opt, str, IPADDR_ANY);
|
||||
}
|
||||
|
||||
@@ -1075,7 +1090,7 @@ do { \
|
||||
if (strlen(str) > IPSET_MAXNAMELEN - 1) { \
|
||||
if (saved != NULL) \
|
||||
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); \
|
||||
} \
|
||||
} while (0)
|
||||
@@ -1122,8 +1137,8 @@ ipset_parse_name_compat(struct ipset_session *session,
|
||||
*a++ = '\0';
|
||||
if ((b = elem_separator(a)) != NULL)
|
||||
*b++ = '\0';
|
||||
if (b == NULL
|
||||
|| !(STREQ(a, "before") || STREQ(a, "after"))) {
|
||||
if (b == NULL ||
|
||||
!(STREQ(a, "before") || STREQ(a, "after"))) {
|
||||
err = ipset_err(session, "you must specify elements "
|
||||
"as setname%s[before|after]%ssetname",
|
||||
sep, sep);
|
||||
@@ -1164,9 +1179,9 @@ ipset_parse_setname(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str)
|
||||
{
|
||||
assert(session);
|
||||
assert(opt == IPSET_SETNAME
|
||||
|| opt == IPSET_OPT_NAME
|
||||
|| opt == IPSET_OPT_SETNAME2);
|
||||
assert(opt == IPSET_SETNAME ||
|
||||
opt == IPSET_OPT_NAME ||
|
||||
opt == IPSET_OPT_SETNAME2);
|
||||
assert(str);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @session: session structure
|
||||
@@ -1442,7 +1492,8 @@ ipset_parse_ignored(struct ipset_session *session,
|
||||
|
||||
if (!ipset_data_ignored(ipset_session_data(session), opt))
|
||||
ipset_warn(session,
|
||||
"Option %s is ignored. Please upgrade your syntax.", str);
|
||||
"Option %s is ignored. "
|
||||
"Please upgrade your syntax.", str);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include <sys/socket.h> /* inet_ntop */
|
||||
#include <arpa/inet.h> /* inet_ntop */
|
||||
#include <net/ethernet.h> /* ETH_ALEN */
|
||||
#include <net/if.h> /* IFNAMSIZ */
|
||||
|
||||
#include <libipset/debug.h> /* D() */
|
||||
#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);
|
||||
}
|
||||
|
||||
#define GETNAMEINFO(family, f, n) \
|
||||
static inline int \
|
||||
__getnameinfo##f(char *buf, unsigned int len, \
|
||||
int flags, const union nf_inet_addr *addr) \
|
||||
{ \
|
||||
struct sockaddr_in##n saddr; \
|
||||
int err; \
|
||||
\
|
||||
memset(&saddr, 0, sizeof(saddr)); \
|
||||
in##f##cpy(&saddr.sin##n##_addr, &addr->in##n); \
|
||||
saddr.sin##n##_family = family; \
|
||||
\
|
||||
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);\
|
||||
static inline int
|
||||
__getnameinfo4(char *buf, unsigned int len,
|
||||
int flags, const union nf_inet_addr *addr)
|
||||
{
|
||||
struct sockaddr_in saddr;
|
||||
int err;
|
||||
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
in4cpy(&saddr.sin_addr, &addr->in);
|
||||
saddr.sin_family = AF_INET;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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) \
|
||||
@@ -189,10 +215,8 @@ snprintf_ipv##f(char *buf, unsigned int len, int flags, \
|
||||
return offset; \
|
||||
}
|
||||
|
||||
GETNAMEINFO(AF_INET, 4, )
|
||||
SNPRINTF_IP(32, 4)
|
||||
|
||||
GETNAMEINFO(AF_INET6, 6, 6)
|
||||
SNPRINTF_IP(128, 6)
|
||||
|
||||
/**
|
||||
@@ -287,9 +311,9 @@ ipset_print_ipaddr(char *buf, unsigned int len,
|
||||
assert(buf);
|
||||
assert(len > 0);
|
||||
assert(data);
|
||||
assert(opt == IPSET_OPT_IP
|
||||
|| opt == IPSET_OPT_IP_TO
|
||||
|| opt == IPSET_OPT_IP2);
|
||||
assert(opt == IPSET_OPT_IP ||
|
||||
opt == IPSET_OPT_IP_TO ||
|
||||
opt == IPSET_OPT_IP2);
|
||||
|
||||
family = ipset_data_family(data);
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @buf: printing buffer
|
||||
@@ -511,7 +574,8 @@ ipset_print_icmp(char *buf, unsigned int len,
|
||||
if (name != NULL)
|
||||
return snprintf(buf, len, "%s", name);
|
||||
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)
|
||||
return snprintf(buf, len, "%s", name);
|
||||
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);
|
||||
IF_D(ipset_data_test(data, type->elem[IPSET_DIM_TWO].opt),
|
||||
"print second elem");
|
||||
if (type->dimension == IPSET_DIM_ONE
|
||||
|| (type->last_elem_optional
|
||||
&& !ipset_data_test(data, type->elem[IPSET_DIM_TWO].opt)))
|
||||
if (type->dimension == IPSET_DIM_ONE ||
|
||||
(type->last_elem_optional &&
|
||||
!ipset_data_test(data, type->elem[IPSET_DIM_TWO].opt)))
|
||||
return offset;
|
||||
|
||||
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,
|
||||
type->elem[IPSET_DIM_TWO].opt, env);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
if (type->dimension == IPSET_DIM_TWO
|
||||
|| (type->last_elem_optional
|
||||
&& !ipset_data_test(data, type->elem[IPSET_DIM_THREE].opt)))
|
||||
if (type->dimension == IPSET_DIM_TWO ||
|
||||
(type->last_elem_optional &&
|
||||
!ipset_data_test(data, type->elem[IPSET_DIM_THREE].opt)))
|
||||
return offset;
|
||||
|
||||
size = snprintf(buf + offset, len, IPSET_ELEM_SEPARATOR);
|
||||
@@ -731,6 +796,9 @@ ipset_print_data(char *buf, unsigned int len,
|
||||
case IPSET_OPT_PORT:
|
||||
size = ipset_print_port(buf, len, data, opt, env);
|
||||
break;
|
||||
case IPSET_OPT_IFACE:
|
||||
size = ipset_print_iface(buf, len, data, opt, env);
|
||||
break;
|
||||
case IPSET_OPT_GC:
|
||||
case IPSET_OPT_HASHSIZE:
|
||||
case IPSET_OPT_MAXELEM:
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include <string.h> /* str* */
|
||||
#include <unistd.h> /* getpagesize */
|
||||
#include <net/ethernet.h> /* ETH_ALEN */
|
||||
#include <net/if.h> /* IFNAMSIZ */
|
||||
|
||||
#include <libipset/debug.h> /* D() */
|
||||
#include <libipset/data.h> /* IPSET_OPT_* */
|
||||
@@ -199,7 +200,7 @@ ipset_session_output(struct ipset_session *session,
|
||||
*
|
||||
* Returns -1.
|
||||
*/
|
||||
int __attribute__((format(printf,3,4)))
|
||||
int __attribute__((format(printf, 3, 4)))
|
||||
ipset_session_report(struct ipset_session *session,
|
||||
enum ipset_err_type type,
|
||||
const char *fmt, ...)
|
||||
@@ -475,6 +476,11 @@ static const struct ipset_attr_policy adt_attrs[] = {
|
||||
.type = MNL_TYPE_NESTED,
|
||||
.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[] = {
|
||||
@@ -508,8 +514,8 @@ generic_data_attr_cb(const struct nlattr *attr, void *data,
|
||||
mnl_attr_get_payload_len(attr));
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
if (policy[type].type == MNL_TYPE_NUL_STRING
|
||||
&& mnl_attr_get_payload_len(attr) > IPSET_MAXNAMELEN)
|
||||
if (policy[type].type == MNL_TYPE_NUL_STRING &&
|
||||
mnl_attr_get_payload_len(attr) > IPSET_MAXNAMELEN)
|
||||
return MNL_CB_ERROR;
|
||||
tb[type] = attr;
|
||||
return MNL_CB_OK;
|
||||
@@ -659,7 +665,7 @@ call_outfn(struct ipset_session *session)
|
||||
/* Handle printing failures */
|
||||
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, ...)
|
||||
{
|
||||
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++) {
|
||||
if (!arg->print
|
||||
|| !ipset_data_test(data, arg->opt)
|
||||
|| (arg->opt == IPSET_OPT_FAMILY
|
||||
&& family == type->family))
|
||||
if (!arg->print ||
|
||||
!ipset_data_test(data, arg->opt) ||
|
||||
(arg->opt == IPSET_OPT_FAMILY &&
|
||||
family == type->family))
|
||||
continue;
|
||||
switch (session->mode) {
|
||||
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)) {
|
||||
/* Header part already seen */
|
||||
if (ipset_data_test(data, IPSET_OPT_TYPE)
|
||||
&& nla[IPSET_ATTR_DATA] != NULL)
|
||||
if (ipset_data_test(data, IPSET_OPT_TYPE) &&
|
||||
nla[IPSET_ATTR_DATA] != NULL)
|
||||
FAILURE("Broken %s kernel message: "
|
||||
"extra DATA received!", cmd2name[cmd]);
|
||||
} else {
|
||||
@@ -992,13 +998,14 @@ callback_list(struct ipset_session *session, struct nlattr *nla[],
|
||||
if (nla[IPSET_ATTR_DATA] != NULL) {
|
||||
struct nlattr *cattr[IPSET_ATTR_CREATE_MAX+1] = {};
|
||||
|
||||
if (!(nla[IPSET_ATTR_TYPENAME]
|
||||
&& nla[IPSET_ATTR_FAMILY]
|
||||
&& nla[IPSET_ATTR_REVISION]))
|
||||
if (!(nla[IPSET_ATTR_TYPENAME] &&
|
||||
nla[IPSET_ATTR_FAMILY] &&
|
||||
nla[IPSET_ATTR_REVISION]))
|
||||
FAILURE("Broken %s kernel message: missing %s!",
|
||||
cmd2name[cmd],
|
||||
!nla[IPSET_ATTR_TYPENAME] ? "typename" :
|
||||
!nla[IPSET_ATTR_FAMILY] ? "family" : "revision");
|
||||
!nla[IPSET_ATTR_FAMILY] ? "family" :
|
||||
"revision");
|
||||
|
||||
/* Reset CREATE specific 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",
|
||||
min, max, IPSET_PROTOCOL_MIN, IPSET_PROTOCOL_MAX);
|
||||
|
||||
if (!(session->envopts & IPSET_ENV_QUIET)
|
||||
&& max != IPSET_PROTOCOL_MAX)
|
||||
if (!(session->envopts & IPSET_ENV_QUIET) &&
|
||||
max != IPSET_PROTOCOL_MAX)
|
||||
ipset_warn(session,
|
||||
"Kernel support 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'!",
|
||||
ipset_data_setname(data), setname);
|
||||
|
||||
if (!(nla[IPSET_ATTR_TYPENAME]
|
||||
&& nla[IPSET_ATTR_REVISION]
|
||||
&& nla[IPSET_ATTR_FAMILY]))
|
||||
if (!(nla[IPSET_ATTR_TYPENAME] &&
|
||||
nla[IPSET_ATTR_REVISION] &&
|
||||
nla[IPSET_ATTR_FAMILY]))
|
||||
FAILURE("Broken HEADER kernel message: "
|
||||
"missing attribute '%s'!",
|
||||
!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 char *typename, *orig;
|
||||
|
||||
if (!(nla[IPSET_ATTR_TYPENAME]
|
||||
&& nla[IPSET_ATTR_REVISION]
|
||||
&& nla[IPSET_ATTR_FAMILY]))
|
||||
if (!(nla[IPSET_ATTR_TYPENAME] &&
|
||||
nla[IPSET_ATTR_REVISION] &&
|
||||
nla[IPSET_ATTR_FAMILY]))
|
||||
FAILURE("Broken TYPE kernel message: "
|
||||
"missing attribute '%s'!",
|
||||
!nla[IPSET_ATTR_TYPENAME] ? "typename" :
|
||||
@@ -1318,16 +1325,20 @@ callback_error(const struct nlmsghdr *nlh, void *cbdata)
|
||||
break;
|
||||
case IPSET_CMD_RENAME:
|
||||
ipset_cache_rename(ipset_data_setname(data),
|
||||
ipset_data_get(data, IPSET_OPT_SETNAME2));
|
||||
ipset_data_get(data,
|
||||
IPSET_OPT_SETNAME2));
|
||||
break;
|
||||
case IPSET_CMD_SWAP:
|
||||
ipset_cache_swap(ipset_data_setname(data),
|
||||
ipset_data_get(data, IPSET_OPT_SETNAME2));
|
||||
ipset_data_get(data,
|
||||
IPSET_OPT_SETNAME2));
|
||||
break;
|
||||
case IPSET_CMD_TEST:
|
||||
if (!(session->envopts & IPSET_ENV_QUIET)) {
|
||||
ipset_print_elem(session->report, IPSET_ERRORBUFLEN,
|
||||
session->data, IPSET_OPT_NONE, 0);
|
||||
ipset_print_elem(session->report,
|
||||
IPSET_ERRORBUFLEN,
|
||||
session->data,
|
||||
IPSET_OPT_NONE, 0);
|
||||
ipset_warn(session, " is in set %s.",
|
||||
ipset_data_setname(data));
|
||||
}
|
||||
@@ -1341,7 +1352,8 @@ callback_error(const struct nlmsghdr *nlh, void *cbdata)
|
||||
print_set_done(session);
|
||||
break;
|
||||
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
|
||||
? cmd2name[session->cmd] : "unknown",
|
||||
session->cmd);
|
||||
@@ -1353,8 +1365,8 @@ callback_error(const struct nlmsghdr *nlh, void *cbdata)
|
||||
/* Error messages */
|
||||
|
||||
/* Special case for IPSET_CMD_TEST */
|
||||
if (session->cmd == IPSET_CMD_TEST
|
||||
&& err->error == -IPSET_ERR_EXIST) {
|
||||
if (session->cmd == IPSET_CMD_TEST &&
|
||||
err->error == -IPSET_ERR_EXIST) {
|
||||
if (!(session->envopts & IPSET_ENV_QUIET)) {
|
||||
ipset_print_elem(session->report, IPSET_ERRORBUFLEN,
|
||||
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) \
|
||||
(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
|
||||
rawdata2attr(struct ipset_session *session, struct nlmsghdr *nlh,
|
||||
@@ -1439,7 +1452,8 @@ rawdata2attr(struct ipset_session *session, struct nlmsghdr *nlh,
|
||||
: IPSET_ATTR_IPADDR_IPV6;
|
||||
|
||||
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;
|
||||
nested = mnl_attr_nest_start(nlh, type);
|
||||
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,
|
||||
"Invalid internal TYPE command: "
|
||||
"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))
|
||||
ADDATTR(session, nlh, data, IPSET_ATTR_FAMILY, AF_INET, cmd_attrs);
|
||||
ADDATTR(session, nlh, data, IPSET_ATTR_FAMILY,
|
||||
AF_INET, cmd_attrs);
|
||||
else
|
||||
/* bitmap:port and list:set types */
|
||||
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
|
||||
may_aggregate_ad(struct ipset_session *session, enum ipset_cmd cmd)
|
||||
{
|
||||
return session->lineno != 0
|
||||
&& (cmd == IPSET_CMD_ADD || cmd == IPSET_CMD_DEL)
|
||||
&& cmd == session->cmd
|
||||
&& STREQ(ipset_data_setname(session->data), session->saved_setname);
|
||||
return session->lineno != 0 &&
|
||||
(cmd == IPSET_CMD_ADD || cmd == IPSET_CMD_DEL) &&
|
||||
cmd == session->cmd &&
|
||||
STREQ(ipset_data_setname(session->data), session->saved_setname);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1623,7 +1639,8 @@ build_msg(struct ipset_session *session, bool aggregate)
|
||||
/* Core attributes:
|
||||
* setname, typename, revision, family, flags (optional) */
|
||||
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,
|
||||
IPSET_ATTR_REVISION, cmd_attrs);
|
||||
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))
|
||||
return ipset_err(session,
|
||||
"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))
|
||||
return ipset_err(session,
|
||||
"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_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);
|
||||
break;
|
||||
case IPSET_CMD_ADD:
|
||||
@@ -1688,12 +1708,14 @@ build_msg(struct ipset_session *session, bool aggregate)
|
||||
if (!ipset_data_test(data, IPSET_SETNAME))
|
||||
return ipset_err(session,
|
||||
"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))
|
||||
return ipset_err(session,
|
||||
"Invalid %s command: missing settype",
|
||||
session->cmd == IPSET_CMD_ADD ? "add" : "del");
|
||||
session->cmd == IPSET_CMD_ADD ? "add" :
|
||||
"del");
|
||||
|
||||
/* Core options: setname */
|
||||
ADDATTR_SETNAME(session, nlh, data);
|
||||
@@ -1711,11 +1733,12 @@ build_msg(struct ipset_session *session, bool aggregate)
|
||||
D("open_nested failed");
|
||||
return 1;
|
||||
}
|
||||
if (addattr_adt(session, nlh, data, ipset_data_family(data))
|
||||
|| ADDATTR_RAW(session, nlh, &session->lineno,
|
||||
if (addattr_adt(session, nlh, data, ipset_data_family(data)) ||
|
||||
ADDATTR_RAW(session, nlh, &session->lineno,
|
||||
IPSET_ATTR_LINENO, cmd_attrs)) {
|
||||
/* 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;
|
||||
return 1;
|
||||
}
|
||||
@@ -1769,7 +1792,8 @@ ipset_commit(struct ipset_session *session)
|
||||
assert(session);
|
||||
|
||||
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)
|
||||
/* Nothing to do */
|
||||
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 */
|
||||
session->saved_type = ipset_data_get(data, IPSET_OPT_TYPE);
|
||||
if (session->lineno != 0
|
||||
&& (cmd == IPSET_CMD_ADD || cmd == IPSET_CMD_DEL)) {
|
||||
if (session->lineno != 0 &&
|
||||
(cmd == IPSET_CMD_ADD || cmd == IPSET_CMD_DEL)) {
|
||||
/* Save setname for the next possible aggregated restore line */
|
||||
strcpy(session->saved_setname, ipset_data_setname(data));
|
||||
ipset_data_reset(data);
|
||||
|
@@ -28,8 +28,8 @@ struct ipset {
|
||||
struct ipset *next;
|
||||
};
|
||||
|
||||
static struct ipset_type *typelist = NULL; /* registered set types */
|
||||
static struct ipset *setlist = NULL; /* cached sets */
|
||||
static struct ipset_type *typelist; /* registered set types */
|
||||
static struct ipset *setlist; /* cached sets */
|
||||
|
||||
/**
|
||||
* ipset_cache_add - add a set to the cache
|
||||
@@ -178,7 +178,7 @@ ipset_cache_swap(const char *from, const char *to)
|
||||
bool
|
||||
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))
|
||||
return true;
|
||||
@@ -240,9 +240,11 @@ create_type_get(struct ipset_session *session)
|
||||
if (ret != 0)
|
||||
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))
|
||||
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 (kmin > tmax)
|
||||
|
@@ -174,8 +174,8 @@ ipset_errcode(struct ipset_session *session, enum ipset_cmd cmd, int errcode)
|
||||
|
||||
retry:
|
||||
for (i = 0, generic = -1; table[i].errcode; i++) {
|
||||
if (table[i].errcode == errcode
|
||||
&& (table[i].cmd == cmd || table[i].cmd == 0)) {
|
||||
if (table[i].errcode == errcode &&
|
||||
(table[i].cmd == cmd || table[i].cmd == 0)) {
|
||||
if (table[i].cmd == 0) {
|
||||
generic = i;
|
||||
continue;
|
||||
|
@@ -214,8 +214,8 @@ command follows the syntax
|
||||
|
||||
where the current list of the methods are
|
||||
\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
|
||||
is equal to the number of data types in its type name.
|
||||
are \fBip\fR, \fBnet\fR, \fBmac\fR, \fBport\fR and \fBiface\fR.
|
||||
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
|
||||
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
|
||||
.IP
|
||||
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
|
||||
The \fBlist:set\fR type uses a simple list in which you can store
|
||||
set names.
|
||||
|
@@ -26,12 +26,12 @@
|
||||
static char program_name[] = PACKAGE;
|
||||
static char program_version[] = PACKAGE_VERSION;
|
||||
|
||||
static struct ipset_session *session = NULL;
|
||||
static uint32_t restore_line = 0;
|
||||
static bool interactive = false;
|
||||
static struct ipset_session *session;
|
||||
static uint32_t restore_line;
|
||||
static bool interactive;
|
||||
static char cmdline[1024];
|
||||
static char *newargv[255];
|
||||
static int newargc = 0;
|
||||
static int newargc;
|
||||
|
||||
/* The known set types: (typename, revision, family) is unique */
|
||||
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_netport1;
|
||||
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_ipportip1;
|
||||
extern struct ipset_type ipset_hash_ipportnet1;
|
||||
@@ -56,12 +57,12 @@ enum exittype {
|
||||
SESSION_PROBLEM,
|
||||
};
|
||||
|
||||
static int __attribute__((format(printf,2,3)))
|
||||
static int __attribute__((format(printf, 2, 3)))
|
||||
exit_error(int status, const char *msg, ...)
|
||||
{
|
||||
bool quiet = !interactive
|
||||
&& session
|
||||
&& ipset_envopt_test(session, IPSET_ENV_QUIET);
|
||||
bool quiet = !interactive &&
|
||||
session &&
|
||||
ipset_envopt_test(session, IPSET_ENV_QUIET);
|
||||
|
||||
if (status && msg && !quiet) {
|
||||
va_list args;
|
||||
@@ -97,8 +98,8 @@ exit_error(int status, const char *msg, ...)
|
||||
static int
|
||||
handle_error(void)
|
||||
{
|
||||
if (ipset_session_warning(session)
|
||||
&& !ipset_envopt_test(session, IPSET_ENV_QUIET))
|
||||
if (ipset_session_warning(session) &&
|
||||
!ipset_envopt_test(session, IPSET_ENV_QUIET))
|
||||
fprintf(stderr, "Warning: %s\n",
|
||||
ipset_session_warning(session));
|
||||
if (ipset_session_error(session))
|
||||
@@ -124,9 +125,8 @@ help(void)
|
||||
"Usage: %s [options] COMMAND\n\nCommands:\n",
|
||||
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("\nOptions:\n");
|
||||
|
||||
while (opt->flag) {
|
||||
@@ -236,7 +236,8 @@ call_parser(int *argc, char *argv[], const struct ipset_arg *args)
|
||||
/* Fall through */
|
||||
case IPSET_OPTIONAL_ARG:
|
||||
if (*argc >= 2) {
|
||||
ret = ipset_call_parser(session, arg, argv[1]);
|
||||
ret = ipset_call_parser(session,
|
||||
arg, argv[1]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ipset_shift_argv(argc, argv, 1);
|
||||
@@ -262,7 +263,7 @@ err_unknown:
|
||||
static enum ipset_adt
|
||||
cmd2cmd(int cmd)
|
||||
{
|
||||
switch(cmd) {
|
||||
switch (cmd) {
|
||||
case IPSET_CMD_ADD:
|
||||
return IPSET_ADD;
|
||||
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);
|
||||
|
||||
for (i = IPSET_OPT_IP; i < IPSET_OPT_FLAGS; i++) {
|
||||
if (!(cmdflags & IPSET_FLAG(i))
|
||||
|| (allowed & IPSET_FLAG(i))
|
||||
|| !(flags & IPSET_FLAG(i)))
|
||||
if (!(cmdflags & IPSET_FLAG(i)) ||
|
||||
(allowed & IPSET_FLAG(i)) ||
|
||||
!(flags & IPSET_FLAG(i)))
|
||||
continue;
|
||||
/* Not allowed element-expressions */
|
||||
switch (i) {
|
||||
@@ -358,19 +359,22 @@ check_allowed(const struct ipset_type *type, enum ipset_cmd command)
|
||||
exit_error(OTHER_PROBLEM,
|
||||
"IP/CIDR range is not allowed in command %s "
|
||||
"with set type %s and family %s",
|
||||
cmd2name(command), type->name, session_family());
|
||||
cmd2name(command), type->name,
|
||||
session_family());
|
||||
return;
|
||||
case IPSET_OPT_IP_TO:
|
||||
exit_error(OTHER_PROBLEM,
|
||||
"FROM-TO IP range is not allowed in command %s "
|
||||
"with set type %s and family %s",
|
||||
cmd2name(command), type->name, session_family());
|
||||
cmd2name(command), type->name,
|
||||
session_family());
|
||||
return;
|
||||
case IPSET_OPT_PORT_TO:
|
||||
exit_error(OTHER_PROBLEM,
|
||||
"FROM-TO port range is not allowed in command %s "
|
||||
"with set type %s and family %s",
|
||||
cmd2name(command), type->name, session_family());
|
||||
cmd2name(command), type->name,
|
||||
session_family());
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
@@ -390,7 +394,8 @@ check_allowed(const struct ipset_type *type, enum ipset_cmd command)
|
||||
"%s parameter is not allowed in command %s "
|
||||
"with set type %s and family %s",
|
||||
arg->name[0],
|
||||
cmd2name(command), type->name, session_family());
|
||||
cmd2name(command), type->name,
|
||||
session_family());
|
||||
return;
|
||||
}
|
||||
exit_error(OTHER_PROBLEM,
|
||||
@@ -476,10 +481,10 @@ parse_commandline(int argc, char *argv[])
|
||||
if (!ipset_match_cmd(argv[1], command->name))
|
||||
continue;
|
||||
|
||||
if (restore_line != 0
|
||||
&& (command->cmd == IPSET_CMD_RESTORE
|
||||
|| command->cmd == IPSET_CMD_VERSION
|
||||
|| command->cmd == IPSET_CMD_HELP))
|
||||
if (restore_line != 0 &&
|
||||
(command->cmd == IPSET_CMD_RESTORE ||
|
||||
command->cmd == IPSET_CMD_VERSION ||
|
||||
command->cmd == IPSET_CMD_HELP))
|
||||
return exit_error(PARAMETER_PROBLEM,
|
||||
"Command `%s' is invalid "
|
||||
"in restore mode.",
|
||||
@@ -564,8 +569,8 @@ parse_commandline(int argc, char *argv[])
|
||||
case IPSET_CMD_HELP:
|
||||
help();
|
||||
|
||||
if (interactive
|
||||
|| !ipset_envopt_test(session, IPSET_ENV_QUIET)) {
|
||||
if (interactive ||
|
||||
!ipset_envopt_test(session, IPSET_ENV_QUIET)) {
|
||||
if (arg0) {
|
||||
/* Type-specific help, without kernel checking */
|
||||
type = type_find(arg0);
|
||||
@@ -729,6 +734,7 @@ main(int argc, char *argv[])
|
||||
ipset_type_add(&ipset_hash_net1);
|
||||
ipset_type_add(&ipset_hash_netport1);
|
||||
ipset_type_add(&ipset_hash_netport2);
|
||||
ipset_type_add(&ipset_hash_netiface0);
|
||||
ipset_type_add(&ipset_hash_ipport1);
|
||||
ipset_type_add(&ipset_hash_ipportip1);
|
||||
ipset_type_add(&ipset_hash_ipportnet1);
|
||||
|
120
extensions/ipset-6/src/ipset_hash_netiface.c
Normal file
120
extensions/ipset-6/src/ipset_hash_netiface.c
Normal 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,
|
||||
};
|
||||
|
@@ -149,7 +149,8 @@ ipset_match_cmd(const char *arg, const char * const name[])
|
||||
return true;
|
||||
else if (len != 1)
|
||||
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]);
|
||||
}
|
||||
|
||||
@@ -215,8 +216,8 @@ ipset_match_option(const char *arg, const char * const name[])
|
||||
if (arg[0] == '-' && arg[1] == '-')
|
||||
arg++, arg++;
|
||||
|
||||
return STREQ(arg, name[0])
|
||||
|| (name[1] != NULL && STREQ(arg, name[1]));
|
||||
return STREQ(arg, name[0]) ||
|
||||
(name[1] != NULL && STREQ(arg, name[1]));
|
||||
}
|
||||
|
||||
/* Strict envopt matching */
|
||||
@@ -230,8 +231,8 @@ ipset_match_envopt(const char *arg, const char * const name[])
|
||||
if (arg[0] == '-' && arg[1] == '-')
|
||||
arg++;
|
||||
|
||||
return STREQ(arg, name[0])
|
||||
|| (name[1] != NULL && STREQ(arg, name[1]));
|
||||
return STREQ(arg, name[0]) ||
|
||||
(name[1] != NULL && STREQ(arg, name[1]));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -250,9 +251,8 @@ ipset_shift_argv(int *argc, char *argv[], int from)
|
||||
|
||||
assert(*argc >= from + 1);
|
||||
|
||||
for (i = from + 1; i <= *argc; i++) {
|
||||
for (i = from + 1; i <= *argc; i++)
|
||||
argv[i-1] = argv[i];
|
||||
}
|
||||
(*argc)--;
|
||||
return;
|
||||
}
|
||||
|
Reference in New Issue
Block a user