Don't use 'release' macro.
[platform/upstream/ebtables.git] / ebtablesd.c
1 /*
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
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();
39
40 static void sigpipe_handler(int sig)
41 {
42 }
43 static void copy_table_names()
44 {
45         strcpy(replace[0].name, "filter");
46         strcpy(replace[1].name, "nat");
47         strcpy(replace[2].name, "broute");
48 }
49
50 int 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, base = 0, offset = 0, n = 0, ret = 0, quotemode = 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
95         copy_table_names();
96         ebt_early_init_once();
97
98         while (1) {
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;
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;
119                         }
120                 }
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;
127                         }
128                         offset++;
129                         base = offset;
130                         n = 0;
131                         goto continue_read;
132                 }
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;
137                         }
138                         memmove(cmdline, cmdline+base+offset, ntot-offset);
139                         offset -= base;
140                         offset++;
141                         base = 0;
142                         continue;
143                 }
144
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;
152                         }
153                         argv[argc++] = cmdline + base + n2;
154                         n2 += strlen(cmdline + base + n2) + 1;
155                 }
156                 offset++; /* Move past the '\n' */
157                 base = offset;
158
159                 if (argc > EBTD_ARGC_MAX) {
160                         ebt_print_error("ebtablesd: maximum %d arguments "
161                                         "allowed", EBTD_ARGC_MAX - 1);
162                         goto write_msg;
163                 }
164                 if (argc == 1) {
165                         ebt_print_error("ebtablesd: no arguments");
166                         goto write_msg;
167                 }
168
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;
174                         }
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;
182                         }
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;
189                         }
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;
197                         }
198                         if (!(replace[i].flags & OPT_KERNELDATA)) {
199                                 ebt_print_error("ebtablesd: table %s has not "
200                                                 "been opened");
201                                 goto write_msg;
202                         }
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;
212                         }
213
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;
221                         }
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;
227                         }
228                         if (!ebt_get_kernel_table(&replace[i], 0)) {
229                                 replace[i].flags |= OPT_KERNELDATA;
230                                 open_method[i] = OPEN_METHOD_KERNEL;
231                         }
232                         goto write_msg;
233                 } else if (!strcmp(argv[1], "fopen")) {
234                         struct ebt_u_replace tmp;
235
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;
241                         }
242
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;
250                         }
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;
256                         }
257                         tmp.filename = (char *)malloc(strlen(argv[3]) + 1);
258                         if (!tmp.filename) {
259                                 ebt_print_error("Out of memory");
260                                 goto write_msg;
261                         }
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 */
267
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;
273
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;
279                         }
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;
290                         }
291
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;
299                         }
300                         if (!(replace[i].flags & OPT_KERNELDATA)) {
301                                 ebt_print_error("ebtablesd: table %s has not "
302                                                 "been opened");
303                                 goto write_msg;
304                         }
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;
318                         }
319
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;
327                         }
328                         if (!(replace[i].flags & OPT_KERNELDATA)) {
329                                 ebt_print_error("ebtablesd: table %s has not "
330                                                 "been opened");
331                                 goto write_msg;
332                         }
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;
337                         }
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;
350                         }
351                         break;
352                 }
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;
357                 }
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;
369         }
370 do_exit:
371         unlink(EBTD_PIPE);
372         
373         return 0;
374 }