1 /* Shared library add-on to iptables for ECN matching
2 *
3 * (C) 2002 by Harald Welte <laforge@gnumonks.org>
4 *
5 * This program is distributed under the terms of GNU GPL v2, 1991
6 *
7 * libipt_ecn.c borrowed heavily from libipt_dscp.c
8 *
9 */
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <getopt.h>
14
15 #include <iptables.h>
16 #include <linux/netfilter_ipv4/ip_tables.h>
17 #include <linux/netfilter_ipv4/ipt_2ecn.h>
18
help(void)19 static void help(void)
20 {
21 printf(
22 "ECN match v%s options\n"
23 "[!] --ecn-tcp-cwr Match CWR bit of TCP header\n"
24 "[!] --ecn-tcp-ece Match ECE bit of TCP header\n"
25 "[!] --ecn-ip-ect [0..3] Match ECN codepoint in IPv4 header\n",
26 IPTABLES_VERSION);
27 }
28
29 static struct option opts[] = {
30 { .name = "ecn-tcp-cwr", .has_arg = 0, .flag = 0, .val = 'F' },
31 { .name = "ecn-tcp-ece", .has_arg = 0, .flag = 0, .val = 'G' },
32 { .name = "ecn-ip-ect", .has_arg = 1, .flag = 0, .val = 'H' },
33 { .name = 0 }
34 };
35
36 static int
parse(int c,char ** argv,int invert,unsigned int * flags,const struct ipt_entry * entry,unsigned int * nfcache,struct ipt_entry_match ** match)37 parse(int c, char **argv, int invert, unsigned int *flags,
38 const struct ipt_entry *entry,
39 unsigned int *nfcache,
40 struct ipt_entry_match **match)
41 {
42 unsigned int result;
43 struct ipt_ecn_info *einfo
44 = (struct ipt_ecn_info *)(*match)->data;
45
46 switch (c) {
47 case 'F':
48 if (*flags & IPT_ECN_OP_MATCH_CWR)
49 exit_error(PARAMETER_PROBLEM,
50 "ECN match: can only use parameter ONCE!");
51 check_inverse(optarg, &invert, &optind, 0);
52 einfo->operation |= IPT_ECN_OP_MATCH_CWR;
53 if (invert)
54 einfo->invert |= IPT_ECN_OP_MATCH_CWR;
55 *flags |= IPT_ECN_OP_MATCH_CWR;
56 break;
57
58 case 'G':
59 if (*flags & IPT_ECN_OP_MATCH_ECE)
60 exit_error(PARAMETER_PROBLEM,
61 "ECN match: can only use parameter ONCE!");
62 check_inverse(optarg, &invert, &optind, 0);
63 einfo->operation |= IPT_ECN_OP_MATCH_ECE;
64 if (invert)
65 einfo->invert |= IPT_ECN_OP_MATCH_ECE;
66 *flags |= IPT_ECN_OP_MATCH_ECE;
67 break;
68
69 case 'H':
70 if (*flags & IPT_ECN_OP_MATCH_IP)
71 exit_error(PARAMETER_PROBLEM,
72 "ECN match: can only use parameter ONCE!");
73 check_inverse(optarg, &invert, &optind, 0);
74 if (invert)
75 einfo->invert |= IPT_ECN_OP_MATCH_IP;
76 *flags |= IPT_ECN_OP_MATCH_IP;
77 einfo->operation |= IPT_ECN_OP_MATCH_IP;
78 if (string_to_number(optarg, 0, 3, &result))
79 exit_error(PARAMETER_PROBLEM,
80 "ECN match: Value out of range");
81 einfo->ip_ect = result;
82 break;
83 default:
84 return 0;
85 }
86
87 return 1;
88 }
89
90 static void
final_check(unsigned int flags)91 final_check(unsigned int flags)
92 {
93 if (!flags)
94 exit_error(PARAMETER_PROBLEM,
95 "ECN match: some option required");
96 }
97
98 /* Prints out the matchinfo. */
99 static void
print(const struct ipt_ip * ip,const struct ipt_entry_match * match,int numeric)100 print(const struct ipt_ip *ip,
101 const struct ipt_entry_match *match,
102 int numeric)
103 {
104 const struct ipt_ecn_info *einfo =
105 (const struct ipt_ecn_info *)match->data;
106
107 printf("ECN match ");
108
109 if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
110 if (einfo->invert & IPT_ECN_OP_MATCH_ECE)
111 fputc('!', stdout);
112 printf("ECE ");
113 }
114
115 if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
116 if (einfo->invert & IPT_ECN_OP_MATCH_CWR)
117 fputc('!', stdout);
118 printf("CWR ");
119 }
120
121 if (einfo->operation & IPT_ECN_OP_MATCH_IP) {
122 if (einfo->invert & IPT_ECN_OP_MATCH_IP)
123 fputc('!', stdout);
124 printf("ECT=%d ", einfo->ip_ect);
125 }
126 }
127
128 /* Saves the union ipt_matchinfo in parsable form to stdout. */
129 static void
save(const struct ipt_ip * ip,const struct ipt_entry_match * match)130 save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
131 {
132 const struct ipt_ecn_info *einfo =
133 (const struct ipt_ecn_info *)match->data;
134
135 if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
136 if (einfo->invert & IPT_ECN_OP_MATCH_ECE)
137 printf("! ");
138 printf("--ecn-tcp-ece ");
139 }
140
141 if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
142 if (einfo->invert & IPT_ECN_OP_MATCH_CWR)
143 printf("! ");
144 printf("--ecn-tcp-cwr ");
145 }
146
147 if (einfo->operation & IPT_ECN_OP_MATCH_IP) {
148 if (einfo->invert & IPT_ECN_OP_MATCH_IP)
149 printf("! ");
150 printf("--ecn-ip-ect %d", einfo->ip_ect);
151 }
152 }
153
154 static
155 struct iptables_match ecn
156 = { .name = "ecn",
157 .version = IPTABLES_VERSION,
158 .size = IPT_ALIGN(sizeof(struct ipt_ecn_info)),
159 .userspacesize = IPT_ALIGN(sizeof(struct ipt_ecn_info)),
160 .help = &help,
161 .parse = &parse,
162 .final_check = &final_check,
163 .print = &print,
164 .save = &save,
165 .extra_opts = opts
166 };
167
ipt_2ecn_init(void)168 void ipt_2ecn_init(void)
169 {
170 register_match(&ecn);
171 }
172