summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
author/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=kadlec/emailAddress=kadlec@netfilter.org </C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=kadlec/emailAddress=kadlec@netfilter.org>2004-12-01 09:11:33 +0000
committer/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=kadlec/emailAddress=kadlec@netfilter.org </C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=kadlec/emailAddress=kadlec@netfilter.org>2004-12-01 09:11:33 +0000
commitdda749a352a17d88b1ce8480e31ebab62cc81d1c (patch)
tree5417a23ae366ae2c2c0a2d77f625d0ab2772b66f
parent09fd1f204794bd9411557011098f15cb9c7cdc54 (diff)
ipset 2 related updates (JK)
-rw-r--r--extensions/libipt_SET.c112
-rw-r--r--extensions/libipt_SET.man16
-rw-r--r--extensions/libipt_set.c77
-rw-r--r--extensions/libipt_set.h104
-rw-r--r--extensions/libipt_set.man17
5 files changed, 243 insertions, 83 deletions
diff --git a/extensions/libipt_SET.c b/extensions/libipt_SET.c
index 48c722a..2cf483c 100644
--- a/extensions/libipt_SET.c
+++ b/extensions/libipt_SET.c
@@ -1,3 +1,13 @@
+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
+ * Patrick Schaaf <bof@bof.de>
+ * Martin Josefsson <gandalf@wlug.westbo.se>
+ * Copyright (C) 2003-2004 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.
+ */
+
/* Shared library add-on to iptables to add IP set mangling target. */
#include <stdio.h>
#include <netdb.h>
@@ -11,14 +21,14 @@
#include <linux/netfilter_ipv4/ip_nat_rule.h>
#include <linux/netfilter_ipv4/ip_set.h>
#include <linux/netfilter_ipv4/ipt_set.h>
-#include "../ipset/libipt_set.h"
+#include "libipt_set.h"
/* Function which prints out usage message. */
static void help(void)
{
printf("SET v%s options:\n"
- " --add-set name[:flags] flags\n"
- " --del-set name[:flags] flags\n"
+ " --add-set name flags\n"
+ " --del-set name flags\n"
" add/del src/dst IP/port from/to named sets,\n"
" where flags are the comma separated list of\n"
" 'src' and 'dst'.\n"
@@ -38,13 +48,42 @@ static void init(struct ipt_entry_target *target, unsigned int *nfcache)
(struct ipt_set_info_target *) target->data;
memset(info, 0, sizeof(struct ipt_set_info_target));
- info->add_set.id = -1;
- info->del_set.id = -1;
+ info->add_set.index =
+ info->del_set.index = IP_SET_INVALID_ID;
/* Can't cache this */
*nfcache |= NFC_UNKNOWN;
}
+static void
+parse_target(char **argv, int invert, unsigned int *flags,
+ struct ipt_set_info *info, const char *what)
+{
+ if (info->flags[0])
+ exit_error(PARAMETER_PROBLEM,
+ "--%s can be specified only once", what);
+
+ if (check_inverse(optarg, &invert, NULL, 0))
+ exit_error(PARAMETER_PROBLEM,
+ "Unexpected `!' after --%s", what);
+
+ if (!argv[optind]
+ || argv[optind][0] == '-' || argv[optind][0] == '!')
+ exit_error(PARAMETER_PROBLEM,
+ "--%s requires two args.", what);
+
+ if (strlen(argv[optind-1]) > IP_SET_MAXNAMELEN - 1)
+ exit_error(PARAMETER_PROBLEM,
+ "setname `%s' too long, max %d characters.",
+ argv[optind-1], IP_SET_MAXNAMELEN - 1);
+
+ get_set_byname(argv[optind - 1], info);
+ parse_bindings(argv[optind], info);
+ optind++;
+
+ *flags = 1;
+}
+
/* Function which parses command options; returns true if it
ate an option */
static int
@@ -53,44 +92,15 @@ parse(int c, char **argv, int invert, unsigned int *flags,
{
struct ipt_set_info_target *myinfo =
(struct ipt_set_info_target *) (*target)->data;
- struct ipt_set_info *info;
switch (c) {
- case '1': /* --add-set <set>[:<flags>] <flags> */
- info = &myinfo->add_set;
-
- if (check_inverse(optarg, &invert, NULL, 0))
- exit_error(PARAMETER_PROBLEM,
- "Unexpected `!' after --add-set");
-
- if (!argv[optind]
- || argv[optind][0] == '-' || argv[optind][0] == '!')
- exit_error(PARAMETER_PROBLEM,
- "--add-set requires two args.");
-
- parse_pool(argv[optind - 1], info);
- parse_ipflags(argv[optind++], info);
-
- *flags = 1;
+ case '1': /* --add-set <set> <flags> */
+ parse_target(argv, invert, flags,
+ &myinfo->add_set, "add-set");
break;
case '2': /* --del-set <set>[:<flags>] <flags> */
- info = &myinfo->del_set;
-
- if (check_inverse(optarg, &invert, NULL, 0))
- exit_error(PARAMETER_PROBLEM,
- "Unexpected `!' after --del-set");
-
- if (!argv[optind]
- || argv[optind][0] == '-' || argv[optind][0] == '!')
- exit_error(PARAMETER_PROBLEM,
- "--del-set requires two args.");
-
- parse_pool(argv[optind - 1], info);
- if (parse_ipflags(argv[optind++], info))
- exit_error(PARAMETER_PROBLEM,
- "Can't use overwrite flag with --del-set.");
-
- *flags = 1;
+ parse_target(argv, invert, flags,
+ &myinfo->del_set, "del-set");
break;
default:
@@ -112,21 +122,17 @@ print_target(const char *prefix, const struct ipt_set_info *info)
{
int i;
char setname[IP_SET_MAXNAMELEN];
-
- if (info->id >= 0) {
- get_set_byid(setname, info->id);
- printf("%s %s", prefix, setname);
- for (i = 0; i < info->set_level; i++)
- printf("%s%s",
- i == 0 ? ":" : ",",
- info->flags[i] & IPSET_SRC ? "src" : "dst");
- for (i = info->set_level; i < info->ip_level; i++)
- printf("%s%s%s",
- i == info->set_level ? " " : ",",
- info->flags[i] & IPSET_ADD_OVERWRITE ? "+" : "",
- info->flags[i] & IPSET_SRC ? "src" : "dst");
- printf(" ");
+
+ get_set_byid(setname, info->index);
+ printf("%s %s", prefix, setname);
+ for (i = 0; i < IP_SET_MAX_BINDINGS; i++) {
+ if (!info->flags[i])
+ break;
+ printf("%s%s",
+ i == 0 ? " " : ",",
+ info->flags[i] & IPSET_SRC ? "src" : "dst");
}
+ printf(" ");
}
/* Prints out the targinfo. */
diff --git a/extensions/libipt_SET.man b/extensions/libipt_SET.man
new file mode 100644
index 0000000..8f25bea
--- /dev/null
+++ b/extensions/libipt_SET.man
@@ -0,0 +1,16 @@
+This modules adds and/or deletes entries from IP sets which can be defined
+by ipset(8).
+.TP
+.BR "--add-set " "setname flag[,flag...]"
+add the address(es)/port(s) of the packet to the sets
+.TP
+.BR "--del-set " "setname flag[,flag...]"
+delete the address(es)/port(s) of the packet from the sets,
+where flags are
+.BR "src"
+and/or
+.BR "dst"
+and there can be no more than six of them.
+.TP
+The bindings to follow must previously be defined in order to use
+multilevel adding/deleting by the SET target.
diff --git a/extensions/libipt_set.c b/extensions/libipt_set.c
index 06691f3..7ab78ff 100644
--- a/extensions/libipt_set.c
+++ b/extensions/libipt_set.c
@@ -1,4 +1,14 @@
-/* Shared library add-on to iptables to add IP address set matching. */
+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
+ * Patrick Schaaf <bof@bof.de>
+ * Martin Josefsson <gandalf@wlug.westbo.se>
+ * Copyright (C) 2003-2004 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.
+ */
+
+/* Shared library add-on to iptables to add IP set matching. */
#include <stdio.h>
#include <netdb.h>
#include <string.h>
@@ -10,14 +20,14 @@
#include <iptables.h>
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <linux/netfilter_ipv4/ipt_set.h>
-#include "../ipset/libipt_set.h"
+#include "libipt_set.h"
/* Function which prints out usage message. */
static void help(void)
{
printf("set v%s options:\n"
- " [!] --set name[:flags] flags\n"
- " 'name' is the set name from to match.\n"
+ " [!] --set name flags\n"
+ " 'name' is the set name from to match,\n"
" 'flags' are the comma separated list of\n"
" 'src' and 'dst'.\n"
"\n", IPTABLES_VERSION);
@@ -36,7 +46,6 @@ static void init(struct ipt_entry_match *match, unsigned int *nfcache)
memset(info, 0, sizeof(struct ipt_set_info_match));
- info->match.id = -1;
/* Can't cache this - XXX */
*nfcache |= NFC_UNKNOWN;
@@ -50,23 +59,33 @@ parse(int c, char **argv, int invert, unsigned int *flags,
{
struct ipt_set_info_match *myinfo =
(struct ipt_set_info_match *) (*match)->data;
- struct ipt_set_info *info = &myinfo->match;
+ struct ipt_set_info *info = &myinfo->match_set;
switch (c) {
- case '1': /* --set <set>[:<flags>] <flags> */
+ case '1': /* --set <set> <flag>[,<flag> */
+ if (info->flags[0])
+ exit_error(PARAMETER_PROBLEM,
+ "--set can be specified only once");
+
check_inverse(optarg, &invert, &optind, 0);
if (invert)
info->flags[0] |= IPSET_MATCH_INV;
if (!argv[optind]
- || argv[optind][0] == '-' || argv[optind][0] == '!')
+ || argv[optind][0] == '-'
+ || argv[optind][0] == '!')
exit_error(PARAMETER_PROBLEM,
"--set requires two args.");
- parse_pool(argv[optind - 1], info);
- if (parse_ipflags(argv[optind++], info))
+ if (strlen(argv[optind-1]) > IP_SET_MAXNAMELEN - 1)
exit_error(PARAMETER_PROBLEM,
- "Can't use overwrite flag with --set.");
+ "setname `%s' too long, max %d characters.",
+ argv[optind-1], IP_SET_MAXNAMELEN - 1);
+
+ get_set_byname(argv[optind - 1], info);
+ parse_bindings(argv[optind], info);
+ DEBUGP("parse: set index %u\n", info->index);
+ optind++;
*flags = 1;
break;
@@ -83,7 +102,8 @@ static void final_check(unsigned int flags)
{
if (!flags)
exit_error(PARAMETER_PROBLEM,
- "You must specify either `--set'");
+ "You must specify `--set' with proper arguments");
+ DEBUGP("final check OK\n");
}
static void
@@ -92,22 +112,19 @@ print_match(const char *prefix, const struct ipt_set_info *info)
int i;
char setname[IP_SET_MAXNAMELEN];
- if (info->id >= 0) {
- get_set_byid(setname, info->id);
- printf("%s%s %s",
- (info->flags[0] & IPSET_MATCH_INV) ? "!" : "",
- prefix,
- setname);
- for (i = 0; i < info->set_level; i++)
- printf("%s%s",
- i == 0 ? ":" : ",",
- info->flags[i] & IPSET_SRC ? "src" : "dst");
- for (i = info->set_level; i < info->ip_level; i++)
- printf("%s%s",
- i == info->set_level ? " " : ",",
- info->flags[i] & IPSET_SRC ? "src" : "dst");
- printf(" ");
+ get_set_byid(setname, info->index);
+ printf("%s%s %s",
+ (info->flags[0] & IPSET_MATCH_INV) ? "!" : "",
+ prefix,
+ setname);
+ for (i = 0; i < IP_SET_MAX_BINDINGS; i++) {
+ if (!info->flags[i])
+ break;
+ printf("%s%s",
+ i == 0 ? " " : ",",
+ info->flags[i] & IPSET_SRC ? "src" : "dst");
}
+ printf(" ");
}
/* Prints out the matchinfo. */
@@ -118,7 +135,7 @@ print(const struct ipt_ip *ip,
struct ipt_set_info_match *info =
(struct ipt_set_info_match *) match->data;
- print_match("set", &info->match);
+ print_match("set", &info->match_set);
}
/* Saves the matchinfo in parsable form to stdout. */
@@ -128,11 +145,11 @@ static void save(const struct ipt_ip *ip,
struct ipt_set_info_match *info =
(struct ipt_set_info_match *) match->data;
- print_match("--set", &info->match);
+ print_match("--set", &info->match_set);
}
static
-struct iptables_match set = { NULL,
+struct iptables_match set = {
.name = "set",
.version = IPTABLES_VERSION,
.size = IPT_ALIGN(sizeof(struct ipt_set_info_match)),
diff --git a/extensions/libipt_set.h b/extensions/libipt_set.h
new file mode 100644
index 0000000..0d6b329
--- /dev/null
+++ b/extensions/libipt_set.h
@@ -0,0 +1,104 @@
+#ifndef _LIBIPT_SET_H
+#define _LIBIPT_SET_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#ifdef DEBUG
+#define DEBUGP(x, args...) fprintf(stderr, x, ## args)
+#else
+#define DEBUGP(x, args...)
+#endif
+
+static void
+parse_bindings(const char *optarg, struct ipt_set_info *info)
+{
+ char *saved = strdup(optarg);
+ char *ptr, *tmp = saved;
+ int i = 0;
+
+ while (i < (IP_SET_MAX_BINDINGS - 1) && tmp != NULL) {
+ ptr = strsep(&tmp, ",");
+ if (strncmp(ptr, "src", 3) == 0)
+ info->flags[i++] |= IPSET_SRC;
+ else if (strncmp(ptr, "dst", 3) == 0)
+ info->flags[i++] |= IPSET_DST;
+ else
+ exit_error(PARAMETER_PROBLEM,
+ "You must spefify (the comma separated list of) 'src' or 'dst'.");
+ }
+
+ if (tmp)
+ exit_error(PARAMETER_PROBLEM,
+ "Can't follow bindings deeper than %i.",
+ IP_SET_MAX_BINDINGS - 1);
+
+ free(saved);
+}
+
+static int get_set_getsockopt(void *data, size_t * size)
+{
+ int sockfd = -1;
+ sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+ if (sockfd < 0)
+ exit_error(OTHER_PROBLEM,
+ "Can't open socket to ipset.\n");
+ /* Send! */
+ return getsockopt(sockfd, SOL_IP, SO_IP_SET, data, size);
+}
+
+static void get_set_byname(const char *setname, struct ipt_set_info *info)
+{
+ struct ip_set_req_get_set req;
+ int size = sizeof(struct ip_set_req_get_set);
+ int res;
+
+ req.op = IP_SET_OP_GET_BYNAME;
+ req.version = IP_SET_PROTOCOL_VERSION;
+ strncpy(req.set.name, setname, IP_SET_MAXNAMELEN);
+ req.set.name[IP_SET_MAXNAMELEN - 1] = '\0';
+ res = get_set_getsockopt(&req, &size);
+ if (res != 0)
+ exit_error(OTHER_PROBLEM,
+ "Problem when communicating with ipset, errno=%d.\n",
+ errno);
+ if (size != sizeof(struct ip_set_req_get_set))
+ exit_error(OTHER_PROBLEM,
+ "Incorrect return size from kernel during ipset lookup, "
+ "(want %d, got %d)\n",
+ sizeof(struct ip_set_req_get_set), size);
+ if (req.set.index == IP_SET_INVALID_ID)
+ exit_error(PARAMETER_PROBLEM,
+ "Set %s doesn't exist.\n", setname);
+
+ info->index = req.set.index;
+}
+
+static void get_set_byid(char * setname, ip_set_id_t index)
+{
+ struct ip_set_req_get_set req;
+ int size = sizeof(struct ip_set_req_get_set);
+ int res;
+
+ req.op = IP_SET_OP_GET_BYINDEX;
+ req.version = IP_SET_PROTOCOL_VERSION;
+ req.set.index = index;
+ res = get_set_getsockopt(&req, &size);
+ if (res != 0)
+ exit_error(OTHER_PROBLEM,
+ "Problem when communicating with ipset, errno=%d.\n",
+ errno);
+ if (size != sizeof(struct ip_set_req_get_set))
+ exit_error(OTHER_PROBLEM,
+ "Incorrect return size from kernel during ipset lookup, "
+ "(want %d, got %d)\n",
+ sizeof(struct ip_set_req_get_set), size);
+ if (req.set.name[0] == '\0')
+ exit_error(PARAMETER_PROBLEM,
+ "Set id %i in kernel doesn't exist.\n", index);
+
+ strncpy(setname, req.set.name, IP_SET_MAXNAMELEN);
+}
+
+#endif /*_LIBIPT_SET_H*/
diff --git a/extensions/libipt_set.man b/extensions/libipt_set.man
new file mode 100644
index 0000000..d280577
--- /dev/null
+++ b/extensions/libipt_set.man
@@ -0,0 +1,17 @@
+This modules macthes IP sets which can be defined by ipset(8).
+.TP
+.BR "--set " "setname flag[,flag...]"
+where flags are
+.BR "src"
+and/or
+.BR "dst"
+and there can be no more than six of them. Hence the command
+.nf
+ iptables -A FORWARD -m set --set test src,dst
+.fi
+will match packets, for which (depending on the type of the set) the source
+address or port number of the packet can be found in the specified set. If
+there is a binding belonging to the mached set element or there is a default
+binding for the given set, then the rule will match the packet only if
+additionally (depending on the type of the set) the destination address or
+port number of the packet can be found in the set according to the binding.