blob: 2f915bcd6a6ab4cc744177272813138b89202172 [file] [log] [blame]
Jozsef Kadlecsikd40f1622010-06-16 12:45:33 +02001/* 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-2010 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. */
Jan Engelhardt32b8e612010-07-23 21:16:14 +020012#include <stdbool.h>
Jozsef Kadlecsikd40f1622010-06-16 12:45:33 +020013#include <stdio.h>
14#include <netdb.h>
15#include <string.h>
16#include <stdlib.h>
17#include <getopt.h>
18#include <ctype.h>
19
20#include <xtables.h>
21#include <linux/netfilter/xt_set.h>
22#include "libxt_set.h"
23
24static void
25set_target_help(void)
26{
27 printf("SET target options:\n"
28 " --add-set name flags\n"
29 " --del-set name flags\n"
30 " add/del src/dst IP/port from/to named sets,\n"
31 " where flags are the comma separated list of\n"
32 " 'src' and 'dst' specifications.\n");
33}
34
35static const struct option set_target_opts[] = {
Jan Engelhardt32b8e612010-07-23 21:16:14 +020036 {.name = "add-set", .has_arg = true, .val = '1'},
37 {.name = "del-set", .has_arg = true, .val = '2'},
38 XT_GETOPT_TABLEEND,
Jozsef Kadlecsikd40f1622010-06-16 12:45:33 +020039};
40
41static void
42set_target_check(unsigned int flags)
43{
44 if (!flags)
45 xtables_error(PARAMETER_PROBLEM,
46 "You must specify either `--add-set' or `--del-set'");
47}
48
49static void
50set_target_init_v0(struct xt_entry_target *target)
51{
52 struct xt_set_info_target_v0 *info =
53 (struct xt_set_info_target_v0 *) target->data;
54
55 info->add_set.index =
56 info->del_set.index = IPSET_INVALID_ID;
57
58}
59
60static void
61parse_target_v0(char **argv, int invert, unsigned int *flags,
62 struct xt_set_info_v0 *info, const char *what)
63{
64 if (info->u.flags[0])
65 xtables_error(PARAMETER_PROBLEM,
66 "--%s can be specified only once", what);
67
68 if (xtables_check_inverse(optarg, &invert, NULL, 0, argv))
69 xtables_error(PARAMETER_PROBLEM,
70 "Unexpected `!' after --%s", what);
71
72 if (!argv[optind]
73 || argv[optind][0] == '-' || argv[optind][0] == '!')
74 xtables_error(PARAMETER_PROBLEM,
75 "--%s requires two args.", what);
76
77 if (strlen(optarg) > IPSET_MAXNAMELEN - 1)
78 xtables_error(PARAMETER_PROBLEM,
79 "setname `%s' too long, max %d characters.",
80 optarg, IPSET_MAXNAMELEN - 1);
81
82 get_set_byname(optarg, (struct xt_set_info *)info);
83 parse_dirs_v0(argv[optind], info);
84 optind++;
85
86 *flags = 1;
87}
88
89static int
90set_target_parse_v0(int c, char **argv, int invert, unsigned int *flags,
91 const void *entry, struct xt_entry_target **target)
92{
93 struct xt_set_info_target_v0 *myinfo =
94 (struct xt_set_info_target_v0 *) (*target)->data;
95
96 switch (c) {
97 case '1': /* --add-set <set> <flags> */
98 parse_target_v0(argv, invert, flags,
99 &myinfo->add_set, "add-set");
100 break;
101 case '2': /* --del-set <set>[:<flags>] <flags> */
102 parse_target_v0(argv, invert, flags,
103 &myinfo->del_set, "del-set");
104 break;
Jozsef Kadlecsikd40f1622010-06-16 12:45:33 +0200105 }
106 return 1;
107}
108
109static void
110print_target_v0(const char *prefix, const struct xt_set_info_v0 *info)
111{
112 int i;
113 char setname[IPSET_MAXNAMELEN];
114
115 if (info->index == IPSET_INVALID_ID)
116 return;
117 get_set_byid(setname, info->index);
Jan Engelhardt73866352010-12-18 02:04:59 +0100118 printf(" %s %s", prefix, setname);
Jozsef Kadlecsikd40f1622010-06-16 12:45:33 +0200119 for (i = 0; i < IPSET_DIM_MAX; i++) {
120 if (!info->u.flags[i])
121 break;
122 printf("%s%s",
123 i == 0 ? " " : ",",
124 info->u.flags[i] & IPSET_SRC ? "src" : "dst");
125 }
Jozsef Kadlecsikd40f1622010-06-16 12:45:33 +0200126}
127
128static void
129set_target_print_v0(const void *ip, const struct xt_entry_target *target,
130 int numeric)
131{
132 const struct xt_set_info_target_v0 *info = (const void *)target->data;
133
134 print_target_v0("add-set", &info->add_set);
135 print_target_v0("del-set", &info->del_set);
136}
137
138static void
139set_target_save_v0(const void *ip, const struct xt_entry_target *target)
140{
141 const struct xt_set_info_target_v0 *info = (const void *)target->data;
142
143 print_target_v0("--add-set", &info->add_set);
144 print_target_v0("--del-set", &info->del_set);
145}
146
147static void
148set_target_init(struct xt_entry_target *target)
149{
150 struct xt_set_info_target *info =
151 (struct xt_set_info_target *) target->data;
152
153 info->add_set.index =
154 info->del_set.index = IPSET_INVALID_ID;
155
156}
157
158static void
159parse_target(char **argv, int invert, unsigned int *flags,
160 struct xt_set_info *info, const char *what)
161{
162 if (info->dim)
163 xtables_error(PARAMETER_PROBLEM,
164 "--%s can be specified only once", what);
165
166 if (xtables_check_inverse(optarg, &invert, NULL, 0, argv))
167 xtables_error(PARAMETER_PROBLEM,
168 "Unexpected `!' after --%s", what);
169
170 if (!argv[optind]
171 || argv[optind][0] == '-' || argv[optind][0] == '!')
172 xtables_error(PARAMETER_PROBLEM,
173 "--%s requires two args.", what);
174
175 if (strlen(optarg) > IPSET_MAXNAMELEN - 1)
176 xtables_error(PARAMETER_PROBLEM,
177 "setname `%s' too long, max %d characters.",
178 optarg, IPSET_MAXNAMELEN - 1);
179
180 get_set_byname(optarg, info);
181 parse_dirs(argv[optind], info);
182 optind++;
183
184 *flags = 1;
185}
186
187static int
188set_target_parse(int c, char **argv, int invert, unsigned int *flags,
189 const void *entry, struct xt_entry_target **target)
190{
191 struct xt_set_info_target *myinfo =
192 (struct xt_set_info_target *) (*target)->data;
193
194 switch (c) {
195 case '1': /* --add-set <set> <flags> */
196 parse_target(argv, invert, flags,
197 &myinfo->add_set, "add-set");
198 break;
199 case '2': /* --del-set <set>[:<flags>] <flags> */
200 parse_target(argv, invert, flags,
201 &myinfo->del_set, "del-set");
202 break;
Jozsef Kadlecsikd40f1622010-06-16 12:45:33 +0200203 }
204 return 1;
205}
206
207static void
208print_target(const char *prefix, const struct xt_set_info *info)
209{
210 int i;
211 char setname[IPSET_MAXNAMELEN];
212
213 if (info->index == IPSET_INVALID_ID)
214 return;
215 get_set_byid(setname, info->index);
Jan Engelhardt73866352010-12-18 02:04:59 +0100216 printf(" %s %s", prefix, setname);
Jozsef Kadlecsik6f03bf72011-01-21 21:55:05 +0100217 for (i = 1; i <= info->dim; i++) {
Jozsef Kadlecsikd40f1622010-06-16 12:45:33 +0200218 printf("%s%s",
219 i == 1 ? " " : ",",
220 info->flags & (1 << i) ? "src" : "dst");
221 }
Jozsef Kadlecsikd40f1622010-06-16 12:45:33 +0200222}
223
224static void
225set_target_print(const void *ip, const struct xt_entry_target *target,
226 int numeric)
227{
228 const struct xt_set_info_target *info = (const void *)target->data;
229
230 print_target("add-set", &info->add_set);
231 print_target("del-set", &info->del_set);
232}
233
234static void
235set_target_save(const void *ip, const struct xt_entry_target *target)
236{
237 const struct xt_set_info_target *info = (const void *)target->data;
238
239 print_target("--add-set", &info->add_set);
240 print_target("--del-set", &info->del_set);
241}
242
243static struct xtables_target set_tg_reg[] = {
244 {
245 .name = "SET",
246 .revision = 0,
247 .version = XTABLES_VERSION,
248 .family = NFPROTO_IPV4,
249 .size = XT_ALIGN(sizeof(struct xt_set_info_target_v0)),
250 .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v0)),
251 .help = set_target_help,
252 .init = set_target_init_v0,
253 .parse = set_target_parse_v0,
254 .final_check = set_target_check,
255 .print = set_target_print_v0,
256 .save = set_target_save_v0,
257 .extra_opts = set_target_opts,
258 },
259 {
260 .name = "SET",
261 .revision = 1,
262 .version = XTABLES_VERSION,
263 .family = NFPROTO_UNSPEC,
264 .size = XT_ALIGN(sizeof(struct xt_set_info_target)),
265 .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target)),
266 .help = set_target_help,
267 .init = set_target_init,
268 .parse = set_target_parse,
269 .final_check = set_target_check,
270 .print = set_target_print,
271 .save = set_target_save,
272 .extra_opts = set_target_opts,
273 },
274};
275
276void _init(void)
277{
278 xtables_register_targets(set_tg_reg, ARRAY_SIZE(set_tg_reg));
279}