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-2004 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 mangling target. */ 12 #include <stdio.h> 13 #include <netdb.h> 14 #include <string.h> 15 #include <stdlib.h> 16 #include <getopt.h> 17 #include <ctype.h> 18 19 #include <iptables.h> 20 #include <linux/netfilter_ipv4/ip_tables.h> 21 #include <linux/netfilter_ipv4/ip_nat_rule.h> 22 #include <linux/netfilter_ipv4/ip_set.h> 23 #include <linux/netfilter_ipv4/ipt_set.h> 24 #include "libipt_set.h" 25 26 /* Function which prints out usage message. */ 27 static void help(void) 28 { 29 printf("SET v%s options:\n" 30 " --add-set name flags\n" 31 " --del-set name flags\n" 32 " add/del src/dst IP/port from/to named sets,\n" 33 " where flags are the comma separated list of\n" 34 " 'src' and 'dst'.\n" 35 "\n", IPTABLES_VERSION); 36 } 37 38 static struct option opts[] = { 39 {"add-set", 1, 0, '1'}, 40 {"del-set", 1, 0, '2'}, 41 {0} 42 }; 43 44 /* Initialize the target. */ 45 static void init(struct ipt_entry_target *target, unsigned int *nfcache) 46 { 47 struct ipt_set_info_target *info = 48 (struct ipt_set_info_target *) target->data; 49 50 memset(info, 0, sizeof(struct ipt_set_info_target)); 51 info->add_set.index = 52 info->del_set.index = IP_SET_INVALID_ID; 53 54 } 55 56 static void 57 parse_target(char **argv, int invert, unsigned int *flags, 58 struct ipt_set_info *info, const char *what) 59 { 60 if (info->flags[0]) 61 exit_error(PARAMETER_PROBLEM, 62 "--%s can be specified only once", what); 63 64 if (check_inverse(optarg, &invert, NULL, 0)) 65 exit_error(PARAMETER_PROBLEM, 66 "Unexpected `!' after --%s", what); 67 68 if (!argv[optind] 69 || argv[optind][0] == '-' || argv[optind][0] == '!') 70 exit_error(PARAMETER_PROBLEM, 71 "--%s requires two args.", what); 72 73 if (strlen(argv[optind-1]) > IP_SET_MAXNAMELEN - 1) 74 exit_error(PARAMETER_PROBLEM, 75 "setname `%s' too long, max %d characters.", 76 argv[optind-1], IP_SET_MAXNAMELEN - 1); 77 78 get_set_byname(argv[optind - 1], info); 79 parse_bindings(argv[optind], info); 80 optind++; 81 82 *flags = 1; 83 } 84 85 /* Function which parses command options; returns true if it 86 ate an option */ 87 static int 88 parse(int c, char **argv, int invert, unsigned int *flags, 89 const struct ipt_entry *entry, struct ipt_entry_target **target) 90 { 91 struct ipt_set_info_target *myinfo = 92 (struct ipt_set_info_target *) (*target)->data; 93 94 switch (c) { 95 case '1': /* --add-set <set> <flags> */ 96 parse_target(argv, invert, flags, 97 &myinfo->add_set, "add-set"); 98 break; 99 case '2': /* --del-set <set>[:<flags>] <flags> */ 100 parse_target(argv, invert, flags, 101 &myinfo->del_set, "del-set"); 102 break; 103 104 default: 105 return 0; 106 } 107 return 1; 108 } 109 110 /* Final check; must specify at least one. */ 111 static void final_check(unsigned int flags) 112 { 113 if (!flags) 114 exit_error(PARAMETER_PROBLEM, 115 "You must specify either `--add-set' or `--del-set'"); 116 } 117 118 static void 119 print_target(const char *prefix, const struct ipt_set_info *info) 120 { 121 int i; 122 char setname[IP_SET_MAXNAMELEN]; 123 124 if (info->index == IP_SET_INVALID_ID) 125 return; 126 get_set_byid(setname, info->index); 127 printf("%s %s", prefix, setname); 128 for (i = 0; i < IP_SET_MAX_BINDINGS; i++) { 129 if (!info->flags[i]) 130 break; 131 printf("%s%s", 132 i == 0 ? " " : ",", 133 info->flags[i] & IPSET_SRC ? "src" : "dst"); 134 } 135 printf(" "); 136 } 137 138 /* Prints out the targinfo. */ 139 static void 140 print(const struct ipt_ip *ip, 141 const struct ipt_entry_target *target, int numeric) 142 { 143 struct ipt_set_info_target *info = 144 (struct ipt_set_info_target *) target->data; 145 146 print_target("add-set", &info->add_set); 147 print_target("del-set", &info->del_set); 148 } 149 150 /* Saves the union ipt_targinfo in parsable form to stdout. */ 151 static void 152 save(const struct ipt_ip *ip, const struct ipt_entry_target *target) 153 { 154 struct ipt_set_info_target *info = 155 (struct ipt_set_info_target *) target->data; 156 157 print_target("--add-set", &info->add_set); 158 print_target("--del-set", &info->del_set); 159 } 160 161 static 162 struct iptables_target ipt_set_target 163 = { 164 .name = "SET", 165 .version = IPTABLES_VERSION, 166 .size = IPT_ALIGN(sizeof(struct ipt_set_info_target)), 167 .userspacesize = IPT_ALIGN(sizeof(struct ipt_set_info_target)), 168 .help = &help, 169 .init = &init, 170 .parse = &parse, 171 .final_check = &final_check, 172 .print = &print, 173 .save = &save, 174 .extra_opts = opts 175 }; 176 177 void ipt_SET_init(void) 178 { 179 register_target(&ipt_set_target); 180 } 181