changing trunk/trunk to trunk
[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 ecn_help(void)
20 {
21         printf(
22 "ECN match 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 }
27
28 static const struct option ecn_opts[] = {
29         { .name = "ecn-tcp-cwr", .has_arg = 0, .val = 'F' },
30         { .name = "ecn-tcp-ece", .has_arg = 0, .val = 'G' },
31         { .name = "ecn-ip-ect",  .has_arg = 1, .val = 'H' },
32         { .name = NULL }
33 };
34
35 static int ecn_parse(int c, char **argv, int invert, unsigned int *flags,
36                      const void *entry, struct xt_entry_match **match)
37 {
38         unsigned int result;
39         struct ipt_ecn_info *einfo
40                 = (struct ipt_ecn_info *)(*match)->data;
41
42         switch (c) {
43         case 'F':
44                 if (*flags & IPT_ECN_OP_MATCH_CWR)
45                         exit_error(PARAMETER_PROBLEM,
46                                    "ECN match: can only use parameter ONCE!");
47                 check_inverse(optarg, &invert, &optind, 0);
48                 einfo->operation |= IPT_ECN_OP_MATCH_CWR;
49                 if (invert)
50                         einfo->invert |= IPT_ECN_OP_MATCH_CWR;
51                 *flags |= IPT_ECN_OP_MATCH_CWR;
52                 break;
53
54         case 'G':
55                 if (*flags & IPT_ECN_OP_MATCH_ECE)
56                         exit_error(PARAMETER_PROBLEM,
57                                    "ECN match: can only use parameter ONCE!");
58                 check_inverse(optarg, &invert, &optind, 0);
59                 einfo->operation |= IPT_ECN_OP_MATCH_ECE;
60                 if (invert)
61                         einfo->invert |= IPT_ECN_OP_MATCH_ECE;
62                 *flags |= IPT_ECN_OP_MATCH_ECE;
63                 break;
64
65         case 'H':
66                 if (*flags & IPT_ECN_OP_MATCH_IP)
67                         exit_error(PARAMETER_PROBLEM,
68                                    "ECN match: can only use parameter ONCE!");
69                 check_inverse(optarg, &invert, &optind, 0);
70                 if (invert)
71                         einfo->invert |= IPT_ECN_OP_MATCH_IP;
72                 *flags |= IPT_ECN_OP_MATCH_IP;
73                 einfo->operation |= IPT_ECN_OP_MATCH_IP;
74                 if (string_to_number(optarg, 0, 3, &result))
75                         exit_error(PARAMETER_PROBLEM,
76                                    "ECN match: Value out of range");
77                 einfo->ip_ect = result;
78                 break;
79         default:
80                 return 0;
81         }
82
83         return 1;
84 }
85
86 static void ecn_check(unsigned int flags)
87 {
88         if (!flags)
89                 exit_error(PARAMETER_PROBLEM,
90                            "ECN match: some option required");
91 }
92
93 /* Prints out the matchinfo. */
94 static void ecn_print(const void *ip, const struct xt_entry_match *match,
95                       int numeric)
96 {
97         const struct ipt_ecn_info *einfo =
98                 (const struct ipt_ecn_info *)match->data;
99
100         printf("ECN match ");
101
102         if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
103                 if (einfo->invert & IPT_ECN_OP_MATCH_ECE)
104                         fputc('!', stdout);
105                 printf("ECE ");
106         }
107
108         if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
109                 if (einfo->invert & IPT_ECN_OP_MATCH_CWR)
110                         fputc('!', stdout);
111                 printf("CWR ");
112         }
113
114         if (einfo->operation & IPT_ECN_OP_MATCH_IP) {
115                 if (einfo->invert & IPT_ECN_OP_MATCH_IP)
116                         fputc('!', stdout);
117                 printf("ECT=%d ", einfo->ip_ect);
118         }
119 }
120
121 /* Saves the union ipt_matchinfo in parsable form to stdout. */
122 static void ecn_save(const void *ip, const struct xt_entry_match *match)
123 {
124         const struct ipt_ecn_info *einfo =
125                 (const struct ipt_ecn_info *)match->data;
126         
127         if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
128                 if (einfo->invert & IPT_ECN_OP_MATCH_ECE)
129                         printf("! ");
130                 printf("--ecn-tcp-ece ");
131         }
132
133         if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
134                 if (einfo->invert & IPT_ECN_OP_MATCH_CWR)
135                         printf("! ");
136                 printf("--ecn-tcp-cwr ");
137         }
138
139         if (einfo->operation & IPT_ECN_OP_MATCH_IP) {
140                 if (einfo->invert & IPT_ECN_OP_MATCH_IP)
141                         printf("! ");
142                 printf("--ecn-ip-ect %d", einfo->ip_ect);
143         }
144 }
145
146 static struct xtables_match ecn_mt_reg = {
147     .name          = "ecn",
148     .version       = XTABLES_VERSION,
149     .family        = PF_INET,
150     .size          = XT_ALIGN(sizeof(struct ipt_ecn_info)),
151     .userspacesize = XT_ALIGN(sizeof(struct ipt_ecn_info)),
152     .help          = ecn_help,
153     .parse         = ecn_parse,
154     .final_check   = ecn_check,
155     .print         = ecn_print,
156     .save          = ecn_save,
157     .extra_opts    = ecn_opts,
158 };
159
160 void _init(void)
161 {
162         xtables_register_match(&ecn_mt_reg);
163 }