From 18b5628da718a56fed9628763669da36b5225aa2 Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=yasuyuki/emailAddress=yasuyuki@netfilter.org" Date: Fri, 20 Oct 2006 12:24:34 +0000 Subject: - Add revision support to ip6tables. - Add support port range match to libip6t_multiport (R?mi Denis-Courmont ) --- ip6tables.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 79 insertions(+), 3 deletions(-) (limited to 'ip6tables.c') diff --git a/ip6tables.c b/ip6tables.c index 659041f..92e434c 100644 --- a/ip6tables.c +++ b/ip6tables.c @@ -1102,10 +1102,51 @@ merge_options(struct option *oldopts, const struct option *newopts, 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 +1154,36 @@ register_match6(struct ip6tables_match *me) 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 +1826,14 @@ void clear_rule_matches(struct ip6tables_rule_match **matches) *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 +2114,7 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) 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 +2259,8 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle) 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); -- cgit v1.2.3