From 418a3a4f4d4e38abd1d691f81f2445590f02ecaf Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Mon, 30 May 2011 17:48:01 +0200 Subject: hash:net,iface type introduced The hash:net,iface type makes possible to store network address and interface name pairs in a set. It's mostly suitable for egress and ingress filtering. Examples: # ipset create test hash:net,iface # ipset add test 192.168.0.0/16,eth0 # ipset add test 192.168.0.0/24,eth1 --- src/Makefile.am | 1 + src/ipset.8 | 71 ++++++++++++++++++++++++++- src/ipset.c | 2 + src/ipset_hash_netiface.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 192 insertions(+), 2 deletions(-) create mode 100644 src/ipset_hash_netiface.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 336145a..f3047f0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,6 +12,7 @@ ipset_SOURCES = ipset.c \ ipset_hash_ipportnet.c \ ipset_hash_net.c \ ipset_hash_netport.c \ + ipset_hash_netiface.c \ ipset_list_set.c \ ui.c ipset_LDADD = ../lib/libipset.la diff --git a/src/ipset.8 b/src/ipset.8 index 90914f4..648e935 100644 --- a/src/ipset.8 +++ b/src/ipset.8 @@ -214,8 +214,8 @@ command follows the syntax where the current list of the methods are \fBbitmap\fR, \fBhash\fR, and \fBlist\fR and the possible data types -are \fBip\fR, \fBnet\fR, \fBmac\fR and \fBport\fR. The dimension of a set -is equal to the number of data types in its type name. +are \fBip\fR, \fBnet\fR, \fBmac\fR, \fBport\fR and \fBiface\fR. +The dimension of a set is equal to the number of data types in its type name. When adding, deleting or testing entries in a set, the same comma separated data syntax must be used for the entry parameter of the commands, i.e @@ -711,6 +711,73 @@ ipset add foo 192.168.1,80,10.0.0/24 ipset add foo 192.168.2,25,10.1.0.0/16 .IP ipset test foo 192.168.1,80.10.0.0/24 +.SS hash:net,iface +The \fBhash:net,iface\fR set type uses a hash to store different sized IP network +address and interface name pairs. Network address with zero prefix size is not +accepted. +.PP +\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ] +.PP +\fIADD\-ENTRY\fR := \fInetaddr\fR,[\fBphysdev\fR:]\fIiface\fR +.PP +\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ] +.PP +\fIDEL\-ENTRY\fR := \fInetaddr\fR,[\fBphysdev\fR:]\fIiface\fR +.PP +\fITEST\-ENTRY\fR := \fInetaddr\fR,[\fBphysdev\fR:]\fIiface\fR +.PP +where +\fInetaddr\fR := \fIip\fR[/\fIcidr\fR] +.PP +Optional \fBcreate\fR options: +.TP +\fBfamily\fR { \fBinet\fR | \fBinet6\fR } +The protocol family of the IP addresses to be stored in the set. The default is +\fBinet\fR, i.e IPv4. +.TP +\fBhashsize\fR \fIvalue\fR +The initial hash size for the set, default is 1024. The hash size must be a power +of two, the kernel automatically rounds up non power of two hash sizes to the first +correct value. +.TP +\fBmaxelem\fR \fIvalue\fR +The maximal number of elements which can be stored in the set, default 65536. +.PP +For the \fInetaddr\fR part of the elements +see the description at the \fBhash:net\fR set type. +.PP +When adding/deleting/testing entries, if the cidr prefix parameter is not specified, +then the host prefix value is assumed. When adding/deleting entries, the exact +element is added/deleted and overlapping elements are not checked by the kernel. +When testing entries, if a host address is tested, then the kernel tries to match +the host address in the networks added to the set and reports the result accordingly. +.PP +From the \fBset\fR netfilter match point of view the searching for a match +always starts from the smallest size of netblock (most specific +prefix) to the largest one (least specific prefix) added to the set. +When adding/deleting IP +addresses to the set by the \fBSET\fR netfilter target, it will be +added/deleted by the most specific prefix which can be found in the +set, or by the host prefix value if the set is empty. +.PP +The second direction parameter of the \fBset\fR match and +\fBSET\fR target modules corresponds to the incoming/outgoing interface +: \fBsrc\fR to the incoming, while \fBdst\fR to the outgoing. When +the interface is flagged with \fBphysdev:\fR, the interface is interpreted +as the incoming/outgoing bridge port. +.PP +The lookup time grows linearly with the number of the different prefix +values added to the set. +.PP +Examples: +.IP +ipset create foo hash:net,iface +.IP +ipset add foo 192.168.0/24,eth0 +.IP +ipset add foo 10.1.0.0/16,eth1 +.IP +ipset test foo 192.168.0/24,eth0 .SS list:set The \fBlist:set\fR type uses a simple list in which you can store set names. diff --git a/src/ipset.c b/src/ipset.c index 371d851..032564c 100644 --- a/src/ipset.c +++ b/src/ipset.c @@ -42,6 +42,7 @@ extern struct ipset_type ipset_hash_net0; extern struct ipset_type ipset_hash_net1; extern struct ipset_type ipset_hash_netport1; extern struct ipset_type ipset_hash_netport2; +extern struct ipset_type ipset_hash_netiface0; extern struct ipset_type ipset_hash_ipport1; extern struct ipset_type ipset_hash_ipportip1; extern struct ipset_type ipset_hash_ipportnet1; @@ -729,6 +730,7 @@ main(int argc, char *argv[]) ipset_type_add(&ipset_hash_net1); ipset_type_add(&ipset_hash_netport1); ipset_type_add(&ipset_hash_netport2); + ipset_type_add(&ipset_hash_netiface0); ipset_type_add(&ipset_hash_ipport1); ipset_type_add(&ipset_hash_ipportip1); ipset_type_add(&ipset_hash_ipportnet1); diff --git a/src/ipset_hash_netiface.c b/src/ipset_hash_netiface.c new file mode 100644 index 0000000..bac860b --- /dev/null +++ b/src/ipset_hash_netiface.c @@ -0,0 +1,120 @@ +/* Copyright 2011 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include /* IPSET_OPT_* */ +#include /* parser functions */ +#include /* printing functions */ +#include /* ipset_port_usage */ +#include /* prototypes */ + +/* Parse commandline arguments */ +static const struct ipset_arg hash_netiface_create_args[] = { + { .name = { "family", NULL }, + .has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_FAMILY, + .parse = ipset_parse_family, .print = ipset_print_family, + }, + /* Alias: family inet */ + { .name = { "-4", NULL }, + .has_arg = IPSET_NO_ARG, .opt = IPSET_OPT_FAMILY, + .parse = ipset_parse_family, + }, + /* Alias: family inet6 */ + { .name = { "-6", NULL }, + .has_arg = IPSET_NO_ARG, .opt = IPSET_OPT_FAMILY, + .parse = ipset_parse_family, + }, + { .name = { "hashsize", NULL }, + .has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_HASHSIZE, + .parse = ipset_parse_uint32, .print = ipset_print_number, + }, + { .name = { "maxelem", NULL }, + .has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_MAXELEM, + .parse = ipset_parse_uint32, .print = ipset_print_number, + }, + { .name = { "timeout", NULL }, + .has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT, + .parse = ipset_parse_uint32, .print = ipset_print_number, + }, + { }, +}; + +static const struct ipset_arg hash_netiface_add_args[] = { + { .name = { "timeout", NULL }, + .has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT, + .parse = ipset_parse_uint32, .print = ipset_print_number, + }, + { }, +}; + +static const char hash_netiface_usage[] = +"create SETNAME hash:net,iface\n" +" [family inet|inet6]\n" +" [hashsize VALUE] [maxelem VALUE]\n" +" [timeout VALUE]\n" +"add SETNAME IP[/CIDR]|FROM-TO,[physdev:]IFACE [timeout VALUE]\n" +"del SETNAME IP[/CIDR]|FROM-TO,[physdev:]IFACE\n" +"test SETNAME IP[/CIDR],[physdev:]IFACE\n\n" +"where depending on the INET family\n" +" IP is a valid IPv4 or IPv6 address (or hostname),\n" +" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n" +" Adding/deleting multiple elements with IPv4 is supported.\n"; + +struct ipset_type ipset_hash_netiface0 = { + .name = "hash:net,iface", + .alias = { "netifacehash", NULL }, + .revision = 0, + .family = AF_INET46, + .dimension = IPSET_DIM_TWO, + .elem = { + [IPSET_DIM_ONE] = { + .parse = ipset_parse_ip4_net6, + .print = ipset_print_ip, + .opt = IPSET_OPT_IP + }, + [IPSET_DIM_TWO] = { + .parse = ipset_parse_iface, + .print = ipset_print_iface, + .opt = IPSET_OPT_IFACE + }, + }, + .args = { + [IPSET_CREATE] = hash_netiface_create_args, + [IPSET_ADD] = hash_netiface_add_args, + }, + .mandatory = { + [IPSET_CREATE] = 0, + [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP) + | IPSET_FLAG(IPSET_OPT_IFACE), + [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP) + | IPSET_FLAG(IPSET_OPT_IFACE), + [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP) + | IPSET_FLAG(IPSET_OPT_IFACE), + }, + .full = { + [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE) + | IPSET_FLAG(IPSET_OPT_MAXELEM) + | IPSET_FLAG(IPSET_OPT_TIMEOUT), + [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP) + | IPSET_FLAG(IPSET_OPT_CIDR) + | IPSET_FLAG(IPSET_OPT_IP_TO) + | IPSET_FLAG(IPSET_OPT_IFACE) + | IPSET_FLAG(IPSET_OPT_PHYSDEV) + | IPSET_FLAG(IPSET_OPT_TIMEOUT), + [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP) + | IPSET_FLAG(IPSET_OPT_CIDR) + | IPSET_FLAG(IPSET_OPT_IP_TO) + | IPSET_FLAG(IPSET_OPT_IFACE) + | IPSET_FLAG(IPSET_OPT_PHYSDEV), + [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP) + | IPSET_FLAG(IPSET_OPT_CIDR) + | IPSET_FLAG(IPSET_OPT_IP_TO) + | IPSET_FLAG(IPSET_OPT_IFACE) + | IPSET_FLAG(IPSET_OPT_PHYSDEV), + }, + + .usage = hash_netiface_usage, +}; + -- cgit v1.2.3