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