iptables-1.2.9-2.3.1.src.rpm
[iptables.git] / extensions / libipt_ecn.c
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_ecn.h>
18
19 static void init(struct ipt_entry_match *m, unsigned int *nfcache) 
20 {
21         *nfcache |= NFC_IP_TOS;
22 }
23
24 static 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
34 static struct option opts[] = {
35         { .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 }
39 };
40
41 static int
42 parse(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");
86                 einfo->ip_ect = result;
87                 break;
88         default:
89                 return 0;
90         }
91
92         return 1;
93 }
94
95 static void
96 final_check(unsigned int flags)
97 {
98         if (!flags)
99                 exit_error(PARAMETER_PROBLEM,
100                            "ECN match: some option required");
101 }
102
103 /* Prints out the matchinfo. */
104 static void
105 print(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. */
134 static void
135 save(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
159 static
160 struct iptables_match ecn
161 = { .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
172 };
173
174 void _init(void)
175 {
176         register_match(&ecn);
177 }