Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
563d36eb JE |
2 | /* |
3 | * TTL modification target for IP tables | |
4 | * (C) 2000,2005 by Harald Welte <laforge@netfilter.org> | |
5 | * | |
6 | * Hop Limit modification target for ip6tables | |
7 | * Maciej Soltysiak <solt@dns.toxicfilms.tv> | |
563d36eb | 8 | */ |
8bee4bad | 9 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
563d36eb JE |
10 | #include <linux/module.h> |
11 | #include <linux/skbuff.h> | |
12 | #include <linux/ip.h> | |
13 | #include <linux/ipv6.h> | |
14 | #include <net/checksum.h> | |
15 | ||
16 | #include <linux/netfilter/x_tables.h> | |
17 | #include <linux/netfilter_ipv4/ipt_TTL.h> | |
18 | #include <linux/netfilter_ipv6/ip6t_HL.h> | |
19 | ||
20 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | |
21 | MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>"); | |
22 | MODULE_DESCRIPTION("Xtables: Hoplimit/TTL Limit field modification target"); | |
23 | MODULE_LICENSE("GPL"); | |
24 | ||
25 | static unsigned int | |
4b560b44 | 26 | ttl_tg(struct sk_buff *skb, const struct xt_action_param *par) |
563d36eb JE |
27 | { |
28 | struct iphdr *iph; | |
29 | const struct ipt_TTL_info *info = par->targinfo; | |
30 | int new_ttl; | |
31 | ||
8e03707f | 32 | if (skb_ensure_writable(skb, sizeof(*iph))) |
563d36eb JE |
33 | return NF_DROP; |
34 | ||
35 | iph = ip_hdr(skb); | |
36 | ||
37 | switch (info->mode) { | |
181b1e9c JP |
38 | case IPT_TTL_SET: |
39 | new_ttl = info->ttl; | |
40 | break; | |
41 | case IPT_TTL_INC: | |
42 | new_ttl = iph->ttl + info->ttl; | |
43 | if (new_ttl > 255) | |
44 | new_ttl = 255; | |
45 | break; | |
46 | case IPT_TTL_DEC: | |
47 | new_ttl = iph->ttl - info->ttl; | |
48 | if (new_ttl < 0) | |
49 | new_ttl = 0; | |
50 | break; | |
51 | default: | |
52 | new_ttl = iph->ttl; | |
53 | break; | |
563d36eb JE |
54 | } |
55 | ||
56 | if (new_ttl != iph->ttl) { | |
57 | csum_replace2(&iph->check, htons(iph->ttl << 8), | |
58 | htons(new_ttl << 8)); | |
59 | iph->ttl = new_ttl; | |
60 | } | |
61 | ||
62 | return XT_CONTINUE; | |
63 | } | |
64 | ||
65 | static unsigned int | |
4b560b44 | 66 | hl_tg6(struct sk_buff *skb, const struct xt_action_param *par) |
563d36eb JE |
67 | { |
68 | struct ipv6hdr *ip6h; | |
69 | const struct ip6t_HL_info *info = par->targinfo; | |
70 | int new_hl; | |
71 | ||
8e03707f | 72 | if (skb_ensure_writable(skb, sizeof(*ip6h))) |
563d36eb JE |
73 | return NF_DROP; |
74 | ||
75 | ip6h = ipv6_hdr(skb); | |
76 | ||
77 | switch (info->mode) { | |
181b1e9c JP |
78 | case IP6T_HL_SET: |
79 | new_hl = info->hop_limit; | |
80 | break; | |
81 | case IP6T_HL_INC: | |
82 | new_hl = ip6h->hop_limit + info->hop_limit; | |
83 | if (new_hl > 255) | |
84 | new_hl = 255; | |
85 | break; | |
86 | case IP6T_HL_DEC: | |
87 | new_hl = ip6h->hop_limit - info->hop_limit; | |
88 | if (new_hl < 0) | |
89 | new_hl = 0; | |
90 | break; | |
91 | default: | |
92 | new_hl = ip6h->hop_limit; | |
93 | break; | |
563d36eb JE |
94 | } |
95 | ||
96 | ip6h->hop_limit = new_hl; | |
97 | ||
98 | return XT_CONTINUE; | |
99 | } | |
100 | ||
135367b8 | 101 | static int ttl_tg_check(const struct xt_tgchk_param *par) |
563d36eb JE |
102 | { |
103 | const struct ipt_TTL_info *info = par->targinfo; | |
104 | ||
0cc9501f | 105 | if (info->mode > IPT_TTL_MAXMODE) |
4a5a5c73 | 106 | return -EINVAL; |
563d36eb | 107 | if (info->mode != IPT_TTL_SET && info->ttl == 0) |
d6b00a53 JE |
108 | return -EINVAL; |
109 | return 0; | |
563d36eb JE |
110 | } |
111 | ||
135367b8 | 112 | static int hl_tg6_check(const struct xt_tgchk_param *par) |
563d36eb JE |
113 | { |
114 | const struct ip6t_HL_info *info = par->targinfo; | |
115 | ||
0cc9501f | 116 | if (info->mode > IP6T_HL_MAXMODE) |
d6b00a53 | 117 | return -EINVAL; |
0cc9501f | 118 | if (info->mode != IP6T_HL_SET && info->hop_limit == 0) |
d6b00a53 | 119 | return -EINVAL; |
d6b00a53 | 120 | return 0; |
563d36eb JE |
121 | } |
122 | ||
123 | static struct xt_target hl_tg_reg[] __read_mostly = { | |
124 | { | |
125 | .name = "TTL", | |
126 | .revision = 0, | |
127 | .family = NFPROTO_IPV4, | |
128 | .target = ttl_tg, | |
129 | .targetsize = sizeof(struct ipt_TTL_info), | |
130 | .table = "mangle", | |
131 | .checkentry = ttl_tg_check, | |
132 | .me = THIS_MODULE, | |
133 | }, | |
134 | { | |
135 | .name = "HL", | |
136 | .revision = 0, | |
137 | .family = NFPROTO_IPV6, | |
138 | .target = hl_tg6, | |
139 | .targetsize = sizeof(struct ip6t_HL_info), | |
140 | .table = "mangle", | |
141 | .checkentry = hl_tg6_check, | |
142 | .me = THIS_MODULE, | |
143 | }, | |
144 | }; | |
145 | ||
146 | static int __init hl_tg_init(void) | |
147 | { | |
148 | return xt_register_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg)); | |
149 | } | |
150 | ||
151 | static void __exit hl_tg_exit(void) | |
152 | { | |
153 | xt_unregister_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg)); | |
154 | } | |
155 | ||
156 | module_init(hl_tg_init); | |
157 | module_exit(hl_tg_exit); | |
158 | MODULE_ALIAS("ipt_TTL"); | |
159 | MODULE_ALIAS("ip6t_HL"); |