prevent source code corruption with static build (reported by Tino Keitel)
[jleu-ebtables.git] / ebtablesd.c
blob062a2d6b5afa3bafca81ca4a7195da9323c38acf
1 /*
2 * ebtablesd.c, January 2005
4 * Author: Bart De Schuymer
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.
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.
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.
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"
32 #define OPT_KERNELDATA 0x800 /* Also defined in ebtables.c */
34 static struct ebt_u_replace replace[3];
35 #define OPEN_METHOD_FILE 1
36 #define OPEN_METHOD_KERNEL 2
37 static int open_method[3];
38 void ebt_early_init_once();
40 static void sigpipe_handler(int sig)
43 static void copy_table_names()
45 strcpy(replace[0].name, "filter");
46 strcpy(replace[1].name, "nat");
47 strcpy(replace[2].name, "broute");
50 int main(int argc_, char *argv_[])
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, base = 0, offset = 0, n = 0, ret = 0, quotemode = 0;
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);
66 /* Not usually reached */
67 exit(0);
68 case -1:
69 return -1;
71 default: /* Parent */
72 wait(NULL);
75 if (mkfifo(EBTD_PIPE, 0600) < 0 && errno != EEXIST) {
76 printf("Error creating FIFO " EBTD_PIPE "\n");
77 ret = -1;
78 goto do_exit;
81 if ((readfd = open(EBTD_PIPE, O_RDONLY | O_NONBLOCK, 0)) == -1) {
82 perror("open");
83 ret = -1;
84 goto do_exit;
87 if (signal(SIGPIPE, sigpipe_handler) == SIG_ERR) {
88 perror("signal");
89 ret = -1;
90 goto do_exit;
93 ebt_silent = 1;
95 copy_table_names();
96 ebt_early_init_once();
98 while (1) {
99 int n2, i, argc, table_nr, ntot;
101 /* base == 0 */
102 ntot = read(readfd, cmdline+offset, EBTD_CMDLINE_MAXLN-offset-1);
103 if (ntot <= 0)
104 continue;
105 ntot += offset;
106 continue_read:
107 /* Put '\0' between arguments. */
108 for (; offset < ntot; n++, offset++) {
109 if (cmdline[offset] == '\"') {
110 quotemode ^= 1;
111 cmdline[offset] = '\0';
112 } else if (!quotemode && cmdline[offset] == ' ') {
113 cmdline[offset] = '\0';
114 } else if (cmdline[offset] == '\n') {
115 if (quotemode)
116 ebt_print_error("ebtablesd: wrong number of \" delimiters");
117 cmdline[offset] = '\0';
118 break;
121 if (n == 0) {
122 if (offset == ntot) {
123 /* The ntot bytes were parsed and ended with '\n' */
124 base = 0;
125 offset = 0;
126 continue;
128 offset++;
129 base = offset;
130 n = 0;
131 goto continue_read;
133 if (offset == ntot) { /* The ntot bytes were parsed but no complete rule is yet specified */
134 if (base == 0) {
135 ebt_print_error("ebtablesd: the maximum command line length is %d", EBTD_CMDLINE_MAXLN-1);
136 goto write_msg;
138 memmove(cmdline, cmdline+base+offset, ntot-offset);
139 offset -= base;
140 offset++;
141 base = 0;
142 continue;
145 table_nr = 0;
146 n2 = 0;
147 argc = 0;
148 while (n2 < n && argc < EBTD_ARGC_MAX) {
149 if (*(cmdline + base + n2) == '\0') {
150 n2++;
151 continue;
153 argv[argc++] = cmdline + base + n2;
154 n2 += strlen(cmdline + base + n2) + 1;
156 offset++; /* Move past the '\n' */
157 base = offset;
159 if (argc > EBTD_ARGC_MAX) {
160 ebt_print_error("ebtablesd: maximum %d arguments "
161 "allowed", EBTD_ARGC_MAX - 1);
162 goto write_msg;
164 if (argc == 1) {
165 ebt_print_error("ebtablesd: no arguments");
166 goto write_msg;
169 /* Parse the options */
170 if (!strcmp(argv[1], "-t")) {
171 if (argc < 3) {
172 ebt_print_error("ebtablesd: -t but no table");
173 goto write_msg;
175 for (i = 0; i < 3; i++)
176 if (!strcmp(replace[i].name, argv[2]))
177 break;
178 if (i == 3) {
179 ebt_print_error("ebtablesd: table '%s' was "
180 "not recognized", argv[2]);
181 goto write_msg;
183 table_nr = i;
184 } else if (!strcmp(argv[1], "free")) {
185 if (argc != 3) {
186 ebt_print_error("ebtablesd: command free "
187 "needs exactly one argument");
188 goto write_msg;
190 for (i = 0; i < 3; i++)
191 if (!strcmp(replace[i].name, argv[2]))
192 break;
193 if (i == 3) {
194 ebt_print_error("ebtablesd: table '%s' was "
195 "not recognized", argv[2]);
196 goto write_msg;
198 if (!(replace[i].flags & OPT_KERNELDATA)) {
199 ebt_print_error("ebtablesd: table %s has not "
200 "been opened");
201 goto write_msg;
203 ebt_cleanup_replace(&replace[i]);
204 copy_table_names();
205 replace[i].flags &= ~OPT_KERNELDATA;
206 goto write_msg;
207 } else if (!strcmp(argv[1], "open")) {
208 if (argc != 3) {
209 ebt_print_error("ebtablesd: command open "
210 "needs exactly one argument");
211 goto write_msg;
214 for (i = 0; i < 3; i++)
215 if (!strcmp(replace[i].name, argv[2]))
216 break;
217 if (i == 3) {
218 ebt_print_error("ebtablesd: table '%s' was "
219 "not recognized", argv[2]);
220 goto write_msg;
222 if (replace[i].flags & OPT_KERNELDATA) {
223 ebt_print_error("ebtablesd: table %s needs to "
224 "be freed before it can be "
225 "opened");
226 goto write_msg;
228 if (!ebt_get_kernel_table(&replace[i], 0)) {
229 replace[i].flags |= OPT_KERNELDATA;
230 open_method[i] = OPEN_METHOD_KERNEL;
232 goto write_msg;
233 } else if (!strcmp(argv[1], "fopen")) {
234 struct ebt_u_replace tmp;
236 memset(&tmp, 0, sizeof(tmp));
237 if (argc != 4) {
238 ebt_print_error("ebtablesd: command fopen "
239 "needs exactly two arguments");
240 goto write_msg;
243 for (i = 0; i < 3; i++)
244 if (!strcmp(replace[i].name, argv[2]))
245 break;
246 if (i == 3) {
247 ebt_print_error("ebtablesd: table '%s' was "
248 "not recognized", argv[2]);
249 goto write_msg;
251 if (replace[i].flags & OPT_KERNELDATA) {
252 ebt_print_error("ebtablesd: table %s needs to "
253 "be freed before it can be "
254 "opened");
255 goto write_msg;
257 tmp.filename = (char *)malloc(strlen(argv[3]) + 1);
258 if (!tmp.filename) {
259 ebt_print_error("Out of memory");
260 goto write_msg;
262 strcpy(tmp.filename, argv[3]);
263 strcpy(tmp.name, "filter");
264 tmp.command = 'L'; /* Make sure retrieve_from_file()
265 * doesn't complain about wrong
266 * table name */
268 ebt_get_kernel_table(&tmp, 0);
269 free(tmp.filename);
270 tmp.filename = NULL;
271 if (ebt_errormsg[0] != '\0')
272 goto write_msg;
274 if (strcmp(tmp.name, argv[2])) {
275 ebt_print_error("ebtablesd: opened file with "
276 "wrong table name '%s'", tmp.name);
277 ebt_cleanup_replace(&tmp);
278 goto write_msg;
280 replace[i] = tmp;
281 replace[i].command = '\0';
282 replace[i].flags |= OPT_KERNELDATA;
283 open_method[i] = OPEN_METHOD_FILE;
284 goto write_msg;
285 } else if (!strcmp(argv[1], "commit")) {
286 if (argc != 3) {
287 ebt_print_error("ebtablesd: command commit "
288 "needs exactly one argument");
289 goto write_msg;
292 for (i = 0; i < 3; i++)
293 if (!strcmp(replace[i].name, argv[2]))
294 break;
295 if (i == 3) {
296 ebt_print_error("ebtablesd: table '%s' was "
297 "not recognized", argv[2]);
298 goto write_msg;
300 if (!(replace[i].flags & OPT_KERNELDATA)) {
301 ebt_print_error("ebtablesd: table %s has not "
302 "been opened");
303 goto write_msg;
305 /* The counters from the kernel are useless if we
306 * didn't start from a kernel table */
307 if (open_method[i] == OPEN_METHOD_FILE)
308 replace[i].num_counters = 0;
309 ebt_deliver_table(&replace[i]);
310 if (ebt_errormsg[0] == '\0' && open_method[i] == OPEN_METHOD_KERNEL)
311 ebt_deliver_counters(&replace[i]);
312 goto write_msg;
313 } else if (!strcmp(argv[1], "fcommit")) {
314 if (argc != 4) {
315 ebt_print_error("ebtablesd: command commit "
316 "needs exactly two argument");
317 goto write_msg;
320 for (i = 0; i < 3; i++)
321 if (!strcmp(replace[i].name, argv[2]))
322 break;
323 if (i == 3) {
324 ebt_print_error("ebtablesd: table '%s' was "
325 "not recognized", argv[2]);
326 goto write_msg;
328 if (!(replace[i].flags & OPT_KERNELDATA)) {
329 ebt_print_error("ebtablesd: table %s has not "
330 "been opened");
331 goto write_msg;
333 replace[i].filename = (char *)malloc(strlen(argv[3]) + 1);
334 if (!replace[i].filename) {
335 ebt_print_error("Out of memory");
336 goto write_msg;
338 strcpy(replace[i].filename, argv[3]);
339 ebt_deliver_table(&replace[i]);
340 if (ebt_errormsg[0] == '\0' && open_method[i] == OPEN_METHOD_KERNEL)
341 ebt_deliver_counters(&replace[i]);
342 free(replace[i].filename);
343 replace[i].filename = NULL;
344 goto write_msg;
345 }else if (!strcmp(argv[1], "quit")) {
346 if (argc != 2) {
347 ebt_print_error("ebtablesd: command quit does "
348 "not take any arguments");
349 goto write_msg;
351 break;
353 if (!(replace[table_nr].flags & OPT_KERNELDATA)) {
354 ebt_print_error("ebtablesd: table %s has not been "
355 "opened", replace[table_nr].name);
356 goto write_msg;
358 optind = 0; /* Setting optind = 1 causes serious annoyances */
359 do_command(argc, argv, EXEC_STYLE_DAEMON, &replace[table_nr]);
360 ebt_reinit_extensions();
361 write_msg:
362 #ifndef SILENT_DAEMON
363 if (ebt_errormsg[0] != '\0')
364 printf("%s.\n", ebt_errormsg);
365 #endif
366 ebt_errormsg[0]= '\0';
367 n = 0;
368 goto continue_read;
370 do_exit:
371 unlink(EBTD_PIPE);
373 return 0;