blob: a35cabbda401e7a35bda5857edf1c9c45f3291c0 [file] [log] [blame]
Harald Weltee40b11d2005-08-06 21:13:04 +00001/* Shared library add-on to iptables for DCCP matching
2 *
3 * (C) 2005 by Harald Welte <laforge@netfilter.org>
4 *
5 * This program is distributed under the terms of GNU GPL v2, 1991
6 *
7 */
Jan Engelhardt753bbed2011-04-20 10:17:33 +02008#include <stdint.h>
Harald Weltee40b11d2005-08-06 21:13:04 +00009#include <stdio.h>
10#include <string.h>
11#include <stdlib.h>
Harald Weltee40b11d2005-08-06 21:13:04 +000012#include <netdb.h>
Jan Engelhardt753bbed2011-04-20 10:17:33 +020013#include <arpa/inet.h>
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +000014#include <xtables.h>
Harald Weltee40b11d2005-08-06 21:13:04 +000015#include <linux/dccp.h>
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +000016#include <linux/netfilter/x_tables.h>
17#include <linux/netfilter/xt_dccp.h>
Harald Weltee40b11d2005-08-06 21:13:04 +000018
19#if 0
20#define DEBUGP(format, first...) printf(format, ##first)
21#define static
22#else
23#define DEBUGP(format, fist...)
24#endif
25
Jan Engelhardt753bbed2011-04-20 10:17:33 +020026enum {
27 O_SOURCE_PORT = 0,
28 O_DEST_PORT,
29 O_DCCP_TYPES,
30 O_DCCP_OPTION,
31};
32
Jan Engelhardt181dead2007-10-04 16:27:07 +000033static void dccp_help(void)
Harald Weltee40b11d2005-08-06 21:13:04 +000034{
35 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020036"dccp match options\n"
Jan Engelhardt96727922008-08-13 14:42:41 +020037"[!] --source-port port[:port] match source port(s)\n"
Harald Weltee40b11d2005-08-06 21:13:04 +000038" --sport ...\n"
Jan Engelhardt96727922008-08-13 14:42:41 +020039"[!] --destination-port port[:port] match destination port(s)\n"
Jan Engelhardtca480662011-08-21 09:15:20 +020040" --dport ...\n"
41"[!] --dccp-types type[,...] match when packet is one of the given types\n"
42"[!] --dccp-option option match if option (by number!) is set\n"
43);
Harald Weltee40b11d2005-08-06 21:13:04 +000044}
45
Jan Engelhardt753bbed2011-04-20 10:17:33 +020046#define s struct xt_dccp_info
47static const struct xt_option_entry dccp_opts[] = {
48 {.name = "source-port", .id = O_SOURCE_PORT, .type = XTTYPE_PORTRC,
49 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, spts)},
50 {.name = "sport", .id = O_SOURCE_PORT, .type = XTTYPE_PORTRC,
51 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, spts)},
52 {.name = "destination-port", .id = O_DEST_PORT, .type = XTTYPE_PORTRC,
53 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, dpts)},
54 {.name = "dport", .id = O_DEST_PORT, .type = XTTYPE_PORTRC,
55 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, dpts)},
Jan Engelhardtd152d6a2011-08-21 09:05:31 +020056 {.name = "dccp-types", .id = O_DCCP_TYPES, .type = XTTYPE_STRING,
57 .flags = XTOPT_INVERT},
Jan Engelhardt753bbed2011-04-20 10:17:33 +020058 {.name = "dccp-option", .id = O_DCCP_OPTION, .type = XTTYPE_UINT8,
Jan Engelhardtd152d6a2011-08-21 09:05:31 +020059 .min = 1, .max = UINT8_MAX, .flags = XTOPT_INVERT | XTOPT_PUT,
Jan Engelhardt753bbed2011-04-20 10:17:33 +020060 XTOPT_POINTER(s, option)},
61 XTOPT_TABLEEND,
Harald Weltee40b11d2005-08-06 21:13:04 +000062};
Jan Engelhardt753bbed2011-04-20 10:17:33 +020063#undef s
Harald Weltee40b11d2005-08-06 21:13:04 +000064
Jan Engelhardt0e2abed2007-10-04 16:25:58 +000065static const char *const dccp_pkt_types[] = {
Harald Weltee40b11d2005-08-06 21:13:04 +000066 [DCCP_PKT_REQUEST] = "REQUEST",
67 [DCCP_PKT_RESPONSE] = "RESPONSE",
68 [DCCP_PKT_DATA] = "DATA",
69 [DCCP_PKT_ACK] = "ACK",
70 [DCCP_PKT_DATAACK] = "DATAACK",
71 [DCCP_PKT_CLOSEREQ] = "CLOSEREQ",
72 [DCCP_PKT_CLOSE] = "CLOSE",
73 [DCCP_PKT_RESET] = "RESET",
74 [DCCP_PKT_SYNC] = "SYNC",
75 [DCCP_PKT_SYNCACK] = "SYNCACK",
76 [DCCP_PKT_INVALID] = "INVALID",
77};
78
Jan Engelhardt7ac40522011-01-07 12:34:04 +010079static uint16_t
Harald Weltee40b11d2005-08-06 21:13:04 +000080parse_dccp_types(const char *typestring)
81{
Jan Engelhardt7ac40522011-01-07 12:34:04 +010082 uint16_t typemask = 0;
Harald Weltee40b11d2005-08-06 21:13:04 +000083 char *ptr, *buffer;
84
85 buffer = strdup(typestring);
86
87 for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) {
88 unsigned int i;
Jan Engelhardt2c69b552009-04-30 19:32:02 +020089 for (i = 0; i < ARRAY_SIZE(dccp_pkt_types); ++i)
Harald Weltee40b11d2005-08-06 21:13:04 +000090 if (!strcasecmp(dccp_pkt_types[i], ptr)) {
91 typemask |= (1 << i);
92 break;
93 }
Jan Engelhardt2c69b552009-04-30 19:32:02 +020094 if (i == ARRAY_SIZE(dccp_pkt_types))
Jan Engelhardt1829ed42009-02-21 03:29:44 +010095 xtables_error(PARAMETER_PROBLEM,
Harald Weltee40b11d2005-08-06 21:13:04 +000096 "Unknown DCCP type `%s'", ptr);
97 }
98
99 free(buffer);
100 return typemask;
101}
102
Jan Engelhardt753bbed2011-04-20 10:17:33 +0200103static void dccp_parse(struct xt_option_call *cb)
Harald Weltee40b11d2005-08-06 21:13:04 +0000104{
Jan Engelhardt753bbed2011-04-20 10:17:33 +0200105 struct xt_dccp_info *einfo = cb->data;
Harald Weltee40b11d2005-08-06 21:13:04 +0000106
Jan Engelhardt753bbed2011-04-20 10:17:33 +0200107 xtables_option_parse(cb);
108 switch (cb->entry->id) {
109 case O_SOURCE_PORT:
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000110 einfo->flags |= XT_DCCP_SRC_PORTS;
Jan Engelhardt753bbed2011-04-20 10:17:33 +0200111 if (cb->invert)
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000112 einfo->invflags |= XT_DCCP_SRC_PORTS;
Harald Weltee40b11d2005-08-06 21:13:04 +0000113 break;
Jan Engelhardt753bbed2011-04-20 10:17:33 +0200114 case O_DEST_PORT:
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000115 einfo->flags |= XT_DCCP_DEST_PORTS;
Jan Engelhardt753bbed2011-04-20 10:17:33 +0200116 if (cb->invert)
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000117 einfo->invflags |= XT_DCCP_DEST_PORTS;
Harald Weltee40b11d2005-08-06 21:13:04 +0000118 break;
Jan Engelhardt753bbed2011-04-20 10:17:33 +0200119 case O_DCCP_TYPES:
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000120 einfo->flags |= XT_DCCP_TYPE;
Jan Engelhardt753bbed2011-04-20 10:17:33 +0200121 einfo->typemask = parse_dccp_types(cb->arg);
122 if (cb->invert)
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000123 einfo->invflags |= XT_DCCP_TYPE;
Harald Weltee40b11d2005-08-06 21:13:04 +0000124 break;
Jan Engelhardt753bbed2011-04-20 10:17:33 +0200125 case O_DCCP_OPTION:
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000126 einfo->flags |= XT_DCCP_OPTION;
Jan Engelhardt753bbed2011-04-20 10:17:33 +0200127 if (cb->invert)
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000128 einfo->invflags |= XT_DCCP_OPTION;
Harald Weltee40b11d2005-08-06 21:13:04 +0000129 break;
Harald Weltee40b11d2005-08-06 21:13:04 +0000130 }
Harald Weltee40b11d2005-08-06 21:13:04 +0000131}
132
Jan Engelhardtdd6e4b92011-05-07 00:05:24 +0200133static const char *
Harald Weltee40b11d2005-08-06 21:13:04 +0000134port_to_service(int port)
135{
Jan Engelhardtdd6e4b92011-05-07 00:05:24 +0200136 const struct servent *service;
Harald Weltee40b11d2005-08-06 21:13:04 +0000137
138 if ((service = getservbyport(htons(port), "dccp")))
139 return service->s_name;
140
141 return NULL;
142}
143
144static void
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100145print_port(uint16_t port, int numeric)
Harald Weltee40b11d2005-08-06 21:13:04 +0000146{
Jan Engelhardtdd6e4b92011-05-07 00:05:24 +0200147 const char *service;
Harald Weltee40b11d2005-08-06 21:13:04 +0000148
149 if (numeric || (service = port_to_service(port)) == NULL)
150 printf("%u", port);
151 else
152 printf("%s", service);
153}
154
155static void
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100156print_ports(const char *name, uint16_t min, uint16_t max,
Harald Weltee40b11d2005-08-06 21:13:04 +0000157 int invert, int numeric)
158{
159 const char *inv = invert ? "!" : "";
160
161 if (min != 0 || max != 0xFFFF || invert) {
Jan Engelhardt73866352010-12-18 02:04:59 +0100162 printf(" %s", name);
Harald Weltee40b11d2005-08-06 21:13:04 +0000163 if (min == max) {
164 printf(":%s", inv);
165 print_port(min, numeric);
166 } else {
167 printf("s:%s", inv);
168 print_port(min, numeric);
169 printf(":");
170 print_port(max, numeric);
171 }
Harald Weltee40b11d2005-08-06 21:13:04 +0000172 }
173}
174
175static void
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100176print_types(uint16_t types, int inverted, int numeric)
Harald Weltee40b11d2005-08-06 21:13:04 +0000177{
178 int have_type = 0;
179
180 if (inverted)
Jan Engelhardt73866352010-12-18 02:04:59 +0100181 printf(" !");
Harald Weltee40b11d2005-08-06 21:13:04 +0000182
Jan Engelhardt73866352010-12-18 02:04:59 +0100183 printf(" ");
Harald Weltee40b11d2005-08-06 21:13:04 +0000184 while (types) {
185 unsigned int i;
186
187 for (i = 0; !(types & (1 << i)); i++);
188
189 if (have_type)
190 printf(",");
191 else
192 have_type = 1;
193
194 if (numeric)
195 printf("%u", i);
196 else
197 printf("%s", dccp_pkt_types[i]);
198
199 types &= ~(1 << i);
200 }
201}
202
203static void
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100204print_option(uint8_t option, int invert, int numeric)
Harald Weltee40b11d2005-08-06 21:13:04 +0000205{
206 if (option || invert)
Jan Engelhardt73866352010-12-18 02:04:59 +0100207 printf(" option=%s%u", invert ? "!" : "", option);
Harald Weltee40b11d2005-08-06 21:13:04 +0000208}
209
Harald Weltee40b11d2005-08-06 21:13:04 +0000210static void
Jan Engelhardt181dead2007-10-04 16:27:07 +0000211dccp_print(const void *ip, const struct xt_entry_match *match, int numeric)
Harald Weltee40b11d2005-08-06 21:13:04 +0000212{
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000213 const struct xt_dccp_info *einfo =
214 (const struct xt_dccp_info *)match->data;
Harald Weltee40b11d2005-08-06 21:13:04 +0000215
Jan Engelhardt73866352010-12-18 02:04:59 +0100216 printf(" dccp");
Harald Weltee40b11d2005-08-06 21:13:04 +0000217
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000218 if (einfo->flags & XT_DCCP_SRC_PORTS) {
Harald Weltee40b11d2005-08-06 21:13:04 +0000219 print_ports("spt", einfo->spts[0], einfo->spts[1],
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000220 einfo->invflags & XT_DCCP_SRC_PORTS,
Harald Weltee40b11d2005-08-06 21:13:04 +0000221 numeric);
222 }
223
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000224 if (einfo->flags & XT_DCCP_DEST_PORTS) {
Harald Weltee40b11d2005-08-06 21:13:04 +0000225 print_ports("dpt", einfo->dpts[0], einfo->dpts[1],
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000226 einfo->invflags & XT_DCCP_DEST_PORTS,
Harald Weltee40b11d2005-08-06 21:13:04 +0000227 numeric);
228 }
229
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000230 if (einfo->flags & XT_DCCP_TYPE) {
Harald Weltee40b11d2005-08-06 21:13:04 +0000231 print_types(einfo->typemask,
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000232 einfo->invflags & XT_DCCP_TYPE,
Harald Weltee40b11d2005-08-06 21:13:04 +0000233 numeric);
234 }
235
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000236 if (einfo->flags & XT_DCCP_OPTION) {
Harald Weltee40b11d2005-08-06 21:13:04 +0000237 print_option(einfo->option,
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000238 einfo->invflags & XT_DCCP_OPTION, numeric);
Harald Weltee40b11d2005-08-06 21:13:04 +0000239 }
240}
241
Jan Engelhardt181dead2007-10-04 16:27:07 +0000242static void dccp_save(const void *ip, const struct xt_entry_match *match)
Harald Weltee40b11d2005-08-06 21:13:04 +0000243{
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000244 const struct xt_dccp_info *einfo =
245 (const struct xt_dccp_info *)match->data;
Harald Weltee40b11d2005-08-06 21:13:04 +0000246
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000247 if (einfo->flags & XT_DCCP_SRC_PORTS) {
248 if (einfo->invflags & XT_DCCP_SRC_PORTS)
Jan Engelhardt73866352010-12-18 02:04:59 +0100249 printf(" !");
Harald Weltee40b11d2005-08-06 21:13:04 +0000250 if (einfo->spts[0] != einfo->spts[1])
Jan Engelhardt73866352010-12-18 02:04:59 +0100251 printf(" --sport %u:%u",
Harald Weltee40b11d2005-08-06 21:13:04 +0000252 einfo->spts[0], einfo->spts[1]);
253 else
Jan Engelhardt73866352010-12-18 02:04:59 +0100254 printf(" --sport %u", einfo->spts[0]);
Harald Weltee40b11d2005-08-06 21:13:04 +0000255 }
256
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000257 if (einfo->flags & XT_DCCP_DEST_PORTS) {
258 if (einfo->invflags & XT_DCCP_DEST_PORTS)
Jan Engelhardt73866352010-12-18 02:04:59 +0100259 printf(" !");
Harald Weltee40b11d2005-08-06 21:13:04 +0000260 if (einfo->dpts[0] != einfo->dpts[1])
Jan Engelhardt73866352010-12-18 02:04:59 +0100261 printf(" --dport %u:%u",
Harald Weltee40b11d2005-08-06 21:13:04 +0000262 einfo->dpts[0], einfo->dpts[1]);
263 else
Jan Engelhardt73866352010-12-18 02:04:59 +0100264 printf(" --dport %u", einfo->dpts[0]);
Harald Weltee40b11d2005-08-06 21:13:04 +0000265 }
266
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000267 if (einfo->flags & XT_DCCP_TYPE) {
Jan Engelhardtf677e7b2011-08-21 09:12:27 +0200268 printf("%s --dccp-types",
Jan Engelhardt7e66a652011-08-21 09:08:04 +0200269 einfo->invflags & XT_DCCP_TYPE ? " !" : "");
270 print_types(einfo->typemask, false, 0);
Harald Weltee40b11d2005-08-06 21:13:04 +0000271 }
272
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000273 if (einfo->flags & XT_DCCP_OPTION) {
Jan Engelhardt7e66a652011-08-21 09:08:04 +0200274 printf("%s --dccp-option %u",
Jan Engelhardtf17fd482011-08-21 09:39:21 +0200275 einfo->invflags & XT_DCCP_OPTION ? " !" : "",
Harald Weltee40b11d2005-08-06 21:13:04 +0000276 einfo->option);
277 }
278}
279
Jan Engelhardt181dead2007-10-04 16:27:07 +0000280static struct xtables_match dccp_match = {
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000281 .name = "dccp",
Jan Engelhardtc5e85732009-06-12 20:55:44 +0200282 .family = NFPROTO_UNSPEC,
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200283 .version = XTABLES_VERSION,
Yasuyuki KOZAKAI3c96c8e2007-07-24 07:19:41 +0000284 .size = XT_ALIGN(sizeof(struct xt_dccp_info)),
285 .userspacesize = XT_ALIGN(sizeof(struct xt_dccp_info)),
Jan Engelhardt181dead2007-10-04 16:27:07 +0000286 .help = dccp_help,
Jan Engelhardt181dead2007-10-04 16:27:07 +0000287 .print = dccp_print,
288 .save = dccp_save,
Jan Engelhardt753bbed2011-04-20 10:17:33 +0200289 .x6_parse = dccp_parse,
290 .x6_options = dccp_opts,
Harald Weltee40b11d2005-08-06 21:13:04 +0000291};
292
293void _init(void)
294{
Jan Engelhardt181dead2007-10-04 16:27:07 +0000295 xtables_register_match(&dccp_match);
Harald Weltee40b11d2005-08-06 21:13:04 +0000296}