diff options
author | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2010-10-24 21:42:48 +0200 |
---|---|---|
committer | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2010-10-24 21:42:48 +0200 |
commit | 0d32c5c070f817229110f92d7b31df9a3e4eeec5 (patch) | |
tree | 5ee04a9e03de32d2029ad0d708811e382ca922d1 | |
parent | 62a3d29539aa109fed1c8a20d63ef95948b13842 (diff) |
Fixes, cleanups, commentsv5.0-pre8
- More comments added to the code
- ICMP and ICMPv6 support added to the hash:ip,port, hash:ip,port,ip
and hash:ip,port,net types
- hash:net and hash:ip,port,net types are reworked
- hash:net,port type added
- Wrong direction parameters fixed in hash:ip,port
- Helps and manpage are updated
- More tests added
- Ugly macros are rewritten to functions in parse.c
(Holger Eitzenberger)
- resize related bug in hash types fixed (Holger Eitzenberger)
- autoreconf patches by Jan Engelhardt applied
- netlink patch minimalized: dumping can be initialized by a second
parsing of the message (thanks to David and Patrick for the suggestion)
- IPv4/IPv6 address attributes are introduced in order to fix the context
(suggested by David)
88 files changed, 2487 insertions, 1086 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f6660e --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +*~ +*.la +*.lo +*.o +.deps +.libs +Makefile +Makefile.in + +/aclocal.m4 +/autom4te.cache +/compile +/config.* +/configure +/depcomp +/install-sh +/libtool +/ltmain.sh +/missing +/stamp-h1 diff --git a/Makefile.am b/Makefile.am index 7225f86..c68544a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,7 @@ ## Process this file with automake to produce Makefile.in +ACLOCAL_AMFLAGS = -I m4 + include $(top_srcdir)/Make_global.am if ! WITH_KBUILDDIR @@ -46,8 +48,8 @@ cleanup_dirs := . include/libipset lib src tests tidy: distclean modules_clean rm -rf .deps $(foreach dir,$(cleanup_dirs),$(wildcard $(dir)/*~)) rm -rf aclocal.m4 autom4te.cache - rm -rf config.* configure depcomp install-sh libtool ltmain.sh + rm -rf config.* configure compile depcomp install-sh libtool ltmain.sh rm -rf Makefile Makefile.in lib/Makefile lib/Makefile.in src/Makefile src/Makefile.in - rm -rf missing stamp-h1 + rm -rf missing stamp-h1 m4/* .PHONY: modules modules_instal modules_clean update_includes tests @@ -1,18 +1,5 @@ #!/bin/sh -run () -{ - echo "running: $*" - eval $* - - if test $? != 0 ; then - echo "error: while running '$*'" - exit 1 - fi -} - -run aclocal -run autoheader -run libtoolize -f -run automake -a -run autoconf +mkdir -p m4 +autoreconf -fi +rm -rf autom4te.cache diff --git a/configure.ac b/configure.ac index 7622ac4..38164cf 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,9 @@ dnl Boilerplate AC_INIT([ipset], [5.0], [kadlec@blackhole.kfki.hu]) -AC_CANONICAL_SYSTEM +AC_CANONICAL_TARGET +AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_HEADER([config.h]) -AM_INIT_AUTOMAKE([-Wall -Werror foreign]) +AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) dnl Shortcut: Linux supported alone case $target in @@ -12,10 +13,14 @@ esac dnl Additional arguments dnl Kernel build directory or source tree -AC_ARG_WITH([kernel], - AS_HELP_STRING([--with-kernel=PATH], - [Path to kernel source/build directory]), - [KBUILDDIR="$withval";]) +AC_ARG_WITH([kbuild], + AS_HELP_STRING([--with-kbuild=PATH], + [Path to kernel build directory]), + [KBUILDDIR="$withval";]) +AC_ARG_WITH([ksource], + AS_HELP_STRING([--with-ksource=PATH], + [Path to kernel source directory, if not the same as the kernel build directory]), + [KSOURCEDIR="$withval";]) AM_CONDITIONAL(WITH_KBUILDDIR, test "$KBUILDDIR" != "") AC_SUBST(KBUILDDIR) @@ -27,9 +32,16 @@ else kbuilddir="/lib/modules/`uname -r`/build" fi -if test ! -e "$kbuilddir/include/linux/netfilter/nfnetlink.h" +if test -n "$KSOURCEDIR"; then + ksourcedir="$KSOURCEDIR" +elif test -e "$kbuilddir/include/linux/netfilter/nfnetlink.h"; then + ksourcedir="$kbuilddir" +else + ksourcedir="/lib/modules/$(uname -r)/source" +fi +if test ! -e "$ksourcedir/include/linux/netfilter/nfnetlink.h" then - AC_MSG_ERROR([Invalid kernel build directory $kbuilddir]) + AC_MSG_ERROR([Invalid kernel source directory $ksourcedir]) fi if test ! -e "$kbuilddir/.config" @@ -45,11 +57,11 @@ then fi dnl Check kernel dependencies: nfnetlink.h -NFNL_CB_CONST="`./check_const $kbuilddir/include/linux/netfilter/nfnetlink.h`" +NFNL_CB_CONST="`./check_const $ksourcedir/include/linux/netfilter/nfnetlink.h`" AC_SUBST(NFNL_CB_CONST) dnl Check kernel dependencies: netlink.h -NETLINK_DUMP_CONST="`./check_const $kbuilddir/include/linux/netlink.h`" +NETLINK_DUMP_CONST="`./check_const $ksourcedir/include/linux/netlink.h`" AC_SUBST(NETLINK_DUMP_CONST) dnl Maximal number of sets supported by the kernel, default 256 @@ -98,15 +110,13 @@ AM_CONDITIONAL([DISABLE_EXTRA_FLAGS], [test "x$extra_flags" = xno]) dnl Checks for programs AC_PROG_CC -AC_PROG_LIBTOOL +AM_PROG_CC_C_O +LT_INIT AC_PROG_INSTALL AC_PROG_LN_S dnl Checks for libraries -AC_CHECK_LIB([mnl], [mnl_socket_open]) -if test x"${ac_cv_lib_mnl_mnl_socket_open}" = xno; then - AC_MSG_ERROR(libmnl not found) -fi +PKG_CHECK_MODULES([libmnl], [libmnl >= 1]) dnl Checks for header files diff --git a/include/libipset/errcode.h b/include/libipset/errcode.h index 5ad41ff..ed56eb5 100644 --- a/include/libipset/errcode.h +++ b/include/libipset/errcode.h @@ -11,10 +11,11 @@ struct ipset_session; +/* Kernel error code to message table */ struct ipset_errcode_table { - int errcode; - enum ipset_cmd cmd; - const char *message; + int errcode; /* error code returned by the kernel */ + enum ipset_cmd cmd; /* issued command */ + const char *message; /* error message the code translated to */ }; extern int ipset_errcode(struct ipset_session *session, enum ipset_cmd cmd, diff --git a/include/libipset/icmp.h b/include/libipset/icmp.h new file mode 100644 index 0000000..89604cd --- /dev/null +++ b/include/libipset/icmp.h @@ -0,0 +1,16 @@ +/* Copyright 2007-2010 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. + */ +#ifndef LIBIPSET_ICMP_H +#define LIBIPSET_ICMP_H + +#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 int name_to_icmp(const char *str, uint16_t *typecode); + +#endif /* LIBIPSET_ICMP_H */ diff --git a/include/libipset/icmpv6.h b/include/libipset/icmpv6.h new file mode 100644 index 0000000..b23c822 --- /dev/null +++ b/include/libipset/icmpv6.h @@ -0,0 +1,16 @@ +/* Copyright 2007-2010 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. + */ +#ifndef LIBIPSET_ICMPV6_H +#define LIBIPSET_ICMPV6_H + +#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 int name_to_icmpv6(const char *str, uint16_t *typecode); + +#endif /* LIBIPSET_ICMPV6_H */ diff --git a/include/libipset/linux_ip_set.h b/include/libipset/linux_ip_set.h index 0ad2b14..c3296df 100644 --- a/include/libipset/linux_ip_set.h +++ b/include/libipset/linux_ip_set.h @@ -52,7 +52,7 @@ enum { IPSET_ATTR_PROTOCOL, /* 1: Protocol version */ IPSET_ATTR_SETNAME, /* 2: Name of the set */ IPSET_ATTR_TYPENAME, /* 3: Typename */ - IPSET_ATTR_SETNAME2 = IPSET_ATTR_TYPENAME, /* rename/swap */ + IPSET_ATTR_SETNAME2 = IPSET_ATTR_TYPENAME, /* Setname at rename/swap */ IPSET_ATTR_REVISION, /* 4: Settype revision */ IPSET_ATTR_FAMILY, /* 5: Settype family */ IPSET_ATTR_FLAGS, /* 6: Flags at command level */ @@ -77,7 +77,7 @@ enum { IPSET_ATTR_TIMEOUT, /* 6 */ IPSET_ATTR_PROTO, /* 7 */ IPSET_ATTR_CADT_FLAGS, /* 8 */ - IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO, + IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO, /* 9 */ /* Reserve empty slots */ IPSET_ATTR_CADT_MAX = 16, /* Create-only specific attributes */ @@ -108,6 +108,14 @@ enum { }; #define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1) +/* IP specific attributes */ +enum { + IPSET_ATTR_IPADDR_IPV4 = IPSET_ATTR_UNSPEC + 1, + IPSET_ATTR_IPADDR_IPV6, + __IPSET_ATTR_IPADDR_MAX, +}; +#define IPSET_ATTR_IPADDR_MAX (__IPSET_ATTR_IPADDR_MAX - 1) + /* Error codes */ enum ipset_errno { IPSET_ERR_PRIVATE = 128, @@ -123,16 +131,20 @@ enum ipset_errno { IPSET_ERR_INVALID_FAMILY, IPSET_ERR_TIMEOUT, IPSET_ERR_REFERENCED, + IPSET_ERR_IPADDR_IPV4, + IPSET_ERR_IPADDR_IPV6, /* Type specific error codes */ IPSET_ERR_TYPE_SPECIFIC = 160, }; +/* Flags at command level */ enum ipset_cmd_flags { IPSET_FLAG_BIT_EXIST = 0, IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST), }; +/* Flags at CADT attribute level */ enum ipset_cadt_flags { IPSET_FLAG_BIT_BEFORE = 0, IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE), @@ -148,7 +160,4 @@ enum ipset_adt { IPSET_CADT_MAX, }; -#define IPSET_IPPROTO_ANY 255 -#define IPSET_IPPROTO_TCPUDP 254 - #endif /* __IP_SET_H */ diff --git a/include/libipset/linux_ip_set_bitmap.h b/include/libipset/linux_ip_set_bitmap.h index 01ea534..95fb963 100644 --- a/include/libipset/linux_ip_set_bitmap.h +++ b/include/libipset/linux_ip_set_bitmap.h @@ -3,7 +3,9 @@ /* Bitmap type specific error codes */ enum { + /* The element is out of the range of the set */ IPSET_ERR_BITMAP_RANGE = IPSET_ERR_TYPE_SPECIFIC, + /* The range exceeds the size limit of the set type */ IPSET_ERR_BITMAP_RANGE_SIZE, }; diff --git a/include/libipset/linux_ip_set_hash.h b/include/libipset/linux_ip_set_hash.h index db6977b..7c6336a 100644 --- a/include/libipset/linux_ip_set_hash.h +++ b/include/libipset/linux_ip_set_hash.h @@ -1,11 +1,15 @@ #ifndef __IP_SET_HASH_H #define __IP_SET_HASH_H -/* Bitmap type specific error codes */ +/* Hash type specific error codes */ enum { + /* Hash is full */ IPSET_ERR_HASH_FULL = IPSET_ERR_TYPE_SPECIFIC, + /* Null-valued element */ IPSET_ERR_HASH_ELEM, + /* Invalid protocol */ IPSET_ERR_INVALID_PROTO, + /* Protocol missing but must be specified */ IPSET_ERR_MISSING_PROTO, }; diff --git a/include/libipset/linux_ip_set_list.h b/include/libipset/linux_ip_set_list.h index cf282c5..2395aa2 100644 --- a/include/libipset/linux_ip_set_list.h +++ b/include/libipset/linux_ip_set_list.h @@ -3,11 +3,17 @@ /* List type specific error codes */ enum { + /* Set name to be added/deleted/tested does not exist. */ IPSET_ERR_NAME = IPSET_ERR_TYPE_SPECIFIC, + /* list:set type is not permitted to add */ IPSET_ERR_LOOP, + /* Missing reference set */ IPSET_ERR_BEFORE, + /* Reference set does not exist */ IPSET_ERR_NAMEREF, + /* Set is full */ IPSET_ERR_LIST_FULL, + /* Reference set is not added to the set */ IPSET_ERR_REF_EXIST, }; diff --git a/include/libipset/nf_inet_addr.h b/include/libipset/nf_inet_addr.h index 91f1914..0e0701e 100644 --- a/include/libipset/nf_inet_addr.h +++ b/include/libipset/nf_inet_addr.h @@ -10,7 +10,7 @@ #include <stdint.h> /* uint32_t */ #include <netinet/in.h> /* struct in[6]_addr */ -/* The same structure to hold IP addresses as in linux/netfilter.h */ +/* The structure to hold IP addresses, same as in linux/netfilter.h */ union nf_inet_addr { uint32_t all[4]; uint32_t ip; diff --git a/include/libipset/parse.h b/include/libipset/parse.h index 1e055ee..aaa1577 100644 --- a/include/libipset/parse.h +++ b/include/libipset/parse.h @@ -23,12 +23,19 @@ typedef int (*ipset_parsefn)(struct ipset_session *s, extern int ipset_parse_ether(struct ipset_session *session, enum ipset_opt opt, const char *str); -extern int ipset_parse_single_port(struct ipset_session *session, - enum ipset_opt opt, const char *str); extern int ipset_parse_port(struct ipset_session *session, - enum ipset_opt opt, const char *str); + enum ipset_opt opt, const char *str, + const char *proto); +extern int ipset_parse_tcp_port(struct ipset_session *session, + enum ipset_opt opt, const char *str); +extern int ipset_parse_single_tcp_port(struct ipset_session *session, + enum ipset_opt opt, const char *str); extern int ipset_parse_proto(struct ipset_session *session, enum ipset_opt opt, const char *str); +extern int ipset_parse_icmp(struct ipset_session *session, + enum ipset_opt opt, const char *str); +extern int ipset_parse_icmpv6(struct ipset_session *session, + enum ipset_opt opt, const char *str); extern int ipset_parse_proto_port(struct ipset_session *session, enum ipset_opt opt, const char *str); extern int ipset_parse_family(struct ipset_session *session, diff --git a/include/libipset/print.h b/include/libipset/print.h index 1fc5abc..963b42e 100644 --- a/include/libipset/print.h +++ b/include/libipset/print.h @@ -10,50 +10,56 @@ #include <libipset/data.h> /* enum ipset_opt */ typedef int (*ipset_printfn)(char *buf, unsigned int len, - const struct ipset_data *data, enum ipset_opt opt, - uint8_t env); + const struct ipset_data *data, + enum ipset_opt opt, uint8_t env); extern int ipset_print_ether(char *buf, unsigned int len, - const struct ipset_data *data, enum ipset_opt opt, - uint8_t env); + const struct ipset_data *data, + enum ipset_opt opt, uint8_t env); extern int ipset_print_family(char *buf, unsigned int len, - const struct ipset_data *data, enum ipset_opt opt, - uint8_t env); + const struct ipset_data *data, + enum ipset_opt opt, uint8_t env); extern int ipset_print_type(char *buf, unsigned int len, - const struct ipset_data *data, enum ipset_opt opt, - uint8_t env); + const struct ipset_data *data, + enum ipset_opt opt, uint8_t env); extern int ipset_print_ip(char *buf, unsigned int len, - const struct ipset_data *data, enum ipset_opt opt, - uint8_t env); + const struct ipset_data *data, + enum ipset_opt opt, uint8_t env); extern int ipset_print_ipaddr(char *buf, unsigned int len, - const struct ipset_data *data, enum ipset_opt opt, - uint8_t env); + const struct ipset_data *data, + enum ipset_opt opt, uint8_t env); extern int ipset_print_number(char *buf, unsigned int len, - const struct ipset_data *data, enum ipset_opt opt, - uint8_t env); + const struct ipset_data *data, + enum ipset_opt opt, uint8_t env); extern int ipset_print_name(char *buf, unsigned int len, - const struct ipset_data *data, enum ipset_opt opt, - uint8_t env); + const struct ipset_data *data, + enum ipset_opt opt, uint8_t env); extern int ipset_print_port(char *buf, unsigned int len, - const struct ipset_data *data, enum ipset_opt opt, - uint8_t env); + 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); + const struct ipset_data *data, + enum ipset_opt opt, uint8_t env); +extern int ipset_print_icmp(char *buf, unsigned int len, + const struct ipset_data *data, + enum ipset_opt opt, uint8_t env); +extern int ipset_print_icmpv6(char *buf, unsigned int len, + const struct ipset_data *data, + enum ipset_opt opt, uint8_t env); extern int ipset_print_proto_port(char *buf, unsigned int len, const struct ipset_data *data, enum ipset_opt opt, uint8_t env); extern int ipset_print_flag(char *buf, unsigned int len, - const struct ipset_data *data, enum ipset_opt opt, - uint8_t env); + const struct ipset_data *data, + enum ipset_opt opt, uint8_t env); extern int ipset_print_elem(char *buf, unsigned int len, - const struct ipset_data *data, enum ipset_opt opt, - uint8_t env); + const struct ipset_data *data, + enum ipset_opt opt, uint8_t env); #define ipset_print_portnum ipset_print_number extern int ipset_print_data(char *buf, unsigned int len, - const struct ipset_data *data, enum ipset_opt opt, - uint8_t env); + const struct ipset_data *data, + enum ipset_opt opt, uint8_t env); #endif /* LIBIPSET_PRINT_H */ diff --git a/include/libipset/types.h b/include/libipset/types.h index 6a17750..f1847aa 100644 --- a/include/libipset/types.h +++ b/include/libipset/types.h @@ -77,22 +77,23 @@ struct ipset_elem { * but for the readability the full list is supported. */ struct ipset_type { - char name[IPSET_MAXNAMELEN]; /* type name */ - uint8_t revision; /* revision number */ - uint8_t family; /* supported family */ - uint8_t dimension; /* elem dimension */ - int8_t kernel_check; /* kernel check */ - bool last_elem_optional; /* last element optional */ - struct ipset_elem elem[IPSET_DIM_MAX]; /* parse elem */ - ipset_parsefn compat_parse_elem; /* compatibility parser */ - const struct ipset_arg *args[IPSET_CADT_MAX]; /* create/ADT args except elem */ - uint64_t mandatory[IPSET_CADT_MAX]; /* create/ADT mandatory flags */ - uint64_t full[IPSET_CADT_MAX]; /* full args flags */ - size_t maxsize[IPSET_MAXSIZE_MAX]; /* max sizes */ - const char *usage; /* terse usage */ + char name[IPSET_MAXNAMELEN]; /* type name */ + uint8_t revision; /* revision number */ + uint8_t family; /* supported family */ + uint8_t dimension; /* elem dimension */ + int8_t kernel_check; /* kernel check */ + bool last_elem_optional; /* last element optional */ + struct ipset_elem elem[IPSET_DIM_MAX]; /* parse elem */ + ipset_parsefn compat_parse_elem; /* compatibility parser */ + const struct ipset_arg *args[IPSET_CADT_MAX]; /* create/ADT args besides elem */ + uint64_t mandatory[IPSET_CADT_MAX]; /* create/ADT mandatory flags */ + uint64_t full[IPSET_CADT_MAX]; /* full args flags */ + size_t maxsize[IPSET_MAXSIZE_MAX]; /* max sizes */ + const char *usage; /* terse usage */ + void (*usagefn)(void); /* additional usage */ struct ipset_type *next; - const char *alias[]; /* name alias(es) */ + const char *alias[]; /* name alias(es) */ }; extern int ipset_cache_add(const char *name, const struct ipset_type *type, diff --git a/include/libipset/ui.h b/include/libipset/ui.h index f8eeae0..b05b737 100644 --- a/include/libipset/ui.h +++ b/include/libipset/ui.h @@ -7,6 +7,8 @@ #ifndef LIBIPSET_UI_H #define LIBIPSET_UI_H +#include <libipset/linux_ip_set.h> /* enum ipset_cmd */ + /* Commands in userspace */ struct ipset_commands { enum ipset_cmd cmd; @@ -37,5 +39,6 @@ extern bool ipset_match_cmd(const char *arg, const char * const name[]); extern bool ipset_match_option(const char *arg, const char * const name[]); extern bool ipset_match_envopt(const char *arg, const char * const name[]); extern void ipset_shift_argv(int *argc, char *argv[], int from); +extern void ipset_port_usage(void); #endif /* LIBIPSET_UI_H */ diff --git a/include/libipset/utils.h b/include/libipset/utils.h index 672bfa9..75efdac 100644 --- a/include/libipset/utils.h +++ b/include/libipset/utils.h @@ -24,6 +24,10 @@ #define UNUSED __attribute__ ((unused)) +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) +#endif + static inline void in4cpy(struct in_addr *dest, const struct in_addr *src) { diff --git a/kernel/Kbuild b/kernel/Kbuild index 9875d70..c496a93 100644 --- a/kernel/Kbuild +++ b/kernel/Kbuild @@ -6,7 +6,7 @@ EXTRA_CFLAGS := -I$(M)/include \ obj-m += ip_set.o xt_set.o obj-m += ip_set_bitmap_ip.o ip_set_bitmap_ipmac.o ip_set_bitmap_port.o obj-m += ip_set_hash_ip.o ip_set_hash_ipport.o ip_set_hash_ipportip.o -obj-m += ip_set_hash_net.o ip_set_hash_ipportnet.o +obj-m += ip_set_hash_net.o ip_set_hash_ipportnet.o ip_set_hash_netport.o obj-m += ip_set_list_set.o # It's for me... diff --git a/kernel/include/linux/netfilter/ip_set.h b/kernel/include/linux/netfilter/ip_set.h index 1c41396..8abf8f8 100644 --- a/kernel/include/linux/netfilter/ip_set.h +++ b/kernel/include/linux/netfilter/ip_set.h @@ -52,7 +52,7 @@ enum { IPSET_ATTR_PROTOCOL, /* 1: Protocol version */ IPSET_ATTR_SETNAME, /* 2: Name of the set */ IPSET_ATTR_TYPENAME, /* 3: Typename */ - IPSET_ATTR_SETNAME2 = IPSET_ATTR_TYPENAME, /* rename/swap */ + IPSET_ATTR_SETNAME2 = IPSET_ATTR_TYPENAME, /* Setname at rename/swap */ IPSET_ATTR_REVISION, /* 4: Settype revision */ IPSET_ATTR_FAMILY, /* 5: Settype family */ IPSET_ATTR_FLAGS, /* 6: Flags at command level */ @@ -77,7 +77,7 @@ enum { IPSET_ATTR_TIMEOUT, /* 6 */ IPSET_ATTR_PROTO, /* 7 */ IPSET_ATTR_CADT_FLAGS, /* 8 */ - IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO, + IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO, /* 9 */ /* Reserve empty slots */ IPSET_ATTR_CADT_MAX = 16, /* Create-only specific attributes */ @@ -108,6 +108,14 @@ enum { }; #define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1) +/* IP specific attributes */ +enum { + IPSET_ATTR_IPADDR_IPV4 = IPSET_ATTR_UNSPEC + 1, + IPSET_ATTR_IPADDR_IPV6, + __IPSET_ATTR_IPADDR_MAX, +}; +#define IPSET_ATTR_IPADDR_MAX (__IPSET_ATTR_IPADDR_MAX - 1) + /* Error codes */ enum ipset_errno { IPSET_ERR_PRIVATE = 128, @@ -123,16 +131,20 @@ enum ipset_errno { IPSET_ERR_INVALID_FAMILY, IPSET_ERR_TIMEOUT, IPSET_ERR_REFERENCED, + IPSET_ERR_IPADDR_IPV4, + IPSET_ERR_IPADDR_IPV6, /* Type specific error codes */ IPSET_ERR_TYPE_SPECIFIC = 160, }; +/* Flags at command level */ enum ipset_cmd_flags { IPSET_FLAG_BIT_EXIST = 0, IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST), }; +/* Flags at CADT attribute level */ enum ipset_cadt_flags { IPSET_FLAG_BIT_BEFORE = 0, IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE), @@ -148,9 +160,6 @@ enum ipset_adt { IPSET_CADT_MAX, }; -#define IPSET_IPPROTO_ANY 255 -#define IPSET_IPPROTO_TCPUDP 254 - #ifdef __KERNEL__ #include <linux/ip.h> #include <linux/ipv6.h> @@ -196,7 +205,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), - /* Actually just a flag for dumping */ + /* Strictly speaking not a feature, but a flag for dumping: + * this settype must be dumped last */ IPSET_DUMP_LAST_FLAG = 7, IPSET_DUMP_LAST = (1 << IPSET_DUMP_LAST_FLAG), }; @@ -223,7 +233,7 @@ struct ip_set_type_variant { int (*uadt)(struct ip_set *set, struct nlattr *head, int len, enum ipset_adt adt, u32 *lineno, u32 flags); - /* Low level add/del/test entries */ + /* Low level add/del/test functions */ ipset_adtfn adt[IPSET_ADT_MAX]; /* When adding entries and set is full, try to resize the set */ @@ -241,7 +251,7 @@ struct ip_set_type_variant { struct netlink_callback *cb); /* Return true if "b" set is the same as "a" - * according to the set parameters */ + * according to the create set parameters */ bool (*same_set)(const struct ip_set *a, const struct ip_set *b); }; @@ -285,7 +295,7 @@ struct ip_set { const struct ip_set_type *type; /* The type variant doing the real job */ const struct ip_set_type_variant *variant; - /* The actual INET family */ + /* The actual INET family of the set */ u8 family; /* The type specific data */ void *data; @@ -340,6 +350,7 @@ ip_set_free(void *members) kfree(members); } +/* Ignore IPSET_ERR_EXIST errors if asked to do so? */ static inline bool ip_set_eexist(int ret, u32 flags) { @@ -379,6 +390,52 @@ ip_set_get_n16(const struct nlattr *attr) return attr->nla_type & NLA_F_NET_BYTEORDER ? value : htons(value); } +static const struct nla_policy +ipaddr_policy[IPSET_ATTR_IPADDR_MAX + 1] __read_mostly = { + [IPSET_ATTR_IPADDR_IPV4] = { .type = NLA_U32 }, + [IPSET_ATTR_IPADDR_IPV6] = { .type = NLA_BINARY, + .len = sizeof(struct in6_addr) }, +}; + +static inline int +ip_set_get_ipaddr4(struct nlattr *attr[], int type, u32 *ipaddr) +{ + struct nlattr *tb[IPSET_ATTR_IPADDR_MAX+1] = {}; + + if (!attr[type]) + return -IPSET_ERR_PROTOCOL; + + if (nla_parse(tb, IPSET_ATTR_IPADDR_MAX, + nla_data(attr[type]), nla_len(attr[type]), + ipaddr_policy)) + return -IPSET_ERR_PROTOCOL; + if (!tb[IPSET_ATTR_IPADDR_IPV4]) + return -IPSET_ERR_IPADDR_IPV4; + + *ipaddr = ip_set_get_n32(tb[IPSET_ATTR_IPADDR_IPV4]); + return 0; +} + +static inline int +ip_set_get_ipaddr6(struct nlattr *attr[], int type, union nf_inet_addr *ipaddr) +{ + struct nlattr *tb[IPSET_ATTR_IPADDR_MAX+1] = {}; + + if (!attr[type]) + return -IPSET_ERR_PROTOCOL; + + if (nla_parse(tb, IPSET_ATTR_IPADDR_MAX, + nla_data(attr[type]), nla_len(attr[type]), + ipaddr_policy)) + return -IPSET_ERR_PROTOCOL; + if (!tb[IPSET_ATTR_IPADDR_IPV6]) + return -IPSET_ERR_IPADDR_IPV6; + + memcpy(ipaddr, nla_data(tb[IPSET_ATTR_IPADDR_IPV6]), + sizeof(struct in6_addr)); + return 0; +} + #define ipset_nest_start(skb, attr) nla_nest_start(skb, attr | NLA_F_NESTED) #define ipset_nest_end(skb, start) nla_nest_end(skb, start) @@ -388,6 +445,27 @@ ip_set_get_n16(const struct nlattr *attr) #define NLA_PUT_NET16(skb, type, value) \ NLA_PUT_BE16(skb, type | NLA_F_NET_BYTEORDER, value) +#define NLA_PUT_IPADDR4(skb, type, ipaddr) \ +do { \ + struct nlattr *__nested = ipset_nest_start(skb, type); \ + \ + if (!__nested) \ + goto nla_put_failure; \ + NLA_PUT_NET32(skb, IPSET_ATTR_IPADDR_IPV4, ipaddr); \ + ipset_nest_end(skb, __nested); \ +} while (0) + +#define NLA_PUT_IPADDR6(skb, type, ipaddrptr) \ +do { \ + struct nlattr *__nested = ipset_nest_start(skb, type); \ + \ + if (!__nested) \ + goto nla_put_failure; \ + NLA_PUT(skb, IPSET_ATTR_IPADDR_IPV6, \ + sizeof(struct in6_addr), ipaddrptr); \ + ipset_nest_end(skb, __nested); \ +} while (0) + /* Get address from skbuff */ static inline u32 ip4addr(const struct sk_buff *skb, bool src) diff --git a/kernel/include/linux/netfilter/ip_set_bitmap.h b/kernel/include/linux/netfilter/ip_set_bitmap.h index 0d067d0..f3bff2c 100644 --- a/kernel/include/linux/netfilter/ip_set_bitmap.h +++ b/kernel/include/linux/netfilter/ip_set_bitmap.h @@ -3,7 +3,9 @@ /* Bitmap type specific error codes */ enum { + /* The element is out of the range of the set */ IPSET_ERR_BITMAP_RANGE = IPSET_ERR_TYPE_SPECIFIC, + /* The range exceeds the size limit of the set type */ IPSET_ERR_BITMAP_RANGE_SIZE, }; diff --git a/kernel/include/linux/netfilter/ip_set_chash.h b/kernel/include/linux/netfilter/ip_set_chash.h index 5e615e4..6fd1d32 100644 --- a/kernel/include/linux/netfilter/ip_set_chash.h +++ b/kernel/include/linux/netfilter/ip_set_chash.h @@ -5,13 +5,11 @@ #include <linux/netfilter/ip_set_slist.h> #include <linux/netfilter/ip_set_timeout.h> -#define CONCAT(a, b, c) a##b##c -#define TOKEN(a, b, c) CONCAT(a, b, c) - -/* Cache friendly hash with resizing when linear searching becomes too long. - * Internally jhash is used with the assumption that the size of the stored - * data is a multiple of sizeof(u32). If storage supports timeout, the - * timeout field must be the last one in the data structure. +/* Cacheline friendly hash with resizing when linear searching becomes too + * long. Internally jhash is used with the assumption that the size of the + * stored data is a multiple of sizeof(u32). If storage supports timeout, + * the timeout field must be the last one in the data structure - that field + * is ignored when computing the hash key. */ /* Number of elements to store in an array block */ @@ -19,9 +17,10 @@ /* Number of arrays: max ARRAY_SIZE * CHAIN_LIMIT "long" chains */ #define CHASH_DEFAULT_CHAIN_LIMIT 3 +/* Book-keeping of the prefixes added to the set */ struct chash_nets { + u8 cidr; /* the different cidr values in the set */ u32 nets; /* number of elements per cidr */ - u8 cidr; /* the cidr values added to the set */ }; struct chash { @@ -37,14 +36,12 @@ struct chash { #ifdef IP_SET_HASH_WITH_NETMASK u8 netmask; /* netmask value for subnets to store */ #endif -#ifdef IP_SET_HASH_WITH_PROTO - u8 proto; /* default protocol for SET target */ -#endif #ifdef IP_SET_HASH_WITH_NETS - struct chash_nets nets[0]; /* book keeping of networks */ + struct chash_nets nets[0]; /* book-keeping of prefixes */ #endif }; +/* Compute htable_bits from the user input parameter hashsize */ static inline u8 htable_bits(u32 hashsize) { @@ -57,34 +54,56 @@ htable_bits(u32 hashsize) return bits; } +#ifdef IP_SET_HASH_WITH_NETS + +#define SET_HOST_MASK(family) (family == AF_INET ? 32 : 128) + +/* Network cidr size book keeping when the hash stores different + * sized networks */ static inline void -add_cidr(struct chash_nets *nets, u8 host_mask, u8 cidr) +add_cidr(struct chash *h, u8 cidr, u8 host_mask) { u8 i; - pr_debug("add_cidr %u", cidr); - for (i = 0; i < host_mask - 1 && nets[i].cidr; i++) { + ++h->nets[cidr-1].nets; + + pr_debug("add_cidr added %u: %u", cidr, h->nets[cidr-1].nets); + + if (h->nets[cidr-1].nets > 1) + return; + + /* New cidr size */ + for (i = 0; i < host_mask && h->nets[i].cidr; i++) { /* Add in increasing prefix order, so larger cidr first */ - if (nets[i].cidr < cidr) - swap(nets[i].cidr, cidr); + if (h->nets[i].cidr < cidr) + swap(h->nets[i].cidr, cidr); } - if (i < host_mask - 1) - nets[i].cidr = cidr; + if (i < host_mask) + h->nets[i].cidr = cidr; } static inline void -del_cidr(struct chash_nets *nets, u8 host_mask, u8 cidr) +del_cidr(struct chash *h, u8 cidr, u8 host_mask) { u8 i; - pr_debug("del_cidr %u", cidr); - for (i = 0; i < host_mask - 2 && nets[i].cidr; i++) { - if (nets[i].cidr == cidr) - nets[i].cidr = cidr = nets[i+1].cidr; + --h->nets[cidr-1].nets; + + pr_debug("del_cidr deleted %u: %u", cidr, h->nets[cidr-1].nets); + + if (h->nets[cidr-1].nets != 0) + return; + + /* All entries with this cidr size deleted, so cleanup h->cidr[] */ + for (i = 0; i < host_mask - 1 && h->nets[i].cidr; i++) { + if (h->nets[i].cidr == cidr) + h->nets[i].cidr = cidr = h->nets[i+1].cidr; } - nets[host_mask - 2].cidr = 0; + h->nets[i - 1].cidr = 0; } +#endif +/* Destroy the hashtable part of the set */ static void chash_destroy(struct slist *t, u8 htable_bits) { @@ -93,12 +112,13 @@ chash_destroy(struct slist *t, u8 htable_bits) for (i = 0; i < jhash_size(htable_bits); i++) slist_for_each_safe(n, tmp, &t[i]) - /* FIXME: slab cache */ + /* FIXME: use slab cache */ kfree(n); ip_set_free(t); } +/* Calculate the actual memory size of the set data */ static size_t chash_memsize(const struct chash *h, size_t dsize, u8 host_mask) { @@ -106,7 +126,7 @@ chash_memsize(const struct chash *h, size_t dsize, u8 host_mask) u32 i; size_t memsize = sizeof(*h) #ifdef IP_SET_HASH_WITH_NETS - + sizeof(struct chash_nets) * (host_mask - 1) + + sizeof(struct chash_nets) * host_mask #endif + jhash_size(h->htable_bits) * sizeof(struct slist); @@ -118,6 +138,7 @@ chash_memsize(const struct chash *h, size_t dsize, u8 host_mask) return memsize; } +/* Flush a hash type of set: destroy all elements */ static void ip_set_hash_flush(struct ip_set *set) { @@ -133,11 +154,12 @@ ip_set_hash_flush(struct ip_set *set) } #ifdef IP_SET_HASH_WITH_NETS memset(h->nets, 0, sizeof(struct chash_nets) - * (set->family == AF_INET ? 31 : 127)); + * SET_HOST_MASK(set->family)); #endif h->elements = 0; } +/* Destroy a hash type of set */ static void ip_set_hash_destroy(struct ip_set *set) { @@ -152,12 +174,15 @@ ip_set_hash_destroy(struct ip_set *set) set->data = NULL; } -#define JHASH2(data, initval, htable_bits) \ -jhash2((u32 *)(data), sizeof(struct type_pf_elem)/sizeof(u32), initval) \ - & jhash_mask(htable_bits) +#define JHASH2(data, initval, htable_bits) \ +(jhash2((u32 *)(data), sizeof(struct type_pf_elem)/sizeof(u32), initval) \ + & jhash_mask(htable_bits)) #endif /* _IP_SET_CHASH_H */ +#define CONCAT(a, b, c) a##b##c +#define TOKEN(a, b, c) CONCAT(a, b, c) + /* Type/family dependent function prototypes */ #define type_pf_data_equal TOKEN(TYPE, PF, _data_equal) @@ -208,10 +233,13 @@ jhash2((u32 *)(data), sizeof(struct type_pf_elem)/sizeof(u32), initval) \ /* Flavour without timeout */ +/* Get the ith element from the array block n */ #define chash_data(n, i) \ (struct type_pf_elem *)((char *)(n) + sizeof(struct slist) \ + (i)*sizeof(struct type_pf_elem)) +/* Add an element to the hash table when resizing the set: + * we spare the maintenance of the internal counters. */ static int type_pf_chash_readd(struct chash *h, struct slist *t, u8 htable_bits, const struct type_pf_elem *value, gfp_t gfp_flags) @@ -240,7 +268,7 @@ type_pf_chash_readd(struct chash *h, struct slist *t, u8 htable_bits, prev->next = (struct slist *) tmp; data = chash_data(tmp, 0); } else { - /* Rehashing */ + /* Trigger rehashing */ return -EAGAIN; } found: @@ -248,13 +276,16 @@ found: return 0; } +/* Delete an element from the hash table: swap it with the last + * element in the hash bucket and free up the array if it was + * completely emptied */ static void type_pf_chash_del_elem(struct chash *h, struct slist *prev, struct slist *n, int i) { struct type_pf_elem *data = chash_data(n, i); struct slist *tmp; - int j; + int j; /* Index in array */ if (n->next != NULL) { for (prev = n, tmp = n->next; @@ -276,8 +307,7 @@ type_pf_chash_del_elem(struct chash *h, struct slist *prev, type_pf_data_swap(data, chash_data(tmp, j)); } #ifdef IP_SET_HASH_WITH_NETS - if (--h->nets[data->cidr-1].nets == 0) - del_cidr(h->nets, HOST_MASK, data->cidr); + del_cidr(h, data->cidr, HOST_MASK); #endif if (j == 0) { prev->next = NULL; @@ -288,6 +318,9 @@ type_pf_chash_del_elem(struct chash *h, struct slist *prev, h->elements--; } +/* Resize a hash: create a new hash table with doubling the hashsize + * and inserting the elements to it. Repeat until we succeed or + * fail due to memory pressures. */ static int type_pf_resize(struct ip_set *set, gfp_t gfp_flags, bool retried) { @@ -299,7 +332,7 @@ type_pf_resize(struct ip_set *set, gfp_t gfp_flags, bool retried) int ret; retry: - ret = 0; + ret = i = 0; htable_bits++; if (!htable_bits) /* In case we have plenty of memory :-) */ @@ -310,8 +343,8 @@ retry: return -ENOMEM; write_lock_bh(&set->lock); - for (i = 0; i < jhash_size(h->htable_bits); i++) { next_slot: + for (; i < jhash_size(h->htable_bits); i++) { slist_for_each(n, &h->htable[i]) { for (j = 0; j < h->array_size; j++) { data = chash_data(n, j); @@ -344,6 +377,8 @@ next_slot: return 0; } +/* Add an element to a hash and update the internal counters when succeeded, + * otherwise report the proper error code. */ static int type_pf_chash_add(struct ip_set *set, void *value, gfp_t gfp_flags, u32 timeout) @@ -356,11 +391,7 @@ type_pf_chash_add(struct ip_set *set, void *value, int i = 0, j = 0; u32 hash; -#ifdef IP_SET_HASH_WITH_NETS - if (h->elements >= h->maxelem || h->nets[d->cidr-1].nets == UINT_MAX) -#else if (h->elements >= h->maxelem) -#endif return -IPSET_ERR_HASH_FULL; hash = JHASH2(value, h->initval, h->htable_bits); @@ -390,13 +421,13 @@ type_pf_chash_add(struct ip_set *set, void *value, found: type_pf_data_copy(data, d); #ifdef IP_SET_HASH_WITH_NETS - if (h->nets[d->cidr-1].nets++ == 0) - add_cidr(h->nets, HOST_MASK, d->cidr); + add_cidr(h, d->cidr, HOST_MASK); #endif h->elements++; return 0; } +/* Delete an element from the hash */ static int type_pf_chash_del(struct ip_set *set, void *value, gfp_t gfp_flags, u32 timeout) @@ -423,6 +454,9 @@ type_pf_chash_del(struct ip_set *set, void *value, } #ifdef IP_SET_HASH_WITH_NETS + +/* Special test function which takes into account the different network + * sizes added to the set */ static inline int type_pf_chash_test_cidrs(struct ip_set *set, struct type_pf_elem *d, @@ -433,11 +467,11 @@ type_pf_chash_test_cidrs(struct ip_set *set, const struct type_pf_elem *data; int i, j = 0; u32 hash; - u8 host_mask = set->family == AF_INET ? 32 : 128; + u8 host_mask = SET_HOST_MASK(set->family); retry: pr_debug("test by nets"); - for (; j < host_mask - 1 && h->nets[j].cidr; j++) { + for (; j < host_mask && h->nets[j].cidr; j++) { type_pf_data_netmask(d, h->nets[j].cidr); hash = JHASH2(d, h->initval, h->htable_bits); slist_for_each(n, &h->htable[hash]) @@ -455,6 +489,7 @@ retry: } #endif +/* Test whether the element is added to the set */ static inline int type_pf_chash_test(struct ip_set *set, void *value, gfp_t gfp_flags, u32 timeout) @@ -465,10 +500,11 @@ type_pf_chash_test(struct ip_set *set, void *value, const struct type_pf_elem *data; int i; u32 hash; -#ifdef IP_SET_HASH_WITH_NETS - u8 host_mask = set->family == AF_INET ? 32 : 128; - if (d->cidr == host_mask) +#ifdef IP_SET_HASH_WITH_NETS + /* If we test an IP address and not a network address, + * try all possible network sizes */ + if (d->cidr == SET_HOST_MASK(set->family)) return type_pf_chash_test_cidrs(set, d, gfp_flags, timeout); #endif @@ -484,6 +520,7 @@ type_pf_chash_test(struct ip_set *set, void *value, return 0; } +/* Reply a HEADER request: fill out the header part of the set */ static int type_pf_head(struct ip_set *set, struct sk_buff *skb) { @@ -508,10 +545,6 @@ type_pf_head(struct ip_set *set, struct sk_buff *skb) if (h->netmask != HOST_MASK) NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, h->netmask); #endif -#ifdef IP_SET_HASH_WITH_PROTO - if (h->proto != IPSET_IPPROTO_TCPUDP) - NLA_PUT_U8(skb, IPSET_ATTR_PROTO, h->proto); -#endif NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(atomic_read(&set->ref) - 1)); NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)); @@ -524,6 +557,7 @@ nla_put_failure: return -EFAULT; } +/* Reply a LIST/SAVE request: dump the elements of the specified set */ static int type_pf_list(struct ip_set *set, struct sk_buff *skb, struct netlink_callback *cb) @@ -599,7 +633,8 @@ static const struct ip_set_type_variant type_pf_variant __read_mostly = { /* Flavour with timeout support */ #define chash_tdata(n, i) \ -(struct type_pf_elem *)((char *)(n) + sizeof(struct slist) + (i)*sizeof(struct type_pf_telem)) +(struct type_pf_elem *)((char *)(n) + sizeof(struct slist) \ + + (i)*sizeof(struct type_pf_telem)) static inline u32 type_pf_data_timeout(const struct type_pf_elem *data) @@ -666,7 +701,7 @@ type_pf_chash_treadd(struct chash *h, struct slist *t, u8 htable_bits, prev->next = (struct slist *) tmp; data = chash_tdata(tmp, 0); } else { - /* Rehashing */ + /* Trigger rehashing */ return -EAGAIN; } found: @@ -681,7 +716,7 @@ type_pf_chash_del_telem(struct chash *h, struct slist *prev, { struct type_pf_elem *d, *data = chash_tdata(n, i); struct slist *tmp; - int j; + int j; /* Index in array */ pr_debug("del %u", i); if (n->next != NULL) { @@ -706,8 +741,7 @@ type_pf_chash_del_telem(struct chash *h, struct slist *prev, type_pf_data_swap_timeout(data, d); } #ifdef IP_SET_HASH_WITH_NETS - if (--h->nets[data->cidr-1].nets == 0) - del_cidr(h->nets, HOST_MASK, data->cidr); + del_cidr(h, data->cidr, HOST_MASK); #endif if (j == 0) { prev->next = NULL; @@ -718,6 +752,7 @@ type_pf_chash_del_telem(struct chash *h, struct slist *prev, h->elements--; } +/* Delete expired elements from the hashtable */ static void type_pf_chash_expire(struct chash *h) { @@ -760,7 +795,7 @@ type_pf_tresize(struct ip_set *set, gfp_t gfp_flags, bool retried) } retry: - ret = 0; + ret = i = 0; htable_bits++; if (!htable_bits) /* In case we have plenty of memory :-) */ @@ -771,8 +806,8 @@ retry: return -ENOMEM; write_lock_bh(&set->lock); - for (i = 0; i < jhash_size(h->htable_bits); i++) { next_slot: + for (; i < jhash_size(h->htable_bits); i++) { slist_for_each(n, &h->htable[i]) { for (j = 0; j < h->array_size; j++) { data = chash_tdata(n, j); @@ -781,8 +816,8 @@ next_slot: goto next_slot; } ret = type_pf_chash_treadd(h, t, htable_bits, - data, gfp_flags, - type_pf_data_timeout(data)); + data, gfp_flags, + type_pf_data_timeout(data)); if (ret < 0) { write_unlock_bh(&set->lock); chash_destroy(t, htable_bits); @@ -821,11 +856,7 @@ type_pf_chash_tadd(struct ip_set *set, void *value, if (h->elements >= h->maxelem) /* FIXME: when set is full, we slow down here */ type_pf_chash_expire(h); -#ifdef IP_SET_HASH_WITH_NETS - if (h->elements >= h->maxelem || h->nets[d->cidr-1].nets == UINT_MAX) -#else if (h->elements >= h->maxelem) -#endif return -IPSET_ERR_HASH_FULL; hash = JHASH2(d, h->initval, h->htable_bits); @@ -854,17 +885,14 @@ type_pf_chash_tadd(struct ip_set *set, void *value, return -EAGAIN; } found: - if (type_pf_data_isnull(data)) { + if (type_pf_data_isnull(data)) h->elements++; #ifdef IP_SET_HASH_WITH_NETS - } else { - if (--h->nets[data->cidr-1].nets == 0) - del_cidr(h->nets, HOST_MASK, data->cidr); - } - if (h->nets[d->cidr-1].nets++ == 0) { - add_cidr(h->nets, HOST_MASK, d->cidr); + else + del_cidr(h, data->cidr, HOST_MASK); + + add_cidr(h, d->cidr, HOST_MASK); #endif - } type_pf_data_copy(data, d); type_pf_data_timeout_set(data, timeout); return 0; @@ -908,10 +936,10 @@ type_pf_chash_ttest_cidrs(struct ip_set *set, struct slist *n; int i, j = 0; u32 hash; - u8 host_mask = set->family == AF_INET ? 32 : 128; + u8 host_mask = SET_HOST_MASK(set->family); retry: - for (; j < host_mask - 1 && h->nets[j].cidr; j++) { + for (; j < host_mask && h->nets[j].cidr; j++) { type_pf_data_netmask(d, h->nets[j].cidr); hash = JHASH2(d, h->initval, h->htable_bits); slist_for_each(n, &h->htable[hash]) @@ -938,10 +966,9 @@ type_pf_chash_ttest(struct ip_set *set, void *value, struct slist *n; int i; u32 hash; -#ifdef IP_SET_HASH_WITH_NETS - u8 host_mask = set->family == AF_INET ? 32 : 128; - if (d->cidr == host_mask) +#ifdef IP_SET_HASH_WITH_NETS + if (d->cidr == SET_HOST_MASK(set->family)) return type_pf_chash_ttest_cidrs(set, d, gfp_flags, timeout); #endif @@ -1048,7 +1075,8 @@ type_pf_gc_init(struct ip_set *set) h->gc.function = type_pf_gc; h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ; add_timer(&h->gc); - pr_debug("gc initialized, run in every %u", IPSET_GC_PERIOD(h->timeout)); + pr_debug("gc initialized, run in every %u", + IPSET_GC_PERIOD(h->timeout)); } #undef type_pf_data_equal diff --git a/kernel/include/linux/netfilter/ip_set_getport.h b/kernel/include/linux/netfilter/ip_set_getport.h index cf150d3..e4d469d 100644 --- a/kernel/include/linux/netfilter/ip_set_getport.h +++ b/kernel/include/linux/netfilter/ip_set_getport.h @@ -2,13 +2,14 @@ #define _IP_SET_GETPORT_H #ifdef __KERNEL__ +#include <linux/icmp.h> +#include <linux/icmpv6.h> #include <linux/netfilter_ipv6/ip6_tables.h> #include <net/ip.h> #define IPSET_INVALID_PORT 65536 /* We must handle non-linear skbs */ - static inline bool get_port(const struct sk_buff *skb, int protocol, unsigned int protooff, bool src, u16 *port, u8 *proto) @@ -38,13 +39,32 @@ get_port(const struct sk_buff *skb, int protocol, unsigned int protooff, *port = src ? uh->source : uh->dest; break; } - default: - if (*proto == IPSET_IPPROTO_TCPUDP) + case IPPROTO_ICMP: { + struct icmphdr _icmph; + const struct icmphdr *ic; + + ic = skb_header_pointer(skb, protooff, sizeof(_icmph), &_icmph); + if (ic == NULL) + return false; + + *port = (ic->type << 8) & ic->code; + break; + } + case IPPROTO_ICMPV6: { + struct icmp6hdr _icmph; + const struct icmp6hdr *ic; + + ic = skb_header_pointer(skb, protooff, sizeof(_icmph), &_icmph); + if (ic == NULL) return false; + + *port = (ic->icmp6_type << 8) & ic->icmp6_code; + break; + } + default: break; } - if (*proto != IPSET_IPPROTO_TCPUDP) - *proto = protocol; + *proto = protocol; return true; } @@ -56,9 +76,6 @@ get_ip4_port(const struct sk_buff *skb, bool src, u16 *port, u8 *proto) unsigned int protooff = ip_hdrlen(skb); int protocol = iph->protocol; - if (!(*proto >= IPSET_IPPROTO_TCPUDP || *proto == protocol)) - return false; - /* See comments at tcp_match in ip_tables.c */ if (ntohs(iph->frag_off) & IP_OFFSET) return false; @@ -77,21 +94,32 @@ get_ip6_port(const struct sk_buff *skb, bool src, u16 *port, u8 *proto) if (protocol < 0 || fragoff) return false; - if (!(*proto >= IPSET_IPPROTO_TCPUDP || *proto == protocol)) - return false; - return get_port(skb, protocol, protooff, src, port, proto); } static inline bool get_ip_port(const struct sk_buff *skb, u8 pf, bool src, u16 *port) { - u8 proto = IPSET_IPPROTO_TCPUDP; - - if (pf == AF_INET) - return get_ip4_port(skb, src, port, &proto); - else - return get_ip6_port(skb, src, port, &proto); + bool ret; + u8 proto; + + switch (pf) { + case AF_INET: + ret = get_ip4_port(skb, src, port, &proto); + case AF_INET6: + ret = get_ip6_port(skb, src, port, &proto); + default: + return false; + } + if (!ret) + return ret; + switch (proto) { + case IPPROTO_TCP: + case IPPROTO_UDP: + return true; + default: + return false; + } } #endif /* __KERNEL__ */ diff --git a/kernel/include/linux/netfilter/ip_set_hash.h b/kernel/include/linux/netfilter/ip_set_hash.h index 4003af0..e149a2b 100644 --- a/kernel/include/linux/netfilter/ip_set_hash.h +++ b/kernel/include/linux/netfilter/ip_set_hash.h @@ -1,11 +1,15 @@ #ifndef __IP_SET_HASH_H #define __IP_SET_HASH_H -/* Bitmap type specific error codes */ +/* Hash type specific error codes */ enum { + /* Hash is full */ IPSET_ERR_HASH_FULL = IPSET_ERR_TYPE_SPECIFIC, + /* Null-valued element */ IPSET_ERR_HASH_ELEM, + /* Invalid protocol */ IPSET_ERR_INVALID_PROTO, + /* Protocol missing but must be specified */ IPSET_ERR_MISSING_PROTO, }; diff --git a/kernel/include/linux/netfilter/ip_set_kernel.h b/kernel/include/linux/netfilter/ip_set_kernel.h index 0f04217..d770589 100644 --- a/kernel/include/linux/netfilter/ip_set_kernel.h +++ b/kernel/include/linux/netfilter/ip_set_kernel.h @@ -1,13 +1,6 @@ #ifndef _IP_SET_KERNEL_H #define _IP_SET_KERNEL_H -/* Copyright (C) 2003-2010 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. - */ - #ifdef __KERNEL__ #ifdef CONFIG_DEBUG_KERNEL diff --git a/kernel/include/linux/netfilter/ip_set_list.h b/kernel/include/linux/netfilter/ip_set_list.h index c40643e..9988570 100644 --- a/kernel/include/linux/netfilter/ip_set_list.h +++ b/kernel/include/linux/netfilter/ip_set_list.h @@ -3,11 +3,17 @@ /* List type specific error codes */ enum { + /* Set name to be added/deleted/tested does not exist. */ IPSET_ERR_NAME = IPSET_ERR_TYPE_SPECIFIC, + /* list:set type is not permitted to add */ IPSET_ERR_LOOP, + /* Missing reference set */ IPSET_ERR_BEFORE, + /* Reference set does not exist */ IPSET_ERR_NAMEREF, + /* Set is full */ IPSET_ERR_LIST_FULL, + /* Reference set is not added to the set */ IPSET_ERR_REF_EXIST, }; diff --git a/kernel/include/linux/netfilter/ip_set_slist.h b/kernel/include/linux/netfilter/ip_set_slist.h index abc5afe..3e8d8b0 100644 --- a/kernel/include/linux/netfilter/ip_set_slist.h +++ b/kernel/include/linux/netfilter/ip_set_slist.h @@ -25,7 +25,8 @@ struct slist { pos = pos->next) #define slist_for_each_prev(prev, pos, head) \ - for (prev = head, pos = (head)->next; pos && ({ prefetch(pos->next); 1; }); \ + for (prev = head, pos = (head)->next; \ + pos && ({ prefetch(pos->next); 1; }); \ prev = pos, pos = pos->next) #define slist_for_each_safe(pos, n, head) \ @@ -46,7 +47,8 @@ struct slist { pos = pos->next) /** - * slist_for_each_entry_continue - iterate over a hlist continuing after current point + * slist_for_each_entry_continue - iterate over a hlist continuing + * after current point * @tpos: the type * to use as a loop cursor. * @pos: the &struct slist to use as a loop cursor. * @member: the name of the slist within the struct. @@ -58,7 +60,8 @@ struct slist { pos = pos->next) /** - * slist_for_each_entry_from - iterate over a hlist continuing from current point + * slist_for_each_entry_from - iterate over a hlist continuing + * from current point * @tpos: the type * to use as a loop cursor. * @pos: the &struct slist to use as a loop cursor. * @member: the name of the slist within the struct. diff --git a/kernel/include/linux/netfilter/ip_set_timeout.h b/kernel/include/linux/netfilter/ip_set_timeout.h index bf1cbf6..b917480 100644 --- a/kernel/include/linux/netfilter/ip_set_timeout.h +++ b/kernel/include/linux/netfilter/ip_set_timeout.h @@ -17,7 +17,7 @@ #define IPSET_GC_PERIOD(timeout) \ ((timeout/3) ? min_t(u32, (timeout)/3, IPSET_GC_TIME) : 1) -/* Set is defined without timeout support */ +/* Set is defined without timeout support: timeout value may be 0 */ #define IPSET_NO_TIMEOUT UINT_MAX #define with_timeout(timeout) ((timeout) != IPSET_NO_TIMEOUT) @@ -27,11 +27,14 @@ ip_set_timeout_uget(struct nlattr *tb) { unsigned int timeout = ip_set_get_h32(tb); + /* Userspace supplied TIMEOUT parameter: adjust crazy size */ return timeout == IPSET_NO_TIMEOUT ? IPSET_NO_TIMEOUT - 1 : timeout; } #ifdef IP_SET_BITMAP_TIMEOUT +/* Bitmap specific timeout constants and macros for the entries */ + /* Bitmap entry is unset */ #define IPSET_ELEM_UNSET 0 /* Bitmap entry is set with no timeout value */ @@ -63,6 +66,7 @@ ip_set_timeout_set(u32 timeout) t = timeout * HZ + jiffies; if (t == IPSET_ELEM_UNSET || t == IPSET_ELEM_PERMANENT) + /* Bingo! */ t++; return t; @@ -76,19 +80,23 @@ ip_set_timeout_get(unsigned long timeout) #else +/* Hash specific timeout constants and macros for the entries */ + /* Hash entry is set with no timeout value */ -#define IPSET_ELEM_UNSET 0 +#define IPSET_ELEM_PERMANENT 0 static inline bool ip_set_timeout_test(unsigned long timeout) { - return timeout == IPSET_ELEM_UNSET || time_after(timeout, jiffies); + return timeout == IPSET_ELEM_PERMANENT + || time_after(timeout, jiffies); } static inline bool ip_set_timeout_expired(unsigned long timeout) { - return timeout != IPSET_ELEM_UNSET && time_before(timeout, jiffies); + return timeout != IPSET_ELEM_PERMANENT + && time_before(timeout, jiffies); } static inline unsigned long @@ -97,10 +105,11 @@ ip_set_timeout_set(u32 timeout) unsigned long t; if (!timeout) - return IPSET_ELEM_UNSET; + return IPSET_ELEM_PERMANENT; t = timeout * HZ + jiffies; - if (t == IPSET_ELEM_UNSET) + if (t == IPSET_ELEM_PERMANENT) + /* Bingo! :-) */ t++; return t; @@ -109,10 +118,10 @@ ip_set_timeout_set(u32 timeout) static inline u32 ip_set_timeout_get(unsigned long timeout) { - return timeout == IPSET_ELEM_UNSET ? 0 : (timeout - jiffies)/HZ; + return timeout == IPSET_ELEM_PERMANENT ? 0 : (timeout - jiffies)/HZ; } -#endif /* IP_SET_BITMAP_TIMEOUT */ +#endif /* ! IP_SET_BITMAP_TIMEOUT */ #endif /* __KERNEL__ */ -#endif /*_IP_SET_TIMEOUT_H */ +#endif /* _IP_SET_TIMEOUT_H */ diff --git a/kernel/ip_set.c b/kernel/ip_set.c index 74b2e91..a1813e2 100644 --- a/kernel/ip_set.c +++ b/kernel/ip_set.c @@ -91,8 +91,9 @@ find_set_type_rcu(const char *name, u8 family, u8 revision) return type; } -/* Find a given set type by name and family together - * with the supported minimal and maximum revisions. +/* Find a given set type by name and family. + * If we succeeded, the supported minimal and maximum revisions are + * filled out. */ static bool find_set_type_minmax(const char *name, u8 family, @@ -224,7 +225,7 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb, read_unlock_bh(&set->lock); if (ret == -EAGAIN) { - /* Type requests element to be re-added */ + /* Type requests element to be completed */ pr_debug("element must be competed, ADD is triggered"); write_lock_bh(&set->lock); set->variant->kadt(set, skb, IPSET_ADD, family, dim, flags); @@ -842,9 +843,10 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb, /* List/save set data */ -#define DUMP_ALL 0L -#define DUMP_ONE 1L -#define DUMP_LAST 2L +#define DUMP_INIT 0L +#define DUMP_ALL 1L +#define DUMP_ONE 2L +#define DUMP_LAST 3L static int ip_set_dump_done(struct netlink_callback *cb) @@ -868,6 +870,38 @@ dump_attrs(struct nlmsghdr *nlh) } } +static inline int +dump_init(struct netlink_callback *cb) +{ + struct nlmsghdr *nlh = nlmsg_hdr(cb->skb); + int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); + struct nlattr *cda[IPSET_ATTR_CMD_MAX+1]; + struct nlattr *attr = (void *)nlh + min_len; + ip_set_id_t index; + + /* Second pass, so parser can't fail */ + nla_parse(cda, IPSET_ATTR_CMD_MAX, + attr, nlh->nlmsg_len - min_len, ip_set_setname_policy); + + /* cb->args[0] : dump single set/all sets + * [1] : set index + * [..]: type specific + */ + + if (!cda[IPSET_ATTR_SETNAME]) { + cb->args[0] = DUMP_ALL; + return 0; + } + + index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME])); + if (index == IPSET_INVALID_ID) + return -EEXIST; + + cb->args[0] = DUMP_ONE; + cb->args[1] = index; + return 0; +} + static int ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) { @@ -877,6 +911,16 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) unsigned int flags = NETLINK_CB(cb->skb).pid ? NLM_F_MULTI : 0; int ret = 0; + if (cb->args[0] == DUMP_INIT) { + ret = dump_init(cb); + if (ret < 0) { + /* We have to create and send the error message + * manually :-( */ + netlink_ack(cb->skb, nlmsg_hdr(cb->skb), ret); + return ret; + } + } + if (cb->args[1] >= ip_set_max) goto out; @@ -971,28 +1015,12 @@ ip_set_dump(struct sock *ctnl, struct sk_buff *skb, NFNL_CB_CONST struct nlmsghdr *nlh, NFNL_CB_CONST struct nlattr * NFNL_CB_CONST attr[]) { - ip_set_id_t index; - if (unlikely(protocol_failed(attr))) return -IPSET_ERR_PROTOCOL; - if (!attr[IPSET_ATTR_SETNAME]) - return netlink_dump_start(ctnl, skb, nlh, - ip_set_dump_start, - ip_set_dump_done); - - index = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); - if (index == IPSET_INVALID_ID) - return -EEXIST; - - /* cb->args[0] : dump single set/all sets - * [1] : set index - * [..]: type specific - */ - return netlink_dump_init(ctnl, skb, nlh, - ip_set_dump_start, - ip_set_dump_done, - 2, DUMP_ONE, index); + return netlink_dump_start(ctnl, skb, nlh, + ip_set_dump_start, + ip_set_dump_done); } /* Add, del and test */ @@ -1025,7 +1053,8 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, write_unlock_bh(&set->lock); } while (ret == -EAGAIN && set->variant->resize - && (ret = set->variant->resize(set, GFP_KERNEL, retried++)) == 0); + && (ret = set->variant->resize(set, GFP_ATOMIC, + retried++)) == 0); if (!ret || (ret == -IPSET_ERR_EXIST && eexist)) return 0; @@ -1240,7 +1269,8 @@ ip_set_type(struct sock *ctnl, struct sk_buff *skb, /* Try to load in the type module */ load_type_module(typename); if (!find_set_type_minmax(typename, family, &min, &max)) { - pr_debug("can't find: %s, family: %u", typename, family); + pr_debug("can't find: %s, family: %u", + typename, family); return -EEXIST; } } @@ -1503,7 +1533,8 @@ ip_set_init(void) if (ip_set_max >= IPSET_INVALID_ID) ip_set_max = IPSET_INVALID_ID - 1; - ip_set_list = kzalloc(sizeof(struct ip_set *) * ip_set_max, GFP_KERNEL); + ip_set_list = kzalloc(sizeof(struct ip_set *) * ip_set_max, + GFP_KERNEL); if (!ip_set_list) { pr_err("ip_set: Unable to create ip_set_list"); return -ENOMEM; diff --git a/kernel/ip_set_bitmap_ip.c b/kernel/ip_set_bitmap_ip.c index 76baa13..5bb6a3c 100644 --- a/kernel/ip_set_bitmap_ip.c +++ b/kernel/ip_set_bitmap_ip.c @@ -103,8 +103,8 @@ bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb, static const struct nla_policy bitmap_ip_adt_policy[IPSET_ATTR_ADT_MAX+1] __read_mostly = { - [IPSET_ATTR_IP] = { .type = NLA_U32 }, - [IPSET_ATTR_IP_TO] = { .type = NLA_U32 }, + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, + [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, @@ -126,16 +126,16 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len, if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); - if (tb[IPSET_ATTR_IP]) - ip = ip_set_get_h32(tb[IPSET_ATTR_IP]); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &ip); + if (ret) + return ret; + ip = ntohl(ip); if (ip < map->first_ip || ip > map->last_ip) return -IPSET_ERR_BITMAP_RANGE; - /* Set was defined without timeout support, - * don't ignore attribute silently */ + /* Set was defined without timeout support: + * don't ignore the attribute silently */ if (tb[IPSET_ATTR_TIMEOUT]) return -IPSET_ERR_TIMEOUT; @@ -143,7 +143,10 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len, return bitmap_ip_test(map, ip_to_id(map, ip)); if (tb[IPSET_ATTR_IP_TO]) { - ip_to = ip_set_get_h32(tb[IPSET_ATTR_IP_TO]); + ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &ip_to); + if (ret) + return ret; + ip_to = ntohl(ip_to); if (ip > ip_to) { swap(ip, ip_to); if (ip < map->first_ip) @@ -203,8 +206,8 @@ bitmap_ip_head(struct ip_set *set, struct sk_buff *skb) nested = ipset_nest_start(skb, IPSET_ATTR_DATA); if (!nested) goto nla_put_failure; - NLA_PUT_NET32(skb, IPSET_ATTR_IP, htonl(map->first_ip)); - NLA_PUT_NET32(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, htonl(map->first_ip)); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)); if (map->netmask != 32) NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, map->netmask); NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, @@ -241,8 +244,8 @@ bitmap_ip_list(struct ip_set *set, } else goto nla_put_failure; } - NLA_PUT_NET32(skb, IPSET_ATTR_IP, - htonl(map->first_ip + id * map->hosts)); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, + htonl(map->first_ip + id * map->hosts)); ipset_nest_end(skb, nested); } ipset_nest_end(skb, atd); @@ -280,7 +283,7 @@ static const struct ip_set_type_variant bitmap_ip __read_mostly = { /* Timeout variant */ struct bitmap_ip_timeout { - void *members; /* the set members */ + unsigned long *members; /* the set members */ u32 first_ip; /* host byte order, included in range */ u32 last_ip; /* host byte order, included in range */ u32 elements; /* number of max elements in the set */ @@ -295,21 +298,17 @@ struct bitmap_ip_timeout { static inline bool bitmap_ip_timeout_test(const struct bitmap_ip_timeout *map, u32 id) { - unsigned long *table = map->members; - - return ip_set_timeout_test(table[id]); + return ip_set_timeout_test(map->members[id]); } static inline int bitmap_ip_timeout_add(struct bitmap_ip_timeout *map, u32 id, u32 timeout) { - unsigned long *table = map->members; - if (bitmap_ip_timeout_test(map, id)) return -IPSET_ERR_EXIST; - table[id] = ip_set_timeout_set(timeout); + map->members[id] = ip_set_timeout_set(timeout); return 0; } @@ -317,13 +316,12 @@ bitmap_ip_timeout_add(struct bitmap_ip_timeout *map, static inline int bitmap_ip_timeout_del(struct bitmap_ip_timeout *map, u32 id) { - unsigned long *table = map->members; int ret = -IPSET_ERR_EXIST; if (bitmap_ip_timeout_test(map, id)) ret = 0; - table[id] = IPSET_ELEM_UNSET; + map->members[id] = IPSET_ELEM_UNSET; return ret; } @@ -368,10 +366,10 @@ bitmap_ip_timeout_uadt(struct ip_set *set, struct nlattr *head, int len, if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); - if (tb[IPSET_ATTR_IP]) - ip = ip_set_get_h32(tb[IPSET_ATTR_IP]); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &ip); + if (ret) + return ret; + ip = ntohl(ip); if (ip < map->first_ip || ip > map->last_ip) return -IPSET_ERR_BITMAP_RANGE; @@ -381,7 +379,10 @@ bitmap_ip_timeout_uadt(struct ip_set *set, struct nlattr *head, int len, ip_to_id((const struct bitmap_ip *)map, ip)); if (tb[IPSET_ATTR_IP_TO]) { - ip_to = ip_set_get_h32(tb[IPSET_ATTR_IP_TO]); + ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &ip_to); + if (ret) + return ret; + ip_to = ntohl(ip_to); if (ip > ip_to) { swap(ip, ip_to); if (ip < map->first_ip) @@ -434,7 +435,7 @@ bitmap_ip_timeout_flush(struct ip_set *set) { struct bitmap_ip_timeout *map = set->data; - memset(map->members, 0, map->memsize); + memset(map->members, IPSET_ELEM_UNSET, map->memsize); } static int @@ -446,11 +447,11 @@ bitmap_ip_timeout_head(struct ip_set *set, struct sk_buff *skb) nested = ipset_nest_start(skb, IPSET_ATTR_DATA); if (!nested) goto nla_put_failure; - NLA_PUT_NET32(skb, IPSET_ATTR_IP, htonl(map->first_ip)); - NLA_PUT_NET32(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, htonl(map->first_ip)); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)); if (map->netmask != 32) NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, map->netmask); - NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT , htonl(map->timeout)); + NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout)); NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(atomic_read(&set->ref) - 1)); NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, @@ -486,8 +487,8 @@ bitmap_ip_timeout_list(struct ip_set *set, } else goto nla_put_failure; } - NLA_PUT_NET32(skb, IPSET_ATTR_IP, - htonl(map->first_ip + id * map->hosts)); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, + htonl(map->first_ip + id * map->hosts)); NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(table[id]))); ipset_nest_end(skb, nested); @@ -563,8 +564,8 @@ bitmap_ip_gc_init(struct ip_set *set) static const struct nla_policy bitmap_ip_create_policy[IPSET_ATTR_CREATE_MAX+1] __read_mostly = { - [IPSET_ATTR_IP] = { .type = NLA_U32 }, - [IPSET_ATTR_IP_TO] = { .type = NLA_U32 }, + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, + [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, [IPSET_ATTR_NETMASK] = { .type = NLA_U8 }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, @@ -597,18 +598,22 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len, struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1]; u32 first_ip, last_ip, hosts, elements; u8 netmask = 32; + int ret; if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len, bitmap_ip_create_policy)) return -IPSET_ERR_PROTOCOL; - if (tb[IPSET_ATTR_IP]) - first_ip = ip_set_get_h32(tb[IPSET_ATTR_IP]); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &first_ip); + if (ret) + return ret; + first_ip = ntohl(first_ip); if (tb[IPSET_ATTR_IP_TO]) { - last_ip = ip_set_get_h32(tb[IPSET_ATTR_IP_TO]); + ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &last_ip); + if (ret) + return ret; + last_ip = htonl(last_ip); if (first_ip > last_ip) { u32 tmp = first_ip; diff --git a/kernel/ip_set_bitmap_ipmac.c b/kernel/ip_set_bitmap_ipmac.c index c595e18..6778819 100644 --- a/kernel/ip_set_bitmap_ipmac.c +++ b/kernel/ip_set_bitmap_ipmac.c @@ -51,6 +51,7 @@ struct bitmap_ipmac { size_t dsize; /* size of element */ }; +/* ADT structure for generic function args */ struct ipmac { u32 id; /* id in array */ unsigned char *ether; /* ethernet address */ @@ -133,7 +134,7 @@ bitmap_ipmac_add(struct ip_set *set, void *value, if (!data->ether) /* Already added without ethernet address */ return -IPSET_ERR_EXIST; - /* Fill the MAC address and activate the timer */ + /* Fill the MAC address */ memcpy(elem->ether, data->ether, ETH_ALEN); elem->match = MAC_FILLED; break; @@ -192,8 +193,8 @@ bitmap_ipmac_list(struct ip_set *set, } else goto nla_put_failure; } - NLA_PUT_NET32(skb, IPSET_ATTR_IP, - htonl(map->first_ip + id)); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, + htonl(map->first_ip + id)); if (elem->match == MAC_FILLED) NLA_PUT(skb, IPSET_ATTR_ETHER, ETH_ALEN, elem->ether); @@ -255,7 +256,7 @@ bitmap_ipmac_tadd(struct ip_set *set, void *value, elem->timeout = ip_set_timeout_set(timeout); break; case MAC_FILLED: - if (bitmap_expired(map, data->id)) + if (!bitmap_expired(map, data->id)) return -IPSET_ERR_EXIST; /* Fall through */ case MAC_EMPTY: @@ -264,7 +265,7 @@ bitmap_ipmac_tadd(struct ip_set *set, void *value, elem->match = MAC_FILLED; } else elem->match = MAC_UNSET; - /* If MAC is unset yet, we store plain timeout + /* If MAC is unset yet, we store plain timeout value * because the timer is not activated yet * and we can reuse it later when MAC is filled out, * possibly by the kernel */ @@ -318,8 +319,8 @@ bitmap_ipmac_tlist(struct ip_set *set, } else goto nla_put_failure; } - NLA_PUT_NET32(skb, IPSET_ATTR_IP, - htonl(map->first_ip + id)); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, + htonl(map->first_ip + id)); if (elem->match == MAC_FILLED) NLA_PUT(skb, IPSET_ATTR_ETHER, ETH_ALEN, elem->ether); @@ -365,7 +366,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb, static const struct nla_policy bitmap_ipmac_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = { - [IPSET_ATTR_IP] = { .type = NLA_U32 }, + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, [IPSET_ATTR_ETHER] = { .type = NLA_BINARY, .len = ETH_ALEN }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, @@ -389,10 +390,10 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *head, int len, if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); - if (tb[IPSET_ATTR_IP]) - data.id = ip_set_get_h32(tb[IPSET_ATTR_IP]); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.id); + if (ret) + return ret; + data.id = ntohl(data.id); if (data.id < map->first_ip || data.id > map->last_ip) return -IPSET_ERR_BITMAP_RANGE; @@ -410,7 +411,7 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *head, int len, data.id -= map->first_ip; - ret = adtfn(set, &data, GFP_KERNEL, timeout); + ret = adtfn(set, &data, GFP_ATOMIC, timeout); return ip_set_eexist(ret, flags) ? 0 : ret; } @@ -447,8 +448,8 @@ bitmap_ipmac_head(struct ip_set *set, struct sk_buff *skb) nested = ipset_nest_start(skb, IPSET_ATTR_DATA); if (!nested) goto nla_put_failure; - NLA_PUT_NET32(skb, IPSET_ATTR_IP, htonl(map->first_ip)); - NLA_PUT_NET32(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, htonl(map->first_ip)); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)); NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(atomic_read(&set->ref) - 1)); NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, @@ -543,8 +544,8 @@ bitmap_ipmac_gc_init(struct ip_set *set) static const struct nla_policy bitmap_ipmac_create_policy[IPSET_ATTR_CREATE_MAX+1] __read_mostly = { - [IPSET_ATTR_IP] = { .type = NLA_U32 }, - [IPSET_ATTR_IP_TO] = { .type = NLA_U32 }, + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, + [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, }; @@ -573,18 +574,22 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *head, int len, struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1]; u32 first_ip, last_ip, elements; struct bitmap_ipmac *map; + int ret; if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len, bitmap_ipmac_create_policy)) return -IPSET_ERR_PROTOCOL; - if (tb[IPSET_ATTR_IP]) - first_ip = ip_set_get_h32(tb[IPSET_ATTR_IP]); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &first_ip); + if (ret) + return ret; + first_ip = ntohl(first_ip); if (tb[IPSET_ATTR_IP_TO]) { - last_ip = ip_set_get_h32(tb[IPSET_ATTR_IP_TO]); + ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &last_ip); + if (ret) + return ret; + last_ip = ntohl(last_ip); if (first_ip > last_ip) { u32 tmp = first_ip; diff --git a/kernel/ip_set_bitmap_port.c b/kernel/ip_set_bitmap_port.c index c385f99..27363f6 100644 --- a/kernel/ip_set_bitmap_port.c +++ b/kernel/ip_set_bitmap_port.c @@ -265,7 +265,7 @@ const struct ip_set_type_variant bitmap_port __read_mostly = { /* Timeout variant */ struct bitmap_port_timeout { - void *members; /* the set members */ + unsigned long *members; /* the set members */ u16 first_port; /* host byte order, included in range */ u16 last_port; /* host byte order, included in range */ size_t memsize; /* members size */ @@ -277,21 +277,17 @@ struct bitmap_port_timeout { static inline bool bitmap_port_timeout_test(const struct bitmap_port_timeout *map, u16 id) { - unsigned long *timeout = map->members; - - return ip_set_timeout_test(timeout[id]); + return ip_set_timeout_test(map->members[id]); } static int bitmap_port_timeout_add(const struct bitmap_port_timeout *map, u16 id, u32 timeout) { - unsigned long *table = map->members; - if (bitmap_port_timeout_test(map, id)) return -IPSET_ERR_EXIST; - table[id] = ip_set_timeout_set(timeout); + map->members[id] = ip_set_timeout_set(timeout); return 0; } @@ -300,13 +296,12 @@ static int bitmap_port_timeout_del(const struct bitmap_port_timeout *map, u16 id) { - unsigned long *table = map->members; int ret = -IPSET_ERR_EXIST; if (bitmap_port_timeout_test(map, id)) ret = 0; - table[id] = IPSET_ELEM_UNSET; + map->members[id] = IPSET_ELEM_UNSET; return ret; } diff --git a/kernel/ip_set_hash_ip.c b/kernel/ip_set_hash_ip.c index 3295b26..6fad300 100644 --- a/kernel/ip_set_hash_ip.c +++ b/kernel/ip_set_hash_ip.c @@ -90,7 +90,7 @@ hash_ip4_data_zero_out(struct hash_ip4_elem *elem) static inline bool hash_ip4_data_list(struct sk_buff *skb, const struct hash_ip4_elem *data) { - NLA_PUT_NET32(skb, IPSET_ATTR_IP, data->ip); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); return 0; nla_put_failure: @@ -103,7 +103,7 @@ hash_ip4_data_tlist(struct sk_buff *skb, const struct hash_ip4_elem *data) const struct hash_ip4_telem *tdata = (const struct hash_ip4_telem *)data; - NLA_PUT_NET32(skb, IPSET_ATTR_IP, tdata->ip); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip); NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(tdata->timeout))); @@ -136,8 +136,8 @@ hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb, static const struct nla_policy hash_ip4_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = { - [IPSET_ATTR_IP] = { .type = NLA_U32 }, - [IPSET_ATTR_IP_TO] = { .type = NLA_U32 }, + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, + [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, @@ -160,10 +160,9 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *head, int len, if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); - if (tb[IPSET_ATTR_IP]) - ip = ip_set_get_n32(tb[IPSET_ATTR_IP]); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &ip); + if (ret) + return ret; ip &= NETMASK(h->netmask); if (ip == 0) @@ -176,11 +175,14 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *head, int len, } if (adt == IPSET_TEST) - return adtfn(set, &ip, GFP_KERNEL, timeout); + return adtfn(set, &ip, GFP_ATOMIC, timeout); ip = ntohl(ip); if (tb[IPSET_ATTR_IP_TO]) { - ip_to = ip_set_get_h32(tb[IPSET_ATTR_IP_TO]); + ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &ip_to); + if (ret) + return ret; + ip_to = ntohl(ip_to); if (ip > ip_to) swap(ip, ip_to); } else if (tb[IPSET_ATTR_CIDR]) { @@ -197,7 +199,7 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *head, int len, for (; !before(ip_to, ip); ip += hosts) { nip = htonl(ip); - ret = adtfn(set, &nip, GFP_KERNEL, timeout); + ret = adtfn(set, &nip, GFP_ATOMIC, timeout); if (ret && !ip_set_eexist(ret, flags)) return ret; @@ -279,7 +281,7 @@ ip6_netmask(union nf_inet_addr *ip, u8 prefix) static inline bool hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *data) { - NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &data->ip); + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); return 0; nla_put_failure: @@ -292,7 +294,7 @@ hash_ip6_data_tlist(struct sk_buff *skb, const struct hash_ip6_elem *data) const struct hash_ip6_telem *e = (const struct hash_ip6_telem *)data; - NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &e->ip); + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(e->timeout))); return 0; @@ -326,8 +328,7 @@ hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb, static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = { - [IPSET_ATTR_IP] = { .type = NLA_BINARY, - .len = sizeof(struct in6_addr) }, + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, }; @@ -339,7 +340,7 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *head, int len, struct chash *h = set->data; struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; - union nf_inet_addr *ip; + union nf_inet_addr ip; u32 timeout = h->timeout; int ret; @@ -350,13 +351,12 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *head, int len, if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); - if (tb[IPSET_ATTR_IP]) - ip = nla_data(tb[IPSET_ATTR_IP]); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &ip); + if (ret) + return ret; - ip6_netmask(ip, h->netmask); - if (ipv6_addr_any(&ip->in6)) + ip6_netmask(&ip, h->netmask); + if (ipv6_addr_any(&ip.in6)) return -IPSET_ERR_HASH_ELEM; if (tb[IPSET_ATTR_TIMEOUT]) { @@ -365,7 +365,7 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *head, int len, timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); } - ret = adtfn(set, ip, GFP_KERNEL, timeout); + ret = adtfn(set, &ip, GFP_ATOMIC, timeout); return ip_set_eexist(ret, flags) ? 0 : ret; } @@ -430,8 +430,9 @@ hash_ip_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) get_random_bytes(&h->initval, sizeof(h->initval)); h->timeout = IPSET_NO_TIMEOUT; - h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist), - GFP_KERNEL); + h->htable = ip_set_alloc( + jhash_size(h->htable_bits) * sizeof(struct slist), + GFP_KERNEL); if (!h->htable) { kfree(h); return -ENOMEM; diff --git a/kernel/ip_set_hash_ipport.c b/kernel/ip_set_hash_ipport.c index 8554c80..1dd8187 100644 --- a/kernel/ip_set_hash_ipport.c +++ b/kernel/ip_set_hash_ipport.c @@ -104,10 +104,9 @@ static inline bool hash_ipport4_data_list(struct sk_buff *skb, const struct hash_ipport4_elem *data) { - NLA_PUT_NET32(skb, IPSET_ATTR_IP, data->ip); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); - if (data->proto != IPSET_IPPROTO_TCPUDP) - NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); return 0; nla_put_failure: @@ -121,10 +120,9 @@ hash_ipport4_data_tlist(struct sk_buff *skb, const struct hash_ipport4_telem *tdata = (const struct hash_ipport4_telem *)data; - NLA_PUT_NET32(skb, IPSET_ATTR_IP, tdata->ip); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port); - if (data->proto != IPSET_IPPROTO_TCPUDP) - NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(tdata->timeout))); @@ -134,8 +132,6 @@ nla_put_failure: return 1; } -#define IP_SET_HASH_WITH_PROTO - #define PF 4 #define HOST_MASK 32 #include <linux/netfilter/ip_set_chash.h> @@ -146,9 +142,9 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb, { struct chash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; - struct hash_ipport4_elem data = { .proto = h->proto }; + struct hash_ipport4_elem data = { }; - if (!get_ip4_port(skb, flags & IPSET_DIM_ONE_SRC, + if (!get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC, &data.port, &data.proto)) return -EINVAL; @@ -158,8 +154,8 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb, } static const struct nla_policy -hash_ipport4_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = { - [IPSET_ATTR_IP] = { .type = NLA_U32 }, +hash_ipport_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = { + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, [IPSET_ATTR_PORT] = { .type = NLA_U16 }, [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, @@ -173,21 +169,20 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *head, int len, struct chash *h = set->data; struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; - struct hash_ipport4_elem data = { .proto = h->proto }; + struct hash_ipport4_elem data = { }; u32 timeout = h->timeout; int ret; if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_ipport4_adt_policy)) + hash_ipport_adt_policy)) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); - if (tb[IPSET_ATTR_IP]) - data.ip = ip_set_get_n32(tb[IPSET_ATTR_IP]); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.ip); + if (ret) + return ret; if (tb[IPSET_ATTR_PORT]) data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]); @@ -197,15 +192,15 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *head, int len, if (tb[IPSET_ATTR_PROTO]) { data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); - if (data.proto == 0 || data.proto >= IPSET_IPPROTO_TCPUDP) + if (data.proto == 0) return -IPSET_ERR_INVALID_PROTO; - } else if (data.proto == IPSET_IPPROTO_ANY) + } else return -IPSET_ERR_MISSING_PROTO; switch (data.proto) { case IPPROTO_UDP: case IPPROTO_TCP: - case IPSET_IPPROTO_TCPUDP: + case IPPROTO_ICMP: break; default: data.port = 0; @@ -218,7 +213,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *head, int len, timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); } - ret = adtfn(set, &data, GFP_KERNEL, timeout); + ret = adtfn(set, &data, GFP_ATOMIC, timeout); return ip_set_eexist(ret, flags) ? 0 : ret; } @@ -232,7 +227,6 @@ hash_ipport_same_set(const struct ip_set *a, const struct ip_set *b) /* Resizing changes htable_bits, so we ignore it */ return x->maxelem == y->maxelem && x->timeout == y->timeout - && x->proto == y->proto && x->array_size == y->array_size && x->chain_limit == y->chain_limit; } @@ -297,10 +291,9 @@ static inline bool hash_ipport6_data_list(struct sk_buff *skb, const struct hash_ipport6_elem *data) { - NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &data->ip); + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); - if (data->proto != IPSET_IPPROTO_TCPUDP) - NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); return 0; nla_put_failure: @@ -314,10 +307,9 @@ hash_ipport6_data_tlist(struct sk_buff *skb, const struct hash_ipport6_telem *e = (const struct hash_ipport6_telem *)data; - NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &e->ip); + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); - if (data->proto != IPSET_IPPROTO_TCPUDP) - NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(e->timeout))); return 0; @@ -339,9 +331,9 @@ hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb, { struct chash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; - struct hash_ipport6_elem data = { .proto = h->proto }; + struct hash_ipport6_elem data = { }; - if (!get_ip6_port(skb, flags & IPSET_DIM_ONE_SRC, + if (!get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC, &data.port, &data.proto)) return -EINVAL; @@ -350,16 +342,6 @@ hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb, return adtfn(set, &data, GFP_ATOMIC, h->timeout); } -static const struct nla_policy -hash_ipport6_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = { - [IPSET_ATTR_IP] = { .type = NLA_BINARY, - .len = sizeof(struct in6_addr) }, - [IPSET_ATTR_PORT] = { .type = NLA_U16 }, - [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, - [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, -}; - static int hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len, enum ipset_adt adt, u32 *lineno, u32 flags) @@ -367,22 +349,20 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len, struct chash *h = set->data; struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; - struct hash_ipport6_elem data = { .proto = h->proto }; + struct hash_ipport6_elem data = { }; u32 timeout = h->timeout; int ret; if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_ipport6_adt_policy)) + hash_ipport_adt_policy)) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); - if (tb[IPSET_ATTR_IP]) - memcpy(&data.ip, nla_data(tb[IPSET_ATTR_IP]), - sizeof(struct in6_addr)); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &data.ip); + if (ret) + return ret; if (tb[IPSET_ATTR_PORT]) data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]); @@ -392,15 +372,15 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len, if (tb[IPSET_ATTR_PROTO]) { data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); - if (data.proto == 0 || data.proto >= IPSET_IPPROTO_TCPUDP) + if (data.proto == 0) return -IPSET_ERR_INVALID_PROTO; - } else if (data.proto == IPSET_IPPROTO_ANY) + } else return -IPSET_ERR_MISSING_PROTO; switch (data.proto) { case IPPROTO_UDP: case IPPROTO_TCP: - case IPSET_IPPROTO_TCPUDP: + case IPPROTO_ICMPV6: break; default: data.port = 0; @@ -413,7 +393,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len, timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); } - ret = adtfn(set, &data, GFP_KERNEL, timeout); + ret = adtfn(set, &data, GFP_ATOMIC, timeout); return ip_set_eexist(ret, flags) ? 0 : ret; } @@ -436,7 +416,6 @@ hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1]; struct chash *h; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; - u8 proto = IPSET_IPPROTO_TCPUDP; /* Backward compatibility */ if (!(set->family == AF_INET || set->family == AF_INET6)) return -IPSET_ERR_INVALID_FAMILY; @@ -454,12 +433,6 @@ hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) if (tb[IPSET_ATTR_MAXELEM]) maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]); - if (tb[IPSET_ATTR_PROTO]) { - proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); - if (!proto) - return -IPSET_ERR_INVALID_PROTO; - } - h = kzalloc(sizeof(*h), GFP_KERNEL); if (!h) return -ENOMEM; @@ -469,11 +442,11 @@ hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) h->array_size = CHASH_DEFAULT_ARRAY_SIZE; h->chain_limit = CHASH_DEFAULT_CHAIN_LIMIT; get_random_bytes(&h->initval, sizeof(h->initval)); - h->proto = proto; h->timeout = IPSET_NO_TIMEOUT; - h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist), - GFP_KERNEL); + h->htable = ip_set_alloc( + jhash_size(h->htable_bits) * sizeof(struct slist), + GFP_KERNEL); if (!h->htable) { kfree(h); return -ENOMEM; diff --git a/kernel/ip_set_hash_ipportip.c b/kernel/ip_set_hash_ipportip.c index d2db3a9..a20f1ef 100644 --- a/kernel/ip_set_hash_ipportip.c +++ b/kernel/ip_set_hash_ipportip.c @@ -107,11 +107,10 @@ static inline bool hash_ipportip4_data_list(struct sk_buff *skb, const struct hash_ipportip4_elem *data) { - NLA_PUT_NET32(skb, IPSET_ATTR_IP, data->ip); - NLA_PUT_NET32(skb, IPSET_ATTR_IP2, data->ip2); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, data->ip2); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); - if (data->proto != IPSET_IPPROTO_TCPUDP) - NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); return 0; nla_put_failure: @@ -125,11 +124,10 @@ hash_ipportip4_data_tlist(struct sk_buff *skb, const struct hash_ipportip4_telem *tdata = (const struct hash_ipportip4_telem *)data; - NLA_PUT_NET32(skb, IPSET_ATTR_IP, tdata->ip); - NLA_PUT_NET32(skb, IPSET_ATTR_IP2, tdata->ip2); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, tdata->ip2); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port); - if (data->proto != IPSET_IPPROTO_TCPUDP) - NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(tdata->timeout))); @@ -139,8 +137,6 @@ nla_put_failure: return 1; } -#define IP_SET_HASH_WITH_PROTO - #define PF 4 #define HOST_MASK 32 #include <linux/netfilter/ip_set_chash.h> @@ -151,7 +147,7 @@ hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb, { struct chash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; - struct hash_ipportip4_elem data = { .proto = h->proto }; + struct hash_ipportip4_elem data = { }; if (!get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC, &data.port, &data.proto)) @@ -164,9 +160,9 @@ hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb, } static const struct nla_policy -hash_ipportip4_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = { - [IPSET_ATTR_IP] = { .type = NLA_U32 }, - [IPSET_ATTR_IP2] = { .type = NLA_U32 }, +hash_ipportip_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = { + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, + [IPSET_ATTR_IP2] = { .type = NLA_NESTED }, [IPSET_ATTR_PORT] = { .type = NLA_U16 }, [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, @@ -180,26 +176,24 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *head, int len, struct chash *h = set->data; struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; - struct hash_ipportip4_elem data = { .proto = h->proto }; + struct hash_ipportip4_elem data = { }; u32 timeout = h->timeout; int ret; if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_ipportip4_adt_policy)) + hash_ipportip_adt_policy)) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); - if (tb[IPSET_ATTR_IP]) - data.ip = ip_set_get_n32(tb[IPSET_ATTR_IP]); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.ip); + if (ret) + return ret; - if (tb[IPSET_ATTR_IP2]) - data.ip2 = ip_set_get_n32(tb[IPSET_ATTR_IP2]); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP2, &data.ip2); + if (ret) + return ret; if (tb[IPSET_ATTR_PORT]) data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]); @@ -209,15 +203,15 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *head, int len, if (tb[IPSET_ATTR_PROTO]) { data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); - if (data.proto == 0 || data.proto >= IPSET_IPPROTO_TCPUDP) + if (data.proto == 0) return -IPSET_ERR_INVALID_PROTO; - } else if (data.proto == IPSET_IPPROTO_ANY) + } else return -IPSET_ERR_MISSING_PROTO; switch (data.proto) { case IPPROTO_UDP: case IPPROTO_TCP: - case IPSET_IPPROTO_TCPUDP: + case IPPROTO_ICMP: break; default: data.port = 0; @@ -230,7 +224,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *head, int len, timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); } - ret = adtfn(set, &data, GFP_KERNEL, timeout); + ret = adtfn(set, &data, GFP_ATOMIC, timeout); return ip_set_eexist(ret, flags) ? 0 : ret; } @@ -244,7 +238,6 @@ hash_ipportip_same_set(const struct ip_set *a, const struct ip_set *b) /* Resizing changes htable_bits, so we ignore it */ return x->maxelem == y->maxelem && x->timeout == y->timeout - && x->proto == y->proto && x->array_size == y->array_size && x->chain_limit == y->chain_limit; } @@ -312,11 +305,10 @@ static inline bool hash_ipportip6_data_list(struct sk_buff *skb, const struct hash_ipportip6_elem *data) { - NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &data->ip); - NLA_PUT(skb, IPSET_ATTR_IP2, sizeof(struct in6_addr), &data->ip2); + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); - if (data->proto != IPSET_IPPROTO_TCPUDP) - NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); return 0; nla_put_failure: @@ -330,11 +322,10 @@ hash_ipportip6_data_tlist(struct sk_buff *skb, const struct hash_ipportip6_telem *e = (const struct hash_ipportip6_telem *)data; - NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &e->ip); - NLA_PUT(skb, IPSET_ATTR_IP2, sizeof(struct in6_addr), &data->ip2); + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); - if (data->proto != IPSET_IPPROTO_TCPUDP) - NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(e->timeout))); return 0; @@ -356,7 +347,7 @@ hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb, { struct chash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; - struct hash_ipportip6_elem data = { .proto = h->proto }; + struct hash_ipportip6_elem data = { }; if (!get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC, &data.port, &data.proto)) @@ -368,18 +359,6 @@ hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb, return adtfn(set, &data, GFP_ATOMIC, h->timeout); } -static const struct nla_policy -hash_ipportip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = { - [IPSET_ATTR_IP] = { .type = NLA_BINARY, - .len = sizeof(struct in6_addr) }, - [IPSET_ATTR_IP2] = { .type = NLA_BINARY, - .len = sizeof(struct in6_addr) }, - [IPSET_ATTR_PORT] = { .type = NLA_U16 }, - [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, - [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, -}; - static int hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len, enum ipset_adt adt, u32 *lineno, u32 flags) @@ -387,28 +366,24 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len, struct chash *h = set->data; struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; - struct hash_ipportip6_elem data = { .proto = h->proto }; + struct hash_ipportip6_elem data = { }; u32 timeout = h->timeout; int ret; if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_ipportip6_adt_policy)) + hash_ipportip_adt_policy)) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); - if (tb[IPSET_ATTR_IP]) - memcpy(&data.ip, nla_data(tb[IPSET_ATTR_IP]), - sizeof(struct in6_addr)); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &data.ip); + if (ret) + return ret; - if (tb[IPSET_ATTR_IP2]) - memcpy(&data.ip2, nla_data(tb[IPSET_ATTR_IP2]), - sizeof(struct in6_addr)); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP2, &data.ip2); + if (ret) + return ret; if (tb[IPSET_ATTR_PORT]) data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]); @@ -418,15 +393,15 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len, if (tb[IPSET_ATTR_PROTO]) { data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); - if (data.proto == 0 || data.proto >= IPSET_IPPROTO_TCPUDP) + if (data.proto == 0) return -IPSET_ERR_INVALID_PROTO; - } else if (data.proto == IPSET_IPPROTO_ANY) + } else return -IPSET_ERR_MISSING_PROTO; switch (data.proto) { case IPPROTO_UDP: case IPPROTO_TCP: - case IPSET_IPPROTO_TCPUDP: + case IPPROTO_ICMPV6: break; default: data.port = 0; @@ -439,7 +414,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len, timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); } - ret = adtfn(set, &data, GFP_KERNEL, timeout); + ret = adtfn(set, &data, GFP_ATOMIC, timeout); return ip_set_eexist(ret, flags) ? 0 : ret; } @@ -452,7 +427,6 @@ hash_ipportip_create_policy[IPSET_ATTR_CREATE_MAX+1] __read_mostly = { [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 }, }; @@ -463,7 +437,6 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *head, struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1]; struct chash *h; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; - u8 proto = IPSET_IPPROTO_TCPUDP; /* Backward compatibility */ if (!(set->family == AF_INET || set->family == AF_INET6)) return -IPSET_ERR_INVALID_FAMILY; @@ -481,12 +454,6 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *head, if (tb[IPSET_ATTR_MAXELEM]) maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]); - if (tb[IPSET_ATTR_PROTO]) { - proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); - if (!proto) - return -IPSET_ERR_INVALID_PROTO; - } - h = kzalloc(sizeof(*h), GFP_KERNEL); if (!h) return -ENOMEM; @@ -496,11 +463,11 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *head, h->array_size = CHASH_DEFAULT_ARRAY_SIZE; h->chain_limit = CHASH_DEFAULT_CHAIN_LIMIT; get_random_bytes(&h->initval, sizeof(h->initval)); - h->proto = proto; h->timeout = IPSET_NO_TIMEOUT; - h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist), - GFP_KERNEL); + h->htable = ip_set_alloc( + jhash_size(h->htable_bits) * sizeof(struct slist), + GFP_KERNEL); if (!h->htable) { kfree(h); return -ENOMEM; diff --git a/kernel/ip_set_hash_ipportnet.c b/kernel/ip_set_hash_ipportnet.c index f2c0d07..3904168 100644 --- a/kernel/ip_set_hash_ipportnet.c +++ b/kernel/ip_set_hash_ipportnet.c @@ -115,12 +115,11 @@ static inline bool hash_ipportnet4_data_list(struct sk_buff *skb, const struct hash_ipportnet4_elem *data) { - NLA_PUT_NET32(skb, IPSET_ATTR_IP, data->ip); - NLA_PUT_NET32(skb, IPSET_ATTR_IP2, data->ip2); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, data->ip2); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr); - if (data->proto != IPSET_IPPROTO_TCPUDP) - NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); return 0; nla_put_failure: @@ -134,12 +133,11 @@ hash_ipportnet4_data_tlist(struct sk_buff *skb, const struct hash_ipportnet4_telem *tdata = (const struct hash_ipportnet4_telem *)data; - NLA_PUT_NET32(skb, IPSET_ATTR_IP, tdata->ip); - NLA_PUT_NET32(skb, IPSET_ATTR_IP2, tdata->ip2); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, tdata->ip2); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port); NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr); - if (data->proto != IPSET_IPPROTO_TCPUDP) - NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(tdata->timeout))); @@ -163,8 +161,7 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb, struct chash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipportnet4_elem data = - { .cidr = h->nets[0].cidr || HOST_MASK, - .proto = h->proto }; + { .cidr = h->nets[0].cidr || HOST_MASK }; if (data.cidr == 0) return -EINVAL; @@ -183,9 +180,9 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb, } static const struct nla_policy -hash_ipportnet4_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = { - [IPSET_ATTR_IP] = { .type = NLA_U32 }, - [IPSET_ATTR_IP2] = { .type = NLA_U32 }, +hash_ipportnet_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = { + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, + [IPSET_ATTR_IP2] = { .type = NLA_NESTED }, [IPSET_ATTR_PORT] = { .type = NLA_U16 }, [IPSET_ATTR_CIDR2] = { .type = NLA_U8 }, [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, @@ -200,27 +197,24 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len, struct chash *h = set->data; struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; - struct hash_ipportnet4_elem data = { .cidr = HOST_MASK, - .proto = h->proto }; + struct hash_ipportnet4_elem data = { .cidr = HOST_MASK }; u32 timeout = h->timeout; int ret; if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_ipportnet4_adt_policy)) + hash_ipportnet_adt_policy)) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); - if (tb[IPSET_ATTR_IP]) - data.ip = ip_set_get_n32(tb[IPSET_ATTR_IP]); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.ip); + if (ret) + return ret; - if (tb[IPSET_ATTR_IP2]) - data.ip2 = ip_set_get_n32(tb[IPSET_ATTR_IP2]); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP2, &data.ip2); + if (ret) + return ret; if (tb[IPSET_ATTR_CIDR2]) data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]); @@ -238,15 +232,15 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len, if (tb[IPSET_ATTR_PROTO]) { data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); - if (data.proto == 0 || data.proto >= IPSET_IPPROTO_TCPUDP) + if (data.proto == 0) return -IPSET_ERR_INVALID_PROTO; - } else if (data.proto == IPSET_IPPROTO_ANY) + } else return -IPSET_ERR_MISSING_PROTO; switch (data.proto) { case IPPROTO_UDP: case IPPROTO_TCP: - case IPSET_IPPROTO_TCPUDP: + case IPPROTO_ICMP: break; default: data.port = 0; @@ -259,7 +253,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len, timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); } - ret = adtfn(set, &data, GFP_KERNEL, timeout); + ret = adtfn(set, &data, GFP_ATOMIC, timeout); return ip_set_eexist(ret, flags) ? 0 : ret; } @@ -273,7 +267,6 @@ hash_ipportnet_same_set(const struct ip_set *a, const struct ip_set *b) /* Resizing changes htable_bits, so we ignore it */ return x->maxelem == y->maxelem && x->timeout == y->timeout - && x->proto == y->proto && x->array_size == y->array_size && x->chain_limit == y->chain_limit; } @@ -358,12 +351,11 @@ static inline bool hash_ipportnet6_data_list(struct sk_buff *skb, const struct hash_ipportnet6_elem *data) { - NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &data->ip); - NLA_PUT(skb, IPSET_ATTR_IP2, sizeof(struct in6_addr), &data->ip2); + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr); - if (data->proto != IPSET_IPPROTO_TCPUDP) - NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); return 0; nla_put_failure: @@ -377,12 +369,11 @@ hash_ipportnet6_data_tlist(struct sk_buff *skb, const struct hash_ipportnet6_telem *e = (const struct hash_ipportnet6_telem *)data; - NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &e->ip); - NLA_PUT(skb, IPSET_ATTR_IP2, sizeof(struct in6_addr), &data->ip2); + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr); - if (data->proto != IPSET_IPPROTO_TCPUDP) - NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(e->timeout))); return 0; @@ -405,8 +396,7 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb, struct chash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipportnet6_elem data = - { .cidr = h->nets[0].cidr || HOST_MASK, - .proto = h->proto }; + { .cidr = h->nets[0].cidr || HOST_MASK }; if (data.cidr == 0) return -EINVAL; @@ -424,19 +414,6 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb, return adtfn(set, &data, GFP_ATOMIC, h->timeout); } -static const struct nla_policy -hash_ipportnet6_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = { - [IPSET_ATTR_IP] = { .type = NLA_BINARY, - .len = sizeof(struct in6_addr) }, - [IPSET_ATTR_IP2] = { .type = NLA_BINARY, - .len = sizeof(struct in6_addr) }, - [IPSET_ATTR_PORT] = { .type = NLA_U16 }, - [IPSET_ATTR_CIDR2] = { .type = NLA_U8 }, - [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, - [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, -}; - static int hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len, enum ipset_adt adt, u32 *lineno, u32 flags) @@ -444,29 +421,24 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len, struct chash *h = set->data; struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; - struct hash_ipportnet6_elem data = { .cidr = HOST_MASK, - .proto = h->proto }; + struct hash_ipportnet6_elem data = { .cidr = HOST_MASK }; u32 timeout = h->timeout; int ret; if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_ipportnet6_adt_policy)) + hash_ipportnet_adt_policy)) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); - if (tb[IPSET_ATTR_IP]) - memcpy(&data.ip, nla_data(tb[IPSET_ATTR_IP]), - sizeof(struct in6_addr)); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &data.ip); + if (ret) + return ret; - if (tb[IPSET_ATTR_IP2]) - memcpy(&data.ip2, nla_data(tb[IPSET_ATTR_IP2]), - sizeof(struct in6_addr)); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP2, &data.ip2); + if (ret) + return ret; if (tb[IPSET_ATTR_CIDR2]) data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]); @@ -484,15 +456,15 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len, if (tb[IPSET_ATTR_PROTO]) { data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); - if (data.proto == 0 || data.proto >= IPSET_IPPROTO_TCPUDP) + if (data.proto == 0) return -IPSET_ERR_INVALID_PROTO; - } else if (data.proto == IPSET_IPPROTO_ANY) + } else return -IPSET_ERR_MISSING_PROTO; switch (data.proto) { case IPPROTO_UDP: case IPPROTO_TCP: - case IPSET_IPPROTO_TCPUDP: + case IPPROTO_ICMPV6: break; default: data.port = 0; @@ -505,7 +477,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len, timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); } - ret = adtfn(set, &data, GFP_KERNEL, timeout); + ret = adtfn(set, &data, GFP_ATOMIC, timeout); return ip_set_eexist(ret, flags) ? 0 : ret; } @@ -518,7 +490,6 @@ hash_ipportnet_create_policy[IPSET_ATTR_CREATE_MAX+1] __read_mostly = { [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 }, }; @@ -529,7 +500,6 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head, struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1]; struct chash *h; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; - u8 proto = IPSET_IPPROTO_TCPUDP; /* Backward compatibility */ if (!(set->family == AF_INET || set->family == AF_INET6)) return -IPSET_ERR_INVALID_FAMILY; @@ -547,14 +517,9 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head, if (tb[IPSET_ATTR_MAXELEM]) maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]); - if (tb[IPSET_ATTR_PROTO]) { - proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); - if (!proto) - return -IPSET_ERR_INVALID_PROTO; - } h = kzalloc(sizeof(*h) + sizeof(struct chash_nets) - * (set->family == AF_INET ? 31 : 127), GFP_KERNEL); + * (set->family == AF_INET ? 32 : 128), GFP_KERNEL); h = kzalloc(sizeof(*h), GFP_KERNEL); if (!h) return -ENOMEM; @@ -563,11 +528,11 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head, h->array_size = CHASH_DEFAULT_ARRAY_SIZE; h->chain_limit = CHASH_DEFAULT_CHAIN_LIMIT; get_random_bytes(&h->initval, sizeof(h->initval)); - h->proto = proto; h->timeout = IPSET_NO_TIMEOUT; - h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist), - GFP_KERNEL); + h->htable = ip_set_alloc( + jhash_size(h->htable_bits) * sizeof(struct slist), + GFP_KERNEL); if (!h->htable) { kfree(h); return -ENOMEM; @@ -579,7 +544,8 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head, h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); set->variant = set->family == AF_INET - ? &hash_ipportnet4_tvariant : &hash_ipportnet6_tvariant; + ? &hash_ipportnet4_tvariant + : &hash_ipportnet6_tvariant; if (set->family == AF_INET) hash_ipportnet4_gc_init(set); diff --git a/kernel/ip_set_hash_net.c b/kernel/ip_set_hash_net.c index 6b755ce..27191f2 100644 --- a/kernel/ip_set_hash_net.c +++ b/kernel/ip_set_hash_net.c @@ -106,7 +106,7 @@ hash_net4_data_zero_out(struct hash_net4_elem *elem) static inline bool hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data) { - NLA_PUT_NET32(skb, IPSET_ATTR_IP, data->ip); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); return 0; @@ -120,7 +120,7 @@ hash_net4_data_tlist(struct sk_buff *skb, const struct hash_net4_elem *data) const struct hash_net4_telem *tdata = (const struct hash_net4_telem *)data; - NLA_PUT_NET32(skb, IPSET_ATTR_IP, tdata->ip); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip); NLA_PUT_U8(skb, IPSET_ATTR_CIDR, tdata->cidr); NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(tdata->timeout))); @@ -157,8 +157,8 @@ hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb, } static const struct nla_policy -hash_net4_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = { - [IPSET_ATTR_IP] = { .type = NLA_U32 }, +hash_net_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = { + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, }; @@ -175,16 +175,15 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *head, int len, int ret; if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_net4_adt_policy)) + hash_net_adt_policy)) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); - if (tb[IPSET_ATTR_IP]) - data.ip = ip_set_get_n32(tb[IPSET_ATTR_IP]); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.ip); + if (ret) + return ret; if (tb[IPSET_ATTR_CIDR]) data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); @@ -200,7 +199,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *head, int len, timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); } - ret = adtfn(set, &data, GFP_KERNEL, timeout); + ret = adtfn(set, &data, GFP_ATOMIC, timeout); return ip_set_eexist(ret, flags) ? 0 : ret; } @@ -292,7 +291,7 @@ hash_net6_data_netmask(struct hash_net6_elem *elem, u8 cidr) static inline bool hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data) { - NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &data->ip); + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); return 0; @@ -306,7 +305,7 @@ hash_net6_data_tlist(struct sk_buff *skb, const struct hash_net6_elem *data) const struct hash_net6_telem *e = (const struct hash_net6_telem *)data; - NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &e->ip); + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); NLA_PUT_U8(skb, IPSET_ATTR_CIDR, e->cidr); NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(e->timeout))); @@ -342,15 +341,6 @@ hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb, return adtfn(set, &data, GFP_ATOMIC, h->timeout); } -static const struct nla_policy -hash_net6_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = { - [IPSET_ATTR_IP] = { .type = NLA_BINARY, - .len = sizeof(struct in6_addr) }, - [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, - [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, -}; - static int hash_net6_uadt(struct ip_set *set, struct nlattr *head, int len, enum ipset_adt adt, u32 *lineno, u32 flags) @@ -363,17 +353,15 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *head, int len, int ret; if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_net6_adt_policy)) + hash_net_adt_policy)) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); - if (tb[IPSET_ATTR_IP]) - memcpy(&data.ip, nla_data(tb[IPSET_ATTR_IP]), - sizeof(struct in6_addr)); - else - return -IPSET_ERR_PROTOCOL; + 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]); @@ -389,7 +377,7 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *head, int len, timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); } - ret = adtfn(set, &data, GFP_KERNEL, timeout); + ret = adtfn(set, &data, GFP_ATOMIC, timeout); return ip_set_eexist(ret, flags) ? 0 : ret; } @@ -430,7 +418,7 @@ hash_net_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) h = kzalloc(sizeof(*h) + sizeof(struct chash_nets) - * (set->family == AF_INET ? 31 : 127), GFP_KERNEL); + * (set->family == AF_INET ? 32 : 128), GFP_KERNEL); if (!h) return -ENOMEM; @@ -441,8 +429,9 @@ hash_net_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) get_random_bytes(&h->initval, sizeof(h->initval)); h->timeout = IPSET_NO_TIMEOUT; - h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist), - GFP_KERNEL); + h->htable = ip_set_alloc( + jhash_size(h->htable_bits) * sizeof(struct slist), + GFP_KERNEL); if (!h->htable) { kfree(h); return -ENOMEM; diff --git a/kernel/ip_set_hash_netport.c b/kernel/ip_set_hash_netport.c new file mode 100644 index 0000000..f7f43b8 --- /dev/null +++ b/kernel/ip_set_hash_netport.c @@ -0,0 +1,566 @@ +/* Copyright (C) 2003-2010 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,port type */ + +#include <linux/netfilter/ip_set_kernel.h> +#include <linux/netfilter/ip_set_jhash.h> +#include <linux/module.h> +#include <linux/ip.h> +#include <linux/skbuff.h> +#include <linux/errno.h> +#include <asm/uaccess.h> +#include <asm/bitops.h> +#include <linux/spinlock.h> +#include <linux/random.h> +#include <net/ip.h> +#include <net/ipv6.h> +#include <net/netlink.h> +#include <net/pfxlen.h> + +#include <linux/netfilter.h> +#include <linux/netfilter/ip_set.h> +#include <linux/netfilter/ip_set_timeout.h> +#include <linux/netfilter/ip_set_getport.h> +#include <linux/netfilter/ip_set_hash.h> + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); +MODULE_DESCRIPTION("hash:net,port type of IP sets"); +MODULE_ALIAS("ip_set_hash:net,port"); + +/* Type specific function prefix */ +#define TYPE hash_netport + +static bool +hash_netport_same_set(const struct ip_set *a, const struct ip_set *b); + +#define hash_netport4_same_set hash_netport_same_set +#define hash_netport6_same_set hash_netport_same_set + +/* The type variant functions: IPv4 */ + +/* Member elements without timeout */ +struct hash_netport4_elem { + u32 ip; + u16 port; + u8 proto; + u8 cidr; +}; + +/* Member elements with timeout support */ +struct hash_netport4_telem { + u32 ip; + u16 port; + u8 proto; + u8 cidr; + unsigned long timeout; +}; + +static inline bool +hash_netport4_data_equal(const struct hash_netport4_elem *ip1, + const struct hash_netport4_elem *ip2) +{ + return ip1->ip == ip2->ip + && ip1->port == ip2->port + && ip1->proto == ip2->proto + && ip1->cidr == ip2->cidr; +} + +static inline bool +hash_netport4_data_isnull(const struct hash_netport4_elem *elem) +{ + return elem->proto == 0; +} + +static inline void +hash_netport4_data_copy(struct hash_netport4_elem *dst, + const struct hash_netport4_elem *src) +{ + dst->ip = src->ip; + dst->port = src->port; + dst->proto = src->proto; + dst->cidr = src->cidr; +} + +static inline void +hash_netport4_data_swap(struct hash_netport4_elem *dst, + struct hash_netport4_elem *src) +{ + swap(dst->ip, src->ip); + swap(dst->port, src->port); + swap(dst->proto, src->proto); + swap(dst->cidr, src->cidr); +} + +static inline void +hash_netport4_data_netmask(struct hash_netport4_elem *elem, u8 cidr) +{ + elem->ip &= NETMASK(cidr); + elem->cidr = cidr; +} + +static inline void +hash_netport4_data_zero_out(struct hash_netport4_elem *elem) +{ + elem->proto = 0; +} + +static inline bool +hash_netport4_data_list(struct sk_buff *skb, + const struct hash_netport4_elem *data) +{ + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); + NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); + NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); + NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + return 0; + +nla_put_failure: + return 1; +} + +static inline bool +hash_netport4_data_tlist(struct sk_buff *skb, + const struct hash_netport4_elem *data) +{ + const struct hash_netport4_telem *tdata = + (const struct hash_netport4_telem *)data; + + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip); + NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port); + NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); + NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + 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_PROTO +#define IP_SET_HASH_WITH_NETS + +#define PF 4 +#define HOST_MASK 32 +#include <linux/netfilter/ip_set_chash.h> + +static int +hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb, + enum ipset_adt adt, u8 pf, u8 dim, u8 flags) +{ + struct chash *h = set->data; + ipset_adtfn adtfn = set->variant->adt[adt]; + struct hash_netport4_elem data = + { .cidr = h->nets[0].cidr || HOST_MASK }; + + if (data.cidr == 0) + return -EINVAL; + if (adt == IPSET_TEST) + data.cidr = HOST_MASK; + + if (!get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC, + &data.port, &data.proto)) + return -EINVAL; + + ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip); + data.ip &= NETMASK(data.cidr); + + return adtfn(set, &data, GFP_ATOMIC, h->timeout); +} + +static const struct nla_policy +hash_netport_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = { + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, + [IPSET_ATTR_PORT] = { .type = NLA_U16 }, + [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, + [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, +}; + +static int +hash_netport4_uadt(struct ip_set *set, struct nlattr *head, int len, + enum ipset_adt adt, u32 *lineno, u32 flags) +{ + struct chash *h = set->data; + struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; + ipset_adtfn adtfn = set->variant->adt[adt]; + struct hash_netport4_elem data = { .cidr = HOST_MASK }; + u32 timeout = h->timeout; + int ret; + + if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, + hash_netport_adt_policy)) + return -IPSET_ERR_PROTOCOL; + + if (tb[IPSET_ATTR_LINENO]) + *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); + + ret = ip_set_get_ipaddr4(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; + data.ip &= NETMASK(data.cidr); + + if (tb[IPSET_ATTR_PORT]) + data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]); + else + return -IPSET_ERR_PROTOCOL; + + if (tb[IPSET_ATTR_PROTO]) { + data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); + + if (data.proto == 0) + return -IPSET_ERR_INVALID_PROTO; + } else + return -IPSET_ERR_MISSING_PROTO; + + switch (data.proto) { + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_ICMP: + break; + default: + data.port = 0; + break; + } + + if (tb[IPSET_ATTR_TIMEOUT]) { + if (!with_timeout(h->timeout)) + return -IPSET_ERR_TIMEOUT; + timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); + } + + ret = adtfn(set, &data, GFP_ATOMIC, timeout); + + return ip_set_eexist(ret, flags) ? 0 : ret; +} + +static bool +hash_netport_same_set(const struct ip_set *a, const struct ip_set *b) +{ + struct chash *x = a->data; + struct chash *y = b->data; + + /* Resizing changes htable_bits, so we ignore it */ + return x->maxelem == y->maxelem + && x->timeout == y->timeout + && x->array_size == y->array_size + && x->chain_limit == y->chain_limit; +} + +/* The type variant functions: IPv6 */ + +struct hash_netport6_elem { + union nf_inet_addr ip; + u16 port; + u8 proto; + u8 cidr; +}; + +struct hash_netport6_telem { + union nf_inet_addr ip; + u16 port; + u8 proto; + u8 cidr; + unsigned long timeout; +}; + +static inline bool +hash_netport6_data_equal(const struct hash_netport6_elem *ip1, + const struct hash_netport6_elem *ip2) +{ + return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 + && ip1->port == ip2->port + && ip1->proto == ip2->proto + && ip1->cidr == ip2->cidr; +} + +static inline bool +hash_netport6_data_isnull(const struct hash_netport6_elem *elem) +{ + return elem->proto == 0; +} + +static inline void +hash_netport6_data_copy(struct hash_netport6_elem *dst, + const struct hash_netport6_elem *src) +{ + memcpy(dst, src, sizeof(*dst)); +} + +static inline void +hash_netport6_data_swap(struct hash_netport6_elem *dst, + struct hash_netport6_elem *src) +{ + struct hash_netport6_elem tmp; + + memcpy(&tmp, dst, sizeof(tmp)); + memcpy(dst, src, sizeof(tmp)); + memcpy(src, &tmp, sizeof(tmp)); +} + +static inline void +hash_netport6_data_zero_out(struct hash_netport6_elem *elem) +{ + elem->proto = 0; +} + +static inline void +ip6_netmask(union nf_inet_addr *ip, u8 prefix) +{ + ip->ip6[0] &= NETMASK6(prefix)[0]; + ip->ip6[1] &= NETMASK6(prefix)[1]; + ip->ip6[2] &= NETMASK6(prefix)[2]; + ip->ip6[3] &= NETMASK6(prefix)[3]; +} + +static inline void +hash_netport6_data_netmask(struct hash_netport6_elem *elem, u8 cidr) +{ + ip6_netmask(&elem->ip, cidr); + elem->cidr = cidr; +} + +static inline bool +hash_netport6_data_list(struct sk_buff *skb, + const struct hash_netport6_elem *data) +{ + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); + NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); + NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); + NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + return 0; + +nla_put_failure: + return 1; +} + +static inline bool +hash_netport6_data_tlist(struct sk_buff *skb, + const struct hash_netport6_elem *data) +{ + const struct hash_netport6_telem *e = + (const struct hash_netport6_telem *)data; + + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); + NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); + NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); + NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, + htonl(ip_set_timeout_get(e->timeout))); + return 0; + +nla_put_failure: + return 1; +} + +#undef PF +#undef HOST_MASK + +#define PF 6 +#define HOST_MASK 128 +#include <linux/netfilter/ip_set_chash.h> + +static int +hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb, + enum ipset_adt adt, u8 pf, u8 dim, u8 flags) +{ + struct chash *h = set->data; + ipset_adtfn adtfn = set->variant->adt[adt]; + struct hash_netport6_elem data = + { .cidr = h->nets[0].cidr || HOST_MASK }; + + if (data.cidr == 0) + return -EINVAL; + if (adt == IPSET_TEST) + data.cidr = HOST_MASK; + + if (!get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC, + &data.port, &data.proto)) + return -EINVAL; + + ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6); + ip6_netmask(&data.ip, data.cidr); + + return adtfn(set, &data, GFP_ATOMIC, h->timeout); +} + +static int +hash_netport6_uadt(struct ip_set *set, struct nlattr *head, int len, + enum ipset_adt adt, u32 *lineno, u32 flags) +{ + struct chash *h = set->data; + struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; + ipset_adtfn adtfn = set->variant->adt[adt]; + struct hash_netport6_elem data = { .cidr = HOST_MASK }; + u32 timeout = h->timeout; + int ret; + + if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, + hash_netport_adt_policy)) + return -IPSET_ERR_PROTOCOL; + + 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_PORT]) + data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]); + else + return -IPSET_ERR_PROTOCOL; + + if (tb[IPSET_ATTR_PROTO]) { + data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); + + if (data.proto == 0) + return -IPSET_ERR_INVALID_PROTO; + } else + return -IPSET_ERR_MISSING_PROTO; + + switch (data.proto) { + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_ICMPV6: + break; + default: + data.port = 0; + break; + } + + if (tb[IPSET_ATTR_TIMEOUT]) { + if (!with_timeout(h->timeout)) + return -IPSET_ERR_TIMEOUT; + timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); + } + + ret = adtfn(set, &data, GFP_ATOMIC, timeout); + + return ip_set_eexist(ret, flags) ? 0 : ret; +} + +/* Create hash:ip type of sets */ + +static const struct nla_policy +hash_netport_create_policy[IPSET_ATTR_CREATE_MAX+1] __read_mostly = { + [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 }, +}; + +static int +hash_netport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) +{ + struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1]; + struct chash *h; + u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; + + if (!(set->family == AF_INET || set->family == AF_INET6)) + return -IPSET_ERR_INVALID_FAMILY; + + if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len, + hash_netport_create_policy)) + 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 chash_nets) + * (set->family == AF_INET ? 32 : 128), GFP_KERNEL); + if (!h) + return -ENOMEM; + + h->maxelem = maxelem; + h->htable_bits = htable_bits(hashsize); + h->array_size = CHASH_DEFAULT_ARRAY_SIZE; + h->chain_limit = CHASH_DEFAULT_CHAIN_LIMIT; + get_random_bytes(&h->initval, sizeof(h->initval)); + h->timeout = IPSET_NO_TIMEOUT; + + h->htable = ip_set_alloc( + jhash_size(h->htable_bits) * sizeof(struct slist), + GFP_KERNEL); + if (!h->htable) { + kfree(h); + return -ENOMEM; + } + + 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_netport4_tvariant : &hash_netport6_tvariant; + + if (set->family == AF_INET) + hash_netport4_gc_init(set); + else + hash_netport6_gc_init(set); + } else { + set->variant = set->family == AF_INET + ? &hash_netport4_variant : &hash_netport6_variant; + } + + pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)", + set->name, jhash_size(h->htable_bits), + h->htable_bits, h->maxelem, set->data, h->htable); + + return 0; +} + +static struct ip_set_type hash_netport_type = { + .name = "hash:net,port", + .protocol = IPSET_PROTOCOL, + .features = IPSET_TYPE_IP | IPSET_TYPE_PORT, + .dimension = IPSET_DIM_TWO, + .family = AF_UNSPEC, + .revision = 0, + .create = hash_netport_create, + .me = THIS_MODULE, +}; + +static int __init +hash_netport_init(void) +{ + return ip_set_type_register(&hash_netport_type); +} + +static void __exit +hash_netport_fini(void) +{ + ip_set_type_unregister(&hash_netport_type); +} + +module_init(hash_netport_init); +module_exit(hash_netport_fini); diff --git a/kernel/ip_set_list_set.c b/kernel/ip_set_list_set.c index c1e4699..ea3f0a9 100644 --- a/kernel/ip_set_list_set.c +++ b/kernel/ip_set_list_set.c @@ -250,7 +250,8 @@ list_set_uadt(struct ip_set *set, struct nlattr *head, int len, } if (tb[IPSET_ATTR_NAMEREF]) { - refid = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAMEREF]), &s); + refid = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAMEREF]), + &s); if (refid == IPSET_INVALID_ID) { ret = -IPSET_ERR_NAMEREF; goto finish; @@ -320,7 +321,8 @@ list_set_uadt(struct ip_set *set, struct nlattr *head, int len, continue; else if (elem->id == id && (before == 0 - || (before > 0 && next_id_eq(map, i, refid)))) + || (before > 0 + && next_id_eq(map, i, refid)))) ret = list_set_del(map, id, i); else if (before < 0 && elem->id == refid && next_id_eq(map, i, id)) diff --git a/lib/Makefile.am b/lib/Makefile.am index bf4e133..7913877 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,13 +1,15 @@ include $(top_srcdir)/Make_global.am -AM_CFLAGS += -fPIC -LIBS = +AM_CFLAGS += ${libmnl_CFLAGS} lib_LTLIBRARIES = libipset.la libipset_la_LDFLAGS = -version-info $(LIBVERSION) +libipset_la_LIBADD = ${libmnl_LIBS} libipset_la_SOURCES = \ data.c \ + icmp.c \ + icmpv6.c \ mnl.c \ parse.c \ print.c \ @@ -31,6 +31,7 @@ struct ipset_data { uint64_t ignored; /* Setname */ char setname[IPSET_MAXNAMELEN]; + /* Set type */ const struct ipset_type *type; /* Common CADT options */ uint8_t cidr; @@ -161,7 +162,7 @@ do { \ /** * ipset_data_ignored - test and set ignored bits in the data blob * @data: data blob - * @flags: the option flags which is ignored + * @flags: the option flag to be ignored * * Returns true if the option was not already ignored. */ @@ -205,6 +206,7 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value) break; case IPSET_OPT_FAMILY: data->family = *(const uint8_t *) value; + D("family set to %u", data->family); break; /* CADT options */ case IPSET_OPT_IP: @@ -263,7 +265,8 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value) break; /* Create-specific options, type */ case IPSET_OPT_TYPENAME: - ipset_strncpy(data->u.create.typename, value, IPSET_MAXNAMELEN); + ipset_strncpy(data->u.create.typename, value, + IPSET_MAXNAMELEN); break; case IPSET_OPT_REVISION: data->u.create.revision = *(const uint8_t *) value; @@ -332,7 +335,7 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt) assert(data); assert(opt != IPSET_OPT_NONE); - if (opt != IPSET_OPT_TYPENAME && !ipset_data_test(data, opt)) + if (!(opt == IPSET_OPT_TYPENAME || ipset_data_test(data, opt))) return NULL; switch (opt) { @@ -418,11 +421,11 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt) } /** - * ipset_data_sizeof - calculates the size for the type of data + * ipset_data_sizeof - calculates the size of the data type * @opt: option kind of the data * @family: INET family * - * Returns the size required to store the given option kind. + * Returns the size required to store the given data type. */ size_t ipset_data_sizeof(enum ipset_opt opt, uint8_t family) @@ -502,7 +505,7 @@ ipset_data_family(const struct ipset_data *data) * @data: data blob * * Return the value of IPSET_OPT_CIDR stored in the data blob. - * If it is not set, the the returned value corresponds to + * If it is not set, then the returned value corresponds to * the default one according to the family type or zero. */ uint8_t diff --git a/lib/icmp.c b/lib/icmp.c new file mode 100644 index 0000000..93276e2 --- /dev/null +++ b/lib/icmp.c @@ -0,0 +1,79 @@ +/* Copyright 2007-2010 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/utils.h> /* STRNEQ */ +#include <libipset/icmp.h> /* prototypes */ + +struct icmp_names { + const char *name; + uint8_t type, code; +}; + +static const struct icmp_names icmp_typecodes[] = { + { "echo-reply", 0, 0 }, + { "pong", 0, 0 }, + { "network-unreachable", 3, 0 }, + { "host-unreachable", 3, 1 }, + { "protocol-unreachable", 3, 2 }, + { "port-unreachable", 3, 3 }, + { "fragmentation-needed", 3, 4 }, + { "source-route-failed", 3, 5 }, + { "network-unknown", 3, 6 }, + { "host-unknown", 3, 7 }, + { "network-prohibited", 3, 9 }, + { "host-prohibited", 3, 10 }, + { "TOS-network-unreachable", 3, 11 }, + { "TOS-host-unreachable", 3, 12 }, + { "communication-prohibited", 3, 13 }, + { "host-precedence-violation", 3, 14 }, + { "precedence-cutoff", 3, 15 }, + { "source-quench", 4, 0 }, + { "network-redirect", 5, 0 }, + { "host-redirect", 5, 1 }, + { "TOS-network-redirect", 5, 2 }, + { "TOS-host-redirect", 5, 3 }, + { "echo-request", 8, 0 }, + { "ping", 8, 0 }, + { "router-advertisement", 9, 0 }, + { "router-solicitation", 10, 0 }, + { "ttl-zero-during-transit", 11, 0 }, + { "ttl-zero-during-reassembly", 11, 1 }, + { "ip-header-bad", 12, 0 }, + { "required-option-missing", 12, 1 }, + { "timestamp-request", 13, 0 }, + { "timestamp-reply", 14, 0 }, + { "address-mask-request", 17, 0 }, + { "address-mask-reply", 18, 0 }, +}; + +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) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(icmp_typecodes); i++) + if (icmp_typecodes[i].type == type && icmp_typecodes[i].code == code) + return icmp_typecodes[i].name; + + return NULL; +} + +int name_to_icmp(const char *str, uint16_t *typecode) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(icmp_typecodes); i++) + if (STRNEQ(icmp_typecodes[i].name, str, strlen(str))) { + *typecode = (icmp_typecodes[i].type << 8) | icmp_typecodes[i].code; + return 0; + } + + return -1; +} diff --git a/lib/icmpv6.c b/lib/icmpv6.c new file mode 100644 index 0000000..c32a6a4 --- /dev/null +++ b/lib/icmpv6.c @@ -0,0 +1,66 @@ +/* Copyright 2007-2010 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/utils.h> /* STRNEQ */ +#include <libipset/icmpv6.h> /* prototypes */ + +struct icmpv6_names { + const char *name; + uint8_t type, code; +}; + +static const struct icmpv6_names icmpv6_typecodes[] = { + { "no-route", 1, 0 }, + { "communication-prohibited", 1, 1 }, + { "address-unreachable", 1, 3 }, + { "port-unreachable", 1, 4 }, + { "packet-too-big", 2, 0 }, + { "ttl-zero-during-transit", 3, 0 }, + { "ttl-zero-during-reassembly", 3, 1 }, + { "bad-header", 4, 0 }, + { "unknown-header-type", 4, 1 }, + { "unknown-option", 4, 2 }, + { "echo-request", 128, 0 }, + { "ping", 128, 0 }, + { "echo-reply", 129, 0 }, + { "pong", 129, 0 }, + { "router-solicitation", 133, 0 }, + { "router-advertisement", 134, 0 }, + { "neighbour-solicitation", 135, 0 }, + { "neigbour-solicitation", 135, 0 }, + { "neighbour-advertisement", 136, 0 }, + { "neigbour-advertisement", 136, 0 }, + { "redirect", 137, 0 }, +}; + +const char * id_to_icmpv6(uint8_t id) +{ + return id < ARRAY_SIZE(icmpv6_typecodes) ? icmpv6_typecodes[id].name : NULL; +} + +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) + return icmpv6_typecodes[i].name; + + return NULL; +} + +int name_to_icmpv6(const char *str, uint16_t *typecode) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(icmpv6_typecodes); i++) + if (STRNEQ(icmpv6_typecodes[i].name, str, strlen(str))) { + *typecode = (icmpv6_typecodes[i].type << 8) | icmpv6_typecodes[i].code; + return 0; + } + + return -1; +} @@ -21,12 +21,13 @@ #define NFNL_SUBSYS_IPSET 6 #endif +/* Internal data structure for the kernel-userspace communication parameters */ struct ipset_handle { - struct mnl_socket *h; - unsigned int seq; - unsigned int portid; - mnl_cb_t *cb_ctl; - void *data; + struct mnl_socket *h; /* the mnl socket */ + unsigned int seq; /* netlink message sequence number */ + unsigned int portid; /* the socket port identifier */ + mnl_cb_t *cb_ctl; /* control block callbacks */ + void *data; /* data pointer */ }; /* Netlink flags of the commands */ @@ -46,6 +47,12 @@ static uint16_t cmdflags[] = { [IPSET_CMD_PROTOCOL-1] = NLM_F_REQUEST, }; +/** + * ipset_get_nlmsg_type - get ipset netlink message type + * @nlh: pointer to the netlink message header + * + * Returns the ipset netlink message type, i.e. the ipset command. + */ int ipset_get_nlmsg_type(const struct nlmsghdr *nlh) { diff --git a/lib/parse.c b/lib/parse.c index 84b6a3f..28192d8 100644 --- a/lib/parse.c +++ b/lib/parse.c @@ -12,9 +12,12 @@ #include <sys/types.h> /* getaddrinfo */ #include <sys/socket.h> /* getaddrinfo, AF_ */ #include <net/ethernet.h> /* ETH_ALEN */ +#include <netinet/in.h> /* IPPROTO_ */ #include <libipset/debug.h> /* D() */ #include <libipset/data.h> /* IPSET_OPT_* */ +#include <libipset/icmp.h> /* name_to_icmp */ +#include <libipset/icmpv6.h> /* name_to_icmpv6 */ #include <libipset/pfxlen.h> /* prefixlen_netmask_map */ #include <libipset/session.h> /* ipset_err */ #include <libipset/types.h> /* ipset_type_get */ @@ -192,32 +195,35 @@ error: * Parse TCP service names or port numbers */ static int -parse_portname(struct ipset_session *session, const char *str, uint16_t *port) +parse_portname(struct ipset_session *session, const char *str, + uint16_t *port, const char *proto) { struct servent *service; - if ((service = getservbyname(str, "tcp")) != NULL) { + if ((service = getservbyname(str, proto)) != NULL) { *port = ntohs((uint16_t) service->s_port); return 0; } - return syntax_err("cannot parse '%s' as a (TCP) port", str); + return syntax_err("cannot parse '%s' as a %s port", str, proto); } /** - * ipset_parse_single_port - parse a single (TCP) port number or name + * ipset_parse_single_port - parse a single port number or name * @session: session structure * @opt: option kind of the data * @str: string to parse + * @proto: protocol * - * Parse string as a single (TCP) port number or name. The parsed port + * Parse string as a single port number or name. The parsed port * number is stored in the data blob of the session. * * Returns 0 on success or a negative error code. */ int -ipset_parse_single_port(struct ipset_session *session, - enum ipset_opt opt, const char *str) +ipset_parse_port(struct ipset_session *session, + enum ipset_opt opt, const char *str, + const char *proto) { uint16_t port; int err; @@ -227,31 +233,31 @@ ipset_parse_single_port(struct ipset_session *session, assert(str); if ((err = string_to_u16(session, str, &port)) == 0 - || (err = parse_portname(session, str, &port)) == 0) + || (err = parse_portname(session, str, &port, proto)) == 0) err = ipset_session_data_set(session, opt, &port); if (!err) - /* No error, so reset session messages! */ + /* No error, so reset false error messages! */ ipset_session_report_reset(session); return err; } /** - * ipset_parse_port - parse (TCP) port name, number, or range of them + * ipset_parse_tcp_port - parse TCP port name, number, or range of them * @session: session structure * @opt: option kind of the data * @str: string to parse * - * Parse string as a TCP port name or number or range of them. + * Parse string as a TCP port name or number or range of them * separated by a dash. The parsed port numbers are stored * in the data blob of the session. * * Returns 0 on success or a negative error code. */ int -ipset_parse_port(struct ipset_session *session, - enum ipset_opt opt, const char *str) +ipset_parse_tcp_port(struct ipset_session *session, + enum ipset_opt opt, const char *str) { char *a, *saved, *tmp; int err = 0; @@ -270,11 +276,11 @@ ipset_parse_port(struct ipset_session *session, if (a != NULL) { /* port-port */ *a++ = '\0'; - err = ipset_parse_single_port(session, IPSET_OPT_PORT_TO, a); + err = ipset_parse_port(session, IPSET_OPT_PORT_TO, a, "TCP"); if (err) goto error; } - err = ipset_parse_single_port(session, opt, tmp); + err = ipset_parse_port(session, opt, tmp, "TCP"); error: free(saved); @@ -282,14 +288,36 @@ error: } /** + * ipset_parse_single_tcp_port - parse TCP port name or number + * @session: session structure + * @opt: option kind of the data + * @str: string to parse + * + * Parse string as a single TCP port name or number. + * The parsed port number is stored + * in the data blob of the session. + * + * Returns 0 on success or a negative error code. + */ +int +ipset_parse_single_tcp_port(struct ipset_session *session, + enum ipset_opt opt, const char *str) +{ + assert(session); + assert(opt == IPSET_OPT_PORT || opt == IPSET_OPT_PORT_TO); + assert(str); + + return ipset_parse_port(session, opt, str, "TCP"); +} + +/** * ipset_parse_proto - parse protocol name * @session: session structure * @opt: option kind of the data * @str: string to parse * - * Parse string as a protocol name. "any" is supported - * as a special protocol name for ipset itself. - * The parsed protocol are stored in the data blob of the session. + * Parse string as a protocol name. + * The parsed protocol is stored in the data blob of the session. * * Returns 0 on success or a negative error code. */ @@ -297,26 +325,114 @@ int ipset_parse_proto(struct ipset_session *session, enum ipset_opt opt, const char *str) { + struct protoent *protoent; uint8_t proto = 0; assert(session); assert(opt == IPSET_OPT_PROTO); assert(str); - if (STREQ(str, "any")) - proto = IPSET_IPPROTO_ANY; - else { - struct protoent *protoent = getprotobyname(str); - if (protoent == NULL) - return syntax_err("cannot parse '%s' as a protocol name", str); - proto = protoent->p_proto; - } - if (!proto || proto == IPSET_IPPROTO_TCPUDP) - return syntax_err("invalid protocol '%s'", str); + protoent = getprotobyname(strcasecmp(str, "icmpv6") == 0 + ? "ipv6-icmp" : str); + if (protoent == NULL) + return syntax_err("cannot parse '%s' " + "as a protocol name", str); + proto = protoent->p_proto; + if (!proto) + return syntax_err("Unsupported protocol '%s'", str); return ipset_session_data_set(session, opt, &proto); } +/* Parse ICMP and ICMPv6 type/code */ +static int +parse_icmp_typecode(struct ipset_session *session, + enum ipset_opt opt, const char *str, + const char *family) +{ + uint16_t typecode; + uint8_t type, code; + char *a, *saved, *tmp; + int err; + + saved = tmp = strdup(str); + if (tmp == NULL) + return ipset_err(session, + "Cannot allocate memory to duplicate %s.", + str); + a = cidr_separator(tmp); + if (a == NULL) { + free(saved); + return ipset_err(session, + "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) + goto error; + + typecode = (type << 8) | code; + err = ipset_session_data_set(session, opt, &typecode); + +error: + free(saved); + return err; +} + +/** + * ipset_parse_icmp - parse an ICMP name or type/code + * @session: session structure + * @opt: option kind of the data + * @str: string to parse + * + * Parse string as an ICMP name or type/code numbers. + * The parsed ICMP type/code is stored in the data blob of the session. + * + * Returns 0 on success or a negative error code. + */ +int +ipset_parse_icmp(struct ipset_session *session, + enum ipset_opt opt, const char *str) +{ + uint16_t typecode; + + assert(session); + assert(opt == IPSET_OPT_PORT); + assert(str); + + if (name_to_icmp(str, &typecode) < 0) + return parse_icmp_typecode(session, opt, str, "ICMP"); + + return ipset_session_data_set(session, opt, &typecode); +} + +/** + * ipset_parse_icmpv6 - parse an ICMPv6 name or type/code + * @session: session structure + * @opt: option kind of the data + * @str: string to parse + * + * Parse string as an ICMPv6 name or type/code numbers. + * The parsed ICMPv6 type/code is stored in the data blob of the session. + * + * Returns 0 on success or a negative error code. + */ +int +ipset_parse_icmpv6(struct ipset_session *session, + enum ipset_opt opt, const char *str) +{ + uint16_t typecode; + + assert(session); + assert(opt == IPSET_OPT_PORT); + assert(str); + + if (name_to_icmpv6(str, &typecode) < 0) + return parse_icmp_typecode(session, opt, str, "ICMPv6"); + + return ipset_session_data_set(session, opt, &typecode); +} + /** * ipset_parse_proto_port - parse (optional) protocol and a single port * @session: session structure @@ -334,13 +450,17 @@ int ipset_parse_proto_port(struct ipset_session *session, enum ipset_opt opt, const char *str) { + struct ipset_data *data; char *a, *saved, *tmp; + const char *proto; + uint8_t p = IPPROTO_TCP; int err = 0; assert(session); assert(opt == IPSET_OPT_PORT); assert(str); + data = ipset_session_data(session); saved = tmp = strdup(str); if (tmp == NULL) return ipset_err(session, @@ -349,14 +469,54 @@ ipset_parse_proto_port(struct ipset_session *session, a = proto_separator(tmp); if (a != NULL) { + uint8_t family = ipset_data_family(data); + /* proto:port */ *a++ = '\0'; err = ipset_parse_proto(session, IPSET_OPT_PROTO, tmp); if (err) goto error; - tmp = a; + + p = *(const uint8_t *) ipset_data_get(data, IPSET_OPT_PROTO); + switch (p) { + case IPPROTO_TCP: + proto = tmp; + tmp = a; + goto parse_port; + case IPPROTO_UDP: + proto = tmp; + tmp = a; + goto parse_port; + case IPPROTO_ICMP: + if (family != AF_INET) { + 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"); + 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."); + goto error; + } + ipset_data_flags_set(data, IPSET_FLAG(opt)); + } + goto error; + } else { + proto = "TCP"; + err = ipset_data_set(data, IPSET_OPT_PROTO, &p); + if (err) + goto error; } - err = ipset_parse_single_port(session, opt, tmp); +parse_port: + err = ipset_parse_port(session, opt, tmp, proto); error: free(saved); @@ -387,7 +547,8 @@ ipset_parse_family(struct ipset_session *session, data = ipset_session_data(session); if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_FAMILY))) - syntax_err("protocol family may not be specified multiple times"); + syntax_err("protocol family may not be specified " + "multiple times"); if (STREQ(str, "inet") || STREQ(str, "ipv4") || STREQ(str, "-4")) family = AF_INET; @@ -402,12 +563,13 @@ ipset_parse_family(struct ipset_session *session, } /* - * Parse IPv4/IPv6 addresses, networks and ranges + * Parse IPv4/IPv6 addresses, networks and ranges. * We resolve hostnames but just the first IP address is used. */ static struct addrinfo * -get_addrinfo(struct ipset_session *session, const char *str, uint8_t family) +call_getaddrinfo(struct ipset_session *session, const char *str, + uint8_t family) { struct addrinfo hints; struct addrinfo *res; @@ -429,101 +591,96 @@ get_addrinfo(struct ipset_session *session, const char *str, uint8_t family) return res; } -#define GET_ADDRINFO(family, IP, f, n) \ -static int \ -get_addrinfo##f(struct ipset_session *session, \ - const char *str, \ - struct addrinfo **info, \ - struct in##n##_addr **inaddr) \ -{ \ - struct addrinfo *i; \ - struct sockaddr_in##n saddr; \ - int found; \ - \ - if ((*info = get_addrinfo(session, str, family)) == NULL) { \ - syntax_err("cannot parse %s: " IP " resolving failed", \ - str); \ - return EINVAL; \ - } \ - \ - for (i = *info, found = 0; i != NULL; i = i->ai_next) { \ - if (i->ai_family != family \ - || i->ai_addrlen != sizeof(saddr)) \ - continue; \ - if (found == 0) { \ - /* Workaround: can't cast on Sparc */ \ - memcpy(&saddr, i->ai_addr, sizeof(saddr)); \ - *inaddr = &saddr.sin##n##_addr; \ - } else if (found == 1) { \ - ipset_warn(session, \ - "%s resolves to multiple addresses: " \ - "using only the first one returned by the resolver", \ - str); \ - } \ - found++; \ - } \ - if (found == 0) \ - return syntax_err("cannot parse %s: " \ - IP "address could not be resolved", \ - str); \ - return 0; \ +static int +get_addrinfo(struct ipset_session *session, + enum ipset_opt opt, + const char *str, + struct addrinfo **info, + uint8_t family) +{ + struct addrinfo *i; + size_t addrlen = family == AF_INET ? sizeof(struct sockaddr_in) + : sizeof(struct sockaddr_in6); + int found, err = 0; + + if ((*info = call_getaddrinfo(session, str, family)) == NULL) { + syntax_err("cannot parse %s: resolving to %s address failed", + str, family == AF_INET ? "IPv4" : "IPv6"); + return EINVAL; + } + + for (i = *info, found = 0; i != NULL; i = i->ai_next) { + if (i->ai_family != family || i->ai_addrlen != addrlen) + continue; + if (found == 0) { + if (family == AF_INET) { + err = ipset_session_data_set(session, opt, + &((const struct sockaddr_in *)i->ai_addr)->sin_addr); + } else { + err = ipset_session_data_set(session, opt, + &((const struct sockaddr_in6 *)i->ai_addr)->sin6_addr); + } + } else if (found == 1) { + ipset_warn(session, + "%s resolves to multiple addresses: " + "using only the first one returned " + "by the resolver", + str); + } + found++; + } + if (found == 0) + return syntax_err("cannot parse %s: " + "%s address could not be resolved", + str, family == AF_INET ? "IPv4" : "IPv6"); + return err; } -#define PARSE_IP(mask, f, n) \ -static int \ -parse_ipv##f(struct ipset_session *session, \ - enum ipset_opt opt, const char *str) \ -{ \ - uint8_t m = mask; \ - int aerr = EINVAL, err = 0, range = 0; \ - char *saved = strdup(str); \ - char *a, *tmp = saved; \ - struct addrinfo *info; \ - struct in##n##_addr *inaddr; \ - struct ipset_data *data = ipset_session_data(session); \ - enum ipset_opt copt = opt == IPSET_OPT_IP ? IPSET_OPT_CIDR \ - : IPSET_OPT_CIDR2; \ - \ - if (tmp == NULL) \ - return ipset_err(session, \ - "Cannot allocate memory to duplicate %s.",\ - str); \ - if ((a = cidr_separator(tmp)) != NULL) { \ - /* IP/mask */ \ - *a++ = '\0'; \ - \ - if ((err = string_to_cidr(session, a, 0, m, &m)) != 0 \ - || (err = ipset_data_set(data, copt, &m)) != 0) \ - goto out; \ - } else if ((a = range_separator(tmp)) != NULL) { \ - /* IP-IP */ \ - *a++ = '\0'; \ - D("range %s", a); \ - range++; \ - } \ - if ((aerr = get_addrinfo##f(session, tmp, &info, &inaddr)) != 0 \ - || (err = ipset_data_set(data, opt, inaddr)) != 0 \ - || !range) \ - goto out; \ - freeaddrinfo(info); \ - if ((aerr = get_addrinfo##f(session, a, &info, &inaddr)) == 0) \ - err = ipset_data_set(data, IPSET_OPT_IP_TO, inaddr); \ - \ -out: \ - if (aerr != EINVAL) \ - /* getaddrinfo not failed */ \ - freeaddrinfo(info); \ - else if (aerr) \ - err = -1; \ - free(saved); \ - return err; \ -} +static int +parse_ipaddr(struct ipset_session *session, + enum ipset_opt opt, const char *str, + uint8_t family) +{ + uint8_t m = family == AF_INET ? 32 : 128; + int aerr = EINVAL, err = 0, range = 0; + char *saved = strdup(str); + char *a, *tmp = saved; + struct addrinfo *info; + enum ipset_opt copt = opt == IPSET_OPT_IP ? IPSET_OPT_CIDR + : IPSET_OPT_CIDR2; -GET_ADDRINFO(AF_INET, "IPv4", 4, ) -PARSE_IP(32, 4, ) + if (tmp == NULL) + return ipset_err(session, + "Cannot allocate memory to duplicate %s.", + str); + if ((a = cidr_separator(tmp)) != NULL) { + /* IP/mask */ + *a++ = '\0'; -GET_ADDRINFO(AF_INET6, "IPv6", 6, 6) -PARSE_IP(128, 6, 6) + 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 */ + *a++ = '\0'; + D("range %s", a); + range++; + } + if ((aerr = get_addrinfo(session, opt, tmp, &info, family)) != 0 + || !range) + goto out; + freeaddrinfo(info); + aerr = get_addrinfo(session, IPSET_OPT_IP_TO, a, &info, family); + +out: + if (aerr != EINVAL) + /* getaddrinfo not failed */ + freeaddrinfo(info); + else if (aerr) + err = -1; + free(saved); + return err; +} enum ipaddr_type { IPADDR_ANY, @@ -536,7 +693,6 @@ static int parse_ip(struct ipset_session *session, enum ipset_opt opt, const char *str, enum ipaddr_type addrtype) { - int err = 0; struct ipset_data *data = ipset_session_data(session); uint8_t family = ipset_data_family(data); @@ -566,12 +722,7 @@ parse_ip(struct ipset_session *session, break; } - if (family == AF_INET) - err = parse_ipv4(session, opt, str); - else - err = parse_ipv6(session, opt, str); - - return err; + return parse_ipaddr(session, opt, str, family); } /** diff --git a/lib/print.c b/lib/print.c index 77c283a..87a9f2b 100644 --- a/lib/print.c +++ b/lib/print.c @@ -15,6 +15,8 @@ #include <libipset/debug.h> /* D() */ #include <libipset/data.h> /* ipset_data_* */ +#include <libipset/icmp.h> /* icmp_to_name */ +#include <libipset/icmpv6.h> /* icmpv6_to_name */ #include <libipset/parse.h> /* IPSET_*_SEPARATOR */ #include <libipset/types.h> /* ipset set types */ #include <libipset/session.h> /* IPSET_FLAG_ */ @@ -463,8 +465,6 @@ ipset_print_proto(char *buf, unsigned int len, proto = *(const uint8_t *) ipset_data_get(data, IPSET_OPT_PROTO); assert(proto); - if (proto == IPSET_IPPROTO_ANY) - return snprintf(buf, len, "any"); protoent = getprotobynumber(proto); if (protoent) return snprintf(buf, len, "%s", protoent->p_name); @@ -474,6 +474,72 @@ ipset_print_proto(char *buf, unsigned int len, } /** + * ipset_print_icmp - print ICMP code name or type/code + * @buf: printing buffer + * @len: length of available buffer space + * @data: data blob + * @opt: the option kind + * @env: environment flags + * + * Print ICMP code name or type/code name to output buffer. + * + * Return lenght of printed string or error size. + */ +int +ipset_print_icmp(char *buf, unsigned int len, + const struct ipset_data *data, enum ipset_opt opt, + uint8_t env UNUSED) +{ + const char *name; + uint16_t typecode; + + assert(buf); + assert(len > 0); + assert(data); + assert(opt == IPSET_OPT_PORT); + + typecode = *(const uint16_t *) ipset_data_get(data, IPSET_OPT_PORT); + name = icmp_to_name(typecode >> 8, typecode & 0xFF); + if (name != NULL) + return snprintf(buf, len, "%s", name); + else + return snprintf(buf, len, "%u/%u", typecode >> 8, typecode & 0xFF); +} + +/** + * ipset_print_icmpv6 - print ICMPv6 code name or type/code + * @buf: printing buffer + * @len: length of available buffer space + * @data: data blob + * @opt: the option kind + * @env: environment flags + * + * Print ICMPv6 code name or type/code name to output buffer. + * + * Return lenght of printed string or error size. + */ +int +ipset_print_icmpv6(char *buf, unsigned int len, + const struct ipset_data *data, enum ipset_opt opt, + uint8_t env UNUSED) +{ + const char *name; + uint16_t typecode; + + assert(buf); + assert(len > 0); + assert(data); + assert(opt == IPSET_OPT_PORT); + + typecode = *(const uint16_t *) ipset_data_get(data, IPSET_OPT_PORT); + name = icmpv6_to_name(typecode >> 8, typecode & 0xFF); + if (name != NULL) + return snprintf(buf, len, "%s", name); + else + return snprintf(buf, len, "%u/%u", typecode >> 8, typecode & 0xFF); +} + +/** * ipset_print_proto_port - print proto:port * @buf: printing buffer * @len: length of available buffer space @@ -498,14 +564,33 @@ ipset_print_proto_port(char *buf, unsigned int len, assert(opt == IPSET_OPT_PORT); if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_PROTO))) { + uint8_t proto = *(const uint8_t *) ipset_data_get(data, + IPSET_OPT_PROTO); size = ipset_print_proto(buf, len, data, IPSET_OPT_PROTO, env); SNPRINTF_FAILURE(size, len, offset); if (len < 2) return -ENOSPC; - strcat(buf, ":"); - SNPRINTF_FAILURE(1, len, offset); + size = snprintf(buf + offset, len, IPSET_PROTO_SEPARATOR); + SNPRINTF_FAILURE(size, len, offset); + + switch (proto) { + case IPPROTO_TCP: + case IPPROTO_UDP: + break; + case IPPROTO_ICMP: + return ipset_print_icmp(buf + offset, len, data, + IPSET_OPT_PORT, env); + case IPPROTO_ICMPV6: + return ipset_print_icmpv6(buf + offset, len, data, + IPSET_OPT_PORT, env); + default: + break; + } } - return ipset_print_port(buf + offset, len, data, IPSET_OPT_PORT, env); + size = ipset_print_port(buf + offset, len, data, IPSET_OPT_PORT, env); + SNPRINTF_FAILURE(size, len, offset); + + return offset; } #define print_second(data) \ diff --git a/lib/session.c b/lib/session.c index 8a0493a..ba4e458 100644 --- a/lib/session.c +++ b/lib/session.c @@ -319,11 +319,11 @@ const struct ipset_attr_policy cmd_attrs[] = { const struct ipset_attr_policy create_attrs[] = { [IPSET_ATTR_IP] = { - .type = MNL_TYPE_BINARY, + .type = MNL_TYPE_NESTED, .opt = IPSET_OPT_IP, }, [IPSET_ATTR_IP_TO] = { - .type = MNL_TYPE_BINARY, + .type = MNL_TYPE_NESTED, .opt = IPSET_OPT_IP_TO, }, [IPSET_ATTR_CIDR] = { @@ -394,11 +394,11 @@ const struct ipset_attr_policy create_attrs[] = { const struct ipset_attr_policy adt_attrs[] = { [IPSET_ATTR_IP] = { - .type = MNL_TYPE_BINARY, + .type = MNL_TYPE_NESTED, .opt = IPSET_OPT_IP, }, [IPSET_ATTR_IP_TO] = { - .type = MNL_TYPE_BINARY, + .type = MNL_TYPE_NESTED, .opt = IPSET_OPT_IP_TO, }, [IPSET_ATTR_CIDR] = { @@ -445,7 +445,7 @@ const struct ipset_attr_policy adt_attrs[] = { .len = IPSET_MAXNAMELEN, }, [IPSET_ATTR_IP2] = { - .type = MNL_TYPE_BINARY, + .type = MNL_TYPE_NESTED, .opt = IPSET_OPT_IP2, }, [IPSET_ATTR_CIDR2] = { @@ -454,6 +454,61 @@ const struct ipset_attr_policy adt_attrs[] = { }, }; +const struct ipset_attr_policy ipaddr_attrs[] = { + [IPSET_ATTR_IPADDR_IPV4] = { + .type = MNL_TYPE_U32, + }, + [IPSET_ATTR_IPADDR_IPV6] = { + .type = MNL_TYPE_BINARY, + .len = sizeof(union nf_inet_addr), + }, +}; + +static int +generic_data_attr_cb(const struct nlattr *attr, void *data, + int attr_max, const struct ipset_attr_policy *policy) +{ + const struct nlattr **tb = (const struct nlattr **)data; + int type = mnl_attr_get_type(attr); + + D("attr type: %u, len %u", type, attr->nla_len); + if (mnl_attr_type_valid(attr, attr_max) < 0) { + D("attr type: %u INVALID", type); + return MNL_CB_ERROR; + } + if (mnl_attr_validate(attr, policy[type].type) < 0) { + D("attr type: %u POLICY, attrlen %u", type, + 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) + return MNL_CB_ERROR; + tb[type] = attr; + return MNL_CB_OK; +} + +static int +create_attr_cb(const struct nlattr *attr, void *data) +{ + return generic_data_attr_cb(attr, data, + IPSET_ATTR_CREATE_MAX, create_attrs); +} + +static int +adt_attr_cb(const struct nlattr *attr, void *data) +{ + return generic_data_attr_cb(attr, data, + IPSET_ATTR_ADT_MAX, adt_attrs); +} + +static int +ipaddr_attr_cb(const struct nlattr *attr, void *data) +{ + return generic_data_attr_cb(attr, data, + IPSET_ATTR_IPADDR_MAX, ipaddr_attrs); +} + #define FAILURE(format, args...) \ { ipset_err(session, format , ## args); return MNL_CB_ERROR; } @@ -469,26 +524,45 @@ attr2data(struct ipset_session *session, struct nlattr *nla[], attr = &attrs[type]; d = mnl_attr_get_payload(nla[type]); - if (attr->type == MNL_TYPE_BINARY && !attr->len) { + if (attr->type == MNL_TYPE_NESTED && attr->opt) { + /* IP addresses */ + struct nlattr *ipattr[IPSET_ATTR_IPADDR_MAX+1] = {}; uint8_t family = ipset_data_family(data); + int atype; + D("attr type %u", type); + if (mnl_attr_parse_nested(nla[type], + ipaddr_attr_cb, ipattr) < 0) + FAILURE("Broken kernel message, cannot validate " + "IP address attribute!"); /* Validate by hand */ switch (family) { case AF_INET: - if (nla[type]->nla_len < sizeof(uint32_t)) + atype = IPSET_ATTR_IPADDR_IPV4; + if (!ipattr[atype]) + FAILURE("Broken kernel message: IPv4 address " + "expected but not received!"); + if (ipattr[atype]->nla_len < sizeof(uint32_t)) FAILURE("Broken kernel message: " - "cannot validate IPv4 address attribute!"); + "cannot validate IPv4 " + "address attribute!"); break; case AF_INET6: - if (nla[type]->nla_len < sizeof(struct in6_addr)) + atype = IPSET_ATTR_IPADDR_IPV6; + if (!ipattr[atype]) + FAILURE("Broken kernel message: IPv6 address " + "expected but not received!"); + if (ipattr[atype]->nla_len < sizeof(struct in6_addr)) FAILURE("Broken kernel message: " - "cannot validate IPv6 address attribute!"); + "cannot validate IPv6 " + "address attribute!"); break; default: FAILURE("Broken kernel message: " "IP address attribute but " "family is unspecified!"); } + d = mnl_attr_get_payload(ipattr[atype]); } else if (nla[type]->nla_type & NLA_F_NET_BYTEORDER) { switch (attr->type) { case MNL_TYPE_U32: { @@ -744,7 +818,8 @@ 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)) + || (arg->opt == IPSET_OPT_FAMILY + && family == type->family)) continue; switch (session->mode) { case IPSET_LIST_SAVE: @@ -820,44 +895,6 @@ print_set_done(struct ipset_session *session) } static int -generic_data_attr_cb(const struct nlattr *attr, void *data, - int attr_max, const struct ipset_attr_policy *policy) -{ - const struct nlattr **tb = (const struct nlattr **)data; - int type = mnl_attr_get_type(attr); - - D("attr type: %u, len %u", type, attr->nla_len); - if (mnl_attr_type_valid(attr, attr_max) < 0) { - D("attr type: %u INVALID", type); - return MNL_CB_ERROR; - } - if (mnl_attr_validate(attr, policy[type].type) < 0) { - D("attr type: %u POLICY, attrlen %u", type, - 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) - return MNL_CB_ERROR; - tb[type] = attr; - return MNL_CB_OK; -} - -static int -create_attr_cb(const struct nlattr *attr, void *data) -{ - return generic_data_attr_cb(attr, data, - IPSET_ATTR_CREATE_MAX, create_attrs); -} - -static int -adt_attr_cb(const struct nlattr *attr, void *data) -{ - return generic_data_attr_cb(attr, data, - IPSET_ATTR_ADT_MAX, adt_attrs); -} - -static int callback_list(struct ipset_session *session, struct nlattr *nla[], enum ipset_cmd cmd) { @@ -1291,7 +1328,7 @@ static size_t attr_len(const struct ipset_attr_policy *attr, uint8_t family, uint16_t *flags) { switch (attr->type) { - case MNL_TYPE_BINARY: + case MNL_TYPE_NESTED: if (attr->len) return attr->len; @@ -1325,6 +1362,19 @@ rawdata2attr(struct nlmsghdr *nlh, alen = attr_len(attr, family, &flags); switch (attr->type) { + case MNL_TYPE_NESTED: { + /* IP addresses */ + struct nlattr *nested = mnl_attr_nest_start(nlh, type); + int atype = family == AF_INET ? IPSET_ATTR_IPADDR_IPV4 + : IPSET_ATTR_IPADDR_IPV6; + + D("family: %s", family == AF_INET ? "INET" : + family == AF_INET6 ? "INET6" : "UNSPEC"); + mnl_attr_put(nlh, atype | flags, alen, d); + mnl_attr_nest_end(nlh, nested); + + return 0; + } case MNL_TYPE_U32: { uint32_t value = htonl(*(const uint32_t *)d); @@ -1510,7 +1560,8 @@ build_msg(struct ipset_session *session, bool aggregate) ADDATTR(nlh, data, IPSET_ATTR_TYPENAME, AF_INET, cmd_attrs); ADDATTR_RAW(nlh, &type->revision, IPSET_ATTR_REVISION, cmd_attrs); - D("family: %u", ipset_data_family(data)); + D("family: %u, type family %u", + ipset_data_family(data), type->family); ADDATTR(nlh, data, IPSET_ATTR_FAMILY, AF_INET, cmd_attrs); /* Type-specific create attributes */ @@ -1568,8 +1619,10 @@ build_msg(struct ipset_session *session, bool aggregate) } } type = ipset_data_get(data, IPSET_OPT_TYPE); + D("family: %u, type family %u", + ipset_data_family(data), type->family); open_nested(session, nlh, IPSET_ATTR_DATA); - addattr_adt(nlh, data, type->family); + addattr_adt(nlh, data, ipset_data_family(data)); ADDATTR_RAW(nlh, &session->lineno, IPSET_ATTR_LINENO, cmd_attrs); close_nested(session, nlh); @@ -1590,9 +1643,11 @@ build_msg(struct ipset_session *session, bool aggregate) "Invalid test command: missing settype"); type = ipset_data_get(data, IPSET_OPT_TYPE); + D("family: %u, type family %u", + ipset_data_family(data), type->family); ADDATTR_SETNAME(nlh, data); open_nested(session, nlh, IPSET_ATTR_DATA); - addattr_adt(nlh, data, type->family); + addattr_adt(nlh, data, ipset_data_family(data)); close_nested(session, nlh); break; } diff --git a/lib/types.c b/lib/types.c index e3cad35..3d9b034 100644 --- a/lib/types.c +++ b/lib/types.c @@ -11,6 +11,7 @@ #include <sys/socket.h> /* AF_ */ #include <stdlib.h> /* malloc, free */ #include <stdio.h> /* FIXME: debug */ +#include <libmnl/libmnl.h> /* MNL_ALIGN */ #include <libipset/debug.h> /* D() */ #include <libipset/data.h> /* ipset_data_* */ @@ -438,14 +439,25 @@ type_max_size(struct ipset_type *type, uint8_t family) continue; if (!(IPSET_FLAG(opt) & type->full[IPSET_ADD])) continue; - max += ipset_data_sizeof(opt, family); + max += MNL_ALIGN(ipset_data_sizeof(opt, family)) + + MNL_ATTR_HDRLEN; + switch (opt) { + case IPSET_OPT_IP: + case IPSET_OPT_IP_TO: + case IPSET_OPT_IP2: + /* Nested attributes */ + max += MNL_ATTR_HDRLEN; + break; + default: + break; + } } type->maxsize[sizeid] = max; } /** * ipset_type_add - add (register) a userspace set type - * @type: set type structure + * @type: pointer to the set type structure * * Add the given set type to the type list. The types * are added sorted, in descending revision number. diff --git a/netlink.patch b/netlink.patch index 344cfc8..b651d44 100644 --- a/netlink.patch +++ b/netlink.patch @@ -12,75 +12,3 @@ index 9f00da2..9f51ff6 100644 #ifdef __KERNEL__ -diff --git a/include/linux/netlink.h b/include/linux/netlink.h -index ab5d312..ef8b229 100644 ---- a/include/linux/netlink.h -+++ b/include/linux/netlink.h -@@ -263,11 +263,14 @@ __nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags) - #define NLMSG_PUT(skb, pid, seq, type, len) \ - NLMSG_NEW(skb, pid, seq, type, len, 0) - --extern int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, -- const struct nlmsghdr *nlh, -- int (*dump)(struct sk_buff *skb, struct netlink_callback*), -- int (*done)(struct netlink_callback*)); -- -+extern int netlink_dump_init(struct sock *ssk, struct sk_buff *skb, -+ const struct nlmsghdr *nlh, -+ int (*dump)(struct sk_buff *skb, struct netlink_callback*), -+ int (*done)(struct netlink_callback*), -+ unsigned char init, ...); -+ -+#define netlink_dump_start(ssk, skb, nlh, dump, done) \ -+ netlink_dump_init(ssk, skb, nlh, dump, done, 0) - - #define NL_NONROOT_RECV 0x1 - #define NL_NONROOT_SEND 0x2 -diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c -index 19e9800..7d85d45 100644 ---- a/net/netlink/af_netlink.c -+++ b/net/netlink/af_netlink.c -@@ -1714,15 +1714,18 @@ errout: - return err; - } - --int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, -- const struct nlmsghdr *nlh, -- int (*dump)(struct sk_buff *skb, -- struct netlink_callback *), -- int (*done)(struct netlink_callback *)) -+int netlink_dump_init(struct sock *ssk, struct sk_buff *skb, -+ const struct nlmsghdr *nlh, -+ int (*dump)(struct sk_buff *skb, -+ struct netlink_callback *), -+ int (*done)(struct netlink_callback *), -+ unsigned char init, ...) - { - struct netlink_callback *cb; - struct sock *sk; - struct netlink_sock *nlk; -+ va_list args; -+ unsigned char i; - - cb = kzalloc(sizeof(*cb), GFP_KERNEL); - if (cb == NULL) -@@ -1733,6 +1736,10 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, - cb->nlh = nlh; - atomic_inc(&skb->users); - cb->skb = skb; -+ va_start(args, init); -+ for (i = 0; i < init; i++) -+ cb->args[i] = va_arg(args, long); -+ va_end(args); - - sk = netlink_lookup(sock_net(ssk), ssk->sk_protocol, NETLINK_CB(skb).pid); - if (sk == NULL) { -@@ -1759,7 +1766,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, - */ - return -EINTR; - } --EXPORT_SYMBOL(netlink_dump_start); -+EXPORT_SYMBOL(netlink_dump_init); - - void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) - { diff --git a/netlink.patch-2.6.31.1 b/netlink.patch-2.6.31.1 deleted file mode 100644 index 2caed0b..0000000 --- a/netlink.patch-2.6.31.1 +++ /dev/null @@ -1,86 +0,0 @@ -diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h -index 9f00da2..9f51ff6 100644 ---- a/include/linux/netfilter/nfnetlink.h -+++ b/include/linux/netfilter/nfnetlink.h -@@ -47,7 +47,8 @@ struct nfgenmsg { - #define NFNL_SUBSYS_QUEUE 3 - #define NFNL_SUBSYS_ULOG 4 - #define NFNL_SUBSYS_OSF 5 --#define NFNL_SUBSYS_COUNT 6 -+#define NFNL_SUBSYS_IPSET 6 -+#define NFNL_SUBSYS_COUNT 7 - - #ifdef __KERNEL__ - -diff --git a/include/linux/netlink.h b/include/linux/netlink.h -index ab5d312..ef8b229 100644 ---- a/include/linux/netlink.h -+++ b/include/linux/netlink.h -@@ -263,11 +263,14 @@ __nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags) - #define NLMSG_PUT(skb, pid, seq, type, len) \ - NLMSG_NEW(skb, pid, seq, type, len, 0) - --extern int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, -- struct nlmsghdr *nlh, -- int (*dump)(struct sk_buff *skb, struct netlink_callback*), -- int (*done)(struct netlink_callback*)); -- -+extern int netlink_dump_init(struct sock *ssk, struct sk_buff *skb, -+ struct nlmsghdr *nlh, -+ int (*dump)(struct sk_buff *skb, struct netlink_callback*), -+ int (*done)(struct netlink_callback*), -+ unsigned char init, ...); -+ -+#define netlink_dump_start(ssk, skb, nlh, dump, done) \ -+ netlink_dump_init(ssk, skb, nlh, dump, done, 0) - - #define NL_NONROOT_RECV 0x1 - #define NL_NONROOT_SEND 0x2 -diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c -index 19e9800..7d85d45 100644 ---- a/net/netlink/af_netlink.c -+++ b/net/netlink/af_netlink.c -@@ -1714,15 +1714,18 @@ errout: - return err; - } - --int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, -- struct nlmsghdr *nlh, -- int (*dump)(struct sk_buff *skb, -- struct netlink_callback *), -- int (*done)(struct netlink_callback *)) -+int netlink_dump_init(struct sock *ssk, struct sk_buff *skb, -+ struct nlmsghdr *nlh, -+ int (*dump)(struct sk_buff *skb, -+ struct netlink_callback *), -+ int (*done)(struct netlink_callback *), -+ unsigned char init, ...) - { - struct netlink_callback *cb; - struct sock *sk; - struct netlink_sock *nlk; -+ va_list args; -+ unsigned char i; - - cb = kzalloc(sizeof(*cb), GFP_KERNEL); - if (cb == NULL) -@@ -1733,6 +1736,10 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, - cb->nlh = nlh; - atomic_inc(&skb->users); - cb->skb = skb; -+ va_start(args, init); -+ for (i = 0; i < init; i++) -+ cb->args[i] = va_arg(args, long); -+ va_end(args); - - sk = netlink_lookup(sock_net(ssk), ssk->sk_protocol, NETLINK_CB(skb).pid); - if (sk == NULL) { -@@ -1759,7 +1766,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, - */ - return -EINTR; - } --EXPORT_SYMBOL(netlink_dump_start); -+EXPORT_SYMBOL(netlink_dump_init); - - void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) - { diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..6166aba --- /dev/null +++ b/src/.gitignore @@ -0,0 +1 @@ +/ipset diff --git a/src/Makefile.am b/src/Makefile.am index ebd08a3..ce7de24 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,6 +11,7 @@ ipset_SOURCES = ipset.c \ ipset_hash_ipportip.c \ ipset_hash_ipportnet.c \ ipset_hash_net.c \ + ipset_hash_netport.c \ ipset_list_set.c \ ui.c ipset_LDADD = ../lib/libipset.la diff --git a/src/errcode.c b/src/errcode.c index ae0d8c8..313c500 100644 --- a/src/errcode.c +++ b/src/errcode.c @@ -32,7 +32,8 @@ static const struct ipset_errcode_table core_errcode_table[] = { { IPSET_ERR_FIND_TYPE, 0, "Kernel error received: set type does not supported" }, { IPSET_ERR_MAX_SETS, 0, - "Kernel error received: maximal number of sets reached, cannot create more." }, + "Kernel error received: maximal number of sets reached, " + "cannot create more." }, { IPSET_ERR_INVALID_NETMASK, 0, "The value of the netmask parameter is invalid" }, { IPSET_ERR_INVALID_FAMILY, 0, @@ -63,6 +64,10 @@ static const struct ipset_errcode_table core_errcode_table[] = { "The value of the CIDR parameter of the IP address is invalid" }, { IPSET_ERR_TIMEOUT, 0, "Timeout cannot be used: set was created without timeout support" }, + { IPSET_ERR_IPADDR_IPV4, 0, + "An IPv4 address is expected, but not received" }, + { IPSET_ERR_IPADDR_IPV6, 0, + "An IPv6 address is expected, but not received" }, /* ADD specific error codes */ { IPSET_ERR_EXIST, IPSET_CMD_ADD, @@ -119,23 +124,25 @@ static const struct ipset_errcode_table list_errcode_table[] = { { IPSET_ERR_BEFORE, 0, "No reference set specified." }, { IPSET_ERR_NAMEREF, 0, - "The set to which you referred with 'before' or 'after' does not exist." }, + "The set to which you referred with 'before' or 'after' " + "does not exist." }, { IPSET_ERR_LIST_FULL, 0, "The set is full, more elements cannot be added." }, { IPSET_ERR_REF_EXIST, 0, - "The set to which you referred with 'before' or 'after' is not added to the set." }, + "The set to which you referred with 'before' or 'after' " + "is not added to the set." }, { }, }; #define MATCH_TYPENAME(a, b) STRNEQ(a, b, strlen(b)) /** - * ipset_errcode - interpret an error code + * ipset_errcode - interpret a kernel error code * @session: session structure * @errcode: errcode * * Find the error code and print the appropriate - * error message. + * error message into the error buffer. * * Returns -1. */ @@ -182,5 +189,6 @@ retry: strerror(errcode)); else return ipset_err(session, - "Undecoded error %u received from kernel", errcode); + "Undecoded error %u received from kernel", + errcode); } diff --git a/src/ipset.8 b/src/ipset.8 index c4f6a6b..2169c36 100644 --- a/src/ipset.8 +++ b/src/ipset.8 @@ -13,7 +13,7 @@ .\" You should have received a copy of the GNU General Public License .\" along with this program; if not, write to the Free Software .\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -.TH "IPSET" "8" "Jun 11, 2010" "Jozsef Kadlecsik" "" +.TH "IPSET" "8" "Oct 15, 2010" "Jozsef Kadlecsik" "" .SH "NAME" ipset \(em administration tool for IP sets .SH "SYNOPSIS" @@ -82,7 +82,7 @@ type specific options. If the \fB\-exist\fR option is specified, \fBipset\fR -ignores the error otherwise raised when the the same set (setname and create parameters +ignores the error otherwise raised when the same set (setname and create parameters are identical) already exists. .TP \fBadd\fP \fISETNAME\fP \fIADD\-ENTRY\fP [ \fIADD\-OPTIONS\fP ] @@ -97,7 +97,7 @@ Delete an entry from a set. If the \fB\-exist\fR option is specified, \fBipset\fR -ignores if the entry does not added (expired) to the set. +ignores if the entry does not added to (already expired from) the set. .TP \fBtest\fP \fISETNAME\fP \fITEST\-ENTRY\fP [ \fITEST\-OPTIONS\fP ] Test wether an entry is in a set or not. Exit status number is zero @@ -230,19 +230,19 @@ The \fBbitmap:ip\fR set type uses a memory range to store either IPv4 host (default) or IPv4 network addresses. A \fBbitmap:ip\fR type of set can store up to 65536 entries. .PP -\fICREATE\-OPTIONS\fR := \fBrange\fP \fIfrom\-ip\fP\-\fIto\-ip\fR|\fIip\fR/\fIcidr\fR [ \fBnetmask\fP \fIcidr\fP ] [ \fBtimeout\fR \fIvalue\fR ] +\fICREATE\-OPTIONS\fR := \fBrange\fP \fIfromip\fP\-\fItoip\fR|\fIip\fR/\fIcidr\fR [ \fBnetmask\fP \fIcidr\fP ] [ \fBtimeout\fR \fIvalue\fR ] .PP -\fIADD\-ENTRY\fR := { \fIipaddr\fR | \fIfromaddr\fR\-\fItoaddr\fR | \fIipaddr\fR/\fIcidr\fR } +\fIADD\-ENTRY\fR := { \fIipaddr\fR | \fIfromip\fR\-\fItoip\fR | \fIipaddr\fR/\fIcidr\fR } .PP \fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ] .PP -\fIDEL\-ENTRY\fR := { \fIipaddr\fR | \fIfromaddr\fR\-\fItoaddr\fR | \fIipaddr\fR/\fIcidr\fR } +\fIDEL\-ENTRY\fR := { \fIipaddr\fR | \fIfromip\fR\-\fItoip\fR | \fIipaddr\fR/\fIcidr\fR } .PP \fITEST\-ENTRY\fR := \fIipaddr\fR .PP Mandatory \fBcreate\fR options: .TP -\fBrange\fP \fIfrom\-ip\fP\-\fIto\-ip\fR|\fIip\fR/\fIcidr\fR +\fBrange\fP \fIfromip\fP\-\fItoip\fR|\fIip\fR/\fIcidr\fR Create the set from the specified inclusive address range expressed in an IPv4 address range or network. The size of the range (in entries) cannot exceed the limit of maximum 65536 elements. @@ -251,10 +251,10 @@ Optional \fBcreate\fR options: .TP \fBnetmask\fP \fIcidr\fP When the optional \fBnetmask\fP parameter specified, network addresses will be -stored in the set instead of IP host addresses. The \fIcidr\fR value must be +stored in the set instead of IP host addresses. The \fIcidr\fR prefix value must be between 1\-32. An IP address will be in the set if the network address, which is resulted by -masking the address with the specified netmask calculated from the cidr value, +masking the address with the specified netmask calculated from the prefix, can be found in the set. .PP The \fBbitmap:ip\fR type supports adding or deleting multiple entries in one @@ -270,19 +270,19 @@ ipset test foo 192.168.1.1 .SS bitmap:ip,mac The \fBbitmap:ip,mac\fR set type uses a memory range to store IPv4 and a MAC address pairs. A \fBbitmap:ip,mac\fR type of set can store up to 65536 entries. .PP -\fICREATE\-OPTIONS\fR := \fBrange\fP \fIfrom\-ip\fP\-\fIto\-ip\fR|\fIip\fR/\fIcidr\fR [ \fBtimeout\fR \fIvalue\fR ] +\fICREATE\-OPTIONS\fR := \fBrange\fP \fIfromip\fP\-\fItoip\fR|\fIip\fR/\fIcidr\fR [ \fBtimeout\fR \fIvalue\fR ] .PP -\fIADD\-ENTRY\fR := \fIipaddr\fR[,\fImac\-addr\fR] +\fIADD\-ENTRY\fR := \fIipaddr\fR[,\fImacaddr\fR] .PP \fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ] .PP -\fIDEL\-ENTRY\fR := \fIipaddr\fR[,\fImac\-addr\fR] +\fIDEL\-ENTRY\fR := \fIipaddr\fR[,\fImacaddr\fR] .PP -\fITEST\-ENTRY\fR := \fIipaddr\fR[,\fImac\-addr\fR] +\fITEST\-ENTRY\fR := \fIipaddr\fR[,\fImacaddr\fR] .PP Mandatory options to use when creating a \fBbitmap:ip,mac\fR type of set: .TP -\fBrange\fP \fIfrom\-ip\fP\-\fIto\-ip\fR|\fIip\fR/\fIcidr\fR +\fBrange\fP \fIfromip\fP\-\fItoip\fR|\fIip\fR/\fIcidr\fR Create the set from the specified inclusive address range expressed in an IPv4 address range or network. The size of the range cannot exceed the limit of maximum 65536 entries. @@ -309,19 +309,19 @@ ipset test foo 192.168.1.1 The \fBbitmap:port\fR set type uses a memory range to store port numbers and such a set can store up to 65536 ports. .PP -\fICREATE\-OPTIONS\fR := \fBrange\fP \fIfrom\-port\fP\-\fIto\-port [ \fBtimeout\fR \fIvalue\fR ] +\fICREATE\-OPTIONS\fR := \fBrange\fP \fIfromport\fP\-\fItoport [ \fBtimeout\fR \fIvalue\fR ] .PP -\fIADD\-ENTRY\fR := { \fIport\fR | \fIfrom\-port\fR\-\fIto\-port\fR } +\fIADD\-ENTRY\fR := { \fIport\fR | \fIfromport\fR\-\fItoport\fR } .PP \fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ] .PP -\fIDEL\-ENTRY\fR := { \fIport\fR | \fIfrom\-port\fR\-\fIto\-port\fR } +\fIDEL\-ENTRY\fR := { \fIport\fR | \fIfromport\fR\-\fItoport\fR } .PP \fITEST\-ENTRY\fR := \fIport\fR .PP Mandatory options to use when creating a \fBbitmap:port\fR type of set: .TP -\fBrange\fP \fIfrom\-port\fP\-\fIto\-port\fR +\fBrange\fP \fIfromport\fP\-\fItoport\fR Create the set from the specified inclusive port range. .PP Examples: @@ -368,10 +368,10 @@ The maximal number of elements which can be stored in the set, default 65536. .TP \fBnetmask\fP \fIcidr\fP When the optional \fBnetmask\fP parameter specified, network addresses will be -stored in the set instead of IP host addresses. The \fIcidr\fP value must be +stored in the set instead of IP host addresses. The \fIcidr\fP prefix value must be between 1\-32 for IPv4 and between 1\-128 for IPv6. An IP address will be in the set if the network address, which is resulted by masking the address with the netmask -calculated from the cidr, can be found in the set. +calculated from the prefix, can be found in the set. .PP Examples: .IP @@ -407,18 +407,18 @@ correct value. \fBmaxelem\fR \fIvalue\fR The maximal number of elements which can be stored in the set, default 65536. .PP -When adding/deleting/testing entries, if the cidr parameter is not specified, -then the host cidr value is assumed. When adding/deleting entries, overlapping elements -are not checked. +When adding/deleting/testing entries, if the cidr prefix parameter is not specified, +then the host prefix value is assumed. When adding/deleting entries, overlapping +elements are not checked. .PP From the \fBset\fR netfilter match point of view an IP address will be in a \fBhash:net\fR type of set if it belongs to any of the netblocks added to the set. The matching always start from the smallest size of netblock (most specific -cidr) to the largest ones (least specific cidr). When adding/deleting IP +prefix) to the largest ones (least specific prefix). When adding/deleting IP addresses to the set by the \fBSET\fR netfilter target, it will be -added/deleted by the most specific cidr which can be found in the -set, or by the host cidr value if the set is empty. +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 lookup time grows linearly with the number of the different \fIcidr\fR +The lookup time grows linearly with the number of the different prefix values added to the set. .PP Examples: @@ -626,10 +626,12 @@ the match and target will skip any set in \fIa\fR and \fIb\fR which stores data triples, but will match all sets with single or double data storage in \fIa\fR set and stop matching at the first successful set, and add src to the first single or src,dst to the first double data storage set -in \fIb\fR to which the entry can be added. +in \fIb\fR to which the entry can be added. You can imagine a \fBlist:set\fR +type of set as an ordered union of the set elements. .PP -You can imagine a setlist type of set as an ordered union of -the set elements. +Please note: by the \fBipset\fR commad you can add, delete and \fBtest\fR +the setnames in a \fBlist:set\fR type of set, and \fBnot\fR the presence of +a set's member (such as an IP address). .SH "GENERAL RESTRICTIONS" Zero valued set entries cannot be used with hash methods. Zero protocol value with ports cannot be used. diff --git a/src/ipset.c b/src/ipset.c index c613b24..c55bf59 100644 --- a/src/ipset.c +++ b/src/ipset.c @@ -38,10 +38,10 @@ extern struct ipset_type ipset_bitmap_ipmac0; extern struct ipset_type ipset_bitmap_port0; extern struct ipset_type ipset_hash_ip0; extern struct ipset_type ipset_hash_net0; +extern struct ipset_type ipset_hash_netport0; extern struct ipset_type ipset_hash_ipport0; extern struct ipset_type ipset_hash_ipportip0; extern struct ipset_type ipset_hash_ipportnet0; -extern struct ipset_type ipset_tree_ip0; extern struct ipset_type ipset_list_set0; enum exittype { @@ -213,7 +213,8 @@ call_parser(int *argc, char *argv[], const struct ipset_arg *args) goto done; for (arg = args; arg->opt; arg++) { for (i = 1; i < *argc; ) { - D("argc: %u, i: %u: %s vs %s", *argc, i, argv[i], arg->name[0]); + D("argc: %u, i: %u: %s vs %s", + *argc, i, argv[i], arg->name[0]); if (!(ipset_match_option(argv[i], arg->name))) { i++; continue; @@ -227,7 +228,8 @@ call_parser(int *argc, char *argv[], const struct ipset_arg *args) case IPSET_MANDATORY_ARG: if (i + 1 > *argc) return exit_error(PARAMETER_PROBLEM, - "Missing mandatory argument of option `%s'", + "Missing mandatory argument " + "of option `%s'", arg->name[0]); /* Fall through */ case IPSET_OPTIONAL_ARG: @@ -276,7 +278,8 @@ check_mandatory(const struct ipset_type *type, int cmd) return; if (!arg) { exit_error(OTHER_PROBLEM, - "There are missing mandatory flags but can't check them. " + "There are missing mandatory flags " + "but can't check them. " "It's a bug, please report the problem."); return; } @@ -354,7 +357,8 @@ parse_commandline(int argc, char *argv[]) case IPSET_MANDATORY_ARG: if (i + 1 > argc) return exit_error(PARAMETER_PROBLEM, - "Missing mandatory argument to option %s", + "Missing mandatory argument " + "to option %s", opt->name[0]); /* Fall through */ case IPSET_OPTIONAL_ARG: @@ -392,10 +396,13 @@ parse_commandline(int argc, char *argv[]) || command->cmd == IPSET_CMD_VERSION || command->cmd == IPSET_CMD_HELP)) return exit_error(PARAMETER_PROBLEM, - "Command `%s' is invalid in restore mode.", + "Command `%s' is invalid " + "in restore mode.", command->name[0]); - if (interactive && command->cmd == IPSET_CMD_RESTORE) { - printf("Restore command ignored in interactive mode\n"); + if (interactive + && command->cmd == IPSET_CMD_RESTORE) { + printf("Restore command ignored " + "in interactive mode\n"); return 0; } @@ -407,7 +414,8 @@ parse_commandline(int argc, char *argv[]) case IPSET_MANDATORY_ARG2: if (i + 1 > argc) return exit_error(PARAMETER_PROBLEM, - "Missing mandatory argument to command %s", + "Missing mandatory argument " + "to command %s", command->name[0]); /* Fall through */ case IPSET_OPTIONAL_ARG: @@ -422,7 +430,8 @@ parse_commandline(int argc, char *argv[]) if (command->has_arg == IPSET_MANDATORY_ARG2) { if (i + 1 > argc) return exit_error(PARAMETER_PROBLEM, - "Missing second mandatory argument to command %s", + "Missing second mandatory " + "argument to command %s", command->name[0]); arg1 = argv[i]; /* Shift off second arg */ @@ -460,7 +469,8 @@ parse_commandline(int argc, char *argv[]) } if (argc > 1) return exit_error(PARAMETER_PROBLEM, - "No command specified: unknown argument %s", argv[1]); + "No command specified: unknown argument %s", + argv[1]); return exit_error(PARAMETER_PROBLEM, "No command specified."); case IPSET_CMD_VERSION: printf("%s v%s.\n", program_name, program_version); @@ -480,16 +490,21 @@ parse_commandline(int argc, char *argv[]) "Unknown settype: `%s'", arg0); printf("\n%s type specific options:\n\n%s", type->name, type->usage); + if (type->usagefn) + type->usagefn(); if (type->family == AF_UNSPEC) printf("\nType %s is family neutral.\n", type->name); else if (type->family == AF_INET46) - printf("\nType %s supports INET and INET6.\n", + printf("\nType %s supports INET " + "and INET6.\n", type->name); else - printf("\nType %s supports family %s only.\n", + printf("\nType %s supports family " + "%s only.\n", type->name, - type->family == AF_INET ? "INET" : "INET6"); + type->family == AF_INET + ? "INET" : "INET6"); } else { printf("\nSupported set types:\n"); type = ipset_types(); @@ -541,7 +556,8 @@ parse_commandline(int argc, char *argv[]) case IPSET_CMD_SAVE: /* Args: [setname] */ if (arg0) { - ret = ipset_parse_setname(session, IPSET_SETNAME, arg0); + ret = ipset_parse_setname(session, + IPSET_SETNAME, arg0); if (ret < 0) return handle_error(); } @@ -622,6 +638,7 @@ main(int argc, char *argv[]) ipset_type_add(&ipset_bitmap_port0); ipset_type_add(&ipset_hash_ip0); ipset_type_add(&ipset_hash_net0); + ipset_type_add(&ipset_hash_netport0); ipset_type_add(&ipset_hash_ipport0); ipset_type_add(&ipset_hash_ipportip0); ipset_type_add(&ipset_hash_ipportnet0); diff --git a/src/ipset_bitmap_ip.c b/src/ipset_bitmap_ip.c index e28432b..4194875 100644 --- a/src/ipset_bitmap_ip.c +++ b/src/ipset_bitmap_ip.c @@ -52,7 +52,9 @@ static const char bitmap_ip_usage[] = " [netmask CIDR] [timeout VALUE]\n" "add SETNAME IP|IP/CIDR|FROM-TO [timeout VALUE]\n" "del SETNAME IP|IP/CIDR|FROM-TO\n" -"test SETNAME IP\n"; +"test SETNAME IP\n\n" +"where IP, FROM and TO are IPv4 addresses (or hostnames),\n" +" CIDR is a valid IPv4 CIDR prefix.\n"; struct ipset_type ipset_bitmap_ip0 = { .name = "bitmap:ip", diff --git a/src/ipset_bitmap_ipmac.c b/src/ipset_bitmap_ipmac.c index 382ebb5..8f2cb72 100644 --- a/src/ipset_bitmap_ipmac.c +++ b/src/ipset_bitmap_ipmac.c @@ -48,7 +48,10 @@ static const char bitmap_ipmac_usage[] = " [matchunset] [timeout VALUE]\n" "add SETNAME IP[,MAC] [timeout VALUE]\n" "del SETNAME IP[,MAC]\n" -"test SETNAME IP[,MAC]\n"; +"test SETNAME IP[,MAC]\n\n" +"where IP, FROM and TO are IPv4 addresses (or hostnames),\n" +" CIDR is a valid IPv4 CIDR prefix,\n" +" MAC is a valid MAC address.\n"; struct ipset_type ipset_bitmap_ipmac0 = { .name = "bitmap:ip,mac", diff --git a/src/ipset_bitmap_port.c b/src/ipset_bitmap_port.c index 7871891..82b98a4 100644 --- a/src/ipset_bitmap_port.c +++ b/src/ipset_bitmap_port.c @@ -13,7 +13,7 @@ static const struct ipset_arg bitmap_port_create_args[] = { { .name = { "range", NULL }, .has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PORT, - .parse = ipset_parse_port, .print = ipset_print_port, + .parse = ipset_parse_tcp_port, .print = ipset_print_port, }, { .name = { "timeout", NULL }, .has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT, @@ -22,11 +22,11 @@ static const struct ipset_arg bitmap_port_create_args[] = { /* Backward compatibility */ { .name = { "from", NULL }, .has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PORT, - .parse = ipset_parse_single_port, + .parse = ipset_parse_single_tcp_port, }, { .name = { "to", NULL }, .has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PORT_TO, - .parse = ipset_parse_single_port, + .parse = ipset_parse_single_tcp_port, }, { }, }; @@ -44,7 +44,8 @@ static const char bitmap_port_usage[] = " [timeout VALUE]\n" "add SETNAME PORT|FROM-TO [timeout VALUE]\n" "del SETNAME PORT|FROM-TO\n" -"test SETNAME PORT\n"; +"test SETNAME PORT\n\n" +"where PORT, FROM and TO are port numbers or port names from /etc/services.\n"; struct ipset_type ipset_bitmap_port0 = { .name = "bitmap:port", @@ -54,7 +55,7 @@ struct ipset_type ipset_bitmap_port0 = { .dimension = IPSET_DIM_ONE, .elem = { [IPSET_DIM_ONE] = { - .parse = ipset_parse_port, + .parse = ipset_parse_tcp_port, .print = ipset_print_port, .opt = IPSET_OPT_PORT }, diff --git a/src/ipset_hash_ip.c b/src/ipset_hash_ip.c index 6609eea..be64189 100644 --- a/src/ipset_hash_ip.c +++ b/src/ipset_hash_ip.c @@ -72,7 +72,10 @@ static const char hash_ip_usage[] = " [netmask CIDR] [timeout VALUE]\n" "add SETNAME IP|IP/CIDR|FROM-TO [timeout VALUE]\n" "del SETNAME IP|IP/CIDR|FROM-TO\n" -"test SETNAME IP\n"; +"test SETNAME IP\n\n" +"where depending on the INET family\n" +" IP, FROM and TO are IPv4 or IPv6 addresses (or hostnames),\n" +" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"; struct ipset_type ipset_hash_ip0 = { .name = "hash:ip", diff --git a/src/ipset_hash_ipport.c b/src/ipset_hash_ipport.c index 94a8cc6..4b06d5e 100644 --- a/src/ipset_hash_ipport.c +++ b/src/ipset_hash_ipport.c @@ -7,6 +7,7 @@ #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 */ @@ -37,10 +38,6 @@ static const struct ipset_arg hash_ipport_create_args[] = { .has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT, .parse = ipset_parse_uint32, .print = ipset_print_number, }, - { .name = { "proto", NULL }, - .has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PROTO, - .parse = ipset_parse_proto, .print = ipset_print_proto, - }, /* Backward compatibility */ { .name = { "probes", NULL }, .has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PROBES, @@ -75,12 +72,14 @@ static const struct ipset_arg hash_ipport_add_args[] = { static const char hash_ipport_usage[] = "create SETNAME hash:ip,port\n" -" [family inet|inet6] [proto PROTO]\n" +" [family inet|inet6]\n" " [hashsize VALUE] [maxelem VALUE]\n" " [timeout VALUE]\n" -"add SETNAME IP,[PROTO:]PORT [timeout VALUE]\n" -"del SETNAME IP,[PROTO:]PORT\n" -"test SETNAME IP,[PROTO:]PORT\n"; +"add SETNAME IP,PROTO:PORT [timeout VALUE]\n" +"del SETNAME IP,PROTO:PORT\n" +"test SETNAME IP,PROTO:PORT\n\n" +"where depending on the INET family\n" +" IP is a valid IPv4 or IPv6 address (or hostname),\n"; struct ipset_type ipset_hash_ipport0 = { .name = "hash:ip,port", @@ -107,16 +106,18 @@ struct ipset_type ipset_hash_ipport0 = { .mandatory = { [IPSET_CREATE] = 0, [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP) + | IPSET_FLAG(IPSET_OPT_PROTO) | IPSET_FLAG(IPSET_OPT_PORT), [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP) + | IPSET_FLAG(IPSET_OPT_PROTO) | IPSET_FLAG(IPSET_OPT_PORT), [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP) + | IPSET_FLAG(IPSET_OPT_PROTO) | IPSET_FLAG(IPSET_OPT_PORT), }, .full = { [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE) | IPSET_FLAG(IPSET_OPT_MAXELEM) - | IPSET_FLAG(IPSET_OPT_PROTO) | IPSET_FLAG(IPSET_OPT_TIMEOUT), [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP) | IPSET_FLAG(IPSET_OPT_PORT) @@ -131,4 +132,5 @@ struct ipset_type ipset_hash_ipport0 = { }, .usage = hash_ipport_usage, + .usagefn = ipset_port_usage, }; diff --git a/src/ipset_hash_ipportip.c b/src/ipset_hash_ipportip.c index dc121e4..5294da3 100644 --- a/src/ipset_hash_ipportip.c +++ b/src/ipset_hash_ipportip.c @@ -7,6 +7,7 @@ #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 */ @@ -37,10 +38,6 @@ static const struct ipset_arg hash_ipportip_create_args[] = { .has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT, .parse = ipset_parse_uint32, .print = ipset_print_number, }, - { .name = { "proto", NULL }, - .has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PROTO, - .parse = ipset_parse_proto, .print = ipset_print_proto, - }, /* Backward compatibility */ { .name = { "probes", NULL }, .has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PROBES, @@ -75,12 +72,14 @@ static const struct ipset_arg hash_ipportip_add_args[] = { static const char hash_ipportip_usage[] = "create SETNAME hash:ip,port,ip\n" -" [family inet|inet6] [proto PROTO]\n" +" [family inet|inet6]\n" " [hashsize VALUE] [maxelem VALUE]\n" " [timeout VALUE]\n" -"add SETNAME IP,[PROTO:]PORT,IP [timeout VALUE]\n" -"del SETNAME IP,[PROTO:]PORT,IP\n" -"test SETNAME IP,[PROTO:]PORT,IP\n"; +"add SETNAME IP,PROTO:PORT,IP [timeout VALUE]\n" +"del SETNAME IP,PROTO:PORT,IP\n" +"test SETNAME IP,PROTO:PORT,IP\n\n" +"where depending on the INET family\n" +" IP are valid IPv4 or IPv6 addresses (or hostnames),\n"; struct ipset_type ipset_hash_ipportip0 = { .name = "hash:ip,port,ip", @@ -113,18 +112,20 @@ struct ipset_type ipset_hash_ipportip0 = { [IPSET_CREATE] = 0, [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP) | IPSET_FLAG(IPSET_OPT_PORT) + | IPSET_FLAG(IPSET_OPT_PROTO) | IPSET_FLAG(IPSET_OPT_IP2), [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP) | IPSET_FLAG(IPSET_OPT_PORT) + | IPSET_FLAG(IPSET_OPT_PROTO) | IPSET_FLAG(IPSET_OPT_IP2), [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP) | IPSET_FLAG(IPSET_OPT_PORT) + | IPSET_FLAG(IPSET_OPT_PROTO) | IPSET_FLAG(IPSET_OPT_IP2), }, .full = { [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE) | IPSET_FLAG(IPSET_OPT_MAXELEM) - | IPSET_FLAG(IPSET_OPT_PROTO) | IPSET_FLAG(IPSET_OPT_TIMEOUT), [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP) | IPSET_FLAG(IPSET_OPT_PORT) @@ -142,4 +143,5 @@ struct ipset_type ipset_hash_ipportip0 = { }, .usage = hash_ipportip_usage, + .usagefn = ipset_port_usage, }; diff --git a/src/ipset_hash_ipportnet.c b/src/ipset_hash_ipportnet.c index a668c5e..3c073cd 100644 --- a/src/ipset_hash_ipportnet.c +++ b/src/ipset_hash_ipportnet.c @@ -7,6 +7,7 @@ #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 */ @@ -37,10 +38,6 @@ static const struct ipset_arg hash_ipportnet_create_args[] = { .has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT, .parse = ipset_parse_uint32, .print = ipset_print_number, }, - { .name = { "proto", NULL }, - .has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PROTO, - .parse = ipset_parse_proto, .print = ipset_print_proto, - }, /* Backward compatibility */ { .name = { "probes", NULL }, .has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PROBES, @@ -75,12 +72,15 @@ static const struct ipset_arg hash_ipportnet_add_args[] = { static const char hash_ipportnet_usage[] = "create SETNAME hash:ip,port,net\n" -" [family inet|inet6] [proto PROTO]\n" +" [family inet|inet6]\n" " [hashsize VALUE] [maxelem VALUE]\n" " [timeout VALUE]\n" -"add SETNAME IP,[PROTO:]PORT,IP[/CIDR] [timeout VALUE]\n" -"del SETNAME IP,[PROTO:]PORT,IP[/CIDR]\n" -"test SETNAME IP,[PROTO:]PORT,IP[/CIDR]\n"; +"add SETNAME IP,PROTO:PORT,IP[/CIDR] [timeout VALUE]\n" +"del SETNAME IP,PROTO:PORT,IP[/CIDR]\n" +"test SETNAME IP,PROTO:PORT,IP[/CIDR]\n\n" +"where depending on the INET family\n" +" IP are valid IPv4 or IPv6 addresses (or hostnames),\n" +" CIDR is a valid IPv4 or IPv6 CIDR prefix,\n"; struct ipset_type ipset_hash_ipportnet0 = { .name = "hash:ip,port,net", @@ -113,18 +113,20 @@ struct ipset_type ipset_hash_ipportnet0 = { [IPSET_CREATE] = 0, [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP) | IPSET_FLAG(IPSET_OPT_PORT) + | IPSET_FLAG(IPSET_OPT_PROTO) | IPSET_FLAG(IPSET_OPT_IP2), [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP) | IPSET_FLAG(IPSET_OPT_PORT) + | IPSET_FLAG(IPSET_OPT_PROTO) | IPSET_FLAG(IPSET_OPT_IP2), [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP) | IPSET_FLAG(IPSET_OPT_PORT) + | IPSET_FLAG(IPSET_OPT_PROTO) | IPSET_FLAG(IPSET_OPT_IP2), }, .full = { [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE) | IPSET_FLAG(IPSET_OPT_MAXELEM) - | IPSET_FLAG(IPSET_OPT_PROTO) | IPSET_FLAG(IPSET_OPT_TIMEOUT), [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP) | IPSET_FLAG(IPSET_OPT_PORT) @@ -145,4 +147,5 @@ struct ipset_type ipset_hash_ipportnet0 = { }, .usage = hash_ipportnet_usage, + .usagefn = ipset_port_usage, }; diff --git a/src/ipset_hash_net.c b/src/ipset_hash_net.c index c14652d..e8891c1 100644 --- a/src/ipset_hash_net.c +++ b/src/ipset_hash_net.c @@ -64,7 +64,10 @@ static const char hash_net_usage[] = " [timeout VALUE]\n" "add SETNAME IP[/CIDR] [timeout VALUE]\n" "del SETNAME IP[/CIDR]\n" -"test SETNAME IP[/CIDR]\n"; +"test SETNAME IP[/CIDR]\n\n" +"where depending on the INET family\n" +" IP is an IPv4 or IPv6 address (or hostname),\n" +" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"; struct ipset_type ipset_hash_net0 = { .name = "hash:net", diff --git a/src/ipset_hash_netport.c b/src/ipset_hash_netport.c new file mode 100644 index 0000000..934162a --- /dev/null +++ b/src/ipset_hash_netport.c @@ -0,0 +1,119 @@ +/* Copyright 2007-2010 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_netport_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_netport_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_netport_usage[] = +"create SETNAME hash:net,port\n" +" [family inet|inet6]\n" +" [hashsize VALUE] [maxelem VALUE]\n" +" [timeout VALUE]\n" +"add SETNAME IP[/CIDR],PROTO:PORT [timeout VALUE]\n" +"del SETNAME IP[/CIDR],PROTO:PORT\n" +"test SETNAME IP[/CIDR],PROTO:PORT\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"; + +struct ipset_type ipset_hash_netport0 = { + .name = "hash:net,port", + .alias = { "netporthash", NULL }, + .revision = 0, + .family = AF_INET46, + .dimension = IPSET_DIM_TWO, + .elem = { + [IPSET_DIM_ONE] = { + .parse = ipset_parse_ipnet, + .print = ipset_print_ip, + .opt = IPSET_OPT_IP + }, + [IPSET_DIM_TWO] = { + .parse = ipset_parse_proto_port, + .print = ipset_print_proto_port, + .opt = IPSET_OPT_PORT + }, + }, + .args = { + [IPSET_CREATE] = hash_netport_create_args, + [IPSET_ADD] = hash_netport_add_args, + }, + .mandatory = { + [IPSET_CREATE] = 0, + [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP) + | IPSET_FLAG(IPSET_OPT_PROTO) + | IPSET_FLAG(IPSET_OPT_PORT), + [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP) + | IPSET_FLAG(IPSET_OPT_PROTO) + | IPSET_FLAG(IPSET_OPT_PORT), + [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP) + | IPSET_FLAG(IPSET_OPT_PROTO) + | IPSET_FLAG(IPSET_OPT_PORT), + }, + .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_PORT) + | IPSET_FLAG(IPSET_OPT_PROTO) + | IPSET_FLAG(IPSET_OPT_TIMEOUT) + | IPSET_FLAG(IPSET_OPT_CIDR), + [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP) + | IPSET_FLAG(IPSET_OPT_PORT) + | IPSET_FLAG(IPSET_OPT_PROTO) + | IPSET_FLAG(IPSET_OPT_CIDR), + [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP) + | IPSET_FLAG(IPSET_OPT_PORT) + | IPSET_FLAG(IPSET_OPT_PROTO) + | IPSET_FLAG(IPSET_OPT_CIDR), + }, + + .usage = hash_netport_usage, + .usagefn = ipset_port_usage, +}; diff --git a/src/ipset_list_set.c b/src/ipset_list_set.c index 76cf9b2..d0b0dd6 100644 --- a/src/ipset_list_set.c +++ b/src/ipset_list_set.c @@ -43,7 +43,8 @@ static const char list_set_usage[] = " [size VALUE] [timeout VALUE]\n" "add SETNAME NAME [before|after NAME] [timeout VALUE]\n" "del SETNAME NAME\n" -"test SETNAME NAME\n"; +"test SETNAME NAME\n\n" +"where NAME are existing set names.\n"; struct ipset_type ipset_list_set0 = { .name = "list:set", @@ -9,6 +9,8 @@ #include <string.h> /* memcmp, str* */ #include <libipset/linux_ip_set.h> /* IPSET_CMD_* */ +#include <libipset/icmp.h> /* id_to_icmp */ +#include <libipset/icmpv6.h> /* id_to_icmpv6 */ #include <libipset/types.h> /* IPSET_*_ARG */ #include <libipset/session.h> /* ipset_envopt_parse */ #include <libipset/parse.h> /* ipset_parse_family */ @@ -141,7 +143,7 @@ ipset_match_cmd(const char *arg, const char * const name[]) if (len > strlen(name[0]) || !len) return false; - else if (memcmp(arg, name[0], len) == 0) + else if (strcmp(arg, name[0]) == 0) return true; else if (len != 1) return false; @@ -242,3 +244,33 @@ ipset_shift_argv(int *argc, char *argv[], int from) return; } +/** + * ipset_port_usage - prints the usage for the port parameter + * + * Print the usage for the port parameter to stdout. + */ +void +ipset_port_usage(void) +{ + int i; + const char *name; + + printf(" [PROTO:]PORT is a valid pattern of the following:\n" + " PORTNAME port name from /etc/services\n" + " PORTNUMBER port number identifier\n" + " tcp|udp:PORTNAME|PORTNUMBER\n" + " icmp:CODENAME supported ICMP codename\n" + " icmp:TYPE/CODE ICMP type/code value\n" + " icmpv6:CODENAME supported ICMPv6 codename\n" + " icmpv6:TYPE/CODE ICMPv6 type/code value\n" + " PROTO:0 all other protocols\n\n"); + + printf(" Supported ICMP codenames:\n"); + i = 0; + while ((name = id_to_icmp(i++)) != NULL) + printf(" %s\n", name); + printf(" Supported ICMPv6 codenames:\n"); + i = 0; + while ((name = id_to_icmpv6(i++)) != NULL) + printf(" %s\n", name); +} diff --git a/tests/hash:ip,port,ip.t.list0 b/tests/hash:ip,port,ip.t.list0 index b20c8d8..daad2db 100644 --- a/tests/hash:ip,port,ip.t.list0 +++ b/tests/hash:ip,port,ip.t.list0 @@ -4,8 +4,8 @@ Header: family inet hashsize 1024 maxelem 65536 timeout x Size in memory: 8720 References: 0 Members: -2.0.0.0,5,1.1.1.1 timeout x -2.0.0.1,5,1.1.1.1 timeout x -2.1.0.0,128,2.2.2.2 timeout x -2.1.0.1,128,2.2.2.2 timeout x +2.0.0.0,tcp:5,1.1.1.1 timeout x +2.0.0.1,tcp:5,1.1.1.1 timeout x +2.1.0.0,tcp:128,2.2.2.2 timeout x +2.1.0.1,tcp:128,2.2.2.2 timeout x diff --git a/tests/hash:ip,port.t b/tests/hash:ip,port.t index e3b292b..6fe18ee 100644 --- a/tests/hash:ip,port.t +++ b/tests/hash:ip,port.t @@ -40,8 +40,8 @@ 0 ipset flush test # Delete test set 0 ipset destroy test -# Create a set with default TCP protocol -0 ipset create test hash:ip,port proto tcp +# Create a set +0 ipset create test hash:ip,port # Add element without specifying protocol 0 ipset add test 2.0.0.1,80 # Add "same" element but with UDP protocol diff --git a/tests/hash:ip,port.t.list0 b/tests/hash:ip,port.t.list0 index 25d8632..fb6a8ec 100644 --- a/tests/hash:ip,port.t.list0 +++ b/tests/hash:ip,port.t.list0 @@ -4,8 +4,8 @@ Header: family inet hashsize 1024 maxelem 65536 timeout x Size in memory: 8592 References: 0 Members: -2.0.0.0,5 timeout x -2.0.0.1,5 timeout x -2.1.0.0,128 timeout x -2.1.0.1,128 timeout x +2.0.0.0,tcp:5 timeout x +2.0.0.1,tcp:5 timeout x +2.1.0.0,tcp:128 timeout x +2.1.0.1,tcp:128 timeout x diff --git a/tests/hash:ip,port.t.list2 b/tests/hash:ip,port.t.list2 index e8a9db0..5686e43 100644 --- a/tests/hash:ip,port.t.list2 +++ b/tests/hash:ip,port.t.list2 @@ -1,7 +1,7 @@ Name: test Type: hash:ip,port -Header: family inet hashsize 1024 maxelem 65536 proto tcp -Size in memory: 8424 +Header: family inet hashsize 1024 maxelem 65536 +Size in memory: 8432 References: 0 Members: 2.0.0.1,ospf:0 diff --git a/tests/hash:ip.t b/tests/hash:ip.t index c7bddb8..c45bb2d 100644 --- a/tests/hash:ip.t +++ b/tests/hash:ip.t @@ -44,6 +44,8 @@ 0 ipset -F test # IP: Delete test set 0 ipset -X test +# IP: Stress test resizing +0 ./resize.sh # Network: Create a set with timeout 0 ipset -N test iphash --hashsize 128 --netmask 24 timeout 6 # Network: Add zero valued element diff --git a/tests/hash:ip6,port,ip6.t.list0 b/tests/hash:ip6,port,ip6.t.list0 index 84cdf5c..4e8f425 100644 --- a/tests/hash:ip6,port,ip6.t.list0 +++ b/tests/hash:ip6,port,ip6.t.list0 @@ -4,8 +4,8 @@ Header: family inet6 hashsize 1024 maxelem 65536 timeout x Size in memory: 9104 References: 0 Members: -2:1::1,128,2:2:2::2 timeout x -2:1::,128,2:2:2::2 timeout x -2::1,5,1:1:1::1 timeout x -2::,5,1:1:1::1 timeout x +2:1::1,tcp:128,2:2:2::2 timeout x +2:1::,tcp:128,2:2:2::2 timeout x +2::1,tcp:5,1:1:1::1 timeout x +2::,tcp:5,1:1:1::1 timeout x diff --git a/tests/hash:ip6,port.t.list0 b/tests/hash:ip6,port.t.list0 index defd377..140ea45 100644 --- a/tests/hash:ip6,port.t.list0 +++ b/tests/hash:ip6,port.t.list0 @@ -4,8 +4,8 @@ Header: family inet6 hashsize 1024 maxelem 65536 timeout x Size in memory: 8848 References: 0 Members: -2:1::1,128 timeout x -2:1::,128 timeout x -2::1,5 timeout x -2::,5 timeout x +2:1::1,tcp:128 timeout x +2:1::,tcp:128 timeout x +2::1,tcp:5 timeout x +2::,tcp:5 timeout x diff --git a/tests/hash:net,port.t b/tests/hash:net,port.t new file mode 100644 index 0000000..19f45d1 --- /dev/null +++ b/tests/hash:net,port.t @@ -0,0 +1,51 @@ +# Create a set with timeout +0 ipset create test hash:net,port hashsize 128 timeout 6 +# Add zero valued element +1 ipset add test 0.0.0.0/0,0 +# Test zero valued element +1 ipset test test 0.0.0.0/0,0 +# Delete zero valued element +1 ipset del test 0.0.0.0/0,0 +# Try to add /0 +1 ipset add test 1.1.1.1/0,0 +# Try to add /32 +0 ipset add test 1.1.1.1/32,tcp:5 +# Add almost zero valued element +0 ipset add test 0.0.0.0/1,tcp:8 +# Test almost zero valued element +0 ipset test test 0.0.0.0/1,tcp:8 +# Test almost zero valued element with UDP +1 ipset test test 0.0.0.0/1,udp:8 +# Delete almost zero valued element +0 ipset del test 0.0.0.0/1,tcp:8 +# Test deleted element +1 ipset test test 0.0.0.0/1,tcp:8 +# Delete element not added to the set +1 ipset del test 0.0.0.0/1,tcp:8 +# Add first random network +0 ipset add test 2.0.0.1/24,icmp:ping +# Add second random network +0 ipset add test 192.168.68.69/27,tcp:8 +# Test first random value +0 ipset test test 2.0.0.255,icmp:ping +# Test second random value +0 ipset test test 192.168.68.95,tcp:8 +# Test value not added to the set +1 ipset test test 2.0.1.0,icmp:ping +# Try to add IP address +0 ipset add test 2.0.0.1,icmp:ping timeout 3 +# List set +0 ipset list test | sed 's/timeout ./timeout x/' > .foo0 && ./sort.sh .foo0 +# Check listing +0 diff -I 'Size in memory.*' .foo hash:net,port.t.list0 +# Sleep 6s so that element can time out +0 sleep 6 +# IP: List set +0 ipset -L test 2>/dev/null > .foo0 && ./sort.sh .foo0 +# IP: Check listing +0 diff -I 'Size in memory.*' .foo hash:net,port.t.list1 && rm .foo +# Flush test set +0 ipset flush test +# Delete test set +0 ipset destroy test +# eof diff --git a/tests/hash:net,port.t.list0 b/tests/hash:net,port.t.list0 new file mode 100644 index 0000000..8194872 --- /dev/null +++ b/tests/hash:net,port.t.list0 @@ -0,0 +1,11 @@ +Name: test +Type: hash:net,port +Header: family inet hashsize 128 maxelem 65536 timeout x +Size in memory: 2072 +References: 0 +Members: +1.1.1.1,tcp:5 timeout x +192.168.68.64/27,tcp:8 timeout x +2.0.0.0/24,icmp:echo-request timeout x +2.0.0.1,icmp:echo-request timeout x + diff --git a/tests/hash:net,port.t.list1 b/tests/hash:net,port.t.list1 new file mode 100644 index 0000000..20d38a8 --- /dev/null +++ b/tests/hash:net,port.t.list1 @@ -0,0 +1,7 @@ +Name: test +Type: hash:net,port +Header: family inet hashsize 128 maxelem 65536 timeout 6 +Size in memory: 2000 +References: 0 +Members: + diff --git a/tests/hash:net6,port.t b/tests/hash:net6,port.t new file mode 100644 index 0000000..bfb6f27 --- /dev/null +++ b/tests/hash:net6,port.t @@ -0,0 +1,51 @@ +# Create a set with timeout +0 ipset create test hash:net,port family inet6 hashsize 128 timeout 6 +# Add zero valued element +1 ipset add test ::/0,tcp:8 +# Test zero valued element +1 ipset test test ::/0,tcp:8 +# Delete zero valued element +1 ipset del test ::/0,tcp:8 +# Try to add /0 +1 ipset add test 1:1:1::1/0,tcp:8 +# Try to add /128 +0 ipset add test 1:1:1::1/128,tcp:8 timeout 0 +# Add almost zero valued element +0 ipset add test 0:0:0::0/1,tcp:8 +# Test almost zero valued element +0 ipset test test 0:0:0::0/1,tcp:8 +# Test almost zero valued element with UDP +1 ipset test test 0:0:0::0/1,udp:8 +# Delete almost zero valued element +0 ipset del test 0:0:0::0/1,tcp:8 +# Test deleted element +1 ipset test test 0:0:0::0/1,tcp:8 +# Delete element not added to the set +1 ipset del test 0:0:0::0/1,tcp:8 +# Add first random network +0 ipset add test 2:0:0::1/24,tcp:8 +# Add second random network +0 ipset add test 192:168:68::69/27,icmpv6:ping +# Test first random value +0 ipset test test 2:0:0::255,tcp:8 +# Test second random value +0 ipset test test 192:168:68::95,icmpv6:ping +# Test value not added to the set +1 ipset test test 3:0:0::1,tcp:8 +# Try to add IP address +0 ipset add test 3:0:0::1,tcp:8 +# List set +0 ipset list test | sed 's/timeout ./timeout x/' > .foo0 && ./sort.sh .foo0 +# Check listing +0 diff -I 'Size in memory.*' .foo hash:net6,port.t.list0 && rm .foo +# Sleep 6s so that element can time out +0 sleep 6 +# IP: List set +0 ipset -L test 2>/dev/null > .foo0 && ./sort.sh .foo0 +# IP: Check listing +0 diff -I 'Size in memory.*' .foo hash:net6,port.t.list1 && rm .foo +# Flush test set +0 ipset flush test +# Delete test set +0 ipset destroy test +# eof diff --git a/tests/hash:net6,port.t.list0 b/tests/hash:net6,port.t.list0 new file mode 100644 index 0000000..0e26a6e --- /dev/null +++ b/tests/hash:net6,port.t.list0 @@ -0,0 +1,11 @@ +Name: test +Type: hash:net,port +Header: family inet6 hashsize 128 maxelem 65536 timeout x +Size in memory: 2328 +References: 0 +Members: +1:1:1::1,tcp:8 timeout x +192:160::/27,ipv6-icmp:echo-request timeout x +2::/24,tcp:8 timeout x +3::1,tcp:8 timeout x + diff --git a/tests/hash:net6,port.t.list1 b/tests/hash:net6,port.t.list1 new file mode 100644 index 0000000..873788e --- /dev/null +++ b/tests/hash:net6,port.t.list1 @@ -0,0 +1,8 @@ +Name: test +Type: hash:net,port +Header: family inet6 hashsize 128 maxelem 65536 timeout 6 +Size in memory: 2328 +References: 0 +Members: +1:1:1::1,tcp:8 timeout 0 + diff --git a/tests/hash:net6.t b/tests/hash:net6.t index 5a575d1..f1ae092 100644 --- a/tests/hash:net6.t +++ b/tests/hash:net6.t @@ -8,7 +8,7 @@ 1 ipset del test ::/0 # Try to add /0 1 ipset add test 1:1:1::1/0 -# Try to add /32 +# Try to add /128 0 ipset add test 1:1:1::1/128 # Add almost zero valued element 0 ipset add test 0:0:0::0/1 diff --git a/tests/ipporthash.t.list0 b/tests/ipporthash.t.list0 index 2e78ac4..e28593c 100644 --- a/tests/ipporthash.t.list0 +++ b/tests/ipporthash.t.list0 @@ -4,8 +4,8 @@ Header: family inet hashsize 1024 maxelem 65536 Size in memory: 8464 References: 0 Members: -2.0.0.0,5 -2.0.0.1,5 -2.1.0.0,128 -2.1.0.1,128 +2.0.0.0,tcp:5 +2.0.0.1,tcp:5 +2.1.0.0,tcp:128 +2.1.0.1,tcp:128 diff --git a/tests/ipporthash.t.list1 b/tests/ipporthash.t.list1 index e0f0da5..1fbfc9c 100644 --- a/tests/ipporthash.t.list1 +++ b/tests/ipporthash.t.list1 @@ -4,8 +4,8 @@ Header: family inet hashsize 1024 maxelem 65536 Size in memory: 8464 References: 0 Members: -1.255.255.255,5 -2.0.0.0,5 -2.0.255.255,128 -2.1.0.0,128 +1.255.255.255,tcp:5 +2.0.0.0,tcp:5 +2.0.255.255,tcp:128 +2.1.0.0,tcp:128 diff --git a/tests/ipportiphash.t.list0 b/tests/ipportiphash.t.list0 index ba20b14..623e683 100644 --- a/tests/ipportiphash.t.list0 +++ b/tests/ipportiphash.t.list0 @@ -4,8 +4,8 @@ Header: family inet hashsize 1024 maxelem 65536 Size in memory: 8528 References: 0 Members: -2.0.0.0,5,1.1.1.1 -2.0.0.1,5,1.1.1.1 -2.1.0.0,128,2.2.2.2 -2.1.0.1,128,2.2.2.2 +2.0.0.0,tcp:5,1.1.1.1 +2.0.0.1,tcp:5,1.1.1.1 +2.1.0.0,tcp:128,2.2.2.2 +2.1.0.1,tcp:128,2.2.2.2 diff --git a/tests/ipportiphash.t.list1 b/tests/ipportiphash.t.list1 index aca272a..104a94a 100644 --- a/tests/ipportiphash.t.list1 +++ b/tests/ipportiphash.t.list1 @@ -4,6 +4,6 @@ Header: family inet hashsize 1024 maxelem 65536 Size in memory: 8416 References: 0 Members: -2.0.0.0,5,1.1.1.1 -2.0.255.255,128,2.2.2.2 +2.0.0.0,tcp:5,1.1.1.1 +2.0.255.255,tcp:128,2.2.2.2 diff --git a/tests/ipportnethash.t.list0 b/tests/ipportnethash.t.list0 index 60a0242..ebc2ab6 100644 --- a/tests/ipportnethash.t.list0 +++ b/tests/ipportnethash.t.list0 @@ -4,8 +4,8 @@ Header: family inet hashsize 1024 maxelem 65536 Size in memory: 8776 References: 0 Members: -2.0.0.0,5,1.1.1.0/24 -2.0.0.1,5,1.1.1.0/24 -2.1.0.0,128,2.0.0.0/12 -2.1.0.1,128,2.0.0.0/12 +2.0.0.0,tcp:5,1.1.1.0/24 +2.0.0.1,tcp:5,1.1.1.0/24 +2.1.0.0,tcp:128,2.0.0.0/12 +2.1.0.1,tcp:128,2.0.0.0/12 diff --git a/tests/ipportnethash.t.list1 b/tests/ipportnethash.t.list1 index 5d74105..fc90f78 100644 --- a/tests/ipportnethash.t.list1 +++ b/tests/ipportnethash.t.list1 @@ -4,8 +4,8 @@ Header: family inet hashsize 1024 maxelem 65536 Size in memory: 8776 References: 0 Members: -1.255.255.255,5,1.1.1.0/24 -2.0.0.0,5,1.1.1.0/24 -2.0.255.255,128,2.0.0.0/12 -2.1.0.0,128,2.0.0.0/12 +1.255.255.255,tcp:5,1.1.1.0/24 +2.0.0.0,tcp:5,1.1.1.0/24 +2.0.255.255,tcp:128,2.0.0.0/12 +2.1.0.0,tcp:128,2.0.0.0/12 diff --git a/tests/iptables.sh b/tests/iptables.sh index 213e748..1bf96df 100755 --- a/tests/iptables.sh +++ b/tests/iptables.sh @@ -41,7 +41,7 @@ start) ../src/ipset a ip1 $IP1 2>/dev/null ../src/ipset n ip2 hash:ip $family 2>/dev/null ../src/ipset a ip2 $IP2 2>/dev/null - ../src/ipset n ipport hash:ip,port $family proto any 2>/dev/null + ../src/ipset n ipport hash:ip,port $family 2>/dev/null ../src/ipset n list list:set 2>/dev/null ../src/ipset a list ipport 2>/dev/null ../src/ipset a list ip1 2>/dev/null diff --git a/tests/resize.sh b/tests/resize.sh new file mode 100755 index 0000000..5d39f66 --- /dev/null +++ b/tests/resize.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -e + +../src/ipset n resize-test hash:ip hashsize 64 +for x in `seq 1 20`; do + for y in `seq 1 255`; do + ../src/ipset a resize-test 192.168.$x.$y + done +done +../src/ipset x resize-test diff --git a/tests/runtest.sh b/tests/runtest.sh index cc6678a..6ce4477 100755 --- a/tests/runtest.sh +++ b/tests/runtest.sh @@ -1,12 +1,14 @@ #!/bin/bash +# set -x + tests="init" tests="$tests ipmap bitmap:ip" tests="$tests macipmap portmap" tests="$tests iphash hash:ip hash:ip6" tests="$tests ipporthash hash:ip,port hash:ip6,port" tests="$tests ipportiphash hash:ip,port,ip hash:ip6,port,ip6" -tests="$tests nethash hash:net hash:net6" +tests="$tests nethash hash:net hash:net6 hash:net,port hash:net6,port" tests="$tests setlist" tests="$tests iptree iptreemap" @@ -20,7 +22,7 @@ add_tests() { add=match_target6 fi line="`dmesg | tail -1 | cut -d " " -f 2-`" - if [ ! -e /var/log/kern.log -o -z "`grep \"$line\" /var/log/kern.log`" ]; then + if [ ! -e /var/log/kern.log -o -z "`grep -F \"$line\" /var/log/kern.log`" ]; then echo "The destination for kernel log is not /var/log/kern.log, skipping $1 match and target tests" return fi |