Skip to content

Commit 93f6515

Browse files
kltsengdavem330
authored andcommitted
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>
1 parent 469689a commit 93f6515

File tree

6 files changed

+244
-17
lines changed

6 files changed

+244
-17
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* ebt_ip6
3+
*
4+
* Authors:
5+
* Kuo-Lang Tseng <kuo-lang.tseng@intel.com>
6+
* Manohar Castelino <manohar.r.castelino@intel.com>
7+
*
8+
* Jan 11, 2008
9+
*
10+
*/
11+
12+
#ifndef __LINUX_BRIDGE_EBT_IP6_H
13+
#define __LINUX_BRIDGE_EBT_IP6_H
14+
15+
#define EBT_IP6_SOURCE 0x01
16+
#define EBT_IP6_DEST 0x02
17+
#define EBT_IP6_TCLASS 0x04
18+
#define EBT_IP6_PROTO 0x08
19+
#define EBT_IP6_SPORT 0x10
20+
#define EBT_IP6_DPORT 0x20
21+
#define EBT_IP6_MASK (EBT_IP6_SOURCE | EBT_IP6_DEST | EBT_IP6_TCLASS |\
22+
EBT_IP6_PROTO | EBT_IP6_SPORT | EBT_IP6_DPORT)
23+
#define EBT_IP6_MATCH "ip6"
24+
25+
/* the same values are used for the invflags */
26+
struct ebt_ip6_info
27+
{
28+
struct in6_addr saddr;
29+
struct in6_addr daddr;
30+
struct in6_addr smsk;
31+
struct in6_addr dmsk;
32+
uint8_t tclass;
33+
uint8_t protocol;
34+
uint8_t bitmask;
35+
uint8_t invflags;
36+
uint16_t sport[2];
37+
uint16_t dport[2];
38+
};
39+
40+
#endif

include/linux/netfilter_bridge/ebt_log.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
#define EBT_LOG_IP 0x01 /* if the frame is made by ip, log the ip information */
55
#define EBT_LOG_ARP 0x02
66
#define EBT_LOG_NFLOG 0x04
7-
#define EBT_LOG_MASK (EBT_LOG_IP | EBT_LOG_ARP)
7+
#define EBT_LOG_IP6 0x08
8+
#define EBT_LOG_MASK (EBT_LOG_IP | EBT_LOG_ARP | EBT_LOG_IP6)
89
#define EBT_LOG_PREFIX_SIZE 30
910
#define EBT_LOG_WATCHER "log"
1011

net/bridge/netfilter/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ config BRIDGE_EBT_IP
8383

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

86+
config BRIDGE_EBT_IP6
87+
tristate "ebt: IP6 filter support"
88+
depends on BRIDGE_NF_EBTABLES
89+
help
90+
This option adds the IP6 match, which allows basic IPV6 header field
91+
filtering.
92+
93+
To compile it as a module, choose M here. If unsure, say N.
94+
8695
config BRIDGE_EBT_LIMIT
8796
tristate "ebt: limit match support"
8897
depends on BRIDGE_NF_EBTABLES

net/bridge/netfilter/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ obj-$(CONFIG_BRIDGE_EBT_802_3) += ebt_802_3.o
1414
obj-$(CONFIG_BRIDGE_EBT_AMONG) += ebt_among.o
1515
obj-$(CONFIG_BRIDGE_EBT_ARP) += ebt_arp.o
1616
obj-$(CONFIG_BRIDGE_EBT_IP) += ebt_ip.o
17+
obj-$(CONFIG_BRIDGE_EBT_IP) += ebt_ip6.o
1718
obj-$(CONFIG_BRIDGE_EBT_LIMIT) += ebt_limit.o
1819
obj-$(CONFIG_BRIDGE_EBT_MARK) += ebt_mark_m.o
1920
obj-$(CONFIG_BRIDGE_EBT_PKTTYPE) += ebt_pkttype.o

net/bridge/netfilter/ebt_ip6.c

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/*
2+
* ebt_ip6
3+
*
4+
* Authors:
5+
* Manohar Castelino <manohar.r.castelino@intel.com>
6+
* Kuo-Lang Tseng <kuo-lang.tseng@intel.com>
7+
* Jan Engelhardt <jengelh@computergmbh.de>
8+
*
9+
* Summary:
10+
* This is just a modification of the IPv4 code written by
11+
* Bart De Schuymer <bdschuym@pandora.be>
12+
* with the changes required to support IPv6
13+
*
14+
* Jan, 2008
15+
*/
16+
17+
#include <linux/netfilter_bridge/ebtables.h>
18+
#include <linux/netfilter_bridge/ebt_ip6.h>
19+
#include <linux/ipv6.h>
20+
#include <net/ipv6.h>
21+
#include <linux/in.h>
22+
#include <linux/module.h>
23+
#include <net/dsfield.h>
24+
25+
struct tcpudphdr {
26+
__be16 src;
27+
__be16 dst;
28+
};
29+
30+
static int ebt_filter_ip6(const struct sk_buff *skb,
31+
const struct net_device *in,
32+
const struct net_device *out, const void *data,
33+
unsigned int datalen)
34+
{
35+
const struct ebt_ip6_info *info = (struct ebt_ip6_info *)data;
36+
const struct ipv6hdr *ih6;
37+
struct ipv6hdr _ip6h;
38+
const struct tcpudphdr *pptr;
39+
struct tcpudphdr _ports;
40+
struct in6_addr tmp_addr;
41+
int i;
42+
43+
ih6 = skb_header_pointer(skb, 0, sizeof(_ip6h), &_ip6h);
44+
if (ih6 == NULL)
45+
return EBT_NOMATCH;
46+
if (info->bitmask & EBT_IP6_TCLASS &&
47+
FWINV(info->tclass != ipv6_get_dsfield(ih6), EBT_IP6_TCLASS))
48+
return EBT_NOMATCH;
49+
for (i = 0; i < 4; i++)
50+
tmp_addr.in6_u.u6_addr32[i] = ih6->saddr.in6_u.u6_addr32[i] &
51+
info->smsk.in6_u.u6_addr32[i];
52+
if (info->bitmask & EBT_IP6_SOURCE &&
53+
FWINV((ipv6_addr_cmp(&tmp_addr, &info->saddr) != 0),
54+
EBT_IP6_SOURCE))
55+
return EBT_NOMATCH;
56+
for (i = 0; i < 4; i++)
57+
tmp_addr.in6_u.u6_addr32[i] = ih6->daddr.in6_u.u6_addr32[i] &
58+
info->dmsk.in6_u.u6_addr32[i];
59+
if (info->bitmask & EBT_IP6_DEST &&
60+
FWINV((ipv6_addr_cmp(&tmp_addr, &info->daddr) != 0), EBT_IP6_DEST))
61+
return EBT_NOMATCH;
62+
if (info->bitmask & EBT_IP6_PROTO) {
63+
uint8_t nexthdr = ih6->nexthdr;
64+
int offset_ph;
65+
66+
offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr);
67+
if (offset_ph == -1)
68+
return EBT_NOMATCH;
69+
if (FWINV(info->protocol != nexthdr, EBT_IP6_PROTO))
70+
return EBT_NOMATCH;
71+
if (!(info->bitmask & EBT_IP6_DPORT) &&
72+
!(info->bitmask & EBT_IP6_SPORT))
73+
return EBT_MATCH;
74+
pptr = skb_header_pointer(skb, offset_ph, sizeof(_ports),
75+
&_ports);
76+
if (pptr == NULL)
77+
return EBT_NOMATCH;
78+
if (info->bitmask & EBT_IP6_DPORT) {
79+
u32 dst = ntohs(pptr->dst);
80+
if (FWINV(dst < info->dport[0] ||
81+
dst > info->dport[1], EBT_IP6_DPORT))
82+
return EBT_NOMATCH;
83+
}
84+
if (info->bitmask & EBT_IP6_SPORT) {
85+
u32 src = ntohs(pptr->src);
86+
if (FWINV(src < info->sport[0] ||
87+
src > info->sport[1], EBT_IP6_SPORT))
88+
return EBT_NOMATCH;
89+
}
90+
return EBT_MATCH;
91+
}
92+
return EBT_MATCH;
93+
}
94+
95+
static int ebt_ip6_check(const char *tablename, unsigned int hookmask,
96+
const struct ebt_entry *e, void *data, unsigned int datalen)
97+
{
98+
struct ebt_ip6_info *info = (struct ebt_ip6_info *)data;
99+
100+
if (datalen != EBT_ALIGN(sizeof(struct ebt_ip6_info)))
101+
return -EINVAL;
102+
if (e->ethproto != htons(ETH_P_IPV6) || e->invflags & EBT_IPROTO)
103+
return -EINVAL;
104+
if (info->bitmask & ~EBT_IP6_MASK || info->invflags & ~EBT_IP6_MASK)
105+
return -EINVAL;
106+
if (info->bitmask & (EBT_IP6_DPORT | EBT_IP6_SPORT)) {
107+
if (info->invflags & EBT_IP6_PROTO)
108+
return -EINVAL;
109+
if (info->protocol != IPPROTO_TCP &&
110+
info->protocol != IPPROTO_UDP &&
111+
info->protocol != IPPROTO_UDPLITE &&
112+
info->protocol != IPPROTO_SCTP &&
113+
info->protocol != IPPROTO_DCCP)
114+
return -EINVAL;
115+
}
116+
if (info->bitmask & EBT_IP6_DPORT && info->dport[0] > info->dport[1])
117+
return -EINVAL;
118+
if (info->bitmask & EBT_IP6_SPORT && info->sport[0] > info->sport[1])
119+
return -EINVAL;
120+
return 0;
121+
}
122+
123+
static struct ebt_match filter_ip6 =
124+
{
125+
.name = EBT_IP6_MATCH,
126+
.match = ebt_filter_ip6,
127+
.check = ebt_ip6_check,
128+
.me = THIS_MODULE,
129+
};
130+
131+
static int __init ebt_ip6_init(void)
132+
{
133+
return ebt_register_match(&filter_ip6);
134+
}
135+
136+
static void __exit ebt_ip6_fini(void)
137+
{
138+
ebt_unregister_match(&filter_ip6);
139+
}
140+
141+
module_init(ebt_ip6_init);
142+
module_exit(ebt_ip6_fini);
143+
MODULE_DESCRIPTION("Ebtables: IPv6 protocol packet match");
144+
MODULE_LICENSE("GPL");

