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@medozas.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 #include <linux/ipv6.h> 17 #include <net/ipv6.h> 18 #include <linux/in.h> 19 #include <linux/module.h> 20 #include <net/dsfield.h> 21 #include <linux/netfilter/x_tables.h> 22 #include <linux/netfilter_bridge/ebtables.h> 23 #include <linux/netfilter_bridge/ebt_ip6.h> 24 25 union pkthdr { 26 struct { 27 __be16 src; 28 __be16 dst; 29 } tcpudphdr; 30 struct { 31 u8 type; 32 u8 code; 33 } icmphdr; 34 }; 35 36 static bool 37 ebt_ip6_mt(const struct sk_buff *skb, struct xt_action_param *par) 38 { 39 const struct ebt_ip6_info *info = par->matchinfo; 40 const struct ipv6hdr *ih6; 41 struct ipv6hdr _ip6h; 42 const union pkthdr *pptr; 43 union pkthdr _pkthdr; 44 45 ih6 = skb_header_pointer(skb, 0, sizeof(_ip6h), &_ip6h); 46 if (ih6 == NULL) 47 return false; 48 if ((info->bitmask & EBT_IP6_TCLASS) && 49 NF_INVF(info, EBT_IP6_TCLASS, 50 info->tclass != ipv6_get_dsfield(ih6))) 51 return false; 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)))) 60 return false; 61 if (info->bitmask & EBT_IP6_PROTO) { 62 uint8_t nexthdr = ih6->nexthdr; 63 __be16 frag_off; 64 int offset_ph; 65 66 offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr, &frag_off); 67 if (offset_ph == -1) 68 return false; 69 if (NF_INVF(info, EBT_IP6_PROTO, info->protocol != nexthdr)) 70 return false; 71 if (!(info->bitmask & (EBT_IP6_DPORT | 72 EBT_IP6_SPORT | EBT_IP6_ICMP6))) 73 return true; 74 75 /* min icmpv6 headersize is 4, so sizeof(_pkthdr) is ok. */ 76 pptr = skb_header_pointer(skb, offset_ph, sizeof(_pkthdr), 77 &_pkthdr); 78 if (pptr == NULL) 79 return false; 80 if (info->bitmask & EBT_IP6_DPORT) { 81 u16 dst = ntohs(pptr->tcpudphdr.dst); 82 if (NF_INVF(info, EBT_IP6_DPORT, 83 dst < info->dport[0] || 84 dst > info->dport[1])) 85 return false; 86 } 87 if (info->bitmask & EBT_IP6_SPORT) { 88 u16 src = ntohs(pptr->tcpudphdr.src); 89 if (NF_INVF(info, EBT_IP6_SPORT, 90 src < info->sport[0] || 91 src > info->sport[1])) 92 return false; 93 } 94 if ((info->bitmask & EBT_IP6_ICMP6) && 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])) 100 return false; 101 } 102 return true; 103 } 104 105 static int ebt_ip6_mt_check(const struct xt_mtchk_param *par) 106 { 107 const struct ebt_entry *e = par->entryinfo; 108 struct ebt_ip6_info *info = par->matchinfo; 109 110 if (e->ethproto != htons(ETH_P_IPV6) || e->invflags & EBT_IPROTO) 111 return -EINVAL; 112 if (info->bitmask & ~EBT_IP6_MASK || info->invflags & ~EBT_IP6_MASK) 113 return -EINVAL; 114 if (info->bitmask & (EBT_IP6_DPORT | EBT_IP6_SPORT)) { 115 if (info->invflags & EBT_IP6_PROTO) 116 return -EINVAL; 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) 122 return -EINVAL; 123 } 124 if (info->bitmask & EBT_IP6_DPORT && info->dport[0] > info->dport[1]) 125 return -EINVAL; 126 if (info->bitmask & EBT_IP6_SPORT && info->sport[0] > info->sport[1]) 127 return -EINVAL; 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 } 136 return 0; 137 } 138 139 static struct xt_match ebt_ip6_mt_reg __read_mostly = { 140 .name = "ip6", 141 .revision = 0, 142 .family = NFPROTO_BRIDGE, 143 .match = ebt_ip6_mt, 144 .checkentry = ebt_ip6_mt_check, 145 .matchsize = sizeof(struct ebt_ip6_info), 146 .me = THIS_MODULE, 147 }; 148 149 static int __init ebt_ip6_init(void) 150 { 151 return xt_register_match(&ebt_ip6_mt_reg); 152 } 153 154 static void __exit ebt_ip6_fini(void) 155 { 156 xt_unregister_match(&ebt_ip6_mt_reg); 157 } 158 159 module_init(ebt_ip6_init); 160 module_exit(ebt_ip6_fini); 161 MODULE_DESCRIPTION("Ebtables: IPv6 protocol packet match"); 162 MODULE_AUTHOR("Kuo-Lang Tseng <kuo-lang.tseng@intel.com>"); 163 MODULE_LICENSE("GPL"); 164