libxt_dccp.c revision bf97128c7262f17a02fec41cdae75b472ba77f88
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] = xtables_parse_port(buffer, "dccp"); 66 } 67 else { 68 *cp = '\0'; 69 cp++; 70 71 ports[0] = buffer[0] ? xtables_parse_port(buffer, "dccp") : 0; 72 ports[1] = cp[0] ? xtables_parse_port(cp, "dccp") : 0xFFFF; 73 74 if (ports[0] > ports[1]) 75 xtables_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 < ARRAY_SIZE(dccp_pkt_types); ++i) 106 if (!strcasecmp(dccp_pkt_types[i], ptr)) { 107 typemask |= (1 << i); 108 break; 109 } 110 if (i == ARRAY_SIZE(dccp_pkt_types)) 111 xtables_error(PARAMETER_PROBLEM, 112 "Unknown DCCP type `%s'", ptr); 113 } 114 115 free(buffer); 116 return typemask; 117} 118 119static u_int8_t parse_dccp_option(char *optstring) 120{ 121 unsigned int ret; 122 123 if (!xtables_strtoui(optstring, NULL, &ret, 1, UINT8_MAX)) 124 xtables_error(PARAMETER_PROBLEM, "Bad DCCP option \"%s\"", 125 optstring); 126 127 return ret; 128} 129 130static int 131dccp_parse(int c, char **argv, int invert, unsigned int *flags, 132 const void *entry, struct xt_entry_match **match) 133{ 134 struct xt_dccp_info *einfo 135 = (struct xt_dccp_info *)(*match)->data; 136 137 switch (c) { 138 case '1': 139 if (*flags & XT_DCCP_SRC_PORTS) 140 xtables_error(PARAMETER_PROBLEM, 141 "Only one `--source-port' allowed"); 142 einfo->flags |= XT_DCCP_SRC_PORTS; 143 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 144 parse_dccp_ports(argv[optind-1], einfo->spts); 145 if (invert) 146 einfo->invflags |= XT_DCCP_SRC_PORTS; 147 *flags |= XT_DCCP_SRC_PORTS; 148 break; 149 150 case '2': 151 if (*flags & XT_DCCP_DEST_PORTS) 152 xtables_error(PARAMETER_PROBLEM, 153 "Only one `--destination-port' allowed"); 154 einfo->flags |= XT_DCCP_DEST_PORTS; 155 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 156 parse_dccp_ports(argv[optind-1], einfo->dpts); 157 if (invert) 158 einfo->invflags |= XT_DCCP_DEST_PORTS; 159 *flags |= XT_DCCP_DEST_PORTS; 160 break; 161 162 case '3': 163 if (*flags & XT_DCCP_TYPE) 164 xtables_error(PARAMETER_PROBLEM, 165 "Only one `--dccp-types' allowed"); 166 einfo->flags |= XT_DCCP_TYPE; 167 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 168 einfo->typemask = parse_dccp_types(argv[optind-1]); 169 if (invert) 170 einfo->invflags |= XT_DCCP_TYPE; 171 *flags |= XT_DCCP_TYPE; 172 break; 173 174 case '4': 175 if (*flags & XT_DCCP_OPTION) 176 xtables_error(PARAMETER_PROBLEM, 177 "Only one `--dccp-option' allowed"); 178 einfo->flags |= XT_DCCP_OPTION; 179 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 180 einfo->option = parse_dccp_option(argv[optind-1]); 181 if (invert) 182 einfo->invflags |= XT_DCCP_OPTION; 183 *flags |= XT_DCCP_OPTION; 184 break; 185 default: 186 return 0; 187 } 188 return 1; 189} 190 191static char * 192port_to_service(int port) 193{ 194 struct servent *service; 195 196 if ((service = getservbyport(htons(port), "dccp"))) 197 return service->s_name; 198 199 return NULL; 200} 201 202static void 203print_port(u_int16_t port, int numeric) 204{ 205 char *service; 206 207 if (numeric || (service = port_to_service(port)) == NULL) 208 printf("%u", port); 209 else 210 printf("%s", service); 211} 212 213static void 214print_ports(const char *name, u_int16_t min, u_int16_t max, 215 int invert, int numeric) 216{ 217 const char *inv = invert ? "!" : ""; 218 219 if (min != 0 || max != 0xFFFF || invert) { 220 printf("%s", name); 221 if (min == max) { 222 printf(":%s", inv); 223 print_port(min, numeric); 224 } else { 225 printf("s:%s", inv); 226 print_port(min, numeric); 227 printf(":"); 228 print_port(max, numeric); 229 } 230 printf(" "); 231 } 232} 233 234static void 235print_types(u_int16_t types, int inverted, int numeric) 236{ 237 int have_type = 0; 238 239 if (inverted) 240 printf("! "); 241 242 while (types) { 243 unsigned int i; 244 245 for (i = 0; !(types & (1 << i)); i++); 246 247 if (have_type) 248 printf(","); 249 else 250 have_type = 1; 251 252 if (numeric) 253 printf("%u", i); 254 else 255 printf("%s", dccp_pkt_types[i]); 256 257 types &= ~(1 << i); 258 } 259} 260 261static void 262print_option(u_int8_t option, int invert, int numeric) 263{ 264 if (option || invert) 265 printf("option=%s%u ", invert ? "!" : "", option); 266} 267 268static void 269dccp_print(const void *ip, const struct xt_entry_match *match, int numeric) 270{ 271 const struct xt_dccp_info *einfo = 272 (const struct xt_dccp_info *)match->data; 273 274 printf("dccp "); 275 276 if (einfo->flags & XT_DCCP_SRC_PORTS) { 277 print_ports("spt", einfo->spts[0], einfo->spts[1], 278 einfo->invflags & XT_DCCP_SRC_PORTS, 279 numeric); 280 } 281 282 if (einfo->flags & XT_DCCP_DEST_PORTS) { 283 print_ports("dpt", einfo->dpts[0], einfo->dpts[1], 284 einfo->invflags & XT_DCCP_DEST_PORTS, 285 numeric); 286 } 287 288 if (einfo->flags & XT_DCCP_TYPE) { 289 print_types(einfo->typemask, 290 einfo->invflags & XT_DCCP_TYPE, 291 numeric); 292 } 293 294 if (einfo->flags & XT_DCCP_OPTION) { 295 print_option(einfo->option, 296 einfo->invflags & XT_DCCP_OPTION, numeric); 297 } 298} 299 300static void dccp_save(const void *ip, const struct xt_entry_match *match) 301{ 302 const struct xt_dccp_info *einfo = 303 (const struct xt_dccp_info *)match->data; 304 305 if (einfo->flags & XT_DCCP_SRC_PORTS) { 306 if (einfo->invflags & XT_DCCP_SRC_PORTS) 307 printf("! "); 308 if (einfo->spts[0] != einfo->spts[1]) 309 printf("--sport %u:%u ", 310 einfo->spts[0], einfo->spts[1]); 311 else 312 printf("--sport %u ", einfo->spts[0]); 313 } 314 315 if (einfo->flags & XT_DCCP_DEST_PORTS) { 316 if (einfo->invflags & XT_DCCP_DEST_PORTS) 317 printf("! "); 318 if (einfo->dpts[0] != einfo->dpts[1]) 319 printf("--dport %u:%u ", 320 einfo->dpts[0], einfo->dpts[1]); 321 else 322 printf("--dport %u ", einfo->dpts[0]); 323 } 324 325 if (einfo->flags & XT_DCCP_TYPE) { 326 printf("--dccp-type "); 327 print_types(einfo->typemask, einfo->invflags & XT_DCCP_TYPE,0); 328 } 329 330 if (einfo->flags & XT_DCCP_OPTION) { 331 printf("--dccp-option %s%u ", 332 einfo->typemask & XT_DCCP_OPTION ? "! " : "", 333 einfo->option); 334 } 335} 336 337static struct xtables_match dccp_match = { 338 .name = "dccp", 339 .family = NFPROTO_UNSPEC, 340 .version = XTABLES_VERSION, 341 .size = XT_ALIGN(sizeof(struct xt_dccp_info)), 342 .userspacesize = XT_ALIGN(sizeof(struct xt_dccp_info)), 343 .help = dccp_help, 344 .init = dccp_init, 345 .parse = dccp_parse, 346 .print = dccp_print, 347 .save = dccp_save, 348 .extra_opts = dccp_opts, 349}; 350 351void _init(void) 352{ 353 xtables_register_match(&dccp_match); 354} 355