1 /* Shared library add-on to iptables to add addrtype matching support 2 * 3 * Copyright (c) 2003-2013 Patrick McHardy <kaber (at) trash.net> 4 * 5 * This program is released under the terms of GNU GPL */ 6 #include <stdio.h> 7 #include <string.h> 8 #include <xtables.h> 9 #include <linux/netfilter/xt_addrtype.h> 10 11 enum { 12 O_SRC_TYPE = 0, 13 O_DST_TYPE, 14 O_LIMIT_IFACE_IN, 15 O_LIMIT_IFACE_OUT, 16 F_SRC_TYPE = 1 << O_SRC_TYPE, 17 F_DST_TYPE = 1 << O_DST_TYPE, 18 F_LIMIT_IFACE_IN = 1 << O_LIMIT_IFACE_IN, 19 F_LIMIT_IFACE_OUT = 1 << O_LIMIT_IFACE_OUT, 20 }; 21 22 /* from linux/rtnetlink.h, must match order of enumeration */ 23 static const char *const rtn_names[] = { 24 "UNSPEC", 25 "UNICAST", 26 "LOCAL", 27 "BROADCAST", 28 "ANYCAST", 29 "MULTICAST", 30 "BLACKHOLE", 31 "UNREACHABLE", 32 "PROHIBIT", 33 "THROW", 34 "NAT", 35 "XRESOLVE", 36 NULL 37 }; 38 39 static void addrtype_help_types(void) 40 { 41 int i; 42 43 for (i = 0; rtn_names[i]; i++) 44 printf(" %s\n", rtn_names[i]); 45 } 46 47 static void addrtype_help_v0(void) 48 { 49 printf( 50 "Address type match options:\n" 51 " [!] --src-type type[,...] Match source address type\n" 52 " [!] --dst-type type[,...] Match destination address type\n" 53 "\n" 54 "Valid types: \n"); 55 addrtype_help_types(); 56 } 57 58 static void addrtype_help_v1(void) 59 { 60 printf( 61 "Address type match options:\n" 62 " [!] --src-type type[,...] Match source address type\n" 63 " [!] --dst-type type[,...] Match destination address type\n" 64 " --limit-iface-in Match only on the packet's incoming device\n" 65 " --limit-iface-out Match only on the packet's outgoing device\n" 66 "\n" 67 "Valid types: \n"); 68 addrtype_help_types(); 69 } 70 71 static int 72 parse_type(const char *name, size_t len, uint16_t *mask) 73 { 74 int i; 75 76 for (i = 0; rtn_names[i]; i++) 77 if (strncasecmp(name, rtn_names[i], len) == 0) { 78 /* build up bitmask for kernel module */ 79 *mask |= (1 << i); 80 return 1; 81 } 82 83 return 0; 84 } 85 86 static void parse_types(const char *arg, uint16_t *mask) 87 { 88 const char *comma; 89 90 while ((comma = strchr(arg, ',')) != NULL) { 91 if (comma == arg || !parse_type(arg, comma-arg, mask)) 92 xtables_error(PARAMETER_PROBLEM, 93 "addrtype: bad type `%s'", arg); 94 arg = comma + 1; 95 } 96 97 if (strlen(arg) == 0 || !parse_type(arg, strlen(arg), mask)) 98 xtables_error(PARAMETER_PROBLEM, "addrtype: bad type \"%s\"", arg); 99 } 100 101 static void addrtype_parse_v0(struct xt_option_call *cb) 102 { 103 struct xt_addrtype_info *info = cb->data; 104 105 xtables_option_parse(cb); 106 switch (cb->entry->id) { 107 case O_SRC_TYPE: 108 parse_types(cb->arg, &info->source); 109 if (cb->invert) 110 info->invert_source = 1; 111 break; 112 case O_DST_TYPE: 113 parse_types(cb->arg, &info->dest); 114 if (cb->invert) 115 info->invert_dest = 1; 116 break; 117 } 118 } 119 120 static void addrtype_parse_v1(struct xt_option_call *cb) 121 { 122 struct xt_addrtype_info_v1 *info = cb->data; 123 124 xtables_option_parse(cb); 125 switch (cb->entry->id) { 126 case O_SRC_TYPE: 127 parse_types(cb->arg, &info->source); 128 if (cb->invert) 129 info->flags |= XT_ADDRTYPE_INVERT_SOURCE; 130 break; 131 case O_DST_TYPE: 132 parse_types(cb->arg, &info->dest); 133 if (cb->invert) 134 info->flags |= XT_ADDRTYPE_INVERT_DEST; 135 break; 136 case O_LIMIT_IFACE_IN: 137 info->flags |= XT_ADDRTYPE_LIMIT_IFACE_IN; 138 break; 139 case O_LIMIT_IFACE_OUT: 140 info->flags |= XT_ADDRTYPE_LIMIT_IFACE_OUT; 141 break; 142 } 143 } 144 145 static void addrtype_check(struct xt_fcheck_call *cb) 146 { 147 if (!(cb->xflags & (F_SRC_TYPE | F_DST_TYPE))) 148 xtables_error(PARAMETER_PROBLEM, 149 "addrtype: you must specify --src-type or --dst-type"); 150 } 151 152 static void print_types(uint16_t mask) 153 { 154 const char *sep = ""; 155 int i; 156 157 for (i = 0; rtn_names[i]; i++) 158 if (mask & (1 << i)) { 159 printf("%s%s", sep, rtn_names[i]); 160 sep = ","; 161 } 162 } 163 164 static void addrtype_print_v0(const void *ip, const struct xt_entry_match *match, 165 int numeric) 166 { 167 const struct xt_addrtype_info *info = (const void *)match->data; 168 169 printf(" ADDRTYPE match"); 170 if (info->source) { 171 printf(" src-type "); 172 if (info->invert_source) 173 printf("!"); 174 print_types(info->source); 175 } 176 if (info->dest) { 177 printf(" dst-type"); 178 if (info->invert_dest) 179 printf("!"); 180 print_types(info->dest); 181 } 182 } 183 184 static void addrtype_print_v1(const void *ip, const struct xt_entry_match *match, 185 int numeric) 186 { 187 const struct xt_addrtype_info_v1 *info = (const void *)match->data; 188 189 printf(" ADDRTYPE match"); 190 if (info->source) { 191 printf(" src-type "); 192 if (info->flags & XT_ADDRTYPE_INVERT_SOURCE) 193 printf("!"); 194 print_types(info->source); 195 } 196 if (info->dest) { 197 printf(" dst-type "); 198 if (info->flags & XT_ADDRTYPE_INVERT_DEST) 199 printf("!"); 200 print_types(info->dest); 201 } 202 if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN) 203 printf(" limit-in"); 204 if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) 205 printf(" limit-out"); 206 } 207 208 static void addrtype_save_v0(const void *ip, const struct xt_entry_match *match) 209 { 210 const struct xt_addrtype_info *info = (const void *)match->data; 211 212 if (info->source) { 213 if (info->invert_source) 214 printf(" !"); 215 printf(" --src-type "); 216 print_types(info->source); 217 } 218 if (info->dest) { 219 if (info->invert_dest) 220 printf(" !"); 221 printf(" --dst-type "); 222 print_types(info->dest); 223 } 224 } 225 226 static void addrtype_save_v1(const void *ip, const struct xt_entry_match *match) 227 { 228 const struct xt_addrtype_info_v1 *info = (const void *)match->data; 229 230 if (info->source) { 231 if (info->flags & XT_ADDRTYPE_INVERT_SOURCE) 232 printf(" !"); 233 printf(" --src-type "); 234 print_types(info->source); 235 } 236 if (info->dest) { 237 if (info->flags & XT_ADDRTYPE_INVERT_DEST) 238 printf(" !"); 239 printf(" --dst-type "); 240 print_types(info->dest); 241 } 242 if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN) 243 printf(" --limit-iface-in"); 244 if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) 245 printf(" --limit-iface-out"); 246 } 247 248 static const struct xt_option_entry addrtype_opts_v0[] = { 249 {.name = "src-type", .id = O_SRC_TYPE, .type = XTTYPE_STRING, 250 .flags = XTOPT_INVERT}, 251 {.name = "dst-type", .id = O_DST_TYPE, .type = XTTYPE_STRING, 252 .flags = XTOPT_INVERT}, 253 XTOPT_TABLEEND, 254 }; 255 256 static const struct xt_option_entry addrtype_opts_v1[] = { 257 {.name = "src-type", .id = O_SRC_TYPE, .type = XTTYPE_STRING, 258 .flags = XTOPT_INVERT}, 259 {.name = "dst-type", .id = O_DST_TYPE, .type = XTTYPE_STRING, 260 .flags = XTOPT_INVERT}, 261 {.name = "limit-iface-in", .id = O_LIMIT_IFACE_IN, 262 .type = XTTYPE_NONE, .excl = F_LIMIT_IFACE_OUT}, 263 {.name = "limit-iface-out", .id = O_LIMIT_IFACE_OUT, 264 .type = XTTYPE_NONE, .excl = F_LIMIT_IFACE_IN}, 265 XTOPT_TABLEEND, 266 }; 267 268 static struct xtables_match addrtype_mt_reg[] = { 269 { 270 .name = "addrtype", 271 .version = XTABLES_VERSION, 272 .family = NFPROTO_IPV4, 273 .size = XT_ALIGN(sizeof(struct xt_addrtype_info)), 274 .userspacesize = XT_ALIGN(sizeof(struct xt_addrtype_info)), 275 .help = addrtype_help_v0, 276 .print = addrtype_print_v0, 277 .save = addrtype_save_v0, 278 .x6_parse = addrtype_parse_v0, 279 .x6_fcheck = addrtype_check, 280 .x6_options = addrtype_opts_v0, 281 }, 282 { 283 .name = "addrtype", 284 .revision = 1, 285 .version = XTABLES_VERSION, 286 .family = NFPROTO_UNSPEC, 287 .size = XT_ALIGN(sizeof(struct xt_addrtype_info_v1)), 288 .userspacesize = XT_ALIGN(sizeof(struct xt_addrtype_info_v1)), 289 .help = addrtype_help_v1, 290 .print = addrtype_print_v1, 291 .save = addrtype_save_v1, 292 .x6_parse = addrtype_parse_v1, 293 .x6_fcheck = addrtype_check, 294 .x6_options = addrtype_opts_v1, 295 }, 296 }; 297 298 299 void _init(void) 300 { 301 xtables_register_matches(addrtype_mt_reg, ARRAY_SIZE(addrtype_mt_reg)); 302 } 303