11da177e4SLinus Torvalds /* ipv6header match - matches IPv6 packets based 21da177e4SLinus Torvalds on whether they contain certain headers */ 31da177e4SLinus Torvalds 41da177e4SLinus Torvalds /* Original idea: Brad Chapman 51da177e4SLinus Torvalds * Rewritten by: Andras Kis-Szabo <kisza@sch.bme.hu> */ 61da177e4SLinus Torvalds 71da177e4SLinus Torvalds /* (C) 2001-2002 Andras Kis-Szabo <kisza@sch.bme.hu> 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 101da177e4SLinus Torvalds * it under the terms of the GNU General Public License version 2 as 111da177e4SLinus Torvalds * published by the Free Software Foundation. 121da177e4SLinus Torvalds */ 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds #include <linux/module.h> 151da177e4SLinus Torvalds #include <linux/skbuff.h> 161da177e4SLinus Torvalds #include <linux/ipv6.h> 171da177e4SLinus Torvalds #include <linux/types.h> 181da177e4SLinus Torvalds #include <net/checksum.h> 191da177e4SLinus Torvalds #include <net/ipv6.h> 201da177e4SLinus Torvalds 216709dbbbSJan Engelhardt #include <linux/netfilter/x_tables.h> 221da177e4SLinus Torvalds #include <linux/netfilter_ipv6/ip6_tables.h> 231da177e4SLinus Torvalds #include <linux/netfilter_ipv6/ip6t_ipv6header.h> 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 262ae15b64SJan Engelhardt MODULE_DESCRIPTION("Xtables: IPv6 header types match"); 271da177e4SLinus Torvalds MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); 281da177e4SLinus Torvalds 291d93a9cbSJan Engelhardt static bool 3062fc8051SJan Engelhardt ipv6header_mt6(const struct sk_buff *skb, struct xt_action_param *par) 311da177e4SLinus Torvalds { 32f7108a20SJan Engelhardt const struct ip6t_ipv6header_info *info = par->matchinfo; 331da177e4SLinus Torvalds unsigned int temp; 341da177e4SLinus Torvalds int len; 351da177e4SLinus Torvalds u8 nexthdr; 361da177e4SLinus Torvalds unsigned int ptr; 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds /* Make sure this isn't an evil packet */ 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds /* type of the 1st exthdr */ 410660e03fSArnaldo Carvalho de Melo nexthdr = ipv6_hdr(skb)->nexthdr; 421da177e4SLinus Torvalds /* pointer to the 1st exthdr */ 431da177e4SLinus Torvalds ptr = sizeof(struct ipv6hdr); 441da177e4SLinus Torvalds /* available length */ 451da177e4SLinus Torvalds len = skb->len - ptr; 461da177e4SLinus Torvalds temp = 0; 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds while (ip6t_ext_hdr(nexthdr)) { 493cf93c96SJan Engelhardt const struct ipv6_opt_hdr *hp; 503cf93c96SJan Engelhardt struct ipv6_opt_hdr _hdr; 511da177e4SLinus Torvalds int hdrlen; 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds /* No more exthdr -> evaluate */ 541da177e4SLinus Torvalds if (nexthdr == NEXTHDR_NONE) { 551da177e4SLinus Torvalds temp |= MASK_NONE; 561da177e4SLinus Torvalds break; 571da177e4SLinus Torvalds } 58b98b4947SChristoph Paasch /* Is there enough space for the next ext header? */ 59b98b4947SChristoph Paasch if (len < (int)sizeof(struct ipv6_opt_hdr)) 60b98b4947SChristoph Paasch return false; 611da177e4SLinus Torvalds /* ESP -> evaluate */ 621da177e4SLinus Torvalds if (nexthdr == NEXTHDR_ESP) { 631da177e4SLinus Torvalds temp |= MASK_ESP; 641da177e4SLinus Torvalds break; 651da177e4SLinus Torvalds } 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); 681da177e4SLinus Torvalds BUG_ON(hp == NULL); 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds /* Calculate the header length */ 717c4e36bcSJan Engelhardt if (nexthdr == NEXTHDR_FRAGMENT) 721da177e4SLinus Torvalds hdrlen = 8; 737c4e36bcSJan Engelhardt else if (nexthdr == NEXTHDR_AUTH) 741da177e4SLinus Torvalds hdrlen = (hp->hdrlen + 2) << 2; 751da177e4SLinus Torvalds else 761da177e4SLinus Torvalds hdrlen = ipv6_optlen(hp); 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds /* set the flag */ 791da177e4SLinus Torvalds switch (nexthdr) { 801da177e4SLinus Torvalds case NEXTHDR_HOP: 811da177e4SLinus Torvalds temp |= MASK_HOPOPTS; 821da177e4SLinus Torvalds break; 831da177e4SLinus Torvalds case NEXTHDR_ROUTING: 841da177e4SLinus Torvalds temp |= MASK_ROUTING; 851da177e4SLinus Torvalds break; 861da177e4SLinus Torvalds case NEXTHDR_FRAGMENT: 871da177e4SLinus Torvalds temp |= MASK_FRAGMENT; 881da177e4SLinus Torvalds break; 891da177e4SLinus Torvalds case NEXTHDR_AUTH: 901da177e4SLinus Torvalds temp |= MASK_AH; 911da177e4SLinus Torvalds break; 921da177e4SLinus Torvalds case NEXTHDR_DEST: 931da177e4SLinus Torvalds temp |= MASK_DSTOPTS; 941da177e4SLinus Torvalds break; 951da177e4SLinus Torvalds default: 961d93a9cbSJan Engelhardt return false; 971da177e4SLinus Torvalds break; 981da177e4SLinus Torvalds } 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds nexthdr = hp->nexthdr; 1011da177e4SLinus Torvalds len -= hdrlen; 1021da177e4SLinus Torvalds ptr += hdrlen; 1031da177e4SLinus Torvalds if (ptr > skb->len) 1041da177e4SLinus Torvalds break; 1051da177e4SLinus Torvalds } 1061da177e4SLinus Torvalds 1077c4e36bcSJan Engelhardt if (nexthdr != NEXTHDR_NONE && nexthdr != NEXTHDR_ESP) 1081da177e4SLinus Torvalds temp |= MASK_PROTO; 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds if (info->modeflag) 1111da177e4SLinus Torvalds return !((temp ^ info->matchflags ^ info->invflags) 1121da177e4SLinus Torvalds & info->matchflags); 1131da177e4SLinus Torvalds else { 1141da177e4SLinus Torvalds if (info->invflags) 1151da177e4SLinus Torvalds return temp != info->matchflags; 1161da177e4SLinus Torvalds else 1171da177e4SLinus Torvalds return temp == info->matchflags; 1181da177e4SLinus Torvalds } 1191da177e4SLinus Torvalds } 1201da177e4SLinus Torvalds 121b0f38452SJan Engelhardt static int ipv6header_mt6_check(const struct xt_mtchk_param *par) 1221da177e4SLinus Torvalds { 1239b4fce7aSJan Engelhardt const struct ip6t_ipv6header_info *info = par->matchinfo; 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds /* invflags is 0 or 0xff in hard mode */ 126f0daaa65SYasuyuki Kozakai if ((!info->modeflag) && info->invflags != 0x00 && 127f0daaa65SYasuyuki Kozakai info->invflags != 0xFF) 128bd414ee6SJan Engelhardt return -EINVAL; 1291da177e4SLinus Torvalds 130bd414ee6SJan Engelhardt return 0; 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds 133d3c5ee6dSJan Engelhardt static struct xt_match ipv6header_mt6_reg __read_mostly = { 1341da177e4SLinus Torvalds .name = "ipv6header", 135ee999d8bSJan Engelhardt .family = NFPROTO_IPV6, 136d3c5ee6dSJan Engelhardt .match = ipv6header_mt6, 1377f939713SPatrick McHardy .matchsize = sizeof(struct ip6t_ipv6header_info), 138d3c5ee6dSJan Engelhardt .checkentry = ipv6header_mt6_check, 1391da177e4SLinus Torvalds .destroy = NULL, 1401da177e4SLinus Torvalds .me = THIS_MODULE, 1411da177e4SLinus Torvalds }; 1421da177e4SLinus Torvalds 143d3c5ee6dSJan Engelhardt static int __init ipv6header_mt6_init(void) 1441da177e4SLinus Torvalds { 145d3c5ee6dSJan Engelhardt return xt_register_match(&ipv6header_mt6_reg); 1461da177e4SLinus Torvalds } 1471da177e4SLinus Torvalds 148d3c5ee6dSJan Engelhardt static void __exit ipv6header_mt6_exit(void) 1491da177e4SLinus Torvalds { 150d3c5ee6dSJan Engelhardt xt_unregister_match(&ipv6header_mt6_reg); 1511da177e4SLinus Torvalds } 1521da177e4SLinus Torvalds 153d3c5ee6dSJan Engelhardt module_init(ipv6header_mt6_init); 154d3c5ee6dSJan Engelhardt module_exit(ipv6header_mt6_exit); 155