Skip to content

Commit

Permalink
netfilter: add IPv4/6 IPComp extension match support
Browse files Browse the repository at this point in the history
With this plugin, user could specify IPComp tagged with certain
CPI that host not interested will be DROPped or any other action.

For example:
iptables  -A INPUT -p 108 -m ipcomp --ipcompspi 0x87 -j DROP
ip6tables -A INPUT -p 108 -m ipcomp --ipcompspi 0x87 -j DROP

Then input IPComp packet with CPI equates 0x87 will not reach
upper layer anymore.

Signed-off-by: Fan Du <fan.du@windriver.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
  • Loading branch information
fan.du authored and Pablo Neira Ayuso committed Dec 24, 2013
1 parent 08c0cad commit 6a649f3
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 0 deletions.
1 change: 1 addition & 0 deletions include/uapi/linux/netfilter/Kbuild
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ header-y += xt_ecn.h
header-y += xt_esp.h
header-y += xt_hashlimit.h
header-y += xt_helper.h
header-y += xt_ipcomp.h
header-y += xt_iprange.h
header-y += xt_ipvs.h
header-y += xt_length.h
Expand Down
16 changes: 16 additions & 0 deletions include/uapi/linux/netfilter/xt_ipcomp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef _XT_IPCOMP_H
#define _XT_IPCOMP_H

#include <linux/types.h>

struct xt_ipcomp {
__u32 spis[2]; /* Security Parameter Index */
__u8 invflags; /* Inverse flags */
__u8 hdrres; /* Test of the Reserved Filed */
};

/* Values for "invflags" field in struct xt_ipcomp. */
#define XT_IPCOMP_INV_SPI 0x01 /* Invert the sense of spi. */
#define XT_IPCOMP_INV_MASK 0x01 /* All possible flags. */

#endif /*_XT_IPCOMP_H*/
9 changes: 9 additions & 0 deletions net/netfilter/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,15 @@ config NETFILTER_XT_MATCH_HL
in the IPv6 header, or the time-to-live field in the IPv4
header of the packet.

config NETFILTER_XT_MATCH_IPCOMP
tristate '"ipcomp" match support'
depends on NETFILTER_ADVANCED
help
This match extension allows you to match a range of CPIs(16 bits)
inside IPComp header of IPSec packets.

To compile it as a module, choose M here. If unsure, say N.

config NETFILTER_XT_MATCH_IPRANGE
tristate '"iprange" address range match support'
depends on NETFILTER_ADVANCED
Expand Down
1 change: 1 addition & 0 deletions net/netfilter/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += xt_esp.o
obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o
obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o
obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o
obj-$(CONFIG_NETFILTER_XT_MATCH_IPCOMP) += xt_ipcomp.o
obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o
obj-$(CONFIG_NETFILTER_XT_MATCH_IPVS) += xt_ipvs.o
obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o
Expand Down
111 changes: 111 additions & 0 deletions net/netfilter/xt_ipcomp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/* Kernel module to match IPComp parameters for IPv4 and IPv6
*
* Copyright (C) 2013 WindRiver
*
* Author:
* Fan Du <fan.du@windriver.com>
*
* Based on:
* net/netfilter/xt_esp.c
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/in.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ip.h>

#include <linux/netfilter/xt_ipcomp.h>
#include <linux/netfilter/x_tables.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Fan Du <fan.du@windriver.com>");
MODULE_DESCRIPTION("Xtables: IPv4/6 IPsec-IPComp SPI match");

/* Returns 1 if the spi is matched by the range, 0 otherwise */
static inline bool
spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, bool invert)
{
bool r;
pr_debug("spi_match:%c 0x%x <= 0x%x <= 0x%x\n",
invert ? '!' : ' ', min, spi, max);
r = (spi >= min && spi <= max) ^ invert;
pr_debug(" result %s\n", r ? "PASS" : "FAILED");
return r;
}

static bool comp_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
struct ip_comp_hdr _comphdr;
const struct ip_comp_hdr *chdr;
const struct xt_ipcomp *compinfo = par->matchinfo;

/* Must not be a fragment. */
if (par->fragoff != 0)
return false;

chdr = skb_header_pointer(skb, par->thoff, sizeof(_comphdr), &_comphdr);
if (chdr == NULL) {
/* We've been asked to examine this packet, and we
* can't. Hence, no choice but to drop.
*/
pr_debug("Dropping evil IPComp tinygram.\n");
par->hotdrop = true;
return 0;
}

return spi_match(compinfo->spis[0], compinfo->spis[1],
ntohl(chdr->cpi << 16),
!!(compinfo->invflags & XT_IPCOMP_INV_SPI));
}

static int comp_mt_check(const struct xt_mtchk_param *par)
{
const struct xt_ipcomp *compinfo = par->matchinfo;

/* Must specify no unknown invflags */
if (compinfo->invflags & ~XT_IPCOMP_INV_MASK) {
pr_err("unknown flags %X\n", compinfo->invflags);
return -EINVAL;
}
return 0;
}

static struct xt_match comp_mt_reg[] __read_mostly = {
{
.name = "ipcomp",
.family = NFPROTO_IPV4,
.match = comp_mt,
.matchsize = sizeof(struct xt_ipcomp),
.proto = IPPROTO_COMP,
.checkentry = comp_mt_check,
.me = THIS_MODULE,
},
{
.name = "ipcomp",
.family = NFPROTO_IPV6,
.match = comp_mt,
.matchsize = sizeof(struct xt_ipcomp),
.proto = IPPROTO_COMP,
.checkentry = comp_mt_check,
.me = THIS_MODULE,
},
};

static int __init comp_mt_init(void)
{
return xt_register_matches(comp_mt_reg, ARRAY_SIZE(comp_mt_reg));
}

static void __exit comp_mt_exit(void)
{
xt_unregister_matches(comp_mt_reg, ARRAY_SIZE(comp_mt_reg));
}

module_init(comp_mt_init);
module_exit(comp_mt_exit);

0 comments on commit 6a649f3

Please sign in to comment.