libxt_dccp.c revision 7e66a657d0fbb8a3f27fd78c7bb27859d44002aa
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 <stdint.h> 9#include <stdio.h> 10#include <string.h> 11#include <stdlib.h> 12#include <netdb.h> 13#include <arpa/inet.h> 14#include <xtables.h> 15#include <linux/dccp.h> 16#include <linux/netfilter/x_tables.h> 17#include <linux/netfilter/xt_dccp.h> 18 19#if 0 20#define DEBUGP(format, first...) printf(format, ##first) 21#define static 22#else 23#define DEBUGP(format, fist...) 24#endif 25 26enum { 27 O_SOURCE_PORT = 0, 28 O_DEST_PORT, 29 O_DCCP_TYPES, 30 O_DCCP_OPTION, 31}; 32 33static void dccp_help(void) 34{ 35 printf( 36"dccp match options\n" 37"[!] --source-port port[:port] match source port(s)\n" 38" --sport ...\n" 39"[!] --destination-port port[:port] match destination port(s)\n" 40" --dport ...\n"); 41} 42 43#define s struct xt_dccp_info 44static const struct xt_option_entry dccp_opts[] = { 45 {.name = "source-port", .id = O_SOURCE_PORT, .type = XTTYPE_PORTRC, 46 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, spts)}, 47 {.name = "sport", .id = O_SOURCE_PORT, .type = XTTYPE_PORTRC, 48 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, spts)}, 49 {.name = "destination-port", .id = O_DEST_PORT, .type = XTTYPE_PORTRC, 50 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, dpts)}, 51 {.name = "dport", .id = O_DEST_PORT, .type = XTTYPE_PORTRC, 52 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, dpts)}, 53 {.name = "dccp-types", .id = O_DCCP_TYPES, .type = XTTYPE_STRING, 54 .flags = XTOPT_INVERT}, 55 {.name = "dccp-option", .id = O_DCCP_OPTION, .type = XTTYPE_UINT8, 56 .min = 1, .max = UINT8_MAX, .flags = XTOPT_INVERT | XTOPT_PUT, 57 XTOPT_POINTER(s, option)}, 58 XTOPT_TABLEEND, 59}; 60#undef s 61 62static const char *const dccp_pkt_types[] = { 63 [DCCP_PKT_REQUEST] = "REQUEST", 64 [DCCP_PKT_RESPONSE] = "RESPONSE", 65 [DCCP_PKT_DATA] = "DATA", 66 [DCCP_PKT_ACK] = "ACK", 67 [DCCP_PKT_DATAACK] = "DATAACK", 68 [DCCP_PKT_CLOSEREQ] = "CLOSEREQ", 69 [DCCP_PKT_CLOSE] = "CLOSE", 70 [DCCP_PKT_RESET] = "RESET", 71 [DCCP_PKT_SYNC] = "SYNC", 72 [DCCP_PKT_SYNCACK] = "SYNCACK", 73 [DCCP_PKT_INVALID] = "INVALID", 74}; 75 76static uint16_t 77parse_dccp_types(const char *typestring) 78{ 79 uint16_t typemask = 0; 80 char *ptr, *buffer; 81 82 buffer = strdup(typestring); 83 84 for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) { 85 unsigned int i; 86 for (i = 0; i < ARRAY_SIZE(dccp_pkt_types); ++i) 87 if (!strcasecmp(dccp_pkt_types[i], ptr)) { 88 typemask |= (1 << i); 89 break; 90 } 91 if (i == ARRAY_SIZE(dccp_pkt_types)) 92 xtables_error(PARAMETER_PROBLEM, 93 "Unknown DCCP type `%s'", ptr); 94 } 95 96 free(buffer); 97 return typemask; 98} 99 100static void dccp_parse(struct xt_option_call *cb) 101{ 102 struct xt_dccp_info *einfo = cb->data; 103 104 xtables_option_parse(cb); 105 switch (cb->entry->id) { 106 case O_SOURCE_PORT: 107 einfo->flags |= XT_DCCP_SRC_PORTS; 108 if (cb->invert) 109 einfo->invflags |= XT_DCCP_SRC_PORTS; 110 break; 111 case O_DEST_PORT: 112 einfo->flags |= XT_DCCP_DEST_PORTS; 113 if (cb->invert) 114 einfo->invflags |= XT_DCCP_DEST_PORTS; 115 break; 116 case O_DCCP_TYPES: 117 einfo->flags |= XT_DCCP_TYPE; 118 einfo->typemask = parse_dccp_types(cb->arg); 119 if (cb->invert) 120 einfo->invflags |= XT_DCCP_TYPE; 121 break; 122 case O_DCCP_OPTION: 123 einfo->flags |= XT_DCCP_OPTION; 124 if (cb->invert) 125 einfo->invflags |= XT_DCCP_OPTION; 126 break; 127 } 128} 129 130static const char * 131port_to_service(int port) 132{ 133 const struct servent *service; 134 135 if ((service = getservbyport(htons(port), "dccp"))) 136 return service->s_name; 137 138 return NULL; 139} 140 141static void 142print_port(uint16_t port, int numeric) 143{ 144 const char *service; 145 146 if (numeric || (service = port_to_service(port)) == NULL) 147 printf("%u", port); 148 else 149 printf("%s", service); 150} 151 152static void 153print_ports(const char *name, uint16_t min, uint16_t max, 154 int invert, int numeric) 155{ 156 const char *inv = invert ? "!" : ""; 157 158 if (min != 0 || max != 0xFFFF || invert) { 159 printf(" %s", name); 160 if (min == max) { 161 printf(":%s", inv); 162 print_port(min, numeric); 163 } else { 164 printf("s:%s", inv); 165 print_port(min, numeric); 166 printf(":"); 167 print_port(max, numeric); 168 } 169 } 170} 171 172static void 173print_types(uint16_t types, int inverted, int numeric) 174{ 175 int have_type = 0; 176 177 if (inverted) 178 printf(" !"); 179 180 printf(" "); 181 while (types) { 182 unsigned int i; 183 184 for (i = 0; !(types & (1 << i)); i++); 185 186 if (have_type) 187 printf(","); 188 else 189 have_type = 1; 190 191 if (numeric) 192 printf("%u", i); 193 else 194 printf("%s", dccp_pkt_types[i]); 195 196 types &= ~(1 << i); 197 } 198} 199 200static void 201print_option(uint8_t option, int invert, int numeric) 202{ 203 if (option || invert) 204 printf(" option=%s%u", invert ? "!" : "", option); 205} 206 207static void 208dccp_print(const void *ip, const struct xt_entry_match *match, int numeric) 209{ 210 const struct xt_dccp_info *einfo = 211 (const struct xt_dccp_info *)match->data; 212 213 printf(" dccp"); 214 215 if (einfo->flags & XT_DCCP_SRC_PORTS) { 216 print_ports("spt", einfo->spts[0], einfo->spts[1], 217 einfo->invflags & XT_DCCP_SRC_PORTS, 218 numeric); 219 } 220 221 if (einfo->flags & XT_DCCP_DEST_PORTS) { 222 print_ports("dpt", einfo->dpts[0], einfo->dpts[1], 223 einfo->invflags & XT_DCCP_DEST_PORTS, 224 numeric); 225 } 226 227 if (einfo->flags & XT_DCCP_TYPE) { 228 print_types(einfo->typemask, 229 einfo->invflags & XT_DCCP_TYPE, 230 numeric); 231 } 232 233 if (einfo->flags & XT_DCCP_OPTION) { 234 print_option(einfo->option, 235 einfo->invflags & XT_DCCP_OPTION, numeric); 236 } 237} 238 239static void dccp_save(const void *ip, const struct xt_entry_match *match) 240{ 241 const struct xt_dccp_info *einfo = 242 (const struct xt_dccp_info *)match->data; 243 244 if (einfo->flags & XT_DCCP_SRC_PORTS) { 245 if (einfo->invflags & XT_DCCP_SRC_PORTS) 246 printf(" !"); 247 if (einfo->spts[0] != einfo->spts[1]) 248 printf(" --sport %u:%u", 249 einfo->spts[0], einfo->spts[1]); 250 else 251 printf(" --sport %u", einfo->spts[0]); 252 } 253 254 if (einfo->flags & XT_DCCP_DEST_PORTS) { 255 if (einfo->invflags & XT_DCCP_DEST_PORTS) 256 printf(" !"); 257 if (einfo->dpts[0] != einfo->dpts[1]) 258 printf(" --dport %u:%u", 259 einfo->dpts[0], einfo->dpts[1]); 260 else 261 printf(" --dport %u", einfo->dpts[0]); 262 } 263 264 if (einfo->flags & XT_DCCP_TYPE) { 265 printf("%s --dccp-type", 266 einfo->invflags & XT_DCCP_TYPE ? " !" : ""); 267 print_types(einfo->typemask, false, 0); 268 } 269 270 if (einfo->flags & XT_DCCP_OPTION) { 271 printf("%s --dccp-option %u", 272 einfo->typemask & XT_DCCP_OPTION ? " !" : "", 273 einfo->option); 274 } 275} 276 277static struct xtables_match dccp_match = { 278 .name = "dccp", 279 .family = NFPROTO_UNSPEC, 280 .version = XTABLES_VERSION, 281 .size = XT_ALIGN(sizeof(struct xt_dccp_info)), 282 .userspacesize = XT_ALIGN(sizeof(struct xt_dccp_info)), 283 .help = dccp_help, 284 .print = dccp_print, 285 .save = dccp_save, 286 .x6_parse = dccp_parse, 287 .x6_options = dccp_opts, 288}; 289 290void _init(void) 291{ 292 xtables_register_match(&dccp_match); 293} 294