libxt_dccp.c revision 500f483fff529dcd88ec96b9d5054be6cd6363a0
1/* 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 */ 8#include <stdio.h> 9#include <string.h> 10#include <stdlib.h> 11#include <getopt.h> 12#include <netdb.h> 13#include <ctype.h> 14 15#include <xtables.h> 16#include <linux/dccp.h> 17#include <linux/netfilter/x_tables.h> 18#include <linux/netfilter/xt_dccp.h> 19 20#if 0 21#define DEBUGP(format, first...) printf(format, ##first) 22#define static 23#else 24#define DEBUGP(format, fist...) 25#endif 26 27/* Initialize the match. */ 28static void 29init(struct xt_entry_match *m) 30{ 31 struct xt_dccp_info *einfo = (struct xt_dccp_info *)m->data; 32 33 memset(einfo, 0, sizeof(struct xt_dccp_info)); 34} 35 36static void help(void) 37{ 38 printf( 39"DCCP match v%s options\n" 40" --source-port [!] port[:port] match source port(s)\n" 41" --sport ...\n" 42" --destination-port [!] port[:port] match destination port(s)\n" 43" --dport ...\n" 44, 45 IPTABLES_VERSION); 46} 47 48static const struct option opts[] = { 49 { .name = "source-port", .has_arg = 1, .val = '1' }, 50 { .name = "sport", .has_arg = 1, .val = '1' }, 51 { .name = "destination-port", .has_arg = 1, .val = '2' }, 52 { .name = "dport", .has_arg = 1, .val = '2' }, 53 { .name = "dccp-types", .has_arg = 1, .val = '3' }, 54 { .name = "dccp-option", .has_arg = 1, .val = '4' }, 55 { } 56}; 57 58static void 59parse_dccp_ports(const char *portstring, 60 u_int16_t *ports) 61{ 62 char *buffer; 63 char *cp; 64 65 buffer = strdup(portstring); 66 DEBUGP("%s\n", portstring); 67 if ((cp = strchr(buffer, ':')) == NULL) { 68 ports[0] = ports[1] = parse_port(buffer, "dccp"); 69 } 70 else { 71 *cp = '\0'; 72 cp++; 73 74 ports[0] = buffer[0] ? parse_port(buffer, "dccp") : 0; 75 ports[1] = cp[0] ? parse_port(cp, "dccp") : 0xFFFF; 76 77 if (ports[0] > ports[1]) 78 exit_error(PARAMETER_PROBLEM, 79 "invalid portrange (min > max)"); 80 } 81 free(buffer); 82} 83 84static char *dccp_pkt_types[] = { 85 [DCCP_PKT_REQUEST] = "REQUEST", 86 [DCCP_PKT_RESPONSE] = "RESPONSE", 87 [DCCP_PKT_DATA] = "DATA", 88 [DCCP_PKT_ACK] = "ACK", 89 [DCCP_PKT_DATAACK] = "DATAACK", 90 [DCCP_PKT_CLOSEREQ] = "CLOSEREQ", 91 [DCCP_PKT_CLOSE] = "CLOSE", 92 [DCCP_PKT_RESET] = "RESET", 93 [DCCP_PKT_SYNC] = "SYNC", 94 [DCCP_PKT_SYNCACK] = "SYNCACK", 95 [DCCP_PKT_INVALID] = "INVALID", 96}; 97 98static u_int16_t 99parse_dccp_types(const char *typestring) 100{ 101 u_int16_t typemask = 0; 102 char *ptr, *buffer; 103 104 buffer = strdup(typestring); 105 106 for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) { 107 unsigned int i; 108 for (i = 0; i < sizeof(dccp_pkt_types)/sizeof(char *); i++) { 109 if (!strcasecmp(dccp_pkt_types[i], ptr)) { 110 typemask |= (1 << i); 111 break; 112 } 113 } 114 if (i == sizeof(dccp_pkt_types)/sizeof(char *)) 115 exit_error(PARAMETER_PROBLEM, 116 "Unknown DCCP type `%s'", ptr); 117 } 118 119 free(buffer); 120 return typemask; 121} 122 123static u_int8_t parse_dccp_option(char *optstring) 124{ 125 unsigned int ret; 126 127 if (string_to_number(optstring, 1, 255, &ret) == -1) 128 exit_error(PARAMETER_PROBLEM, "Bad DCCP option `%s'", 129 optstring); 130 131 return (u_int8_t)ret; 132} 133 134static int 135parse(int c, char **argv, int invert, unsigned int *flags, 136 const void *entry, 137 struct xt_entry_match **match) 138{ 139 struct xt_dccp_info *einfo 140 = (struct xt_dccp_info *)(*match)->data; 141 142 switch (c) { 143 case '1': 144 if (*flags & XT_DCCP_SRC_PORTS) 145 exit_error(PARAMETER_PROBLEM, 146 "Only one `--source-port' allowed"); 147 einfo->flags |= XT_DCCP_SRC_PORTS; 148 check_inverse(optarg, &invert, &optind, 0); 149 parse_dccp_ports(argv[optind-1], einfo->spts); 150 if (invert) 151 einfo->invflags |= XT_DCCP_SRC_PORTS; 152 *flags |= XT_DCCP_SRC_PORTS; 153 break; 154 155 case '2': 156 if (*flags & XT_DCCP_DEST_PORTS) 157 exit_error(PARAMETER_PROBLEM, 158 "Only one `--destination-port' allowed"); 159 einfo->flags |= XT_DCCP_DEST_PORTS; 160 check_inverse(optarg, &invert, &optind, 0); 161 parse_dccp_ports(argv[optind-1], einfo->dpts); 162 if (invert) 163 einfo->invflags |= XT_DCCP_DEST_PORTS; 164 *flags |= XT_DCCP_DEST_PORTS; 165 break; 166 167 case '3': 168 if (*flags & XT_DCCP_TYPE) 169 exit_error(PARAMETER_PROBLEM, 170 "Only one `--dccp-types' allowed"); 171 einfo->flags |= XT_DCCP_TYPE; 172 check_inverse(optarg, &invert, &optind, 0); 173 einfo->typemask = parse_dccp_types(argv[optind-1]); 174 if (invert) 175 einfo->invflags |= XT_DCCP_TYPE; 176 *flags |= XT_DCCP_TYPE; 177 break; 178 179 case '4': 180 if (*flags & XT_DCCP_OPTION) 181 exit_error(PARAMETER_PROBLEM, 182 "Only one `--dccp-option' allowed"); 183 einfo->flags |= XT_DCCP_OPTION; 184 check_inverse(optarg, &invert, &optind, 0); 185 einfo->option = parse_dccp_option(argv[optind-1]); 186 if (invert) 187 einfo->invflags |= XT_DCCP_OPTION; 188 *flags |= XT_DCCP_OPTION; 189 break; 190 default: 191 return 0; 192 } 193 return 1; 194} 195 196static void 197final_check(unsigned int flags) 198{ 199} 200 201static char * 202port_to_service(int port) 203{ 204 struct servent *service; 205 206 if ((service = getservbyport(htons(port), "dccp"))) 207 return service->s_name; 208 209 return NULL; 210} 211 212static void 213print_port(u_int16_t port, int numeric) 214{ 215 char *service; 216 217 if (numeric || (service = port_to_service(port)) == NULL) 218 printf("%u", port); 219 else 220 printf("%s", service); 221} 222 223static void 224print_ports(const char *name, u_int16_t min, u_int16_t max, 225 int invert, int numeric) 226{ 227 const char *inv = invert ? "!" : ""; 228 229 if (min != 0 || max != 0xFFFF || invert) { 230 printf("%s", name); 231 if (min == max) { 232 printf(":%s", inv); 233 print_port(min, numeric); 234 } else { 235 printf("s:%s", inv); 236 print_port(min, numeric); 237 printf(":"); 238 print_port(max, numeric); 239 } 240 printf(" "); 241 } 242} 243 244static void 245print_types(u_int16_t types, int inverted, int numeric) 246{ 247 int have_type = 0; 248 249 if (inverted) 250 printf("! "); 251 252 while (types) { 253 unsigned int i; 254 255 for (i = 0; !(types & (1 << i)); i++); 256 257 if (have_type) 258 printf(","); 259 else 260 have_type = 1; 261 262 if (numeric) 263 printf("%u", i); 264 else 265 printf("%s", dccp_pkt_types[i]); 266 267 types &= ~(1 << i); 268 } 269} 270 271static void 272print_option(u_int8_t option, int invert, int numeric) 273{ 274 if (option || invert) 275 printf("option=%s%u ", invert ? "!" : "", option); 276} 277 278/* Prints out the matchinfo. */ 279static void 280print(const void *ip, 281 const struct xt_entry_match *match, 282 int numeric) 283{ 284 const struct xt_dccp_info *einfo = 285 (const struct xt_dccp_info *)match->data; 286 287 printf("dccp "); 288 289 if (einfo->flags & XT_DCCP_SRC_PORTS) { 290 print_ports("spt", einfo->spts[0], einfo->spts[1], 291 einfo->invflags & XT_DCCP_SRC_PORTS, 292 numeric); 293 } 294 295 if (einfo->flags & XT_DCCP_DEST_PORTS) { 296 print_ports("dpt", einfo->dpts[0], einfo->dpts[1], 297 einfo->invflags & XT_DCCP_DEST_PORTS, 298 numeric); 299 } 300 301 if (einfo->flags & XT_DCCP_TYPE) { 302 print_types(einfo->typemask, 303 einfo->invflags & XT_DCCP_TYPE, 304 numeric); 305 } 306 307 if (einfo->flags & XT_DCCP_OPTION) { 308 print_option(einfo->option, 309 einfo->invflags & XT_DCCP_OPTION, numeric); 310 } 311} 312 313/* Saves the union ipt_matchinfo in parsable form to stdout. */ 314static void 315save(const void *ip, 316 const struct xt_entry_match *match) 317{ 318 const struct xt_dccp_info *einfo = 319 (const struct xt_dccp_info *)match->data; 320 321 if (einfo->flags & XT_DCCP_SRC_PORTS) { 322 if (einfo->invflags & XT_DCCP_SRC_PORTS) 323 printf("! "); 324 if (einfo->spts[0] != einfo->spts[1]) 325 printf("--sport %u:%u ", 326 einfo->spts[0], einfo->spts[1]); 327 else 328 printf("--sport %u ", einfo->spts[0]); 329 } 330 331 if (einfo->flags & XT_DCCP_DEST_PORTS) { 332 if (einfo->invflags & XT_DCCP_DEST_PORTS) 333 printf("! "); 334 if (einfo->dpts[0] != einfo->dpts[1]) 335 printf("--dport %u:%u ", 336 einfo->dpts[0], einfo->dpts[1]); 337 else 338 printf("--dport %u ", einfo->dpts[0]); 339 } 340 341 if (einfo->flags & XT_DCCP_TYPE) { 342 printf("--dccp-type "); 343 print_types(einfo->typemask, einfo->invflags & XT_DCCP_TYPE,0); 344 } 345 346 if (einfo->flags & XT_DCCP_OPTION) { 347 printf("--dccp-option %s%u ", 348 einfo->typemask & XT_DCCP_OPTION ? "! " : "", 349 einfo->option); 350 } 351} 352 353static struct xtables_match dccp = 354{ 355 .name = "dccp", 356 .family = AF_INET, 357 .version = IPTABLES_VERSION, 358 .size = XT_ALIGN(sizeof(struct xt_dccp_info)), 359 .userspacesize = XT_ALIGN(sizeof(struct xt_dccp_info)), 360 .help = &help, 361 .init = &init, 362 .parse = &parse, 363 .final_check = &final_check, 364 .print = &print, 365 .save = &save, 366 .extra_opts = opts 367}; 368 369static struct xtables_match dccp6 = 370{ 371 .name = "dccp", 372 .family = AF_INET6, 373 .version = IPTABLES_VERSION, 374 .size = XT_ALIGN(sizeof(struct xt_dccp_info)), 375 .userspacesize = XT_ALIGN(sizeof(struct xt_dccp_info)), 376 .help = &help, 377 .init = &init, 378 .parse = &parse, 379 .final_check = &final_check, 380 .print = &print, 381 .save = &save, 382 .extra_opts = opts 383}; 384 385void _init(void) 386{ 387 xtables_register_match(&dccp); 388 xtables_register_match(&dccp6); 389} 390 391