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 | */ |
| 9 | |
| 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"); |
| 23 | MODULE_DESCRIPTION("IPv6 AH match"); |
| 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 | |
| 32 | pr_debug("ah spi_match:%c 0x%x <= 0x%x <= 0x%x", |
| 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 | 1d93a9c | 2007-07-07 22:15:35 -0700 | [diff] [blame] | 39 | static bool |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 40 | match(const struct sk_buff *skb, |
| 41 | const struct net_device *in, |
| 42 | const struct net_device *out, |
Patrick McHardy | c498673 | 2006-03-20 18:02:56 -0800 | [diff] [blame] | 43 | const struct xt_match *match, |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 44 | const void *matchinfo, |
| 45 | int offset, |
| 46 | unsigned int protoff, |
Jan Engelhardt | cff533a | 2007-07-07 22:15:12 -0700 | [diff] [blame] | 47 | bool *hotdrop) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 48 | { |
Jan Engelhardt | a47362a | 2007-07-07 22:16:55 -0700 | [diff] [blame] | 49 | struct ip_auth_hdr _ah; |
| 50 | const struct ip_auth_hdr *ah; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 51 | const struct ip6t_ah *ahinfo = matchinfo; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 52 | unsigned int ptr; |
| 53 | unsigned int hdrlen = 0; |
Patrick McHardy | 6d38163 | 2006-10-24 16:15:10 -0700 | [diff] [blame] | 54 | int err; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 55 | |
Patrick McHardy | 6d38163 | 2006-10-24 16:15:10 -0700 | [diff] [blame] | 56 | err = ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH, NULL); |
| 57 | if (err < 0) { |
| 58 | if (err != -ENOENT) |
Jan Engelhardt | cff533a | 2007-07-07 22:15:12 -0700 | [diff] [blame] | 59 | *hotdrop = true; |
Jan Engelhardt | 1d93a9c | 2007-07-07 22:15:35 -0700 | [diff] [blame] | 60 | return false; |
Patrick McHardy | 6d38163 | 2006-10-24 16:15:10 -0700 | [diff] [blame] | 61 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 62 | |
Yasuyuki Kozakai | e674d0f | 2005-09-19 15:34:40 -0700 | [diff] [blame] | 63 | ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah); |
| 64 | if (ah == NULL) { |
Jan Engelhardt | cff533a | 2007-07-07 22:15:12 -0700 | [diff] [blame] | 65 | *hotdrop = true; |
Jan Engelhardt | 1d93a9c | 2007-07-07 22:15:35 -0700 | [diff] [blame] | 66 | return false; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 67 | } |
| 68 | |
Yasuyuki Kozakai | e674d0f | 2005-09-19 15:34:40 -0700 | [diff] [blame] | 69 | hdrlen = (ah->hdrlen + 2) << 2; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 70 | |
Patrick McHardy | 0d53778 | 2007-07-07 22:39:38 -0700 | [diff] [blame^] | 71 | pr_debug("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen); |
| 72 | pr_debug("RES %04X ", ah->reserved); |
| 73 | pr_debug("SPI %u %08X\n", ntohl(ah->spi), ntohl(ah->spi)); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 74 | |
Patrick McHardy | 0d53778 | 2007-07-07 22:39:38 -0700 | [diff] [blame^] | 75 | pr_debug("IPv6 AH spi %02X ", |
| 76 | spi_match(ahinfo->spis[0], ahinfo->spis[1], |
| 77 | ntohl(ah->spi), |
| 78 | !!(ahinfo->invflags & IP6T_AH_INV_SPI))); |
| 79 | pr_debug("len %02X %04X %02X ", |
| 80 | ahinfo->hdrlen, hdrlen, |
| 81 | (!ahinfo->hdrlen || |
| 82 | (ahinfo->hdrlen == hdrlen) ^ |
| 83 | !!(ahinfo->invflags & IP6T_AH_INV_LEN))); |
| 84 | pr_debug("res %02X %04X %02X\n", |
| 85 | ahinfo->hdrres, ah->reserved, |
| 86 | !(ahinfo->hdrres && ah->reserved)); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 87 | |
| 88 | return (ah != NULL) |
| 89 | && |
Jan Engelhardt | 7c4e36b | 2007-07-07 22:19:08 -0700 | [diff] [blame] | 90 | spi_match(ahinfo->spis[0], ahinfo->spis[1], |
| 91 | ntohl(ah->spi), |
| 92 | !!(ahinfo->invflags & IP6T_AH_INV_SPI)) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 93 | && |
| 94 | (!ahinfo->hdrlen || |
YOSHIFUJI Hideaki | 1ab1457 | 2007-02-09 23:24:49 +0900 | [diff] [blame] | 95 | (ahinfo->hdrlen == hdrlen) ^ |
| 96 | !!(ahinfo->invflags & IP6T_AH_INV_LEN)) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 97 | && |
| 98 | !(ahinfo->hdrres && ah->reserved); |
| 99 | } |
| 100 | |
| 101 | /* Called when user tries to insert an entry of this type. */ |
Jan Engelhardt | ccb79bd | 2007-07-07 22:16:00 -0700 | [diff] [blame] | 102 | static bool |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 103 | checkentry(const char *tablename, |
YOSHIFUJI Hideaki | 1ab1457 | 2007-02-09 23:24:49 +0900 | [diff] [blame] | 104 | const void *entry, |
Patrick McHardy | c498673 | 2006-03-20 18:02:56 -0800 | [diff] [blame] | 105 | const struct xt_match *match, |
YOSHIFUJI Hideaki | 1ab1457 | 2007-02-09 23:24:49 +0900 | [diff] [blame] | 106 | void *matchinfo, |
| 107 | unsigned int hook_mask) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 108 | { |
| 109 | const struct ip6t_ah *ahinfo = matchinfo; |
| 110 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 111 | if (ahinfo->invflags & ~IP6T_AH_INV_MASK) { |
Patrick McHardy | 0d53778 | 2007-07-07 22:39:38 -0700 | [diff] [blame^] | 112 | pr_debug("ip6t_ah: unknown flags %X\n", ahinfo->invflags); |
Jan Engelhardt | ccb79bd | 2007-07-07 22:16:00 -0700 | [diff] [blame] | 113 | return false; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 114 | } |
Jan Engelhardt | ccb79bd | 2007-07-07 22:16:00 -0700 | [diff] [blame] | 115 | return true; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 116 | } |
| 117 | |
Patrick McHardy | 9f15c53 | 2007-07-07 22:22:02 -0700 | [diff] [blame] | 118 | static struct xt_match ah_match __read_mostly = { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 119 | .name = "ah", |
Jan Engelhardt | 6709dbb | 2007-02-07 15:11:19 -0800 | [diff] [blame] | 120 | .family = AF_INET6, |
Patrick McHardy | 7f93971 | 2006-03-20 18:01:43 -0800 | [diff] [blame] | 121 | .match = match, |
| 122 | .matchsize = sizeof(struct ip6t_ah), |
| 123 | .checkentry = checkentry, |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 124 | .me = THIS_MODULE, |
| 125 | }; |
| 126 | |
Andrew Morton | 65b4b4e | 2006-03-28 16:37:06 -0800 | [diff] [blame] | 127 | static int __init ip6t_ah_init(void) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 128 | { |
Jan Engelhardt | 6709dbb | 2007-02-07 15:11:19 -0800 | [diff] [blame] | 129 | return xt_register_match(&ah_match); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 130 | } |
| 131 | |
Andrew Morton | 65b4b4e | 2006-03-28 16:37:06 -0800 | [diff] [blame] | 132 | static void __exit ip6t_ah_fini(void) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 133 | { |
Jan Engelhardt | 6709dbb | 2007-02-07 15:11:19 -0800 | [diff] [blame] | 134 | xt_unregister_match(&ah_match); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 135 | } |
| 136 | |
Andrew Morton | 65b4b4e | 2006-03-28 16:37:06 -0800 | [diff] [blame] | 137 | module_init(ip6t_ah_init); |
| 138 | module_exit(ip6t_ah_fini); |