Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* Kernel module to match AH parameters. */ |
| 2 | |
| 3 | /* (C) 2001-2002 Andras Kis-Szabo <kisza@sch.bme.hu> |
| 4 | * |
| 5 | * This program is free software; you can redistribute it and/or modify |
| 6 | * it under the terms of the GNU General Public License version 2 as |
| 7 | * published by the Free Software Foundation. |
| 8 | */ |
Jan Engelhardt | ff67e4e | 2010-03-19 21:08:16 +0100 | [diff] [blame] | 9 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 10 | #include <linux/module.h> |
| 11 | #include <linux/skbuff.h> |
Arnaldo Carvalho de Melo | 14c8502 | 2005-12-27 02:43:12 -0200 | [diff] [blame] | 12 | #include <linux/ip.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 13 | #include <linux/ipv6.h> |
| 14 | #include <linux/types.h> |
| 15 | #include <net/checksum.h> |
| 16 | #include <net/ipv6.h> |
| 17 | |
Jan Engelhardt | 6709dbb | 2007-02-07 15:11:19 -0800 | [diff] [blame] | 18 | #include <linux/netfilter/x_tables.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 19 | #include <linux/netfilter_ipv6/ip6_tables.h> |
| 20 | #include <linux/netfilter_ipv6/ip6t_ah.h> |
| 21 | |
| 22 | MODULE_LICENSE("GPL"); |
Jan Engelhardt | 2ae15b6 | 2008-01-14 23:42:28 -0800 | [diff] [blame] | 23 | MODULE_DESCRIPTION("Xtables: IPv6 IPsec-AH match"); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 24 | MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); |
| 25 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 26 | /* Returns 1 if the spi is matched by the range, 0 otherwise */ |
Jan Engelhardt | 1d93a9c | 2007-07-07 22:15:35 -0700 | [diff] [blame] | 27 | static inline bool |
| 28 | spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, bool invert) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 29 | { |
Jan Engelhardt | 1d93a9c | 2007-07-07 22:15:35 -0700 | [diff] [blame] | 30 | bool r; |
Patrick McHardy | 0d53778 | 2007-07-07 22:39:38 -0700 | [diff] [blame] | 31 | |
Jan Engelhardt | ff67e4e | 2010-03-19 21:08:16 +0100 | [diff] [blame] | 32 | pr_debug("spi_match:%c 0x%x <= 0x%x <= 0x%x\n", |
Patrick McHardy | 0d53778 | 2007-07-07 22:39:38 -0700 | [diff] [blame] | 33 | invert ? '!' : ' ', min, spi, max); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 34 | r = (spi >= min && spi <= max) ^ invert; |
Patrick McHardy | 0d53778 | 2007-07-07 22:39:38 -0700 | [diff] [blame] | 35 | pr_debug(" result %s\n", r ? "PASS" : "FAILED"); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 36 | return r; |
| 37 | } |
| 38 | |
Jan Engelhardt | 62fc805 | 2009-07-07 20:42:08 +0200 | [diff] [blame] | 39 | static bool ah_mt6(const struct sk_buff *skb, struct xt_action_param *par) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 40 | { |
Jan Engelhardt | a47362a | 2007-07-07 22:16:55 -0700 | [diff] [blame] | 41 | struct ip_auth_hdr _ah; |
| 42 | const struct ip_auth_hdr *ah; |
Jan Engelhardt | f7108a2 | 2008-10-08 11:35:18 +0200 | [diff] [blame] | 43 | const struct ip6t_ah *ahinfo = par->matchinfo; |
Hans Schillstrom | 84018f5 | 2012-04-23 03:35:26 +0000 | [diff] [blame] | 44 | unsigned int ptr = 0; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 45 | unsigned int hdrlen = 0; |
Patrick McHardy | 6d38163 | 2006-10-24 16:15:10 -0700 | [diff] [blame] | 46 | int err; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 47 | |
Hans Schillstrom | 84018f5 | 2012-04-23 03:35:26 +0000 | [diff] [blame] | 48 | err = ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH, NULL, NULL); |
Patrick McHardy | 6d38163 | 2006-10-24 16:15:10 -0700 | [diff] [blame] | 49 | if (err < 0) { |
| 50 | if (err != -ENOENT) |
Jan Engelhardt | b4ba261 | 2009-07-07 20:54:30 +0200 | [diff] [blame] | 51 | par->hotdrop = true; |
Jan Engelhardt | 1d93a9c | 2007-07-07 22:15:35 -0700 | [diff] [blame] | 52 | return false; |
Patrick McHardy | 6d38163 | 2006-10-24 16:15:10 -0700 | [diff] [blame] | 53 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 54 | |
Yasuyuki Kozakai | e674d0f | 2005-09-19 15:34:40 -0700 | [diff] [blame] | 55 | ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah); |
| 56 | if (ah == NULL) { |
Jan Engelhardt | b4ba261 | 2009-07-07 20:54:30 +0200 | [diff] [blame] | 57 | par->hotdrop = true; |
Jan Engelhardt | 1d93a9c | 2007-07-07 22:15:35 -0700 | [diff] [blame] | 58 | return false; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 59 | } |
| 60 | |
Yasuyuki Kozakai | e674d0f | 2005-09-19 15:34:40 -0700 | [diff] [blame] | 61 | hdrlen = (ah->hdrlen + 2) << 2; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 62 | |
Patrick McHardy | 0d53778 | 2007-07-07 22:39:38 -0700 | [diff] [blame] | 63 | pr_debug("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen); |
| 64 | pr_debug("RES %04X ", ah->reserved); |
| 65 | pr_debug("SPI %u %08X\n", ntohl(ah->spi), ntohl(ah->spi)); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 66 | |
Patrick McHardy | 0d53778 | 2007-07-07 22:39:38 -0700 | [diff] [blame] | 67 | pr_debug("IPv6 AH spi %02X ", |
| 68 | spi_match(ahinfo->spis[0], ahinfo->spis[1], |
| 69 | ntohl(ah->spi), |
| 70 | !!(ahinfo->invflags & IP6T_AH_INV_SPI))); |
| 71 | pr_debug("len %02X %04X %02X ", |
| 72 | ahinfo->hdrlen, hdrlen, |
| 73 | (!ahinfo->hdrlen || |
| 74 | (ahinfo->hdrlen == hdrlen) ^ |
| 75 | !!(ahinfo->invflags & IP6T_AH_INV_LEN))); |
| 76 | pr_debug("res %02X %04X %02X\n", |
| 77 | ahinfo->hdrres, ah->reserved, |
| 78 | !(ahinfo->hdrres && ah->reserved)); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 79 | |
Joe Perches | 3666ed1 | 2009-11-23 23:17:06 +0100 | [diff] [blame] | 80 | return (ah != NULL) && |
| 81 | spi_match(ahinfo->spis[0], ahinfo->spis[1], |
| 82 | ntohl(ah->spi), |
| 83 | !!(ahinfo->invflags & IP6T_AH_INV_SPI)) && |
| 84 | (!ahinfo->hdrlen || |
| 85 | (ahinfo->hdrlen == hdrlen) ^ |
| 86 | !!(ahinfo->invflags & IP6T_AH_INV_LEN)) && |
| 87 | !(ahinfo->hdrres && ah->reserved); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 88 | } |
| 89 | |
Jan Engelhardt | b0f3845 | 2010-03-19 17:16:42 +0100 | [diff] [blame] | 90 | static int ah_mt6_check(const struct xt_mtchk_param *par) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 91 | { |
Jan Engelhardt | 9b4fce7 | 2008-10-08 11:35:18 +0200 | [diff] [blame] | 92 | const struct ip6t_ah *ahinfo = par->matchinfo; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 93 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 94 | if (ahinfo->invflags & ~IP6T_AH_INV_MASK) { |
Jan Engelhardt | ff67e4e | 2010-03-19 21:08:16 +0100 | [diff] [blame] | 95 | pr_debug("unknown flags %X\n", ahinfo->invflags); |
Jan Engelhardt | bd414ee | 2010-03-23 16:35:56 +0100 | [diff] [blame] | 96 | return -EINVAL; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 97 | } |
Jan Engelhardt | bd414ee | 2010-03-23 16:35:56 +0100 | [diff] [blame] | 98 | return 0; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 99 | } |
| 100 | |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 101 | static struct xt_match ah_mt6_reg __read_mostly = { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 102 | .name = "ah", |
Jan Engelhardt | ee999d8 | 2008-10-08 11:35:01 +0200 | [diff] [blame] | 103 | .family = NFPROTO_IPV6, |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 104 | .match = ah_mt6, |
Patrick McHardy | 7f93971 | 2006-03-20 18:01:43 -0800 | [diff] [blame] | 105 | .matchsize = sizeof(struct ip6t_ah), |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 106 | .checkentry = ah_mt6_check, |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 107 | .me = THIS_MODULE, |
| 108 | }; |
| 109 | |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 110 | static int __init ah_mt6_init(void) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 111 | { |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 112 | return xt_register_match(&ah_mt6_reg); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 113 | } |
| 114 | |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 115 | static void __exit ah_mt6_exit(void) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 116 | { |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 117 | xt_unregister_match(&ah_mt6_reg); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 118 | } |
| 119 | |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 120 | module_init(ah_mt6_init); |
| 121 | module_exit(ah_mt6_exit); |