ip6t_ipv6header.c (3416B)
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 22MODULE_LICENSE("GPL"); 23MODULE_DESCRIPTION("Xtables: IPv6 header types match"); 24MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); 25 26static bool 27ipv6header_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 120static 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 132static 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 142static int __init ipv6header_mt6_init(void) 143{ 144 return xt_register_match(&ipv6header_mt6_reg); 145} 146 147static void __exit ipv6header_mt6_exit(void) 148{ 149 xt_unregister_match(&ipv6header_mt6_reg); 150} 151 152module_init(ipv6header_mt6_init); 153module_exit(ipv6header_mt6_exit);