DNETMAP version 2

- new type: static binding
- new persistent flag option for prefix
- add extra information in /proc/net/xt_DNETMAP/prefix_stat that
  includes the count of static bindings and persistent flag
- add proc interface write support (add/del/flush binding)
- updated manual
This commit is contained in:
Marek Kierdelewicz
2012-06-10 12:35:56 +02:00
committed by Jan Engelhardt
parent 1e8da7c31c
commit 492236f931
4 changed files with 446 additions and 81 deletions

View File

@@ -20,6 +20,8 @@ static const struct option DNETMAP_opts[] = {
{"prefix", 1, NULL, 'p'},
{"reuse", 0, NULL, 'r'},
{"ttl", 1, NULL, 't'},
{"static", 0, NULL, 's'},
{"persistent", 0, NULL, 'e'},
{.name = NULL}
};
@@ -33,9 +35,14 @@ static void DNETMAP_help(void)
" --%s seconds\n"
" Regenerate bindings ttl value to seconds. If negative value is specified,\n"
" bindings ttl is kept unchanged. If not specified then default ttl value (600s)\n"
" is used.\n\n",
" is used\n"
" --%s\n"
" Match only static entries for this rule. Dynamic entries won't be created.\n"
" --%s\n"
" Set prefix persistent. It won't be removed after deleting last iptables rule.\n\n",
DNETMAP_opts[0].name, DNETMAP_opts[1].name,
DNETMAP_opts[2].name);
DNETMAP_opts[2].name, DNETMAP_opts[3].name,
DNETMAP_opts[4].name);
}
static u_int32_t bits2netmask(int bits)
@@ -151,6 +158,20 @@ static int DNETMAP_parse(int c, char **argv, int invert, unsigned int *flags,
*flags |= XT_DNETMAP_REUSE;
tginfo->flags |= XT_DNETMAP_REUSE;
return 1;
case 's':
xtables_param_act(XTF_ONLY_ONCE, MODULENAME, "--static",
*flags & XT_DNETMAP_STATIC);
xtables_param_act(XTF_NO_INVERT, MODULENAME, "--static", invert);
*flags |= XT_DNETMAP_STATIC;
tginfo->flags |= XT_DNETMAP_STATIC;
return 1;
case 'e':
xtables_param_act(XTF_ONLY_ONCE, MODULENAME, "--persistent",
*flags & XT_DNETMAP_PERSISTENT);
xtables_param_act(XTF_NO_INVERT, MODULENAME, "--persistent", invert);
*flags |= XT_DNETMAP_PERSISTENT;
tginfo->flags |= XT_DNETMAP_PERSISTENT;
return 1;
case 't':
xtables_param_act(XTF_ONLY_ONCE, MODULENAME, "--ttl",
*flags & XT_DNETMAP_TTL);
@@ -198,7 +219,15 @@ static void DNETMAP_print(const void *ip, const struct xt_entry_target *target,
else
printf("any");
printf(" reuse %i", (*flags & XT_DNETMAP_REUSE) > 0);
if (*flags & XT_DNETMAP_REUSE)
printf(" reuse");
if (*flags & XT_DNETMAP_STATIC)
printf(" static");
if (*flags & XT_DNETMAP_PERSISTENT)
printf(" persistent");
if (*flags & XT_DNETMAP_TTL)
printf(" ttl %i", tginfo->ttl);
else
@@ -214,7 +243,15 @@ static void DNETMAP_save(const void *ip, const struct xt_entry_target *target)
printf(" --%s ", DNETMAP_opts[0].name);
DNETMAP_print_addr(ip, target, 0);
}
printf(" --reuse %i ", *flags & XT_DNETMAP_REUSE);
if (*flags & XT_DNETMAP_REUSE)
printf(" --reuse ");
if (*flags & XT_DNETMAP_STATIC)
printf(" --static ");
if (*flags & XT_DNETMAP_PERSISTENT)
printf(" --persistent ");
/* ommited because default value can change as kernel mod param */
if (*flags & XT_DNETMAP_TTL)

View File

@@ -18,6 +18,17 @@ Network subnet to map to. If not specified, all existing prefixes are used.
\fB\-\-reuse\fR
Reuse entry for given prenat-ip from any prefix despite bindings ttl < 0.
.TP
\fB\-\-persistent\fR
Set prefix persistent. It won't be removed after deleting last iptables rule.
Option is effective only in the first rule for a given prefix. If you
need to change persistency for existing prefix, please use proc interface
described below.
.TP
\fB\-\-static\fR
Don't create dynamic mappings using this rule. Use static mappings only. Note
that you need to create static mappings via proc interface for this rule with
this option to have any effect.
.TP
\fB\-\-ttl\fR \fIseconds\fR
Regenerate bindings ttl value to \fIseconds\fR. If negative value is specified,
bindings ttl is kept unchanged. If not specified then default ttl value (600s)
@@ -30,16 +41,45 @@ Module creates following entries for each new specified subnet:
\fB/proc/net/xt_DNETMAP/\fR\fIsubnet\fR\fB_\fR\fImask\fR
Contains binding table for subnet/mask. Each line contains \fBprenat-ip\fR,
\fBpostnat-ip\fR,\fBttl\fR (seconds till entry times out), \fBlasthit\fR (last
entry hit in seconds relative to system boot time).
entry hit in seconds relative to system boot time). Please note that \fBttl\fR
and \fBlasthit\fR entries contain \fBS\fR in case of static binding.
.TP
\fB/proc/net/xt_DNETMAP/\fR\fIsubnet\fR\fB_\fR\fImask\fR\fB_stat\fR
Contains statistics for given subnet/mask. Line contains contains three
Contains statistics for given subnet/mask. Line contains contains four
numerical values separated by spaces. First one is number of currently used
addresses (bindings with negative ttl excluded), second one is number of all
usable addresses in subnet and third one is mean \fBttl\fR value for all active
entries.
dynamic addresses (bindings with negative ttl excluded), second one is number
static assignments, third one is number of all usable addresses in subnet and
the fourth one is mean \fBttl\fR value for all active entries. If prefix has
persistent flag set it'll be noted as fifth entry.
.PP
Following write operations are supported via proc interface:
.TP
echo "+\fIprenatIP\fR:\fIpostnatIP\fR" > \fB/proc/net/xt_DNETMAP/subnet_mask\fR
Adds static binding between prenatIP nad postnatIP. If postnatIP is already
bound, previous binding will be timedout immediatelly. Static binding is never
timedout.
.TP
echo "-\fIIP\fR" > \fB/proc/net/xt_DNETMAP/subnet_mask\fR
Removes binding with \fIIP\fR as prenat or postnat address. If removed binding
is currently static, it'll make entry available for dynamic allocation.
.TP
echo "+persistent" > \fB/proc/net/xt_DNETMAP/subnet_mask\fR
Sets persistent flag for prefix. It's usefull if you don't want bindings to get
flushed when firewall is restarted. You can check if prefix is persistent by
printing \fB/proc/net/xt_DNETMAP/\fR\fIsubnet\fR\fB_\fR\fImask\fR\fB_stat\fR
contents.
.TP
echo "-persistent" > \fB/proc/net/xt_DNETMAP/subnet_mask\fR
Unsets persistent flag for prefix. In this mode prefix will be deleted if the
last iptables rule for that prefix is removed.
.TP
echo "flush" > \fB/proc/net/xt_DNETMAP/subnet_mask\fR
Flushes all bindings for specific prefix. All static entries are also flushed
and are available for dynamic bindings.
.PP
Note! Entries are removed if the last iptables rule for a specific prefix is
deleted unless there's persistent flag set.
.PP
Entries are removed if the last iptables rule for a specific subnet is deleted.
\fB* Logging\fR
@@ -88,4 +128,45 @@ specify \fB\-\-prefix\fR parameter in PREROUTING rule, because this way it DNATs
traffic to all active prefixes. You could specify prefix it you'd like to make
DNAT work for specific prefix only.
\fB4.\fR Map 192.168.0.0/24 to subnets 20.0.0.0/26 with static assignments only:
iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j DNETMAP --prefix 20.0.0.0/26
--static
echo "+192.168.0.10:20.0.0.1" > /proc/net/xt_DNETMAP/20.0.0.0_26
.br
echo "+192.168.0.11:20.0.0.2" > /proc/net/xt_DNETMAP/20.0.0.0_26
.br
echo "+192.168.0.51:20.0.0.3" > /proc/net/xt_DNETMAP/20.0.0.0_26
This configuration will allow only preconfigured static bindings to work due to
\fBstatic\fR rule option. Without this flag dynamic bindings would be created
using non-static entries.
\fB5.\fR Persistent prefix:
iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j DNETMAP --prefix 20.0.0.0/26
--persistent
.br
\fBor\fR
.br
iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j DNETMAP --prefix 20.0.0.0/26
.br
echo "+persistent" > /proc/net/xt_DNETMAP/20.0.0.0_26
Now we can check persistent flag of the prefix:
.br
cat /proc/net/xt_DNETMAP/20.0.0.0_26
.br
0 0 64 0 \fBpersistent\fR
Flush iptables nat table and see that prefix is still in existence:
.br
iptables -F -t nat
.br
ls -l /proc/net/xt_DNETMAP
.br
-rw-r--r-- 1 root root 0 06-10 09:01 20.0.0.0_26
.br
-rw-r--r-- 1 root root 0 06-10 09:01 20.0.0.0_26_stat
.

