changing trunk/trunk to trunk
[iptables.git] / extensions / libxt_dscp.c
1 /* Shared library add-on to iptables for DSCP
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_dscp.c borrowed heavily from libipt_tos.c
8  *
9  * --class support added by Iain Barnes
10  * 
11  * For a list of DSCP codepoints see 
12  * http://www.iana.org/assignments/dscp-registry
13  *
14  */
15 #include <stdio.h>
16 #include <string.h>
17 #include <stdlib.h>
18 #include <getopt.h>
19
20 #include <xtables.h>
21 #include <linux/netfilter/x_tables.h>
22 #include <linux/netfilter/xt_dscp.h>
23
24 /* This is evil, but it's my code - HW*/
25 #include "dscp_helper.c"
26
27 static void dscp_help(void)
28 {
29         printf(
30 "dscp match options\n"
31 "[!] --dscp value               Match DSCP codepoint with numerical value\n"
32 "                               This value can be in decimal (ex: 32)\n"
33 "                               or in hex (ex: 0x20)\n"
34 "[!] --dscp-class name          Match the DiffServ class. This value may\n"
35 "                               be any of the BE,EF, AFxx or CSx classes\n"
36 "\n"
37 "                               These two options are mutually exclusive !\n");
38 }
39
40 static const struct option dscp_opts[] = {
41         { "dscp", 1, NULL, 'F' },
42         { "dscp-class", 1, NULL, 'G' },
43         { .name = NULL }
44 };
45
46 static void
47 parse_dscp(const char *s, struct xt_dscp_info *dinfo)
48 {
49         unsigned int dscp;
50        
51         if (string_to_number(s, 0, 255, &dscp) == -1)
52                 exit_error(PARAMETER_PROBLEM,
53                            "Invalid dscp `%s'\n", s);
54
55         if (dscp > XT_DSCP_MAX)
56                 exit_error(PARAMETER_PROBLEM,
57                            "DSCP `%d` out of range\n", dscp);
58
59         dinfo->dscp = (u_int8_t )dscp;
60         return;
61 }
62
63
64 static void
65 parse_class(const char *s, struct xt_dscp_info *dinfo)
66 {
67         unsigned int dscp = class_to_dscp(s);
68
69         /* Assign the value */
70         dinfo->dscp = (u_int8_t)dscp;
71 }
72
73
74 static int
75 dscp_parse(int c, char **argv, int invert, unsigned int *flags,
76            const void *entry, struct xt_entry_match **match)
77 {
78         struct xt_dscp_info *dinfo
79                 = (struct xt_dscp_info *)(*match)->data;
80
81         switch (c) {
82         case 'F':
83                 if (*flags)
84                         exit_error(PARAMETER_PROBLEM,
85                                    "DSCP match: Only use --dscp ONCE!");
86                 check_inverse(optarg, &invert, &optind, 0);
87                 parse_dscp(argv[optind-1], dinfo);
88                 if (invert)
89                         dinfo->invert = 1;
90                 *flags = 1;
91                 break;
92
93         case 'G':
94                 if (*flags)
95                         exit_error(PARAMETER_PROBLEM,
96                                         "DSCP match: Only use --dscp-class ONCE!");
97                 check_inverse(optarg, &invert, &optind, 0);
98                 parse_class(argv[optind - 1], dinfo);
99                 if (invert)
100                         dinfo->invert = 1;
101                 *flags = 1;
102                 break;
103
104         default:
105                 return 0;
106         }
107
108         return 1;
109 }
110
111 static void dscp_check(unsigned int flags)
112 {
113         if (!flags)
114                 exit_error(PARAMETER_PROBLEM,
115                            "DSCP match: Parameter --dscp is required");
116 }
117
118 static void
119 print_dscp(u_int8_t dscp, int invert, int numeric)
120 {
121         if (invert)
122                 fputc('!', stdout);
123
124         printf("0x%02x ", dscp);
125 }
126
127 /* Prints out the matchinfo. */
128 static void
129 dscp_print(const void *ip, const struct xt_entry_match *match, int numeric)
130 {
131         const struct xt_dscp_info *dinfo =
132                 (const struct xt_dscp_info *)match->data;
133         printf("DSCP match ");
134         print_dscp(dinfo->dscp, dinfo->invert, numeric);
135 }
136
137 /* Saves the union ipt_matchinfo in parsable form to stdout. */
138 static void dscp_save(const void *ip, const struct xt_entry_match *match)
139 {
140         const struct xt_dscp_info *dinfo =
141                 (const struct xt_dscp_info *)match->data;
142
143         printf("--dscp ");
144         print_dscp(dinfo->dscp, dinfo->invert, 1);
145 }
146
147 static struct xtables_match dscp_match = {
148         .family         = AF_INET,
149         .name           = "dscp",
150         .version        = XTABLES_VERSION,
151         .size           = XT_ALIGN(sizeof(struct xt_dscp_info)),
152         .userspacesize  = XT_ALIGN(sizeof(struct xt_dscp_info)),
153         .help           = dscp_help,
154         .parse          = dscp_parse,
155         .final_check    = dscp_check,
156         .print          = dscp_print,
157         .save           = dscp_save,
158         .extra_opts     = dscp_opts,
159 };
160
161 static struct xtables_match dscp_match6 = {
162         .family         = AF_INET6,
163         .name           = "dscp",
164         .version        = XTABLES_VERSION,
165         .size           = XT_ALIGN(sizeof(struct xt_dscp_info)),
166         .userspacesize  = XT_ALIGN(sizeof(struct xt_dscp_info)),
167         .help           = dscp_help,
168         .parse          = dscp_parse,
169         .final_check    = dscp_check,
170         .print          = dscp_print,
171         .save           = dscp_save,
172         .extra_opts     = dscp_opts,
173 };
174
175 void _init(void)
176 {
177         xtables_register_match(&dscp_match);
178         xtables_register_match(&dscp_match6);
179 }