ebt_ip6.c (4572B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * ebt_ip6 4 * 5 * Authors: 6 * Manohar Castelino <manohar.r.castelino@intel.com> 7 * Kuo-Lang Tseng <kuo-lang.tseng@intel.com> 8 * Jan Engelhardt <jengelh@medozas.de> 9 * 10 * Summary: 11 * This is just a modification of the IPv4 code written by 12 * Bart De Schuymer <bdschuym@pandora.be> 13 * with the changes required to support IPv6 14 * 15 * Jan, 2008 16 */ 17#include <linux/ipv6.h> 18#include <net/ipv6.h> 19#include <linux/in.h> 20#include <linux/module.h> 21#include <net/dsfield.h> 22#include <linux/netfilter/x_tables.h> 23#include <linux/netfilter_bridge/ebtables.h> 24#include <linux/netfilter_bridge/ebt_ip6.h> 25 26union pkthdr { 27 struct { 28 __be16 src; 29 __be16 dst; 30 } tcpudphdr; 31 struct { 32 u8 type; 33 u8 code; 34 } icmphdr; 35}; 36 37static bool 38ebt_ip6_mt(const struct sk_buff *skb, struct xt_action_param *par) 39{ 40 const struct ebt_ip6_info *info = par->matchinfo; 41 const struct ipv6hdr *ih6; 42 struct ipv6hdr _ip6h; 43 const union pkthdr *pptr; 44 union pkthdr _pkthdr; 45 46 ih6 = skb_header_pointer(skb, 0, sizeof(_ip6h), &_ip6h); 47 if (ih6 == NULL) 48 return false; 49 if ((info->bitmask & EBT_IP6_TCLASS) && 50 NF_INVF(info, EBT_IP6_TCLASS, 51 info->tclass != ipv6_get_dsfield(ih6))) 52 return false; 53 if (((info->bitmask & EBT_IP6_SOURCE) && 54 NF_INVF(info, EBT_IP6_SOURCE, 55 ipv6_masked_addr_cmp(&ih6->saddr, &info->smsk, 56 &info->saddr))) || 57 ((info->bitmask & EBT_IP6_DEST) && 58 NF_INVF(info, EBT_IP6_DEST, 59 ipv6_masked_addr_cmp(&ih6->daddr, &info->dmsk, 60 &info->daddr)))) 61 return false; 62 if (info->bitmask & EBT_IP6_PROTO) { 63 uint8_t nexthdr = ih6->nexthdr; 64 __be16 frag_off; 65 int offset_ph; 66 67 offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr, &frag_off); 68 if (offset_ph == -1) 69 return false; 70 if (NF_INVF(info, EBT_IP6_PROTO, info->protocol != nexthdr)) 71 return false; 72 if (!(info->bitmask & (EBT_IP6_DPORT | 73 EBT_IP6_SPORT | EBT_IP6_ICMP6))) 74 return true; 75 76 /* min icmpv6 headersize is 4, so sizeof(_pkthdr) is ok. */ 77 pptr = skb_header_pointer(skb, offset_ph, sizeof(_pkthdr), 78 &_pkthdr); 79 if (pptr == NULL) 80 return false; 81 if (info->bitmask & EBT_IP6_DPORT) { 82 u16 dst = ntohs(pptr->tcpudphdr.dst); 83 if (NF_INVF(info, EBT_IP6_DPORT, 84 dst < info->dport[0] || 85 dst > info->dport[1])) 86 return false; 87 } 88 if (info->bitmask & EBT_IP6_SPORT) { 89 u16 src = ntohs(pptr->tcpudphdr.src); 90 if (NF_INVF(info, EBT_IP6_SPORT, 91 src < info->sport[0] || 92 src > info->sport[1])) 93 return false; 94 } 95 if ((info->bitmask & EBT_IP6_ICMP6) && 96 NF_INVF(info, EBT_IP6_ICMP6, 97 pptr->icmphdr.type < info->icmpv6_type[0] || 98 pptr->icmphdr.type > info->icmpv6_type[1] || 99 pptr->icmphdr.code < info->icmpv6_code[0] || 100 pptr->icmphdr.code > info->icmpv6_code[1])) 101 return false; 102 } 103 return true; 104} 105 106static int ebt_ip6_mt_check(const struct xt_mtchk_param *par) 107{ 108 const struct ebt_entry *e = par->entryinfo; 109 struct ebt_ip6_info *info = par->matchinfo; 110 111 if (e->ethproto != htons(ETH_P_IPV6) || e->invflags & EBT_IPROTO) 112 return -EINVAL; 113 if (info->bitmask & ~EBT_IP6_MASK || info->invflags & ~EBT_IP6_MASK) 114 return -EINVAL; 115 if (info->bitmask & (EBT_IP6_DPORT | EBT_IP6_SPORT)) { 116 if (info->invflags & EBT_IP6_PROTO) 117 return -EINVAL; 118 if (info->protocol != IPPROTO_TCP && 119 info->protocol != IPPROTO_UDP && 120 info->protocol != IPPROTO_UDPLITE && 121 info->protocol != IPPROTO_SCTP && 122 info->protocol != IPPROTO_DCCP) 123 return -EINVAL; 124 } 125 if (info->bitmask & EBT_IP6_DPORT && info->dport[0] > info->dport[1]) 126 return -EINVAL; 127 if (info->bitmask & EBT_IP6_SPORT && info->sport[0] > info->sport[1]) 128 return -EINVAL; 129 if (info->bitmask & EBT_IP6_ICMP6) { 130 if ((info->invflags & EBT_IP6_PROTO) || 131 info->protocol != IPPROTO_ICMPV6) 132 return -EINVAL; 133 if (info->icmpv6_type[0] > info->icmpv6_type[1] || 134 info->icmpv6_code[0] > info->icmpv6_code[1]) 135 return -EINVAL; 136 } 137 return 0; 138} 139 140static struct xt_match ebt_ip6_mt_reg __read_mostly = { 141 .name = "ip6", 142 .revision = 0, 143 .family = NFPROTO_BRIDGE, 144 .match = ebt_ip6_mt, 145 .checkentry = ebt_ip6_mt_check, 146 .matchsize = sizeof(struct ebt_ip6_info), 147 .me = THIS_MODULE, 148}; 149 150static int __init ebt_ip6_init(void) 151{ 152 return xt_register_match(&ebt_ip6_mt_reg); 153} 154 155static void __exit ebt_ip6_fini(void) 156{ 157 xt_unregister_match(&ebt_ip6_mt_reg); 158} 159 160module_init(ebt_ip6_init); 161module_exit(ebt_ip6_fini); 162MODULE_DESCRIPTION("Ebtables: IPv6 protocol packet match"); 163MODULE_AUTHOR("Kuo-Lang Tseng <kuo-lang.tseng@intel.com>"); 164MODULE_LICENSE("GPL");