Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  ebt_ip6
0004  *
0005  *  Authors:
0006  *  Manohar Castelino <manohar.r.castelino@intel.com>
0007  *  Kuo-Lang Tseng <kuo-lang.tseng@intel.com>
0008  *  Jan Engelhardt <jengelh@medozas.de>
0009  *
0010  * Summary:
0011  * This is just a modification of the IPv4 code written by
0012  * Bart De Schuymer <bdschuym@pandora.be>
0013  * with the changes required to support IPv6
0014  *
0015  *  Jan, 2008
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         /* min icmpv6 headersize is 4, so sizeof(_pkthdr) is ok. */
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");