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 */ 15static 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 31static 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 39static 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 51static int 52parse_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 66static 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 84static 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 119static 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 126static 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 140static 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 162static 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 182static struct option opts[] = { 183 { "src-type", 1, 0, '1' }, 184 { "dst-type", 1, 0, '2' }, 185 { 0 } 186}; 187 188static 189struct 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 204void _init(void) 205{ 206 register_match(&addrtype); 207} 208