[PATCH] iptables: ip6table version support and
libip6t_multiport.fix
Laurence J. Lane
ljlane at debian.org
Mon Oct 2 03:37:54 CEST 2006
On 9/10/06, Laurence J. Lane <ljlane at debian.org> wrote:
> details: http://bugs.debian.org/329775
>
> The 329775-submitter at bugs.debian.org address reaches all
> interested Debian parties.
>
> Rémi Denis-Courmont has submitted a patch to that adds version support
> to ip6tables and updates libip6t_multiport to v1. (Rémi also posted to the
> list but something appears to have gone wrong.)
>
> It Works for Me.
I guess the list software ate the attachment.
diff -Nru iptables-1.3.5.orig/extensions/libip6t_multiport.c
iptables-1.3.5/extensions/libip6t_multiport.c
--- iptables-1.3.5.orig/extensions/libip6t_multiport.c 2005-02-19
21:19:17.000000000 +0200
+++ iptables-1.3.5/extensions/libip6t_multiport.c 2006-08-27
13:03:36.000000000 +0300
@@ -20,6 +20,23 @@
" --dports ...\n"
" match destination port(s)\n"
" --ports port[,port,port]\n"
+" match both source and destination port(s)\n"
+" NOTE: this kernel does not support port ranges in multiport.\n",
+IPTABLES_VERSION);
+}
+
+static void
+help_v1(void)
+{
+ printf(
+"multiport v%s options:\n"
+" --source-ports [!] port[,port:port,port...]\n"
+" --sports ...\n"
+" match source port(s)\n"
+" --destination-ports [!] port[,port:port,port...]\n"
+" --dports ...\n"
+" match destination port(s)\n"
+" --ports [!] port[,port:port,port]\n"
" match both source and destination port(s)\n",
IPTABLES_VERSION);
}
@@ -49,7 +66,7 @@
{
unsigned int portnum;
- if ((string_to_number(port, 0, 65535, &portnum)) != -1 ||
+ if (string_to_number(port, 0, 65535, &portnum) != -1 ||
(portnum = service_to_port(port, proto)) != -1)
return (u_int16_t)portnum;
@@ -77,6 +94,46 @@
return i;
}
+static void
+parse_multi_ports_v1(const char *portstring,
+ struct xt_multiport_v1 *multiinfo,
+ const char *proto)
+{
+ char *buffer, *cp, *next, *range;
+ unsigned int i;
+ u_int16_t m;
+
+ buffer = strdup(portstring);
+ if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed");
+
+ for (i=0; i<XT_MULTI_PORTS; i++)
+ multiinfo->pflags[i] = 0;
+
+ for (cp=buffer, i=0; cp && i<XT_MULTI_PORTS; cp=next, i++) {
+ next=strchr(cp, ',');
+ if (next) *next++='\0';
+ range = strchr(cp, ':');
+ if (range) {
+ if (i == XT_MULTI_PORTS-1)
+ exit_error(PARAMETER_PROBLEM,
+ "too many ports specified");
+ *range++ = '\0';
+ }
+ multiinfo->ports[i] = parse_port(cp, proto);
+ if (range) {
+ multiinfo->pflags[i] = 1;
+ multiinfo->ports[++i] = parse_port(range, proto);
+ if (multiinfo->ports[i-1] >= multiinfo->ports[i])
+ exit_error(PARAMETER_PROBLEM,
+ "invalid portrange specified");
+ m <<= 1;
+ }
+ }
+ multiinfo->count = i;
+ if (cp) exit_error(PARAMETER_PROBLEM, "too many ports specified");
+ free(buffer);
+}
+
/* Initialize the match. */
static void
init(struct ip6t_entry_match *m, unsigned int *nfcache)
@@ -150,6 +207,52 @@
return 1;
}
+static int
+parse_v1(int c, char **argv, int invert, unsigned int *flags,
+ const struct ip6t_entry *entry,
+ unsigned int *nfcache,
+ struct ip6t_entry_match **match)
+{
+ const char *proto;
+ struct xt_multiport_v1 *multiinfo
+ = (struct xt_multiport_v1 *)(*match)->data;
+
+ switch (c) {
+ case '1':
+ check_inverse(argv[optind-1], &invert, &optind, 0);
+ proto = check_proto(entry);
+ parse_multi_ports_v1(argv[optind-1], multiinfo, proto);
+ multiinfo->flags = IP6T_MULTIPORT_SOURCE;
+ break;
+
+ case '2':
+ check_inverse(argv[optind-1], &invert, &optind, 0);
+ proto = check_proto(entry);
+ parse_multi_ports_v1(argv[optind-1], multiinfo, proto);
+ multiinfo->flags = IP6T_MULTIPORT_DESTINATION;
+ break;
+
+ case '3':
+ check_inverse(argv[optind-1], &invert, &optind, 0);
+ proto = check_proto(entry);
+ parse_multi_ports_v1(argv[optind-1], multiinfo, proto);
+ multiinfo->flags = IP6T_MULTIPORT_EITHER;
+ break;
+
+ default:
+ return 0;
+ }
+
+ if (invert)
+ multiinfo->invert = 1;
+
+ if (*flags)
+ exit_error(PARAMETER_PROBLEM,
+ "multiport can only have one option");
+ *flags = 1;
+ return 1;
+}
+
/* Final check; must specify something. */
static void
final_check(unsigned int flags)
@@ -218,6 +321,49 @@
printf(" ");
}
+static void
+print_v1(const struct ip6t_ip6 *ip,
+ const struct ip6t_entry_match *match,
+ int numeric)
+{
+ const struct xt_multiport_v1 *multiinfo
+ = (const struct xt_multiport_v1 *)match->data;
+ unsigned int i;
+
+ printf("multiport ");
+
+ switch (multiinfo->flags) {
+ case IP6T_MULTIPORT_SOURCE:
+ printf("sports ");
+ break;
+
+ case IP6T_MULTIPORT_DESTINATION:
+ printf("dports ");
+ break;
+
+ case IP6T_MULTIPORT_EITHER:
+ printf("ports ");
+ break;
+
+ default:
+ printf("ERROR ");
+ break;
+ }
+
+ if (multiinfo->invert)
+ printf("! ");
+
+ for (i=0; i < multiinfo->count; i++) {
+ printf("%s", i ? "," : "");
+ print_port(multiinfo->ports[i], ip->proto, numeric);
+ if (multiinfo->pflags[i]) {
+ printf(":");
+ print_port(multiinfo->ports[++i], ip->proto, numeric);
+ }
+ }
+ printf(" ");
+}
+
/* Saves the union ip6t_matchinfo in parsable form to stdout. */
static void save(const struct ip6t_ip6 *ip, const struct
ip6t_entry_match *match)
{
@@ -246,6 +392,41 @@
printf(" ");
}
+static void save_v1(const struct ip6t_ip6 *ip,
+ const struct ip6t_entry_match *match)
+{
+ const struct xt_multiport_v1 *multiinfo
+ = (const struct xt_multiport_v1 *)match->data;
+ unsigned int i;
+
+ switch (multiinfo->flags) {
+ case IP6T_MULTIPORT_SOURCE:
+ printf("--sports ");
+ break;
+
+ case IP6T_MULTIPORT_DESTINATION:
+ printf("--dports ");
+ break;
+
+ case IP6T_MULTIPORT_EITHER:
+ printf("--ports ");
+ break;
+ }
+
+ if (multiinfo->invert)
+ printf("! ");
+
+ for (i=0; i < multiinfo->count; i++) {
+ printf("%s", i ? "," : "");
+ print_port(multiinfo->ports[i], ip->proto, 1);
+ if (multiinfo->pflags[i]) {
+ printf(":");
+ print_port(multiinfo->ports[++i], ip->proto, 1);
+ }
+ }
+ printf(" ");
+}
+
static struct ip6tables_match multiport = {
.name = "multiport",
.version = IPTABLES_VERSION,
@@ -260,8 +441,25 @@
.extra_opts = opts,
};
+static struct ip6tables_match multiport_v1 = {
+ .next = NULL,
+ .name = "multiport",
+ .revision = 1,
+ .version = IPTABLES_VERSION,
+ .size = IP6T_ALIGN(sizeof(struct xt_multiport_v1)),
+ .userspacesize = IP6T_ALIGN(sizeof(struct xt_multiport_v1)),
+ .help = &help_v1,
+ .init = &init,
+ .parse = &parse_v1,
+ .final_check = &final_check,
+ .print = &print_v1,
+ .save = &save_v1,
+ .extra_opts = opts
+};
+
void
_init(void)
{
register_match6(&multiport);
+ register_match6(&multiport_v1);
}
diff -Nru iptables-1.3.5.orig/include/ip6tables.h
iptables-1.3.5/include/ip6tables.h
--- iptables-1.3.5.orig/include/ip6tables.h 2006-01-30 10:43:09.000000000 +0200
+++ iptables-1.3.5/include/ip6tables.h 2006-08-27 13:02:55.000000000 +0300
@@ -22,6 +22,9 @@
ip6t_chainlabel name;
+ /* Revision of match (0 by default). */
+ u_int8_t revision;
+
const char *version;
/* Size of match data. */
diff -Nru iptables-1.3.5.orig/ip6tables.c iptables-1.3.5/ip6tables.c
--- iptables-1.3.5.orig/ip6tables.c 2006-01-30 10:43:12.000000000 +0200
+++ iptables-1.3.5/ip6tables.c 2006-08-27 13:13:37.000000000 +0300
@@ -193,6 +193,8 @@
const char *program_name;
char *lib_dir;
+int kernel_version;
+
/* Keeping track of external matches and targets: linked lists. */
struct ip6tables_match *ip6tables_matches = NULL;
struct ip6tables_target *ip6tables_targets = NULL;
@@ -1047,10 +1049,51 @@
return merge;
}
+static int compatible_revision(const char *name, u_int8_t revision, int opt)
+{
+ struct ip6t_get_revision rev;
+ socklen_t s = sizeof(rev);
+ int max_rev, sockfd;
+
+ sockfd = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
+ if (sockfd < 0) {
+ fprintf(stderr, "Could not open socket to kernel: %s\n",
+ strerror(errno));
+ exit(1);
+ }
+
+ strcpy(rev.name, name);
+ rev.revision = revision;
+
+ max_rev = getsockopt(sockfd, IPPROTO_IPV6, opt, &rev, &s);
+ if (max_rev < 0) {
+ /* Definitely don't support this? */
+ if (errno == EPROTONOSUPPORT) {
+ close(sockfd);
+ return 0;
+ } else if (errno == ENOPROTOOPT) {
+ close(sockfd);
+ /* Assume only revision 0 support (old kernel) */
+ return (revision == 0);
+ } else {
+ fprintf(stderr, "getsockopt failed strangely: %s\n",
+ strerror(errno));
+ exit(1);
+ }
+ }
+ close(sockfd);
+ return 1;
+}
+
+static int compatible_match_revision(const char *name, u_int8_t revision)
+{
+ return compatible_revision(name, revision, IP6T_SO_GET_REVISION_MATCH);
+}
+
void
register_match6(struct ip6tables_match *me)
{
- struct ip6tables_match **i;
+ struct ip6tables_match **i, *old;
if (strcmp(me->version, program_version) != 0) {
fprintf(stderr, "%s: match `%s' v%s (I'm v%s).\n",
@@ -1058,12 +1101,36 @@
exit(1);
}
- if (find_match(me->name, DURING_LOAD, NULL)) {
- fprintf(stderr, "%s: match `%s' already registered.\n",
+ /* Revision field stole a char from name. */
+ if (strlen(me->name) >= IP6T_FUNCTION_MAXNAMELEN-1) {
+ fprintf(stderr, "%s: target `%s' has invalid name\n",
program_name, me->name);
exit(1);
}
+ old = find_match(me->name, DURING_LOAD, NULL);
+ if (old) {
+ if (old->revision == me->revision) {
+ fprintf(stderr,
+ "%s: match `%s' already registered.\n",
+ program_name, me->name);
+ exit(1);
+ }
+
+ /* Now we have two (or more) options, check compatibility. */
+ if (compatible_match_revision(old->name, old->revision)
+ && old->revision > me->revision)
+ return;
+
+ /* Replace if compatible. */
+ if (!compatible_match_revision(me->name, me->revision))
+ return;
+
+ /* Delete old one. */
+ for (i = &ip6tables_matches; *i!=old; i = &(*i)->next);
+ *i = old->next;
+ }
+
if (me->size != IP6T_ALIGN(me->size)) {
fprintf(stderr, "%s: match `%s' has invalid size %u.\n",
program_name, me->name, (unsigned int)me->size);
@@ -1700,6 +1767,14 @@
*matches = NULL;
}
+static void set_revision(char *name, u_int8_t revision)
+{
+ /* Old kernel sources don't have ".revision" field,
+ but we stole a byte from name. */
+ name[IP6T_FUNCTION_MAXNAMELEN - 2] = '\0';
+ name[IP6T_FUNCTION_MAXNAMELEN - 1] = revision;
+}
+
int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle)
{
struct ip6t_entry fw, *e = NULL;
@@ -1978,6 +2053,7 @@
m->m = fw_calloc(1, size);
m->m->u.match_size = size;
strcpy(m->m->u.user.name, m->name);
+ set_revision(m->m->u.user.name, m->revision);
if (m->init != NULL)
m->init(m->m, &fw.nfcache);
opts = merge_options(opts, m->extra_opts, &m->option_offset);
@@ -2120,6 +2196,8 @@
m->m = fw_calloc(1, size);
m->m->u.match_size = size;
strcpy(m->m->u.user.name, m->name);
+ set_revision(m->m->u.user.name,
+ m->revision);
if (m->init != NULL)
m->init(m->m, &fw.nfcache);
More information about the netfilter-devel
mailing list