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