0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <linux/ipv6.h>
0018 #include <net/ipv6.h>
0019 #include <linux/in.h>
0020 #include <linux/module.h>
0021 #include <net/dsfield.h>
0022 #include <linux/netfilter/x_tables.h>
0023 #include <linux/netfilter_bridge/ebtables.h>
0024 #include <linux/netfilter_bridge/ebt_ip6.h>
0025
0026 union pkthdr {
0027 struct {
0028 __be16 src;
0029 __be16 dst;
0030 } tcpudphdr;
0031 struct {
0032 u8 type;
0033 u8 code;
0034 } icmphdr;
0035 };
0036
0037 static bool
0038 ebt_ip6_mt(const struct sk_buff *skb, struct xt_action_param *par)
0039 {
0040 const struct ebt_ip6_info *info = par->matchinfo;
0041 const struct ipv6hdr *ih6;
0042 struct ipv6hdr _ip6h;
0043 const union pkthdr *pptr;
0044 union pkthdr _pkthdr;
0045
0046 ih6 = skb_header_pointer(skb, 0, sizeof(_ip6h), &_ip6h);
0047 if (ih6 == NULL)
0048 return false;
0049 if ((info->bitmask & EBT_IP6_TCLASS) &&
0050 NF_INVF(info, EBT_IP6_TCLASS,
0051 info->tclass != ipv6_get_dsfield(ih6)))
0052 return false;
0053 if (((info->bitmask & EBT_IP6_SOURCE) &&
0054 NF_INVF(info, EBT_IP6_SOURCE,
0055 ipv6_masked_addr_cmp(&ih6->saddr, &info->smsk,
0056 &info->saddr))) ||
0057 ((info->bitmask & EBT_IP6_DEST) &&
0058 NF_INVF(info, EBT_IP6_DEST,
0059 ipv6_masked_addr_cmp(&ih6->daddr, &info->dmsk,
0060 &info->daddr))))
0061 return false;
0062 if (info->bitmask & EBT_IP6_PROTO) {
0063 uint8_t nexthdr = ih6->nexthdr;
0064 __be16 frag_off;
0065 int offset_ph;
0066
0067 offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr, &frag_off);
0068 if (offset_ph == -1)
0069 return false;
0070 if (NF_INVF(info, EBT_IP6_PROTO, info->protocol != nexthdr))
0071 return false;
0072 if (!(info->bitmask & (EBT_IP6_DPORT |
0073 EBT_IP6_SPORT | EBT_IP6_ICMP6)))
0074 return true;
0075
0076
0077 pptr = skb_header_pointer(skb, offset_ph, sizeof(_pkthdr),
0078 &_pkthdr);
0079 if (pptr == NULL)
0080 return false;
0081 if (info->bitmask & EBT_IP6_DPORT) {
0082 u16 dst = ntohs(pptr->tcpudphdr.dst);
0083 if (NF_INVF(info, EBT_IP6_DPORT,
0084 dst < info->dport[0] ||
0085 dst > info->dport[1]))
0086 return false;
0087 }
0088 if (info->bitmask & EBT_IP6_SPORT) {
0089 u16 src = ntohs(pptr->tcpudphdr.src);
0090 if (NF_INVF(info, EBT_IP6_SPORT,
0091 src < info->sport[0] ||
0092 src > info->sport[1]))
0093 return false;
0094 }
0095 if ((info->bitmask & EBT_IP6_ICMP6) &&
0096 NF_INVF(info, EBT_IP6_ICMP6,
0097 pptr->icmphdr.type < info->icmpv6_type[0] ||
0098 pptr->icmphdr.type > info->icmpv6_type[1] ||
0099 pptr->icmphdr.code < info->icmpv6_code[0] ||
0100 pptr->icmphdr.code > info->icmpv6_code[1]))
0101 return false;
0102 }
0103 return true;
0104 }
0105
0106 static int ebt_ip6_mt_check(const struct xt_mtchk_param *par)
0107 {
0108 const struct ebt_entry *e = par->entryinfo;
0109 struct ebt_ip6_info *info = par->matchinfo;
0110
0111 if (e->ethproto != htons(ETH_P_IPV6) || e->invflags & EBT_IPROTO)
0112 return -EINVAL;
0113 if (info->bitmask & ~EBT_IP6_MASK || info->invflags & ~EBT_IP6_MASK)
0114 return -EINVAL;
0115 if (info->bitmask & (EBT_IP6_DPORT | EBT_IP6_SPORT)) {
0116 if (info->invflags & EBT_IP6_PROTO)
0117 return -EINVAL;
0118 if (info->protocol != IPPROTO_TCP &&
0119 info->protocol != IPPROTO_UDP &&
0120 info->protocol != IPPROTO_UDPLITE &&
0121 info->protocol != IPPROTO_SCTP &&
0122 info->protocol != IPPROTO_DCCP)
0123 return -EINVAL;
0124 }
0125 if (info->bitmask & EBT_IP6_DPORT && info->dport[0] > info->dport[1])
0126 return -EINVAL;
0127 if (info->bitmask & EBT_IP6_SPORT && info->sport[0] > info->sport[1])
0128 return -EINVAL;
0129 if (info->bitmask & EBT_IP6_ICMP6) {
0130 if ((info->invflags & EBT_IP6_PROTO) ||
0131 info->protocol != IPPROTO_ICMPV6)
0132 return -EINVAL;
0133 if (info->icmpv6_type[0] > info->icmpv6_type[1] ||
0134 info->icmpv6_code[0] > info->icmpv6_code[1])
0135 return -EINVAL;
0136 }
0137 return 0;
0138 }
0139
0140 static struct xt_match ebt_ip6_mt_reg __read_mostly = {
0141 .name = "ip6",
0142 .revision = 0,
0143 .family = NFPROTO_BRIDGE,
0144 .match = ebt_ip6_mt,
0145 .checkentry = ebt_ip6_mt_check,
0146 .matchsize = sizeof(struct ebt_ip6_info),
0147 .me = THIS_MODULE,
0148 };
0149
0150 static int __init ebt_ip6_init(void)
0151 {
0152 return xt_register_match(&ebt_ip6_mt_reg);
0153 }
0154
0155 static void __exit ebt_ip6_fini(void)
0156 {
0157 xt_unregister_match(&ebt_ip6_mt_reg);
0158 }
0159
0160 module_init(ebt_ip6_init);
0161 module_exit(ebt_ip6_fini);
0162 MODULE_DESCRIPTION("Ebtables: IPv6 protocol packet match");
0163 MODULE_AUTHOR("Kuo-Lang Tseng <kuo-lang.tseng@intel.com>");
0164 MODULE_LICENSE("GPL");