Commit cad3ff82 authored by Rusty Russell's avatar Rusty Russell Committed by Linus Torvalds

[PATCH] iptables revision getsockopt

This adds a new getsockopt to iptables, which allows userspace to
query the revision number of extensions.  iptables 1.3.0 (to be
released soon) already has support for this.
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 5d9ed066
...@@ -158,7 +158,9 @@ struct ipt_entry ...@@ -158,7 +158,9 @@ struct ipt_entry
#define IPT_SO_GET_INFO (IPT_BASE_CTL) #define IPT_SO_GET_INFO (IPT_BASE_CTL)
#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1) #define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1)
#define IPT_SO_GET_MAX IPT_SO_GET_ENTRIES #define IPT_SO_GET_REVISION_MATCH (IPT_BASE_CTL + 2)
#define IPT_SO_GET_REVISION_TARGET (IPT_BASE_CTL + 3)
#define IPT_SO_GET_MAX IPT_SO_GET_REVISION_TARGET
/* CONTINUE verdict for targets */ /* CONTINUE verdict for targets */
#define IPT_CONTINUE 0xFFFFFFFF #define IPT_CONTINUE 0xFFFFFFFF
...@@ -288,6 +290,15 @@ struct ipt_get_entries ...@@ -288,6 +290,15 @@ struct ipt_get_entries
struct ipt_entry entrytable[0]; struct ipt_entry entrytable[0];
}; };
/* The argument to IPT_SO_GET_REVISION_*. Returns highest revision
* kernel supports, if >= revision. */
struct ipt_get_revision
{
char name[IPT_FUNCTION_MAXNAMELEN-1];
u_int8_t revision;
};
/* Standard return verdict, or do jump. */ /* Standard return verdict, or do jump. */
#define IPT_STANDARD_TARGET "" #define IPT_STANDARD_TARGET ""
/* Error verdict. */ /* Error verdict. */
......
...@@ -488,6 +488,65 @@ static inline struct ipt_target *find_target_lock(const char *name, u8 revision) ...@@ -488,6 +488,65 @@ static inline struct ipt_target *find_target_lock(const char *name, u8 revision)
return ERR_PTR(-EPROTOTYPE); return ERR_PTR(-EPROTOTYPE);
} }
static int match_revfn(const char *name, u8 revision, int *bestp)
{
struct ipt_match *m;
int have_rev = 0;
list_for_each_entry(m, &ipt_match, list) {
if (strcmp(m->name, name) == 0) {
if (m->revision > *bestp)
*bestp = m->revision;
if (m->revision == revision)
have_rev = 1;
}
}
return have_rev;
}
static int target_revfn(const char *name, u8 revision, int *bestp)
{
struct ipt_target *t;
int have_rev = 0;
list_for_each_entry(t, &ipt_target, list) {
if (strcmp(t->name, name) == 0) {
if (t->revision > *bestp)
*bestp = t->revision;
if (t->revision == revision)
have_rev = 1;
}
}
return have_rev;
}
/* Returns true or false (if no such extension at all) */
static inline int find_revision(const char *name, u8 revision,
int (*revfn)(const char *, u8, int *),
int *err)
{
int have_rev, best = -1;
if (down_interruptible(&ipt_mutex) != 0) {
*err = -EINTR;
return 1;
}
have_rev = revfn(name, revision, &best);
up(&ipt_mutex);
/* Nothing at all? Return 0 to try loading module. */
if (best == -1) {
*err = -ENOENT;
return 0;
}
*err = best;
if (!have_rev)
*err = -EPROTONOSUPPORT;
return 1;
}
/* All zeroes == unconditional rule. */ /* All zeroes == unconditional rule. */
static inline int static inline int
unconditional(const struct ipt_ip *ip) unconditional(const struct ipt_ip *ip)
...@@ -1316,6 +1375,31 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) ...@@ -1316,6 +1375,31 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
break; break;
} }
case IPT_SO_GET_REVISION_MATCH:
case IPT_SO_GET_REVISION_TARGET: {
struct ipt_get_revision rev;
int (*revfn)(const char *, u8, int *);
if (*len != sizeof(rev)) {
ret = -EINVAL;
break;
}
if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
ret = -EFAULT;
break;
}
if (cmd == IPT_SO_GET_REVISION_TARGET)
revfn = target_revfn;
else
revfn = match_revfn;
try_then_request_module(find_revision(rev.name, rev.revision,
revfn, &ret),
"ipt_%s", rev.name);
break;
}
default: default:
duprintf("do_ipt_get_ctl: unknown request %i\n", cmd); duprintf("do_ipt_get_ctl: unknown request %i\n", cmd);
ret = -EINVAL; ret = -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment