Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 1 | /* |
| 2 | * ebt_ip6 |
| 3 | * |
| 4 | * Authors: |
| 5 | * Manohar Castelino <manohar.r.castelino@intel.com> |
| 6 | * Kuo-Lang Tseng <kuo-lang.tseng@intel.com> |
Jan Engelhardt | 408ffaa | 2010-02-28 23:19:52 +0100 | [diff] [blame] | 7 | * Jan Engelhardt <jengelh@medozas.de> |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 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 | */ |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 16 | #include <linux/ipv6.h> |
| 17 | #include <net/ipv6.h> |
| 18 | #include <linux/in.h> |
| 19 | #include <linux/module.h> |
| 20 | #include <net/dsfield.h> |
Jan Engelhardt | 18219d3 | 2008-10-08 11:35:13 +0200 | [diff] [blame] | 21 | #include <linux/netfilter/x_tables.h> |
| 22 | #include <linux/netfilter_bridge/ebtables.h> |
| 23 | #include <linux/netfilter_bridge/ebt_ip6.h> |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 24 | |
Florian Westphal | 6faee60 | 2010-12-20 15:57:47 +0100 | [diff] [blame] | 25 | union pkthdr { |
| 26 | struct { |
| 27 | __be16 src; |
| 28 | __be16 dst; |
| 29 | } tcpudphdr; |
| 30 | struct { |
| 31 | u8 type; |
| 32 | u8 code; |
| 33 | } icmphdr; |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 34 | }; |
| 35 | |
Jan Engelhardt | 2d06d4a | 2008-10-08 11:35:15 +0200 | [diff] [blame] | 36 | static bool |
Jan Engelhardt | 62fc805 | 2009-07-07 20:42:08 +0200 | [diff] [blame] | 37 | ebt_ip6_mt(const struct sk_buff *skb, struct xt_action_param *par) |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 38 | { |
Jan Engelhardt | f7108a2 | 2008-10-08 11:35:18 +0200 | [diff] [blame] | 39 | const struct ebt_ip6_info *info = par->matchinfo; |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 40 | const struct ipv6hdr *ih6; |
| 41 | struct ipv6hdr _ip6h; |
Florian Westphal | 6faee60 | 2010-12-20 15:57:47 +0100 | [diff] [blame] | 42 | const union pkthdr *pptr; |
| 43 | union pkthdr _pkthdr; |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 44 | |
| 45 | ih6 = skb_header_pointer(skb, 0, sizeof(_ip6h), &_ip6h); |
| 46 | if (ih6 == NULL) |
Jan Engelhardt | 8cc784e | 2008-10-08 11:35:13 +0200 | [diff] [blame] | 47 | return false; |
Joe Perches | c37a2df | 2016-06-24 13:25:22 -0700 | [diff] [blame] | 48 | if ((info->bitmask & EBT_IP6_TCLASS) && |
| 49 | NF_INVF(info, EBT_IP6_TCLASS, |
| 50 | info->tclass != ipv6_get_dsfield(ih6))) |
Jan Engelhardt | 8cc784e | 2008-10-08 11:35:13 +0200 | [diff] [blame] | 51 | return false; |
Joe Perches | c37a2df | 2016-06-24 13:25:22 -0700 | [diff] [blame] | 52 | if (((info->bitmask & EBT_IP6_SOURCE) && |
| 53 | NF_INVF(info, EBT_IP6_SOURCE, |
| 54 | ipv6_masked_addr_cmp(&ih6->saddr, &info->smsk, |
| 55 | &info->saddr))) || |
| 56 | ((info->bitmask & EBT_IP6_DEST) && |
| 57 | NF_INVF(info, EBT_IP6_DEST, |
| 58 | ipv6_masked_addr_cmp(&ih6->daddr, &info->dmsk, |
| 59 | &info->daddr)))) |
Jan Engelhardt | 8cc784e | 2008-10-08 11:35:13 +0200 | [diff] [blame] | 60 | return false; |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 61 | if (info->bitmask & EBT_IP6_PROTO) { |
| 62 | uint8_t nexthdr = ih6->nexthdr; |
Jesse Gross | 75f2811 | 2011-11-30 17:05:51 -0800 | [diff] [blame] | 63 | __be16 frag_off; |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 64 | int offset_ph; |
| 65 | |
Jesse Gross | 75f2811 | 2011-11-30 17:05:51 -0800 | [diff] [blame] | 66 | offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr, &frag_off); |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 67 | if (offset_ph == -1) |
Jan Engelhardt | 8cc784e | 2008-10-08 11:35:13 +0200 | [diff] [blame] | 68 | return false; |
Joe Perches | c37a2df | 2016-06-24 13:25:22 -0700 | [diff] [blame] | 69 | if (NF_INVF(info, EBT_IP6_PROTO, info->protocol != nexthdr)) |
Jan Engelhardt | 8cc784e | 2008-10-08 11:35:13 +0200 | [diff] [blame] | 70 | return false; |
Ian Morris | c1bc1d2 | 2015-10-26 09:10:43 +0000 | [diff] [blame] | 71 | if (!(info->bitmask & (EBT_IP6_DPORT | |
| 72 | EBT_IP6_SPORT | EBT_IP6_ICMP6))) |
Jan Engelhardt | 8cc784e | 2008-10-08 11:35:13 +0200 | [diff] [blame] | 73 | return true; |
Florian Westphal | 6faee60 | 2010-12-20 15:57:47 +0100 | [diff] [blame] | 74 | |
| 75 | /* min icmpv6 headersize is 4, so sizeof(_pkthdr) is ok. */ |
| 76 | pptr = skb_header_pointer(skb, offset_ph, sizeof(_pkthdr), |
| 77 | &_pkthdr); |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 78 | if (pptr == NULL) |
Jan Engelhardt | 8cc784e | 2008-10-08 11:35:13 +0200 | [diff] [blame] | 79 | return false; |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 80 | if (info->bitmask & EBT_IP6_DPORT) { |
Florian Westphal | 6faee60 | 2010-12-20 15:57:47 +0100 | [diff] [blame] | 81 | u16 dst = ntohs(pptr->tcpudphdr.dst); |
Joe Perches | c37a2df | 2016-06-24 13:25:22 -0700 | [diff] [blame] | 82 | if (NF_INVF(info, EBT_IP6_DPORT, |
| 83 | dst < info->dport[0] || |
| 84 | dst > info->dport[1])) |
Jan Engelhardt | 8cc784e | 2008-10-08 11:35:13 +0200 | [diff] [blame] | 85 | return false; |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 86 | } |
| 87 | if (info->bitmask & EBT_IP6_SPORT) { |
Florian Westphal | 6faee60 | 2010-12-20 15:57:47 +0100 | [diff] [blame] | 88 | u16 src = ntohs(pptr->tcpudphdr.src); |
Joe Perches | c37a2df | 2016-06-24 13:25:22 -0700 | [diff] [blame] | 89 | if (NF_INVF(info, EBT_IP6_SPORT, |
| 90 | src < info->sport[0] || |
| 91 | src > info->sport[1])) |
Jan Engelhardt | 8cc784e | 2008-10-08 11:35:13 +0200 | [diff] [blame] | 92 | return false; |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 93 | } |
Florian Westphal | 6faee60 | 2010-12-20 15:57:47 +0100 | [diff] [blame] | 94 | if ((info->bitmask & EBT_IP6_ICMP6) && |
Joe Perches | c37a2df | 2016-06-24 13:25:22 -0700 | [diff] [blame] | 95 | NF_INVF(info, EBT_IP6_ICMP6, |
| 96 | pptr->icmphdr.type < info->icmpv6_type[0] || |
| 97 | pptr->icmphdr.type > info->icmpv6_type[1] || |
| 98 | pptr->icmphdr.code < info->icmpv6_code[0] || |
| 99 | pptr->icmphdr.code > info->icmpv6_code[1])) |
Florian Westphal | 6faee60 | 2010-12-20 15:57:47 +0100 | [diff] [blame] | 100 | return false; |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 101 | } |
Jan Engelhardt | 8cc784e | 2008-10-08 11:35:13 +0200 | [diff] [blame] | 102 | return true; |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 103 | } |
| 104 | |
Jan Engelhardt | b0f3845 | 2010-03-19 17:16:42 +0100 | [diff] [blame] | 105 | static int ebt_ip6_mt_check(const struct xt_mtchk_param *par) |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 106 | { |
Jan Engelhardt | 9b4fce7 | 2008-10-08 11:35:18 +0200 | [diff] [blame] | 107 | const struct ebt_entry *e = par->entryinfo; |
| 108 | struct ebt_ip6_info *info = par->matchinfo; |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 109 | |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 110 | if (e->ethproto != htons(ETH_P_IPV6) || e->invflags & EBT_IPROTO) |
Jan Engelhardt | bd414ee | 2010-03-23 16:35:56 +0100 | [diff] [blame] | 111 | return -EINVAL; |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 112 | if (info->bitmask & ~EBT_IP6_MASK || info->invflags & ~EBT_IP6_MASK) |
Jan Engelhardt | bd414ee | 2010-03-23 16:35:56 +0100 | [diff] [blame] | 113 | return -EINVAL; |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 114 | if (info->bitmask & (EBT_IP6_DPORT | EBT_IP6_SPORT)) { |
| 115 | if (info->invflags & EBT_IP6_PROTO) |
Jan Engelhardt | bd414ee | 2010-03-23 16:35:56 +0100 | [diff] [blame] | 116 | return -EINVAL; |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 117 | if (info->protocol != IPPROTO_TCP && |
| 118 | info->protocol != IPPROTO_UDP && |
| 119 | info->protocol != IPPROTO_UDPLITE && |
| 120 | info->protocol != IPPROTO_SCTP && |
| 121 | info->protocol != IPPROTO_DCCP) |
Jan Engelhardt | bd414ee | 2010-03-23 16:35:56 +0100 | [diff] [blame] | 122 | return -EINVAL; |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 123 | } |
| 124 | if (info->bitmask & EBT_IP6_DPORT && info->dport[0] > info->dport[1]) |
Jan Engelhardt | bd414ee | 2010-03-23 16:35:56 +0100 | [diff] [blame] | 125 | return -EINVAL; |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 126 | if (info->bitmask & EBT_IP6_SPORT && info->sport[0] > info->sport[1]) |
Jan Engelhardt | bd414ee | 2010-03-23 16:35:56 +0100 | [diff] [blame] | 127 | return -EINVAL; |
Florian Westphal | 6faee60 | 2010-12-20 15:57:47 +0100 | [diff] [blame] | 128 | if (info->bitmask & EBT_IP6_ICMP6) { |
| 129 | if ((info->invflags & EBT_IP6_PROTO) || |
| 130 | info->protocol != IPPROTO_ICMPV6) |
| 131 | return -EINVAL; |
| 132 | if (info->icmpv6_type[0] > info->icmpv6_type[1] || |
| 133 | info->icmpv6_code[0] > info->icmpv6_code[1]) |
| 134 | return -EINVAL; |
| 135 | } |
Jan Engelhardt | bd414ee | 2010-03-23 16:35:56 +0100 | [diff] [blame] | 136 | return 0; |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 137 | } |
| 138 | |
Jan Engelhardt | 043ef46 | 2008-10-08 11:35:15 +0200 | [diff] [blame] | 139 | static struct xt_match ebt_ip6_mt_reg __read_mostly = { |
| 140 | .name = "ip6", |
Jan Engelhardt | 001a18d | 2008-10-08 11:35:14 +0200 | [diff] [blame] | 141 | .revision = 0, |
| 142 | .family = NFPROTO_BRIDGE, |
Jan Engelhardt | 2d06d4a | 2008-10-08 11:35:15 +0200 | [diff] [blame] | 143 | .match = ebt_ip6_mt, |
| 144 | .checkentry = ebt_ip6_mt_check, |
Florian Westphal | fc0e3df | 2010-02-15 18:16:26 +0100 | [diff] [blame] | 145 | .matchsize = sizeof(struct ebt_ip6_info), |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 146 | .me = THIS_MODULE, |
| 147 | }; |
| 148 | |
| 149 | static int __init ebt_ip6_init(void) |
| 150 | { |
Jan Engelhardt | 043ef46 | 2008-10-08 11:35:15 +0200 | [diff] [blame] | 151 | return xt_register_match(&ebt_ip6_mt_reg); |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 152 | } |
| 153 | |
| 154 | static void __exit ebt_ip6_fini(void) |
| 155 | { |
Jan Engelhardt | 043ef46 | 2008-10-08 11:35:15 +0200 | [diff] [blame] | 156 | xt_unregister_match(&ebt_ip6_mt_reg); |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 157 | } |
| 158 | |
| 159 | module_init(ebt_ip6_init); |
| 160 | module_exit(ebt_ip6_fini); |
| 161 | MODULE_DESCRIPTION("Ebtables: IPv6 protocol packet match"); |
Jan Engelhardt | 8244f4b | 2010-02-28 23:22:04 +0100 | [diff] [blame] | 162 | MODULE_AUTHOR("Kuo-Lang Tseng <kuo-lang.tseng@intel.com>"); |
Kuo-lang Tseng | 93f6515 | 2008-06-09 15:55:45 -0700 | [diff] [blame] | 163 | MODULE_LICENSE("GPL"); |