1 /* iptables module for the IPv4 and TCP ECN bits, Version 1.5
3 * (C) 2002 by Harald Welte <laforge@netfilter.org>
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.
9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11 #include <linux/module.h>
12 #include <linux/skbuff.h>
15 #include <linux/tcp.h>
16 #include <net/checksum.h>
18 #include <linux/netfilter/x_tables.h>
19 #include <linux/netfilter_ipv4/ip_tables.h>
20 #include <linux/netfilter_ipv4/ipt_ECN.h>
22 MODULE_LICENSE("GPL");
23 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
24 MODULE_DESCRIPTION("Xtables: Explicit Congestion Notification (ECN) flag modification");
26 /* set ECT codepoint from IP header.
27 * return false if there was an error. */
29 set_ect_ip(struct sk_buff
*skb
, const struct ipt_ECN_info
*einfo
)
31 struct iphdr
*iph
= ip_hdr(skb
);
33 if ((iph
->tos
& IPT_ECN_IP_MASK
) != (einfo
->ip_ect
& IPT_ECN_IP_MASK
)) {
35 if (!skb_make_writable(skb
, sizeof(struct iphdr
)))
39 iph
->tos
&= ~IPT_ECN_IP_MASK
;
40 iph
->tos
|= (einfo
->ip_ect
& IPT_ECN_IP_MASK
);
41 csum_replace2(&iph
->check
, htons(oldtos
), htons(iph
->tos
));
46 /* Return false if there was an error. */
48 set_ect_tcp(struct sk_buff
*skb
, const struct ipt_ECN_info
*einfo
)
50 struct tcphdr _tcph
, *tcph
;
53 /* Not enough header? */
54 tcph
= skb_header_pointer(skb
, ip_hdrlen(skb
), sizeof(_tcph
), &_tcph
);
58 if ((!(einfo
->operation
& IPT_ECN_OP_SET_ECE
) ||
59 tcph
->ece
== einfo
->proto
.tcp
.ece
) &&
60 (!(einfo
->operation
& IPT_ECN_OP_SET_CWR
) ||
61 tcph
->cwr
== einfo
->proto
.tcp
.cwr
))
64 if (!skb_make_writable(skb
, ip_hdrlen(skb
) + sizeof(*tcph
)))
66 tcph
= (void *)ip_hdr(skb
) + ip_hdrlen(skb
);
68 oldval
= ((__be16
*)tcph
)[6];
69 if (einfo
->operation
& IPT_ECN_OP_SET_ECE
)
70 tcph
->ece
= einfo
->proto
.tcp
.ece
;
71 if (einfo
->operation
& IPT_ECN_OP_SET_CWR
)
72 tcph
->cwr
= einfo
->proto
.tcp
.cwr
;
74 inet_proto_csum_replace2(&tcph
->check
, skb
,
75 oldval
, ((__be16
*)tcph
)[6], 0);
80 ecn_tg(struct sk_buff
*skb
, const struct xt_action_param
*par
)
82 const struct ipt_ECN_info
*einfo
= par
->targinfo
;
84 if (einfo
->operation
& IPT_ECN_OP_SET_IP
)
85 if (!set_ect_ip(skb
, einfo
))
88 if (einfo
->operation
& (IPT_ECN_OP_SET_ECE
| IPT_ECN_OP_SET_CWR
) &&
89 ip_hdr(skb
)->protocol
== IPPROTO_TCP
)
90 if (!set_ect_tcp(skb
, einfo
))
96 static int ecn_tg_check(const struct xt_tgchk_param
*par
)
98 const struct ipt_ECN_info
*einfo
= par
->targinfo
;
99 const struct ipt_entry
*e
= par
->entryinfo
;
101 if (einfo
->operation
& IPT_ECN_OP_MASK
) {
102 pr_info("unsupported ECN operation %x\n", einfo
->operation
);
105 if (einfo
->ip_ect
& ~IPT_ECN_IP_MASK
) {
106 pr_info("new ECT codepoint %x out of mask\n", einfo
->ip_ect
);
109 if ((einfo
->operation
& (IPT_ECN_OP_SET_ECE
|IPT_ECN_OP_SET_CWR
)) &&
110 (e
->ip
.proto
!= IPPROTO_TCP
|| (e
->ip
.invflags
& XT_INV_PROTO
))) {
111 pr_info("cannot use TCP operations on a non-tcp rule\n");
117 static struct xt_target ecn_tg_reg __read_mostly
= {
119 .family
= NFPROTO_IPV4
,
121 .targetsize
= sizeof(struct ipt_ECN_info
),
123 .checkentry
= ecn_tg_check
,
127 static int __init
ecn_tg_init(void)
129 return xt_register_target(&ecn_tg_reg
);
132 static void __exit
ecn_tg_exit(void)
134 xt_unregister_target(&ecn_tg_reg
);
137 module_init(ecn_tg_init
);
138 module_exit(ecn_tg_exit
);