Support for IPv6 multiport ports range
PATCH 1/1 Support for IPv6 multiport ports range
Hello,
While merging ipt_multiport and ip6t_multiport to xt_multiport in kernel 2.6.17, ip6t_multiport gained support for port ranges. However, iptables userland does not currently support the feature.
The first patch adds revision matching support for match extensions in ip6tables, and the second actually adds port range support to libip6t_multiport.
---- ip6tables-revision.patch ----
ip6tables.h +3 -0
@@ -33,6 +33,9 @@ip6t_chainlabel name; +/* Revision of match (0 by default). */ +u_int8_t revision; +const char *version;/* Size of match data. */
ip6tables.c +3 -0
@@ -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 ;
@@ -1102,10 +1104,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",
@@ -1113,12 +1156,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);
@@ -1761,6 +1828,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;
@@ -2041,6 +2116,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);
if (m != m->next)
@@ -2185,6 +2261,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);
---- end ----
---- ipv6-multiport-v1.patch ----
libip6t_multiport.c +146 -0
169 lines not on this page · raw message
ip6t_entry_match *match)
{
@@ -238,6 +384,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,
@@ -252,8 +433,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);
}
---- end ----
Regards,
Signature · 2 lines
Rémi Denis-Courmont http://www.remlab.net/