mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 14:42:24 +00:00
netfilter: ebtables: add IPv6 support
It implements matching functions for IPv6 address & traffic class (merged from the patch sent by Jan Engelhardt [jengelh@computergmbh.de] http://marc.info/?l=netfilter-devel&m=120182168424052&w=2), protocol, and layer-4 port id. Corresponding watcher logging function is also added for IPv6. Signed-off-by: Kuo-lang Tseng <kuo-lang.tseng@intel.com> Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
469689a4dd
commit
93f6515872
40
include/linux/netfilter_bridge/ebt_ip6.h
Normal file
40
include/linux/netfilter_bridge/ebt_ip6.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* ebt_ip6
|
||||
*
|
||||
* Authors:
|
||||
* Kuo-Lang Tseng <kuo-lang.tseng@intel.com>
|
||||
* Manohar Castelino <manohar.r.castelino@intel.com>
|
||||
*
|
||||
* Jan 11, 2008
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_BRIDGE_EBT_IP6_H
|
||||
#define __LINUX_BRIDGE_EBT_IP6_H
|
||||
|
||||
#define EBT_IP6_SOURCE 0x01
|
||||
#define EBT_IP6_DEST 0x02
|
||||
#define EBT_IP6_TCLASS 0x04
|
||||
#define EBT_IP6_PROTO 0x08
|
||||
#define EBT_IP6_SPORT 0x10
|
||||
#define EBT_IP6_DPORT 0x20
|
||||
#define EBT_IP6_MASK (EBT_IP6_SOURCE | EBT_IP6_DEST | EBT_IP6_TCLASS |\
|
||||
EBT_IP6_PROTO | EBT_IP6_SPORT | EBT_IP6_DPORT)
|
||||
#define EBT_IP6_MATCH "ip6"
|
||||
|
||||
/* the same values are used for the invflags */
|
||||
struct ebt_ip6_info
|
||||
{
|
||||
struct in6_addr saddr;
|
||||
struct in6_addr daddr;
|
||||
struct in6_addr smsk;
|
||||
struct in6_addr dmsk;
|
||||
uint8_t tclass;
|
||||
uint8_t protocol;
|
||||
uint8_t bitmask;
|
||||
uint8_t invflags;
|
||||
uint16_t sport[2];
|
||||
uint16_t dport[2];
|
||||
};
|
||||
|
||||
#endif
|
@ -4,7 +4,8 @@
|
||||
#define EBT_LOG_IP 0x01 /* if the frame is made by ip, log the ip information */
|
||||
#define EBT_LOG_ARP 0x02
|
||||
#define EBT_LOG_NFLOG 0x04
|
||||
#define EBT_LOG_MASK (EBT_LOG_IP | EBT_LOG_ARP)
|
||||
#define EBT_LOG_IP6 0x08
|
||||
#define EBT_LOG_MASK (EBT_LOG_IP | EBT_LOG_ARP | EBT_LOG_IP6)
|
||||
#define EBT_LOG_PREFIX_SIZE 30
|
||||
#define EBT_LOG_WATCHER "log"
|
||||
|
||||
|
@ -83,6 +83,15 @@ config BRIDGE_EBT_IP
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config BRIDGE_EBT_IP6
|
||||
tristate "ebt: IP6 filter support"
|
||||
depends on BRIDGE_NF_EBTABLES
|
||||
help
|
||||
This option adds the IP6 match, which allows basic IPV6 header field
|
||||
filtering.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config BRIDGE_EBT_LIMIT
|
||||
tristate "ebt: limit match support"
|
||||
depends on BRIDGE_NF_EBTABLES
|
||||
|
@ -14,6 +14,7 @@ obj-$(CONFIG_BRIDGE_EBT_802_3) += ebt_802_3.o
|
||||
obj-$(CONFIG_BRIDGE_EBT_AMONG) += ebt_among.o
|
||||
obj-$(CONFIG_BRIDGE_EBT_ARP) += ebt_arp.o
|
||||
obj-$(CONFIG_BRIDGE_EBT_IP) += ebt_ip.o
|
||||
obj-$(CONFIG_BRIDGE_EBT_IP) += ebt_ip6.o
|
||||
obj-$(CONFIG_BRIDGE_EBT_LIMIT) += ebt_limit.o
|
||||
obj-$(CONFIG_BRIDGE_EBT_MARK) += ebt_mark_m.o
|
||||
obj-$(CONFIG_BRIDGE_EBT_PKTTYPE) += ebt_pkttype.o
|
||||
|
144
net/bridge/netfilter/ebt_ip6.c
Normal file
144
net/bridge/netfilter/ebt_ip6.c
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* ebt_ip6
|
||||
*
|
||||
* Authors:
|
||||
* Manohar Castelino <manohar.r.castelino@intel.com>
|
||||
* Kuo-Lang Tseng <kuo-lang.tseng@intel.com>
|
||||
* Jan Engelhardt <jengelh@computergmbh.de>
|
||||
*
|
||||
* Summary:
|
||||
* This is just a modification of the IPv4 code written by
|
||||
* Bart De Schuymer <bdschuym@pandora.be>
|
||||
* with the changes required to support IPv6
|
||||
*
|
||||
* Jan, 2008
|
||||
*/
|
||||
|
||||
#include <linux/netfilter_bridge/ebtables.h>
|
||||
#include <linux/netfilter_bridge/ebt_ip6.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/module.h>
|
||||
#include <net/dsfield.h>
|
||||
|
||||
struct tcpudphdr {
|
||||
__be16 src;
|
||||
__be16 dst;
|
||||
};
|
||||
|
||||
static int ebt_filter_ip6(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out, const void *data,
|
||||
unsigned int datalen)
|
||||
{
|
||||
const struct ebt_ip6_info *info = (struct ebt_ip6_info *)data;
|
||||
const struct ipv6hdr *ih6;
|
||||
struct ipv6hdr _ip6h;
|
||||
const struct tcpudphdr *pptr;
|
||||
struct tcpudphdr _ports;
|
||||
struct in6_addr tmp_addr;
|
||||
int i;
|
||||
|
||||
ih6 = skb_header_pointer(skb, 0, sizeof(_ip6h), &_ip6h);
|
||||
if (ih6 == NULL)
|
||||
return EBT_NOMATCH;
|
||||
if (info->bitmask & EBT_IP6_TCLASS &&
|
||||
FWINV(info->tclass != ipv6_get_dsfield(ih6), EBT_IP6_TCLASS))
|
||||
return EBT_NOMATCH;
|
||||
for (i = 0; i < 4; i++)
|
||||
tmp_addr.in6_u.u6_addr32[i] = ih6->saddr.in6_u.u6_addr32[i] &
|
||||
info->smsk.in6_u.u6_addr32[i];
|
||||
if (info->bitmask & EBT_IP6_SOURCE &&
|
||||
FWINV((ipv6_addr_cmp(&tmp_addr, &info->saddr) != 0),
|
||||
EBT_IP6_SOURCE))
|
||||
return EBT_NOMATCH;
|
||||
for (i = 0; i < 4; i++)
|
||||
tmp_addr.in6_u.u6_addr32[i] = ih6->daddr.in6_u.u6_addr32[i] &
|
||||
info->dmsk.in6_u.u6_addr32[i];
|
||||
if (info->bitmask & EBT_IP6_DEST &&
|
||||
FWINV((ipv6_addr_cmp(&tmp_addr, &info->daddr) != 0), EBT_IP6_DEST))
|
||||
return EBT_NOMATCH;
|
||||
if (info->bitmask & EBT_IP6_PROTO) {
|
||||
uint8_t nexthdr = ih6->nexthdr;
|
||||
int offset_ph;
|
||||
|
||||
offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr);
|
||||
if (offset_ph == -1)
|
||||
return EBT_NOMATCH;
|
||||
if (FWINV(info->protocol != nexthdr, EBT_IP6_PROTO))
|
||||
return EBT_NOMATCH;
|
||||
if (!(info->bitmask & EBT_IP6_DPORT) &&
|
||||
!(info->bitmask & EBT_IP6_SPORT))
|
||||
return EBT_MATCH;
|
||||
pptr = skb_header_pointer(skb, offset_ph, sizeof(_ports),
|
||||
&_ports);
|
||||
if (pptr == NULL)
|
||||
return EBT_NOMATCH;
|
||||
if (info->bitmask & EBT_IP6_DPORT) {
|
||||
u32 dst = ntohs(pptr->dst);
|
||||
if (FWINV(dst < info->dport[0] ||
|
||||
dst > info->dport[1], EBT_IP6_DPORT))
|
||||
return EBT_NOMATCH;
|
||||
}
|
||||
if (info->bitmask & EBT_IP6_SPORT) {
|
||||
u32 src = ntohs(pptr->src);
|
||||
if (FWINV(src < info->sport[0] ||
|
||||
src > info->sport[1], EBT_IP6_SPORT))
|
||||
return EBT_NOMATCH;
|
||||
}
|
||||
return EBT_MATCH;
|
||||
}
|
||||
return EBT_MATCH;
|
||||
}
|
||||
|
||||
static int ebt_ip6_check(const char *tablename, unsigned int hookmask,
|
||||
const struct ebt_entry *e, void *data, unsigned int datalen)
|
||||
{
|
||||
struct ebt_ip6_info *info = (struct ebt_ip6_info *)data;
|
||||
|
||||
if (datalen != EBT_ALIGN(sizeof(struct ebt_ip6_info)))
|
||||
return -EINVAL;
|
||||
if (e->ethproto != htons(ETH_P_IPV6) || e->invflags & EBT_IPROTO)
|
||||
return -EINVAL;
|
||||
if (info->bitmask & ~EBT_IP6_MASK || info->invflags & ~EBT_IP6_MASK)
|
||||
return -EINVAL;
|
||||
if (info->bitmask & (EBT_IP6_DPORT | EBT_IP6_SPORT)) {
|
||||
if (info->invflags & EBT_IP6_PROTO)
|
||||
return -EINVAL;
|
||||
if (info->protocol != IPPROTO_TCP &&
|
||||
info->protocol != IPPROTO_UDP &&
|
||||
info->protocol != IPPROTO_UDPLITE &&
|
||||
info->protocol != IPPROTO_SCTP &&
|
||||
info->protocol != IPPROTO_DCCP)
|
||||
return -EINVAL;
|
||||
}
|
||||
if (info->bitmask & EBT_IP6_DPORT && info->dport[0] > info->dport[1])
|
||||
return -EINVAL;
|
||||
if (info->bitmask & EBT_IP6_SPORT && info->sport[0] > info->sport[1])
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ebt_match filter_ip6 =
|
||||
{
|
||||
.name = EBT_IP6_MATCH,
|
||||
.match = ebt_filter_ip6,
|
||||
.check = ebt_ip6_check,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init ebt_ip6_init(void)
|
||||
{
|
||||
return ebt_register_match(&filter_ip6);
|
||||
}
|
||||
|
||||
static void __exit ebt_ip6_fini(void)
|
||||
{
|
||||
ebt_unregister_match(&filter_ip6);
|
||||
}
|
||||
|
||||
module_init(ebt_ip6_init);
|
||||
module_exit(ebt_ip6_fini);
|
||||
MODULE_DESCRIPTION("Ebtables: IPv6 protocol packet match");
|
||||
MODULE_LICENSE("GPL");
|
@ -18,6 +18,9 @@
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <net/netfilter/nf_log.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <linux/in6.h>
|
||||
|
||||
static DEFINE_SPINLOCK(ebt_log_lock);
|
||||
|
||||
@ -58,6 +61,27 @@ static void print_MAC(const unsigned char *p)
|
||||
printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':');
|
||||
}
|
||||
|
||||
static void
|
||||
print_ports(const struct sk_buff *skb, uint8_t protocol, int offset)
|
||||
{
|
||||
if (protocol == IPPROTO_TCP ||
|
||||
protocol == IPPROTO_UDP ||
|
||||
protocol == IPPROTO_UDPLITE ||
|
||||
protocol == IPPROTO_SCTP ||
|
||||
protocol == IPPROTO_DCCP) {
|
||||
const struct tcpudphdr *pptr;
|
||||
struct tcpudphdr _ports;
|
||||
|
||||
pptr = skb_header_pointer(skb, offset,
|
||||
sizeof(_ports), &_ports);
|
||||
if (pptr == NULL) {
|
||||
printk(" INCOMPLETE TCP/UDP header");
|
||||
return;
|
||||
}
|
||||
printk(" SPT=%u DPT=%u", ntohs(pptr->src), ntohs(pptr->dst));
|
||||
}
|
||||
}
|
||||
|
||||
#define myNIPQUAD(a) a[0], a[1], a[2], a[3]
|
||||
static void
|
||||
ebt_log_packet(unsigned int pf, unsigned int hooknum,
|
||||
@ -95,23 +119,31 @@ ebt_log_packet(unsigned int pf, unsigned int hooknum,
|
||||
printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u, IP "
|
||||
"tos=0x%02X, IP proto=%d", NIPQUAD(ih->saddr),
|
||||
NIPQUAD(ih->daddr), ih->tos, ih->protocol);
|
||||
if (ih->protocol == IPPROTO_TCP ||
|
||||
ih->protocol == IPPROTO_UDP ||
|
||||
ih->protocol == IPPROTO_UDPLITE ||
|
||||
ih->protocol == IPPROTO_SCTP ||
|
||||
ih->protocol == IPPROTO_DCCP) {
|
||||
const struct tcpudphdr *pptr;
|
||||
struct tcpudphdr _ports;
|
||||
print_ports(skb, ih->protocol, ih->ihl*4);
|
||||
goto out;
|
||||
}
|
||||
|
||||
pptr = skb_header_pointer(skb, ih->ihl*4,
|
||||
sizeof(_ports), &_ports);
|
||||
if (pptr == NULL) {
|
||||
printk(" INCOMPLETE TCP/UDP header");
|
||||
goto out;
|
||||
}
|
||||
printk(" SPT=%u DPT=%u", ntohs(pptr->src),
|
||||
ntohs(pptr->dst));
|
||||
if ((bitmask & EBT_LOG_IP6) && eth_hdr(skb)->h_proto ==
|
||||
htons(ETH_P_IPV6)) {
|
||||
const struct ipv6hdr *ih;
|
||||
struct ipv6hdr _iph;
|
||||
uint8_t nexthdr;
|
||||
int offset_ph;
|
||||
|
||||
ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
|
||||
if (ih == NULL) {
|
||||
printk(" INCOMPLETE IPv6 header");
|
||||
goto out;
|
||||
}
|
||||
printk(" IPv6 SRC=%x:%x:%x:%x:%x:%x:%x:%x "
|
||||
"IPv6 DST=%x:%x:%x:%x:%x:%x:%x:%x, IPv6 "
|
||||
"priority=0x%01X, Next Header=%d", NIP6(ih->saddr),
|
||||
NIP6(ih->daddr), ih->priority, ih->nexthdr);
|
||||
nexthdr = ih->nexthdr;
|
||||
offset_ph = ipv6_skip_exthdr(skb, sizeof(_iph), &nexthdr);
|
||||
if (offset_ph == -1)
|
||||
goto out;
|
||||
print_ports(skb, nexthdr, offset_ph);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user