Skip to content

Commit

Permalink
netfilter: xt_recent: add address masking option
Browse files Browse the repository at this point in the history
The mask option allows you put all address belonging that mask into
the same recent slot. This can be useful in case that recent is used
to detect attacks from the same network segment.

Tested for backward compatibility.

Signed-off-by: Denys Fedoryshchenko <denys@visp.net.lb>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
  • Loading branch information
Denys Fedoryshchenko authored and Pablo Neira Ayuso committed Jun 7, 2012
1 parent 1da6dd0 commit efdedd5
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 9 deletions.
7 changes: 7 additions & 0 deletions Documentation/feature-removal-schedule.txt
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,13 @@ Why: Remount currently allows changing bound subsystems and

----------------------------

What: xt_recent rev 0
When: 2013
Who: Pablo Neira Ayuso <pablo@netfilter.org>
Files: net/netfilter/xt_recent.c

----------------------------

What: KVM debugfs statistics
When: 2013
Why: KVM tracepoints provide mostly equivalent information in a much more
Expand Down
10 changes: 10 additions & 0 deletions include/linux/netfilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ static inline int nf_inet_addr_cmp(const union nf_inet_addr *a1,
a1->all[3] == a2->all[3];
}

static inline void nf_inet_addr_mask(const union nf_inet_addr *a1,
union nf_inet_addr *result,
const union nf_inet_addr *mask)
{
result->all[0] = a1->all[0] & mask->all[0];
result->all[1] = a1->all[1] & mask->all[1];
result->all[2] = a1->all[2] & mask->all[2];
result->all[3] = a1->all[3] & mask->all[3];
}

extern void netfilter_init(void);

/* Largest hook number + 1 */
Expand Down
10 changes: 10 additions & 0 deletions include/linux/netfilter/xt_recent.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,14 @@ struct xt_recent_mtinfo {
__u8 side;
};

struct xt_recent_mtinfo_v1 {
__u32 seconds;
__u32 hit_count;
__u8 check_set;
__u8 invert;
char name[XT_RECENT_NAME_LEN];
__u8 side;
union nf_inet_addr mask;
};

#endif /* _LINUX_NETFILTER_XT_RECENT_H */
62 changes: 53 additions & 9 deletions net/netfilter/xt_recent.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ struct recent_entry {
struct recent_table {
struct list_head list;
char name[XT_RECENT_NAME_LEN];
union nf_inet_addr mask;
unsigned int refcnt;
unsigned int entries;
struct list_head lru_list;
Expand Down Expand Up @@ -228,10 +229,10 @@ recent_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
struct net *net = dev_net(par->in ? par->in : par->out);
struct recent_net *recent_net = recent_pernet(net);
const struct xt_recent_mtinfo *info = par->matchinfo;
const struct xt_recent_mtinfo_v1 *info = par->matchinfo;
struct recent_table *t;
struct recent_entry *e;
union nf_inet_addr addr = {};
union nf_inet_addr addr = {}, addr_mask;
u_int8_t ttl;
bool ret = info->invert;

Expand Down Expand Up @@ -261,12 +262,15 @@ recent_mt(const struct sk_buff *skb, struct xt_action_param *par)

spin_lock_bh(&recent_lock);
t = recent_table_lookup(recent_net, info->name);
e = recent_entry_lookup(t, &addr, par->family,

nf_inet_addr_mask(&addr, &addr_mask, &t->mask);

e = recent_entry_lookup(t, &addr_mask, par->family,
(info->check_set & XT_RECENT_TTL) ? ttl : 0);
if (e == NULL) {
if (!(info->check_set & XT_RECENT_SET))
goto out;
e = recent_entry_init(t, &addr, par->family, ttl);
e = recent_entry_init(t, &addr_mask, par->family, ttl);
if (e == NULL)
par->hotdrop = true;
ret = !ret;
Expand Down Expand Up @@ -306,10 +310,10 @@ recent_mt(const struct sk_buff *skb, struct xt_action_param *par)
return ret;
}

static int recent_mt_check(const struct xt_mtchk_param *par)
static int recent_mt_check(const struct xt_mtchk_param *par,
const struct xt_recent_mtinfo_v1 *info)
{
struct recent_net *recent_net = recent_pernet(par->net);
const struct xt_recent_mtinfo *info = par->matchinfo;
struct recent_table *t;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *pde;
Expand Down Expand Up @@ -361,6 +365,8 @@ static int recent_mt_check(const struct xt_mtchk_param *par)
goto out;
}
t->refcnt = 1;

memcpy(&t->mask, &info->mask, sizeof(t->mask));
strcpy(t->name, info->name);
INIT_LIST_HEAD(&t->lru_list);
for (i = 0; i < ip_list_hash_size; i++)
Expand All @@ -385,10 +391,28 @@ static int recent_mt_check(const struct xt_mtchk_param *par)
return ret;
}

static int recent_mt_check_v0(const struct xt_mtchk_param *par)
{
const struct xt_recent_mtinfo_v0 *info_v0 = par->matchinfo;
struct xt_recent_mtinfo_v1 info_v1;

/* Copy revision 0 structure to revision 1 */
memcpy(&info_v1, info_v0, sizeof(struct xt_recent_mtinfo));
/* Set default mask to ensure backward compatible behaviour */
memset(info_v1.mask.all, 0xFF, sizeof(info_v1.mask.all));

return recent_mt_check(par, &info_v1);
}

static int recent_mt_check_v1(const struct xt_mtchk_param *par)
{
return recent_mt_check(par, par->matchinfo);
}

static void recent_mt_destroy(const struct xt_mtdtor_param *par)
{
struct recent_net *recent_net = recent_pernet(par->net);
const struct xt_recent_mtinfo *info = par->matchinfo;
const struct xt_recent_mtinfo_v1 *info = par->matchinfo;
struct recent_table *t;

mutex_lock(&recent_mutex);
Expand Down Expand Up @@ -625,7 +649,7 @@ static struct xt_match recent_mt_reg[] __read_mostly = {
.family = NFPROTO_IPV4,
.match = recent_mt,
.matchsize = sizeof(struct xt_recent_mtinfo),
.checkentry = recent_mt_check,
.checkentry = recent_mt_check_v0,
.destroy = recent_mt_destroy,
.me = THIS_MODULE,
},
Expand All @@ -635,10 +659,30 @@ static struct xt_match recent_mt_reg[] __read_mostly = {
.family = NFPROTO_IPV6,
.match = recent_mt,
.matchsize = sizeof(struct xt_recent_mtinfo),
.checkentry = recent_mt_check,
.checkentry = recent_mt_check_v0,
.destroy = recent_mt_destroy,
.me = THIS_MODULE,
},
{
.name = "recent",
.revision = 1,
.family = NFPROTO_IPV4,
.match = recent_mt,
.matchsize = sizeof(struct xt_recent_mtinfo_v1),
.checkentry = recent_mt_check_v1,
.destroy = recent_mt_destroy,
.me = THIS_MODULE,
},
{
.name = "recent",
.revision = 1,
.family = NFPROTO_IPV6,
.match = recent_mt,
.matchsize = sizeof(struct xt_recent_mtinfo_v1),
.checkentry = recent_mt_check_v1,
.destroy = recent_mt_destroy,
.me = THIS_MODULE,
}
};

static int __init recent_mt_init(void)
Expand Down

0 comments on commit efdedd5

Please sign in to comment.