blob: d7b7f3b16dfef6fbc965c6c972145aea6d93ffa2 [file] [log] [blame]
Harald Welte7a447312002-05-29 15:11:49 +00001/* 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_ecn.h>
18
19static void init(struct ipt_entry_match *m, unsigned int *nfcache)
20{
21 *nfcache |= NFC_IP_TOS;
22}
23
24static void help(void)
25{
26 printf(
27"ECN match v%s options\n"
28"[!] --ecn-tcp-cwr Match CWR bit of TCP header\n"
29"[!] --ecn-tcp-ece Match ECE bit of TCP header\n"
30"[!] --ecn-ip-ect [0..3] Match ECN codepoint in IPv4 header\n",
31 IPTABLES_VERSION);
32}
33
34static struct option opts[] = {
Stephane Ouellettefb7ed722003-04-11 08:20:01 +000035 { .name = "ecn-tcp-cwr", .has_arg = 0, .flag = 0, .val = 'F' },
36 { .name = "ecn-tcp-ece", .has_arg = 0, .flag = 0, .val = 'G' },
37 { .name = "ecn-ip-ect", .has_arg = 1, .flag = 0, .val = 'H' },
38 { .name = 0 }
Harald Welte7a447312002-05-29 15:11:49 +000039};
40
41static int
42parse(int c, char **argv, int invert, unsigned int *flags,
43 const struct ipt_entry *entry,
44 unsigned int *nfcache,
45 struct ipt_entry_match **match)
46{
47 unsigned int result;
48 struct ipt_ecn_info *einfo
49 = (struct ipt_ecn_info *)(*match)->data;
50
51 switch (c) {
52 case 'F':
53 if (*flags & IPT_ECN_OP_MATCH_CWR)
54 exit_error(PARAMETER_PROBLEM,
55 "ECN match: can only use parameter ONCE!");
56 check_inverse(optarg, &invert, &optind, 0);
57 einfo->operation |= IPT_ECN_OP_MATCH_CWR;
58 if (invert)
59 einfo->invert |= IPT_ECN_OP_MATCH_CWR;
60 *flags |= IPT_ECN_OP_MATCH_CWR;
61 break;
62
63 case 'G':
64 if (*flags & IPT_ECN_OP_MATCH_ECE)
65 exit_error(PARAMETER_PROBLEM,
66 "ECN match: can only use parameter ONCE!");
67 check_inverse(optarg, &invert, &optind, 0);
68 einfo->operation |= IPT_ECN_OP_MATCH_ECE;
69 if (invert)
70 einfo->invert |= IPT_ECN_OP_MATCH_ECE;
71 *flags |= IPT_ECN_OP_MATCH_ECE;
72 break;
73
74 case 'H':
75 if (*flags & IPT_ECN_OP_MATCH_IP)
76 exit_error(PARAMETER_PROBLEM,
77 "ECN match: can only use parameter ONCE!");
78 check_inverse(optarg, &invert, &optind, 0);
79 if (invert)
80 einfo->invert |= IPT_ECN_OP_MATCH_IP;
81 *flags |= IPT_ECN_OP_MATCH_IP;
82 einfo->operation |= IPT_ECN_OP_MATCH_IP;
83 if (string_to_number(optarg, 0, 3, &result))
84 exit_error(PARAMETER_PROBLEM,
85 "ECN match: Value out of range");
Harald Welte0e9ed732002-08-05 19:35:52 +000086 einfo->ip_ect = result;
Harald Welte7a447312002-05-29 15:11:49 +000087 break;
88 default:
89 return 0;
90 }
91
92 return 1;
93}
94
95static void
96final_check(unsigned int flags)
97{
98 if (!flags)
99 exit_error(PARAMETER_PROBLEM,
100 "ECN match: some option required");
101}
102
Harald Welte7a447312002-05-29 15:11:49 +0000103/* Prints out the matchinfo. */
104static void
105print(const struct ipt_ip *ip,
106 const struct ipt_entry_match *match,
107 int numeric)
108{
109 const struct ipt_ecn_info *einfo =
110 (const struct ipt_ecn_info *)match->data;
111
112 printf("ECN match ");
113
114 if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
115 if (einfo->invert & IPT_ECN_OP_MATCH_ECE)
116 fputc('!', stdout);
117 printf("ECE ");
118 }
119
120 if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
121 if (einfo->invert & IPT_ECN_OP_MATCH_CWR)
122 fputc('!', stdout);
123 printf("CWR ");
124 }
125
126 if (einfo->operation & IPT_ECN_OP_MATCH_IP) {
127 if (einfo->invert & IPT_ECN_OP_MATCH_IP)
128 fputc('!', stdout);
129 printf("ECT=%d ", einfo->ip_ect);
130 }
131}
132
133/* Saves the union ipt_matchinfo in parsable form to stdout. */
134static void
135save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
136{
137 const struct ipt_ecn_info *einfo =
138 (const struct ipt_ecn_info *)match->data;
139
140 if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
141 if (einfo->invert & IPT_ECN_OP_MATCH_ECE)
142 printf("! ");
143 printf("--ecn-tcp-ece ");
144 }
145
146 if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
147 if (einfo->invert & IPT_ECN_OP_MATCH_CWR)
148 printf("! ");
149 printf("--ecn-tcp-cwr ");
150 }
151
152 if (einfo->operation & IPT_ECN_OP_MATCH_IP) {
153 if (einfo->invert & IPT_ECN_OP_MATCH_IP)
154 printf("! ");
155 printf("--ecn-ip-ect %d", einfo->ip_ect);
156 }
157}
158
159static
160struct iptables_match ecn
Stephane Ouellettefb7ed722003-04-11 08:20:01 +0000161= { .name = "ecn",
162 .version = IPTABLES_VERSION,
163 .size = IPT_ALIGN(sizeof(struct ipt_ecn_info)),
164 .userspacesize = IPT_ALIGN(sizeof(struct ipt_ecn_info)),
165 .help = &help,
166 .init = &init,
167 .parse = &parse,
168 .final_check = &final_check,
169 .print = &print,
170 .save = &save,
171 .extra_opts = opts
Harald Welte7a447312002-05-29 15:11:49 +0000172};
173
174void _init(void)
175{
176 register_match(&ecn);
177}