blob: d1fef5aca6c5b35f24a39b1450e967ff7b5127b9 [file] [log] [blame]
Bart De Schuymer6622a012005-01-19 21:09:05 +00001/*
2 * ebtablesd.c, January 2005
3 *
4 * Author: Bart De Schuymer
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <unistd.h>
24#include <signal.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <sys/wait.h>
28#include <fcntl.h>
29#include <errno.h>
30#include "include/ebtables_u.h"
31
32#define OPT_KERNELDATA 0x800 /* Also defined in ebtables.c */
33
34static struct ebt_u_replace replace[3];
35#define OPEN_METHOD_FILE 1
36#define OPEN_METHOD_KERNEL 2
37static int open_method[3];
38void ebt_early_init_once();
39
40static void sigpipe_handler(int sig)
41{
42}
Bart De Schuymerd1c9cec2005-01-24 21:09:59 +000043static void copy_table_names()
44{
45 strcpy(replace[0].name, "filter");
46 strcpy(replace[1].name, "nat");
47 strcpy(replace[2].name, "broute");
48}
Bart De Schuymer6622a012005-01-19 21:09:05 +000049
50int main(int argc_, char *argv_[])
51{
52 char *argv[EBTD_ARGC_MAX], *args[4], name[] = "mkdir",
53 mkdir_option[] = "-p", mkdir_dir[] = EBTD_PIPE_DIR,
54 cmdline[EBTD_CMDLINE_MAXLN];
55 int readfd, stop = 0, base = 0, offset = 0, n = 0, ret = 0;
56
57 /* Make sure the pipe directory exists */
58 args[0] = name;
59 args[1] = mkdir_option;
60 args[2] = mkdir_dir;
61 args[3] = NULL;
62 switch (fork()) {
63 case 0:
64 execvp(args[0], args);
65
66 /* Not usually reached */
67 exit(0);
68 case -1:
69 return -1;
70
71 default: /* Parent */
72 wait(NULL);
73 }
74
75 if (mkfifo(EBTD_PIPE, 0600) < 0 && errno != EEXIST) {
76 printf("Error creating FIFO " EBTD_PIPE "\n");
77 ret = -1;
78 goto do_exit;
79 }
80
81 if ((readfd = open(EBTD_PIPE, O_RDONLY | O_NONBLOCK, 0)) == -1) {
82 perror("open");
83 ret = -1;
84 goto do_exit;
85 }
86
87 if (signal(SIGPIPE, sigpipe_handler) == SIG_ERR) {
88 perror("signal");
89 ret = -1;
90 goto do_exit;
91 }
92
93 ebt_silent = 1;
94
Bart De Schuymerd1c9cec2005-01-24 21:09:59 +000095 copy_table_names();
Bart De Schuymer6622a012005-01-19 21:09:05 +000096 ebt_early_init_once();
97
98 while (!stop) {
99 int n2, i, argc, table_nr, ntot;
100
101 /* base == 0 */
102 ntot = read(readfd, cmdline+offset, EBTD_CMDLINE_MAXLN-offset-1);
103 if (ntot <= 0)
104 continue;
105 ntot += offset;
106continue_read:
107 /* Change all ' ' into '\0'. This implies that the user is not
108 * allowed to use spaces (that don't distinguish options or
109 * commands) in her rules. This comes down to not allowing spaces
110 * in options like the string of --ulog-prefix (use '_' instead).
111 */
112 for (; offset < ntot; n++, offset++) {
113 if (cmdline[offset] == ' ')
114 cmdline[offset] = '\0';
115 if (cmdline[offset] == '\n') {
116 cmdline[offset] = '\0';
117 break;
118 }
119 }
120 if (n == 0) {
121 if (offset == ntot) {
122 /* The ntot bytes were parsed and ended with '\n' */
123 base = 0;
124 offset = 0;
125 continue;
126 }
127 offset++;
128 base = offset;
129 n = 0;
130 goto continue_read;
131 }
132 if (offset == ntot) { /* The ntot bytes were parsed but no complete rule is yet specified */
133 if (base == 0) {
134 ebt_print_error("ebtablesd: the maximum command line length is %d", EBTD_CMDLINE_MAXLN-1);
135 goto write_msg;
136 }
137 memmove(cmdline, cmdline+base+offset, ntot-offset);
138 offset -= base;
139 offset++;
140 base = 0;
141 continue;
142 }
143
144 table_nr = 0;
145 n2 = 0;
146 argc = 0;
147 while (n2 < n && argc < EBTD_ARGC_MAX) {
148 argv[argc++] = cmdline + base + n2;
149 n2 += strlen(cmdline + base + n2) + 1;
150 }
151 offset++; /* Move past the '\n' */
152 base = offset;
153
154 if (argc > EBTD_ARGC_MAX) {
155 ebt_print_error("ebtablesd: maximum %d arguments "
156 "allowed", EBTD_ARGC_MAX - 1);
157 goto write_msg;
158 }
159 if (argc == 1) {
160 ebt_print_error("ebtablesd: no arguments");
161 goto write_msg;
162 }
163
164 /* Parse the options */
165 if (!strcmp(argv[1], "-t")) {
166 if (argc < 3) {
167 ebt_print_error("ebtablesd: -t but no table");
168 goto write_msg;
169 }
170 for (i = 0; i < 3; i++)
171 if (!strcmp(replace[i].name, argv[2]))
172 break;
173 if (i == 3) {
174 ebt_print_error("ebtablesd: table '%s' was "
175 "not recognized", argv[2]);
176 goto write_msg;
177 }
178 table_nr = i;
179 } else if (!strcmp(argv[1], "free")) {
180 if (argc != 3) {
181 ebt_print_error("ebtablesd: command free "
182 "needs exactly one argument");
183 goto write_msg;
184 }
185 for (i = 0; i < 3; i++)
186 if (!strcmp(replace[i].name, argv[2]))
187 break;
188 if (i == 3) {
189 ebt_print_error("ebtablesd: table '%s' was "
190 "not recognized", argv[2]);
191 goto write_msg;
192 }
193 if (!(replace[i].flags & OPT_KERNELDATA)) {
194 ebt_print_error("ebtablesd: table %s has not "
195 "been opened");
196 goto write_msg;
197 }
198 ebt_cleanup_replace(&replace[i]);
Bart De Schuymerd1c9cec2005-01-24 21:09:59 +0000199 copy_table_names();
Bart De Schuymer6622a012005-01-19 21:09:05 +0000200 replace[i].flags &= ~OPT_KERNELDATA;
201 goto write_msg;
202 } else if (!strcmp(argv[1], "open")) {
203 if (argc != 3) {
204 ebt_print_error("ebtablesd: command open "
205 "needs exactly one argument");
206 goto write_msg;
207 }
208
209 for (i = 0; i < 3; i++)
210 if (!strcmp(replace[i].name, argv[2]))
211 break;
212 if (i == 3) {
213 ebt_print_error("ebtablesd: table '%s' was "
214 "not recognized", argv[2]);
215 goto write_msg;
216 }
217 if (replace[i].flags & OPT_KERNELDATA) {
218 ebt_print_error("ebtablesd: table %s needs to "
219 "be freed before it can be "
220 "opened");
221 goto write_msg;
222 }
223 if (!ebt_get_kernel_table(&replace[i], 0)) {
224 replace[i].flags |= OPT_KERNELDATA;
225 open_method[i] = OPEN_METHOD_KERNEL;
226 }
227 goto write_msg;
228 } else if (!strcmp(argv[1], "fopen")) {
229 struct ebt_u_replace tmp;
230
231 memset(&tmp, 0, sizeof(tmp));
232 if (argc != 4) {
233 ebt_print_error("ebtablesd: command fopen "
234 "needs exactly two arguments");
235 goto write_msg;
236 }
237
238 for (i = 0; i < 3; i++)
239 if (!strcmp(replace[i].name, argv[2]))
240 break;
241 if (i == 3) {
242 ebt_print_error("ebtablesd: table '%s' was "
243 "not recognized", argv[2]);
244 goto write_msg;
245 }
246 if (replace[i].flags & OPT_KERNELDATA) {
247 ebt_print_error("ebtablesd: table %s needs to "
248 "be freed before it can be "
249 "opened");
250 goto write_msg;
251 }
252 tmp.filename = (char *)malloc(strlen(argv[3]) + 1);
253 if (!tmp.filename) {
254 ebt_print_error("Out of memory");
255 goto write_msg;
256 }
257 strcpy(tmp.filename, argv[3]);
258 strcpy(tmp.name, "filter");
259 tmp.command = 'L'; /* Make sure retrieve_from_file()
260 * doesn't complain about wrong
261 * table name */
262
263 ebt_get_kernel_table(&tmp, 0);
264 free(tmp.filename);
265 tmp.filename = NULL;
266 if (ebt_errormsg[0] != '\0')
267 goto write_msg;
268
269 if (strcmp(tmp.name, argv[2])) {
270 ebt_print_error("ebtablesd: opened file with "
271 "wrong table name '%s'", tmp.name);
272 ebt_cleanup_replace(&tmp);
273 goto write_msg;
274 }
275 replace[i] = tmp;
276 replace[i].command = '\0';
277 replace[i].flags |= OPT_KERNELDATA;
278 open_method[i] = OPEN_METHOD_FILE;
279 goto write_msg;
280 } else if (!strcmp(argv[1], "commit")) {
281 if (argc != 3) {
282 ebt_print_error("ebtablesd: command commit "
283 "needs exactly one argument");
284 goto write_msg;
285 }
286
287 for (i = 0; i < 3; i++)
288 if (!strcmp(replace[i].name, argv[2]))
289 break;
290 if (i == 3) {
291 ebt_print_error("ebtablesd: table '%s' was "
292 "not recognized", argv[2]);
293 goto write_msg;
294 }
295 if (!(replace[i].flags & OPT_KERNELDATA)) {
296 ebt_print_error("ebtablesd: table %s has not "
297 "been opened");
298 goto write_msg;
299 }
300 /* The counters from the kernel are useless if we
301 * didn't start from a kernel table */
302 if (open_method[i] == OPEN_METHOD_FILE)
303 replace[i].num_counters = 0;
304 ebt_deliver_table(&replace[i]);
305 if (ebt_errormsg[0] == '\0' && open_method[i] == OPEN_METHOD_KERNEL)
306 ebt_deliver_counters(&replace[i], EXEC_STYLE_DAEMON);
307 goto write_msg;
308 } else if (!strcmp(argv[1], "fcommit")) {
309 if (argc != 4) {
310 ebt_print_error("ebtablesd: command commit "
311 "needs exactly two argument");
312 goto write_msg;
313 }
314
315 for (i = 0; i < 3; i++)
316 if (!strcmp(replace[i].name, argv[2]))
317 break;
318 if (i == 3) {
319 ebt_print_error("ebtablesd: table '%s' was "
320 "not recognized", argv[2]);
321 goto write_msg;
322 }
323 if (!(replace[i].flags & OPT_KERNELDATA)) {
324 ebt_print_error("ebtablesd: table %s has not "
325 "been opened");
326 goto write_msg;
327 }
328 replace[i].filename = (char *)malloc(strlen(argv[3]) + 1);
329 if (!replace[i].filename) {
330 ebt_print_error("Out of memory");
331 goto write_msg;
332 }
333 strcpy(replace[i].filename, argv[3]);
334 ebt_deliver_table(&replace[i]);
335 if (ebt_errormsg[0] == '\0' && open_method[i] == OPEN_METHOD_KERNEL)
336 ebt_deliver_counters(&replace[i], EXEC_STYLE_DAEMON);
337 free(replace[i].filename);
338 replace[i].filename = NULL;
339 goto write_msg;
340 }else if (!strcmp(argv[1], "quit")) {
341 if (argc != 2) {
342 ebt_print_error("ebtablesd: command quit does "
343 "not take any arguments");
344 goto write_msg;
345 }
346 stop = 1;
347 goto write_msg;
348 }
349 if (!(replace[table_nr].flags & OPT_KERNELDATA)) {
350 ebt_print_error("ebtablesd: table %s has not been "
351 "opened", replace[table_nr].name);
352 goto write_msg;
353 }
Bart De Schuymerb92edb82005-01-23 19:08:14 +0000354 optind = 0; /* Setting optind = 1 causes serious annoyances */
Bart De Schuymer6622a012005-01-19 21:09:05 +0000355 do_command(argc, argv, EXEC_STYLE_DAEMON, &replace[table_nr]);
356 ebt_reinit_extensions();
357write_msg:
358#ifndef SILENT_DAEMON
359 if (ebt_errormsg[0] != '\0')
Bart De Schuymer87889eb2005-01-24 22:25:27 +0000360 printf("%s.\n", ebt_errormsg);
Bart De Schuymer6622a012005-01-19 21:09:05 +0000361#endif
362 ebt_errormsg[0]= '\0';
363 n = 0;
364 goto continue_read;
365 }
366do_exit:
367 unlink(EBTD_PIPE);
368
369 return 0;
370}