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