libxt_dccp.c revision 32b8e61e4e5bd405d9ad07bf9468498dfbb19f9e
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 u_int16_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 u_int16_t 97parse_dccp_types(const char *typestring) 98{ 99 u_int16_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 u_int8_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 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_UNSPEC, 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 352void _init(void) 353{ 354 xtables_register_match(&dccp_match); 355} 356