Commit c069d58e authored by Harald Welte's avatar Harald Welte Committed by David S. Miller

[NETFILTER]: Add new ip6tables matches.

parent db298f3b
#ifndef _IP6T_AH_H
#define _IP6T_AH_H
struct ip6t_ah
{
u_int32_t spis[2]; /* Security Parameter Index */
u_int32_t hdrlen; /* Header Length */
u_int8_t hdrres; /* Test of the Reserved Filed */
u_int8_t invflags; /* Inverse flags */
};
#define IP6T_AH_SPI 0x01
#define IP6T_AH_LEN 0x02
#define IP6T_AH_RES 0x04
/* Values for "invflags" field in struct ip6t_ah. */
#define IP6T_AH_INV_SPI 0x01 /* Invert the sense of spi. */
#define IP6T_AH_INV_LEN 0x02 /* Invert the sense of length. */
#define IP6T_AH_INV_MASK 0x03 /* All possible flags. */
#define MASK_HOPOPTS 128
#define MASK_DSTOPTS 64
#define MASK_ROUTING 32
#define MASK_FRAGMENT 16
#define MASK_AH 8
#define MASK_ESP 4
#define MASK_NONE 2
#define MASK_PROTO 1
#endif /*_IP6T_AH_H*/
#ifndef _IP6T_ESP_H
#define _IP6T_ESP_H
struct ip6t_esp
{
u_int32_t spis[2]; /* Security Parameter Index */
u_int8_t invflags; /* Inverse flags */
};
#define MASK_HOPOPTS 128
#define MASK_DSTOPTS 64
#define MASK_ROUTING 32
#define MASK_FRAGMENT 16
#define MASK_AH 8
#define MASK_ESP 4
#define MASK_NONE 2
#define MASK_PROTO 1
/* Values for "invflags" field in struct ip6t_esp. */
#define IP6T_ESP_INV_SPI 0x01 /* Invert the sense of spi. */
#define IP6T_ESP_INV_MASK 0x01 /* All possible flags. */
#endif /*_IP6T_ESP_H*/
#ifndef _IP6T_FRAG_H
#define _IP6T_FRAG_H
struct ip6t_frag
{
u_int32_t ids[2]; /* Security Parameter Index */
u_int32_t hdrlen; /* Header Length */
u_int8_t flags; /* */
u_int8_t invflags; /* Inverse flags */
};
#define IP6T_FRAG_IDS 0x01
#define IP6T_FRAG_LEN 0x02
#define IP6T_FRAG_RES 0x04
#define IP6T_FRAG_FST 0x08
#define IP6T_FRAG_MF 0x10
#define IP6T_FRAG_NMF 0x20
/* Values for "invflags" field in struct ip6t_frag. */
#define IP6T_FRAG_INV_IDS 0x01 /* Invert the sense of ids. */
#define IP6T_FRAG_INV_LEN 0x02 /* Invert the sense of length. */
#define IP6T_FRAG_INV_MASK 0x03 /* All possible flags. */
#define MASK_HOPOPTS 128
#define MASK_DSTOPTS 64
#define MASK_ROUTING 32
#define MASK_FRAGMENT 16
#define MASK_AH 8
#define MASK_ESP 4
#define MASK_NONE 2
#define MASK_PROTO 1
#endif /*_IP6T_FRAG_H*/
/* ip6tables module for matching the Hop Limit value
* Maciej Soltysiak <solt@dns.toxicfilms.tv>
* Based on HW's ttl module */
#ifndef _IP6T_HL_H
#define _IP6T_HL_H
enum {
IP6T_HL_EQ = 0, /* equals */
IP6T_HL_NE, /* not equals */
IP6T_HL_LT, /* less than */
IP6T_HL_GT, /* greater than */
};
struct ip6t_hl_info {
u_int8_t mode;
u_int8_t hop_limit;
};
#endif
/* ipv6header match - matches IPv6 packets based
on whether they contain certain headers */
/* Original idea: Brad Chapman
* Rewritten by: Andras Kis-Szabo <kisza@sch.bme.hu> */
#ifndef __IPV6HEADER_H
#define __IPV6HEADER_H
struct ip6t_ipv6header_info
{
u_int8_t matchflags;
u_int8_t invflags;
u_int8_t modeflag;
};
#define MASK_HOPOPTS 128
#define MASK_DSTOPTS 64
#define MASK_ROUTING 32
#define MASK_FRAGMENT 16
#define MASK_AH 8
#define MASK_ESP 4
#define MASK_NONE 2
#define MASK_PROTO 1
#endif /* __IPV6HEADER_H */
#ifndef _IP6T_OPTS_H
#define _IP6T_OPTS_H
#define IP6T_OPTS_OPTSNR 16
struct ip6t_opts
{
u_int32_t hdrlen; /* Header Length */
u_int8_t flags; /* */
u_int8_t invflags; /* Inverse flags */
u_int16_t opts[IP6T_OPTS_OPTSNR]; /* opts */
u_int8_t optsnr; /* Nr of OPts */
};
#define IP6T_OPTS_LEN 0x01
#define IP6T_OPTS_OPTS 0x02
#define IP6T_OPTS_NSTRICT 0x04
/* Values for "invflags" field in struct ip6t_rt. */
#define IP6T_OPTS_INV_LEN 0x01 /* Invert the sense of length. */
#define IP6T_OPTS_INV_MASK 0x01 /* All possible flags. */
#define MASK_HOPOPTS 128
#define MASK_DSTOPTS 64
#define MASK_ROUTING 32
#define MASK_FRAGMENT 16
#define MASK_AH 8
#define MASK_ESP 4
#define MASK_NONE 2
#define MASK_PROTO 1
#endif /*_IP6T_OPTS_H*/
#ifndef _IP6T_RT_H
#define _IP6T_RT_H
/*#include <linux/in6.h>*/
#define IP6T_RT_HOPS 16
struct ip6t_rt
{
u_int32_t rt_type; /* Routing Type */
u_int32_t segsleft[2]; /* Segments Left */
u_int32_t hdrlen; /* Header Length */
u_int8_t flags; /* */
u_int8_t invflags; /* Inverse flags */
struct in6_addr addrs[IP6T_RT_HOPS]; /* Hops */
u_int8_t addrnr; /* Nr of Addresses */
};
#define IP6T_RT_TYP 0x01
#define IP6T_RT_SGS 0x02
#define IP6T_RT_LEN 0x04
#define IP6T_RT_RES 0x08
#define IP6T_RT_FST_MASK 0x30
#define IP6T_RT_FST 0x10
#define IP6T_RT_FST_NSTRICT 0x20
/* Values for "invflags" field in struct ip6t_rt. */
#define IP6T_RT_INV_TYP 0x01 /* Invert the sense of type. */
#define IP6T_RT_INV_SGS 0x02 /* Invert the sense of Segments. */
#define IP6T_RT_INV_LEN 0x04 /* Invert the sense of length. */
#define IP6T_RT_INV_MASK 0x07 /* All possible flags. */
#define MASK_HOPOPTS 128
#define MASK_DSTOPTS 64
#define MASK_ROUTING 32
#define MASK_FRAGMENT 16
#define MASK_AH 8
#define MASK_ESP 4
#define MASK_NONE 2
#define MASK_PROTO 1
#endif /*_IP6T_RT_H*/
......@@ -60,6 +60,46 @@ config IP6_NF_MATCH_MAC
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
config IP6_NF_MATCH_RT
tristate "Routing header match support"
depends on IP6_NF_IPTABLES && EXPERIMENTAL
help
rt matching allows you to match packets based on the routing
header of the packet.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
config IP6_NF_MATCH_OPTS
tristate "Hop-by-hop and Dst opts header match support"
depends on IP6_NF_IPTABLES && EXPERIMENTAL
help
This allows one to match packets based on the hop-by-hop
and destination options headers of a packet.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
config IP6_NF_MATCH_FRAG
tristate "Fragmentation header match support"
depends on IP6_NF_IPTABLES && EXPERIMENTAL
help
frag matching allows you to match packets based on the fragmentation
header of the packet.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
config IP6_NF_MATCH_HL
tristate "HL match support"
depends on IP6_NF_IPTABLES
help
HL matching allows you to match packets based on the hop
limit of the packet.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
config IP6_NF_MATCH_MULTIPORT
tristate "Multiple port match support"
depends on IP6_NF_IPTABLES
......@@ -93,6 +133,25 @@ config IP6_NF_MATCH_MARK
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
config IP6_NF_MATCH_IPV6HEADER
tristate "IPv6 Extension Headers Match (EXPERIMENTAL)"
depends on IP6_NF_IPTABLES && EXPERIMENTAL
help
This module allows one to match packets based upon
the ipv6 extension headers.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
config IP6_NF_MATCH_AHESP
tristate "AH/ESP match support (EXPERIMENTAL)"
depends on IP6_NF_IPTABLES && EXPERIMENTAL
help
This module allows one to match AH and ESP packets.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
config IP6_NF_MATCH_LENGTH
tristate "Packet Length match support"
depends on IP6_NF_IPTABLES
......
......@@ -8,6 +8,11 @@ obj-$(CONFIG_IP6_NF_MATCH_LIMIT) += ip6t_limit.o
obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o
obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o
obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o
obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o
obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o
obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o
obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o
......@@ -16,3 +21,4 @@ obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
obj-$(CONFIG_IP_NF_MATCH_HL) += ip6t_hl.o
/* Kernel module to match AH parameters. */
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ipv6.h>
#include <linux/types.h>
#include <net/checksum.h>
#include <net/ipv6.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_ipv6/ip6t_ah.h>
EXPORT_NO_SYMBOLS;
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("IPv6 AH match");
MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
#if 0
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
struct ahhdr {
__u8 nexthdr;
__u8 hdrlen;
__u16 reserved;
__u32 spi;
};
int ipv6_ext_hdr(u8 nexthdr)
{
return ( (nexthdr == NEXTHDR_HOP) ||
(nexthdr == NEXTHDR_ROUTING) ||
(nexthdr == NEXTHDR_FRAGMENT) ||
(nexthdr == NEXTHDR_AUTH) ||
(nexthdr == NEXTHDR_ESP) ||
(nexthdr == NEXTHDR_NONE) ||
(nexthdr == NEXTHDR_DEST) );
}
/* Returns 1 if the spi is matched by the range, 0 otherwise */
static inline int
spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
{
int r=0;
DEBUGP("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
min,spi,max);
r=(spi >= min && spi <= max) ^ invert;
DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n");
return r;
}
static int
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *protohdr,
u_int16_t datalen,
int *hotdrop)
{
struct ahhdr *ah = NULL;
const struct ip6t_ah *ahinfo = matchinfo;
unsigned int temp;
int len;
u8 nexthdr;
unsigned int ptr;
unsigned int hdrlen = 0;
/*DEBUGP("IPv6 AH entered\n");*/
/* if (opt->auth == 0) return 0;
* It does not filled on output */
/* type of the 1st exthdr */
nexthdr = skb->nh.ipv6h->nexthdr;
/* pointer to the 1st exthdr */
ptr = sizeof(struct ipv6hdr);
/* available length */
len = skb->len - ptr;
temp = 0;
while (ipv6_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr *hdr;
DEBUGP("ipv6_ah header iteration \n");
/* Is there enough space for the next ext header? */
if (len < (int)sizeof(struct ipv6_opt_hdr))
return 0;
/* No more exthdr -> evaluate */
if (nexthdr == NEXTHDR_NONE) {
break;
}
/* ESP -> evaluate */
if (nexthdr == NEXTHDR_ESP) {
break;
}
hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
/* Calculate the header length */
if (nexthdr == NEXTHDR_FRAGMENT) {
hdrlen = 8;
} else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hdr->hdrlen+2)<<2;
else
hdrlen = ipv6_optlen(hdr);
/* AH -> evaluate */
if (nexthdr == NEXTHDR_AUTH) {
temp |= MASK_AH;
break;
}
/* set the flag */
switch (nexthdr){
case NEXTHDR_HOP:
case NEXTHDR_ROUTING:
case NEXTHDR_FRAGMENT:
case NEXTHDR_AUTH:
case NEXTHDR_DEST:
break;
default:
DEBUGP("ipv6_ah match: unknown nextheader %u\n",nexthdr);
return 0;
break;
}
nexthdr = hdr->nexthdr;
len -= hdrlen;
ptr += hdrlen;
if ( ptr > skb->len ) {
DEBUGP("ipv6_ah: new pointer too large! \n");
break;
}
}
/* AH header not found */
if ( temp != MASK_AH ) return 0;
if (len < (int)sizeof(struct ahhdr)){
*hotdrop = 1;
return 0;
}
ah=skb->data+ptr;
DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen);
DEBUGP("RES %04X ", ah->reserved);
DEBUGP("SPI %u %08X\n", ntohl(ah->spi), ntohl(ah->spi));
DEBUGP("IPv6 AH spi %02X ",
(spi_match(ahinfo->spis[0], ahinfo->spis[1],
ntohl(ah->spi),
!!(ahinfo->invflags & IP6T_AH_INV_SPI))));
DEBUGP("len %02X %04X %02X ",
ahinfo->hdrlen, hdrlen,
(!ahinfo->hdrlen ||
(ahinfo->hdrlen == hdrlen) ^
!!(ahinfo->invflags & IP6T_AH_INV_LEN)));
DEBUGP("res %02X %04X %02X\n",
ahinfo->hdrres, ah->reserved,
!(ahinfo->hdrres && ah->reserved));
return (ah != NULL)
&&
(spi_match(ahinfo->spis[0], ahinfo->spis[1],
ntohl(ah->spi),
!!(ahinfo->invflags & IP6T_AH_INV_SPI)))
&&
(!ahinfo->hdrlen ||
(ahinfo->hdrlen == hdrlen) ^
!!(ahinfo->invflags & IP6T_AH_INV_LEN))
&&
!(ahinfo->hdrres && ah->reserved);
}
/* Called when user tries to insert an entry of this type. */
static int
checkentry(const char *tablename,
const struct ip6t_ip6 *ip,
void *matchinfo,
unsigned int matchinfosize,
unsigned int hook_mask)
{
const struct ip6t_ah *ahinfo = matchinfo;
if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_ah))) {
DEBUGP("ip6t_ah: matchsize %u != %u\n",
matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_ah)));
return 0;
}
if (ahinfo->invflags & ~IP6T_AH_INV_MASK) {
DEBUGP("ip6t_ah: unknown flags %X\n",
ahinfo->invflags);
return 0;
}
return 1;
}
static struct ip6t_match ah_match
= { { NULL, NULL }, "ah", &match, &checkentry, NULL, THIS_MODULE };
static int __init init(void)
{
return ip6t_register_match(&ah_match);
}
static void __exit cleanup(void)
{
ip6t_unregister_match(&ah_match);
}
module_init(init);
module_exit(cleanup);
/* Kernel module to match Hop-by-Hop and Destination parameters. */
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ipv6.h>
#include <linux/types.h>
#include <net/checksum.h>
#include <net/ipv6.h>
#include <asm/byteorder.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_ipv6/ip6t_opts.h>
#define LOW(n) (n & 0x00FF)
#define HOPBYHOP 0
EXPORT_NO_SYMBOLS;
MODULE_LICENSE("GPL");
#if HOPBYHOP
MODULE_DESCRIPTION("IPv6 HbH match");
#else
MODULE_DESCRIPTION("IPv6 DST match");
#endif
MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
#if 0
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
int ipv6_ext_hdr(u8 nexthdr)
{
return ( (nexthdr == NEXTHDR_HOP) ||
(nexthdr == NEXTHDR_ROUTING) ||
(nexthdr == NEXTHDR_FRAGMENT) ||
(nexthdr == NEXTHDR_AUTH) ||
(nexthdr == NEXTHDR_ESP) ||
(nexthdr == NEXTHDR_NONE) ||
(nexthdr == NEXTHDR_DEST) );
}
/*
* (Type & 0xC0) >> 6
* 0 -> ignorable
* 1 -> must drop the packet
* 2 -> send ICMP PARM PROB regardless and drop packet
* 3 -> Send ICMP if not a multicast address and drop packet
* (Type & 0x20) >> 5
* 0 -> invariant
* 1 -> can change the routing
* (Type & 0x1F) Type
* 0 -> PAD0 (only 1 byte!)
* 1 -> PAD1 LENGTH info (total length = length + 2)
* C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k )
* 5 -> RTALERT 2 x x
*/
static int
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *protohdr,
u_int16_t datalen,
int *hotdrop)
{
struct ipv6_opt_hdr *optsh = NULL;
const struct ip6t_opts *optinfo = matchinfo;
unsigned int temp;
unsigned int len;
u8 nexthdr;
unsigned int ptr;
unsigned int hdrlen = 0;
unsigned int ret = 0;
u_int16_t *optdesc = NULL;
/* type of the 1st exthdr */
nexthdr = skb->nh.ipv6h->nexthdr;
/* pointer to the 1st exthdr */
ptr = sizeof(struct ipv6hdr);
/* available length */
len = skb->len - ptr;
temp = 0;
while (ipv6_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr *hdr;
DEBUGP("ipv6_opts header iteration \n");
/* Is there enough space for the next ext header? */
if (len < (int)sizeof(struct ipv6_opt_hdr))
return 0;
/* No more exthdr -> evaluate */
if (nexthdr == NEXTHDR_NONE) {
break;
}
/* ESP -> evaluate */
if (nexthdr == NEXTHDR_ESP) {
break;
}
hdr=(void *)(skb->data)+ptr;
/* Calculate the header length */
if (nexthdr == NEXTHDR_FRAGMENT) {
hdrlen = 8;
} else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hdr->hdrlen+2)<<2;
else
hdrlen = ipv6_optlen(hdr);
/* OPTS -> evaluate */
#if HOPBYHOP
if (nexthdr == NEXTHDR_HOP) {
temp |= MASK_HOPOPTS;
#else
if (nexthdr == NEXTHDR_DEST) {
temp |= MASK_DSTOPTS;
#endif
break;
}
/* set the flag */
switch (nexthdr){
case NEXTHDR_HOP:
case NEXTHDR_ROUTING:
case NEXTHDR_FRAGMENT:
case NEXTHDR_AUTH:
case NEXTHDR_DEST:
break;
default:
DEBUGP("ipv6_opts match: unknown nextheader %u\n",nexthdr);
return 0;
break;
}
nexthdr = hdr->nexthdr;
len -= hdrlen;
ptr += hdrlen;
if ( ptr > skb->len ) {
DEBUGP("ipv6_opts: new pointer is too large! \n");
break;
}
}
/* OPTIONS header not found */
#if HOPBYHOP
if ( temp != MASK_HOPOPTS ) return 0;
#else
if ( temp != MASK_DSTOPTS ) return 0;
#endif
if (len < (int)sizeof(struct ipv6_opt_hdr)){
*hotdrop = 1;
return 0;
}
if (len < hdrlen){
/* Packet smaller than it's length field */
return 0;
}
optsh=(void *)(skb->data)+ptr;
DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen);
DEBUGP("len %02X %04X %02X ",
optinfo->hdrlen, hdrlen,
(!(optinfo->flags & IP6T_OPTS_LEN) ||
((optinfo->hdrlen == hdrlen) ^
!!(optinfo->invflags & IP6T_OPTS_INV_LEN))));
ret = (optsh != NULL)
&&
(!(optinfo->flags & IP6T_OPTS_LEN) ||
((optinfo->hdrlen == hdrlen) ^
!!(optinfo->invflags & IP6T_OPTS_INV_LEN)));
temp = len = 0;
ptr += 2;
hdrlen -= 2;
if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){
return ret;
} else if (optinfo->flags & IP6T_OPTS_NSTRICT) {
DEBUGP("Not strict - not implemented");
} else {
DEBUGP("Strict ");
DEBUGP("#%d ",optinfo->optsnr);
for(temp=0; temp<optinfo->optsnr; temp++){
optdesc = (void *)(skb->data)+ptr;
/* Type check */
if ( (unsigned char)*optdesc !=
(optinfo->opts[temp] & 0xFF00)>>8 ){
DEBUGP("Tbad %02X %02X\n",
(unsigned char)*optdesc,
(optinfo->opts[temp] &
0xFF00)>>8);
return 0;
} else {
DEBUGP("Tok ");
}
/* Length check */
if (((optinfo->opts[temp] & 0x00FF) != 0xFF) &&
(unsigned char)*optdesc != 0){
if ( ntohs((u16)*optdesc) !=
optinfo->opts[temp] ){
DEBUGP("Lbad %02X %04X %04X\n",
(unsigned char)*optdesc,
ntohs((u16)*optdesc),
optinfo->opts[temp]);
return 0;
} else {
DEBUGP("Lok ");
}
}
/* Step to the next */
if ((unsigned char)*optdesc == 0){
DEBUGP("PAD0 \n");
ptr++;
hdrlen--;
} else {
ptr += LOW(ntohs(*optdesc));
hdrlen -= LOW(ntohs(*optdesc));
DEBUGP("len%04X \n",
LOW(ntohs(*optdesc)));
}
if (ptr > skb->len || ( !hdrlen &&
(temp != optinfo->optsnr - 1))) {
DEBUGP("new pointer is too large! \n");
break;
}
}
if (temp == optinfo->optsnr)
return ret;
else return 0;
}
return 0;
}
/* Called when user tries to insert an entry of this type. */
static int
checkentry(const char *tablename,
const struct ip6t_ip6 *ip,
void *matchinfo,
unsigned int matchinfosize,
unsigned int hook_mask)
{
const struct ip6t_opts *optsinfo = matchinfo;
if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) {
DEBUGP("ip6t_opts: matchsize %u != %u\n",
matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts)));
return 0;
}
if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) {
DEBUGP("ip6t_opts: unknown flags %X\n",
optsinfo->invflags);
return 0;
}
return 1;
}
static struct ip6t_match opts_match
#if HOPBYHOP
= { { NULL, NULL }, "hbh", &match, &checkentry, NULL, THIS_MODULE };
#else
= { { NULL, NULL }, "dst", &match, &checkentry, NULL, THIS_MODULE };
#endif
static int __init init(void)
{
return ip6t_register_match(&opts_match);
}
static void __exit cleanup(void)
{
ip6t_unregister_match(&opts_match);
}
module_init(init);
module_exit(cleanup);
/* Kernel module to match ESP parameters. */
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ipv6.h>
#include <linux/types.h>
#include <net/checksum.h>
#include <net/ipv6.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_ipv6/ip6t_esp.h>
EXPORT_NO_SYMBOLS;
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("IPv6 ESP match");
MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
#if 0
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
struct esphdr {
__u32 spi;
};
int ipv6_ext_hdr(u8 nexthdr)
{
return ( (nexthdr == NEXTHDR_HOP) ||
(nexthdr == NEXTHDR_ROUTING) ||
(nexthdr == NEXTHDR_FRAGMENT) ||
(nexthdr == NEXTHDR_AUTH) ||
(nexthdr == NEXTHDR_ESP) ||
(nexthdr == NEXTHDR_NONE) ||
(nexthdr == NEXTHDR_DEST) );
}
/* Returns 1 if the spi is matched by the range, 0 otherwise */
static inline int
spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
{
int r=0;
DEBUGP("esp spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
min,spi,max);
r=(spi >= min && spi <= max) ^ invert;
DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n");
return r;
}
static int
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *protohdr,
u_int16_t datalen,
int *hotdrop)
{
struct esphdr *esp = NULL;
const struct ip6t_esp *espinfo = matchinfo;
unsigned int temp;
int len;
u8 nexthdr;
unsigned int ptr;
/* Make sure this isn't an evil packet */
/*DEBUGP("ipv6_esp entered \n");*/
/* type of the 1st exthdr */
nexthdr = skb->nh.ipv6h->nexthdr;
/* pointer to the 1st exthdr */
ptr = sizeof(struct ipv6hdr);
/* available length */
len = skb->len - ptr;
temp = 0;
while (ipv6_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr *hdr;
int hdrlen;
DEBUGP("ipv6_esp header iteration \n");
/* Is there enough space for the next ext header? */
if (len < (int)sizeof(struct ipv6_opt_hdr))
return 0;
/* No more exthdr -> evaluate */
if (nexthdr == NEXTHDR_NONE) {
break;
}
/* ESP -> evaluate */
if (nexthdr == NEXTHDR_ESP) {
temp |= MASK_ESP;
break;
}
hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
/* Calculate the header length */
if (nexthdr == NEXTHDR_FRAGMENT) {
hdrlen = 8;
} else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hdr->hdrlen+2)<<2;
else
hdrlen = ipv6_optlen(hdr);
/* set the flag */
switch (nexthdr){
case NEXTHDR_HOP:
case NEXTHDR_ROUTING:
case NEXTHDR_FRAGMENT:
case NEXTHDR_AUTH:
case NEXTHDR_DEST:
break;
default:
DEBUGP("ipv6_esp match: unknown nextheader %u\n",nexthdr);
return 0;
break;
}
nexthdr = hdr->nexthdr;
len -= hdrlen;
ptr += hdrlen;
if ( ptr > skb->len ) {
DEBUGP("ipv6_esp: new pointer too large! \n");
break;
}
}
/* ESP header not found */
if ( temp != MASK_ESP ) return 0;
if (len < (int)sizeof(struct esphdr)){
*hotdrop = 1;
return 0;
}
esp=skb->data+ptr;
DEBUGP("IPv6 ESP SPI %u %08X\n", ntohl(esp->spi), ntohl(esp->spi));
return (esp != NULL)
&& spi_match(espinfo->spis[0], espinfo->spis[1],
ntohl(esp->spi),
!!(espinfo->invflags & IP6T_ESP_INV_SPI));
}
/* Called when user tries to insert an entry of this type. */
static int
checkentry(const char *tablename,
const struct ip6t_ip6 *ip,
void *matchinfo,
unsigned int matchinfosize,
unsigned int hook_mask)
{
const struct ip6t_esp *espinfo = matchinfo;
if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_esp))) {
DEBUGP("ip6t_esp: matchsize %u != %u\n",
matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_esp)));
return 0;
}
if (espinfo->invflags & ~IP6T_ESP_INV_MASK) {
DEBUGP("ip6t_esp: unknown flags %X\n",
espinfo->invflags);
return 0;
}
return 1;
}
static struct ip6t_match esp_match
= { { NULL, NULL }, "esp", &match, &checkentry, NULL, THIS_MODULE };
static int __init init(void)
{
return ip6t_register_match(&esp_match);
}
static void __exit cleanup(void)
{
ip6t_unregister_match(&esp_match);
}
module_init(init);
module_exit(cleanup);
/* Kernel module to match FRAG parameters. */
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ipv6.h>
#include <linux/types.h>
#include <net/checksum.h>
#include <net/ipv6.h>
#include <asm/byteorder.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_ipv6/ip6t_frag.h>
EXPORT_NO_SYMBOLS;
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("IPv6 FRAG match");
MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
#if 0
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
#if 0
#if BYTE_ORDER == BIG_ENDIAN
#define IP6F_OFF_MASK 0xfff8 /* mask out offset from _offlg */
#define IP6F_RESERVED_MASK 0x0006 /* reserved bits in ip6f_offlg */
#define IP6F_MORE_FRAG 0x0001 /* more-fragments flag */
#else /* BYTE_ORDER == LITTLE_ENDIAN */
#define IP6F_OFF_MASK 0xf8ff /* mask out offset from _offlg */
#define IP6F_RESERVED_MASK 0x0600 /* reserved bits in ip6f_offlg */
#define IP6F_MORE_FRAG 0x0100 /* more-fragments flag */
#endif
#endif
#define IP6F_OFF_MASK 0xf8ff /* mask out offset from _offlg */
#define IP6F_RESERVED_MASK 0x0600 /* reserved bits in ip6f_offlg */
#define IP6F_MORE_FRAG 0x0100 /* more-fragments flag */
struct fraghdr {
__u8 nexthdr;
__u8 hdrlen;
__u16 info;
__u32 id;
};
int ipv6_ext_hdr(u8 nexthdr)
{
return ( (nexthdr == NEXTHDR_HOP) ||
(nexthdr == NEXTHDR_ROUTING) ||
(nexthdr == NEXTHDR_FRAGMENT) ||
(nexthdr == NEXTHDR_AUTH) ||
(nexthdr == NEXTHDR_ESP) ||
(nexthdr == NEXTHDR_NONE) ||
(nexthdr == NEXTHDR_DEST) );
}
/* Returns 1 if the id is matched by the range, 0 otherwise */
static inline int
id_match(u_int32_t min, u_int32_t max, u_int32_t id, int invert)
{
int r=0;
DEBUGP("frag id_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
min,id,max);
r=(id >= min && id <= max) ^ invert;
DEBUGP(" result %s\n",r? "PASS" : "FAILED");
return r;
}
static int
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *protohdr,
u_int16_t datalen,
int *hotdrop)
{
struct fraghdr *frag = NULL;
const struct ip6t_frag *fraginfo = matchinfo;
unsigned int temp;
int len;
u8 nexthdr;
unsigned int ptr;
unsigned int hdrlen = 0;
/* type of the 1st exthdr */
nexthdr = skb->nh.ipv6h->nexthdr;
/* pointer to the 1st exthdr */
ptr = sizeof(struct ipv6hdr);
/* available length */
len = skb->len - ptr;
temp = 0;
while (ipv6_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr *hdr;
DEBUGP("ipv6_frag header iteration \n");
/* Is there enough space for the next ext header? */
if (len < (int)sizeof(struct ipv6_opt_hdr))
return 0;
/* No more exthdr -> evaluate */
if (nexthdr == NEXTHDR_NONE) {
break;
}
/* ESP -> evaluate */
if (nexthdr == NEXTHDR_ESP) {
break;
}
hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
/* Calculate the header length */
if (nexthdr == NEXTHDR_FRAGMENT) {
hdrlen = 8;
} else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hdr->hdrlen+2)<<2;
else
hdrlen = ipv6_optlen(hdr);
/* FRAG -> evaluate */
if (nexthdr == NEXTHDR_FRAGMENT) {
temp |= MASK_FRAGMENT;
break;
}
/* set the flag */
switch (nexthdr){
case NEXTHDR_HOP:
case NEXTHDR_ROUTING:
case NEXTHDR_FRAGMENT:
case NEXTHDR_AUTH:
case NEXTHDR_DEST:
break;
default:
DEBUGP("ipv6_frag match: unknown nextheader %u\n",nexthdr);
return 0;
break;
}
nexthdr = hdr->nexthdr;
len -= hdrlen;
ptr += hdrlen;
if ( ptr > skb->len ) {
DEBUGP("ipv6_frag: new pointer too large! \n");
break;
}
}
/* FRAG header not found */
if ( temp != MASK_FRAGMENT ) return 0;
if (len < (int)sizeof(struct fraghdr)){
*hotdrop = 1;
return 0;
}
frag=skb->data+ptr;
DEBUGP("IPv6 FRAG LEN %u %u ", hdrlen, frag->hdrlen);
DEBUGP("INFO %04X ", frag->info);
DEBUGP("OFFSET %04X ", frag->info & IP6F_OFF_MASK);
DEBUGP("RES %04X ", frag->info & IP6F_RESERVED_MASK);
DEBUGP("MF %04X ", frag->info & IP6F_MORE_FRAG);
DEBUGP("ID %u %08X\n", ntohl(frag->id), ntohl(frag->id));
DEBUGP("IPv6 FRAG id %02X ",
(id_match(fraginfo->ids[0], fraginfo->ids[1],
ntohl(frag->id),
!!(fraginfo->invflags & IP6T_FRAG_INV_IDS))));
DEBUGP("len %02X %04X %02X ",
fraginfo->hdrlen, hdrlen,
(!fraginfo->hdrlen ||
(fraginfo->hdrlen == hdrlen) ^
!!(fraginfo->invflags & IP6T_FRAG_INV_LEN)));
DEBUGP("res %02X %02X %02X ",
(fraginfo->flags & IP6T_FRAG_RES), frag->info & IP6F_RESERVED_MASK,
!((fraginfo->flags & IP6T_FRAG_RES) && (frag->info & IP6F_RESERVED_MASK)));
DEBUGP("first %02X %02X %02X ",
(fraginfo->flags & IP6T_FRAG_FST), frag->info & IP6F_OFF_MASK,
!((fraginfo->flags & IP6T_FRAG_FST) && (frag->info & IP6F_OFF_MASK)));
DEBUGP("mf %02X %02X %02X ",
(fraginfo->flags & IP6T_FRAG_MF), frag->info & IP6F_MORE_FRAG,
!((fraginfo->flags & IP6T_FRAG_MF) && !((frag->info & IP6F_MORE_FRAG))));
DEBUGP("last %02X %02X %02X\n",
(fraginfo->flags & IP6T_FRAG_NMF), frag->info & IP6F_MORE_FRAG,
!((fraginfo->flags & IP6T_FRAG_NMF) && (frag->info & IP6F_MORE_FRAG)));
return (frag != NULL)
&&
(id_match(fraginfo->ids[0], fraginfo->ids[1],
ntohl(frag->id),
!!(fraginfo->invflags & IP6T_FRAG_INV_IDS)))
&&
(!fraginfo->hdrlen ||
(fraginfo->hdrlen == hdrlen) ^
!!(fraginfo->invflags & IP6T_FRAG_INV_LEN))
&&
!((fraginfo->flags & IP6T_FRAG_RES) && (frag->info & IP6F_RESERVED_MASK))
&&
!((fraginfo->flags & IP6T_FRAG_FST) && (frag->info & IP6F_OFF_MASK))
&&
!((fraginfo->flags & IP6T_FRAG_MF) && !((frag->info & IP6F_MORE_FRAG)))
&&
!((fraginfo->flags & IP6T_FRAG_NMF) && (frag->info & IP6F_MORE_FRAG));
}
/* Called when user tries to insert an entry of this type. */
static int
checkentry(const char *tablename,
const struct ip6t_ip6 *ip,
void *matchinfo,
unsigned int matchinfosize,
unsigned int hook_mask)
{
const struct ip6t_frag *fraginfo = matchinfo;
if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_frag))) {
DEBUGP("ip6t_frag: matchsize %u != %u\n",
matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_frag)));
return 0;
}
if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) {
DEBUGP("ip6t_frag: unknown flags %X\n",
fraginfo->invflags);
return 0;
}
return 1;
}
static struct ip6t_match frag_match
= { { NULL, NULL }, "frag", &match, &checkentry, NULL, THIS_MODULE };
static int __init init(void)
{
return ip6t_register_match(&frag_match);
}
static void __exit cleanup(void)
{
ip6t_unregister_match(&frag_match);
}
module_init(init);
module_exit(cleanup);
/* Kernel module to match Hop-by-Hop and Destination parameters. */
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ipv6.h>
#include <linux/types.h>
#include <net/checksum.h>
#include <net/ipv6.h>
#include <asm/byteorder.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_ipv6/ip6t_opts.h>
#define LOW(n) (n & 0x00FF)
#define HOPBYHOP 1
EXPORT_NO_SYMBOLS;
MODULE_LICENSE("GPL");
#if HOPBYHOP
MODULE_DESCRIPTION("IPv6 HbH match");
#else
MODULE_DESCRIPTION("IPv6 DST match");
#endif
MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
#if 0
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
int ipv6_ext_hdr(u8 nexthdr)
{
return ( (nexthdr == NEXTHDR_HOP) ||
(nexthdr == NEXTHDR_ROUTING) ||
(nexthdr == NEXTHDR_FRAGMENT) ||
(nexthdr == NEXTHDR_AUTH) ||
(nexthdr == NEXTHDR_ESP) ||
(nexthdr == NEXTHDR_NONE) ||
(nexthdr == NEXTHDR_DEST) );
}
/*
* (Type & 0xC0) >> 6
* 0 -> ignorable
* 1 -> must drop the packet
* 2 -> send ICMP PARM PROB regardless and drop packet
* 3 -> Send ICMP if not a multicast address and drop packet
* (Type & 0x20) >> 5
* 0 -> invariant
* 1 -> can change the routing
* (Type & 0x1F) Type
* 0 -> PAD0 (only 1 byte!)
* 1 -> PAD1 LENGTH info (total length = length + 2)
* C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k )
* 5 -> RTALERT 2 x x
*/
static int
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *protohdr,
u_int16_t datalen,
int *hotdrop)
{
struct ipv6_opt_hdr *optsh = NULL;
const struct ip6t_opts *optinfo = matchinfo;
unsigned int temp;
unsigned int len;
u8 nexthdr;
unsigned int ptr;
unsigned int hdrlen = 0;
unsigned int ret = 0;
u_int16_t *optdesc = NULL;
/* type of the 1st exthdr */
nexthdr = skb->nh.ipv6h->nexthdr;
/* pointer to the 1st exthdr */
ptr = sizeof(struct ipv6hdr);
/* available length */
len = skb->len - ptr;
temp = 0;
while (ipv6_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr *hdr;
DEBUGP("ipv6_opts header iteration \n");
/* Is there enough space for the next ext header? */
if (len < (int)sizeof(struct ipv6_opt_hdr))
return 0;
/* No more exthdr -> evaluate */
if (nexthdr == NEXTHDR_NONE) {
break;
}
/* ESP -> evaluate */
if (nexthdr == NEXTHDR_ESP) {
break;
}
hdr=(void *)(skb->data)+ptr;
/* Calculate the header length */
if (nexthdr == NEXTHDR_FRAGMENT) {
hdrlen = 8;
} else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hdr->hdrlen+2)<<2;
else
hdrlen = ipv6_optlen(hdr);
/* OPTS -> evaluate */
#if HOPBYHOP
if (nexthdr == NEXTHDR_HOP) {
temp |= MASK_HOPOPTS;
#else
if (nexthdr == NEXTHDR_DEST) {
temp |= MASK_DSTOPTS;
#endif
break;
}
/* set the flag */
switch (nexthdr){
case NEXTHDR_HOP:
case NEXTHDR_ROUTING:
case NEXTHDR_FRAGMENT:
case NEXTHDR_AUTH:
case NEXTHDR_DEST:
break;
default:
DEBUGP("ipv6_opts match: unknown nextheader %u\n",nexthdr);
return 0;
break;
}
nexthdr = hdr->nexthdr;
len -= hdrlen;
ptr += hdrlen;
if ( ptr > skb->len ) {
DEBUGP("ipv6_opts: new pointer is too large! \n");
break;
}
}
/* OPTIONS header not found */
#if HOPBYHOP
if ( temp != MASK_HOPOPTS ) return 0;
#else
if ( temp != MASK_DSTOPTS ) return 0;
#endif
if (len < (int)sizeof(struct ipv6_opt_hdr)){
*hotdrop = 1;
return 0;
}
if (len < hdrlen){
/* Packet smaller than it's length field */
return 0;
}
optsh=(void *)(skb->data)+ptr;
DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen);
DEBUGP("len %02X %04X %02X ",
optinfo->hdrlen, hdrlen,
(!(optinfo->flags & IP6T_OPTS_LEN) ||
((optinfo->hdrlen == hdrlen) ^
!!(optinfo->invflags & IP6T_OPTS_INV_LEN))));
ret = (optsh != NULL)
&&
(!(optinfo->flags & IP6T_OPTS_LEN) ||
((optinfo->hdrlen == hdrlen) ^
!!(optinfo->invflags & IP6T_OPTS_INV_LEN)));
temp = len = 0;
ptr += 2;
hdrlen -= 2;
if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){
return ret;
} else if (optinfo->flags & IP6T_OPTS_NSTRICT) {
DEBUGP("Not strict - not implemented");
} else {
DEBUGP("Strict ");
DEBUGP("#%d ",optinfo->optsnr);
for(temp=0; temp<optinfo->optsnr; temp++){
optdesc = (void *)(skb->data)+ptr;
/* Type check */
if ( (unsigned char)*optdesc !=
(optinfo->opts[temp] & 0xFF00)>>8 ){
DEBUGP("Tbad %02X %02X\n",
(unsigned char)*optdesc,
(optinfo->opts[temp] &
0xFF00)>>8);
return 0;
} else {
DEBUGP("Tok ");
}
/* Length check */
if (((optinfo->opts[temp] & 0x00FF) != 0xFF) &&
(unsigned char)*optdesc != 0){
if ( ntohs((u16)*optdesc) !=
optinfo->opts[temp] ){
DEBUGP("Lbad %02X %04X %04X\n",
(unsigned char)*optdesc,
ntohs((u16)*optdesc),
optinfo->opts[temp]);
return 0;
} else {
DEBUGP("Lok ");
}
}
/* Step to the next */
if ((unsigned char)*optdesc == 0){
DEBUGP("PAD0 \n");
ptr++;
hdrlen--;
} else {
ptr += LOW(ntohs(*optdesc));
hdrlen -= LOW(ntohs(*optdesc));
DEBUGP("len%04X \n",
LOW(ntohs(*optdesc)));
}
if (ptr > skb->len || ( !hdrlen &&
(temp != optinfo->optsnr - 1))) {
DEBUGP("new pointer is too large! \n");
break;
}
}
if (temp == optinfo->optsnr)
return ret;
else return 0;
}
return 0;
}
/* Called when user tries to insert an entry of this type. */
static int
checkentry(const char *tablename,
const struct ip6t_ip6 *ip,
void *matchinfo,
unsigned int matchinfosize,
unsigned int hook_mask)
{
const struct ip6t_opts *optsinfo = matchinfo;
if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) {
DEBUGP("ip6t_opts: matchsize %u != %u\n",
matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts)));
return 0;
}
if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) {
DEBUGP("ip6t_opts: unknown flags %X\n",
optsinfo->invflags);
return 0;
}
return 1;
}
static struct ip6t_match opts_match
#if HOPBYHOP
= { { NULL, NULL }, "hbh", &match, &checkentry, NULL, THIS_MODULE };
#else
= { { NULL, NULL }, "dst", &match, &checkentry, NULL, THIS_MODULE };
#endif
static int __init init(void)
{
return ip6t_register_match(&opts_match);
}
static void __exit cleanup(void)
{
ip6t_unregister_match(&opts_match);
}
module_init(init);
module_exit(cleanup);
/*
* Hop Limit matching module
* Maciej Soltysiak <solt@dns.toxicfilms.tv>
* Based on HW's ttl module
*
* This software is distributed under the terms GNU GPL
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter_ipv6/ip6t_hl.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
MODULE_DESCRIPTION("IP tables Hop Limit matching module");
MODULE_LICENSE("GPL");
static int match(const struct sk_buff *skb, const struct net_device *in,
const struct net_device *out, const void *matchinfo,
int offset, const void *hdr, u_int16_t datalen,
int *hotdrop)
{
const struct ip6t_hl_info *info = matchinfo;
const struct ipv6hdr *ip6h = skb->nh.ipv6h;
switch (info->mode) {
case IP6T_HL_EQ:
return (ip6h->hop_limit == info->hop_limit);
break;
case IP6T_HL_NE:
return (!(ip6h->hop_limit == info->hop_limit));
break;
case IP6T_HL_LT:
return (ip6h->hop_limit < info->hop_limit);
break;
case IP6T_HL_GT:
return (ip6h->hop_limit > info->hop_limit);
break;
default:
printk(KERN_WARNING "ip6t_hl: unknown mode %d\n",
info->mode);
return 0;
}
return 0;
}
static int checkentry(const char *tablename, const struct ip6t_ip6 *ip,
void *matchinfo, unsigned int matchsize,
unsigned int hook_mask)
{
if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_hl_info)))
return 0;
return 1;
}
static struct ip6t_match hl_match = { { NULL, NULL }, "hl", &match,
&checkentry, NULL, THIS_MODULE };
static int __init init(void)
{
return ip6t_register_match(&hl_match);
}
static void __exit fini(void)
{
ip6t_unregister_match(&hl_match);
}
module_init(init);
module_exit(fini);
/* ipv6header match - matches IPv6 packets based
on whether they contain certain headers */
/* Original idea: Brad Chapman
* Rewritten by: Andras Kis-Szabo <kisza@sch.bme.hu> */
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ipv6.h>
#include <linux/types.h>
#include <net/checksum.h>
#include <net/ipv6.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_ipv6/ip6t_ipv6header.h>
EXPORT_NO_SYMBOLS;
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("IPv6 headers match");
MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
#if 0
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
int ipv6_ext_hdr(u8 nexthdr)
{
return ( (nexthdr == NEXTHDR_HOP) ||
(nexthdr == NEXTHDR_ROUTING) ||
(nexthdr == NEXTHDR_FRAGMENT) ||
(nexthdr == NEXTHDR_AUTH) ||
(nexthdr == NEXTHDR_ESP) ||
(nexthdr == NEXTHDR_NONE) ||
(nexthdr == NEXTHDR_DEST) );
}
static int
ipv6header_match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *protohdr,
u_int16_t datalen,
int *hotdrop)
{
const struct ip6t_ipv6header_info *info = matchinfo;
unsigned int temp;
int len;
u8 nexthdr;
unsigned int ptr;
struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
/* Make sure this isn't an evil packet */
DEBUGP("ipv6_header entered \n");
/* type of the 1st exthdr */
nexthdr = skb->nh.ipv6h->nexthdr;
/* pointer to the 1st exthdr */
ptr = sizeof(struct ipv6hdr);
/* available length */
len = skb->len - ptr;
temp = 0;
DEBUGP("ipv6_header nexthdr %02X \n",nexthdr);
DEBUGP("ipv6_header ptr %08X \n",ptr);
DEBUGP("ipv6_header skblen %04X \n",skb->len);
DEBUGP("ipv6_header skbdatalen %04X \n",skb->data_len);
DEBUGP("ipv6_header len %04X \n",len);
#if 0
for (temp=0;temp<skb->len;temp++){
if (!(temp % 16 )) DEBUGP("\nipv6_header data ");
DEBUGP("%02X ",skb->data[temp]);
}
#endif
DEBUGP("\nipv6_header h.raw %02X %02X %02X %02X \n",
skb->h.raw[0],
skb->h.raw[1],
skb->h.raw[2],
skb->h.raw[3]);
DEBUGP("ipv6_header nh.raw %02X %02X %02X %02X \n",
skb->nh.raw[0],
skb->nh.raw[1],
skb->nh.raw[2],
skb->nh.raw[3]);
DEBUGP("ipv6_header CB %02X %02X %02X %02X %02X %02X %02X \n",
opt->iif,
opt->ra,
opt->hop,
opt->auth,
opt->dst0,
opt->srcrt,
opt->dst1);
temp = 0;
while (ipv6_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr *hdr;
int hdrlen;
DEBUGP("ipv6_header header iteration \n");
/* Is there enough space for the next ext header? */
if (len < (int)sizeof(struct ipv6_opt_hdr))
return 0;
/* No more exthdr -> evaluate */
if (nexthdr == NEXTHDR_NONE) {
temp |= MASK_NONE;
break;
}
/* ESP -> evaluate */
if (nexthdr == NEXTHDR_ESP) {
temp |= MASK_ESP;
break;
}
hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
/* Calculate the header length */
if (nexthdr == NEXTHDR_FRAGMENT) {
hdrlen = 8;
} else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hdr->hdrlen+2)<<2;
else
hdrlen = ipv6_optlen(hdr);
DEBUGP("ipv6_header hdrlen %04X \n",hdrlen);
/* set the flag */
switch (nexthdr){
case NEXTHDR_HOP:
temp |= MASK_HOPOPTS;
break;
case NEXTHDR_ROUTING:
temp |= MASK_ROUTING;
break;
case NEXTHDR_FRAGMENT:
temp |= MASK_FRAGMENT;
break;
case NEXTHDR_AUTH:
temp |= MASK_AH;
break;
case NEXTHDR_DEST:
temp |= MASK_DSTOPTS;
break;
default:
DEBUGP("IPV6HEADER match: unknown nextheader %u\n",nexthdr);
return 0;
break;
}
nexthdr = hdr->nexthdr;
len -= hdrlen;
ptr += hdrlen;
if ( ptr > skb->len ) {
DEBUGP("ipv6_header new ptr %04X \n",ptr);
break;
}
}
if ( (nexthdr != NEXTHDR_NONE ) && (nexthdr != NEXTHDR_ESP) )
temp |= MASK_PROTO;
DEBUGP ("ipv6header: %02X %02X \n", temp, info->matchflags);
if (info->modeflag)
return (!( (temp & info->matchflags)
^ info->matchflags) ^ info->invflags);
else
return (!( temp ^ info->matchflags) ^ info->invflags);
}
static int
ipv6header_checkentry(const char *tablename,
const struct ip6t_ip6 *ip,
void *matchinfo,
unsigned int matchsize,
unsigned int hook_mask)
{
/* Check for obvious errors */
/* This match is valid in all hooks! */
if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info))) {
DEBUGP("ip6t_ipv6header: matchsize != %u\n",
IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info)));
return 0;
}
return 1;
}
static void
ipv6header_destroy(void *matchinfo,
unsigned int matchinfosize)
{
return;
}
static struct ip6t_match
ip6t_ipv6header_match = {
{ NULL, NULL },
"ipv6header",
&ipv6header_match,
&ipv6header_checkentry,
&ipv6header_destroy,
THIS_MODULE
};
static int __init ipv6header_init(void)
{
return ip6t_register_match(&ip6t_ipv6header_match);
}
static void __exit ipv6header_exit(void)
{
ip6t_unregister_match(&ip6t_ipv6header_match);
}
module_init(ipv6header_init);
module_exit(ipv6header_exit);
/* Kernel module to match ROUTING parameters. */
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ipv6.h>
#include <linux/types.h>
#include <net/checksum.h>
#include <net/ipv6.h>
#include <asm/byteorder.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_ipv6/ip6t_rt.h>
EXPORT_NO_SYMBOLS;
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("IPv6 RT match");
MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
#if 0
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
int ipv6_ext_hdr(u8 nexthdr)
{
return ( (nexthdr == NEXTHDR_HOP) ||
(nexthdr == NEXTHDR_ROUTING) ||
(nexthdr == NEXTHDR_FRAGMENT) ||
(nexthdr == NEXTHDR_AUTH) ||
(nexthdr == NEXTHDR_ESP) ||
(nexthdr == NEXTHDR_NONE) ||
(nexthdr == NEXTHDR_DEST) );
}
/* Returns 1 if the id is matched by the range, 0 otherwise */
static inline int
segsleft_match(u_int32_t min, u_int32_t max, u_int32_t id, int invert)
{
int r=0;
DEBUGP("rt segsleft_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
min,id,max);
r=(id >= min && id <= max) ^ invert;
DEBUGP(" result %s\n",r? "PASS" : "FAILED");
return r;
}
static int
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *protohdr,
u_int16_t datalen,
int *hotdrop)
{
struct ipv6_rt_hdr *route = NULL;
const struct ip6t_rt *rtinfo = matchinfo;
unsigned int temp;
unsigned int len;
u8 nexthdr;
unsigned int ptr;
unsigned int hdrlen = 0;
unsigned int ret = 0;
/* type of the 1st exthdr */
nexthdr = skb->nh.ipv6h->nexthdr;
/* pointer to the 1st exthdr */
ptr = sizeof(struct ipv6hdr);
/* available length */
len = skb->len - ptr;
temp = 0;
while (ipv6_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr *hdr;
DEBUGP("ipv6_rt header iteration \n");
/* Is there enough space for the next ext header? */
if (len < (int)sizeof(struct ipv6_opt_hdr))
return 0;
/* No more exthdr -> evaluate */
if (nexthdr == NEXTHDR_NONE) {
break;
}
/* ESP -> evaluate */
if (nexthdr == NEXTHDR_ESP) {
break;
}
hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
/* Calculate the header length */
if (nexthdr == NEXTHDR_FRAGMENT) {
hdrlen = 8;
} else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hdr->hdrlen+2)<<2;
else
hdrlen = ipv6_optlen(hdr);
/* ROUTING -> evaluate */
if (nexthdr == NEXTHDR_ROUTING) {
temp |= MASK_ROUTING;
break;
}
/* set the flag */
switch (nexthdr){
case NEXTHDR_HOP:
case NEXTHDR_ROUTING:
case NEXTHDR_FRAGMENT:
case NEXTHDR_AUTH:
case NEXTHDR_DEST:
break;
default:
DEBUGP("ipv6_rt match: unknown nextheader %u\n",nexthdr);
return 0;
break;
}
nexthdr = hdr->nexthdr;
len -= hdrlen;
ptr += hdrlen;
if ( ptr > skb->len ) {
DEBUGP("ipv6_rt: new pointer is too large! \n");
break;
}
}
/* ROUTING header not found */
if ( temp != MASK_ROUTING ) return 0;
if (len < (int)sizeof(struct ipv6_rt_hdr)){
*hotdrop = 1;
return 0;
}
if (len < hdrlen){
/* Pcket smaller than its length field */
return 0;
}
route=skb->data+ptr;
DEBUGP("IPv6 RT LEN %u %u ", hdrlen, route->hdrlen);
DEBUGP("TYPE %04X ", route->type);
DEBUGP("SGS_LEFT %u %08X\n", ntohl(route->segments_left), ntohl(route->segments_left));
DEBUGP("IPv6 RT segsleft %02X ",
(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
ntohl(route->segments_left),
!!(rtinfo->invflags & IP6T_RT_INV_SGS))));
DEBUGP("type %02X %02X %02X ",
rtinfo->rt_type, route->type,
(!(rtinfo->flags & IP6T_RT_TYP) ||
((rtinfo->rt_type == route->type) ^
!!(rtinfo->invflags & IP6T_RT_INV_TYP))));
DEBUGP("len %02X %04X %02X ",
rtinfo->hdrlen, hdrlen,
(!(rtinfo->flags & IP6T_RT_LEN) ||
((rtinfo->hdrlen == hdrlen) ^
!!(rtinfo->invflags & IP6T_RT_INV_LEN))));
DEBUGP("res %02X %02X %02X ",
(rtinfo->flags & IP6T_RT_RES), ((struct rt0_hdr *)route)->bitmap,
!((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->bitmap)));
ret = (route != NULL)
&&
(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
ntohl(route->segments_left),
!!(rtinfo->invflags & IP6T_RT_INV_SGS)))
&&
(!(rtinfo->flags & IP6T_RT_LEN) ||
((rtinfo->hdrlen == hdrlen) ^
!!(rtinfo->invflags & IP6T_RT_INV_LEN)))
&&
(!(rtinfo->flags & IP6T_RT_TYP) ||
((rtinfo->rt_type == route->type) ^
!!(rtinfo->invflags & IP6T_RT_INV_TYP)))
&&
!((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->bitmap));
DEBUGP("#%d ",rtinfo->addrnr);
temp = len = ptr = 0;
if ( !(rtinfo->flags & IP6T_RT_FST) ){
return ret;
} else if (rtinfo->flags & IP6T_RT_FST_NSTRICT) {
DEBUGP("Not strict ");
if ( rtinfo->addrnr > (unsigned int)((hdrlen-8)/16) ){
DEBUGP("There isn't enough space\n");
return 0;
} else {
DEBUGP("#%d ",rtinfo->addrnr);
ptr = 0;
for(temp=0; temp<(unsigned int)((hdrlen-8)/16); temp++){
len = 0;
while ((u8)(((struct rt0_hdr *)route)->
addr[temp].s6_addr[len]) ==
(u8)(rtinfo->addrs[ptr].s6_addr[len])){
DEBUGP("%02X?%02X ",
(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
(u8)(rtinfo->addrs[ptr].s6_addr[len]));
len++;
if ( len == 16 ) break;
}
if (len==16) {
DEBUGP("ptr=%d temp=%d;\n",ptr,temp);
ptr++;
} else {
DEBUGP("%02X?%02X ",
(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
(u8)(rtinfo->addrs[ptr].s6_addr[len]));
DEBUGP("!ptr=%d temp=%d;\n",ptr,temp);
}
if (ptr==rtinfo->addrnr) break;
}
DEBUGP("ptr=%d len=%d #%d\n",ptr,len, rtinfo->addrnr);
if ( (len == 16) && (ptr == rtinfo->addrnr))
return ret;
else return 0;
}
} else {
DEBUGP("Strict ");
if ( rtinfo->addrnr > (unsigned int)((hdrlen-8)/16) ){
DEBUGP("There isn't enough space\n");
return 0;
} else {
DEBUGP("#%d ",rtinfo->addrnr);
for(temp=0; temp<rtinfo->addrnr; temp++){
len = 0;
while ((u8)(((struct rt0_hdr *)route)->
addr[temp].s6_addr[len]) ==
(u8)(rtinfo->addrs[temp].s6_addr[len])){
DEBUGP("%02X?%02X ",
(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
(u8)(rtinfo->addrs[temp].s6_addr[len]));
len++;
if ( len == 16 ) break;
}
if (len!=16) {
DEBUGP("%02X?%02X ",
(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
(u8)(rtinfo->addrs[temp].s6_addr[len]));
DEBUGP("!len=%d temp=%d;\n",len,temp);
break;
}
}
DEBUGP("temp=%d len=%d #%d\n",temp,len,rtinfo->addrnr);
if ( (len == 16) && (temp == rtinfo->addrnr) && (temp == (unsigned int)((hdrlen-8)/16)))
return ret;
else return 0;
}
}
return 0;
}
/* Called when user tries to insert an entry of this type. */
static int
checkentry(const char *tablename,
const struct ip6t_ip6 *ip,
void *matchinfo,
unsigned int matchinfosize,
unsigned int hook_mask)
{
const struct ip6t_rt *rtinfo = matchinfo;
if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_rt))) {
DEBUGP("ip6t_rt: matchsize %u != %u\n",
matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_rt)));
return 0;
}
if (rtinfo->invflags & ~IP6T_RT_INV_MASK) {
DEBUGP("ip6t_rt: unknown flags %X\n",
rtinfo->invflags);
return 0;
}
if ( (rtinfo->flags & (IP6T_RT_RES|IP6T_RT_FST_MASK)) &&
(!(rtinfo->flags & IP6T_RT_TYP) ||
(rtinfo->rt_type != 0) ||
(rtinfo->invflags & IP6T_RT_INV_TYP)) ) {
DEBUGP("`--rt-type 0' required before `--rt-0-*'");
return 0;
}
return 1;
}
static struct ip6t_match rt_match
= { { NULL, NULL }, "rt", &match, &checkentry, NULL, THIS_MODULE };
static int __init init(void)
{
return ip6t_register_match(&rt_match);
}
static void __exit cleanup(void)
{
ip6t_unregister_match(&rt_match);
}
module_init(init);
module_exit(cleanup);
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