net/bridge/netfilter/ebt_log.c

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
#include <linux/if_arp.h>
1919
#include <linux/spinlock.h>
2020
#include <net/netfilter/nf_log.h>
21+
#include <linux/ipv6.h>
22+
#include <net/ipv6.h>
23+
#include <linux/in6.h>
2124

2225
static DEFINE_SPINLOCK(ebt_log_lock);
2326

@@ -58,6 +61,27 @@ static void print_MAC(const unsigned char *p)
5861
printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':');
5962
}
6063

64+
static void
65+
print_ports(const struct sk_buff *skb, uint8_t protocol, int offset)
66+
{
67+
if (protocol == IPPROTO_TCP ||
68+
protocol == IPPROTO_UDP ||
69+
protocol == IPPROTO_UDPLITE ||
70+
protocol == IPPROTO_SCTP ||
71+
protocol == IPPROTO_DCCP) {
72+
const struct tcpudphdr *pptr;
73+
struct tcpudphdr _ports;
74+
75+
pptr = skb_header_pointer(skb, offset,
76+
sizeof(_ports), &_ports);
77+
if (pptr == NULL) {
78+
printk(" INCOMPLETE TCP/UDP header");
79+
return;
80+
}
81+
printk(" SPT=%u DPT=%u", ntohs(pptr->src), ntohs(pptr->dst));
82+
}
83+
}
84+
6185
#define myNIPQUAD(a) a[0], a[1], a[2], a[3]
6286
static void
6387
ebt_log_packet(unsigned int pf, unsigned int hooknum,
@@ -95,23 +119,31 @@ ebt_log_packet(unsigned int pf, unsigned int hooknum,
95119
printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u, IP "
96120
"tos=0x%02X, IP proto=%d", NIPQUAD(ih->saddr),
97121
NIPQUAD(ih->daddr), ih->tos, ih->protocol);
98-
if (ih->protocol == IPPROTO_TCP ||
99-
ih->protocol == IPPROTO_UDP ||
100-
ih->protocol == IPPROTO_UDPLITE ||
101-
ih->protocol == IPPROTO_SCTP ||
102-
ih->protocol == IPPROTO_DCCP) {
103-
const struct tcpudphdr *pptr;
104-
struct tcpudphdr _ports;
105-
106-
pptr = skb_header_pointer(skb, ih->ihl*4,
107-
sizeof(_ports), &_ports);
108-
if (pptr == NULL) {
109-
printk(" INCOMPLETE TCP/UDP header");
110-
goto out;
111-
}
112-
printk(" SPT=%u DPT=%u", ntohs(pptr->src),
113-
ntohs(pptr->dst));
122+
print_ports(skb, ih->protocol, ih->ihl*4);
123+
goto out;
124+
}
125+
126+
if ((bitmask & EBT_LOG_IP6) && eth_hdr(skb)->h_proto ==
127+
htons(ETH_P_IPV6)) {
128+
const struct ipv6hdr *ih;
129+
struct ipv6hdr _iph;
130+
uint8_t nexthdr;
131+
int offset_ph;
132+
133+
ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
134+
if (ih == NULL) {
135+
printk(" INCOMPLETE IPv6 header");
136+
goto out;
114137
}
138+
printk(" IPv6 SRC=%x:%x:%x:%x:%x:%x:%x:%x "
139+
"IPv6 DST=%x:%x:%x:%x:%x:%x:%x:%x, IPv6 "
140+
"priority=0x%01X, Next Header=%d", NIP6(ih->saddr),
141+
NIP6(ih->daddr), ih->priority, ih->nexthdr);
142+
nexthdr = ih->nexthdr;
143+
offset_ph = ipv6_skip_exthdr(skb, sizeof(_iph), &nexthdr);
144+
if (offset_ph == -1)
145+
goto out;
146+
print_ports(skb, nexthdr, offset_ph);
115147
goto out;
116148
}
117149

0 commit comments

Comments
 (0)