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 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <getopt.h> 9 #include <iptables.h> 10 11 #include <linux/netfilter_ipv4/ip_tables.h> 12 #include <linux/netfilter_ipv4/ipt_addrtype.h> 13 14 /* from linux/rtnetlink.h, must match order of enumeration */ 15 static char *rtn_names[] = { 16 "UNSPEC", 17 "UNICAST", 18 "LOCAL", 19 "BROADCAST", 20 "ANYCAST", 21 "MULTICAST", 22 "BLACKHOLE", 23 "UNREACHABLE", 24 "PROHIBIT", 25 "THROW", 26 "NAT", 27 "XRESOLVE", 28 NULL 29 }; 30 31 static void help_types(void) 32 { 33 int i; 34 35 for (i = 0; rtn_names[i]; i++) 36 printf(" %s\n", rtn_names[i]); 37 } 38 39 static void help(void) 40 { 41 printf( 42 "Address type match v%s options:\n" 43 " [!] --src-type type[,...] Match source address type\n" 44 " [!] --dst-type type[,...] Match destination address type\n" 45 "\n" 46 "Valid types: \n" 47 , IPTABLES_VERSION); 48 help_types(); 49 } 50 51 static int 52 parse_type(const char *name, size_t strlen, u_int16_t *mask) 53 { 54 int i; 55 56 for (i = 0; rtn_names[i]; i++) 57 if (strncasecmp(name, rtn_names[i], strlen) == 0) { 58 /* build up bitmask for kernel module */ 59 *mask |= (1 << i); 60 return 1; 61 } 62 63 return 0; 64 } 65 66 static void parse_types(const char *arg, u_int16_t *mask) 67 { 68 const char *comma; 69 70 while ((comma = strchr(arg, ',')) != NULL) { 71 if (comma == arg || !parse_type(arg, comma-arg, mask)) 72 exit_error(PARAMETER_PROBLEM, 73 "addrtype: bad type `%s'", arg); 74 arg = comma + 1; 75 } 76 77 if (strlen(arg) == 0 || !parse_type(arg, strlen(arg), mask)) 78 exit_error(PARAMETER_PROBLEM, "addrtype: bad type `%s'", arg); 79 } 80 81 #define IPT_ADDRTYPE_OPT_SRCTYPE 0x1 82 #define IPT_ADDRTYPE_OPT_DSTTYPE 0x2 83 84 static int parse(int c, char **argv, int invert, unsigned int *flags, 85 const struct ipt_entry *entry, unsigned int *nfcache, 86 struct ipt_entry_match **match) 87 { 88 struct ipt_addrtype_info *info = 89 (struct ipt_addrtype_info *) (*match)->data; 90 91 switch (c) { 92 case '1': 93 if (*flags&IPT_ADDRTYPE_OPT_SRCTYPE) 94 exit_error(PARAMETER_PROBLEM, 95 "addrtype: can't specify src-type twice"); 96 check_inverse(optarg, &invert, &optind, 0); 97 parse_types(argv[optind-1], &info->source); 98 if (invert) 99 info->invert_source = 1; 100 *flags |= IPT_ADDRTYPE_OPT_SRCTYPE; 101 break; 102 case '2': 103 if (*flags&IPT_ADDRTYPE_OPT_DSTTYPE) 104 exit_error(PARAMETER_PROBLEM, 105 "addrtype: can't specify dst-type twice"); 106 check_inverse(optarg, &invert, &optind, 0); 107 parse_types(argv[optind-1], &info->dest); 108 if (invert) 109 info->invert_dest = 1; 110 *flags |= IPT_ADDRTYPE_OPT_DSTTYPE; 111 break; 112 default: 113 return 0; 114 } 115 116 return 1; 117 } 118 119 static void final_check(unsigned int flags) 120 { 121 if (!(flags & (IPT_ADDRTYPE_OPT_SRCTYPE|IPT_ADDRTYPE_OPT_DSTTYPE))) 122 exit_error(PARAMETER_PROBLEM, 123 "addrtype: you must specify --src-type or --dst-type"); 124 } 125 126 static void print_types(u_int16_t mask) 127 { 128 const char *sep = ""; 129 int i; 130 131 for (i = 0; rtn_names[i]; i++) 132 if (mask & (1 << i)) { 133 printf("%s%s", sep, rtn_names[i]); 134 sep = ","; 135 } 136 137 printf(" "); 138 } 139 140 static void print(const struct ipt_ip *ip, 141 const struct ipt_entry_match *match, 142 int numeric) 143 { 144 const struct ipt_addrtype_info *info = 145 (struct ipt_addrtype_info *) match->data; 146 147 printf("ADDRTYPE match "); 148 if (info->source) { 149 printf("src-type "); 150 if (info->invert_source) 151 printf("!"); 152 print_types(info->source); 153 } 154 if (info->dest) { 155 printf("dst-type "); 156 if (info->invert_dest) 157 printf("!"); 158 print_types(info->dest); 159 } 160 } 161 162 static void save(const struct ipt_ip *ip, 163 const struct ipt_entry_match *match) 164 { 165 const struct ipt_addrtype_info *info = 166 (struct ipt_addrtype_info *) match->data; 167 168 if (info->source) { 169 printf("--src-type "); 170 if (info->invert_source) 171 printf("! "); 172 print_types(info->source); 173 } 174 if (info->dest) { 175 printf("--dst-type "); 176 if (info->invert_dest) 177 printf("! "); 178 print_types(info->dest); 179 } 180 } 181 182 static struct option opts[] = { 183 { "src-type", 1, 0, '1' }, 184 { "dst-type", 1, 0, '2' }, 185 { 0 } 186 }; 187 188 static 189 struct iptables_match addrtype = { 190 .next = NULL, 191 .name = "addrtype", 192 .version = IPTABLES_VERSION, 193 .size = IPT_ALIGN(sizeof(struct ipt_addrtype_info)), 194 .userspacesize = IPT_ALIGN(sizeof(struct ipt_addrtype_info)), 195 .help = &help, 196 .parse = &parse, 197 .final_check = &final_check, 198 .print = &print, 199 .save = &save, 200 .extra_opts = opts 201 }; 202 203 204 void ipt_addrtype_init(void) 205 { 206 register_match(&addrtype); 207 } 208