1 /* Copyright (C) 2000-2002 Joakim Axelsson <gozem (at) linux.nu> 2 * Patrick Schaaf <bof (at) bof.de> 3 * Martin Josefsson <gandalf (at) wlug.westbo.se> 4 * Copyright (C) 2003-2010 Jozsef Kadlecsik <kadlec (at) blackhole.kfki.hu> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 */ 10 11 /* Shared library add-on to iptables to add IP set matching. */ 12 #include <stdbool.h> 13 #include <stdio.h> 14 #include <netdb.h> 15 #include <string.h> 16 #include <stdlib.h> 17 #include <getopt.h> 18 #include <ctype.h> 19 #include <errno.h> 20 21 #include <xtables.h> 22 #include <linux/netfilter/xt_set.h> 23 #include "libxt_set.h" 24 25 /* Revision 0 */ 26 27 static void 28 set_help_v0(void) 29 { 30 printf("set match options:\n" 31 " [!] --match-set name flags\n" 32 " 'name' is the set name from to match,\n" 33 " 'flags' are the comma separated list of\n" 34 " 'src' and 'dst' specifications.\n"); 35 } 36 37 static const struct option set_opts_v0[] = { 38 {.name = "match-set", .has_arg = true, .val = '1'}, 39 {.name = "set", .has_arg = true, .val = '2'}, 40 XT_GETOPT_TABLEEND, 41 }; 42 43 static void 44 set_check_v0(unsigned int flags) 45 { 46 if (!flags) 47 xtables_error(PARAMETER_PROBLEM, 48 "You must specify `--match-set' with proper arguments"); 49 } 50 51 static int 52 set_parse_v0(int c, char **argv, int invert, unsigned int *flags, 53 const void *entry, struct xt_entry_match **match) 54 { 55 struct xt_set_info_match_v0 *myinfo = 56 (struct xt_set_info_match_v0 *) (*match)->data; 57 struct xt_set_info_v0 *info = &myinfo->match_set; 58 59 switch (c) { 60 case '2': 61 fprintf(stderr, 62 "--set option deprecated, please use --match-set\n"); 63 case '1': /* --match-set <set> <flag>[,<flag> */ 64 if (info->u.flags[0]) 65 xtables_error(PARAMETER_PROBLEM, 66 "--match-set can be specified only once"); 67 68 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 69 if (invert) 70 info->u.flags[0] |= IPSET_MATCH_INV; 71 72 if (!argv[optind] 73 || argv[optind][0] == '-' 74 || argv[optind][0] == '!') 75 xtables_error(PARAMETER_PROBLEM, 76 "--match-set requires two args."); 77 78 if (strlen(optarg) > IPSET_MAXNAMELEN - 1) 79 xtables_error(PARAMETER_PROBLEM, 80 "setname `%s' too long, max %d characters.", 81 optarg, IPSET_MAXNAMELEN - 1); 82 83 get_set_byname(optarg, (struct xt_set_info *)info); 84 parse_dirs_v0(argv[optind], info); 85 DEBUGP("parse: set index %u\n", info->index); 86 optind++; 87 88 *flags = 1; 89 break; 90 } 91 92 return 1; 93 } 94 95 static void 96 print_match_v0(const char *prefix, const struct xt_set_info_v0 *info) 97 { 98 int i; 99 char setname[IPSET_MAXNAMELEN]; 100 101 get_set_byid(setname, info->index); 102 printf("%s %s %s", 103 (info->u.flags[0] & IPSET_MATCH_INV) ? " !" : "", 104 prefix, 105 setname); 106 for (i = 0; i < IPSET_DIM_MAX; i++) { 107 if (!info->u.flags[i]) 108 break; 109 printf("%s%s", 110 i == 0 ? " " : ",", 111 info->u.flags[i] & IPSET_SRC ? "src" : "dst"); 112 } 113 } 114 115 /* Prints out the matchinfo. */ 116 static void 117 set_print_v0(const void *ip, const struct xt_entry_match *match, int numeric) 118 { 119 const struct xt_set_info_match_v0 *info = (const void *)match->data; 120 121 print_match_v0("match-set", &info->match_set); 122 } 123 124 static void 125 set_save_v0(const void *ip, const struct xt_entry_match *match) 126 { 127 const struct xt_set_info_match_v0 *info = (const void *)match->data; 128 129 print_match_v0("--match-set", &info->match_set); 130 } 131 132 /* Revision 1 */ 133 134 #define set_help_v1 set_help_v0 135 #define set_opts_v1 set_opts_v0 136 #define set_check_v1 set_check_v0 137 138 static int 139 set_parse_v1(int c, char **argv, int invert, unsigned int *flags, 140 const void *entry, struct xt_entry_match **match) 141 { 142 struct xt_set_info_match_v1 *myinfo = 143 (struct xt_set_info_match_v1 *) (*match)->data; 144 struct xt_set_info *info = &myinfo->match_set; 145 146 switch (c) { 147 case '2': 148 fprintf(stderr, 149 "--set option deprecated, please use --match-set\n"); 150 case '1': /* --match-set <set> <flag>[,<flag> */ 151 if (info->dim) 152 xtables_error(PARAMETER_PROBLEM, 153 "--match-set can be specified only once"); 154 155 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 156 if (invert) 157 info->flags |= IPSET_INV_MATCH; 158 159 if (!argv[optind] 160 || argv[optind][0] == '-' 161 || argv[optind][0] == '!') 162 xtables_error(PARAMETER_PROBLEM, 163 "--match-set requires two args."); 164 165 if (strlen(optarg) > IPSET_MAXNAMELEN - 1) 166 xtables_error(PARAMETER_PROBLEM, 167 "setname `%s' too long, max %d characters.", 168 optarg, IPSET_MAXNAMELEN - 1); 169 170 get_set_byname(optarg, info); 171 parse_dirs(argv[optind], info); 172 DEBUGP("parse: set index %u\n", info->index); 173 optind++; 174 175 *flags = 1; 176 break; 177 } 178 179 return 1; 180 } 181 182 static void 183 print_match(const char *prefix, const struct xt_set_info *info) 184 { 185 int i; 186 char setname[IPSET_MAXNAMELEN]; 187 188 get_set_byid(setname, info->index); 189 printf("%s %s %s", 190 (info->flags & IPSET_INV_MATCH) ? " !" : "", 191 prefix, 192 setname); 193 for (i = 1; i <= info->dim; i++) { 194 printf("%s%s", 195 i == 1 ? " " : ",", 196 info->flags & (1 << i) ? "src" : "dst"); 197 } 198 } 199 200 /* Prints out the matchinfo. */ 201 static void 202 set_print_v1(const void *ip, const struct xt_entry_match *match, int numeric) 203 { 204 const struct xt_set_info_match_v1 *info = (const void *)match->data; 205 206 print_match("match-set", &info->match_set); 207 } 208 209 static void 210 set_save_v1(const void *ip, const struct xt_entry_match *match) 211 { 212 const struct xt_set_info_match_v1 *info = (const void *)match->data; 213 214 print_match("--match-set", &info->match_set); 215 } 216 217 static struct xtables_match set_mt_reg[] = { 218 { 219 .name = "set", 220 .revision = 0, 221 .version = XTABLES_VERSION, 222 .family = NFPROTO_IPV4, 223 .size = XT_ALIGN(sizeof(struct xt_set_info_match_v0)), 224 .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_match_v0)), 225 .help = set_help_v0, 226 .parse = set_parse_v0, 227 .final_check = set_check_v0, 228 .print = set_print_v0, 229 .save = set_save_v0, 230 .extra_opts = set_opts_v0, 231 }, 232 { 233 .name = "set", 234 .revision = 1, 235 .version = XTABLES_VERSION, 236 .family = NFPROTO_UNSPEC, 237 .size = XT_ALIGN(sizeof(struct xt_set_info_match_v1)), 238 .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_match_v1)), 239 .help = set_help_v1, 240 .parse = set_parse_v1, 241 .final_check = set_check_v1, 242 .print = set_print_v1, 243 .save = set_save_v1, 244 .extra_opts = set_opts_v1, 245 }, 246 }; 247 248 void _init(void) 249 { 250 xtables_register_matches(set_mt_reg, ARRAY_SIZE(set_mt_reg)); 251 } 252