summaryrefslogtreecommitdiffstats
path: root/ip6tables.c
diff options
context:
space:
mode:
author/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=yasuyuki/emailAddress=yasuyuki@netfilter.org </C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=yasuyuki/emailAddress=yasuyuki@netfilter.org>2006-10-20 12:24:34 +0000
committer/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=yasuyuki/emailAddress=yasuyuki@netfilter.org </C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=yasuyuki/emailAddress=yasuyuki@netfilter.org>2006-10-20 12:24:34 +0000
commit18b5628da718a56fed9628763669da36b5225aa2 (patch)
tree7423f160dbf6a9767e28b38538cbecca0362daf5 /ip6tables.c
parentd517a823e33419d6ee9f7f22d5270e6e750c891c (diff)
- Add revision support to ip6tables.
- Add support port range match to libip6t_multiport (R?mi Denis-Courmont <rdenis@simphalempin.com>)
Diffstat (limited to 'ip6tables.c')
-rw-r--r--ip6tables.c82
1 files changed, 79 insertions, 3 deletions
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);