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