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