1*a71a9546SAutomerger Merge Worker /* Shared library add-on to iptables for DCCP matching
2*a71a9546SAutomerger Merge Worker *
3*a71a9546SAutomerger Merge Worker * (C) 2005 by Harald Welte <[email protected]>
4*a71a9546SAutomerger Merge Worker *
5*a71a9546SAutomerger Merge Worker * This program is distributed under the terms of GNU GPL v2, 1991
6*a71a9546SAutomerger Merge Worker *
7*a71a9546SAutomerger Merge Worker */
8*a71a9546SAutomerger Merge Worker #include <stdint.h>
9*a71a9546SAutomerger Merge Worker #include <stdio.h>
10*a71a9546SAutomerger Merge Worker #include <string.h>
11*a71a9546SAutomerger Merge Worker #include <stdlib.h>
12*a71a9546SAutomerger Merge Worker #include <netdb.h>
13*a71a9546SAutomerger Merge Worker #include <arpa/inet.h>
14*a71a9546SAutomerger Merge Worker #include <xtables.h>
15*a71a9546SAutomerger Merge Worker #include <linux/dccp.h>
16*a71a9546SAutomerger Merge Worker #include <linux/netfilter/x_tables.h>
17*a71a9546SAutomerger Merge Worker #include <linux/netfilter/xt_dccp.h>
18*a71a9546SAutomerger Merge Worker
19*a71a9546SAutomerger Merge Worker #if 0
20*a71a9546SAutomerger Merge Worker #define DEBUGP(format, first...) printf(format, ##first)
21*a71a9546SAutomerger Merge Worker #define static
22*a71a9546SAutomerger Merge Worker #else
23*a71a9546SAutomerger Merge Worker #define DEBUGP(format, fist...)
24*a71a9546SAutomerger Merge Worker #endif
25*a71a9546SAutomerger Merge Worker
26*a71a9546SAutomerger Merge Worker enum {
27*a71a9546SAutomerger Merge Worker O_SOURCE_PORT = 0,
28*a71a9546SAutomerger Merge Worker O_DEST_PORT,
29*a71a9546SAutomerger Merge Worker O_DCCP_TYPES,
30*a71a9546SAutomerger Merge Worker O_DCCP_OPTION,
31*a71a9546SAutomerger Merge Worker };
32*a71a9546SAutomerger Merge Worker
dccp_help(void)33*a71a9546SAutomerger Merge Worker static void dccp_help(void)
34*a71a9546SAutomerger Merge Worker {
35*a71a9546SAutomerger Merge Worker printf(
36*a71a9546SAutomerger Merge Worker "dccp match options\n"
37*a71a9546SAutomerger Merge Worker "[!] --source-port port[:port] match source port(s)\n"
38*a71a9546SAutomerger Merge Worker " --sport ...\n"
39*a71a9546SAutomerger Merge Worker "[!] --destination-port port[:port] match destination port(s)\n"
40*a71a9546SAutomerger Merge Worker " --dport ...\n"
41*a71a9546SAutomerger Merge Worker "[!] --dccp-types type[,...] match when packet is one of the given types\n"
42*a71a9546SAutomerger Merge Worker "[!] --dccp-option option match if option (by number!) is set\n"
43*a71a9546SAutomerger Merge Worker );
44*a71a9546SAutomerger Merge Worker }
45*a71a9546SAutomerger Merge Worker
46*a71a9546SAutomerger Merge Worker #define s struct xt_dccp_info
47*a71a9546SAutomerger Merge Worker static const struct xt_option_entry dccp_opts[] = {
48*a71a9546SAutomerger Merge Worker {.name = "source-port", .id = O_SOURCE_PORT, .type = XTTYPE_PORTRC,
49*a71a9546SAutomerger Merge Worker .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, spts)},
50*a71a9546SAutomerger Merge Worker {.name = "sport", .id = O_SOURCE_PORT, .type = XTTYPE_PORTRC,
51*a71a9546SAutomerger Merge Worker .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, spts)},
52*a71a9546SAutomerger Merge Worker {.name = "destination-port", .id = O_DEST_PORT, .type = XTTYPE_PORTRC,
53*a71a9546SAutomerger Merge Worker .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, dpts)},
54*a71a9546SAutomerger Merge Worker {.name = "dport", .id = O_DEST_PORT, .type = XTTYPE_PORTRC,
55*a71a9546SAutomerger Merge Worker .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, dpts)},
56*a71a9546SAutomerger Merge Worker {.name = "dccp-types", .id = O_DCCP_TYPES, .type = XTTYPE_STRING,
57*a71a9546SAutomerger Merge Worker .flags = XTOPT_INVERT},
58*a71a9546SAutomerger Merge Worker {.name = "dccp-option", .id = O_DCCP_OPTION, .type = XTTYPE_UINT8,
59*a71a9546SAutomerger Merge Worker .min = 1, .max = UINT8_MAX, .flags = XTOPT_INVERT | XTOPT_PUT,
60*a71a9546SAutomerger Merge Worker XTOPT_POINTER(s, option)},
61*a71a9546SAutomerger Merge Worker XTOPT_TABLEEND,
62*a71a9546SAutomerger Merge Worker };
63*a71a9546SAutomerger Merge Worker #undef s
64*a71a9546SAutomerger Merge Worker
65*a71a9546SAutomerger Merge Worker static const char *const dccp_pkt_types[] = {
66*a71a9546SAutomerger Merge Worker [DCCP_PKT_REQUEST] = "REQUEST",
67*a71a9546SAutomerger Merge Worker [DCCP_PKT_RESPONSE] = "RESPONSE",
68*a71a9546SAutomerger Merge Worker [DCCP_PKT_DATA] = "DATA",
69*a71a9546SAutomerger Merge Worker [DCCP_PKT_ACK] = "ACK",
70*a71a9546SAutomerger Merge Worker [DCCP_PKT_DATAACK] = "DATAACK",
71*a71a9546SAutomerger Merge Worker [DCCP_PKT_CLOSEREQ] = "CLOSEREQ",
72*a71a9546SAutomerger Merge Worker [DCCP_PKT_CLOSE] = "CLOSE",
73*a71a9546SAutomerger Merge Worker [DCCP_PKT_RESET] = "RESET",
74*a71a9546SAutomerger Merge Worker [DCCP_PKT_SYNC] = "SYNC",
75*a71a9546SAutomerger Merge Worker [DCCP_PKT_SYNCACK] = "SYNCACK",
76*a71a9546SAutomerger Merge Worker [DCCP_PKT_INVALID] = "INVALID",
77*a71a9546SAutomerger Merge Worker };
78*a71a9546SAutomerger Merge Worker
79*a71a9546SAutomerger Merge Worker /* Bits for type values 11-15 */
80*a71a9546SAutomerger Merge Worker #define INVALID_OTHER_TYPE_MASK 0xf800
81*a71a9546SAutomerger Merge Worker
82*a71a9546SAutomerger Merge Worker static uint16_t
parse_dccp_types(const char * typestring)83*a71a9546SAutomerger Merge Worker parse_dccp_types(const char *typestring)
84*a71a9546SAutomerger Merge Worker {
85*a71a9546SAutomerger Merge Worker uint16_t typemask = 0;
86*a71a9546SAutomerger Merge Worker char *ptr, *buffer;
87*a71a9546SAutomerger Merge Worker
88*a71a9546SAutomerger Merge Worker buffer = xtables_strdup(typestring);
89*a71a9546SAutomerger Merge Worker
90*a71a9546SAutomerger Merge Worker for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) {
91*a71a9546SAutomerger Merge Worker unsigned int i;
92*a71a9546SAutomerger Merge Worker for (i = 0; i < ARRAY_SIZE(dccp_pkt_types); ++i)
93*a71a9546SAutomerger Merge Worker if (!strcasecmp(dccp_pkt_types[i], ptr)) {
94*a71a9546SAutomerger Merge Worker typemask |= (1 << i);
95*a71a9546SAutomerger Merge Worker break;
96*a71a9546SAutomerger Merge Worker }
97*a71a9546SAutomerger Merge Worker if (i == ARRAY_SIZE(dccp_pkt_types))
98*a71a9546SAutomerger Merge Worker xtables_error(PARAMETER_PROBLEM,
99*a71a9546SAutomerger Merge Worker "Unknown DCCP type `%s'", ptr);
100*a71a9546SAutomerger Merge Worker }
101*a71a9546SAutomerger Merge Worker if (typemask & (1 << DCCP_PKT_INVALID))
102*a71a9546SAutomerger Merge Worker typemask |= INVALID_OTHER_TYPE_MASK;
103*a71a9546SAutomerger Merge Worker
104*a71a9546SAutomerger Merge Worker
105*a71a9546SAutomerger Merge Worker free(buffer);
106*a71a9546SAutomerger Merge Worker return typemask;
107*a71a9546SAutomerger Merge Worker }
108*a71a9546SAutomerger Merge Worker
dccp_parse(struct xt_option_call * cb)109*a71a9546SAutomerger Merge Worker static void dccp_parse(struct xt_option_call *cb)
110*a71a9546SAutomerger Merge Worker {
111*a71a9546SAutomerger Merge Worker struct xt_dccp_info *einfo = cb->data;
112*a71a9546SAutomerger Merge Worker
113*a71a9546SAutomerger Merge Worker xtables_option_parse(cb);
114*a71a9546SAutomerger Merge Worker switch (cb->entry->id) {
115*a71a9546SAutomerger Merge Worker case O_SOURCE_PORT:
116*a71a9546SAutomerger Merge Worker einfo->flags |= XT_DCCP_SRC_PORTS;
117*a71a9546SAutomerger Merge Worker if (cb->invert)
118*a71a9546SAutomerger Merge Worker einfo->invflags |= XT_DCCP_SRC_PORTS;
119*a71a9546SAutomerger Merge Worker break;
120*a71a9546SAutomerger Merge Worker case O_DEST_PORT:
121*a71a9546SAutomerger Merge Worker einfo->flags |= XT_DCCP_DEST_PORTS;
122*a71a9546SAutomerger Merge Worker if (cb->invert)
123*a71a9546SAutomerger Merge Worker einfo->invflags |= XT_DCCP_DEST_PORTS;
124*a71a9546SAutomerger Merge Worker break;
125*a71a9546SAutomerger Merge Worker case O_DCCP_TYPES:
126*a71a9546SAutomerger Merge Worker einfo->flags |= XT_DCCP_TYPE;
127*a71a9546SAutomerger Merge Worker einfo->typemask = parse_dccp_types(cb->arg);
128*a71a9546SAutomerger Merge Worker if (cb->invert)
129*a71a9546SAutomerger Merge Worker einfo->invflags |= XT_DCCP_TYPE;
130*a71a9546SAutomerger Merge Worker break;
131*a71a9546SAutomerger Merge Worker case O_DCCP_OPTION:
132*a71a9546SAutomerger Merge Worker einfo->flags |= XT_DCCP_OPTION;
133*a71a9546SAutomerger Merge Worker if (cb->invert)
134*a71a9546SAutomerger Merge Worker einfo->invflags |= XT_DCCP_OPTION;
135*a71a9546SAutomerger Merge Worker break;
136*a71a9546SAutomerger Merge Worker }
137*a71a9546SAutomerger Merge Worker }
138*a71a9546SAutomerger Merge Worker
139*a71a9546SAutomerger Merge Worker static const char *
port_to_service(int port)140*a71a9546SAutomerger Merge Worker port_to_service(int port)
141*a71a9546SAutomerger Merge Worker {
142*a71a9546SAutomerger Merge Worker const struct servent *service;
143*a71a9546SAutomerger Merge Worker
144*a71a9546SAutomerger Merge Worker if ((service = getservbyport(htons(port), "dccp")))
145*a71a9546SAutomerger Merge Worker return service->s_name;
146*a71a9546SAutomerger Merge Worker
147*a71a9546SAutomerger Merge Worker return NULL;
148*a71a9546SAutomerger Merge Worker }
149*a71a9546SAutomerger Merge Worker
150*a71a9546SAutomerger Merge Worker static void
print_port(uint16_t port,int numeric)151*a71a9546SAutomerger Merge Worker print_port(uint16_t port, int numeric)
152*a71a9546SAutomerger Merge Worker {
153*a71a9546SAutomerger Merge Worker const char *service;
154*a71a9546SAutomerger Merge Worker
155*a71a9546SAutomerger Merge Worker if (numeric || (service = port_to_service(port)) == NULL)
156*a71a9546SAutomerger Merge Worker printf("%u", port);
157*a71a9546SAutomerger Merge Worker else
158*a71a9546SAutomerger Merge Worker printf("%s", service);
159*a71a9546SAutomerger Merge Worker }
160*a71a9546SAutomerger Merge Worker
161*a71a9546SAutomerger Merge Worker static void
print_ports(const char * name,uint16_t min,uint16_t max,int invert,int numeric)162*a71a9546SAutomerger Merge Worker print_ports(const char *name, uint16_t min, uint16_t max,
163*a71a9546SAutomerger Merge Worker int invert, int numeric)
164*a71a9546SAutomerger Merge Worker {
165*a71a9546SAutomerger Merge Worker const char *inv = invert ? "!" : "";
166*a71a9546SAutomerger Merge Worker
167*a71a9546SAutomerger Merge Worker if (min != 0 || max != 0xFFFF || invert) {
168*a71a9546SAutomerger Merge Worker printf(" %s", name);
169*a71a9546SAutomerger Merge Worker if (min == max) {
170*a71a9546SAutomerger Merge Worker printf(":%s", inv);
171*a71a9546SAutomerger Merge Worker print_port(min, numeric);
172*a71a9546SAutomerger Merge Worker } else {
173*a71a9546SAutomerger Merge Worker printf("s:%s", inv);
174*a71a9546SAutomerger Merge Worker print_port(min, numeric);
175*a71a9546SAutomerger Merge Worker printf(":");
176*a71a9546SAutomerger Merge Worker print_port(max, numeric);
177*a71a9546SAutomerger Merge Worker }
178*a71a9546SAutomerger Merge Worker }
179*a71a9546SAutomerger Merge Worker }
180*a71a9546SAutomerger Merge Worker
181*a71a9546SAutomerger Merge Worker static void
print_types(uint16_t types,int inverted,int numeric)182*a71a9546SAutomerger Merge Worker print_types(uint16_t types, int inverted, int numeric)
183*a71a9546SAutomerger Merge Worker {
184*a71a9546SAutomerger Merge Worker int have_type = 0;
185*a71a9546SAutomerger Merge Worker
186*a71a9546SAutomerger Merge Worker if (inverted)
187*a71a9546SAutomerger Merge Worker printf(" !");
188*a71a9546SAutomerger Merge Worker
189*a71a9546SAutomerger Merge Worker printf(" ");
190*a71a9546SAutomerger Merge Worker while (types) {
191*a71a9546SAutomerger Merge Worker unsigned int i;
192*a71a9546SAutomerger Merge Worker
193*a71a9546SAutomerger Merge Worker for (i = 0; !(types & (1 << i)); i++);
194*a71a9546SAutomerger Merge Worker
195*a71a9546SAutomerger Merge Worker if (have_type)
196*a71a9546SAutomerger Merge Worker printf(",");
197*a71a9546SAutomerger Merge Worker else
198*a71a9546SAutomerger Merge Worker have_type = 1;
199*a71a9546SAutomerger Merge Worker
200*a71a9546SAutomerger Merge Worker if (numeric)
201*a71a9546SAutomerger Merge Worker printf("%u", i);
202*a71a9546SAutomerger Merge Worker else {
203*a71a9546SAutomerger Merge Worker printf("%s", dccp_pkt_types[i]);
204*a71a9546SAutomerger Merge Worker
205*a71a9546SAutomerger Merge Worker if (i == DCCP_PKT_INVALID)
206*a71a9546SAutomerger Merge Worker break;
207*a71a9546SAutomerger Merge Worker }
208*a71a9546SAutomerger Merge Worker
209*a71a9546SAutomerger Merge Worker types &= ~(1 << i);
210*a71a9546SAutomerger Merge Worker }
211*a71a9546SAutomerger Merge Worker }
212*a71a9546SAutomerger Merge Worker
213*a71a9546SAutomerger Merge Worker static void
print_option(uint8_t option,int invert,int numeric)214*a71a9546SAutomerger Merge Worker print_option(uint8_t option, int invert, int numeric)
215*a71a9546SAutomerger Merge Worker {
216*a71a9546SAutomerger Merge Worker if (option || invert)
217*a71a9546SAutomerger Merge Worker printf(" option=%s%u", invert ? "!" : "", option);
218*a71a9546SAutomerger Merge Worker }
219*a71a9546SAutomerger Merge Worker
220*a71a9546SAutomerger Merge Worker static void
dccp_print(const void * ip,const struct xt_entry_match * match,int numeric)221*a71a9546SAutomerger Merge Worker dccp_print(const void *ip, const struct xt_entry_match *match, int numeric)
222*a71a9546SAutomerger Merge Worker {
223*a71a9546SAutomerger Merge Worker const struct xt_dccp_info *einfo =
224*a71a9546SAutomerger Merge Worker (const struct xt_dccp_info *)match->data;
225*a71a9546SAutomerger Merge Worker
226*a71a9546SAutomerger Merge Worker printf(" dccp");
227*a71a9546SAutomerger Merge Worker
228*a71a9546SAutomerger Merge Worker if (einfo->flags & XT_DCCP_SRC_PORTS) {
229*a71a9546SAutomerger Merge Worker print_ports("spt", einfo->spts[0], einfo->spts[1],
230*a71a9546SAutomerger Merge Worker einfo->invflags & XT_DCCP_SRC_PORTS,
231*a71a9546SAutomerger Merge Worker numeric);
232*a71a9546SAutomerger Merge Worker }
233*a71a9546SAutomerger Merge Worker
234*a71a9546SAutomerger Merge Worker if (einfo->flags & XT_DCCP_DEST_PORTS) {
235*a71a9546SAutomerger Merge Worker print_ports("dpt", einfo->dpts[0], einfo->dpts[1],
236*a71a9546SAutomerger Merge Worker einfo->invflags & XT_DCCP_DEST_PORTS,
237*a71a9546SAutomerger Merge Worker numeric);
238*a71a9546SAutomerger Merge Worker }
239*a71a9546SAutomerger Merge Worker
240*a71a9546SAutomerger Merge Worker if (einfo->flags & XT_DCCP_TYPE) {
241*a71a9546SAutomerger Merge Worker print_types(einfo->typemask,
242*a71a9546SAutomerger Merge Worker einfo->invflags & XT_DCCP_TYPE,
243*a71a9546SAutomerger Merge Worker numeric);
244*a71a9546SAutomerger Merge Worker }
245*a71a9546SAutomerger Merge Worker
246*a71a9546SAutomerger Merge Worker if (einfo->flags & XT_DCCP_OPTION) {
247*a71a9546SAutomerger Merge Worker print_option(einfo->option,
248*a71a9546SAutomerger Merge Worker einfo->invflags & XT_DCCP_OPTION, numeric);
249*a71a9546SAutomerger Merge Worker }
250*a71a9546SAutomerger Merge Worker }
251*a71a9546SAutomerger Merge Worker
dccp_save(const void * ip,const struct xt_entry_match * match)252*a71a9546SAutomerger Merge Worker static void dccp_save(const void *ip, const struct xt_entry_match *match)
253*a71a9546SAutomerger Merge Worker {
254*a71a9546SAutomerger Merge Worker const struct xt_dccp_info *einfo =
255*a71a9546SAutomerger Merge Worker (const struct xt_dccp_info *)match->data;
256*a71a9546SAutomerger Merge Worker
257*a71a9546SAutomerger Merge Worker if (einfo->flags & XT_DCCP_SRC_PORTS) {
258*a71a9546SAutomerger Merge Worker if (einfo->invflags & XT_DCCP_SRC_PORTS)
259*a71a9546SAutomerger Merge Worker printf(" !");
260*a71a9546SAutomerger Merge Worker if (einfo->spts[0] != einfo->spts[1])
261*a71a9546SAutomerger Merge Worker printf(" --sport %u:%u",
262*a71a9546SAutomerger Merge Worker einfo->spts[0], einfo->spts[1]);
263*a71a9546SAutomerger Merge Worker else
264*a71a9546SAutomerger Merge Worker printf(" --sport %u", einfo->spts[0]);
265*a71a9546SAutomerger Merge Worker }
266*a71a9546SAutomerger Merge Worker
267*a71a9546SAutomerger Merge Worker if (einfo->flags & XT_DCCP_DEST_PORTS) {
268*a71a9546SAutomerger Merge Worker if (einfo->invflags & XT_DCCP_DEST_PORTS)
269*a71a9546SAutomerger Merge Worker printf(" !");
270*a71a9546SAutomerger Merge Worker if (einfo->dpts[0] != einfo->dpts[1])
271*a71a9546SAutomerger Merge Worker printf(" --dport %u:%u",
272*a71a9546SAutomerger Merge Worker einfo->dpts[0], einfo->dpts[1]);
273*a71a9546SAutomerger Merge Worker else
274*a71a9546SAutomerger Merge Worker printf(" --dport %u", einfo->dpts[0]);
275*a71a9546SAutomerger Merge Worker }
276*a71a9546SAutomerger Merge Worker
277*a71a9546SAutomerger Merge Worker if (einfo->flags & XT_DCCP_TYPE) {
278*a71a9546SAutomerger Merge Worker printf("%s --dccp-types",
279*a71a9546SAutomerger Merge Worker einfo->invflags & XT_DCCP_TYPE ? " !" : "");
280*a71a9546SAutomerger Merge Worker print_types(einfo->typemask, false, 0);
281*a71a9546SAutomerger Merge Worker }
282*a71a9546SAutomerger Merge Worker
283*a71a9546SAutomerger Merge Worker if (einfo->flags & XT_DCCP_OPTION) {
284*a71a9546SAutomerger Merge Worker printf("%s --dccp-option %u",
285*a71a9546SAutomerger Merge Worker einfo->invflags & XT_DCCP_OPTION ? " !" : "",
286*a71a9546SAutomerger Merge Worker einfo->option);
287*a71a9546SAutomerger Merge Worker }
288*a71a9546SAutomerger Merge Worker }
289*a71a9546SAutomerger Merge Worker
290*a71a9546SAutomerger Merge Worker static const char *const dccp_pkt_types_xlate[] = {
291*a71a9546SAutomerger Merge Worker [DCCP_PKT_REQUEST] = "request",
292*a71a9546SAutomerger Merge Worker [DCCP_PKT_RESPONSE] = "response",
293*a71a9546SAutomerger Merge Worker [DCCP_PKT_DATA] = "data",
294*a71a9546SAutomerger Merge Worker [DCCP_PKT_ACK] = "ack",
295*a71a9546SAutomerger Merge Worker [DCCP_PKT_DATAACK] = "dataack",
296*a71a9546SAutomerger Merge Worker [DCCP_PKT_CLOSEREQ] = "closereq",
297*a71a9546SAutomerger Merge Worker [DCCP_PKT_CLOSE] = "close",
298*a71a9546SAutomerger Merge Worker [DCCP_PKT_RESET] = "reset",
299*a71a9546SAutomerger Merge Worker [DCCP_PKT_SYNC] = "sync",
300*a71a9546SAutomerger Merge Worker [DCCP_PKT_SYNCACK] = "syncack",
301*a71a9546SAutomerger Merge Worker [DCCP_PKT_INVALID] = "10-15",
302*a71a9546SAutomerger Merge Worker };
303*a71a9546SAutomerger Merge Worker
dccp_type_xlate(const struct xt_dccp_info * einfo,struct xt_xlate * xl)304*a71a9546SAutomerger Merge Worker static int dccp_type_xlate(const struct xt_dccp_info *einfo,
305*a71a9546SAutomerger Merge Worker struct xt_xlate *xl)
306*a71a9546SAutomerger Merge Worker {
307*a71a9546SAutomerger Merge Worker bool have_type = false, set_need = false;
308*a71a9546SAutomerger Merge Worker uint16_t types = einfo->typemask;
309*a71a9546SAutomerger Merge Worker
310*a71a9546SAutomerger Merge Worker if (types & INVALID_OTHER_TYPE_MASK) {
311*a71a9546SAutomerger Merge Worker types &= ~INVALID_OTHER_TYPE_MASK;
312*a71a9546SAutomerger Merge Worker types |= 1 << DCCP_PKT_INVALID;
313*a71a9546SAutomerger Merge Worker }
314*a71a9546SAutomerger Merge Worker
315*a71a9546SAutomerger Merge Worker if ((types != 0) && !(types == (types & -types))) {
316*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "{");
317*a71a9546SAutomerger Merge Worker set_need = true;
318*a71a9546SAutomerger Merge Worker }
319*a71a9546SAutomerger Merge Worker
320*a71a9546SAutomerger Merge Worker while (types) {
321*a71a9546SAutomerger Merge Worker unsigned int i;
322*a71a9546SAutomerger Merge Worker
323*a71a9546SAutomerger Merge Worker for (i = 0; !(types & (1 << i)); i++);
324*a71a9546SAutomerger Merge Worker
325*a71a9546SAutomerger Merge Worker if (have_type)
326*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, ", ");
327*a71a9546SAutomerger Merge Worker else
328*a71a9546SAutomerger Merge Worker have_type = true;
329*a71a9546SAutomerger Merge Worker
330*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "%s", dccp_pkt_types_xlate[i]);
331*a71a9546SAutomerger Merge Worker
332*a71a9546SAutomerger Merge Worker types &= ~(1 << i);
333*a71a9546SAutomerger Merge Worker }
334*a71a9546SAutomerger Merge Worker
335*a71a9546SAutomerger Merge Worker if (set_need)
336*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "}");
337*a71a9546SAutomerger Merge Worker
338*a71a9546SAutomerger Merge Worker return 1;
339*a71a9546SAutomerger Merge Worker }
340*a71a9546SAutomerger Merge Worker
dccp_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)341*a71a9546SAutomerger Merge Worker static int dccp_xlate(struct xt_xlate *xl,
342*a71a9546SAutomerger Merge Worker const struct xt_xlate_mt_params *params)
343*a71a9546SAutomerger Merge Worker {
344*a71a9546SAutomerger Merge Worker const struct xt_dccp_info *einfo =
345*a71a9546SAutomerger Merge Worker (const struct xt_dccp_info *)params->match->data;
346*a71a9546SAutomerger Merge Worker int ret = 1;
347*a71a9546SAutomerger Merge Worker
348*a71a9546SAutomerger Merge Worker if (einfo->flags & XT_DCCP_SRC_PORTS) {
349*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "dccp sport%s %u",
350*a71a9546SAutomerger Merge Worker einfo->invflags & XT_DCCP_SRC_PORTS ? " !=" : "",
351*a71a9546SAutomerger Merge Worker einfo->spts[0]);
352*a71a9546SAutomerger Merge Worker
353*a71a9546SAutomerger Merge Worker if (einfo->spts[0] != einfo->spts[1])
354*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "-%u", einfo->spts[1]);
355*a71a9546SAutomerger Merge Worker }
356*a71a9546SAutomerger Merge Worker
357*a71a9546SAutomerger Merge Worker if (einfo->flags & XT_DCCP_DEST_PORTS) {
358*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "dccp dport%s %u",
359*a71a9546SAutomerger Merge Worker einfo->invflags & XT_DCCP_DEST_PORTS ? " !=" : "",
360*a71a9546SAutomerger Merge Worker einfo->dpts[0]);
361*a71a9546SAutomerger Merge Worker
362*a71a9546SAutomerger Merge Worker if (einfo->dpts[0] != einfo->dpts[1])
363*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "-%u", einfo->dpts[1]);
364*a71a9546SAutomerger Merge Worker }
365*a71a9546SAutomerger Merge Worker
366*a71a9546SAutomerger Merge Worker if (einfo->flags & XT_DCCP_TYPE && einfo->typemask) {
367*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "dccp type%s ",
368*a71a9546SAutomerger Merge Worker einfo->invflags & XT_DCCP_TYPE ? " !=" : "");
369*a71a9546SAutomerger Merge Worker ret = dccp_type_xlate(einfo, xl);
370*a71a9546SAutomerger Merge Worker }
371*a71a9546SAutomerger Merge Worker
372*a71a9546SAutomerger Merge Worker /* FIXME: no dccp option support in nftables yet */
373*a71a9546SAutomerger Merge Worker if (einfo->flags & XT_DCCP_OPTION)
374*a71a9546SAutomerger Merge Worker ret = 0;
375*a71a9546SAutomerger Merge Worker
376*a71a9546SAutomerger Merge Worker return ret;
377*a71a9546SAutomerger Merge Worker }
378*a71a9546SAutomerger Merge Worker static struct xtables_match dccp_match = {
379*a71a9546SAutomerger Merge Worker .name = "dccp",
380*a71a9546SAutomerger Merge Worker .family = NFPROTO_UNSPEC,
381*a71a9546SAutomerger Merge Worker .version = XTABLES_VERSION,
382*a71a9546SAutomerger Merge Worker .size = XT_ALIGN(sizeof(struct xt_dccp_info)),
383*a71a9546SAutomerger Merge Worker .userspacesize = XT_ALIGN(sizeof(struct xt_dccp_info)),
384*a71a9546SAutomerger Merge Worker .help = dccp_help,
385*a71a9546SAutomerger Merge Worker .print = dccp_print,
386*a71a9546SAutomerger Merge Worker .save = dccp_save,
387*a71a9546SAutomerger Merge Worker .x6_parse = dccp_parse,
388*a71a9546SAutomerger Merge Worker .x6_options = dccp_opts,
389*a71a9546SAutomerger Merge Worker .xlate = dccp_xlate,
390*a71a9546SAutomerger Merge Worker };
391*a71a9546SAutomerger Merge Worker
_init(void)392*a71a9546SAutomerger Merge Worker void _init(void)
393*a71a9546SAutomerger Merge Worker {
394*a71a9546SAutomerger Merge Worker xtables_register_match(&dccp_match);
395*a71a9546SAutomerger Merge Worker }
396