1 // SPDX-License-Identifier: GPL-2.0-only 2 /* ipv6header match - matches IPv6 packets based 3 on whether they contain certain headers */ 4 5 /* Original idea: Brad Chapman 6 * Rewritten by: Andras Kis-Szabo <kisza@sch.bme.hu> */ 7 8 /* (C) 2001-2002 Andras Kis-Szabo <kisza@sch.bme.hu> 9 */ 10 11 #include <linux/module.h> 12 #include <linux/skbuff.h> 13 #include <linux/ipv6.h> 14 #include <linux/types.h> 15 #include <net/checksum.h> 16 #include <net/ipv6.h> 17 18 #include <linux/netfilter/x_tables.h> 19 #include <linux/netfilter_ipv6.h> 20 #include <linux/netfilter_ipv6/ip6t_ipv6header.h> 21 22 MODULE_LICENSE("GPL"); 23 MODULE_DESCRIPTION("Xtables: IPv6 header types match"); 24 MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); 25 26 static bool 27 ipv6header_mt6(const struct sk_buff *skb, struct xt_action_param *par) 28 { 29 const struct ip6t_ipv6header_info *info = par->matchinfo; 30 unsigned int temp; 31 int len; 32 u8 nexthdr; 33 unsigned int ptr; 34 35 /* Make sure this isn't an evil packet */ 36 37 /* type of the 1st exthdr */ 38 nexthdr = ipv6_hdr(skb)->nexthdr; 39 /* pointer to the 1st exthdr */ 40 ptr = sizeof(struct ipv6hdr); 41 /* available length */ 42 len = skb->len - ptr; 43 temp = 0; 44 45 while (nf_ip6_ext_hdr(nexthdr)) { 46 const struct ipv6_opt_hdr *hp; 47 struct ipv6_opt_hdr _hdr; 48 int hdrlen; 49 50 /* No more exthdr -> evaluate */ 51 if (nexthdr == NEXTHDR_NONE) { 52 temp |= MASK_NONE; 53 break; 54 } 55 /* Is there enough space for the next ext header? */ 56 if (len < (int)sizeof(struct ipv6_opt_hdr)) 57 return false; 58 /* ESP -> evaluate */ 59 if (nexthdr == NEXTHDR_ESP) { 60 temp |= MASK_ESP; 61 break; 62 } 63 64 hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); 65 if (!hp) { 66 par->hotdrop = true; 67 return false; 68 } 69 70 /* Calculate the header length */ 71 if (nexthdr == NEXTHDR_FRAGMENT) 72 hdrlen = 8; 73 else if (nexthdr == NEXTHDR_AUTH) 74 hdrlen = ipv6_authlen(hp); 75 else 76 hdrlen = ipv6_optlen(hp); 77 78 /* set the flag */ 79 switch (nexthdr) { 80 case NEXTHDR_HOP: 81 temp |= MASK_HOPOPTS; 82 break; 83 case NEXTHDR_ROUTING: 84 temp |= MASK_ROUTING; 85 break; 86 case NEXTHDR_FRAGMENT: 87 temp |= MASK_FRAGMENT; 88 break; 89 case NEXTHDR_AUTH: 90 temp |= MASK_AH; 91 break; 92 case NEXTHDR_DEST: 93 temp |= MASK_DSTOPTS; 94 break; 95 default: 96 return false; 97 } 98 99 nexthdr = hp->nexthdr; 100 len -= hdrlen; 101 ptr += hdrlen; 102 if (ptr > skb->len) 103 break; 104 } 105 106 if (nexthdr != NEXTHDR_NONE && nexthdr != NEXTHDR_ESP) 107 temp |= MASK_PROTO; 108 109 if (info->modeflag) 110 return !((temp ^ info->matchflags ^ info->invflags) 111 & info->matchflags); 112 else { 113 if (info->invflags) 114 return temp != info->matchflags; 115 else 116 return temp == info->matchflags; 117 } 118 } 119 120 static int ipv6header_mt6_check(const struct xt_mtchk_param *par) 121 { 122 const struct ip6t_ipv6header_info *info = par->matchinfo; 123 124 /* invflags is 0 or 0xff in hard mode */ 125 if ((!info->modeflag) && info->invflags != 0x00 && 126 info->invflags != 0xFF) 127 return -EINVAL; 128 129 return 0; 130 } 131 132 static struct xt_match ipv6header_mt6_reg __read_mostly = { 133 .name = "ipv6header", 134 .family = NFPROTO_IPV6, 135 .match = ipv6header_mt6, 136 .matchsize = sizeof(struct ip6t_ipv6header_info), 137 .checkentry = ipv6header_mt6_check, 138 .destroy = NULL, 139 .me = THIS_MODULE, 140 }; 141 142 static int __init ipv6header_mt6_init(void) 143 { 144 return xt_register_match(&ipv6header_mt6_reg); 145 } 146 147 static void __exit ipv6header_mt6_exit(void) 148 { 149 xt_unregister_match(&ipv6header_mt6_reg); 150 } 151 152 module_init(ipv6header_mt6_init); 153 module_exit(ipv6header_mt6_exit); 154
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.