iptables-1.3.2-20050720
[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 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
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
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
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
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
168 void _init(void)
169 {
170         register_match(&ecn);
171 }