Commit | Line | Data |
---|---|---|
a468701d YK |
1 | /* x_tables module for setting the IPv4/IPv6 DSCP field, Version 1.8 |
2 | * | |
3 | * (C) 2002 by Harald Welte <laforge@netfilter.org> | |
4 | * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 as | |
8 | * published by the Free Software Foundation. | |
9 | * | |
10 | * See RFC2474 for a description of the DSCP field within the IP Header. | |
a468701d YK |
11 | */ |
12 | ||
13 | #include <linux/module.h> | |
14 | #include <linux/skbuff.h> | |
15 | #include <linux/ip.h> | |
16 | #include <linux/ipv6.h> | |
17 | #include <net/dsfield.h> | |
18 | ||
19 | #include <linux/netfilter/x_tables.h> | |
20 | #include <linux/netfilter/xt_DSCP.h> | |
c9fd4968 | 21 | #include <linux/netfilter_ipv4/ipt_TOS.h> |
a468701d YK |
22 | |
23 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | |
2ae15b64 | 24 | MODULE_DESCRIPTION("Xtables: DSCP/TOS field modification"); |
a468701d YK |
25 | MODULE_LICENSE("GPL"); |
26 | MODULE_ALIAS("ipt_DSCP"); | |
27 | MODULE_ALIAS("ip6t_DSCP"); | |
c9fd4968 | 28 | MODULE_ALIAS("ipt_TOS"); |
5c350e5a | 29 | MODULE_ALIAS("ip6t_TOS"); |
a468701d | 30 | |
d3c5ee6d | 31 | static unsigned int |
7eb35586 | 32 | dscp_tg(struct sk_buff *skb, const struct xt_target_param *par) |
a468701d | 33 | { |
7eb35586 | 34 | const struct xt_DSCP_info *dinfo = par->targinfo; |
3db05fea | 35 | u_int8_t dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT; |
a468701d YK |
36 | |
37 | if (dscp != dinfo->dscp) { | |
3db05fea | 38 | if (!skb_make_writable(skb, sizeof(struct iphdr))) |
a468701d YK |
39 | return NF_DROP; |
40 | ||
3db05fea | 41 | ipv4_change_dsfield(ip_hdr(skb), (__u8)(~XT_DSCP_MASK), |
a468701d YK |
42 | dinfo->dscp << XT_DSCP_SHIFT); |
43 | ||
44 | } | |
45 | return XT_CONTINUE; | |
46 | } | |
47 | ||
d3c5ee6d | 48 | static unsigned int |
7eb35586 | 49 | dscp_tg6(struct sk_buff *skb, const struct xt_target_param *par) |
a468701d | 50 | { |
7eb35586 | 51 | const struct xt_DSCP_info *dinfo = par->targinfo; |
3db05fea | 52 | u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT; |
a468701d YK |
53 | |
54 | if (dscp != dinfo->dscp) { | |
3db05fea | 55 | if (!skb_make_writable(skb, sizeof(struct ipv6hdr))) |
a468701d YK |
56 | return NF_DROP; |
57 | ||
3db05fea | 58 | ipv6_change_dsfield(ipv6_hdr(skb), (__u8)(~XT_DSCP_MASK), |
a468701d YK |
59 | dinfo->dscp << XT_DSCP_SHIFT); |
60 | } | |
61 | return XT_CONTINUE; | |
62 | } | |
63 | ||
af5d6dc2 | 64 | static bool dscp_tg_check(const struct xt_tgchk_param *par) |
a468701d | 65 | { |
af5d6dc2 | 66 | const struct xt_DSCP_info *info = par->targinfo; |
a468701d | 67 | |
af5d6dc2 JE |
68 | if (info->dscp > XT_DSCP_MAX) { |
69 | printk(KERN_WARNING "DSCP: dscp %x out of range\n", info->dscp); | |
e1931b78 | 70 | return false; |
a468701d | 71 | } |
e1931b78 | 72 | return true; |
a468701d YK |
73 | } |
74 | ||
c9fd4968 | 75 | static unsigned int |
7eb35586 | 76 | tos_tg_v0(struct sk_buff *skb, const struct xt_target_param *par) |
c9fd4968 | 77 | { |
7eb35586 | 78 | const struct ipt_tos_target_info *info = par->targinfo; |
c9fd4968 JE |
79 | struct iphdr *iph = ip_hdr(skb); |
80 | u_int8_t oldtos; | |
81 | ||
82 | if ((iph->tos & IPTOS_TOS_MASK) != info->tos) { | |
83 | if (!skb_make_writable(skb, sizeof(struct iphdr))) | |
84 | return NF_DROP; | |
85 | ||
86 | iph = ip_hdr(skb); | |
87 | oldtos = iph->tos; | |
88 | iph->tos = (iph->tos & IPTOS_PREC_MASK) | info->tos; | |
89 | csum_replace2(&iph->check, htons(oldtos), htons(iph->tos)); | |
90 | } | |
91 | ||
92 | return XT_CONTINUE; | |
93 | } | |
94 | ||
af5d6dc2 | 95 | static bool tos_tg_check_v0(const struct xt_tgchk_param *par) |
c9fd4968 | 96 | { |
af5d6dc2 JE |
97 | const struct ipt_tos_target_info *info = par->targinfo; |
98 | const uint8_t tos = info->tos; | |
c9fd4968 JE |
99 | |
100 | if (tos != IPTOS_LOWDELAY && tos != IPTOS_THROUGHPUT && | |
101 | tos != IPTOS_RELIABILITY && tos != IPTOS_MINCOST && | |
102 | tos != IPTOS_NORMALSVC) { | |
103 | printk(KERN_WARNING "TOS: bad tos value %#x\n", tos); | |
104 | return false; | |
105 | } | |
106 | ||
107 | return true; | |
108 | } | |
109 | ||
5c350e5a | 110 | static unsigned int |
7eb35586 | 111 | tos_tg(struct sk_buff *skb, const struct xt_target_param *par) |
5c350e5a | 112 | { |
7eb35586 | 113 | const struct xt_tos_target_info *info = par->targinfo; |
5c350e5a JE |
114 | struct iphdr *iph = ip_hdr(skb); |
115 | u_int8_t orig, nv; | |
116 | ||
117 | orig = ipv4_get_dsfield(iph); | |
9bb268ed | 118 | nv = (orig & ~info->tos_mask) ^ info->tos_value; |
5c350e5a JE |
119 | |
120 | if (orig != nv) { | |
121 | if (!skb_make_writable(skb, sizeof(struct iphdr))) | |
122 | return NF_DROP; | |
123 | iph = ip_hdr(skb); | |
cdfe8b97 | 124 | ipv4_change_dsfield(iph, 0, nv); |
5c350e5a JE |
125 | } |
126 | ||
127 | return XT_CONTINUE; | |
128 | } | |
129 | ||
130 | static unsigned int | |
7eb35586 | 131 | tos_tg6(struct sk_buff *skb, const struct xt_target_param *par) |
5c350e5a | 132 | { |
7eb35586 | 133 | const struct xt_tos_target_info *info = par->targinfo; |
5c350e5a JE |
134 | struct ipv6hdr *iph = ipv6_hdr(skb); |
135 | u_int8_t orig, nv; | |
136 | ||
137 | orig = ipv6_get_dsfield(iph); | |
138 | nv = (orig & info->tos_mask) ^ info->tos_value; | |
139 | ||
140 | if (orig != nv) { | |
141 | if (!skb_make_writable(skb, sizeof(struct iphdr))) | |
142 | return NF_DROP; | |
143 | iph = ipv6_hdr(skb); | |
cdfe8b97 | 144 | ipv6_change_dsfield(iph, 0, nv); |
5c350e5a JE |
145 | } |
146 | ||
147 | return XT_CONTINUE; | |
148 | } | |
149 | ||
d3c5ee6d | 150 | static struct xt_target dscp_tg_reg[] __read_mostly = { |
4470bbc7 PM |
151 | { |
152 | .name = "DSCP", | |
ee999d8b | 153 | .family = NFPROTO_IPV4, |
d3c5ee6d JE |
154 | .checkentry = dscp_tg_check, |
155 | .target = dscp_tg, | |
4470bbc7 PM |
156 | .targetsize = sizeof(struct xt_DSCP_info), |
157 | .table = "mangle", | |
158 | .me = THIS_MODULE, | |
159 | }, | |
160 | { | |
161 | .name = "DSCP", | |
ee999d8b | 162 | .family = NFPROTO_IPV6, |
d3c5ee6d JE |
163 | .checkentry = dscp_tg_check, |
164 | .target = dscp_tg6, | |
4470bbc7 PM |
165 | .targetsize = sizeof(struct xt_DSCP_info), |
166 | .table = "mangle", | |
167 | .me = THIS_MODULE, | |
168 | }, | |
c9fd4968 JE |
169 | { |
170 | .name = "TOS", | |
171 | .revision = 0, | |
ee999d8b | 172 | .family = NFPROTO_IPV4, |
c9fd4968 JE |
173 | .table = "mangle", |
174 | .target = tos_tg_v0, | |
175 | .targetsize = sizeof(struct ipt_tos_target_info), | |
176 | .checkentry = tos_tg_check_v0, | |
177 | .me = THIS_MODULE, | |
178 | }, | |
5c350e5a JE |
179 | { |
180 | .name = "TOS", | |
181 | .revision = 1, | |
ee999d8b | 182 | .family = NFPROTO_IPV4, |
5c350e5a JE |
183 | .table = "mangle", |
184 | .target = tos_tg, | |
185 | .targetsize = sizeof(struct xt_tos_target_info), | |
186 | .me = THIS_MODULE, | |
187 | }, | |
188 | { | |
189 | .name = "TOS", | |
190 | .revision = 1, | |
ee999d8b | 191 | .family = NFPROTO_IPV6, |
5c350e5a JE |
192 | .table = "mangle", |
193 | .target = tos_tg6, | |
194 | .targetsize = sizeof(struct xt_tos_target_info), | |
195 | .me = THIS_MODULE, | |
196 | }, | |
a468701d YK |
197 | }; |
198 | ||
d3c5ee6d | 199 | static int __init dscp_tg_init(void) |
a468701d | 200 | { |
d3c5ee6d | 201 | return xt_register_targets(dscp_tg_reg, ARRAY_SIZE(dscp_tg_reg)); |
a468701d YK |
202 | } |
203 | ||
d3c5ee6d | 204 | static void __exit dscp_tg_exit(void) |
a468701d | 205 | { |
d3c5ee6d | 206 | xt_unregister_targets(dscp_tg_reg, ARRAY_SIZE(dscp_tg_reg)); |
a468701d YK |
207 | } |
208 | ||
d3c5ee6d JE |
209 | module_init(dscp_tg_init); |
210 | module_exit(dscp_tg_exit); |