Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
1da177e4 LT |
2 | /* Kernel module to match AH parameters. */ |
3 | ||
4 | /* (C) 2001-2002 Andras Kis-Szabo <kisza@sch.bme.hu> | |
1da177e4 | 5 | */ |
ff67e4e4 | 6 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
1da177e4 LT |
7 | #include <linux/module.h> |
8 | #include <linux/skbuff.h> | |
14c85021 | 9 | #include <linux/ip.h> |
1da177e4 LT |
10 | #include <linux/ipv6.h> |
11 | #include <linux/types.h> | |
12 | #include <net/checksum.h> | |
13 | #include <net/ipv6.h> | |
14 | ||
6709dbbb | 15 | #include <linux/netfilter/x_tables.h> |
1da177e4 LT |
16 | #include <linux/netfilter_ipv6/ip6_tables.h> |
17 | #include <linux/netfilter_ipv6/ip6t_ah.h> | |
18 | ||
19 | MODULE_LICENSE("GPL"); | |
2ae15b64 | 20 | MODULE_DESCRIPTION("Xtables: IPv6 IPsec-AH match"); |
1da177e4 LT |
21 | MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); |
22 | ||
1da177e4 | 23 | /* Returns 1 if the spi is matched by the range, 0 otherwise */ |
1d93a9cb JE |
24 | static inline bool |
25 | spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, bool invert) | |
1da177e4 | 26 | { |
1d93a9cb | 27 | bool r; |
0d53778e | 28 | |
ff67e4e4 | 29 | pr_debug("spi_match:%c 0x%x <= 0x%x <= 0x%x\n", |
0d53778e | 30 | invert ? '!' : ' ', min, spi, max); |
1da177e4 | 31 | r = (spi >= min && spi <= max) ^ invert; |
0d53778e | 32 | pr_debug(" result %s\n", r ? "PASS" : "FAILED"); |
1da177e4 LT |
33 | return r; |
34 | } | |
35 | ||
62fc8051 | 36 | static bool ah_mt6(const struct sk_buff *skb, struct xt_action_param *par) |
1da177e4 | 37 | { |
a47362a2 JE |
38 | struct ip_auth_hdr _ah; |
39 | const struct ip_auth_hdr *ah; | |
f7108a20 | 40 | const struct ip6t_ah *ahinfo = par->matchinfo; |
84018f55 | 41 | unsigned int ptr = 0; |
1da177e4 | 42 | unsigned int hdrlen = 0; |
6d381634 | 43 | int err; |
1da177e4 | 44 | |
84018f55 | 45 | err = ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH, NULL, NULL); |
6d381634 PM |
46 | if (err < 0) { |
47 | if (err != -ENOENT) | |
b4ba2611 | 48 | par->hotdrop = true; |
1d93a9cb | 49 | return false; |
6d381634 | 50 | } |
1da177e4 | 51 | |
e674d0f3 YK |
52 | ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah); |
53 | if (ah == NULL) { | |
b4ba2611 | 54 | par->hotdrop = true; |
1d93a9cb | 55 | return false; |
1da177e4 LT |
56 | } |
57 | ||
416e8126 | 58 | hdrlen = ipv6_authlen(ah); |
1da177e4 | 59 | |
0d53778e PM |
60 | pr_debug("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen); |
61 | pr_debug("RES %04X ", ah->reserved); | |
62 | pr_debug("SPI %u %08X\n", ntohl(ah->spi), ntohl(ah->spi)); | |
63 | ||
64 | pr_debug("IPv6 AH spi %02X ", | |
65 | spi_match(ahinfo->spis[0], ahinfo->spis[1], | |
66 | ntohl(ah->spi), | |
67 | !!(ahinfo->invflags & IP6T_AH_INV_SPI))); | |
68 | pr_debug("len %02X %04X %02X ", | |
69 | ahinfo->hdrlen, hdrlen, | |
70 | (!ahinfo->hdrlen || | |
71 | (ahinfo->hdrlen == hdrlen) ^ | |
72 | !!(ahinfo->invflags & IP6T_AH_INV_LEN))); | |
73 | pr_debug("res %02X %04X %02X\n", | |
74 | ahinfo->hdrres, ah->reserved, | |
75 | !(ahinfo->hdrres && ah->reserved)); | |
1da177e4 | 76 | |
42f36eba | 77 | return spi_match(ahinfo->spis[0], ahinfo->spis[1], |
3666ed1c JP |
78 | ntohl(ah->spi), |
79 | !!(ahinfo->invflags & IP6T_AH_INV_SPI)) && | |
80 | (!ahinfo->hdrlen || | |
81 | (ahinfo->hdrlen == hdrlen) ^ | |
82 | !!(ahinfo->invflags & IP6T_AH_INV_LEN)) && | |
83 | !(ahinfo->hdrres && ah->reserved); | |
1da177e4 LT |
84 | } |
85 | ||
b0f38452 | 86 | static int ah_mt6_check(const struct xt_mtchk_param *par) |
1da177e4 | 87 | { |
9b4fce7a | 88 | const struct ip6t_ah *ahinfo = par->matchinfo; |
1da177e4 | 89 | |
1da177e4 | 90 | if (ahinfo->invflags & ~IP6T_AH_INV_MASK) { |
ff67e4e4 | 91 | pr_debug("unknown flags %X\n", ahinfo->invflags); |
bd414ee6 | 92 | return -EINVAL; |
1da177e4 | 93 | } |
bd414ee6 | 94 | return 0; |
1da177e4 LT |
95 | } |
96 | ||
d3c5ee6d | 97 | static struct xt_match ah_mt6_reg __read_mostly = { |
1da177e4 | 98 | .name = "ah", |
ee999d8b | 99 | .family = NFPROTO_IPV6, |
d3c5ee6d | 100 | .match = ah_mt6, |
7f939713 | 101 | .matchsize = sizeof(struct ip6t_ah), |
d3c5ee6d | 102 | .checkentry = ah_mt6_check, |
1da177e4 LT |
103 | .me = THIS_MODULE, |
104 | }; | |
105 | ||
d3c5ee6d | 106 | static int __init ah_mt6_init(void) |
1da177e4 | 107 | { |
d3c5ee6d | 108 | return xt_register_match(&ah_mt6_reg); |
1da177e4 LT |
109 | } |
110 | ||
d3c5ee6d | 111 | static void __exit ah_mt6_exit(void) |
1da177e4 | 112 | { |
d3c5ee6d | 113 | xt_unregister_match(&ah_mt6_reg); |
1da177e4 LT |
114 | } |
115 | ||
d3c5ee6d JE |
116 | module_init(ah_mt6_init); |
117 | module_exit(ah_mt6_exit); |