iptables-1.3.2-20050720
[iptables.git] / extensions / libipt_SET.c
1 /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
2  *                         Patrick Schaaf <bof@bof.de>
3  *                         Martin Josefsson <gandalf@wlug.westbo.se>
4  * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@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 _init(void)
178 {
179         register_target(&ipt_set_target);
180 }