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