View File

@@ -3,7 +3,7 @@
* or destination (PREROUTING),
*/
/* (C) 2011 Marek Kierdelewicz <marek@koba.pl>
/* (C) 2012 Marek Kierdelewicz <marek@koba.pl>
*
* module is dedicated to my wife Eliza and my daughters Jula and Ola :* :* :*
*
@@ -40,7 +40,7 @@
#include "xt_DNETMAP.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marek Kierdelewicz <marek@koba.pl>");
MODULE_AUTHOR("Marek Kierdelewicz <marek@piasta.pl>");
MODULE_DESCRIPTION(
"Xtables: dynamic two-way 1:1 NAT mapping of IPv4 addresses");
MODULE_ALIAS("ipt_DNETMAP");
@@ -77,6 +77,7 @@ struct dnetmap_entry {
struct list_head lru_list;
__be32 prenat_addr;
__be32 postnat_addr;
__u8 flags;
unsigned long stamp;
struct dnetmap_prefix *prefix;
};
@@ -84,12 +85,18 @@ struct dnetmap_entry {
struct dnetmap_prefix {
struct nf_nat_ipv4_multi_range_compat prefix;
char prefix_str[16];
struct list_head list;
#ifdef CONFIG_PROC_FS
char proc_str_data[20];
char proc_str_stat[25];
#endif
struct list_head elist; // element list head
struct list_head list; // prefix list
__u8 flags;
unsigned int refcnt;
/* lru entry list */
struct list_head lru_list;
/* hash based on prenat-ips */
struct list_head iphash[0];
/* pointer do dnetmap_net */
struct dnetmap_net *dnetmap;
};
struct dnetmap_net {
@@ -157,6 +164,18 @@ dnetmap_entry_rlookup(struct dnetmap_net *dnetmap_net, const __be32 addr)
return NULL;
}
static int
dnetmap_addr_in_prefix(struct dnetmap_net *dnetmap_net, const __be32 addr,
struct dnetmap_prefix *p)
{
struct dnetmap_entry *e;
list_for_each_entry(e, &p->elist, list)
if (memcmp(&e->postnat_addr, &addr, sizeof(addr)) == 0)
return 1;
return 0;
}
static struct dnetmap_prefix *
dnetmap_prefix_lookup(struct dnetmap_net *dnetmap_net,
const struct nf_nat_ipv4_multi_range_compat *mr)
@@ -169,12 +188,47 @@ dnetmap_prefix_lookup(struct dnetmap_net *dnetmap_net,
return NULL;
}
static void dnetmap_prefix_flush(struct dnetmap_net *dnetmap_net,
static void dnetmap_prefix_destroy(struct dnetmap_net *dnetmap_net,
struct dnetmap_prefix *p)
{
struct dnetmap_entry *e, *next;
unsigned int i;
#ifdef CONFIG_PROC_FS
remove_proc_entry(p->proc_str_data, dnetmap_net->xt_dnetmap);
remove_proc_entry(p->proc_str_stat, dnetmap_net->xt_dnetmap);
#endif
for (i = 0; i < hash_size; i++) {
list_for_each_entry_safe(e, next,
&dnetmap_net->dnetmap_iphash[i], glist)
if (e->prefix == p)
list_del(&e->glist);
list_for_each_entry_safe(e, next,
&dnetmap_net->
dnetmap_iphash[hash_size + i], grlist)
if (e->prefix == p)
list_del(&e->grlist);
}
list_for_each_entry_safe(e, next, &p->elist, list) {
list_del(&e->list);
if(! (e->flags & XT_DNETMAP_STATIC)) list_del(&e->lru_list);
kfree(e);
}
list_del(&p->list);
kfree(p);
}
/* function clears bindings without destroying prefix */
static void dnetmap_prefix_softflush(struct dnetmap_prefix *p)
{
struct dnetmap_net *dnetmap_net = p->dnetmap;
struct dnetmap_entry *e, *next;
unsigned int i;
for (i = 0; i < hash_size; i++) {
list_for_each_entry_safe(e, next,
&dnetmap_net->dnetmap_iphash[i], glist)
@@ -186,12 +240,16 @@ static void dnetmap_prefix_flush(struct dnetmap_net *dnetmap_net,
dnetmap_iphash[hash_size + i], grlist)
if (e->prefix == p)
list_del(&e->grlist);
list_for_each_entry_safe(e, next, &p->iphash[i], list) {
list_del(&e->list);
list_del(&e->lru_list);
kfree(e);
}
list_for_each_entry_safe(e, next, &p->elist, list) {
/* make dynamic entry of any static entry */
if(e->flags & XT_DNETMAP_STATIC){
list_add_tail(&e->lru_list, &p->lru_list);
e->flags&=~XT_DNETMAP_STATIC;
}
e->stamp=jiffies-1;
e->prenat_addr=0;
}
}
@@ -204,11 +262,8 @@ static int dnetmap_tg_check(const struct xt_tgchk_param *par)
struct dnetmap_entry *e;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *pde_data, *pde_stat;
char proc_str_data[20];
char proc_str_stat[25];
#endif
int ret = -EINVAL;
int i;
__be32 a;
__u32 ip_min, ip_max, ip;
@@ -243,11 +298,13 @@ static int dnetmap_tg_check(const struct xt_tgchk_param *par)
goto out;
}
p->refcnt = 1;
p->flags = 0;
p->flags |= (tginfo->flags & XT_DNETMAP_PERSISTENT);
p->dnetmap = dnetmap_net;
memcpy(&p->prefix, mr, sizeof(*mr));
INIT_LIST_HEAD(&p->lru_list);
for (i = 0; i < hash_size * 2; i++)
INIT_LIST_HEAD(&p->iphash[i]);
INIT_LIST_HEAD(&p->elist);
ip_min = ntohl(mr->range[0].min_ip) + (whole_prefix == 0);
ip_max = ntohl(mr->range[0].max_ip) - (whole_prefix == 0);
@@ -255,9 +312,9 @@ static int dnetmap_tg_check(const struct xt_tgchk_param *par)
sprintf(p->prefix_str, NIPQUAD_FMT "/%u", NIPQUAD(mr->range[0].min_ip),
33 - ffs(~(ip_min ^ ip_max)));
#ifdef CONFIG_PROC_FS
sprintf(proc_str_data, NIPQUAD_FMT "_%u", NIPQUAD(mr->range[0].min_ip),
sprintf(p->proc_str_data, NIPQUAD_FMT "_%u", NIPQUAD(mr->range[0].min_ip),
33 - ffs(~(ip_min ^ ip_max)));
sprintf(proc_str_stat, NIPQUAD_FMT "_%u_stat", NIPQUAD(mr->range[0].min_ip),
sprintf(p->proc_str_stat, NIPQUAD_FMT "_%u_stat", NIPQUAD(mr->range[0].min_ip),
33 - ffs(~(ip_min ^ ip_max)));
#endif
printk(KERN_INFO KBUILD_MODNAME ": new prefix %s\n", p->prefix_str);
@@ -271,12 +328,14 @@ static int dnetmap_tg_check(const struct xt_tgchk_param *par)
e->prenat_addr = 0;
e->stamp = jiffies;
e->prefix = p;
e->flags = 0;
list_add_tail(&e->lru_list, &p->lru_list);
list_add_tail(&e->list, &p->elist);
}
#ifdef CONFIG_PROC_FS
/* data */
pde_data = proc_create_data(proc_str_data, proc_perms,
pde_data = proc_create_data(p->proc_str_data, proc_perms,
dnetmap_net->xt_dnetmap,
&dnetmap_tg_fops, p);
if (pde_data == NULL) {
@@ -288,7 +347,7 @@ static int dnetmap_tg_check(const struct xt_tgchk_param *par)
pde_data->gid = proc_gid;
/* statistics */
pde_stat = create_proc_entry(proc_str_stat, proc_perms,
pde_stat = create_proc_entry(p->proc_str_stat, proc_perms,
dnetmap_net->xt_dnetmap);
if (pde_stat == NULL) {
kfree(p);
@@ -351,7 +410,7 @@ dnetmap_tg(struct sk_buff **pskb, const struct xt_action_param *par)
if (memcmp(mr, &e->prefix, sizeof(*mr)))
goto no_rev_map;
/* don't reset ttl if flag is set */
if (jttl >= 0) {
if (jttl >= 0 && (! (e->flags & XT_DNETMAP_STATIC) ) ) {
p = e->prefix;
e->stamp = jiffies + jttl;
list_move_tail(&e->lru_list, &p->lru_list);
@@ -378,17 +437,24 @@ dnetmap_tg(struct sk_buff **pskb, const struct xt_action_param *par)
if (e == NULL) { /* need for new binding */
// finish if it's static only rule
if(tginfo->flags & XT_DNETMAP_STATIC)
goto no_free_ip;
bind_new_prefix:
e = list_entry(p->lru_list.next, struct dnetmap_entry,
lru_list);
if (e->prenat_addr != 0 && time_before(jiffies, e->stamp)) {
if (!disable_log)
if (!disable_log && ! (p->flags & XT_DNETMAP_FULL) ){
printk(KERN_INFO KBUILD_MODNAME
": ip " NIPQUAD_FMT " - no free adresses in prefix %s\n",
NIPQUAD(prenat_ip), p->prefix_str);
p->flags |= XT_DNETMAP_FULL;
}
goto no_free_ip;
}
p->flags &= ~XT_DNETMAP_FULL;
postnat_ip = e->postnat_addr;
if (e->prenat_addr != 0) {
@@ -397,7 +463,6 @@ bind_new_prefix:
printk(KERN_INFO KBUILD_MODNAME
": timeout binding " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n",
NIPQUAD(prenat_ip_prev), NIPQUAD(postnat_ip) );
list_del(&e->list);
list_del(&e->glist);
list_del(&e->grlist);
}
@@ -405,8 +470,6 @@ bind_new_prefix:
e->prenat_addr = prenat_ip;
e->stamp = jiffies + jttl;
list_move_tail(&e->lru_list, &p->lru_list);
list_add_tail(&e->list,
&p->iphash[dnetmap_entry_hash(prenat_ip)]);
list_add_tail(&e->glist,
&dnetmap_net->
dnetmap_iphash[dnetmap_entry_hash(prenat_ip)]);
@@ -421,21 +484,21 @@ bind_new_prefix:
} else {
if (!(tginfo->flags & XT_DNETMAP_REUSE))
if (!(tginfo->flags & XT_DNETMAP_REUSE) && !(e->flags & XT_DNETMAP_STATIC))
if (time_before(e->stamp, jiffies) && p != e->prefix) {
if (!disable_log)
printk(KERN_INFO KBUILD_MODNAME
": timeout binding " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n",
NIPQUAD(e->prenat_addr),
NIPQUAD(e->postnat_addr));
list_del(&e->list);
list_del(&e->glist);
list_del(&e->grlist);
e->prenat_addr = 0;
goto bind_new_prefix;
}
/* don't reset ttl if flag is set */
if (jttl >= 0) {
/* don't reset ttl if flag is set
or it is static entry*/
if (jttl >= 0 && ! (e->flags & XT_DNETMAP_STATIC) ) {
e->stamp = jiffies + jttl;
p = e->prefix;
list_move_tail(&e->lru_list, &p->lru_list);
@@ -466,32 +529,17 @@ static void dnetmap_tg_destroy(const struct xt_tgdtor_param *par)
const struct xt_DNETMAP_tginfo *tginfo = par->targinfo;
const struct nf_nat_ipv4_multi_range_compat *mr = &tginfo->prefix;
struct dnetmap_prefix *p;
#ifdef CONFIG_PROC_FS
char str[25];
#endif
if (!(tginfo->flags & XT_DNETMAP_PREFIX))
return;
mutex_lock(&dnetmap_mutex);
p = dnetmap_prefix_lookup(dnetmap_net, mr);
if (--p->refcnt == 0) {
spin_lock_bh(&dnetmap_lock);
list_del(&p->list);
spin_unlock_bh(&dnetmap_lock);
#ifdef CONFIG_PROC_FS
sprintf(str, NIPQUAD_FMT "_%u", NIPQUAD(mr->range[0].min_ip),
33 - ffs(~(ntohl(mr->range[0].min_ip ^
mr->range[0].max_ip))));
remove_proc_entry(str, dnetmap_net->xt_dnetmap);
sprintf(str, NIPQUAD_FMT "_%u_stat", NIPQUAD(mr->range[0].min_ip),
33 - ffs(~(ntohl(mr->range[0].min_ip ^
mr->range[0].max_ip))));
remove_proc_entry(str, dnetmap_net->xt_dnetmap);
#endif
dnetmap_prefix_flush(dnetmap_net, p);
kfree(p);
p = dnetmap_prefix_lookup(dnetmap_net, mr);
if (--p->refcnt == 0 && (! (p->flags & XT_DNETMAP_PERSISTENT) ) ) {
dnetmap_prefix_destroy(dnetmap_net, p);
}
spin_unlock_bh(&dnetmap_lock);
mutex_unlock(&dnetmap_mutex);
}
@@ -511,7 +559,7 @@ __acquires(dnetmap_lock)
spin_lock_bh(&dnetmap_lock);
list_for_each_entry(e, &prefix->lru_list, lru_list)
list_for_each_entry(e, &prefix->elist, list)
if (p-- == 0)
return e;
return NULL;
@@ -522,13 +570,13 @@ static void *dnetmap_seq_next(struct seq_file *seq, void *v, loff_t * pos)
struct dnetmap_iter_state *st = seq->private;
const struct dnetmap_prefix *prefix = st->p;
const struct dnetmap_entry *e = v;
const struct list_head *head = e->lru_list.next;
const struct list_head *head = e->list.next;
if (head == &prefix->lru_list)
if (head == &prefix->elist)
return NULL;
++*pos;
return list_entry(head, struct dnetmap_entry, lru_list);
return list_entry(head, struct dnetmap_entry, list);
}
static void dnetmap_seq_stop(struct seq_file *s, void *v)
@@ -541,9 +589,14 @@ static int dnetmap_seq_show(struct seq_file *seq, void *v)
{
const struct dnetmap_entry *e = v;
if((e->flags & XT_DNETMAP_STATIC) == 0){
seq_printf(seq, NIPQUAD_FMT " -> " NIPQUAD_FMT " --- ttl: %d lasthit: %lu\n",
NIPQUAD(e->prenat_addr), NIPQUAD(e->postnat_addr),
(int)(e->stamp - jiffies) / HZ, (e->stamp - jtimeout) / HZ);
}else{
seq_printf(seq, NIPQUAD_FMT " -> " NIPQUAD_FMT " --- ttl: S lasthit: S\n",
NIPQUAD(e->prenat_addr), NIPQUAD(e->postnat_addr));
}
return 0;
}
@@ -567,9 +620,180 @@ static int dnetmap_seq_open(struct inode *inode, struct file *file)
return 0;
}
static ssize_t
dnetmap_tg_proc_write(struct file *file, const char __user *input,size_t size, loff_t *loff)
{
const struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
struct dnetmap_prefix *p = pde->data;
struct dnetmap_entry *e;
char buf[sizeof("+192.168.100.100:200.200.200.200")];
const char *c = buf;
const char *c2;
//union nf_inet_addr addr = {};
__be32 addr1,addr2;
bool add;
char str[25];
if (size == 0)
return 0;
if (size > sizeof(buf))
size = sizeof(buf);
if (copy_from_user(buf, input, size) != 0)
return -EFAULT;
if(strcspn(c,"\n") < size)
buf[strcspn(c,"\n")]='\0';
/* Strict protocol! */
if (*loff != 0)
return -ESPIPE;
switch (*c) {
case 'f': /* flush table */
if( strcmp(c,"flush") != 0 )
goto invalid_arg;
printk(KERN_INFO KBUILD_MODNAME ": flushing prefix %s\n", p->prefix_str);
spin_lock_bh(&dnetmap_lock);
dnetmap_prefix_softflush(p);
spin_unlock_bh(&dnetmap_lock);
return size;
case '-': /* remove address or attribute */
if( strcmp(c,"-persistent") == 0){
/* case if persistent flag is already unset */
if( ! (p->flags & XT_DNETMAP_PERSISTENT) ){
printk(KERN_INFO KBUILD_MODNAME ": prefix %s is not persistent already - doing nothing\n", p->prefix_str);
return size;
}
printk(KERN_INFO KBUILD_MODNAME ": prefix %s is now non-persistent\n", p->prefix_str);
spin_lock_bh(&dnetmap_lock);
p->flags &= ~XT_DNETMAP_PERSISTENT;
spin_unlock_bh(&dnetmap_lock);
return size;
}
add = false;
break;
case '+': /* add address or attribute */
if( strcmp(c,"+persistent") == 0){
/* case if persistent flag is already unset */
if( p->flags & XT_DNETMAP_PERSISTENT ){
printk(KERN_INFO KBUILD_MODNAME ": prefix %s is persistent already - doing nothing\n", p->prefix_str);
return size;
}
printk(KERN_INFO KBUILD_MODNAME ": prefix %s is now persistent\n", p->prefix_str);
spin_lock_bh(&dnetmap_lock);
p->flags |= XT_DNETMAP_PERSISTENT;
spin_unlock_bh(&dnetmap_lock);
return size;
}
add = true;
break;
default:
goto invalid_arg;
}
spin_lock_bh(&dnetmap_lock);
// in case static entry is added we need to parse second ip addresses
if (add){
c2 = strchr(c,':');
if(c2 == NULL)
goto invalid_arg_unlock;
c++;
c2++;
if( ! (in4_pton(c2,strlen(c2),(void *)&addr2, '\0', NULL) &&
in4_pton(c,strlen(c),(void *)&addr1, ':', NULL)))
goto invalid_arg_unlock;
// sanity check - prenat ip can't belong to postnat prefix
if ( dnetmap_addr_in_prefix(p->dnetmap, addr1, p)){
printk(KERN_INFO KBUILD_MODNAME ": add static binding operation failed - prenat ip can't belong to postnat prefix\n");
goto invalid_arg_unlock;
}
// make sure postnat ip belongs to postnat prefix
if ( ! dnetmap_addr_in_prefix(p->dnetmap, addr2, p)){
printk(KERN_INFO KBUILD_MODNAME ": add static binding operation failed - postnat ip must belong to postnat prefix\n");
goto invalid_arg_unlock;
}
e = dnetmap_entry_rlookup(p->dnetmap,addr2);
if(e != NULL){
if (!disable_log)
printk(KERN_INFO KBUILD_MODNAME
": timeout binding " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n",
NIPQUAD(e->prenat_addr), NIPQUAD(e->postnat_addr) );
list_del(&e->glist);
list_del(&e->grlist);
}else{
// find existing entry in prefix elist
list_for_each_entry(e, &p->elist, list)
if (memcmp(&e->postnat_addr, &addr2, sizeof(addr2)) == 0){
break;
}
}
e->prenat_addr=addr1;
e->flags |= XT_DNETMAP_STATIC;
list_add_tail(&e->glist,
&p->dnetmap->
dnetmap_iphash[dnetmap_entry_hash(e->prenat_addr)]);
list_add_tail(&e->grlist,
&p->dnetmap->dnetmap_iphash[hash_size +
dnetmap_entry_hash
(e->postnat_addr)]);
list_del(&e->lru_list);
sprintf(str, NIPQUAD_FMT ":" NIPQUAD_FMT, NIPQUAD(addr1),NIPQUAD(addr2));
printk(KERN_INFO KBUILD_MODNAME ": adding static binding %s\n", str);
// case of removing binding
}else{
c++;
if( ! in4_pton(c,strlen(c),(void *)&addr1, '\0', NULL))
goto invalid_arg_unlock;
e = dnetmap_entry_rlookup(p->dnetmap,addr1);
if(e == NULL) e = dnetmap_entry_lookup(p->dnetmap,addr1);
if(e != NULL){
if (!disable_log)
printk(KERN_INFO KBUILD_MODNAME
": remove binding " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n",
NIPQUAD(e->prenat_addr), NIPQUAD(e->postnat_addr) );
list_del(&e->glist);
list_del(&e->grlist);
if(e->flags & XT_DNETMAP_STATIC){
list_add_tail(&e->lru_list,&p->lru_list);
e->flags &= ~XT_DNETMAP_STATIC;
}
e->prenat_addr=0;
e->stamp=jiffies-1;
}else{
goto invalid_arg_unlock;
}
}
spin_unlock_bh(&dnetmap_lock);
/* Note we removed one above */
*loff += size + 1;
return size + 1;
invalid_arg_unlock:
spin_unlock_bh(&dnetmap_lock);
invalid_arg:
//printk(KERN_INFO KBUILD_MODNAME ": Need \"+prenat_ip:postnat_ip\", \"-ip\" or \"/\"\n");
printk(KERN_INFO KBUILD_MODNAME ": Error! Invalid option passed via procfs.\n");
return -EINVAL;
}
static const struct file_operations dnetmap_tg_fops = {
.open = dnetmap_seq_open,
.read = seq_read,
.write = dnetmap_tg_proc_write,
.release = seq_release_private,
.owner = THIS_MODULE,
};
@@ -581,27 +805,31 @@ static int dnetmap_stat_proc_read(char __user *buffer, char **start,
{
const struct dnetmap_prefix *p = data;
struct dnetmap_entry *e;
unsigned int used, all;
unsigned int used, used_static, all;
long int ttl, sum_ttl;
used = 0;
all = 0;
sum_ttl = 0;
used=used_static=all=sum_ttl=0;
spin_lock_bh(&dnetmap_lock);
list_for_each_entry(e, &p->lru_list, lru_list) {
list_for_each_entry(e, &p->elist, list) {
if (e->prenat_addr != 0){
if (e->flags & XT_DNETMAP_STATIC){
used_static++;
}else{
ttl = e->stamp - jiffies;
if (e->prenat_addr != 0 && ttl >= 0) {
used++;
sum_ttl += ttl;
}
}
}
all++;
}
sum_ttl = used > 0 ? sum_ttl / (used * HZ) : 0;
sprintf(buffer, "%u %u %ld\n", used, all, sum_ttl);
sprintf(buffer, "%u %u %u %ld %s\n", used, used_static, all, sum_ttl,(p->flags & XT_DNETMAP_PERSISTENT ? "persistent" : ""));
if (length >= strlen(buffer))
*eof = true;
@@ -663,12 +891,24 @@ static int __net_init dnetmap_net_init(struct net *net)
static void __net_exit dnetmap_net_exit(struct net *net)
{
struct dnetmap_net *dnetmap_net = dnetmap_pernet(net);
struct dnetmap_prefix *p,*next;
mutex_lock(&dnetmap_mutex);
spin_lock_bh(&dnetmap_lock);
list_for_each_entry_safe(p, next, &dnetmap_net->prefixes, list){
BUG_ON(p->refcnt != 0);
dnetmap_prefix_destroy(dnetmap_net, p);
}
spin_unlock_bh(&dnetmap_lock);
mutex_unlock(&dnetmap_mutex);
BUG_ON(!list_empty(&dnetmap_net->prefixes));
kfree(dnetmap_net->dnetmap_iphash);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
kfree(dnetmap_net);
#endif
dnetmap_proc_net_exit(net);
}
@@ -714,6 +954,8 @@ static int __init dnetmap_tg_init(void)
if (err)
unregister_pernet_subsys(&dnetmap_net_ops);
printk( KERN_INFO KBUILD_MODNAME " INIT successfull (version %d)\n", DNETMAP_VERSION );
return err;
}

View File

@@ -1,16 +1,21 @@
#ifndef _LINUX_NETFILTER_XT_DNETMAP_H
#define _LINUX_NETFILTER_XT_DNETMAP_H 1
#define DNETMAP_VERSION 2
enum {
XT_DNETMAP_TTL = 1 << 0,
XT_DNETMAP_REUSE = 1 << 1,
XT_DNETMAP_PREFIX = 1 << 2,
XT_DNETMAP_STATIC = 1 << 3,
XT_DNETMAP_PERSISTENT = 1 << 4,
XT_DNETMAP_FULL = 1 << 5,
};
struct xt_DNETMAP_tginfo {
struct nf_nat_ipv4_multi_range_compat prefix;
__u8 flags;
__s16 ttl;
__s32 ttl;
};
#endif