libxt_dccp.c revision 830132ac9c0d270bf9dcfe85c2464e3fe8c73fb9
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 char * 197port_to_service(int port) 198{ 199 struct servent *service; 200 201 if ((service = getservbyport(htons(port), "dccp"))) 202 return service->s_name; 203 204 return NULL; 205} 206 207static void 208print_port(u_int16_t port, int numeric) 209{ 210 char *service; 211 212 if (numeric || (service = port_to_service(port)) == NULL) 213 printf("%u", port); 214 else 215 printf("%s", service); 216} 217 218static void 219print_ports(const char *name, u_int16_t min, u_int16_t max, 220 int invert, int numeric) 221{ 222 const char *inv = invert ? "!" : ""; 223 224 if (min != 0 || max != 0xFFFF || invert) { 225 printf("%s", name); 226 if (min == max) { 227 printf(":%s", inv); 228 print_port(min, numeric); 229 } else { 230 printf("s:%s", inv); 231 print_port(min, numeric); 232 printf(":"); 233 print_port(max, numeric); 234 } 235 printf(" "); 236 } 237} 238 239static void 240print_types(u_int16_t types, int inverted, int numeric) 241{ 242 int have_type = 0; 243 244 if (inverted) 245 printf("! "); 246 247 while (types) { 248 unsigned int i; 249 250 for (i = 0; !(types & (1 << i)); i++); 251 252 if (have_type) 253 printf(","); 254 else 255 have_type = 1; 256 257 if (numeric) 258 printf("%u", i); 259 else 260 printf("%s", dccp_pkt_types[i]); 261 262 types &= ~(1 << i); 263 } 264} 265 266static void 267print_option(u_int8_t option, int invert, int numeric) 268{ 269 if (option || invert) 270 printf("option=%s%u ", invert ? "!" : "", option); 271} 272 273/* Prints out the matchinfo. */ 274static void 275print(const void *ip, 276 const struct xt_entry_match *match, 277 int numeric) 278{ 279 const struct xt_dccp_info *einfo = 280 (const struct xt_dccp_info *)match->data; 281 282 printf("dccp "); 283 284 if (einfo->flags & XT_DCCP_SRC_PORTS) { 285 print_ports("spt", einfo->spts[0], einfo->spts[1], 286 einfo->invflags & XT_DCCP_SRC_PORTS, 287 numeric); 288 } 289 290 if (einfo->flags & XT_DCCP_DEST_PORTS) { 291 print_ports("dpt", einfo->dpts[0], einfo->dpts[1], 292 einfo->invflags & XT_DCCP_DEST_PORTS, 293 numeric); 294 } 295 296 if (einfo->flags & XT_DCCP_TYPE) { 297 print_types(einfo->typemask, 298 einfo->invflags & XT_DCCP_TYPE, 299 numeric); 300 } 301 302 if (einfo->flags & XT_DCCP_OPTION) { 303 print_option(einfo->option, 304 einfo->invflags & XT_DCCP_OPTION, numeric); 305 } 306} 307 308/* Saves the union ipt_matchinfo in parsable form to stdout. */ 309static void 310save(const void *ip, 311 const struct xt_entry_match *match) 312{ 313 const struct xt_dccp_info *einfo = 314 (const struct xt_dccp_info *)match->data; 315 316 if (einfo->flags & XT_DCCP_SRC_PORTS) { 317 if (einfo->invflags & XT_DCCP_SRC_PORTS) 318 printf("! "); 319 if (einfo->spts[0] != einfo->spts[1]) 320 printf("--sport %u:%u ", 321 einfo->spts[0], einfo->spts[1]); 322 else 323 printf("--sport %u ", einfo->spts[0]); 324 } 325 326 if (einfo->flags & XT_DCCP_DEST_PORTS) { 327 if (einfo->invflags & XT_DCCP_DEST_PORTS) 328 printf("! "); 329 if (einfo->dpts[0] != einfo->dpts[1]) 330 printf("--dport %u:%u ", 331 einfo->dpts[0], einfo->dpts[1]); 332 else 333 printf("--dport %u ", einfo->dpts[0]); 334 } 335 336 if (einfo->flags & XT_DCCP_TYPE) { 337 printf("--dccp-type "); 338 print_types(einfo->typemask, einfo->invflags & XT_DCCP_TYPE,0); 339 } 340 341 if (einfo->flags & XT_DCCP_OPTION) { 342 printf("--dccp-option %s%u ", 343 einfo->typemask & XT_DCCP_OPTION ? "! " : "", 344 einfo->option); 345 } 346} 347 348static struct xtables_match dccp = 349{ 350 .name = "dccp", 351 .family = AF_INET, 352 .version = IPTABLES_VERSION, 353 .size = XT_ALIGN(sizeof(struct xt_dccp_info)), 354 .userspacesize = XT_ALIGN(sizeof(struct xt_dccp_info)), 355 .help = &help, 356 .init = &init, 357 .parse = &parse, 358 .print = &print, 359 .save = &save, 360 .extra_opts = opts 361}; 362 363static struct xtables_match dccp6 = 364{ 365 .name = "dccp", 366 .family = AF_INET6, 367 .version = IPTABLES_VERSION, 368 .size = XT_ALIGN(sizeof(struct xt_dccp_info)), 369 .userspacesize = XT_ALIGN(sizeof(struct xt_dccp_info)), 370 .help = &help, 371 .init = &init, 372 .parse = &parse, 373 .print = &print, 374 .save = &save, 375 .extra_opts = opts 376}; 377 378void _init(void) 379{ 380 xtables_register_match(&dccp); 381 xtables_register_match(&dccp6); 382} 383 384