Branch data Line data Source code
1 : : /*
2 : : *****************************************************************************
3 : : *
4 : : * File: fw_util_firewalld.c
5 : : *
6 : : * Purpose: Fwknop routines for managing firewalld firewall rules.
7 : : *
8 : : * Fwknop is developed primarily by the people listed in the file 'AUTHORS'.
9 : : * Copyright (C) 2009-2014 fwknop developers and contributors. For a full
10 : : * list of contributors, see the file 'CREDITS'.
11 : : *
12 : : * License (GNU General Public License):
13 : : *
14 : : * This program is free software; you can redistribute it and/or
15 : : * modify it under the terms of the GNU General Public License
16 : : * as published by the Free Software Foundation; either version 2
17 : : * of the License, or (at your option) any later version.
18 : : *
19 : : * This program is distributed in the hope that it will be useful,
20 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 : : * GNU General Public License for more details.
23 : : *
24 : : * You should have received a copy of the GNU General Public License
25 : : * along with this program; if not, write to the Free Software
26 : : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 : : * USA
28 : : *
29 : : *****************************************************************************
30 : : */
31 : :
32 : : #include "fwknopd_common.h"
33 : :
34 : : #ifdef FIREWALL_FIREWALLD
35 : :
36 : : #include "fw_util.h"
37 : : #include "utils.h"
38 : : #include "log_msg.h"
39 : : #include "extcmd.h"
40 : : #include "access.h"
41 : :
42 : : static struct fw_config fwc;
43 : : static char cmd_buf[CMD_BUFSIZE];
44 : : static char err_buf[CMD_BUFSIZE];
45 : : static char cmd_out[STANDARD_CMD_OUT_BUFSIZE];
46 : :
47 : : /* assume 'firewall-cmd --direct --passthrough ipv4 -C' is offered
48 : : * (see firewd_chk_support()).
49 : : */
50 : : static int have_firewd_chk_support = 1;
51 : :
52 : : static void
53 : 0 : zero_cmd_buffers(void)
54 : : {
55 : : memset(cmd_buf, 0x0, CMD_BUFSIZE);
56 : : memset(err_buf, 0x0, CMD_BUFSIZE);
57 : : memset(cmd_out, 0x0, STANDARD_CMD_OUT_BUFSIZE);
58 : 0 : }
59 : :
60 : : static int pid_status = 0;
61 : :
62 : : static void
63 : 0 : chop_newline(char *str)
64 : : {
65 [ # # ][ # # ]: 0 : if(str[0] != 0x0 && str[strlen(str)-1] == 0x0a)
66 : 0 : str[strlen(str)-1] = 0x0;
67 : 0 : return;
68 : : }
69 : :
70 : : static int
71 : 0 : rule_exists_no_chk_support(const fko_srv_options_t * const opts,
72 : : const struct fw_chain * const fwc, const unsigned int proto,
73 : : const char * const srcip, const char * const dstip,
74 : : const unsigned int port, const unsigned int exp_ts)
75 : : {
76 : 0 : int rule_exists=0;
77 : 0 : char cmd_buf[CMD_BUFSIZE] = {0};
78 : 0 : char target_search[CMD_BUFSIZE] = {0};
79 : 0 : char proto_search[CMD_BUFSIZE] = {0};
80 : 0 : char srcip_search[CMD_BUFSIZE] = {0};
81 : 0 : char dstip_search[CMD_BUFSIZE] = {0};
82 : 0 : char port_search[CMD_BUFSIZE] = {0};
83 : 0 : char exp_ts_search[CMD_BUFSIZE] = {0};
84 : :
85 : : snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_LIST_RULES_ARGS,
86 : 0 : opts->fw_config->fw_command,
87 : 0 : fwc->table,
88 : 0 : fwc->to_chain
89 : : );
90 : :
91 : : #if CODE_COVERAGE
92 : 0 : int pid_status = 0;
93 : : /* If we're maximizing code coverage, then exercise the run_extcmd_write()
94 : : * function which is normally only used for the PF firewall. This is to
95 : : * maximize code coverage in conjunction with the test suite, and is never
96 : : * compiled in for a production release of fwknop.
97 : : */
98 [ # # ]: 0 : if(run_extcmd_write("/bin/grep -v test", "/bin/echo test", &pid_status, opts) == 0)
99 : 0 : log_msg(LOG_WARNING, "[ignore] Code coverage: Executed command");
100 : : #endif
101 : :
102 [ # # ]: 0 : if(proto == IPPROTO_TCP)
103 : : snprintf(proto_search, CMD_BUFSIZE-1, " tcp ");
104 [ # # ]: 0 : else if(proto == IPPROTO_UDP)
105 : : snprintf(proto_search, CMD_BUFSIZE-1, " udp ");
106 [ # # ]: 0 : else if(proto == IPPROTO_ICMP)
107 : : snprintf(proto_search, CMD_BUFSIZE-1, " icmp ");
108 : : else
109 : : snprintf(proto_search, CMD_BUFSIZE-1, " %u ", proto);
110 : :
111 : : snprintf(port_search, CMD_BUFSIZE-1, ":%u ", port);
112 : 0 : snprintf(target_search, CMD_BUFSIZE-1, " %s ", fwc->target);
113 : : snprintf(srcip_search, CMD_BUFSIZE-1, " %s ", srcip);
114 [ # # ]: 0 : if (dstip != NULL)
115 : : {
116 : : snprintf(dstip_search, CMD_BUFSIZE-1, " %s ", dstip);
117 : : }
118 : : snprintf(exp_ts_search, CMD_BUFSIZE-1, "%u ", exp_ts);
119 : :
120 : : /* search for each of the substrings - yes, matches from different
121 : : * rules may get triggered here, but the expiration time is the
122 : : * primary search method
123 : : */
124 [ # # # # ]: 0 : if(search_extcmd(cmd_buf, WANT_STDERR, NO_TIMEOUT, exp_ts_search, &pid_status, opts)
125 [ # # ]: 0 : && search_extcmd(cmd_buf, WANT_STDERR, NO_TIMEOUT, proto_search, &pid_status, opts)
126 [ # # ]: 0 : && search_extcmd(cmd_buf, WANT_STDERR, NO_TIMEOUT, srcip_search, &pid_status, opts)
127 [ # # ]: 0 : && (dstip == NULL) ? 1 : search_extcmd(cmd_buf, WANT_STDERR, NO_TIMEOUT, dstip_search, &pid_status, opts)
128 [ # # ]: 0 : && search_extcmd(cmd_buf, WANT_STDERR, NO_TIMEOUT, target_search, &pid_status, opts)
129 [ # # ]: 0 : && search_extcmd(cmd_buf, WANT_STDERR, NO_TIMEOUT, port_search, &pid_status, opts))
130 : : rule_exists = 1;
131 : :
132 [ # # ]: 0 : if(rule_exists)
133 : 0 : log_msg(LOG_DEBUG,
134 : : "rule_exists_no_chk_support() %s %u -> %s expires: %u rule (already exists",
135 : : proto_search, port, srcip, exp_ts);
136 : : else
137 : 0 : log_msg(LOG_DEBUG,
138 : : "rule_exists_no_chk_support() %s %u -> %s expires: %u rule does not exist",
139 : : proto_search, port, srcip, exp_ts);
140 : :
141 : 0 : return(rule_exists);
142 : : }
143 : :
144 : : static int
145 : 0 : rule_exists_chk_support(const fko_srv_options_t * const opts,
146 : : const char * const chain, const char * const rule)
147 : : {
148 : 0 : int rule_exists = 0;
149 : 0 : int res = 0;
150 : :
151 : 0 : zero_cmd_buffers();
152 : :
153 : : snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_CHK_RULE_ARGS,
154 : 0 : opts->fw_config->fw_command, chain, rule);
155 : :
156 : 0 : res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
157 : : WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
158 : 0 : chop_newline(err_buf);
159 : :
160 : 0 : log_msg(LOG_DEBUG, "rule_exists_chk_support() CMD: '%s' (res: %d, err: %s)",
161 : : cmd_buf, res, err_buf);
162 : :
163 [ # # ]: 0 : if(strncmp(err_buf, "success", strlen("success")) == 0)
164 : : {
165 : 0 : rule_exists = 1;
166 : 0 : log_msg(LOG_DEBUG, "rule_exists_chk_support() Rule : '%s' in %s already exists",
167 : : rule, chain);
168 : : }
169 : : else
170 : : {
171 : 0 : log_msg(LOG_DEBUG, "rule_exists_chk_support() Rule : '%s' in %s does not exist",
172 : : rule, chain);
173 : : }
174 : :
175 : 0 : return(rule_exists);
176 : : }
177 : :
178 : : static int
179 : 0 : rule_exists(const fko_srv_options_t * const opts,
180 : : const struct fw_chain * const fwc, const char * const rule,
181 : : const unsigned int proto, const char * const srcip,
182 : : const char * const dstip, const unsigned int port,
183 : : const unsigned int exp_ts)
184 : : {
185 : 0 : int rule_exists = 0;
186 : :
187 [ # # ]: 0 : if(have_firewd_chk_support == 1)
188 : 0 : rule_exists = rule_exists_chk_support(opts, fwc->to_chain, rule);
189 : : else
190 [ # # ]: 0 : rule_exists = rule_exists_no_chk_support(opts, fwc, proto, srcip, (opts->fw_config->use_destination ? dstip : NULL), port, exp_ts);
191 : :
192 [ # # ]: 0 : if(rule_exists == 1)
193 : 0 : log_msg(LOG_DEBUG, "rule_exists() Rule : '%s' in %s already exists",
194 : 0 : rule, fwc->to_chain);
195 : : else
196 : 0 : log_msg(LOG_DEBUG, "rule_exists() Rule : '%s' in %s does not exist",
197 : 0 : rule, fwc->to_chain);
198 : :
199 : 0 : return(rule_exists);
200 : : }
201 : :
202 : : static void
203 : 0 : firewd_chk_support(const fko_srv_options_t * const opts)
204 : : {
205 : 0 : int res = 1;
206 : 0 : struct fw_chain *in_chain = &(opts->fw_config->chain[FIREWD_INPUT_ACCESS]);
207 : :
208 : 0 : zero_cmd_buffers();
209 : :
210 : : /* Add a harmless rule to the firewalld INPUT chain and see if firewalld
211 : : * supports '-C' to check for it. Set "have_firewd_chk_support" accordingly,
212 : : * delete the rule, and return.
213 : : */
214 : : snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_TMP_CHK_RULE_ARGS,
215 : 0 : opts->fw_config->fw_command,
216 : 0 : in_chain->table,
217 : 0 : in_chain->from_chain,
218 : : 1, /* first rule */
219 : 0 : in_chain->target
220 : : );
221 : :
222 : 0 : res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
223 : : WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
224 : 0 : chop_newline(err_buf);
225 : :
226 : 0 : log_msg(LOG_DEBUG, "firewd_chk_support() CMD: '%s' (res: %d, err: %s)",
227 : : cmd_buf, res, err_buf);
228 : :
229 : 0 : zero_cmd_buffers();
230 : :
231 : : /* Now see if '-C' works
232 : : */
233 : : snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_TMP_VERIFY_CHK_ARGS,
234 : 0 : opts->fw_config->fw_command,
235 : : in_chain->table,
236 : : in_chain->from_chain,
237 : : in_chain->target
238 : : );
239 : :
240 : 0 : res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
241 : : WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
242 : 0 : chop_newline(err_buf);
243 : :
244 : 0 : log_msg(LOG_DEBUG, "firewd_chk_support() CMD: '%s' (res: %d, err: %s)",
245 : : cmd_buf, res, err_buf);
246 : :
247 [ # # ]: 0 : if(strncmp(err_buf, "success", strlen("success")) == 0)
248 : : {
249 : 0 : log_msg(LOG_DEBUG, "firewd_chk_support() -C supported");
250 : 0 : have_firewd_chk_support = 1;
251 : : }
252 : : else
253 : : {
254 : 0 : log_msg(LOG_DEBUG, "firewd_chk_support() -C not supported");
255 : 0 : have_firewd_chk_support = 0;
256 : : }
257 : :
258 : : /* Delete the tmp rule
259 : : */
260 : 0 : zero_cmd_buffers();
261 : :
262 : : snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_DEL_RULE_ARGS,
263 : 0 : opts->fw_config->fw_command,
264 : : in_chain->table,
265 : : in_chain->from_chain,
266 : : 1
267 : : );
268 : 0 : run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
269 : : WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
270 : :
271 : 0 : return;
272 : : }
273 : :
274 : : static int
275 : 0 : comment_match_exists(const fko_srv_options_t * const opts)
276 : : {
277 : 0 : int res = 1;
278 : 0 : char *ndx = NULL;
279 : 0 : struct fw_chain *in_chain = &(opts->fw_config->chain[FIREWD_INPUT_ACCESS]);
280 : :
281 : 0 : zero_cmd_buffers();
282 : :
283 : : /* Add a harmless rule to the firewalld INPUT chain that uses the comment
284 : : * match and make sure it exists. If not, return zero. Otherwise, delete
285 : : * the rule and return true.
286 : : */
287 : : snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_TMP_COMMENT_ARGS,
288 : 0 : opts->fw_config->fw_command,
289 : 0 : in_chain->table,
290 : 0 : in_chain->from_chain,
291 : : 1, /* first rule */
292 : 0 : in_chain->target
293 : : );
294 : :
295 : 0 : res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
296 : : WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
297 : 0 : chop_newline(err_buf);
298 : :
299 : 0 : log_msg(LOG_DEBUG, "comment_match_exists() CMD: '%s' (res: %d, err: %s)",
300 : : cmd_buf, res, err_buf);
301 : :
302 : 0 : zero_cmd_buffers();
303 : :
304 : : snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_LIST_RULES_ARGS,
305 : 0 : opts->fw_config->fw_command,
306 : : in_chain->table,
307 : : in_chain->from_chain
308 : : );
309 : :
310 : 0 : res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE,
311 : : WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
312 : 0 : chop_newline(cmd_out);
313 : :
314 [ # # ]: 0 : if(!EXTCMD_IS_SUCCESS(res))
315 : 0 : log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);
316 : :
317 : 0 : ndx = strstr(cmd_out, TMP_COMMENT);
318 [ # # ]: 0 : if(ndx == NULL)
319 : : res = 0; /* did not find the tmp comment */
320 : : else
321 : 0 : res = 1;
322 : :
323 [ # # ]: 0 : if(res == 1)
324 : : {
325 : : /* Delete the tmp comment rule
326 : : */
327 : 0 : zero_cmd_buffers();
328 : :
329 : : snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_DEL_RULE_ARGS,
330 : 0 : opts->fw_config->fw_command,
331 : : in_chain->table,
332 : : in_chain->from_chain,
333 : : 1
334 : : );
335 : 0 : run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
336 : : WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
337 : : }
338 : :
339 : 0 : return res;
340 : : }
341 : :
342 : : static int
343 : 0 : add_jump_rule(const fko_srv_options_t * const opts, const int chain_num)
344 : : {
345 : 0 : int res = 0, rv = 0;
346 : :
347 : 0 : zero_cmd_buffers();
348 : :
349 : 0 : snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_ADD_JUMP_RULE_ARGS,
350 : : fwc.fw_command,
351 : 0 : fwc.chain[chain_num].table,
352 : 0 : fwc.chain[chain_num].from_chain,
353 : : fwc.chain[chain_num].jump_rule_pos,
354 : 0 : fwc.chain[chain_num].to_chain
355 : : );
356 : :
357 : 0 : res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
358 : : WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
359 : :
360 : 0 : log_msg(LOG_DEBUG, "add_jump_rule() CMD: '%s' (res: %d, err: %s)",
361 : : cmd_buf, res, err_buf);
362 : :
363 [ # # ]: 0 : if(EXTCMD_IS_SUCCESS(res))
364 : : {
365 : 0 : log_msg(LOG_INFO, "Added jump rule from chain: %s to chain: %s",
366 : : fwc.chain[chain_num].from_chain,
367 : : fwc.chain[chain_num].to_chain);
368 : 0 : rv = 1;
369 : : }
370 : : else
371 : 0 : log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
372 : :
373 : 0 : return rv;
374 : : }
375 : :
376 : : static int
377 : 0 : chain_exists(const fko_srv_options_t * const opts, const int chain_num)
378 : : {
379 : 0 : int res = 0, rv = 0;
380 : :
381 : 0 : zero_cmd_buffers();
382 : :
383 : : snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_CHAIN_EXISTS_ARGS,
384 : : fwc.fw_command,
385 : 0 : fwc.chain[chain_num].table,
386 : 0 : fwc.chain[chain_num].to_chain
387 : : );
388 : :
389 : 0 : res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
390 : : WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
391 : 0 : chop_newline(err_buf);
392 : :
393 : 0 : log_msg(LOG_DEBUG, "chain_exists() CMD: '%s' (res: %d, err: %s)",
394 : : cmd_buf, res, err_buf);
395 : :
396 [ # # ]: 0 : if(strstr(err_buf, FIREWD_CMD_FAIL_STR) == NULL)
397 : : {
398 : 0 : log_msg(LOG_DEBUG, "'%s' table '%s' chain exists",
399 : : fwc.chain[chain_num].table,
400 : : fwc.chain[chain_num].to_chain);
401 : 0 : rv = 1;
402 : : }
403 : : else
404 : 0 : log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
405 : :
406 : 0 : return rv;
407 : : }
408 : :
409 : : static int
410 : 0 : jump_rule_exists_chk_support(const fko_srv_options_t * const opts, const int chain_num)
411 : : {
412 : 0 : int exists = 0;
413 : 0 : char rule_buf[CMD_BUFSIZE] = {0};
414 : :
415 : : snprintf(rule_buf, CMD_BUFSIZE-1, FIREWD_CHK_JUMP_RULE_ARGS,
416 : 0 : fwc.chain[chain_num].table,
417 : 0 : fwc.chain[chain_num].to_chain
418 : : );
419 : :
420 [ # # ]: 0 : if(rule_exists_chk_support(opts, fwc.chain[chain_num].from_chain, rule_buf) == 1)
421 : : {
422 : 0 : log_msg(LOG_DEBUG, "jump_rule_exists_chk_support() jump rule found");
423 : 0 : exists = 1;
424 : : }
425 : : else
426 : 0 : log_msg(LOG_DEBUG, "jump_rule_exists_chk_support() jump rule not found");
427 : :
428 : 0 : return exists;
429 : : }
430 : :
431 : : static int
432 : 0 : jump_rule_exists_no_chk_support(const fko_srv_options_t * const opts, const int chain_num)
433 : : {
434 : 0 : int exists = 0;
435 : 0 : char cmd_buf[CMD_BUFSIZE] = {0};
436 : 0 : char chain_search[CMD_BUFSIZE] = {0};
437 : :
438 : : snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_LIST_RULES_ARGS,
439 : : fwc.fw_command,
440 : 0 : fwc.chain[chain_num].table,
441 : 0 : fwc.chain[chain_num].from_chain
442 : : );
443 : :
444 : : /* include spaces on either side as produced by 'firewalld -L' output
445 : : */
446 : : snprintf(chain_search, CMD_BUFSIZE-1, " %s ",
447 : 0 : fwc.chain[chain_num].to_chain);
448 : :
449 [ # # ]: 0 : if(search_extcmd(cmd_buf, WANT_STDERR,
450 : : NO_TIMEOUT, chain_search, &pid_status, opts) > 0)
451 : 0 : exists = 1;
452 : :
453 [ # # ]: 0 : if(exists)
454 : 0 : log_msg(LOG_DEBUG, "jump_rule_exists_no_chk_support() jump rule found");
455 : : else
456 : 0 : log_msg(LOG_DEBUG, "jump_rule_exists_no_chk_support() jump rule not found");
457 : :
458 : 0 : return(exists);
459 : : }
460 : :
461 : : static int
462 : 0 : jump_rule_exists(const fko_srv_options_t * const opts, const int chain_num)
463 : : {
464 : 0 : int exists = 0;
465 : :
466 [ # # ]: 0 : if(have_firewd_chk_support == 1)
467 : 0 : exists = jump_rule_exists_chk_support(opts, chain_num);
468 : : else
469 : 0 : exists = jump_rule_exists_no_chk_support(opts, chain_num);
470 : :
471 : 0 : return exists;
472 : : }
473 : :
474 : : /* Print all firewall rules currently instantiated by the running fwknopd
475 : : * daemon to stdout.
476 : : */
477 : : int
478 : 0 : fw_dump_rules(const fko_srv_options_t * const opts)
479 : : {
480 : : int i;
481 : 0 : int res, got_err = 0;
482 : :
483 : 0 : struct fw_chain *ch = opts->fw_config->chain;
484 : :
485 [ # # ]: 0 : if (opts->fw_list_all == 1)
486 : : {
487 : 0 : fprintf(stdout, "Listing all firewalld rules in applicable tables...\n");
488 : 0 : fflush(stdout);
489 : :
490 [ # # ]: 0 : for(i=0; i < NUM_FWKNOP_ACCESS_TYPES; i++)
491 : : {
492 [ # # ]: 0 : if(fwc.chain[i].target[0] == '\0')
493 : 0 : continue;
494 : :
495 : 0 : zero_cmd_buffers();
496 : :
497 : : /* Create the list command
498 : : */
499 : : snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_LIST_ALL_RULES_ARGS,
500 : 0 : opts->fw_config->fw_command,
501 : 0 : ch[i].table
502 : : );
503 : :
504 : 0 : res = run_extcmd(cmd_buf, NULL, 0, NO_STDERR,
505 : : NO_TIMEOUT, &pid_status, opts);
506 : :
507 : 0 : log_msg(LOG_DEBUG, "fw_dump_rules() CMD: '%s' (res: %d)",
508 : : cmd_buf, res);
509 : :
510 : : /* Expect full success on this */
511 [ # # ]: 0 : if(! EXTCMD_IS_SUCCESS(res))
512 : : {
513 : 0 : log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
514 : 0 : got_err++;
515 : : }
516 : : }
517 : : }
518 : : else
519 : : {
520 : 0 : fprintf(stdout, "Listing rules in fwknopd firewalld chains...\n");
521 : 0 : fflush(stdout);
522 : :
523 [ # # ]: 0 : for(i=0; i < NUM_FWKNOP_ACCESS_TYPES; i++)
524 : : {
525 [ # # ]: 0 : if(fwc.chain[i].target[0] == '\0')
526 : 0 : continue;
527 : :
528 : 0 : zero_cmd_buffers();
529 : :
530 : : /* Create the list command
531 : : */
532 : : snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_LIST_RULES_ARGS,
533 : 0 : opts->fw_config->fw_command,
534 : 0 : ch[i].table,
535 : 0 : ch[i].to_chain
536 : : );
537 : :
538 : 0 : fprintf(stdout, "\n");
539 : 0 : fflush(stdout);
540 : :
541 : 0 : res = run_extcmd(cmd_buf, NULL, 0, NO_STDERR,
542 : : NO_TIMEOUT, &pid_status, opts);
543 : :
544 : 0 : log_msg(LOG_DEBUG, "fw_dump_rules() CMD: '%s' (res: %d)",
545 : : cmd_buf, res);
546 : :
547 : : /* Expect full success on this */
548 [ # # ]: 0 : if(! EXTCMD_IS_SUCCESS(res))
549 : : {
550 : 0 : log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
551 : 0 : got_err++;
552 : : }
553 : : }
554 : : }
555 : :
556 : 0 : return(got_err);
557 : : }
558 : :
559 : : /* Quietly flush and delete all fwknop custom chains.
560 : : */
561 : : static void
562 : 0 : delete_all_chains(const fko_srv_options_t * const opts)
563 : : {
564 : 0 : int i, res, cmd_ctr = 0;
565 : :
566 [ # # ]: 0 : for(i=0; i < NUM_FWKNOP_ACCESS_TYPES; i++)
567 : : {
568 [ # # ]: 0 : if(fwc.chain[i].target[0] == '\0')
569 : 0 : continue;
570 : :
571 : : /* First look for a jump rule to this chain and remove it if it
572 : : * is there.
573 : : */
574 : : cmd_ctr = 0;
575 [ # # ][ # # ]: 0 : while(cmd_ctr < CMD_LOOP_TRIES && (jump_rule_exists(opts, i) == 1))
576 : : {
577 : 0 : zero_cmd_buffers();
578 : :
579 : : snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_DEL_JUMP_RULE_ARGS,
580 : : fwc.fw_command,
581 : 0 : fwc.chain[i].table,
582 : 0 : fwc.chain[i].from_chain,
583 : 0 : fwc.chain[i].to_chain
584 : : );
585 : :
586 : 0 : res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
587 : : WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
588 : 0 : chop_newline(err_buf);
589 : :
590 : 0 : log_msg(LOG_DEBUG, "delete_all_chains() CMD: '%s' (res: %d, err: %s)",
591 : : cmd_buf, res, err_buf);
592 : :
593 : : /* Expect full success on this */
594 [ # # ]: 0 : if(! EXTCMD_IS_SUCCESS(res))
595 : 0 : log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
596 : :
597 : 0 : cmd_ctr++;
598 : : }
599 : :
600 : 0 : zero_cmd_buffers();
601 : :
602 : : /* Now flush and remove the chain.
603 : : */
604 : : snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_FLUSH_CHAIN_ARGS,
605 : : fwc.fw_command,
606 : 0 : fwc.chain[i].table,
607 : 0 : fwc.chain[i].to_chain
608 : : );
609 : :
610 : 0 : res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, WANT_STDERR,
611 : : NO_TIMEOUT, &pid_status, opts);
612 : 0 : chop_newline(err_buf);
613 : :
614 : 0 : log_msg(LOG_DEBUG, "delete_all_chains() CMD: '%s' (res: %d, err: %s)",
615 : : cmd_buf, res, err_buf);
616 : :
617 : : /* Expect full success on this */
618 [ # # ]: 0 : if(! EXTCMD_IS_SUCCESS(res))
619 : 0 : log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
620 : :
621 : 0 : zero_cmd_buffers();
622 : :
623 : : snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_DEL_CHAIN_ARGS,
624 : : fwc.fw_command,
625 : 0 : fwc.chain[i].table,
626 : : fwc.chain[i].to_chain
627 : : );
628 : :
629 : 0 : res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, WANT_STDERR,
630 : : NO_TIMEOUT, &pid_status, opts);
631 : 0 : chop_newline(err_buf);
632 : :
633 : 0 : log_msg(LOG_DEBUG, "delete_all_chains() CMD: '%s' (res: %d, err: %s)",
634 : : cmd_buf, res, err_buf);
635 : :
636 : : /* Expect full success on this */
637 [ # # ]: 0 : if(! EXTCMD_IS_SUCCESS(res))
638 : 0 : log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
639 : :
640 : : }
641 : 0 : return;
642 : : }
643 : :
644 : : static int
645 : 0 : create_chain(const fko_srv_options_t * const opts, const int chain_num)
646 : : {
647 : 0 : int res = 0, rv = 0;
648 : :
649 : 0 : zero_cmd_buffers();
650 : :
651 : : /* Create the custom chain.
652 : : */
653 : : snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_NEW_CHAIN_ARGS,
654 : : fwc.fw_command,
655 : 0 : fwc.chain[chain_num].table,
656 : 0 : fwc.chain[chain_num].to_chain
657 : : );
658 : :
659 : 0 : res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, WANT_STDERR,
660 : : NO_TIMEOUT, &pid_status, opts);
661 : 0 : chop_newline(err_buf);
662 : :
663 : 0 : log_msg(LOG_DEBUG, "create_chain() CMD: '%s' (res: %d, err: %s)",
664 : : cmd_buf, res, err_buf);
665 : :
666 : : /* Expect full success on this */
667 [ # # ]: 0 : if(EXTCMD_IS_SUCCESS(res))
668 : : rv = 1;
669 : : else
670 : 0 : log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
671 : :
672 : 0 : return rv;
673 : : }
674 : :
675 : : static int
676 : 0 : mk_chain(const fko_srv_options_t * const opts, const int chain_num)
677 : : {
678 : 0 : int err = 0;
679 : :
680 : : /* Make sure the required chain and jump rule exist
681 : : */
682 [ # # ]: 0 : if(! chain_exists(opts, chain_num))
683 [ # # ]: 0 : if(! create_chain(opts, chain_num))
684 : 0 : err++;
685 : :
686 [ # # ]: 0 : if (! jump_rule_exists(opts, chain_num))
687 [ # # ]: 0 : if(! add_jump_rule(opts, chain_num))
688 : 0 : err++;
689 : :
690 : 0 : return err;
691 : : }
692 : :
693 : : /* Create the fwknop custom chains (at least those that are configured).
694 : : */
695 : : static int
696 : 0 : create_fw_chains(const fko_srv_options_t * const opts)
697 : : {
698 : 0 : int i, got_err = 0;
699 : :
700 [ # # ]: 0 : for(i=0; i < NUM_FWKNOP_ACCESS_TYPES; i++)
701 : : {
702 [ # # ]: 0 : if(fwc.chain[i].target[0] == '\0')
703 : 0 : continue;
704 : :
705 : 0 : got_err += mk_chain(opts, i);
706 : : }
707 : :
708 : 0 : return(got_err);
709 : : }
710 : :
711 : : static int
712 : 1629 : set_fw_chain_conf(const int type, const char * const conf_str)
713 : : {
714 : : int i, j, is_err;
715 : 1629 : char tbuf[MAX_LINE_LEN] = {0};
716 : 1629 : const char *ndx = conf_str;
717 : :
718 : : char *chain_fields[FW_NUM_CHAIN_FIELDS];
719 : :
720 : 1629 : struct fw_chain *chain = &(fwc.chain[type]);
721 : :
722 [ - + ]: 1629 : if(conf_str == NULL)
723 : : {
724 : 0 : log_msg(LOG_ERR, "[*] NULL conf_str");
725 : 0 : return 0;
726 : : }
727 : :
728 : 1629 : chain->type = type;
729 : :
730 [ + - ]: 1629 : if(ndx != NULL)
731 : 1629 : chain_fields[0] = tbuf;
732 : :
733 : : i = 0;
734 : : j = 1;
735 [ + + ]: 68418 : while(*ndx != '\0')
736 : : {
737 [ + + ]: 66789 : if(*ndx != ' ')
738 : : {
739 [ + + ]: 58644 : if(*ndx == ',')
740 : : {
741 : 8145 : tbuf[i] = '\0';
742 : 8145 : chain_fields[j++] = &(tbuf[++i]);
743 : : }
744 : : else
745 : 50499 : tbuf[i++] = *ndx;
746 : : }
747 [ + + ]: 66789 : if(*ndx != '\0'
748 : 66789 : && *ndx != ' '
749 [ + + ]: 58644 : && *ndx != ','
750 [ + + ]: 50499 : && *ndx != '_'
751 [ - + ]: 48870 : && isalnum(*ndx) == 0)
752 : : {
753 : 0 : log_msg(LOG_ERR, "[*] Custom chain config parse error: "
754 : : "invalid character '%c' for chain type %i, "
755 : 0 : "line: %s", *ndx, type, conf_str);
756 : 0 : return 0;
757 : : }
758 : 66789 : ndx++;
759 : : }
760 : :
761 : : /* Sanity check - j should be the number of chain fields
762 : : * (excluding the type).
763 : : */
764 [ - + ]: 1629 : if(j != FW_NUM_CHAIN_FIELDS)
765 : : {
766 : 0 : log_msg(LOG_ERR, "[*] Custom chain config parse error: "
767 : : "wrong number of fields for chain type %i, "
768 : : "line: %s", type, conf_str);
769 : 0 : return 0;
770 : : }
771 : :
772 : : /* Pull and set Target */
773 : 1629 : strlcpy(chain->target, chain_fields[0], sizeof(chain->target));
774 : :
775 : : /* Pull and set Table */
776 : 1629 : strlcpy(chain->table, chain_fields[1], sizeof(chain->table));
777 : :
778 : : /* Pull and set From_chain */
779 : 1629 : strlcpy(chain->from_chain, chain_fields[2], sizeof(chain->from_chain));
780 : :
781 : : /* Pull and set Jump_rule_position */
782 : 1629 : chain->jump_rule_pos = strtol_wrapper(chain_fields[3],
783 : : 0, RCHK_MAX_FIREWD_RULE_NUM, NO_EXIT_UPON_ERR, &is_err);
784 [ - + ]: 1629 : if(is_err != FKO_SUCCESS)
785 : : {
786 : 0 : log_msg(LOG_ERR, "[*] invalid jump rule position in Line: %s",
787 : : conf_str);
788 : 0 : return 0;
789 : : }
790 : :
791 : : /* Pull and set To_chain */
792 : 1629 : strlcpy(chain->to_chain, chain_fields[4], sizeof(chain->to_chain));
793 : :
794 : : /* Pull and set to_chain rule position */
795 : 1629 : chain->rule_pos = strtol_wrapper(chain_fields[5],
796 : : 0, RCHK_MAX_FIREWD_RULE_NUM, NO_EXIT_UPON_ERR, &is_err);
797 [ - + ]: 1629 : if(is_err != FKO_SUCCESS)
798 : : {
799 : 0 : log_msg(LOG_ERR, "[*] invalid to_chain rule position in Line: %s",
800 : : conf_str);
801 : 0 : return 0;
802 : : }
803 : : return 1;
804 : : }
805 : :
806 : : int
807 : 1629 : fw_config_init(fko_srv_options_t * const opts)
808 : : {
809 : : memset(&fwc, 0x0, sizeof(struct fw_config));
810 : :
811 : : /* Set our firewall exe command path (firewall-cmd or iptables in most cases).
812 : : */
813 : : #if FIREWALL_FIREWALLD
814 : : char cmd_passthru[512];
815 : 1629 : snprintf(cmd_passthru, sizeof cmd_passthru, "%s %s ",
816 : : opts->config[CONF_FIREWALL_EXE], FIREWD_CMD_PREFIX);
817 : 1629 : strlcpy(fwc.fw_command, cmd_passthru, sizeof(fwc.fw_command));
818 : : #else
819 : : strlcpy(fwc.fw_command, opts->config[CONF_FIREWALL_EXE], sizeof(fwc.fw_command));
820 : : #endif
821 : :
822 : : #if HAVE_LIBFIU
823 : : fiu_return_on("fw_config_init", 0);
824 : : #endif
825 : :
826 : : /* Pull the fwknop chain config info and setup our internal
827 : : * config struct. The FIREWD_INPUT is the only one that is
828 : : * required. The rest are optional.
829 : : */
830 [ + - ]: 1629 : if(set_fw_chain_conf(FIREWD_INPUT_ACCESS, opts->config[CONF_FIREWD_INPUT_ACCESS]) != 1)
831 : : return 0;
832 : :
833 : : /* The FWKNOP_OUTPUT_ACCESS requires ENABLE_FIREWD_OUTPUT_ACCESS == Y
834 : : */
835 [ - + ]: 1629 : if(strncasecmp(opts->config[CONF_ENABLE_FIREWD_OUTPUT], "Y", 1)==0)
836 [ # # ]: 0 : if(set_fw_chain_conf(FIREWD_OUTPUT_ACCESS, opts->config[CONF_FIREWD_OUTPUT_ACCESS]) != 1)
837 : : return 0;
838 : :
839 : : /* The remaining access chains require ENABLE_FIREWD_FORWARDING = Y
840 : : */
841 [ - + ]: 1629 : if(strncasecmp(opts->config[CONF_ENABLE_FIREWD_FORWARDING], "Y", 1)==0)
842 : : {
843 [ # # ]: 0 : if(set_fw_chain_conf(FIREWD_FORWARD_ACCESS, opts->config[CONF_FIREWD_FORWARD_ACCESS]) != 1)
844 : : return 0;
845 : :
846 [ # # ]: 0 : if(set_fw_chain_conf(FIREWD_DNAT_ACCESS, opts->config[CONF_FIREWD_DNAT_ACCESS]) != 1)
847 : : return 0;
848 : :
849 : : /* Requires ENABLE_FIREWD_SNAT = Y
850 : : */
851 [ # # ]: 0 : if(strncasecmp(opts->config[CONF_ENABLE_FIREWD_SNAT], "Y", 1)==0)
852 : : {
853 : : /* Support both SNAT and MASQUERADE - this will be controlled
854 : : * via the access.conf configuration for individual rules
855 : : */
856 [ # # ]: 0 : if(set_fw_chain_conf(FIREWD_MASQUERADE_ACCESS,
857 : 0 : opts->config[CONF_FIREWD_MASQUERADE_ACCESS]) != 1)
858 : : return 0;
859 : :
860 [ # # ]: 0 : if(set_fw_chain_conf(FIREWD_SNAT_ACCESS,
861 : 0 : opts->config[CONF_FIREWD_SNAT_ACCESS]) != 1)
862 : : return 0;
863 : : }
864 : : }
865 : :
866 [ - + ]: 1629 : if(strncasecmp(opts->config[CONF_ENABLE_DESTINATION_RULE], "Y", 1)==0)
867 : : {
868 : 0 : fwc.use_destination = 1;
869 : : }
870 : :
871 : : /* Let us find it via our opts struct as well.
872 : : */
873 : 1629 : opts->fw_config = &fwc;
874 : :
875 : 1629 : return 1;
876 : : }
877 : :
878 : : int
879 : 0 : fw_initialize(const fko_srv_options_t * const opts)
880 : : {
881 : 0 : int res = 1;
882 : :
883 : : /* Flush the chains (just in case) so we can start fresh.
884 : : */
885 [ # # ]: 0 : if(strncasecmp(opts->config[CONF_FLUSH_FIREWD_AT_INIT], "Y", 1) == 0)
886 : 0 : delete_all_chains(opts);
887 : :
888 : : /* Now create any configured chains.
889 : : */
890 [ # # ]: 0 : if(create_fw_chains(opts) != 0)
891 : : {
892 : 0 : log_msg(LOG_WARNING,
893 : : "Warning: Errors detected during fwknop custom chain creation");
894 : 0 : res = 0;
895 : : }
896 : :
897 : : /* Make sure that the 'comment' match is available
898 : : */
899 [ # # ]: 0 : if(strncasecmp(opts->config[CONF_ENABLE_FIREWD_COMMENT_CHECK], "Y", 1) == 0)
900 : : {
901 [ # # ]: 0 : if(comment_match_exists(opts) == 1)
902 : : {
903 : 0 : log_msg(LOG_INFO, "firewalld 'comment' match is available");
904 : : }
905 : : else
906 : : {
907 : 0 : log_msg(LOG_WARNING, "Warning: Could not use the 'comment' match");
908 : 0 : res = 0;
909 : : }
910 : : }
911 : :
912 : : /* See if firewalld offers the '-C' argument (older versions don't). If not,
913 : : * then switch to parsing firewalld -L output to find rules.
914 : : */
915 [ # # ]: 0 : if(opts->firewd_disable_check_support)
916 : 0 : have_firewd_chk_support = 0;
917 : : else
918 : 0 : firewd_chk_support(opts);
919 : :
920 : 0 : return(res);
921 : : }
922 : :
923 : : int
924 : 0 : fw_cleanup(const fko_srv_options_t * const opts)
925 : : {
926 [ # # ]: 0 : if(strncasecmp(opts->config[CONF_FLUSH_FIREWD_AT_EXIT], "N", 1) == 0
927 [ # # ]: 0 : && opts->fw_flush == 0)
928 : : return(0);
929 : :
930 : 0 : delete_all_chains(opts);
931 : 0 : return(0);
932 : : }
933 : :
934 : : static int
935 : 0 : create_rule(const fko_srv_options_t * const opts,
936 : : const char * const fw_chain, const char * const fw_rule)
937 : : {
938 : 0 : int res = 0;
939 : :
940 : 0 : zero_cmd_buffers();
941 : :
942 : 0 : snprintf(cmd_buf, CMD_BUFSIZE-1, "%s -A %s %s", opts->fw_config->fw_command, fw_chain, fw_rule);
943 : :
944 : 0 : res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, WANT_STDERR,
945 : : NO_TIMEOUT, &pid_status, opts);
946 : 0 : chop_newline(err_buf);
947 : :
948 : 0 : log_msg(LOG_DEBUG, "create_rule() CMD: '%s' (res: %d, err: %s)",
949 : : cmd_buf, res, err_buf);
950 : :
951 [ # # ]: 0 : if(EXTCMD_IS_SUCCESS(res))
952 : : {
953 : 0 : log_msg(LOG_DEBUG, "create_rule() Rule: '%s' added to %s", fw_rule, fw_chain);
954 : 0 : res = 1;
955 : : }
956 : : else
957 : 0 : log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
958 : :
959 : 0 : return res;
960 : : }
961 : :
962 : : static void
963 : 0 : firewd_rule(const fko_srv_options_t * const opts,
964 : : const char * const complete_rule_buf,
965 : : const char * const fw_rule_macro,
966 : : const char * const srcip, const char * const dstip,
967 : : const unsigned int proto, const unsigned int port,
968 : : struct fw_chain * const chain,
969 : : const unsigned int exp_ts, const time_t now,
970 : : const char * const msg, const char * const access_msg)
971 : : {
972 : 0 : char rule_buf[CMD_BUFSIZE] = {0};
973 : :
974 [ # # ][ # # ]: 0 : if(complete_rule_buf != NULL && complete_rule_buf[0] != 0x0)
975 : : {
976 : 0 : strlcpy(rule_buf, complete_rule_buf, CMD_BUFSIZE-1);
977 : : }
978 : : else
979 : : {
980 : : memset(rule_buf, 0, CMD_BUFSIZE);
981 : :
982 : : snprintf(rule_buf, CMD_BUFSIZE-1, fw_rule_macro,
983 : 0 : chain->table,
984 : : proto,
985 : : srcip,
986 : : dstip,
987 : : port,
988 : : exp_ts,
989 : 0 : chain->target
990 : : );
991 : : }
992 : :
993 : : /* Check to make sure that the chain and jump rule exists
994 : : */
995 : 0 : mk_chain(opts, chain->type);
996 : :
997 [ # # ]: 0 : if(rule_exists(opts, chain, rule_buf,
998 : : proto, srcip, dstip, port, exp_ts) == 0)
999 : : {
1000 [ # # ]: 0 : if(create_rule(opts, chain->to_chain, rule_buf))
1001 : : {
1002 [ # # ]: 0 : log_msg(LOG_INFO, "Added %s rule to %s for %s -> %s %s, expires at %u",
1003 : : msg, chain->to_chain, srcip, (dstip == NULL) ? FIREWD_ANY_IP : dstip,
1004 : : access_msg, exp_ts
1005 : : );
1006 : :
1007 : 0 : chain->active_rules++;
1008 : :
1009 : : /* Reset the next expected expire time for this chain if it
1010 : : * is warranted.
1011 : : */
1012 [ # # ][ # # ]: 0 : if(chain->next_expire < now || exp_ts < chain->next_expire)
1013 : 0 : chain->next_expire = exp_ts;
1014 : : }
1015 : : }
1016 : :
1017 : 0 : return;
1018 : : }
1019 : :
1020 : 0 : static void forward_access_rule(const fko_srv_options_t * const opts,
1021 : : const acc_stanza_t * const acc,
1022 : : struct fw_chain * const fwd_chain,
1023 : : const char * const nat_ip,
1024 : : const unsigned int nat_port,
1025 : : const unsigned int fst_proto,
1026 : : const unsigned int fst_port,
1027 : : spa_data_t * const spadat,
1028 : : const unsigned int exp_ts,
1029 : : const time_t now)
1030 : : {
1031 : 0 : char rule_buf[CMD_BUFSIZE] = {0};
1032 : :
1033 : 0 : log_msg(LOG_DEBUG,
1034 : : "forward_access_rule() forward_all: %d, nat_ip: %s, nat_port: %d",
1035 : 0 : acc->forward_all, nat_ip, nat_port);
1036 : :
1037 [ # # ]: 0 : if(acc->forward_all)
1038 : : {
1039 : : memset(rule_buf, 0, CMD_BUFSIZE);
1040 : :
1041 : 0 : snprintf(rule_buf, CMD_BUFSIZE-1, FIREWD_FWD_ALL_RULE_ARGS,
1042 : 0 : fwd_chain->table,
1043 : : spadat->use_src_ip,
1044 : : exp_ts,
1045 : 0 : fwd_chain->target
1046 : : );
1047 : :
1048 : : /* Make a global ACCEPT rule for all ports/protocols
1049 : : */
1050 : 0 : firewd_rule(opts, rule_buf, NULL, spadat->use_src_ip,
1051 : : NULL, ANY_PROTO, ANY_PORT, fwd_chain, exp_ts, now,
1052 : : "FORWARD ALL", "*/*");
1053 : : }
1054 : : else
1055 : : {
1056 : : /* Make the FORWARD access rule
1057 : : */
1058 : 0 : firewd_rule(opts, NULL, FIREWD_FWD_RULE_ARGS, spadat->use_src_ip,
1059 : : nat_ip, fst_proto, nat_port, fwd_chain, exp_ts, now,
1060 : 0 : "FORWARD", spadat->spa_message_remain);
1061 : :
1062 : : }
1063 : 0 : return;
1064 : : }
1065 : :
1066 : 0 : static void dnat_rule(const fko_srv_options_t * const opts,
1067 : : const acc_stanza_t * const acc,
1068 : : struct fw_chain * const dnat_chain,
1069 : : const char * const nat_ip,
1070 : : const unsigned int nat_port,
1071 : : const unsigned int fst_proto,
1072 : : const unsigned int fst_port,
1073 : : spa_data_t * const spadat,
1074 : : const unsigned int exp_ts,
1075 : : const time_t now)
1076 : : {
1077 : 0 : char rule_buf[CMD_BUFSIZE] = {0};
1078 : :
1079 : 0 : log_msg(LOG_DEBUG, "dnat_rule() forward_all: %d, nat_ip: %s, nat_port: %d",
1080 : 0 : acc->forward_all, nat_ip, nat_port);
1081 : :
1082 [ # # ]: 0 : if(acc->forward_all)
1083 : : {
1084 : : memset(rule_buf, 0, CMD_BUFSIZE);
1085 : :
1086 [ # # ]: 0 : snprintf(rule_buf, CMD_BUFSIZE-1, FIREWD_DNAT_ALL_RULE_ARGS,
1087 : 0 : dnat_chain->table,
1088 : : spadat->use_src_ip,
1089 : 0 : (fwc.use_destination ? spadat->pkt_destination_ip : FIREWD_ANY_IP),
1090 : : exp_ts,
1091 : 0 : dnat_chain->target,
1092 : : nat_ip
1093 : : );
1094 : :
1095 : : /* Make a global DNAT rule for all ports/protocols
1096 : : */
1097 : 0 : firewd_rule(opts, rule_buf, NULL, spadat->use_src_ip,
1098 : : NULL, ANY_PROTO, ANY_PORT, dnat_chain, exp_ts, now,
1099 : : "DNAT ALL", "*/*");
1100 : : }
1101 : : else
1102 : : {
1103 : : memset(rule_buf, 0, CMD_BUFSIZE);
1104 : :
1105 [ # # ]: 0 : snprintf(rule_buf, CMD_BUFSIZE-1, FIREWD_DNAT_RULE_ARGS,
1106 : 0 : dnat_chain->table,
1107 : : fst_proto,
1108 : : spadat->use_src_ip,
1109 : 0 : (fwc.use_destination ? spadat->pkt_destination_ip : FIREWD_ANY_IP),
1110 : : fst_port,
1111 : : exp_ts,
1112 : 0 : dnat_chain->target,
1113 : : nat_ip,
1114 : : nat_port
1115 : : );
1116 : :
1117 [ # # ]: 0 : firewd_rule(opts, rule_buf, NULL, spadat->use_src_ip,
1118 : 0 : (fwc.use_destination ? spadat->pkt_destination_ip : FIREWD_ANY_IP),
1119 : : fst_proto, fst_port, dnat_chain, exp_ts, now, "DNAT",
1120 : 0 : spadat->spa_message_remain);
1121 : : }
1122 : 0 : return;
1123 : : }
1124 : :
1125 : 0 : static void snat_rule(const fko_srv_options_t * const opts,
1126 : : const acc_stanza_t * const acc,
1127 : : const char * const nat_ip,
1128 : : const unsigned int nat_port,
1129 : : const unsigned int fst_proto,
1130 : : const unsigned int fst_port,
1131 : : spa_data_t * const spadat,
1132 : : const unsigned int exp_ts,
1133 : : const time_t now)
1134 : : {
1135 : 0 : char rule_buf[CMD_BUFSIZE] = {0};
1136 : 0 : char snat_target[SNAT_TARGET_BUFSIZE] = {0};
1137 : 0 : struct fw_chain *snat_chain = NULL;
1138 : :
1139 [ # # ]: 0 : log_msg(LOG_DEBUG,
1140 : : "snat_rule() forward_all: %d, nat_ip: %s, nat_port: %d, force_snat: %d, force_snat_ip: %s, force_masq: %d",
1141 : 0 : acc->forward_all, nat_ip, nat_port, acc->force_snat,
1142 : 0 : (acc->force_snat_ip == NULL) ? "(NONE)" : acc->force_snat_ip,
1143 : 0 : acc->force_masquerade);
1144 : :
1145 [ # # ]: 0 : if(acc->forward_all)
1146 : : {
1147 : : /* Default to MASQUERADE */
1148 : 0 : snat_chain = &(opts->fw_config->chain[FIREWD_MASQUERADE_ACCESS]);
1149 : : snprintf(snat_target, SNAT_TARGET_BUFSIZE-1, " ");
1150 : :
1151 : : /* Add SNAT or MASQUERADE rules.
1152 : : */
1153 [ # # ][ # # ]: 0 : if(acc->force_snat && is_valid_ipv4_addr(acc->force_snat_ip))
1154 : : {
1155 : : /* Using static SNAT */
1156 : 0 : snat_chain = &(opts->fw_config->chain[FIREWD_SNAT_ACCESS]);
1157 : 0 : snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
1158 : : "--to-source %s", acc->force_snat_ip);
1159 : : }
1160 [ # # ]: 0 : else if((opts->config[CONF_SNAT_TRANSLATE_IP] != NULL)
1161 [ # # ]: 0 : && is_valid_ipv4_addr(opts->config[CONF_SNAT_TRANSLATE_IP]))
1162 : : {
1163 : : /* Using static SNAT */
1164 : 0 : snat_chain = &(opts->fw_config->chain[FIREWD_SNAT_ACCESS]);
1165 : 0 : snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
1166 : : "--to-source %s", opts->config[CONF_SNAT_TRANSLATE_IP]);
1167 : : }
1168 : :
1169 : : memset(rule_buf, 0, CMD_BUFSIZE);
1170 : :
1171 : 0 : snprintf(rule_buf, CMD_BUFSIZE-1, FIREWD_SNAT_ALL_RULE_ARGS,
1172 : 0 : snat_chain->table,
1173 : : spadat->use_src_ip,
1174 : : exp_ts,
1175 : 0 : snat_chain->target,
1176 : : snat_target
1177 : : );
1178 : :
1179 : 0 : firewd_rule(opts, rule_buf, NULL, spadat->use_src_ip,
1180 : : NULL, ANY_PROTO, ANY_PORT, snat_chain, exp_ts, now,
1181 : : "SNAT ALL", "*/*");
1182 : : }
1183 : : else
1184 : : {
1185 : : /* Add SNAT or MASQUERADE rules.
1186 : : */
1187 [ # # ][ # # ]: 0 : if(acc->force_snat && is_valid_ipv4_addr(acc->force_snat_ip))
1188 : : {
1189 : : /* Using static SNAT */
1190 : 0 : snat_chain = &(opts->fw_config->chain[FIREWD_SNAT_ACCESS]);
1191 : 0 : snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
1192 : : "--to-source %s:%i", acc->force_snat_ip, fst_port);
1193 : : }
1194 [ # # ][ # # ]: 0 : else if(acc->force_snat && acc->force_masquerade)
1195 : : {
1196 : : /* Using MASQUERADE */
1197 : 0 : snat_chain = &(opts->fw_config->chain[FIREWD_MASQUERADE_ACCESS]);
1198 : : snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
1199 : : "--to-ports %i", fst_port);
1200 : : }
1201 [ # # ]: 0 : else if((opts->config[CONF_SNAT_TRANSLATE_IP] != NULL)
1202 [ # # ]: 0 : && is_valid_ipv4_addr(opts->config[CONF_SNAT_TRANSLATE_IP]))
1203 : : {
1204 : : /* Using static SNAT */
1205 : 0 : snat_chain = &(opts->fw_config->chain[FIREWD_SNAT_ACCESS]);
1206 : 0 : snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
1207 : : "--to-source %s:%i", opts->config[CONF_SNAT_TRANSLATE_IP],
1208 : : fst_port);
1209 : : }
1210 : : else
1211 : : {
1212 : : /* Using MASQUERADE */
1213 : 0 : snat_chain = &(opts->fw_config->chain[FIREWD_MASQUERADE_ACCESS]);
1214 : : snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
1215 : : "--to-ports %i", fst_port);
1216 : : }
1217 : :
1218 : : memset(rule_buf, 0, CMD_BUFSIZE);
1219 : :
1220 : : snprintf(rule_buf, CMD_BUFSIZE-1, FIREWD_SNAT_RULE_ARGS,
1221 : 0 : snat_chain->table,
1222 : : fst_proto,
1223 : : nat_ip,
1224 : : nat_port,
1225 : : exp_ts,
1226 : 0 : snat_chain->target,
1227 : : snat_target
1228 : : );
1229 : :
1230 : 0 : firewd_rule(opts, rule_buf, NULL, spadat->use_src_ip,
1231 : : NULL, fst_proto, nat_port, snat_chain, exp_ts, now, "SNAT",
1232 : 0 : spadat->spa_message_remain);
1233 : : }
1234 : 0 : return;
1235 : : }
1236 : :
1237 : : /****************************************************************************/
1238 : :
1239 : : /* Rule Processing - Create an access request...
1240 : : */
1241 : : int
1242 : 0 : process_spa_request(const fko_srv_options_t * const opts,
1243 : : const acc_stanza_t * const acc, spa_data_t * const spadat)
1244 : : {
1245 : 0 : char nat_ip[MAX_IPV4_STR_LEN] = {0};
1246 : 0 : unsigned int nat_port = 0;
1247 : : unsigned int fst_proto;
1248 : : unsigned int fst_port;
1249 : :
1250 : 0 : struct fw_chain * const in_chain = &(opts->fw_config->chain[FIREWD_INPUT_ACCESS]);
1251 : 0 : struct fw_chain * const out_chain = &(opts->fw_config->chain[FIREWD_OUTPUT_ACCESS]);
1252 : 0 : struct fw_chain * const fwd_chain = &(opts->fw_config->chain[FIREWD_FORWARD_ACCESS]);
1253 : 0 : struct fw_chain * const dnat_chain = &(opts->fw_config->chain[FIREWD_DNAT_ACCESS]);
1254 : :
1255 : 0 : acc_port_list_t *port_list = NULL;
1256 : 0 : acc_port_list_t *ple = NULL;
1257 : :
1258 : 0 : char *ndx = NULL;
1259 : 0 : int res = 0, is_err;
1260 : : time_t now;
1261 : : unsigned int exp_ts;
1262 : :
1263 : : /* Parse and expand our access message.
1264 : : */
1265 [ # # ]: 0 : if(expand_acc_port_list(&port_list, spadat->spa_message_remain) != 1)
1266 : : {
1267 : : /* technically we would already have exited with an error if there were
1268 : : * any memory allocation errors (see the add_port_list() function), but
1269 : : * for completeness...
1270 : : */
1271 : 0 : free_acc_port_list(port_list);
1272 : 0 : return res;
1273 : : }
1274 : :
1275 : : /* Start at the top of the proto-port list...
1276 : : */
1277 : 0 : ple = port_list;
1278 : :
1279 : : /* Remember the first proto/port combo in case we need them
1280 : : * for NAT access requests.
1281 : : */
1282 : 0 : fst_proto = ple->proto;
1283 : 0 : fst_port = ple->port;
1284 : :
1285 : : /* Set our expire time value.
1286 : : */
1287 : 0 : time(&now);
1288 : 0 : exp_ts = now + spadat->fw_access_timeout;
1289 : :
1290 : : /* deal with SPA packets that themselves request a NAT operation
1291 : : */
1292 [ # # ]: 0 : if(spadat->message_type == FKO_LOCAL_NAT_ACCESS_MSG
1293 : : || spadat->message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG
1294 : 0 : || spadat->message_type == FKO_NAT_ACCESS_MSG
1295 [ # # ]: 0 : || spadat->message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG
1296 [ # # ]: 0 : || acc->force_nat)
1297 : : {
1298 [ # # ]: 0 : if(acc->force_nat)
1299 : : {
1300 : 0 : strlcpy(nat_ip, acc->force_nat_ip, sizeof(nat_ip));
1301 : 0 : nat_port = acc->force_nat_port;
1302 : : }
1303 : : else
1304 : : {
1305 : 0 : ndx = strchr(spadat->nat_access, ',');
1306 [ # # ]: 0 : if(ndx != NULL)
1307 : : {
1308 : 0 : strlcpy(nat_ip, spadat->nat_access, (ndx-spadat->nat_access)+1);
1309 [ # # ]: 0 : if (! is_valid_ipv4_addr(nat_ip))
1310 : : {
1311 : 0 : log_msg(LOG_INFO, "Invalid NAT IP in SPA message");
1312 : 0 : free_acc_port_list(port_list);
1313 : 0 : return res;
1314 : : }
1315 : :
1316 : 0 : nat_port = strtol_wrapper(ndx+1, 0, MAX_PORT,
1317 : : NO_EXIT_UPON_ERR, &is_err);
1318 [ # # ]: 0 : if(is_err != FKO_SUCCESS)
1319 : : {
1320 : 0 : log_msg(LOG_INFO, "Invalid NAT port in SPA message");
1321 : 0 : free_acc_port_list(port_list);
1322 : 0 : res = is_err;
1323 : 0 : return res;
1324 : : }
1325 : : }
1326 : : }
1327 : :
1328 [ # # ]: 0 : if(spadat->message_type == FKO_LOCAL_NAT_ACCESS_MSG)
1329 : : {
1330 [ # # ]: 0 : firewd_rule(opts, NULL, FIREWD_RULE_ARGS, spadat->use_src_ip,
1331 : 0 : (fwc.use_destination ? spadat->pkt_destination_ip : FIREWD_ANY_IP),
1332 : : fst_proto, nat_port, in_chain, exp_ts, now, "local NAT",
1333 : : spadat->spa_message_remain);
1334 : : }
1335 [ # # ]: 0 : else if(strlen(fwd_chain->to_chain))
1336 : : {
1337 : : /* FORWARD access rule
1338 : : */
1339 : 0 : forward_access_rule(opts, acc, fwd_chain, nat_ip,
1340 : : nat_port, fst_proto, fst_port, spadat, exp_ts, now);
1341 : : }
1342 : :
1343 : : /* DNAT rule
1344 : : */
1345 [ # # ][ # # ]: 0 : if(strlen(dnat_chain->to_chain) && !acc->disable_dnat)
1346 : 0 : dnat_rule(opts, acc, dnat_chain, nat_ip,
1347 : : nat_port, fst_proto, fst_port, spadat, exp_ts, now);
1348 : :
1349 : : /* SNAT rule
1350 : : */
1351 [ # # ][ # # ]: 0 : if(acc->force_snat || strncasecmp(opts->config[CONF_ENABLE_FIREWD_SNAT], "Y", 1) == 0)
1352 : 0 : snat_rule(opts, acc, nat_ip, nat_port,
1353 : : fst_proto, fst_port, spadat, exp_ts, now);
1354 : : }
1355 : : else /* Non-NAT request - this is the typical case. */
1356 : : {
1357 : : /* Create an access command for each proto/port for the source ip.
1358 : : */
1359 [ # # ]: 0 : while(ple != NULL)
1360 : : {
1361 [ # # ]: 0 : firewd_rule(opts, NULL, FIREWD_RULE_ARGS, spadat->use_src_ip,
1362 : 0 : (fwc.use_destination ? spadat->pkt_destination_ip : FIREWD_ANY_IP),
1363 : : ple->proto, ple->port, in_chain, exp_ts, now, "access",
1364 : : spadat->spa_message_remain);
1365 : :
1366 : : /* We need to make a corresponding OUTPUT rule if out_chain target
1367 : : * is not NULL.
1368 : : */
1369 [ # # ]: 0 : if(strlen(out_chain->to_chain))
1370 : : {
1371 [ # # ]: 0 : firewd_rule(opts, NULL, FIREWD_OUT_RULE_ARGS, spadat->use_src_ip,
1372 : 0 : (fwc.use_destination ? spadat->pkt_destination_ip : FIREWD_ANY_IP),
1373 : : ple->proto, ple->port, out_chain, exp_ts, now, "OUTPUT",
1374 : : spadat->spa_message_remain);
1375 : : }
1376 : 0 : ple = ple->next;
1377 : : }
1378 : : }
1379 : :
1380 : : /* Done with the port list for access rules.
1381 : : */
1382 : 0 : free_acc_port_list(port_list);
1383 : :
1384 : 0 : return(res);
1385 : : }
1386 : :
1387 : : /* Iterate over the configure firewall access chains and purge expired
1388 : : * firewall rules.
1389 : : */
1390 : : void
1391 : 0 : check_firewall_rules(const fko_srv_options_t * const opts)
1392 : : {
1393 : 0 : char exp_str[12] = {0};
1394 : 0 : char rule_num_str[6] = {0};
1395 : : char *ndx, *rn_start, *rn_end, *tmp_mark;
1396 : :
1397 : : int i, res, rn_offset, rule_num, is_err;
1398 : 0 : time_t now, rule_exp, min_exp = 0;
1399 : :
1400 : 0 : struct fw_chain *ch = opts->fw_config->chain;
1401 : :
1402 : 0 : time(&now);
1403 : :
1404 : : /* Iterate over each chain and look for active rules to delete.
1405 : : */
1406 [ # # ]: 0 : for(i=0; i < NUM_FWKNOP_ACCESS_TYPES; i++)
1407 : : {
1408 : : /* If there are no active rules or we have not yet
1409 : : * reached our expected next expire time, continue.
1410 : : */
1411 [ # # ][ # # ]: 0 : if(ch[i].active_rules == 0 || ch[i].next_expire > now)
1412 : 0 : continue;
1413 : :
1414 : 0 : zero_cmd_buffers();
1415 : :
1416 : 0 : rn_offset = 0;
1417 : :
1418 : : /* There should be a rule to delete. Get the current list of
1419 : : * rules for this chain and delete the ones that are expired.
1420 : : */
1421 : : snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_LIST_RULES_ARGS,
1422 : 0 : opts->fw_config->fw_command,
1423 : 0 : ch[i].table,
1424 : 0 : ch[i].to_chain
1425 : : );
1426 : :
1427 : 0 : res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE,
1428 : : WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
1429 : 0 : chop_newline(cmd_out);
1430 : :
1431 : 0 : log_msg(LOG_DEBUG, "check_firewall_rules() CMD: '%s' (res: %d, cmd_out: %s)",
1432 : : cmd_buf, res, cmd_out);
1433 : :
1434 [ # # ]: 0 : if(!EXTCMD_IS_SUCCESS(res))
1435 : : {
1436 : 0 : log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);
1437 : 0 : continue;
1438 : : }
1439 : :
1440 : 0 : log_msg(LOG_DEBUG, "RES=%i, CMD_BUF: %s\nRULES LIST: %s", res, cmd_buf, cmd_out);
1441 : :
1442 : 0 : ndx = strstr(cmd_out, EXPIRE_COMMENT_PREFIX);
1443 [ # # ]: 0 : if(ndx == NULL)
1444 : : {
1445 : : /* we did not find an expected rule.
1446 : : */
1447 : 0 : log_msg(LOG_ERR,
1448 : : "Did not find expire comment in rules list %i", i);
1449 : :
1450 [ # # ]: 0 : if (ch[i].active_rules > 0)
1451 : 0 : ch[i].active_rules--;
1452 : :
1453 : 0 : continue;
1454 : : }
1455 : :
1456 : : /* walk the list and process rules as needed.
1457 : : */
1458 [ # # ]: 0 : while (ndx != NULL) {
1459 : : /* Jump forward and extract the timestamp
1460 : : */
1461 : 0 : ndx += strlen(EXPIRE_COMMENT_PREFIX);
1462 : :
1463 : : /* remember this spot for when we look for the next
1464 : : * rule.
1465 : : */
1466 : 0 : tmp_mark = ndx;
1467 : :
1468 : 0 : strlcpy(exp_str, ndx, sizeof(exp_str));
1469 : 0 : rule_exp = (time_t)atoll(exp_str);
1470 : :
1471 [ # # ]: 0 : if(rule_exp <= now)
1472 : : {
1473 : : /* Backtrack and get the rule number and delete it.
1474 : : */
1475 : : rn_start = ndx;
1476 [ # # ]: 0 : while(--rn_start > cmd_out)
1477 : : {
1478 [ # # ]: 0 : if(*rn_start == '\n')
1479 : : break;
1480 : : }
1481 : :
1482 [ # # ]: 0 : if(*rn_start != '\n')
1483 : : {
1484 : : /* This should not happen. But if it does, complain,
1485 : : * decrement the active rule value, and go on.
1486 : : */
1487 : 0 : log_msg(LOG_ERR,
1488 : : "Rule parse error while finding rule line start in chain %i", i);
1489 : :
1490 [ # # ]: 0 : if (ch[i].active_rules > 0)
1491 : 0 : ch[i].active_rules--;
1492 : :
1493 : : break;
1494 : : }
1495 : 0 : rn_start++;
1496 : :
1497 : 0 : rn_end = strchr(rn_start, ' ');
1498 [ # # ]: 0 : if(rn_end == NULL)
1499 : : {
1500 : : /* This should not happen. But if it does, complain,
1501 : : * decrement the active rule value, and go on.
1502 : : */
1503 : 0 : log_msg(LOG_ERR,
1504 : : "Rule parse error while finding rule number in chain %i", i);
1505 : :
1506 [ # # ]: 0 : if (ch[i].active_rules > 0)
1507 : 0 : ch[i].active_rules--;
1508 : :
1509 : : break;
1510 : : }
1511 : :
1512 : 0 : strlcpy(rule_num_str, rn_start, (rn_end - rn_start)+1);
1513 : :
1514 : 0 : rule_num = strtol_wrapper(rule_num_str, rn_offset, RCHK_MAX_FIREWD_RULE_NUM,
1515 : : NO_EXIT_UPON_ERR, &is_err);
1516 [ # # ]: 0 : if(is_err != FKO_SUCCESS)
1517 : : {
1518 : 0 : log_msg(LOG_ERR,
1519 : : "Rule parse error while finding rule number in chain %i", i);
1520 : :
1521 [ # # ]: 0 : if (ch[i].active_rules > 0)
1522 : 0 : ch[i].active_rules--;
1523 : :
1524 : : break;
1525 : : }
1526 : :
1527 : 0 : zero_cmd_buffers();
1528 : :
1529 : 0 : snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_DEL_RULE_ARGS,
1530 : 0 : opts->fw_config->fw_command,
1531 : : ch[i].table,
1532 : : ch[i].to_chain,
1533 : : rule_num - rn_offset
1534 : : );
1535 : :
1536 : 0 : res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
1537 : : WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
1538 : 0 : chop_newline(err_buf);
1539 : :
1540 : 0 : log_msg(LOG_DEBUG, "check_firewall_rules() CMD: '%s' (res: %d, err: %s)",
1541 : : cmd_buf, res, err_buf);
1542 : :
1543 [ # # ]: 0 : if(EXTCMD_IS_SUCCESS(res))
1544 : : {
1545 : 0 : log_msg(LOG_INFO, "Removed rule %s from %s with expire time of %u",
1546 : : rule_num_str, ch[i].to_chain, rule_exp
1547 : : );
1548 : :
1549 : 0 : rn_offset++;
1550 : :
1551 [ # # ]: 0 : if (ch[i].active_rules > 0)
1552 : 0 : ch[i].active_rules--;
1553 : : }
1554 : : else
1555 : 0 : log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
1556 : :
1557 : : }
1558 : : else
1559 : : {
1560 : : /* Track the minimum future rule expire time.
1561 : : */
1562 [ # # ]: 0 : if(rule_exp > now)
1563 : 0 : min_exp = (min_exp < rule_exp) ? min_exp : rule_exp;
1564 : : }
1565 : :
1566 : : /* Push our tracking index forward beyond (just processed) _exp_
1567 : : * string so we can continue to the next rule in the list.
1568 : : */
1569 : 0 : ndx = strstr(tmp_mark, EXPIRE_COMMENT_PREFIX);
1570 : : }
1571 : :
1572 : : /* Set the next pending expire time accordingly. 0 if there are no
1573 : : * more rules, or whatever the next expected (min_exp) time will be.
1574 : : */
1575 [ # # ]: 0 : if(ch[i].active_rules < 1)
1576 : 0 : ch[i].next_expire = 0;
1577 [ # # ]: 0 : else if(min_exp)
1578 : 0 : ch[i].next_expire = min_exp;
1579 : : }
1580 : 0 : }
1581 : :
1582 : : int
1583 : 10782 : validate_firewd_chain_conf(const char * const chain_str)
1584 : : {
1585 : 10782 : int j, rv = 1;
1586 : 10782 : const char *ndx = chain_str;
1587 : :
1588 : 10782 : j = 1;
1589 [ + + ]: 506754 : while(*ndx != '\0')
1590 : : {
1591 [ + + ]: 495972 : if(*ndx == ',')
1592 : 53910 : j++;
1593 : :
1594 [ + + ]: 495972 : if(*ndx != '\0'
1595 : 495972 : && *ndx != ' '
1596 [ + + ]: 442062 : && *ndx != ','
1597 [ + + ]: 388152 : && *ndx != '_'
1598 [ + - ]: 377370 : && isalnum(*ndx) == 0)
1599 : : {
1600 : : rv = 0;
1601 : : break;
1602 : : }
1603 : 495972 : ndx++;
1604 : : }
1605 : :
1606 : : /* Sanity check - j should be the number of chain fields
1607 : : * (excluding the type).
1608 : : */
1609 [ - + ]: 10782 : if(j != FW_NUM_CHAIN_FIELDS)
1610 : 0 : rv = 0;
1611 : :
1612 : 10782 : return rv;
1613 : : }
1614 : :
1615 : : #endif /* FIREWALL_FIREWALLD */
1616 : :
1617 : : /***EOF***/
|