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