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