From 813e4e05756ff6fea3ea4b4baeb1af93aeb33e34 Mon Sep 17 00:00:00 2001 From: Gerry Reno Date: Thu, 21 Aug 2014 18:16:00 -0400 Subject: [PATCH 01/12] restore keys from prefs when app is launched --- android/project/src/com/max2idea/android/fwknop/Fwknop.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/android/project/src/com/max2idea/android/fwknop/Fwknop.java b/android/project/src/com/max2idea/android/fwknop/Fwknop.java index cdc45a3a..f099f33c 100644 --- a/android/project/src/com/max2idea/android/fwknop/Fwknop.java +++ b/android/project/src/com/max2idea/android/fwknop/Fwknop.java @@ -378,9 +378,12 @@ public class Fwknop extends Activity { this.mCheck.setChecked(prefs.getBoolean("app_start", false)); this.mPasswd = (EditText) findViewById(R.id.passwd); + this.mPasswd.setText(prefs.getString("passwd_str", "")); + this.mOutput = (TextView) findViewById(R.id.output); this.mHmac = (EditText) findViewById(R.id.hmac); + this.mHmac.setText(prefs.getString("hmac_str", "")); mUnlock = (ImageButton) findViewById(R.id.unlock); mUnlock.setOnClickListener(new OnClickListener() { From eb0e8eb6a1946c2e89ff66399e186d54535bf013 Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Tue, 26 Aug 2014 23:21:14 -0400 Subject: [PATCH 02/12] fwknopd man page updates for access.conf vars --- client/config_init.c | 9 ++++---- doc/fwknopd.man.asciidoc | 44 +++++++++++++++++++++++------------- server/fwknopd.8.in | 48 +++++++++++++++++++++++++++------------- 3 files changed, 67 insertions(+), 34 deletions(-) diff --git a/client/config_init.c b/client/config_init.c index fb01d965..73e83ce2 100644 --- a/client/config_init.c +++ b/client/config_init.c @@ -2408,7 +2408,7 @@ usage(void) " '$HOME/.fwknoprc' file to provide some of all\n" " of the configuration parameters.\n" " If more arguments are set through the command\n" - " line, the configuration is updated accordingly\n" + " line, the configuration is updated accordingly.\n" " -A, --access Provide a list of ports/protocols to open\n" " on the server (e.g. 'tcp/22').\n" " -a, --allow-ip Specify IP address to allow within the SPA\n" @@ -2454,6 +2454,7 @@ usage(void) " -u, --user-agent Set the HTTP User-Agent for resolving the\n" " external IP via -R, or for sending SPA\n" " packets over HTTP.\n" + " -w, --wget-cmd Manually set the path to wget in -R mode.\n" " -H, --http-proxy Specify an HTTP proxy host through which the\n" " SPA packet will be sent. The port can also be\n" " specified here by following the host/ip with\n" @@ -2470,9 +2471,9 @@ usage(void) " -K, --key-gen-file Write generated Rijndael + HMAC keys to a\n" " file\n" " --key-rijndael Specify the Rijndael key. Since the password is\n" - " visible to utilities (like 'ps' under Unix) this\n" - " form should only be used where security is not\n" - " important.\n" + " visible to utilities (like 'ps' under Unix)\n" + " this form should only be used where security is\n" + " not important.\n" " --key-base64-rijndael Specify the base64 encoded Rijndael key. Since\n" " the password is visible to utilities (like 'ps'\n" " under Unix) this form should only be used where\n" diff --git a/doc/fwknopd.man.asciidoc b/doc/fwknopd.man.asciidoc index b9eba9f1..f9d57010 100644 --- a/doc/fwknopd.man.asciidoc +++ b/doc/fwknopd.man.asciidoc @@ -229,17 +229,6 @@ See the '@sysconfdir@/fwknop/fwknopd.conf'' file for the full list and correspon synchronization with the *fwknopd* server system (NTP is good). The default age is 120 seconds (two minutes). -*ACCESS_EXPIRE* '':: - Defines an expiration date for the access stanza in MM/DD/YYYY format. - All SPA packets that match an expired stanza will be ignored. This - parameter is optional. - -*ACCESS_EXPIRE_EPOCH* '':: - Defines an expiration date for the access stanza as the epoch time, and is - useful if a more accurate expiration time needs to be given than the day - resolution offered by the ACCESS_EXPIRE variable above. All SPA packets - that match an expired stanza will be ignored. This parameter is optional. - *ENABLE_DIGEST_PERSISTENCE* '':: Track digest sums associated with previous SPA packets processed by *fwknopd*. This allows digest sums to remain persistent across @@ -303,7 +292,7 @@ See the '@sysconfdir@/fwknop/fwknopd.conf'' file for the full list and correspon the '$HOME/.gnupg' directory of the user running *fwknopd* (most likely root). -GPG_EXE* '':: +*GPG_EXE* '':: Specify the path to GPG, and defaults to '/usr/bin/gpg' if not set. *LOCALE* '':: @@ -443,6 +432,17 @@ directive starts a new stanza. optional field, and if not specified then *fwknopd* defaults to using SHA256 if the access stanza requires an HMAC. +*ACCESS_EXPIRE* '':: + Defines an expiration date for the access stanza in MM/DD/YYYY format. + All SPA packets that match an expired stanza will be ignored. This + parameter is optional. + +*ACCESS_EXPIRE_EPOCH* '':: + Defines an expiration date for the access stanza as the epoch time, and is + useful if a more accurate expiration time needs to be given than the day + resolution offered by the ACCESS_EXPIRE variable above. All SPA packets + that match an expired stanza will be ignored. This parameter is optional. + *ENABLE_CMD_EXEC* '':: This instructs *fwknopd* to accept complete commands that are contained within an authorization packet. Any such command will be executed on @@ -468,6 +468,9 @@ directive starts a new stanza. client behind a NAT) or the client must know the external IP and set it via the *-a* argument. +*REQUIRE_SOURCE_ADDRESS* '':: + Synonym for ``REQUIRE_SOURCE_ADDRESS''. + *FORCE_NAT* ' ':: For any valid SPA packet, force the requested connection to be NAT'd through to the specified (usually internal) IP and port value. This is @@ -522,10 +525,14 @@ directive starts a new stanza. and/or pinentry to collect a passphrase. *GPG_REQUIRE_SIG* '':: - With this setting set to 'Y', fwknopd check all GPG-encrypted SPA + With this setting set to 'Y', fwknopd check all GPG-encrypted SPA messages for a signature (signed by the sender's key). If the incoming message is not signed, the decryption process will fail. If not set, the - default is 'N'. + default is 'Y'. + +*GPG_DISABLE_SIG* '':: + Disable signature verification for incoming SPA messages. This is not a + recommended setting, and the default is 'N'. *GPG_IGNORE_SIG_VERIFY_ERROR* '':: Setting this will allow fwknopd to accept incoming GPG-encrypted packets @@ -538,9 +545,16 @@ directive starts a new stanza. any incoming SPA message that has been encrypted with the *fwknopd* server key. This ensures that the verification of the remote user is accomplished via a strong cryptographic mechanism. - This setting only applies if the ``GPG_REQUIRE_SIG'' is set to 'Y'. + Signature verification is enabled by default, and can only be disabled + if ``GPG_DISABLE_SIG'' is set to 'Y' (not a recommended setting). Separate multiple entries with a comma. +*GPG_FINGERPRINT_ID* '':: + Specify a set of full-length GnuPG key fingerprints instead of the shorter + key identifiers set with the ``GPG_REMOTE_ID'' variable. Here is an + example fingerprint for one of the fwknop test suite keys: + '00CC95F05BC146B6AC4038C9E36F443C6A3FAD56'. + *GPG_HOME_DIR* '':: Define the path to the GnuPG directory to be used by the *fwknopd* server. If this keyword is not specified within '@sysconfdir@/fwknop/access.conf' diff --git a/server/fwknopd.8.in b/server/fwknopd.8.in index a318f686..bd349a78 100644 --- a/server/fwknopd.8.in +++ b/server/fwknopd.8.in @@ -2,12 +2,12 @@ .\" Title: fwknopd .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets v1.78.1 -.\" Date: 06/05/2014 +.\" Date: 08/26/2014 .\" Manual: Fwknop Server .\" Source: Fwknop Server .\" Language: English .\" -.TH "FWKNOPD" "8" "06/05/2014" "Fwknop Server" "Fwknop Server" +.TH "FWKNOPD" "8" "08/26/2014" "Fwknop Server" "Fwknop Server" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -317,16 +317,6 @@ Defines the maximum age (in seconds) that an SPA packet will be accepted\&. This server system (NTP is good)\&. The default age is 120 seconds (two minutes)\&. .RE .PP -\fBACCESS_EXPIRE\fR \fI\fR -.RS 4 -Defines an expiration date for the access stanza in MM/DD/YYYY format\&. All SPA packets that match an expired stanza will be ignored\&. This parameter is optional\&. -.RE -.PP -\fBACCESS_EXPIRE_EPOCH\fR \fI\fR -.RS 4 -Defines an expiration date for the access stanza as the epoch time, and is useful if a more accurate expiration time needs to be given than the day resolution offered by the ACCESS_EXPIRE variable above\&. All SPA packets that match an expired stanza will be ignored\&. This parameter is optional\&. -.RE -.PP \fBENABLE_DIGEST_PERSISTENCE\fR \fI\fR .RS 4 Track digest sums associated with previous SPA packets processed by @@ -407,7 +397,7 @@ directory of the user running (most likely root)\&. .RE .PP -GPG_EXE* \fI\fR +\fBGPG_EXE\fR \fI\fR .RS 4 Specify the path to GPG, and defaults to \fI/usr/bin/gpg\fR @@ -551,6 +541,16 @@ Specify the digest algorithm for incoming SPA packet authentication\&. Must be o defaults to using SHA256 if the access stanza requires an HMAC\&. .RE .PP +\fBACCESS_EXPIRE\fR \fI\fR +.RS 4 +Defines an expiration date for the access stanza in MM/DD/YYYY format\&. All SPA packets that match an expired stanza will be ignored\&. This parameter is optional\&. +.RE +.PP +\fBACCESS_EXPIRE_EPOCH\fR \fI\fR +.RS 4 +Defines an expiration date for the access stanza as the epoch time, and is useful if a more accurate expiration time needs to be given than the day resolution offered by the ACCESS_EXPIRE variable above\&. All SPA packets that match an expired stanza will be ignored\&. This parameter is optional\&. +.RE +.PP \fBENABLE_CMD_EXEC\fR \fI\fR .RS 4 This instructs @@ -585,6 +585,11 @@ has to be used to automatically resolve the external address (if the client behi argument\&. .RE .PP +\fBREQUIRE_SOURCE_ADDRESS\fR \fI\fR +.RS 4 +Synonym for \(lqREQUIRE_SOURCE_ADDRESS\(rq\&. +.RE +.PP \fBFORCE_NAT\fR \fI \fR .RS 4 For any valid SPA packet, force the requested connection to be NAT\(cqd through to the specified (usually internal) IP and port value\&. This is useful if there are multiple internal systems running a service such as SSHD, and you want to give transparent access to only one internal system for each stanza in the access\&.conf file\&. This way, multiple external users can each directly access only one internal system per SPA key\&. @@ -633,6 +638,12 @@ to leverage a GnuPG key pair that does not have an associated password\&. While .RS 4 With this setting set to \fIY\fR, fwknopd check all GPG\-encrypted SPA messages for a signature (signed by the sender\(cqs key)\&. If the incoming message is not signed, the decryption process will fail\&. If not set, the default is +\fIY\fR\&. +.RE +.PP +\fBGPG_DISABLE_SIG\fR \fI\fR +.RS 4 +Disable signature verification for incoming SPA messages\&. This is not a recommended setting, and the default is \fIN\fR\&. .RE .PP @@ -646,8 +657,15 @@ Setting this will allow fwknopd to accept incoming GPG\-encrypted packets that a .RS 4 Define a list of gpg key ID\(cqs that are required to have signed any incoming SPA message that has been encrypted with the \fBfwknopd\fR -server key\&. This ensures that the verification of the remote user is accomplished via a strong cryptographic mechanism\&. This setting only applies if the \(lqGPG_REQUIRE_SIG\(rq is set to -\fIY\fR\&. Separate multiple entries with a comma\&. +server key\&. This ensures that the verification of the remote user is accomplished via a strong cryptographic mechanism\&. Signature verification is enabled by default, and can only be disabled if \(lqGPG_DISABLE_SIG\(rq is set to +\fIY\fR +(not a recommended setting)\&. Separate multiple entries with a comma\&. +.RE +.PP +\fBGPG_FINGERPRINT_ID\fR \fI\fR +.RS 4 +Specify a set of full\-length GnuPG key fingerprints instead of the shorter key identifiers set with the \(lqGPG_REMOTE_ID\(rq variable\&. Here is an example fingerprint for one of the fwknop test suite keys: +\fI00CC95F05BC146B6AC4038C9E36F443C6A3FAD56\fR\&. .RE .PP \fBGPG_HOME_DIR\fR \fI\fR From 73186e511ae226f4e5e1dae5638567ecea788fbc Mon Sep 17 00:00:00 2001 From: Damien Stuart Date: Sat, 30 Aug 2014 16:18:46 -0400 Subject: [PATCH 03/12] Added WIN32 definitions for popen (_popen) and pclose (_pclose) to accommodate the call to wget on Windows-based systems. --- common/common.h | 2 ++ win32/config.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/common/common.h b/common/common.h index 5f3007a8..86abe752 100644 --- a/common/common.h +++ b/common/common.h @@ -91,6 +91,8 @@ #define fdopen _fdopen #define close _close #define write _write + #define popen _popen + #define pclose _pclose #define O_WRONLY _O_WRONLY #define O_RDONLY _O_RDONLY #define O_RDWR _O_RDWR diff --git a/win32/config.h b/win32/config.h index 3fda1a18..86b6a9ff 100644 --- a/win32/config.h +++ b/win32/config.h @@ -178,7 +178,7 @@ #undef TIME_WITH_SYS_TIME /* Version number of package */ -#define VERSION "2.0" +#define VERSION "2.6.3" /* Define to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX). */ From ea64f15ae7b73a3986807dd76bf9076756b691e8 Mon Sep 17 00:00:00 2001 From: Gerry Reno Date: Sat, 30 Aug 2014 19:09:02 -0400 Subject: [PATCH 04/12] added .gitignore --- .gitignore | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..8d433592 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# built application files +*.apk +*.ap_ + +# files for the dex VM +*.dex + +# Java class files +*.class + +# generated files +bin/ +gen/ + +# Local configuration file (sdk path, etc) +local.properties + +# Eclipse project files +.classpath +.project + +# Proguard folder generated by Eclipse +proguard/ + +# Intellij project files +*.iml +*.ipr +*.iws +.idea/ + +# CMake files +CMakeCache.txt +CMakeFiles +Makefile +cmake_install.cmake +install_manifest.txt + +#project generated files +android/project/libs +android/project/obj +android/project/jni/fwknop/fko.h +android/project/jni/libfwknop/*.h +android/project/jni/libfwknop/*.c From e54383b518fad5e0a31ae0f752d3c3c7ec70f16c Mon Sep 17 00:00:00 2001 From: Gerry Reno Date: Sun, 31 Aug 2014 00:06:37 -0400 Subject: [PATCH 05/12] first cut at firewalld --- server/fw_util_firewalld.c | 1583 ++++++++++++++++++++++++++++++++++++ server/fw_util_firewalld.h | 62 ++ 2 files changed, 1645 insertions(+) create mode 100644 server/fw_util_firewalld.c create mode 100644 server/fw_util_firewalld.h diff --git a/server/fw_util_firewalld.c b/server/fw_util_firewalld.c new file mode 100644 index 00000000..9fcb2a48 --- /dev/null +++ b/server/fw_util_firewalld.c @@ -0,0 +1,1583 @@ +/* + ***************************************************************************** + * + * File: fw_util_firewalld.c + * + * Purpose: Fwknop routines for managing firewalld firewall rules. + * + * Fwknop is developed primarily by the people listed in the file 'AUTHORS'. + * Copyright (C) 2009-2014 fwknop developers and contributors. For a full + * list of contributors, see the file 'CREDITS'. + * + * License (GNU General Public License): + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + ***************************************************************************** +*/ + +#include "fwknopd_common.h" + +#ifdef FIREWALL_FIREWALLD + +#include "fw_util.h" +#include "utils.h" +#include "log_msg.h" +#include "extcmd.h" +#include "access.h" + +static struct fw_config fwc; +static char cmd_buf[CMD_BUFSIZE]; +static char err_buf[CMD_BUFSIZE]; +static char cmd_out[STANDARD_CMD_OUT_BUFSIZE]; + +/* assume 'firewalld -C' is offered since only older versions + * don't have this (see firewd_chk_support()). +*/ +static int have_firewd_chk_support = 1; + +static void +zero_cmd_buffers(void) +{ + memset(cmd_buf, 0x0, CMD_BUFSIZE); + memset(err_buf, 0x0, CMD_BUFSIZE); + memset(cmd_out, 0x0, STANDARD_CMD_OUT_BUFSIZE); +} + +static void +chop_newline(char *str) +{ + if(str[0] != 0x0 && str[strlen(str)-1] == 0x0a) + str[strlen(str)-1] = 0x0; + return; +} + +static int +rule_exists_no_chk_support(const fko_srv_options_t * const opts, + const struct fw_chain * const fwc, const unsigned int proto, + const char * const ip, const unsigned int port, + const unsigned int exp_ts) +{ + int rule_exists = 0; + char cmd_buf[CMD_BUFSIZE] = {0}; + char line_buf[CMD_BUFSIZE] = {0}; + char target_search[CMD_BUFSIZE] = {0}; + char proto_search[CMD_BUFSIZE] = {0}; + char ip_search[CMD_BUFSIZE] = {0}; + char port_search[CMD_BUFSIZE] = {0}; + char exp_ts_search[CMD_BUFSIZE] = {0}; + FILE *firewd; + + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS, + opts->fw_config->fw_command, + fwc->table, + fwc->to_chain + ); + + firewd = popen(cmd_buf, "r"); + + if(firewd == NULL) + { + log_msg(LOG_ERR, + "Got error %i trying to get rules list.\n", errno); + return(rule_exists); + } + + if(proto == IPPROTO_TCP) + snprintf(proto_search, CMD_BUFSIZE-1, " tcp "); + else if(proto == IPPROTO_UDP) + snprintf(proto_search, CMD_BUFSIZE-1, " udp "); + else if(proto == IPPROTO_ICMP) + snprintf(proto_search, CMD_BUFSIZE-1, " icmp "); + else + snprintf(proto_search, CMD_BUFSIZE-1, " %u ", proto); + + snprintf(port_search, CMD_BUFSIZE-1, ":%u ", port); + snprintf(target_search, CMD_BUFSIZE-1, " %s ", fwc->target); + snprintf(ip_search, CMD_BUFSIZE-1, " %s ", ip); + snprintf(exp_ts_search, CMD_BUFSIZE-1, "%u ", exp_ts); + + while((fgets(line_buf, CMD_BUFSIZE-1, firewd)) != NULL) + { + /* Get past comments and empty lines (note: we only look at the + * first character). + */ + if(IS_EMPTY_LINE(line_buf[0])) + continue; + + if((strstr(line_buf, exp_ts_search) != NULL) + && (strstr(line_buf, proto_search) != NULL) + && (strstr(line_buf, ip_search) != NULL) + && (strstr(line_buf, target_search) != NULL) + && (strstr(line_buf, port_search) != NULL)) + { + rule_exists = 1; + break; + } + } + + pclose(firewd); + + if(rule_exists) + log_msg(LOG_DEBUG, + "rule_exists_no_chk_support() %s %u -> %s expires: %u rule (already exists", + proto_search, port, ip, exp_ts); + else + log_msg(LOG_DEBUG, + "rule_exists_no_chk_support() %s %u -> %s expires: %u rule does not exist", + proto_search, port, ip, exp_ts); + + return(rule_exists); +} + +static int +rule_exists_chk_support(const fko_srv_options_t * const opts, + const char * const chain, const char * const rule) +{ + int rule_exists = 0; + int res = 0; + + zero_cmd_buffers(); + + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_CHK_RULE_ARGS, + opts->fw_config->fw_command, chain, rule); + + res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0); + chop_newline(err_buf); + + log_msg(LOG_DEBUG, "rule_exists_chk_support() CMD: '%s' (res: %d, err: %s)", + cmd_buf, res, err_buf); + + if(EXTCMD_IS_SUCCESS(res) && strlen(err_buf)) + { + log_msg(LOG_DEBUG, "rule_exists_chk_support() Rule : '%s' in %s does not exist", + rule, chain); + } + else + { + rule_exists = 1; + log_msg(LOG_DEBUG, "rule_exists_chk_support() Rule : '%s' in %s already exists", + rule, chain); + } + + return(rule_exists); +} + +static int +rule_exists(const fko_srv_options_t * const opts, + const struct fw_chain * const fwc, const char * const rule, + const unsigned int proto, const char * const ip, + const unsigned int port, const unsigned int exp_ts) +{ + int rule_exists = 0; + + if(have_firewd_chk_support == 1) + rule_exists = rule_exists_chk_support(opts, fwc->to_chain, rule); + else + rule_exists = rule_exists_no_chk_support(opts, fwc, proto, ip, port, exp_ts); + + if(rule_exists == 1) + log_msg(LOG_DEBUG, "rule_exists() Rule : '%s' in %s already exists", + rule, fwc->to_chain); + else + log_msg(LOG_DEBUG, "rule_exists() Rule : '%s' in %s does not exist", + rule, fwc->to_chain); + + return(rule_exists); +} + +static void +firewd_chk_support(const fko_srv_options_t * const opts) +{ + int res = 1; + struct fw_chain *in_chain = &(opts->fw_config->chain[IPT_INPUT_ACCESS]); + + zero_cmd_buffers(); + + /* Add a harmless rule to the firewalld INPUT chain and see if firewalld + * supports '-C' to check for it. Set "have_firewd_chk_support" accordingly, + * delete the rule, and return. + */ + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_TMP_CHK_RULE_ARGS, + opts->fw_config->fw_command, + in_chain->table, + in_chain->from_chain, + 1, /* first rule */ + in_chain->target + ); + + res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0); + chop_newline(err_buf); + + log_msg(LOG_DEBUG, "firewd_chk_support() CMD: '%s' (res: %d, err: %s)", + cmd_buf, res, err_buf); + + zero_cmd_buffers(); + + /* Now see if '-C' works - any output indicates failure + */ + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_TMP_VERIFY_CHK_ARGS, + opts->fw_config->fw_command, + in_chain->table, + in_chain->from_chain, + in_chain->target + ); + + res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0); + chop_newline(err_buf); + + log_msg(LOG_DEBUG, "firewd_chk_support() CMD: '%s' (res: %d, err: %s)", + cmd_buf, res, err_buf); + + if(EXTCMD_IS_SUCCESS(res) && strlen(err_buf)) + { + log_msg(LOG_DEBUG, "firewd_chk_support() -C not supported"); + have_firewd_chk_support = 0; + } + else + { + log_msg(LOG_DEBUG, "firewd_chk_support() -C supported"); + have_firewd_chk_support = 1; + } + + /* Delete the tmp rule + */ + zero_cmd_buffers(); + + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS, + opts->fw_config->fw_command, + in_chain->table, + in_chain->from_chain, + 1 + ); + run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0); + + return; +} + +static int +comment_match_exists(const fko_srv_options_t * const opts) +{ + int res = 1; + char *ndx = NULL; + struct fw_chain *in_chain = &(opts->fw_config->chain[IPT_INPUT_ACCESS]); + + zero_cmd_buffers(); + + /* Add a harmless rule to the firewalld INPUT chain that uses the comment + * match and make sure it exists. If not, return zero. Otherwise, delete + * the rule and return true. + */ + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_TMP_COMMENT_ARGS, + opts->fw_config->fw_command, + in_chain->table, + in_chain->from_chain, + 1, /* first rule */ + in_chain->target + ); + + res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0); + chop_newline(err_buf); + + log_msg(LOG_DEBUG, "comment_match_exists() CMD: '%s' (res: %d, err: %s)", + cmd_buf, res, err_buf); + + zero_cmd_buffers(); + + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS, + opts->fw_config->fw_command, + in_chain->table, + in_chain->from_chain + ); + + res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0); + chop_newline(cmd_out); + + if(!EXTCMD_IS_SUCCESS(res)) + log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out); + + ndx = strstr(cmd_out, TMP_COMMENT); + if(ndx == NULL) + res = 0; /* did not find the tmp comment */ + else + res = 1; + + if(res == 1) + { + /* Delete the tmp comment rule + */ + zero_cmd_buffers(); + + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS, + opts->fw_config->fw_command, + in_chain->table, + in_chain->from_chain, + 1 + ); + run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0); + } + + return res; +} + +static int +add_jump_rule(const fko_srv_options_t * const opts, const int chain_num) +{ + int res = 0; + + zero_cmd_buffers(); + + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_JUMP_RULE_ARGS, + fwc.fw_command, + fwc.chain[chain_num].table, + fwc.chain[chain_num].from_chain, + fwc.chain[chain_num].jump_rule_pos, + fwc.chain[chain_num].to_chain + ); + + res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0); + + log_msg(LOG_DEBUG, "add_jump_rule() CMD: '%s' (res: %d, err: %s)", + cmd_buf, res, err_buf); + + if(EXTCMD_IS_SUCCESS(res)) + log_msg(LOG_INFO, "Added jump rule from chain: %s to chain: %s", + fwc.chain[chain_num].from_chain, + fwc.chain[chain_num].to_chain); + else + log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf); + + return res; +} + +static int +chain_exists(const fko_srv_options_t * const opts, const int chain_num) +{ + int res = 0; + + zero_cmd_buffers(); + + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_CHAIN_EXISTS_ARGS, + fwc.fw_command, + fwc.chain[chain_num].table, + fwc.chain[chain_num].to_chain + ); + + res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0); + chop_newline(err_buf); + + log_msg(LOG_DEBUG, "chain_exists() CMD: '%s' (res: %d, err: %s)", + cmd_buf, res, err_buf); + + if(EXTCMD_IS_SUCCESS(res)) + log_msg(LOG_DEBUG, "'%s' table '%s' chain exists", + fwc.chain[chain_num].table, + fwc.chain[chain_num].to_chain); + else + log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf); + + return res; +} + +static int +jump_rule_exists_chk_support(const fko_srv_options_t * const opts, const int chain_num) +{ + int exists = 0; + char rule_buf[CMD_BUFSIZE] = {0}; + + snprintf(rule_buf, CMD_BUFSIZE-1, IPT_CHK_JUMP_RULE_ARGS, + fwc.chain[chain_num].table, + fwc.chain[chain_num].to_chain + ); + + if(rule_exists_chk_support(opts, fwc.chain[chain_num].from_chain, rule_buf) == 1) + { + log_msg(LOG_DEBUG, "jump_rule_exists_chk_support() jump rule found"); + exists = 1; + } + else + log_msg(LOG_DEBUG, "jump_rule_exists_chk_support() jump rule not found"); + + return exists; +} + +static int +jump_rule_exists_no_chk_support(const fko_srv_options_t * const opts, const int chain_num) +{ + int exists = 0; + char cmd_buf[CMD_BUFSIZE] = {0}; + char chain_search[CMD_BUFSIZE] = {0}; + char line_buf[CMD_BUFSIZE] = {0}; + FILE *firewd; + + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS, + fwc.fw_command, + fwc.chain[chain_num].table, + fwc.chain[chain_num].from_chain + ); + + firewd = popen(cmd_buf, "r"); + + if(firewd == NULL) + { + log_msg(LOG_ERR, + "Got error %i trying to get rules list.\n", errno); + return(exists); + } + + /* include spaces on either side as produced by 'firewalld -L' output + */ + snprintf(chain_search, CMD_BUFSIZE-1, " %s ", + fwc.chain[chain_num].to_chain); + + while((fgets(line_buf, CMD_BUFSIZE-1, firewd)) != NULL) + { + /* Get past comments and empty lines (note: we only look at the + * first character). + */ + if(IS_EMPTY_LINE(line_buf[0])) + continue; + + if(strstr(line_buf, chain_search) != NULL) + { + exists = 1; + break; + } + } + + pclose(firewd); + + + if(exists) + log_msg(LOG_DEBUG, "jump_rule_exists_no_chk_support() jump rule found"); + else + log_msg(LOG_DEBUG, "jump_rule_exists_no_chk_support() jump rule not found"); + + return(exists); +} + +static int +jump_rule_exists(const fko_srv_options_t * const opts, const int chain_num) +{ + int exists = 0; + + if(have_firewd_chk_support == 1) + exists = jump_rule_exists_chk_support(opts, chain_num); + else + exists = jump_rule_exists_no_chk_support(opts, chain_num); + + return exists; +} + +/* Print all firewall rules currently instantiated by the running fwknopd + * daemon to stdout. +*/ +int +fw_dump_rules(const fko_srv_options_t * const opts) +{ + int i; + int res, got_err = 0; + + struct fw_chain *ch = opts->fw_config->chain; + + if (opts->fw_list_all == 1) + { + fprintf(stdout, "Listing all firewalld rules in applicable tables...\n"); + fflush(stdout); + + for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++) + { + + if(fwc.chain[i].target[0] == '\0') + continue; + + zero_cmd_buffers(); + + /* Create the list command + */ + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_ALL_RULES_ARGS, + opts->fw_config->fw_command, + ch[i].table + ); + + res = system(cmd_buf); + + log_msg(LOG_DEBUG, "fw_dump_rules() CMD: '%s' (res: %d)", + cmd_buf, res); + + /* Expect full success on this */ + if(! EXTCMD_IS_SUCCESS(res)) + { + log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf); + got_err++; + } + } + } + else + { + fprintf(stdout, "Listing rules in fwknopd firewalld chains...\n"); + fflush(stdout); + + for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++) + { + + if(fwc.chain[i].target[0] == '\0') + continue; + + zero_cmd_buffers(); + + /* Create the list command + */ + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS, + opts->fw_config->fw_command, + ch[i].table, + ch[i].to_chain + ); + + fprintf(stdout, "\n"); + fflush(stdout); + res = system(cmd_buf); + + log_msg(LOG_DEBUG, "fw_dump_rules() CMD: '%s' (res: %d)", + cmd_buf, res); + + /* Expect full success on this */ + if(! EXTCMD_IS_SUCCESS(res)) + { + log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf); + got_err++; + } + } + } + + return(got_err); +} + +/* Quietly flush and delete all fwknop custom chains. +*/ +static void +delete_all_chains(const fko_srv_options_t * const opts) +{ + int i, res, cmd_ctr = 0; + + for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++) + { + if(fwc.chain[i].target[0] == '\0') + continue; + + /* First look for a jump rule to this chain and remove it if it + * is there. + */ + cmd_ctr = 0; + while(cmd_ctr < CMD_LOOP_TRIES && (jump_rule_exists(opts, i) == 1)) + { + zero_cmd_buffers(); + + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_JUMP_RULE_ARGS, + fwc.fw_command, + fwc.chain[i].table, + fwc.chain[i].from_chain, + fwc.chain[i].to_chain + ); + + res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0); + chop_newline(err_buf); + + log_msg(LOG_DEBUG, "delete_all_chains() CMD: '%s' (res: %d, err: %s)", + cmd_buf, res, err_buf); + + /* Expect full success on this */ + if(! EXTCMD_IS_SUCCESS(res)) + log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf); + + cmd_ctr++; + } + + zero_cmd_buffers(); + + /* Now flush and remove the chain. + */ + snprintf(cmd_buf, CMD_BUFSIZE-1, + "(%s " IPT_FLUSH_CHAIN_ARGS "; %s " IPT_DEL_CHAIN_ARGS ")", // > /dev/null 2>&1", + fwc.fw_command, + fwc.chain[i].table, + fwc.chain[i].to_chain, + fwc.fw_command, + fwc.chain[i].table, + fwc.chain[i].to_chain + ); + + res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0); + chop_newline(err_buf); + + log_msg(LOG_DEBUG, "delete_all_chains() CMD: '%s' (res: %d, err: %s)", + cmd_buf, res, err_buf); + + /* Expect full success on this */ + if(! EXTCMD_IS_SUCCESS(res)) + log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf); + } +} + +static int +create_chain(const fko_srv_options_t * const opts, const int chain_num) +{ + int res = 0; + + zero_cmd_buffers(); + + /* Create the custom chain. + */ + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_NEW_CHAIN_ARGS, + fwc.fw_command, + fwc.chain[chain_num].table, + fwc.chain[chain_num].to_chain + ); + + res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0); + chop_newline(err_buf); + + log_msg(LOG_DEBUG, "create_chain() CMD: '%s' (res: %d, err: %s)", + cmd_buf, res, err_buf); + + /* Expect full success on this */ + if(! EXTCMD_IS_SUCCESS(res)) + log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf); + + return res; +} + +/* Create the fwknop custom chains (at least those that are configured). +*/ +static int +create_fw_chains(const fko_srv_options_t * const opts) +{ + int i, got_err = 0; + + for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++) + { + if(fwc.chain[i].target[0] == '\0') + continue; + + if(chain_exists(opts, i) == 0) + { + + /* Create the chain + */ + if(! EXTCMD_IS_SUCCESS(create_chain(opts, i))) + got_err++; + + /* Then create the jump rule to that chain if it + * doesn't already exist (which is possible) + */ + if(jump_rule_exists(opts, i) == 0) + if(! EXTCMD_IS_SUCCESS(add_jump_rule(opts, i))) + got_err++; + } + } + + return(got_err); +} + +static int +set_fw_chain_conf(const int type, const char * const conf_str) +{ + int i, j, is_err; + char tbuf[MAX_LINE_LEN] = {0}; + const char *ndx = conf_str; + + char *chain_fields[FW_NUM_CHAIN_FIELDS]; + + struct fw_chain *chain = &(fwc.chain[type]); + + if(conf_str == NULL) + { + log_msg(LOG_ERR, "[*] NULL conf_str"); + return 0; + } + + chain->type = type; + + if(ndx != NULL) + chain_fields[0] = tbuf; + + i = 0; + j = 1; + while(*ndx != '\0') + { + if(*ndx != ' ') + { + if(*ndx == ',') + { + tbuf[i] = '\0'; + chain_fields[j++] = &(tbuf[++i]); + } + else + tbuf[i++] = *ndx; + } + if(*ndx != '\0' + && *ndx != ' ' + && *ndx != ',' + && *ndx != '_' + && isalnum(*ndx) == 0) + { + log_msg(LOG_ERR, "[*] Custom chain config parse error: " + "invalid character '%c' for chain type %i, " + "line: %s", *ndx, type, conf_str); + return 0; + } + ndx++; + } + + /* Sanity check - j should be the number of chain fields + * (excluding the type). + */ + if(j != FW_NUM_CHAIN_FIELDS) + { + log_msg(LOG_ERR, "[*] Custom chain config parse error: " + "wrong number of fields for chain type %i, " + "line: %s", type, conf_str); + return 0; + } + + /* Pull and set Target */ + strlcpy(chain->target, chain_fields[0], sizeof(chain->target)); + + /* Pull and set Table */ + strlcpy(chain->table, chain_fields[1], sizeof(chain->table)); + + /* Pull and set From_chain */ + strlcpy(chain->from_chain, chain_fields[2], sizeof(chain->from_chain)); + + /* Pull and set Jump_rule_position */ + chain->jump_rule_pos = strtol_wrapper(chain_fields[3], + 0, RCHK_MAX_IPT_RULE_NUM, NO_EXIT_UPON_ERR, &is_err); + if(is_err != FKO_SUCCESS) + { + log_msg(LOG_ERR, "[*] invalid jump rule position in Line: %s", + conf_str); + return 0; + } + + /* Pull and set To_chain */ + strlcpy(chain->to_chain, chain_fields[4], sizeof(chain->to_chain)); + + /* Pull and set to_chain rule position */ + chain->rule_pos = strtol_wrapper(chain_fields[5], + 0, RCHK_MAX_IPT_RULE_NUM, NO_EXIT_UPON_ERR, &is_err); + if(is_err != FKO_SUCCESS) + { + log_msg(LOG_ERR, "[*] invalid to_chain rule position in Line: %s", + conf_str); + return 0; + } + return 1; +} + +int +fw_config_init(fko_srv_options_t * const opts) +{ + + memset(&fwc, 0x0, sizeof(struct fw_config)); + + /* Set our firewall exe command path (firewalld in most cases). + */ + strlcpy(fwc.fw_command, opts->config[CONF_FIREWALL_EXE], sizeof(fwc.fw_command)); + +#if HAVE_LIBFIU + fiu_return_on("fw_config_init", 0); +#endif + + /* Pull the fwknop chain config info and setup our internal + * config struct. The IPT_INPUT is the only one that is + * required. The rest are optional. + */ + if(set_fw_chain_conf(IPT_INPUT_ACCESS, opts->config[CONF_IPT_INPUT_ACCESS]) != 1) + return 0; + + /* The FWKNOP_OUTPUT_ACCESS requires ENABLE_IPT_OUTPUT_ACCESS be Y + */ + if(strncasecmp(opts->config[CONF_ENABLE_IPT_OUTPUT], "Y", 1)==0) + if(set_fw_chain_conf(IPT_OUTPUT_ACCESS, opts->config[CONF_IPT_OUTPUT_ACCESS]) != 1) + return 0; + + /* The remaining access chains require ENABLE_IPT_FORWARDING = Y + */ + if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1)==0) + { + if(set_fw_chain_conf(IPT_FORWARD_ACCESS, opts->config[CONF_IPT_FORWARD_ACCESS]) != 1) + return 0; + + if(set_fw_chain_conf(IPT_DNAT_ACCESS, opts->config[CONF_IPT_DNAT_ACCESS]) != 1) + return 0; + + /* SNAT (whichever mode) requires ENABLE_IPT_SNAT = Y + */ + if(strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "Y", 1)==0) + { + if(opts->config[CONF_SNAT_TRANSLATE_IP] == NULL + || ! is_valid_ipv4_addr(opts->config[CONF_SNAT_TRANSLATE_IP])) + { + fwc.use_masquerade = 1; + if(set_fw_chain_conf(IPT_MASQUERADE_ACCESS, opts->config[CONF_IPT_MASQUERADE_ACCESS]) != 1) + return 0; + } + else + { + if(is_valid_ipv4_addr(opts->config[CONF_SNAT_TRANSLATE_IP])) + { + if(set_fw_chain_conf(IPT_SNAT_ACCESS, opts->config[CONF_IPT_SNAT_ACCESS]) != 1) + return 0; + } + else + { + return 0; + } + } + } + } + + /* Let us find it via our opts struct as well. + */ + opts->fw_config = &fwc; + + return 1; +} + +int +fw_initialize(const fko_srv_options_t * const opts) +{ + int res = 1; + + /* Flush the chains (just in case) so we can start fresh. + */ + if(strncasecmp(opts->config[CONF_FLUSH_IPT_AT_INIT], "Y", 1) == 0) + delete_all_chains(opts); + + /* Now create any configured chains. + */ + if(create_fw_chains(opts) != 0) + { + log_msg(LOG_WARNING, + "Warning: Errors detected during fwknop custom chain creation"); + res = 0; + } + + /* Make sure that the 'comment' match is available + */ + if(strncasecmp(opts->config[CONF_ENABLE_IPT_COMMENT_CHECK], "Y", 1) == 0) + { + if(comment_match_exists(opts) == 1) + { + log_msg(LOG_INFO, "firewalld 'comment' match is available"); + } + else + { + log_msg(LOG_WARNING, "Warning: Could not use the 'comment' match"); + res = 0; + } + } + + /* See if firewalld offers the '-C' argument (older versions don't). If not, + * then switch to parsing firewalld -L output to find rules. + */ + if(opts->firewd_disable_check_support) + have_firewd_chk_support = 0; + else + firewd_chk_support(opts); + + return(res); +} + +int +fw_cleanup(const fko_srv_options_t * const opts) +{ + if(strncasecmp(opts->config[CONF_FLUSH_IPT_AT_EXIT], "N", 1) == 0 + && opts->fw_flush == 0) + return(0); + + delete_all_chains(opts); + return(0); +} + +static int +create_rule(const fko_srv_options_t * const opts, + const char * const fw_chain, const char * const fw_rule) +{ + int res = 0; + + zero_cmd_buffers(); + + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s -A %s %s", opts->fw_config->fw_command, fw_chain, fw_rule); + + res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0); + chop_newline(err_buf); + + log_msg(LOG_DEBUG, "create_rule() CMD: '%s' (res: %d, err: %s)", + cmd_buf, res, err_buf); + + if(EXTCMD_IS_SUCCESS(res)) + { + log_msg(LOG_DEBUG, "create_rule() Rule: '%s' added to %s", fw_rule, fw_chain); + res = 1; + } + else + log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf); + + return res; +} + +/****************************************************************************/ + +/* Rule Processing - Create an access request... +*/ +int +process_spa_request(const fko_srv_options_t * const opts, + const acc_stanza_t * const acc, spa_data_t * const spadat) +{ + char nat_ip[MAX_IPV4_STR_LEN] = {0}; + char snat_target[SNAT_TARGET_BUFSIZE] = {0}; + char rule_buf[CMD_BUFSIZE] = {0}; + char *ndx; + + unsigned int nat_port = 0; + + acc_port_list_t *port_list = NULL; + acc_port_list_t *ple = NULL; + + unsigned int fst_proto; + unsigned int fst_port; + + struct fw_chain * const in_chain = &(opts->fw_config->chain[IPT_INPUT_ACCESS]); + struct fw_chain * const out_chain = &(opts->fw_config->chain[IPT_OUTPUT_ACCESS]); + struct fw_chain * const fwd_chain = &(opts->fw_config->chain[IPT_FORWARD_ACCESS]); + struct fw_chain * const dnat_chain = &(opts->fw_config->chain[IPT_DNAT_ACCESS]); + struct fw_chain *snat_chain; /* We assign this later (if we need to). */ + + int res = 0, is_err, snat_chain_num = 0; + time_t now; + unsigned int exp_ts; + + /* Parse and expand our access message. + */ + if(expand_acc_port_list(&port_list, spadat->spa_message_remain) != 1) + { + /* technically we would already have exited with an error if there were + * any memory allocation errors (see the add_port_list() function), but + * for completeness... + */ + free_acc_port_list(port_list); + return res; + } + + /* Start at the top of the proto-port list... + */ + ple = port_list; + + /* Remember the first proto/port combo in case we need them + * for NAT access requests. + */ + fst_proto = ple->proto; + fst_port = ple->port; + + /* Set our expire time value. + */ + time(&now); + exp_ts = now + spadat->fw_access_timeout; + + /* For straight access requests, we currently support multiple proto/port + * request. + */ + if((spadat->message_type == FKO_ACCESS_MSG + || spadat->message_type == FKO_CLIENT_TIMEOUT_ACCESS_MSG) && !acc->force_nat) + { + + /* Check to make sure that the jump rules exist for each + * required chain + */ + if(chain_exists(opts, IPT_INPUT_ACCESS) == 0) + create_chain(opts, IPT_INPUT_ACCESS); + + if(jump_rule_exists(opts, IPT_INPUT_ACCESS) == 0) + add_jump_rule(opts, IPT_INPUT_ACCESS); + + if(strlen(out_chain->to_chain)) + { + if(chain_exists(opts, IPT_OUTPUT_ACCESS) == 0) + create_chain(opts, IPT_OUTPUT_ACCESS); + + if(jump_rule_exists(opts, IPT_OUTPUT_ACCESS) == 0) + add_jump_rule(opts, IPT_OUTPUT_ACCESS); + } + + /* Create an access command for each proto/port for the source ip. + */ + while(ple != NULL) + { + memset(rule_buf, 0, CMD_BUFSIZE); + + snprintf(rule_buf, CMD_BUFSIZE-1, IPT_RULE_ARGS, + in_chain->table, + ple->proto, + spadat->use_src_ip, + ple->port, + exp_ts, + in_chain->target + ); + + if(rule_exists(opts, in_chain, rule_buf, + ple->proto, spadat->use_src_ip, ple->port, exp_ts) == 0) + { + if(create_rule(opts, in_chain->to_chain, rule_buf)) + { + log_msg(LOG_INFO, "Added Rule to %s for %s, %s expires at %u", + in_chain->to_chain, spadat->use_src_ip, + spadat->spa_message_remain, exp_ts + ); + + in_chain->active_rules++; + + /* Reset the next expected expire time for this chain if it + * is warranted. + */ + if(in_chain->next_expire < now || exp_ts < in_chain->next_expire) + in_chain->next_expire = exp_ts; + } + } + + /* If we have to make an corresponding OUTPUT rule if out_chain target + * is not NULL. + */ + if(strlen(out_chain->to_chain)) + { + memset(rule_buf, 0, CMD_BUFSIZE); + + snprintf(rule_buf, CMD_BUFSIZE-1, IPT_OUT_RULE_ARGS, + out_chain->table, + ple->proto, + spadat->use_src_ip, + ple->port, + exp_ts, + out_chain->target + ); + + if(rule_exists(opts, out_chain, rule_buf, + ple->proto, spadat->use_src_ip, ple->port, exp_ts) == 0) + { + if(create_rule(opts, out_chain->to_chain, rule_buf)) + { + log_msg(LOG_INFO, "Added Rule in %s for %s, %s expires at %u", + out_chain->to_chain, spadat->use_src_ip, + spadat->spa_message_remain, exp_ts + ); + + out_chain->active_rules++; + + /* Reset the next expected expire time for this chain if it + * is warranted. */ + if(out_chain->next_expire < now || exp_ts < out_chain->next_expire) + out_chain->next_expire = exp_ts; + } + } + } + ple = ple->next; + } + } + /* NAT requests... */ + else if(spadat->message_type == FKO_LOCAL_NAT_ACCESS_MSG + || spadat->message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG + || spadat->message_type == FKO_NAT_ACCESS_MSG + || spadat->message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG + || acc->force_nat) + { + /* Parse out the NAT IP and Port components. + */ + if(acc->force_nat) + { + strlcpy(nat_ip, acc->force_nat_ip, sizeof(nat_ip)); + nat_port = acc->force_nat_port; + } + else + { + ndx = strchr(spadat->nat_access, ','); + if(ndx != NULL) + { + strlcpy(nat_ip, spadat->nat_access, (ndx-spadat->nat_access)+1); + if (! is_valid_ipv4_addr(nat_ip)) + { + log_msg(LOG_INFO, "Invalid NAT IP in SPA message"); + free_acc_port_list(port_list); + return res; + } + + nat_port = strtol_wrapper(ndx+1, 0, MAX_PORT, NO_EXIT_UPON_ERR, &is_err); + if(is_err != FKO_SUCCESS) + { + log_msg(LOG_INFO, "Invalid NAT port in SPA message"); + free_acc_port_list(port_list); + res = is_err; + return res; + } + } + } + + if(spadat->message_type == FKO_LOCAL_NAT_ACCESS_MSG) + { + memset(rule_buf, 0, CMD_BUFSIZE); + + snprintf(rule_buf, CMD_BUFSIZE-1, IPT_RULE_ARGS, + in_chain->table, + fst_proto, + spadat->use_src_ip, + nat_port, + exp_ts, + in_chain->target + ); + + /* Check to make sure that the jump rules exist for each + * required chain + */ + if(chain_exists(opts, IPT_INPUT_ACCESS) == 0) + create_chain(opts, IPT_INPUT_ACCESS); + + if(jump_rule_exists(opts, IPT_INPUT_ACCESS) == 0) + add_jump_rule(opts, IPT_INPUT_ACCESS); + + if(rule_exists(opts, in_chain, rule_buf, + fst_proto, spadat->use_src_ip, nat_port, exp_ts) == 0) + { + if(create_rule(opts, in_chain->to_chain, rule_buf)) + { + log_msg(LOG_INFO, "Added Rule to %s for %s, %s expires at %u", + in_chain->to_chain, spadat->use_src_ip, + spadat->spa_message_remain, exp_ts + ); + + in_chain->active_rules++; + + /* Reset the next expected expire time for this chain if it + * is warranted. + */ + if(in_chain->next_expire < now || exp_ts < in_chain->next_expire) + in_chain->next_expire = exp_ts; + } + } + } + else if(strlen(fwd_chain->to_chain)) + { + /* Make our FORWARD and NAT rules, and make sure the + * required chain and jump rule exists + */ + if(chain_exists(opts, IPT_FORWARD_ACCESS) == 0) + create_chain(opts, IPT_FORWARD_ACCESS); + + if (jump_rule_exists(opts, IPT_FORWARD_ACCESS) == 0) + add_jump_rule(opts, IPT_FORWARD_ACCESS); + + memset(rule_buf, 0, CMD_BUFSIZE); + + snprintf(rule_buf, CMD_BUFSIZE-1, IPT_FWD_RULE_ARGS, + fwd_chain->table, + fst_proto, + spadat->use_src_ip, + nat_ip, + nat_port, + exp_ts, + fwd_chain->target + ); + + if(rule_exists(opts, fwd_chain, rule_buf, fst_proto, + spadat->use_src_ip, nat_port, exp_ts) == 0) + { + if(create_rule(opts, fwd_chain->to_chain, rule_buf)) + { + log_msg(LOG_INFO, "Added FORWARD Rule to %s for %s, %s expires at %u", + fwd_chain->to_chain, spadat->use_src_ip, + spadat->spa_message_remain, exp_ts + ); + + fwd_chain->active_rules++; + + /* Reset the next expected expire time for this chain if it + * is warranted. + */ + if(fwd_chain->next_expire < now || exp_ts < fwd_chain->next_expire) + fwd_chain->next_expire = exp_ts; + } + } + } + + if(strlen(dnat_chain->to_chain)) + { + /* Make sure the required chain and jump rule exist + */ + if(chain_exists(opts, IPT_DNAT_ACCESS) == 0) + create_chain(opts, IPT_DNAT_ACCESS); + + if (jump_rule_exists(opts, IPT_DNAT_ACCESS) == 0) + add_jump_rule(opts, IPT_DNAT_ACCESS); + + memset(rule_buf, 0, CMD_BUFSIZE); + + snprintf(rule_buf, CMD_BUFSIZE-1, IPT_DNAT_RULE_ARGS, + dnat_chain->table, + fst_proto, + spadat->use_src_ip, + fst_port, + exp_ts, + dnat_chain->target, + nat_ip, + nat_port + ); + + if(rule_exists(opts, dnat_chain, rule_buf, fst_proto, + spadat->use_src_ip, fst_port, exp_ts) == 0) + { + if(create_rule(opts, dnat_chain->to_chain, rule_buf)) + { + log_msg(LOG_INFO, "Added DNAT Rule to %s for %s, %s expires at %u", + dnat_chain->to_chain, spadat->use_src_ip, + spadat->spa_message_remain, exp_ts + ); + + dnat_chain->active_rules++; + + /* Reset the next expected expire time for this chain if it + * is warranted. + */ + if(dnat_chain->next_expire < now || exp_ts < dnat_chain->next_expire) + dnat_chain->next_expire = exp_ts; + } + } + } + + /* If SNAT (or MASQUERADE) is wanted, then we add those rules here as well. + */ + if(acc->force_snat || strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "Y", 1) == 0) + { + /* Add SNAT or MASQUERADE rules. + */ + if(acc->force_snat && is_valid_ipv4_addr(acc->force_snat_ip)) + { + /* Using static SNAT */ + snat_chain = &(opts->fw_config->chain[IPT_SNAT_ACCESS]); + snprintf(snat_target, SNAT_TARGET_BUFSIZE-1, + "--to-source %s:%i", acc->force_snat_ip, fst_port); + snat_chain_num = IPT_SNAT_ACCESS; + } + else if(acc->force_snat && acc->force_masquerade) + { + /* Using MASQUERADE */ + snat_chain = &(opts->fw_config->chain[IPT_MASQUERADE_ACCESS]); + snprintf(snat_target, SNAT_TARGET_BUFSIZE-1, + "--to-ports %i", fst_port); + snat_chain_num = IPT_MASQUERADE_ACCESS; + } + else if((opts->config[CONF_SNAT_TRANSLATE_IP] != NULL) + && is_valid_ipv4_addr(opts->config[CONF_SNAT_TRANSLATE_IP])) + { + /* Using static SNAT */ + snat_chain = &(opts->fw_config->chain[IPT_SNAT_ACCESS]); + snprintf(snat_target, SNAT_TARGET_BUFSIZE-1, + "--to-source %s:%i", opts->config[CONF_SNAT_TRANSLATE_IP], + fst_port); + snat_chain_num = IPT_SNAT_ACCESS; + } + else + { + /* Using MASQUERADE */ + snat_chain = &(opts->fw_config->chain[IPT_MASQUERADE_ACCESS]); + snprintf(snat_target, SNAT_TARGET_BUFSIZE-1, + "--to-ports %i", fst_port); + snat_chain_num = IPT_MASQUERADE_ACCESS; + } + + if(chain_exists(opts, snat_chain_num) == 0) + create_chain(opts, snat_chain_num); + + if(jump_rule_exists(opts, snat_chain_num) == 0) + add_jump_rule(opts, snat_chain_num); + + memset(rule_buf, 0, CMD_BUFSIZE); + + snprintf(rule_buf, CMD_BUFSIZE-1, IPT_SNAT_RULE_ARGS, + snat_chain->table, + fst_proto, + nat_ip, + nat_port, + exp_ts, + snat_chain->target, + snat_target + ); + + if(rule_exists(opts, snat_chain, rule_buf, fst_proto, + spadat->use_src_ip, nat_port, exp_ts) == 0) + { + if(create_rule(opts, snat_chain->to_chain, rule_buf)) + { + log_msg(LOG_INFO, "Added SNAT Rule to %s for %s, %s expires at %u", + snat_chain->to_chain, spadat->use_src_ip, + spadat->spa_message_remain, exp_ts + ); + + snat_chain->active_rules++; + + /* Reset the next expected expire time for this chain if it + * is warranted. + */ + if(snat_chain->next_expire < now || exp_ts < snat_chain->next_expire) + snat_chain->next_expire = exp_ts; + } + } + } + } + + /* Done with the port list for access rules. + */ + free_acc_port_list(port_list); + + return(res); +} + +/* Iterate over the configure firewall access chains and purge expired + * firewall rules. +*/ +void +check_firewall_rules(const fko_srv_options_t * const opts) +{ + char exp_str[12] = {0}; + char rule_num_str[6] = {0}; + char *ndx, *rn_start, *rn_end, *tmp_mark; + + int i, res, rn_offset, rule_num, is_err; + time_t now, rule_exp, min_exp = 0; + + struct fw_chain *ch = opts->fw_config->chain; + + time(&now); + + /* Iterate over each chain and look for active rules to delete. + */ + for(i=0; i < NUM_FWKNOP_ACCESS_TYPES; i++) + { + /* If there are no active rules or we have not yet + * reached our expected next expire time, continue. + */ + if(ch[i].active_rules == 0 || ch[i].next_expire > now) + continue; + + zero_cmd_buffers(); + + rn_offset = 0; + + /* There should be a rule to delete. Get the current list of + * rules for this chain and delete the ones that are expired. + */ + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS, + opts->fw_config->fw_command, + ch[i].table, + ch[i].to_chain + ); + + res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0); + chop_newline(cmd_out); + + log_msg(LOG_DEBUG, "check_firewall_rules() CMD: '%s' (res: %d, cmd_out: %s)", + cmd_buf, res, cmd_out); + + if(!EXTCMD_IS_SUCCESS(res)) + { + log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out); + continue; + } + + log_msg(LOG_DEBUG, "RES=%i, CMD_BUF: %s\nRULES LIST: %s", res, cmd_buf, cmd_out); + + ndx = strstr(cmd_out, EXPIRE_COMMENT_PREFIX); + if(ndx == NULL) + { + /* we did not find an expected rule. + */ + log_msg(LOG_ERR, + "Did not find expire comment in rules list %i", i); + + if (ch[i].active_rules > 0) + ch[i].active_rules--; + + continue; + } + + /* walk the list and process rules as needed. + */ + while (ndx != NULL) { + /* Jump forward and extract the timestamp + */ + ndx += strlen(EXPIRE_COMMENT_PREFIX); + + /* remember this spot for when we look for the next + * rule. + */ + tmp_mark = ndx; + + strlcpy(exp_str, ndx, sizeof(exp_str)); + rule_exp = (time_t)atoll(exp_str); + + if(rule_exp <= now) + { + /* Backtrack and get the rule number and delete it. + */ + rn_start = ndx; + while(--rn_start > cmd_out) + { + if(*rn_start == '\n') + break; + } + + if(*rn_start != '\n') + { + /* This should not happen. But if it does, complain, + * decrement the active rule value, and go on. + */ + log_msg(LOG_ERR, + "Rule parse error while finding rule line start in chain %i", i); + + if (ch[i].active_rules > 0) + ch[i].active_rules--; + + break; + } + rn_start++; + + rn_end = strchr(rn_start, ' '); + if(rn_end == NULL) + { + /* This should not happen. But if it does, complain, + * decrement the active rule value, and go on. + */ + log_msg(LOG_ERR, + "Rule parse error while finding rule number in chain %i", i); + + if (ch[i].active_rules > 0) + ch[i].active_rules--; + + break; + } + + strlcpy(rule_num_str, rn_start, (rn_end - rn_start)+1); + + rule_num = strtol_wrapper(rule_num_str, rn_offset, RCHK_MAX_IPT_RULE_NUM, + NO_EXIT_UPON_ERR, &is_err); + if(is_err != FKO_SUCCESS) + { + log_msg(LOG_ERR, + "Rule parse error while finding rule number in chain %i", i); + + if (ch[i].active_rules > 0) + ch[i].active_rules--; + + break; + } + + zero_cmd_buffers(); + + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS, + opts->fw_config->fw_command, + ch[i].table, + ch[i].to_chain, + rule_num - rn_offset + ); + + res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0); + chop_newline(err_buf); + + log_msg(LOG_DEBUG, "check_firewall_rules() CMD: '%s' (res: %d, err: %s)", + cmd_buf, res, err_buf); + + if(EXTCMD_IS_SUCCESS(res)) + { + log_msg(LOG_INFO, "Removed rule %s from %s with expire time of %u", + rule_num_str, ch[i].to_chain, rule_exp + ); + + rn_offset++; + + if (ch[i].active_rules > 0) + ch[i].active_rules--; + } + else + log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf); + + } + else + { + /* Track the minimum future rule expire time. + */ + if(rule_exp > now) + min_exp = (min_exp < rule_exp) ? min_exp : rule_exp; + } + + /* Push our tracking index forward beyond (just processed) _exp_ + * string so we can continue to the next rule in the list. + */ + ndx = strstr(tmp_mark, EXPIRE_COMMENT_PREFIX); + } + + /* Set the next pending expire time accordingly. 0 if there are no + * more rules, or whatever the next expected (min_exp) time will be. + */ + if(ch[i].active_rules < 1) + ch[i].next_expire = 0; + else if(min_exp) + ch[i].next_expire = min_exp; + } +} + +int +validate_firewd_chain_conf(const char * const chain_str) +{ + int j, rv = 1; + const char *ndx = chain_str; + + j = 1; + while(*ndx != '\0') + { + if(*ndx == ',') + j++; + + if(*ndx != '\0' + && *ndx != ' ' + && *ndx != ',' + && *ndx != '_' + && isalnum(*ndx) == 0) + { + rv = 0; + break; + } + ndx++; + } + + /* Sanity check - j should be the number of chain fields + * (excluding the type). + */ + if(j != FW_NUM_CHAIN_FIELDS) + rv = 0; + + return rv; +} + +#endif /* FIREWALL_FIREWALLD */ + +/***EOF***/ diff --git a/server/fw_util_firewalld.h b/server/fw_util_firewalld.h new file mode 100644 index 00000000..89faab6d --- /dev/null +++ b/server/fw_util_firewalld.h @@ -0,0 +1,62 @@ +/* + ***************************************************************************** + * + * File: fw_util_firewalld.h + * + * Purpose: Header file for fw_util_firewalld.c. + * + * Fwknop is developed primarily by the people listed in the file 'AUTHORS'. + * Copyright (C) 2009-2014 fwknop developers and contributors. For a full + * list of contributors, see the file 'CREDITS'. + * + * License (GNU General Public License): + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + ***************************************************************************** +*/ +#ifndef FW_UTIL_FIREWALLD_H +#define FW_UTIL_FIREWALLD_H + +#define SNAT_TARGET_BUFSIZE 64 + +/* firewalld command args +*/ +#define FIREWD_CHK_RULE_ARGS "--direct --passthrough -C %s %s" /* 2>&1 is always added in the second %s */ +#define FIREWD_RULE_ARGS "--direct --passthrough -t %s -p %i -s %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s 2>&1" +#define FIREWD_OUT_RULE_ARGS "--direct --passthrough -t %s -p %i -d %s --sport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s 2>&1" +#define FIREWD_FWD_RULE_ARGS "--direct --passthrough -t %s -p %i -s %s -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s 2>&1" +#define FIREWD_DNAT_RULE_ARGS "--direct --passthrough -t %s -p %i -s %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s --to-destination %s:%i 2>&1" +#define FIREWD_SNAT_RULE_ARGS "--direct --passthrough -t %s -p %i -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s %s 2>&1" +#define FIREWD_TMP_COMMENT_ARGS "--direct --passthrough -t %s -I %s %i -s 127.0.0.2 -m comment --comment " TMP_COMMENT " -j %s 2>&1" +#define FIREWD_TMP_CHK_RULE_ARGS "--direct --passthrough -t %s -I %s %i -s 127.0.0.2 -p udp -j %s 2>&1" +#define FIREWD_TMP_VERIFY_CHK_ARGS "--direct --passthrough -t %s -C %s -s 127.0.0.2 -p udp -j %s 2>&1" +#define FIREWD_DEL_RULE_ARGS "--direct --passthrough -t %s -D %s %i 2>&1" +#define FIREWD_NEW_CHAIN_ARGS "--direct --passthrough -t %s -N %s 2>&1" +#define FIREWD_FLUSH_CHAIN_ARGS "--direct --passthrough -t %s -F %s 2>&1" +#define FIREWD_CHAIN_EXISTS_ARGS "--direct --passthrough -t %s -L %s -n 2>&1" +#define FIREWD_DEL_CHAIN_ARGS "--direct --passthrough -t %s -X %s 2>&1" +#define FIREWD_CHK_JUMP_RULE_ARGS "--direct --passthrough -t %s -j %s 2>&1" +#define FIREWD_ADD_JUMP_RULE_ARGS "--direct --passthrough -t %s -I %s %i -j %s 2>&1" +#define FIREWD_DEL_JUMP_RULE_ARGS "--direct --passthrough -t %s -D %s -j %s 2>&1" /* let firewalld work out the rule number */ +#define FIREWD_LIST_RULES_ARGS "--direct --passthrough -t %s -L %s --line-numbers -n 2>&1" +#define FIREWD_LIST_ALL_RULES_ARGS "--direct --passthrough -t %s -v -n -L --line-numbers 2>&1" + +int validate_firewd_chain_conf(const char * const chain_str); + +#endif /* FW_UTIL_FIREWALLD_H */ + +/***EOF***/ From 25d252c11aea89a5ba5f46868847c72851a62a95 Mon Sep 17 00:00:00 2001 From: Gerry Reno Date: Sun, 31 Aug 2014 00:29:17 -0400 Subject: [PATCH 06/12] more changes for firewalld --- README.md | 9 ++++++--- configure.ac | 37 +++++++++++++++++++++++++++++++++---- fwknop.spec | 10 +++++----- server/fw_util_firewalld.h | 38 +++++++++++++++++++------------------- 4 files changed, 63 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 32256f03..f095480b 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,9 @@ default-drop filtering stance. The main application of SPA is to use a firewall to drop all attempts to connect to services such as SSH in order to make the exploitation of vulnerabilities (both 0-day and unpatched code) more difficult. Because there are no open ports, any service that is concealed by SPA naturally -cannot be scanned for with Nmap. The fwknop project supports three different -firewalls: iptables on Linux systems, pf on OpenBSD, and ipfw on FreeBSD and -Mac OS X. +cannot be scanned for with Nmap. The fwknop project supports four different +firewalls: firewalld and iptables on Linux systems, pf on OpenBSD, and ipfw on +FreeBSD and Mac OS X. SPA is essentially next generation Port Knocking (PK), but solves many of the limitations exhibited by PK while retaining its core benefits. PK limitations @@ -103,6 +103,9 @@ the `INSTALL` file for the general basics on using autoconf. --with-gpgme-prefix=PFX prefix where GPGME is installed (optional) --with-gpg=/path/to/gpg Specify path to the gpg executable that gpgme will use [default=check path] + --with-firewalld=/path/to/firewalld + Specify path to the firewalld executable + [default=check path] --with-iptables=/path/to/iptables Specify path to the iptables executable [default=check path] diff --git a/configure.ac b/configure.ac index e87eeab2..5084e23f 100644 --- a/configure.ac +++ b/configure.ac @@ -476,6 +476,24 @@ AS_IF([test "$want_server" = yes], [ AM_CONDITIONAL([USE_NDBM], [test x$use_ndbm = xyes]) AM_CONDITIONAL([CONFIG_FILE_CACHE], [test x$want_file_cache = xyes]) +dnl Check for firewalld +dnl + AC_ARG_WITH([firewall-cmd], + [AS_HELP_STRING([--with-firewall-cmd=/path/to/firewall-cmd], + [Specify path to the firewall-cmd executable @<:@default=check path@:>@])], + [ + AS_IF([ test "x$withval" = xno ], [], + AS_IF([ test "x$withval" = x -o "x$withval" = xyes ], + [AC_MSG_ERROR([--with-firewall-cmd requires an argument specifying a path to firewall-cmd])], + [ FORCE_FIREWALLD_EXE=$withval ] + ) + ) + ], + [ + AC_PATH_PROG(FIREWALLD_EXE, [firewall-cmd], [], [$APP_PATH]) + ] + ) + dnl Check for iptables dnl AC_ARG_WITH([iptables], @@ -550,6 +568,9 @@ dnl dnl If a firewall was forced. set the appropriate _EXE var and clear the others. dnl + AS_IF([test "x$FORCE_FIREWALLD_EXE" != x], [ + FIREWALLD_EXE="$FORCE_FIREWALLD_EXE" + ],[ AS_IF([test "x$FORCE_IPTABLES_EXE" != x], [ IPTABLES_EXE="$FORCE_IPTABLES_EXE" ],[ @@ -571,12 +592,19 @@ dnl ] ] ] - )))) + ] + ))))) dnl Determine which firewall exe we use (if we have one). -dnl If iptables was found or specified, it wins, then we fallback to ipfw, -dnl then pf, and otherwise we try ipf. +dnl If firewalld was found or specified, it wins, then we fallback to iptables, +dnl then ipfw, pf, and otherwise we try ipf. dnl + AS_IF([test "x$FIREWALLD_EXE" != x], [ + FW_DEF="FW_FIREWALLD" + FIREWALL_TYPE="firewalld" + FIREWALL_EXE=$FIREWALLD_EXE + AC_DEFINE_UNQUOTED([FIREWALL_FIREWALLD], [1], [The firewall type: firewalld.]) + ],[ AS_IF([test "x$IPTABLES_EXE" != x], [ FW_DEF="FW_IPTABLES" FIREWALL_TYPE="iptables" @@ -604,7 +632,8 @@ dnl ] ] ] - )))) + ] + ))))) AC_DEFINE_UNQUOTED([FIREWALL_EXE], ["$FIREWALL_EXE"], [Path to firewall command executable (it should match the firewall type).]) diff --git a/fwknop.spec b/fwknop.spec index aa6084a7..8080759a 100644 --- a/fwknop.spec +++ b/fwknop.spec @@ -50,11 +50,11 @@ Requires: libfko => 2.0.3, libpcap, iptables %description Fwknop implements an authorization scheme known as Single Packet Authorization -(SPA) for Linux systems running iptables. This mechanism requires only a -single encrypted and non-replayed packet to communicate various pieces of -information including desired access through an iptables policy. The main -application of this program is to use iptables in a default-drop stance to -protect services such as SSH with an additional layer of security in order +(SPA) for Linux systems running firewalld or iptables. This mechanism requires +only a single encrypted and non-replayed packet to communicate various pieces of +information including desired access through a firewalld or iptables policy. The +main application of this program is to use firewalld or iptables in a default-drop +stance to protect services such as SSH with an additional layer of security in order to make the exploitation of vulnerabilities (both 0-day and unpatched code) much more difficult. diff --git a/server/fw_util_firewalld.h b/server/fw_util_firewalld.h index 89faab6d..2fe789d2 100644 --- a/server/fw_util_firewalld.h +++ b/server/fw_util_firewalld.h @@ -35,25 +35,25 @@ /* firewalld command args */ -#define FIREWD_CHK_RULE_ARGS "--direct --passthrough -C %s %s" /* 2>&1 is always added in the second %s */ -#define FIREWD_RULE_ARGS "--direct --passthrough -t %s -p %i -s %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s 2>&1" -#define FIREWD_OUT_RULE_ARGS "--direct --passthrough -t %s -p %i -d %s --sport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s 2>&1" -#define FIREWD_FWD_RULE_ARGS "--direct --passthrough -t %s -p %i -s %s -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s 2>&1" -#define FIREWD_DNAT_RULE_ARGS "--direct --passthrough -t %s -p %i -s %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s --to-destination %s:%i 2>&1" -#define FIREWD_SNAT_RULE_ARGS "--direct --passthrough -t %s -p %i -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s %s 2>&1" -#define FIREWD_TMP_COMMENT_ARGS "--direct --passthrough -t %s -I %s %i -s 127.0.0.2 -m comment --comment " TMP_COMMENT " -j %s 2>&1" -#define FIREWD_TMP_CHK_RULE_ARGS "--direct --passthrough -t %s -I %s %i -s 127.0.0.2 -p udp -j %s 2>&1" -#define FIREWD_TMP_VERIFY_CHK_ARGS "--direct --passthrough -t %s -C %s -s 127.0.0.2 -p udp -j %s 2>&1" -#define FIREWD_DEL_RULE_ARGS "--direct --passthrough -t %s -D %s %i 2>&1" -#define FIREWD_NEW_CHAIN_ARGS "--direct --passthrough -t %s -N %s 2>&1" -#define FIREWD_FLUSH_CHAIN_ARGS "--direct --passthrough -t %s -F %s 2>&1" -#define FIREWD_CHAIN_EXISTS_ARGS "--direct --passthrough -t %s -L %s -n 2>&1" -#define FIREWD_DEL_CHAIN_ARGS "--direct --passthrough -t %s -X %s 2>&1" -#define FIREWD_CHK_JUMP_RULE_ARGS "--direct --passthrough -t %s -j %s 2>&1" -#define FIREWD_ADD_JUMP_RULE_ARGS "--direct --passthrough -t %s -I %s %i -j %s 2>&1" -#define FIREWD_DEL_JUMP_RULE_ARGS "--direct --passthrough -t %s -D %s -j %s 2>&1" /* let firewalld work out the rule number */ -#define FIREWD_LIST_RULES_ARGS "--direct --passthrough -t %s -L %s --line-numbers -n 2>&1" -#define FIREWD_LIST_ALL_RULES_ARGS "--direct --passthrough -t %s -v -n -L --line-numbers 2>&1" +#define FIREWD_CHK_RULE_ARGS "--direct --passthrough ipv4 -C %s %s" /* 2>&1 is always added in the second %s */ +#define FIREWD_RULE_ARGS "--direct --passthrough ipv4 -t %s -p %i -s %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s 2>&1" +#define FIREWD_OUT_RULE_ARGS "--direct --passthrough ipv4 -t %s -p %i -d %s --sport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s 2>&1" +#define FIREWD_FWD_RULE_ARGS "--direct --passthrough ipv4 -t %s -p %i -s %s -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s 2>&1" +#define FIREWD_DNAT_RULE_ARGS "--direct --passthrough ipv4 -t %s -p %i -s %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s --to-destination %s:%i 2>&1" +#define FIREWD_SNAT_RULE_ARGS "--direct --passthrough ipv4 -t %s -p %i -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s %s 2>&1" +#define FIREWD_TMP_COMMENT_ARGS "--direct --passthrough ipv4 -t %s -I %s %i -s 127.0.0.2 -m comment --comment " TMP_COMMENT " -j %s 2>&1" +#define FIREWD_TMP_CHK_RULE_ARGS "--direct --passthrough ipv4 -t %s -I %s %i -s 127.0.0.2 -p udp -j %s 2>&1" +#define FIREWD_TMP_VERIFY_CHK_ARGS "--direct --passthrough ipv4 -t %s -C %s -s 127.0.0.2 -p udp -j %s 2>&1" +#define FIREWD_DEL_RULE_ARGS "--direct --passthrough ipv4 -t %s -D %s %i 2>&1" +#define FIREWD_NEW_CHAIN_ARGS "--direct --passthrough ipv4 -t %s -N %s 2>&1" +#define FIREWD_FLUSH_CHAIN_ARGS "--direct --passthrough ipv4 -t %s -F %s 2>&1" +#define FIREWD_CHAIN_EXISTS_ARGS "--direct --passthrough ipv4 -t %s -L %s -n 2>&1" +#define FIREWD_DEL_CHAIN_ARGS "--direct --passthrough ipv4 -t %s -X %s 2>&1" +#define FIREWD_CHK_JUMP_RULE_ARGS "--direct --passthrough ipv4 -t %s -j %s 2>&1" +#define FIREWD_ADD_JUMP_RULE_ARGS "--direct --passthrough ipv4 -t %s -I %s %i -j %s 2>&1" +#define FIREWD_DEL_JUMP_RULE_ARGS "--direct --passthrough ipv4 -t %s -D %s -j %s 2>&1" /* let firewalld work out the rule number */ +#define FIREWD_LIST_RULES_ARGS "--direct --passthrough ipv4 -t %s -L %s --line-numbers -n 2>&1" +#define FIREWD_LIST_ALL_RULES_ARGS "--direct --passthrough ipv4 -t %s -v -n -L --line-numbers 2>&1" int validate_firewd_chain_conf(const char * const chain_str); From d47ebb602a8f42b42031ecfadfaf29f37a6c6829 Mon Sep 17 00:00:00 2001 From: Gerry Reno Date: Sun, 31 Aug 2014 02:23:39 -0400 Subject: [PATCH 07/12] more changes for firewalld --- .gitignore | 29 +++++++++++++++++++++++++++++ server/access.c | 6 +++--- server/cmd_opts.h | 2 +- server/config_init.c | 6 ++++-- server/fw_util.h | 4 +++- server/fw_util_firewalld.h | 2 +- server/fwknopd_common.h | 8 ++++---- server/incoming_spa.c | 2 +- 8 files changed, 46 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index 8d433592..1552b488 100644 --- a/.gitignore +++ b/.gitignore @@ -35,7 +35,36 @@ Makefile cmake_install.cmake install_manifest.txt +# autoconf +*.m4 +Makefile.in +autom4te.cache/ +client/.deps/ +client/Makefile.in +common/Makefile.in +config.h +config.h.in +config.log +config.status +config/ +configure +doc/Makefile.in +lib/.deps/ +lib/.dirstamp +lib/.libs/ +lib/Makefile.in +libtool +server/.deps/ +server/Makefile.in +stamp-h1 + +# C, C++ +*.o +*.lo + #project generated files +common/libfko_util.a +lib/libfko.la android/project/libs android/project/obj android/project/jni/fwknop/fko.h diff --git a/server/access.c b/server/access.c index 28acd0b9..1e6d986f 100644 --- a/server/access.c +++ b/server/access.c @@ -165,7 +165,7 @@ add_acc_expire_time_epoch(fko_srv_options_t *opts, time_t *access_expire_time, c return 1; } -#if FIREWALL_IPTABLES +#if defined(FIREWALL_FIREWALLD) || defined(FIREWALL_IPTABLES) static int add_acc_force_nat(fko_srv_options_t *opts, acc_stanza_t *curr_acc, const char *val) { @@ -1585,7 +1585,7 @@ parse_access_file(fko_srv_options_t *opts) } else if(CONF_VAR_IS(var, "FORCE_NAT")) { -#if FIREWALL_IPTABLES +#if defined(FIREWALL_FIREWALLD) || defined(FIREWALL_IPTABLES) if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1) !=0 ) { log_msg(LOG_ERR, @@ -1607,7 +1607,7 @@ parse_access_file(fko_srv_options_t *opts) } else if(CONF_VAR_IS(var, "FORCE_SNAT")) { -#if FIREWALL_IPTABLES +#if defined(FIREWALL_FIREWALLD) || defined(FIREWALL_IPTABLES) if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1) !=0 ) { log_msg(LOG_ERR, diff --git a/server/cmd_opts.h b/server/cmd_opts.h index 060eba32..5ba7b108 100644 --- a/server/cmd_opts.h +++ b/server/cmd_opts.h @@ -66,7 +66,7 @@ static char *config_map[NUMBER_OF_CONFIG_ENTRIES] = { //"EXTERNAL_CMD_ALARM", //"ENABLE_EXT_CMD_PREFIX", //"EXT_CMD_PREFIX", -#if FIREWALL_IPTABLES +#if defined(FIREWALL_FIREWALLD) || defined(FIREWALL_IPTABLES) "ENABLE_IPT_FORWARDING", "ENABLE_IPT_LOCAL_NAT", "ENABLE_IPT_SNAT", diff --git a/server/config_init.c b/server/config_init.c index f6fed9a3..c3dd7bb1 100644 --- a/server/config_init.c +++ b/server/config_init.c @@ -36,7 +36,9 @@ #include "utils.h" #include "log_msg.h" -#if FIREWALL_IPTABLES +#if FIREWALL_FIREWALLD + #include "fw_util_firewalld.h" +#elif FIREWALL_IPTABLES #include "fw_util_iptables.h" #endif @@ -428,7 +430,7 @@ validate_options(fko_srv_options_t *opts) if(opts->config[CONF_MAX_SNIFF_BYTES] == NULL) set_config_entry(opts, CONF_MAX_SNIFF_BYTES, DEF_MAX_SNIFF_BYTES); -#if FIREWALL_IPTABLES +#if defined(FIREWALL_FIREWALLD) || defined(FIREWALL_IPTABLES) /* Enable IPT forwarding. */ if(opts->config[CONF_ENABLE_IPT_FORWARDING] == NULL) diff --git a/server/fw_util.h b/server/fw_util.h index e94d2186..015b2e63 100644 --- a/server/fw_util.h +++ b/server/fw_util.h @@ -40,7 +40,9 @@ #define EXPIRE_COMMENT_PREFIX "_exp_" #define TMP_COMMENT "__TMPCOMMENT__" -#if FIREWALL_IPTABLES +#if FIREWALL_FIREWALLD + #include "fw_util_firewalld.h" +#elif FIREWALL_IPTABLES #include "fw_util_iptables.h" #elif FIREWALL_IPFW #include "fw_util_ipfw.h" diff --git a/server/fw_util_firewalld.h b/server/fw_util_firewalld.h index 2fe789d2..21c91ff4 100644 --- a/server/fw_util_firewalld.h +++ b/server/fw_util_firewalld.h @@ -55,7 +55,7 @@ #define FIREWD_LIST_RULES_ARGS "--direct --passthrough ipv4 -t %s -L %s --line-numbers -n 2>&1" #define FIREWD_LIST_ALL_RULES_ARGS "--direct --passthrough ipv4 -t %s -v -n -L --line-numbers 2>&1" -int validate_firewd_chain_conf(const char * const chain_str); +int validate_ipt_chain_conf(const char * const chain_str); #endif /* FW_UTIL_FIREWALLD_H */ diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index 32738998..93990189 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -115,9 +115,9 @@ #define RCHK_MAX_PCAP_DISPATCH_COUNT (2 << 22) #define RCHK_MAX_FW_TIMEOUT (2 << 22) -/* Iptables-specific defines +/* FirewallD or Iptables-specific defines */ -#if FIREWALL_IPTABLES +#if defined(FIREWALL_FIREWALLD) || defined(FIREWALL_IPTABLES) #define DEF_FLUSH_IPT_AT_INIT "Y" #define DEF_FLUSH_IPT_AT_EXIT "Y" @@ -215,7 +215,7 @@ enum { //CONF_EXTERNAL_CMD_ALARM, //CONF_ENABLE_EXT_CMD_PREFIX, //CONF_EXT_CMD_PREFIX, -#if FIREWALL_IPTABLES +#if defined(FIREWALL_FIREWALLD) || defined(FIREWALL_IPTABLES) CONF_ENABLE_IPT_FORWARDING, CONF_ENABLE_IPT_LOCAL_NAT, CONF_ENABLE_IPT_SNAT, @@ -352,7 +352,7 @@ typedef struct acc_stanza /* Firewall-related data and types. */ -#if FIREWALL_IPTABLES +#if defined(FIREWALL_FIREWALLD) || defined(FIREWALL_IPTABLES) /* --DSS XXX: These are arbitrary. We should determine appropriate values. */ #define MAX_TABLE_NAME_LEN 64 diff --git a/server/incoming_spa.c b/server/incoming_spa.c index d21cdb6c..9d55af73 100644 --- a/server/incoming_spa.c +++ b/server/incoming_spa.c @@ -815,7 +815,7 @@ incoming_spa(fko_srv_options_t *opts) || spadat.message_type == FKO_NAT_ACCESS_MSG || spadat.message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG) { -#if FIREWALL_IPTABLES +#if defined(FIREWALL_FIREWALLD) || defined(FIREWALL_IPTABLES) if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1)!=0) { log_msg(LOG_WARNING, From ac82b1ced2b976d8010d73cc2786503b14a73641 Mon Sep 17 00:00:00 2001 From: Gerry Reno Date: Sun, 31 Aug 2014 13:51:08 -0400 Subject: [PATCH 08/12] more changes for firewalld --- .gitignore | 25 +++--- server/Makefile.am | 1 + server/access.c | 30 ++++++- server/cmd_opts.h | 19 ++++- server/config_init.c | 150 +++++++++++++++++++++++++++++++++- server/fw_util_firewalld.c | 162 ++++++++++++++++++------------------- server/fw_util_firewalld.h | 2 +- server/fwknopd.conf | 110 +++++++++++++++++++++++++ server/fwknopd_common.h | 91 ++++++++++++++++++++- server/incoming_spa.c | 12 ++- 10 files changed, 501 insertions(+), 101 deletions(-) diff --git a/.gitignore b/.gitignore index 1552b488..44778bc3 100644 --- a/.gitignore +++ b/.gitignore @@ -35,12 +35,16 @@ Makefile cmake_install.cmake install_manifest.txt -# autoconf -*.m4 -Makefile.in +# C, C++ +*.o +*.lo + +#project generated files autom4te.cache/ +*.m4 client/.deps/ client/Makefile.in +common/libfko_util.a common/Makefile.in config.h config.h.in @@ -48,23 +52,24 @@ config.log config.status config/ configure +doc/libfko.info doc/Makefile.in +doc/stamp-vti +doc/version.texi +lib/libfko.la lib/.deps/ lib/.dirstamp lib/.libs/ lib/Makefile.in libtool +Makefile.in server/.deps/ +server/.libs/ +server/fwknopd +server/fwknopd.8 server/Makefile.in stamp-h1 -# C, C++ -*.o -*.lo - -#project generated files -common/libfko_util.a -lib/libfko.la android/project/libs android/project/obj android/project/jni/fwknop/fko.h diff --git a/server/Makefile.am b/server/Makefile.am index fc321ba4..c9ccdbc2 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -8,6 +8,7 @@ fwknopd_SOURCES = fwknopd.c fwknopd.h config_init.c config_init.h \ access.c access.h fwknopd_errors.c fwknopd_errors.h \ tcp_server.c tcp_server.h extcmd.c extcmd.h \ fw_util.c fw_util.h fw_util_ipf.c fw_util_ipf.h \ + fw_util_firewalld.c fw_util_firewalld.h \ fw_util_iptables.c fw_util_iptables.h \ fw_util_ipfw.c fw_util_ipfw.h \ fw_util_pf.c fw_util_pf.h cmd_opts.h diff --git a/server/access.c b/server/access.c index 1e6d986f..7e27b196 100644 --- a/server/access.c +++ b/server/access.c @@ -1585,7 +1585,20 @@ parse_access_file(fko_srv_options_t *opts) } else if(CONF_VAR_IS(var, "FORCE_NAT")) { -#if defined(FIREWALL_FIREWALLD) || defined(FIREWALL_IPTABLES) +#if FIREWALL_FIREWALLD + if(strncasecmp(opts->config[CONF_ENABLE_FIREWD_FORWARDING], "Y", 1) !=0 ) + { + log_msg(LOG_ERR, + "[*] FORCE_NAT requires ENABLE_FIREWD_FORWARDING to be enabled in fwknopd.conf"); + fclose(file_ptr); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } + if(add_acc_force_nat(opts, curr_acc, val) != SUCCESS) + { + fclose(file_ptr); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } +#elif FIREWALL_IPTABLES if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1) !=0 ) { log_msg(LOG_ERR, @@ -1607,7 +1620,20 @@ parse_access_file(fko_srv_options_t *opts) } else if(CONF_VAR_IS(var, "FORCE_SNAT")) { -#if defined(FIREWALL_FIREWALLD) || defined(FIREWALL_IPTABLES) +#if FIREWALL_FIREWALLD + if(strncasecmp(opts->config[CONF_ENABLE_FIREWD_FORWARDING], "Y", 1) !=0 ) + { + log_msg(LOG_ERR, + "[*] FORCE_SNAT requires ENABLE_FIREWD_FORWARDING to be enabled in fwknopd.conf"); + fclose(file_ptr); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } + if(add_acc_force_snat(opts, curr_acc, val) != SUCCESS) + { + fclose(file_ptr); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } +#elif FIREWALL_IPTABLES if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1) !=0 ) { log_msg(LOG_ERR, diff --git a/server/cmd_opts.h b/server/cmd_opts.h index 5ba7b108..db2d4885 100644 --- a/server/cmd_opts.h +++ b/server/cmd_opts.h @@ -66,7 +66,22 @@ static char *config_map[NUMBER_OF_CONFIG_ENTRIES] = { //"EXTERNAL_CMD_ALARM", //"ENABLE_EXT_CMD_PREFIX", //"EXT_CMD_PREFIX", -#if defined(FIREWALL_FIREWALLD) || defined(FIREWALL_IPTABLES) +#if FIREWALL_FIREWALLD + "ENABLE_FIREWD_FORWARDING", + "ENABLE_FIREWD_LOCAL_NAT", + "ENABLE_FIREWD_SNAT", + "SNAT_TRANSLATE_IP", + "ENABLE_FIREWD_OUTPUT", + "FLUSH_FIREWD_AT_INIT", + "FLUSH_FIREWD_AT_EXIT", + "FIREWD_INPUT_ACCESS", + "FIREWD_OUTPUT_ACCESS", + "FIREWD_FORWARD_ACCESS", + "FIREWD_DNAT_ACCESS", + "FIREWD_SNAT_ACCESS", + "FIREWD_MASQUERADE_ACCESS", + "ENABLE_FIREWD_COMMENT_CHECK", +#elif FIREWALL_IPTABLES "ENABLE_IPT_FORWARDING", "ENABLE_IPT_LOCAL_NAT", "ENABLE_IPT_SNAT", @@ -121,6 +136,7 @@ enum { FW_FLUSH, GPG_HOME_DIR, GPG_EXE_PATH, + FIREWD_DISABLE_CHECK_SUPPORT, IPT_DISABLE_CHECK_SUPPORT, PCAP_FILE, ENABLE_PCAP_ANY_DIRECTION, @@ -158,6 +174,7 @@ static struct option cmd_opts[] = {"fw-list-all", 0, NULL, FW_LIST_ALL }, {"gpg-home-dir", 1, NULL, GPG_HOME_DIR }, {"gpg-exe", 1, NULL, GPG_EXE_PATH }, + {"no-firewd-check-support", 0, NULL, FIREWD_DISABLE_CHECK_SUPPORT }, {"no-ipt-check-support", 0, NULL, IPT_DISABLE_CHECK_SUPPORT }, {"locale", 1, NULL, 'l' }, {"rotate-digest-cache", 0, NULL, ROTATE_DIGEST_CACHE }, diff --git a/server/config_init.c b/server/config_init.c index c3dd7bb1..55ca9d37 100644 --- a/server/config_init.c +++ b/server/config_init.c @@ -430,7 +430,150 @@ validate_options(fko_srv_options_t *opts) if(opts->config[CONF_MAX_SNIFF_BYTES] == NULL) set_config_entry(opts, CONF_MAX_SNIFF_BYTES, DEF_MAX_SNIFF_BYTES); -#if defined(FIREWALL_FIREWALLD) || defined(FIREWALL_IPTABLES) +#if FIREWALL_FIREWALLD + /* Enable FIREWD forwarding. + */ + if(opts->config[CONF_ENABLE_FIREWD_FORWARDING] == NULL) + set_config_entry(opts, CONF_ENABLE_FIREWD_FORWARDING, + DEF_ENABLE_FIREWD_FORWARDING); + + /* Enable FIREWD local NAT. + */ + if(opts->config[CONF_ENABLE_FIREWD_LOCAL_NAT] == NULL) + set_config_entry(opts, CONF_ENABLE_FIREWD_LOCAL_NAT, + DEF_ENABLE_FIREWD_LOCAL_NAT); + + /* Enable FIREWD SNAT. + */ + if(opts->config[CONF_ENABLE_FIREWD_SNAT] == NULL) + set_config_entry(opts, CONF_ENABLE_FIREWD_SNAT, + DEF_ENABLE_FIREWD_SNAT); + + /* Make sure we have a valid IP if SNAT is enabled + */ + if(strncasecmp(opts->config[CONF_ENABLE_FIREWD_SNAT], "Y", 1) == 0) + { + /* Note that fw_config_init() will set use_masquerade if necessary + */ + if(opts->config[CONF_SNAT_TRANSLATE_IP] != NULL) + { + if(! is_valid_ipv4_addr(opts->config[CONF_SNAT_TRANSLATE_IP])) + { + log_msg(LOG_ERR, + "Invalid IPv4 addr for SNAT_TRANSLATE_IP" + ); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } + } + } + + /* Enable FIREWD OUTPUT. + */ + if(opts->config[CONF_ENABLE_FIREWD_OUTPUT] == NULL) + set_config_entry(opts, CONF_ENABLE_FIREWD_OUTPUT, + DEF_ENABLE_FIREWD_OUTPUT); + + /* Flush FIREWD at init. + */ + if(opts->config[CONF_FLUSH_FIREWD_AT_INIT] == NULL) + set_config_entry(opts, CONF_FLUSH_FIREWD_AT_INIT, DEF_FLUSH_FIREWD_AT_INIT); + + /* Flush FIREWD at exit. + */ + if(opts->config[CONF_FLUSH_FIREWD_AT_EXIT] == NULL) + set_config_entry(opts, CONF_FLUSH_FIREWD_AT_EXIT, DEF_FLUSH_FIREWD_AT_EXIT); + + /* FIREWD input access. + */ + if(opts->config[CONF_FIREWD_INPUT_ACCESS] == NULL) + set_config_entry(opts, CONF_FIREWD_INPUT_ACCESS, + DEF_FIREWD_INPUT_ACCESS); + + if(validate_firewd_chain_conf(opts->config[CONF_FIREWD_INPUT_ACCESS]) != 1) + { + log_msg(LOG_ERR, + "Invalid FIREWD_INPUT_ACCESS specification, see fwknopd.conf comments" + ); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } + + /* FIREWD output access. + */ + if(opts->config[CONF_FIREWD_OUTPUT_ACCESS] == NULL) + set_config_entry(opts, CONF_FIREWD_OUTPUT_ACCESS, + DEF_FIREWD_OUTPUT_ACCESS); + + if(validate_firewd_chain_conf(opts->config[CONF_FIREWD_OUTPUT_ACCESS]) != 1) + { + log_msg(LOG_ERR, + "Invalid FIREWD_OUTPUT_ACCESS specification, see fwknopd.conf comments" + ); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } + + /* FIREWD forward access. + */ + if(opts->config[CONF_FIREWD_FORWARD_ACCESS] == NULL) + set_config_entry(opts, CONF_FIREWD_FORWARD_ACCESS, + DEF_FIREWD_FORWARD_ACCESS); + + if(validate_firewd_chain_conf(opts->config[CONF_FIREWD_FORWARD_ACCESS]) != 1) + { + log_msg(LOG_ERR, + "Invalid FIREWD_FORWARD_ACCESS specification, see fwknopd.conf comments" + ); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } + + /* FIREWD dnat access. + */ + if(opts->config[CONF_FIREWD_DNAT_ACCESS] == NULL) + set_config_entry(opts, CONF_FIREWD_DNAT_ACCESS, + DEF_FIREWD_DNAT_ACCESS); + + if(validate_firewd_chain_conf(opts->config[CONF_FIREWD_DNAT_ACCESS]) != 1) + { + log_msg(LOG_ERR, + "Invalid FIREWD_DNAT_ACCESS specification, see fwknopd.conf comments" + ); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } + + /* FIREWD snat access. + */ + if(opts->config[CONF_FIREWD_SNAT_ACCESS] == NULL) + set_config_entry(opts, CONF_FIREWD_SNAT_ACCESS, + DEF_FIREWD_SNAT_ACCESS); + + if(validate_firewd_chain_conf(opts->config[CONF_FIREWD_SNAT_ACCESS]) != 1) + { + log_msg(LOG_ERR, + "Invalid FIREWD_SNAT_ACCESS specification, see fwknopd.conf comments" + ); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } + + /* FIREWD masquerade access. + */ + if(opts->config[CONF_FIREWD_MASQUERADE_ACCESS] == NULL) + set_config_entry(opts, CONF_FIREWD_MASQUERADE_ACCESS, + DEF_FIREWD_MASQUERADE_ACCESS); + + if(validate_firewd_chain_conf(opts->config[CONF_FIREWD_MASQUERADE_ACCESS]) != 1) + { + log_msg(LOG_ERR, + "Invalid FIREWD_MASQUERADE_ACCESS specification, see fwknopd.conf comments" + ); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } + + /* Check for the firewalld 'comment' match at init time + */ + if(opts->config[CONF_ENABLE_FIREWD_COMMENT_CHECK] == NULL) + set_config_entry(opts, CONF_ENABLE_FIREWD_COMMENT_CHECK, + DEF_ENABLE_FIREWD_COMMENT_CHECK); + +#elif FIREWALL_IPTABLES /* Enable IPT forwarding. */ if(opts->config[CONF_ENABLE_IPT_FORWARDING] == NULL) @@ -931,6 +1074,9 @@ config_init(fko_srv_options_t *opts, int argc, char **argv) case 'i': set_config_entry(opts, CONF_PCAP_INTF, optarg); break; + case FIREWD_DISABLE_CHECK_SUPPORT: + opts->firewd_disable_check_support = 1; + break; case IPT_DISABLE_CHECK_SUPPORT: opts->ipt_disable_check_support = 1; break; @@ -1071,6 +1217,8 @@ usage(void) " done in the access.conf file).\n" " --gpg-exe - Specify the path to GPG (this is normally done in\n" " the access.conf file).\n" + " --no-firewd-check-support\n" + " - Disable test for 'firewall-cmd ... -C' support.\n" " --no-ipt-check-support - Disable test for 'iptables -C' support.\n" "\n" ); diff --git a/server/fw_util_firewalld.c b/server/fw_util_firewalld.c index 9fcb2a48..3eae64a2 100644 --- a/server/fw_util_firewalld.c +++ b/server/fw_util_firewalld.c @@ -44,8 +44,8 @@ static char cmd_buf[CMD_BUFSIZE]; static char err_buf[CMD_BUFSIZE]; static char cmd_out[STANDARD_CMD_OUT_BUFSIZE]; -/* assume 'firewalld -C' is offered since only older versions - * don't have this (see firewd_chk_support()). +/* assume 'firewall-cmd --direct --passthrough ipv4 -C' is offered + * (see firewd_chk_support()). */ static int have_firewd_chk_support = 1; @@ -81,7 +81,7 @@ rule_exists_no_chk_support(const fko_srv_options_t * const opts, char exp_ts_search[CMD_BUFSIZE] = {0}; FILE *firewd; - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS, + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_LIST_RULES_ARGS, opts->fw_config->fw_command, fwc->table, fwc->to_chain @@ -152,7 +152,7 @@ rule_exists_chk_support(const fko_srv_options_t * const opts, zero_cmd_buffers(); - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_CHK_RULE_ARGS, + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_CHK_RULE_ARGS, opts->fw_config->fw_command, chain, rule); res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0); @@ -203,7 +203,7 @@ static void firewd_chk_support(const fko_srv_options_t * const opts) { int res = 1; - struct fw_chain *in_chain = &(opts->fw_config->chain[IPT_INPUT_ACCESS]); + struct fw_chain *in_chain = &(opts->fw_config->chain[FIREWD_INPUT_ACCESS]); zero_cmd_buffers(); @@ -211,7 +211,7 @@ firewd_chk_support(const fko_srv_options_t * const opts) * supports '-C' to check for it. Set "have_firewd_chk_support" accordingly, * delete the rule, and return. */ - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_TMP_CHK_RULE_ARGS, + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_TMP_CHK_RULE_ARGS, opts->fw_config->fw_command, in_chain->table, in_chain->from_chain, @@ -229,7 +229,7 @@ firewd_chk_support(const fko_srv_options_t * const opts) /* Now see if '-C' works - any output indicates failure */ - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_TMP_VERIFY_CHK_ARGS, + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_TMP_VERIFY_CHK_ARGS, opts->fw_config->fw_command, in_chain->table, in_chain->from_chain, @@ -257,7 +257,7 @@ firewd_chk_support(const fko_srv_options_t * const opts) */ zero_cmd_buffers(); - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS, + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_DEL_RULE_ARGS, opts->fw_config->fw_command, in_chain->table, in_chain->from_chain, @@ -273,7 +273,7 @@ comment_match_exists(const fko_srv_options_t * const opts) { int res = 1; char *ndx = NULL; - struct fw_chain *in_chain = &(opts->fw_config->chain[IPT_INPUT_ACCESS]); + struct fw_chain *in_chain = &(opts->fw_config->chain[FIREWD_INPUT_ACCESS]); zero_cmd_buffers(); @@ -281,7 +281,7 @@ comment_match_exists(const fko_srv_options_t * const opts) * match and make sure it exists. If not, return zero. Otherwise, delete * the rule and return true. */ - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_TMP_COMMENT_ARGS, + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_TMP_COMMENT_ARGS, opts->fw_config->fw_command, in_chain->table, in_chain->from_chain, @@ -297,7 +297,7 @@ comment_match_exists(const fko_srv_options_t * const opts) zero_cmd_buffers(); - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS, + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_LIST_RULES_ARGS, opts->fw_config->fw_command, in_chain->table, in_chain->from_chain @@ -321,7 +321,7 @@ comment_match_exists(const fko_srv_options_t * const opts) */ zero_cmd_buffers(); - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS, + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_DEL_RULE_ARGS, opts->fw_config->fw_command, in_chain->table, in_chain->from_chain, @@ -340,7 +340,7 @@ add_jump_rule(const fko_srv_options_t * const opts, const int chain_num) zero_cmd_buffers(); - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_JUMP_RULE_ARGS, + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_ADD_JUMP_RULE_ARGS, fwc.fw_command, fwc.chain[chain_num].table, fwc.chain[chain_num].from_chain, @@ -370,7 +370,7 @@ chain_exists(const fko_srv_options_t * const opts, const int chain_num) zero_cmd_buffers(); - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_CHAIN_EXISTS_ARGS, + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_CHAIN_EXISTS_ARGS, fwc.fw_command, fwc.chain[chain_num].table, fwc.chain[chain_num].to_chain @@ -398,7 +398,7 @@ jump_rule_exists_chk_support(const fko_srv_options_t * const opts, const int cha int exists = 0; char rule_buf[CMD_BUFSIZE] = {0}; - snprintf(rule_buf, CMD_BUFSIZE-1, IPT_CHK_JUMP_RULE_ARGS, + snprintf(rule_buf, CMD_BUFSIZE-1, FIREWD_CHK_JUMP_RULE_ARGS, fwc.chain[chain_num].table, fwc.chain[chain_num].to_chain ); @@ -423,7 +423,7 @@ jump_rule_exists_no_chk_support(const fko_srv_options_t * const opts, const int char line_buf[CMD_BUFSIZE] = {0}; FILE *firewd; - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS, + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_LIST_RULES_ARGS, fwc.fw_command, fwc.chain[chain_num].table, fwc.chain[chain_num].from_chain @@ -508,7 +508,7 @@ fw_dump_rules(const fko_srv_options_t * const opts) /* Create the list command */ - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_ALL_RULES_ARGS, + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_LIST_ALL_RULES_ARGS, opts->fw_config->fw_command, ch[i].table ); @@ -541,7 +541,7 @@ fw_dump_rules(const fko_srv_options_t * const opts) /* Create the list command */ - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS, + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_LIST_RULES_ARGS, opts->fw_config->fw_command, ch[i].table, ch[i].to_chain @@ -586,7 +586,7 @@ delete_all_chains(const fko_srv_options_t * const opts) { zero_cmd_buffers(); - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_JUMP_RULE_ARGS, + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_DEL_JUMP_RULE_ARGS, fwc.fw_command, fwc.chain[i].table, fwc.chain[i].from_chain, @@ -611,7 +611,7 @@ delete_all_chains(const fko_srv_options_t * const opts) /* Now flush and remove the chain. */ snprintf(cmd_buf, CMD_BUFSIZE-1, - "(%s " IPT_FLUSH_CHAIN_ARGS "; %s " IPT_DEL_CHAIN_ARGS ")", // > /dev/null 2>&1", + "(%s " FIREWD_FLUSH_CHAIN_ARGS "; %s " FIREWD_DEL_CHAIN_ARGS ")", // > /dev/null 2>&1", fwc.fw_command, fwc.chain[i].table, fwc.chain[i].to_chain, @@ -641,7 +641,7 @@ create_chain(const fko_srv_options_t * const opts, const int chain_num) /* Create the custom chain. */ - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_NEW_CHAIN_ARGS, + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_NEW_CHAIN_ARGS, fwc.fw_command, fwc.chain[chain_num].table, fwc.chain[chain_num].to_chain @@ -764,7 +764,7 @@ set_fw_chain_conf(const int type, const char * const conf_str) /* Pull and set Jump_rule_position */ chain->jump_rule_pos = strtol_wrapper(chain_fields[3], - 0, RCHK_MAX_IPT_RULE_NUM, NO_EXIT_UPON_ERR, &is_err); + 0, RCHK_MAX_FIREWD_RULE_NUM, NO_EXIT_UPON_ERR, &is_err); if(is_err != FKO_SUCCESS) { log_msg(LOG_ERR, "[*] invalid jump rule position in Line: %s", @@ -777,7 +777,7 @@ set_fw_chain_conf(const int type, const char * const conf_str) /* Pull and set to_chain rule position */ chain->rule_pos = strtol_wrapper(chain_fields[5], - 0, RCHK_MAX_IPT_RULE_NUM, NO_EXIT_UPON_ERR, &is_err); + 0, RCHK_MAX_FIREWD_RULE_NUM, NO_EXIT_UPON_ERR, &is_err); if(is_err != FKO_SUCCESS) { log_msg(LOG_ERR, "[*] invalid to_chain rule position in Line: %s", @@ -802,44 +802,44 @@ fw_config_init(fko_srv_options_t * const opts) #endif /* Pull the fwknop chain config info and setup our internal - * config struct. The IPT_INPUT is the only one that is + * config struct. The FIREWD_INPUT is the only one that is * required. The rest are optional. */ - if(set_fw_chain_conf(IPT_INPUT_ACCESS, opts->config[CONF_IPT_INPUT_ACCESS]) != 1) + if(set_fw_chain_conf(FIREWD_INPUT_ACCESS, opts->config[CONF_FIREWD_INPUT_ACCESS]) != 1) return 0; - /* The FWKNOP_OUTPUT_ACCESS requires ENABLE_IPT_OUTPUT_ACCESS be Y + /* The FWKNOP_OUTPUT_ACCESS requires ENABLE_FIREWD_OUTPUT_ACCESS be Y */ - if(strncasecmp(opts->config[CONF_ENABLE_IPT_OUTPUT], "Y", 1)==0) - if(set_fw_chain_conf(IPT_OUTPUT_ACCESS, opts->config[CONF_IPT_OUTPUT_ACCESS]) != 1) + if(strncasecmp(opts->config[CONF_ENABLE_FIREWD_OUTPUT], "Y", 1)==0) + if(set_fw_chain_conf(FIREWD_OUTPUT_ACCESS, opts->config[CONF_FIREWD_OUTPUT_ACCESS]) != 1) return 0; - /* The remaining access chains require ENABLE_IPT_FORWARDING = Y + /* The remaining access chains require ENABLE_FIREWD_FORWARDING = Y */ - if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1)==0) + if(strncasecmp(opts->config[CONF_ENABLE_FIREWD_FORWARDING], "Y", 1)==0) { - if(set_fw_chain_conf(IPT_FORWARD_ACCESS, opts->config[CONF_IPT_FORWARD_ACCESS]) != 1) + if(set_fw_chain_conf(FIREWD_FORWARD_ACCESS, opts->config[CONF_FIREWD_FORWARD_ACCESS]) != 1) return 0; - if(set_fw_chain_conf(IPT_DNAT_ACCESS, opts->config[CONF_IPT_DNAT_ACCESS]) != 1) + if(set_fw_chain_conf(FIREWD_DNAT_ACCESS, opts->config[CONF_FIREWD_DNAT_ACCESS]) != 1) return 0; - /* SNAT (whichever mode) requires ENABLE_IPT_SNAT = Y + /* SNAT (whichever mode) requires ENABLE_FIREWD_SNAT = Y */ - if(strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "Y", 1)==0) + if(strncasecmp(opts->config[CONF_ENABLE_FIREWD_SNAT], "Y", 1)==0) { if(opts->config[CONF_SNAT_TRANSLATE_IP] == NULL || ! is_valid_ipv4_addr(opts->config[CONF_SNAT_TRANSLATE_IP])) { fwc.use_masquerade = 1; - if(set_fw_chain_conf(IPT_MASQUERADE_ACCESS, opts->config[CONF_IPT_MASQUERADE_ACCESS]) != 1) + if(set_fw_chain_conf(FIREWD_MASQUERADE_ACCESS, opts->config[CONF_FIREWD_MASQUERADE_ACCESS]) != 1) return 0; } else { if(is_valid_ipv4_addr(opts->config[CONF_SNAT_TRANSLATE_IP])) { - if(set_fw_chain_conf(IPT_SNAT_ACCESS, opts->config[CONF_IPT_SNAT_ACCESS]) != 1) + if(set_fw_chain_conf(FIREWD_SNAT_ACCESS, opts->config[CONF_FIREWD_SNAT_ACCESS]) != 1) return 0; } else @@ -864,7 +864,7 @@ fw_initialize(const fko_srv_options_t * const opts) /* Flush the chains (just in case) so we can start fresh. */ - if(strncasecmp(opts->config[CONF_FLUSH_IPT_AT_INIT], "Y", 1) == 0) + if(strncasecmp(opts->config[CONF_FLUSH_FIREWD_AT_INIT], "Y", 1) == 0) delete_all_chains(opts); /* Now create any configured chains. @@ -878,7 +878,7 @@ fw_initialize(const fko_srv_options_t * const opts) /* Make sure that the 'comment' match is available */ - if(strncasecmp(opts->config[CONF_ENABLE_IPT_COMMENT_CHECK], "Y", 1) == 0) + if(strncasecmp(opts->config[CONF_ENABLE_FIREWD_COMMENT_CHECK], "Y", 1) == 0) { if(comment_match_exists(opts) == 1) { @@ -905,7 +905,7 @@ fw_initialize(const fko_srv_options_t * const opts) int fw_cleanup(const fko_srv_options_t * const opts) { - if(strncasecmp(opts->config[CONF_FLUSH_IPT_AT_EXIT], "N", 1) == 0 + if(strncasecmp(opts->config[CONF_FLUSH_FIREWD_AT_EXIT], "N", 1) == 0 && opts->fw_flush == 0) return(0); @@ -961,10 +961,10 @@ process_spa_request(const fko_srv_options_t * const opts, unsigned int fst_proto; unsigned int fst_port; - struct fw_chain * const in_chain = &(opts->fw_config->chain[IPT_INPUT_ACCESS]); - struct fw_chain * const out_chain = &(opts->fw_config->chain[IPT_OUTPUT_ACCESS]); - struct fw_chain * const fwd_chain = &(opts->fw_config->chain[IPT_FORWARD_ACCESS]); - struct fw_chain * const dnat_chain = &(opts->fw_config->chain[IPT_DNAT_ACCESS]); + struct fw_chain * const in_chain = &(opts->fw_config->chain[FIREWD_INPUT_ACCESS]); + struct fw_chain * const out_chain = &(opts->fw_config->chain[FIREWD_OUTPUT_ACCESS]); + struct fw_chain * const fwd_chain = &(opts->fw_config->chain[FIREWD_FORWARD_ACCESS]); + struct fw_chain * const dnat_chain = &(opts->fw_config->chain[FIREWD_DNAT_ACCESS]); struct fw_chain *snat_chain; /* We assign this later (if we need to). */ int res = 0, is_err, snat_chain_num = 0; @@ -1008,19 +1008,19 @@ process_spa_request(const fko_srv_options_t * const opts, /* Check to make sure that the jump rules exist for each * required chain */ - if(chain_exists(opts, IPT_INPUT_ACCESS) == 0) - create_chain(opts, IPT_INPUT_ACCESS); + if(chain_exists(opts, FIREWD_INPUT_ACCESS) == 0) + create_chain(opts, FIREWD_INPUT_ACCESS); - if(jump_rule_exists(opts, IPT_INPUT_ACCESS) == 0) - add_jump_rule(opts, IPT_INPUT_ACCESS); + if(jump_rule_exists(opts, FIREWD_INPUT_ACCESS) == 0) + add_jump_rule(opts, FIREWD_INPUT_ACCESS); if(strlen(out_chain->to_chain)) { - if(chain_exists(opts, IPT_OUTPUT_ACCESS) == 0) - create_chain(opts, IPT_OUTPUT_ACCESS); + if(chain_exists(opts, FIREWD_OUTPUT_ACCESS) == 0) + create_chain(opts, FIREWD_OUTPUT_ACCESS); - if(jump_rule_exists(opts, IPT_OUTPUT_ACCESS) == 0) - add_jump_rule(opts, IPT_OUTPUT_ACCESS); + if(jump_rule_exists(opts, FIREWD_OUTPUT_ACCESS) == 0) + add_jump_rule(opts, FIREWD_OUTPUT_ACCESS); } /* Create an access command for each proto/port for the source ip. @@ -1029,7 +1029,7 @@ process_spa_request(const fko_srv_options_t * const opts, { memset(rule_buf, 0, CMD_BUFSIZE); - snprintf(rule_buf, CMD_BUFSIZE-1, IPT_RULE_ARGS, + snprintf(rule_buf, CMD_BUFSIZE-1, FIREWD_RULE_ARGS, in_chain->table, ple->proto, spadat->use_src_ip, @@ -1065,7 +1065,7 @@ process_spa_request(const fko_srv_options_t * const opts, { memset(rule_buf, 0, CMD_BUFSIZE); - snprintf(rule_buf, CMD_BUFSIZE-1, IPT_OUT_RULE_ARGS, + snprintf(rule_buf, CMD_BUFSIZE-1, FIREWD_OUT_RULE_ARGS, out_chain->table, ple->proto, spadat->use_src_ip, @@ -1138,7 +1138,7 @@ process_spa_request(const fko_srv_options_t * const opts, { memset(rule_buf, 0, CMD_BUFSIZE); - snprintf(rule_buf, CMD_BUFSIZE-1, IPT_RULE_ARGS, + snprintf(rule_buf, CMD_BUFSIZE-1, FIREWD_RULE_ARGS, in_chain->table, fst_proto, spadat->use_src_ip, @@ -1150,11 +1150,11 @@ process_spa_request(const fko_srv_options_t * const opts, /* Check to make sure that the jump rules exist for each * required chain */ - if(chain_exists(opts, IPT_INPUT_ACCESS) == 0) - create_chain(opts, IPT_INPUT_ACCESS); + if(chain_exists(opts, FIREWD_INPUT_ACCESS) == 0) + create_chain(opts, FIREWD_INPUT_ACCESS); - if(jump_rule_exists(opts, IPT_INPUT_ACCESS) == 0) - add_jump_rule(opts, IPT_INPUT_ACCESS); + if(jump_rule_exists(opts, FIREWD_INPUT_ACCESS) == 0) + add_jump_rule(opts, FIREWD_INPUT_ACCESS); if(rule_exists(opts, in_chain, rule_buf, fst_proto, spadat->use_src_ip, nat_port, exp_ts) == 0) @@ -1181,15 +1181,15 @@ process_spa_request(const fko_srv_options_t * const opts, /* Make our FORWARD and NAT rules, and make sure the * required chain and jump rule exists */ - if(chain_exists(opts, IPT_FORWARD_ACCESS) == 0) - create_chain(opts, IPT_FORWARD_ACCESS); + if(chain_exists(opts, FIREWD_FORWARD_ACCESS) == 0) + create_chain(opts, FIREWD_FORWARD_ACCESS); - if (jump_rule_exists(opts, IPT_FORWARD_ACCESS) == 0) - add_jump_rule(opts, IPT_FORWARD_ACCESS); + if (jump_rule_exists(opts, FIREWD_FORWARD_ACCESS) == 0) + add_jump_rule(opts, FIREWD_FORWARD_ACCESS); memset(rule_buf, 0, CMD_BUFSIZE); - snprintf(rule_buf, CMD_BUFSIZE-1, IPT_FWD_RULE_ARGS, + snprintf(rule_buf, CMD_BUFSIZE-1, FIREWD_FWD_RULE_ARGS, fwd_chain->table, fst_proto, spadat->use_src_ip, @@ -1224,15 +1224,15 @@ process_spa_request(const fko_srv_options_t * const opts, { /* Make sure the required chain and jump rule exist */ - if(chain_exists(opts, IPT_DNAT_ACCESS) == 0) - create_chain(opts, IPT_DNAT_ACCESS); + if(chain_exists(opts, FIREWD_DNAT_ACCESS) == 0) + create_chain(opts, FIREWD_DNAT_ACCESS); - if (jump_rule_exists(opts, IPT_DNAT_ACCESS) == 0) - add_jump_rule(opts, IPT_DNAT_ACCESS); + if (jump_rule_exists(opts, FIREWD_DNAT_ACCESS) == 0) + add_jump_rule(opts, FIREWD_DNAT_ACCESS); memset(rule_buf, 0, CMD_BUFSIZE); - snprintf(rule_buf, CMD_BUFSIZE-1, IPT_DNAT_RULE_ARGS, + snprintf(rule_buf, CMD_BUFSIZE-1, FIREWD_DNAT_RULE_ARGS, dnat_chain->table, fst_proto, spadat->use_src_ip, @@ -1266,43 +1266,43 @@ process_spa_request(const fko_srv_options_t * const opts, /* If SNAT (or MASQUERADE) is wanted, then we add those rules here as well. */ - if(acc->force_snat || strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "Y", 1) == 0) + if(acc->force_snat || strncasecmp(opts->config[CONF_ENABLE_FIREWD_SNAT], "Y", 1) == 0) { /* Add SNAT or MASQUERADE rules. */ if(acc->force_snat && is_valid_ipv4_addr(acc->force_snat_ip)) { /* Using static SNAT */ - snat_chain = &(opts->fw_config->chain[IPT_SNAT_ACCESS]); + snat_chain = &(opts->fw_config->chain[FIREWD_SNAT_ACCESS]); snprintf(snat_target, SNAT_TARGET_BUFSIZE-1, "--to-source %s:%i", acc->force_snat_ip, fst_port); - snat_chain_num = IPT_SNAT_ACCESS; + snat_chain_num = FIREWD_SNAT_ACCESS; } else if(acc->force_snat && acc->force_masquerade) { /* Using MASQUERADE */ - snat_chain = &(opts->fw_config->chain[IPT_MASQUERADE_ACCESS]); + snat_chain = &(opts->fw_config->chain[FIREWD_MASQUERADE_ACCESS]); snprintf(snat_target, SNAT_TARGET_BUFSIZE-1, "--to-ports %i", fst_port); - snat_chain_num = IPT_MASQUERADE_ACCESS; + snat_chain_num = FIREWD_MASQUERADE_ACCESS; } else if((opts->config[CONF_SNAT_TRANSLATE_IP] != NULL) && is_valid_ipv4_addr(opts->config[CONF_SNAT_TRANSLATE_IP])) { /* Using static SNAT */ - snat_chain = &(opts->fw_config->chain[IPT_SNAT_ACCESS]); + snat_chain = &(opts->fw_config->chain[FIREWD_SNAT_ACCESS]); snprintf(snat_target, SNAT_TARGET_BUFSIZE-1, "--to-source %s:%i", opts->config[CONF_SNAT_TRANSLATE_IP], fst_port); - snat_chain_num = IPT_SNAT_ACCESS; + snat_chain_num = FIREWD_SNAT_ACCESS; } else { /* Using MASQUERADE */ - snat_chain = &(opts->fw_config->chain[IPT_MASQUERADE_ACCESS]); + snat_chain = &(opts->fw_config->chain[FIREWD_MASQUERADE_ACCESS]); snprintf(snat_target, SNAT_TARGET_BUFSIZE-1, "--to-ports %i", fst_port); - snat_chain_num = IPT_MASQUERADE_ACCESS; + snat_chain_num = FIREWD_MASQUERADE_ACCESS; } if(chain_exists(opts, snat_chain_num) == 0) @@ -1313,7 +1313,7 @@ process_spa_request(const fko_srv_options_t * const opts, memset(rule_buf, 0, CMD_BUFSIZE); - snprintf(rule_buf, CMD_BUFSIZE-1, IPT_SNAT_RULE_ARGS, + snprintf(rule_buf, CMD_BUFSIZE-1, FIREWD_SNAT_RULE_ARGS, snat_chain->table, fst_proto, nat_ip, @@ -1386,7 +1386,7 @@ check_firewall_rules(const fko_srv_options_t * const opts) /* There should be a rule to delete. Get the current list of * rules for this chain and delete the ones that are expired. */ - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS, + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_LIST_RULES_ARGS, opts->fw_config->fw_command, ch[i].table, ch[i].to_chain @@ -1478,7 +1478,7 @@ check_firewall_rules(const fko_srv_options_t * const opts) strlcpy(rule_num_str, rn_start, (rn_end - rn_start)+1); - rule_num = strtol_wrapper(rule_num_str, rn_offset, RCHK_MAX_IPT_RULE_NUM, + rule_num = strtol_wrapper(rule_num_str, rn_offset, RCHK_MAX_FIREWD_RULE_NUM, NO_EXIT_UPON_ERR, &is_err); if(is_err != FKO_SUCCESS) { @@ -1493,7 +1493,7 @@ check_firewall_rules(const fko_srv_options_t * const opts) zero_cmd_buffers(); - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS, + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " FIREWD_DEL_RULE_ARGS, opts->fw_config->fw_command, ch[i].table, ch[i].to_chain, diff --git a/server/fw_util_firewalld.h b/server/fw_util_firewalld.h index 21c91ff4..2fe789d2 100644 --- a/server/fw_util_firewalld.h +++ b/server/fw_util_firewalld.h @@ -55,7 +55,7 @@ #define FIREWD_LIST_RULES_ARGS "--direct --passthrough ipv4 -t %s -L %s --line-numbers -n 2>&1" #define FIREWD_LIST_ALL_RULES_ARGS "--direct --passthrough ipv4 -t %s -v -n -L --line-numbers 2>&1" -int validate_ipt_chain_conf(const char * const chain_str); +int validate_firewd_chain_conf(const char * const chain_str); #endif /* FW_UTIL_FIREWALLD_H */ diff --git a/server/fwknopd.conf b/server/fwknopd.conf index 1370b313..8faeebd6 100644 --- a/server/fwknopd.conf +++ b/server/fwknopd.conf @@ -196,6 +196,114 @@ #ENABLE_EXT_CMD_PREFIX N; #EXT_CMD_PREFIX FWKNOP_; +############################################################################## +# Parameters specific to firewalld: + +# Flush all existing rules in the fwknop chains at fwknop start time and/or +# exit time. They default to Y and it is a recommended setting for both. +# +#FLUSH_FIREWD_AT_INIT Y; +#FLUSH_FIREWD_AT_EXIT Y; +# + +# Allow SPA clients to request access to services through an firewalld +# firewall instead of just to it (i.e. access through the FWKNOP_FORWARD +# chain instead of the INPUT chain). +# +#ENABLE_FIREWD_FORWARDING N; + +# Allow SPA clients to request access to a local socket via NAT. This still +# puts an ACCEPT rule into the FWKNOP_INPUT chain, but a different port is +# translated via DNAT rules to the real one. So, the user would do +# "ssh -p " to access the local service (see the --NAT-local and +# --NAT-rand-port on the fwknop client command line). +# +#ENABLE_FIREWD_LOCAL_NAT Y; + +# By default, if forwarding access is enabled (see the ENABLE_FIREWD_FORWARDING +# variable above), then fwknop creates DNAT rules for incoming connections, +# but does not also complement these rules with SNAT rules at the same time. +# In some situations, internal systems may not have a route back out for the +# source address of the incoming connection, so it is necessary to also +# apply SNAT rules so that the internal systems see the IP of the internal +# interface where fwknopd is running. This functionality is only enabled +# when ENABLE_FIREWD_SNAT is set to "Y", and by default SNAT rules are built +# with the MASQUERADE target (since then the internal IP does not have to be +# defined here in the fwknop.conf file), but if you want fwknopd to use the +# SNAT target then also defined an IP address with the SNAT_TRANSLATE_IP +# variable. +# +#ENABLE_FIREWD_SNAT N; +#SNAT_TRANSLATE_IP __CHANGEME__; + +# Add ACCEPT rules to the FWKNOP_OUTPUT chain. This is usually only useful +# if there are no state tracking rules to allow connection responses out and +# the OUTPUT chain has a default-drop stance. +# +#ENABLE_FIREWD_OUTPUT N; + +# fwknopd adds allow rules to a custom firewalld chain "FWKNOP_INPUT". +# This chain is called from the INPUT chain, and by default no other +# firewalld chains are used. However, additional chains can be added +# (say, if access needs to be allowed through the local system via the +# FORWARD chain) by altering the FIREWD_FORWARD_ACCESS variable below. +# For a discussion of the format followed by these keywords, read on: +# +# Specify chain names to which firewalld blocking rules will be +# added with the FIREWD_INPUT_ACCESS and FIREWD_FORWARD_ACCESS keyword. +# The format for these variables is: +# +# ,,,,\ +# ,. +# +# "Target": +# Can be any legitimate firewalld target, but should usually just be "DROP". +# +# "Table": +# Can be any firewalld table, but the default is "filter". +# +# "From_chain": +# Is the chain from which packets will be jumped. +# +# "Jump_rule_position": +# Defines the position within the From_chain where the jump rule is added. +# +# "To_chain": +# Is the chain to which packets will be jumped. This is the main chain +# where fwknop rules are added. +# +# "Rule_position": +# Defines the position where rule are added within the To_chain. +# +#FIREWD_INPUT_ACCESS ACCEPT, filter, INPUT, 1, FWKNOP_INPUT, 1; + +# The FIREWD_OUTPUT_ACCESS variable is only used if ENABLE_FIREWD_OUTPUT is enabled +# +#FIREWD_OUTPUT_ACCESS ACCEPT, filter, OUTPUT, 1, FWKNOP_OUTPUT, 1; + +# The FIREWD_FORWARD_ACCESS variable is only used if ENABLE_FIREWD_FORWARDING is +# enabled. +# +#FIREWD_FORWARD_ACCESS ACCEPT, filter, FORWARD, 1, FWKNOP_FORWARD, 1; +#FIREWD_DNAT_ACCESS DNAT, nat, PREROUTING, 1, FWKNOP_PREROUTING, 1; + +# The FIREWD_SNAT_ACCESS variable is not used unless both ENABLE_FIREWD_SNAT and +# ENABLE_FIREWD_FORWARDING are enabled. Also, the external static IP must be +# set with the SNAT_TRANSLATE_IP variable. The default is to use the +# FIREWD_MASQUERADE_ACCESS variable. +# +#FIREWD_SNAT_ACCESS SNAT, nat, POSTROUTING, 1, FWKNOP_POSTROUTING, 1; +#FIREWD_MASQUERADE_ACCESS MASQUERADE, nat, POSTROUTING, 1, FWKNOP_POSTROUTING, 1; + +# The ENABLE_COMMENT_MATCH_CHECK variable instructs fwknopd to check for the +# firewalld 'comment' match at start up. If it's not found, then fwknopd will +# exit and throw an error. This variable is enabled by default, but can be +# disabled if you want fwknopd to run without being sure that the comment match +# if available (not recommended, since the comment match enables new SPA rules +# to be timed out). +# +#ENABLE_FIREWD_COMMENT_CHECK Y; + ############################################################################## # Parameters specific to iptables: @@ -372,6 +480,7 @@ # #PF_EXPIRE_INTERVAL 30; +############################################################################## # Directories - These can override compile-time defaults. # @@ -389,6 +498,7 @@ # System binaries # +#FIREWALL_EXE /bin/firewall-cmd; #FIREWALL_EXE /sbin/iptables; ###EOF### diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index 93990189..5622d36d 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -115,9 +115,29 @@ #define RCHK_MAX_PCAP_DISPATCH_COUNT (2 << 22) #define RCHK_MAX_FW_TIMEOUT (2 << 22) -/* FirewallD or Iptables-specific defines +/* FirewallD-specific defines */ -#if defined(FIREWALL_FIREWALLD) || defined(FIREWALL_IPTABLES) +#if FIREWALL_FIREWALLD + + #define DEF_FLUSH_FIREWD_AT_INIT "Y" + #define DEF_FLUSH_FIREWD_AT_EXIT "Y" + #define DEF_ENABLE_FIREWD_FORWARDING "N" + #define DEF_ENABLE_FIREWD_LOCAL_NAT "Y" + #define DEF_ENABLE_FIREWD_SNAT "N" + #define DEF_ENABLE_FIREWD_OUTPUT "N" + #define DEF_ENABLE_FIREWD_COMMENT_CHECK "Y" + #define DEF_FIREWD_INPUT_ACCESS "ACCEPT, filter, INPUT, 1, FWKNOP_INPUT, 1" + #define DEF_FIREWD_OUTPUT_ACCESS "ACCEPT, filter, OUTPUT, 1, FWKNOP_OUTPUT, 1" + #define DEF_FIREWD_FORWARD_ACCESS "ACCEPT, filter, FORWARD, 1, FWKNOP_FORWARD, 1" + #define DEF_FIREWD_DNAT_ACCESS "DNAT, nat, PREROUTING, 1, FWKNOP_PREROUTING, 1" + #define DEF_FIREWD_SNAT_ACCESS "SNAT, nat, POSTROUTING, 1, FWKNOP_POSTROUTING, 1" + #define DEF_FIREWD_MASQUERADE_ACCESS "MASQUERADE, nat, POSTROUTING, 1, FWKNOP_POSTROUTING, 1" + + #define RCHK_MAX_FIREWD_RULE_NUM (2 << 15) + +/* Iptables-specific defines +*/ +#elif FIREWALL_IPTABLES #define DEF_FLUSH_IPT_AT_INIT "Y" #define DEF_FLUSH_IPT_AT_EXIT "Y" @@ -215,7 +235,22 @@ enum { //CONF_EXTERNAL_CMD_ALARM, //CONF_ENABLE_EXT_CMD_PREFIX, //CONF_EXT_CMD_PREFIX, -#if defined(FIREWALL_FIREWALLD) || defined(FIREWALL_IPTABLES) +#if FIREWALL_FIREWALLD + CONF_ENABLE_FIREWD_FORWARDING, + CONF_ENABLE_FIREWD_LOCAL_NAT, + CONF_ENABLE_FIREWD_SNAT, + CONF_SNAT_TRANSLATE_IP, + CONF_ENABLE_FIREWD_OUTPUT, + CONF_FLUSH_FIREWD_AT_INIT, + CONF_FLUSH_FIREWD_AT_EXIT, + CONF_FIREWD_INPUT_ACCESS, + CONF_FIREWD_OUTPUT_ACCESS, + CONF_FIREWD_FORWARD_ACCESS, + CONF_FIREWD_DNAT_ACCESS, + CONF_FIREWD_SNAT_ACCESS, + CONF_FIREWD_MASQUERADE_ACCESS, + CONF_ENABLE_FIREWD_COMMENT_CHECK, +#elif FIREWALL_IPTABLES CONF_ENABLE_IPT_FORWARDING, CONF_ENABLE_IPT_LOCAL_NAT, CONF_ENABLE_IPT_SNAT, @@ -352,7 +387,54 @@ typedef struct acc_stanza /* Firewall-related data and types. */ -#if defined(FIREWALL_FIREWALLD) || defined(FIREWALL_IPTABLES) +#if FIREWALL_FIREWALLD + /* --DSS XXX: These are arbitrary. We should determine appropriate values. + */ + #define MAX_TABLE_NAME_LEN 64 + #define MAX_CHAIN_NAME_LEN 64 + #define MAX_TARGET_NAME_LEN 64 + + /* Fwknop custom chain types + */ + enum { + FIREWD_INPUT_ACCESS, + FIREWD_OUTPUT_ACCESS, + FIREWD_FORWARD_ACCESS, + FIREWD_DNAT_ACCESS, + FIREWD_SNAT_ACCESS, + FIREWD_MASQUERADE_ACCESS, + NUM_FWKNOP_ACCESS_TYPES /* Leave this entry last */ + }; + + /* Structure to define an fwknop firewall chain configuration. + */ + struct fw_chain { + int type; + char target[MAX_TARGET_NAME_LEN]; + //int direction; + char table[MAX_TABLE_NAME_LEN]; + char from_chain[MAX_CHAIN_NAME_LEN]; + int jump_rule_pos; + char to_chain[MAX_CHAIN_NAME_LEN]; + int rule_pos; + int active_rules; + time_t next_expire; + }; + + /* Based on the fw_chain fields (not counting type) + */ + #define FW_NUM_CHAIN_FIELDS 6 + + struct fw_config { + struct fw_chain chain[NUM_FWKNOP_ACCESS_TYPES]; + char fw_command[MAX_PATH_LEN]; + + /* Flag for firewalld SNAT vs. MASQUERADE usage + */ + unsigned char use_masquerade; + }; + +#elif FIREWALL_IPTABLES /* --DSS XXX: These are arbitrary. We should determine appropriate values. */ #define MAX_TABLE_NAME_LEN 64 @@ -484,6 +566,7 @@ typedef struct fko_srv_options unsigned char verbose; /* Verbose mode flag */ unsigned char exit_after_parse_config; /* Parse config and exit */ + unsigned char firewd_disable_check_support; /* Don't use firewall-cmd ... -C */ unsigned char ipt_disable_check_support; /* Don't use iptables -C */ /* Flag for permitting SPA packets regardless of directionality test diff --git a/server/incoming_spa.c b/server/incoming_spa.c index 9d55af73..bbea1b1f 100644 --- a/server/incoming_spa.c +++ b/server/incoming_spa.c @@ -815,7 +815,17 @@ incoming_spa(fko_srv_options_t *opts) || spadat.message_type == FKO_NAT_ACCESS_MSG || spadat.message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG) { -#if defined(FIREWALL_FIREWALLD) || defined(FIREWALL_IPTABLES) +#if FIREWALL_FIREWALLD + if(strncasecmp(opts->config[CONF_ENABLE_FIREWD_FORWARDING], "Y", 1)!=0) + { + log_msg(LOG_WARNING, + "(stanza #%d) SPA packet from %s requested NAT access, but is not enabled", + stanza_num, spadat.pkt_source_ip + ); + acc = acc->next; + continue; + } +#elif FIREWALL_IPTABLES if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1)!=0) { log_msg(LOG_WARNING, From 2da57da0cb3ec3fac6ec0f5de628d7c3eb2ea0cf Mon Sep 17 00:00:00 2001 From: Gerry Reno Date: Sun, 31 Aug 2014 16:13:46 -0400 Subject: [PATCH 09/12] more changes for firewalld --- server/fw_util_firewalld.c | 8 +++++++- server/fw_util_firewalld.h | 38 +++++++++++++++++++------------------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/server/fw_util_firewalld.c b/server/fw_util_firewalld.c index 3eae64a2..cdf6e4f8 100644 --- a/server/fw_util_firewalld.c +++ b/server/fw_util_firewalld.c @@ -793,9 +793,15 @@ fw_config_init(fko_srv_options_t * const opts) memset(&fwc, 0x0, sizeof(struct fw_config)); - /* Set our firewall exe command path (firewalld in most cases). + /* Set our firewall exe command path (firewall-cmd or iptables in most cases). */ +#if FIREWALL_FIREWALLD + char cmd_passthru[512]; + snprintf(cmd_passthru, sizeof cmd_passthru, "%s %s ", opts->config[CONF_FIREWALL_EXE], " --direct --passthrough ipv4 "); + strlcpy(fwc.fw_command, cmd_passthru, sizeof(fwc.fw_command)); +#else strlcpy(fwc.fw_command, opts->config[CONF_FIREWALL_EXE], sizeof(fwc.fw_command)); +#endif #if HAVE_LIBFIU fiu_return_on("fw_config_init", 0); diff --git a/server/fw_util_firewalld.h b/server/fw_util_firewalld.h index 2fe789d2..b27da5c5 100644 --- a/server/fw_util_firewalld.h +++ b/server/fw_util_firewalld.h @@ -35,25 +35,25 @@ /* firewalld command args */ -#define FIREWD_CHK_RULE_ARGS "--direct --passthrough ipv4 -C %s %s" /* 2>&1 is always added in the second %s */ -#define FIREWD_RULE_ARGS "--direct --passthrough ipv4 -t %s -p %i -s %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s 2>&1" -#define FIREWD_OUT_RULE_ARGS "--direct --passthrough ipv4 -t %s -p %i -d %s --sport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s 2>&1" -#define FIREWD_FWD_RULE_ARGS "--direct --passthrough ipv4 -t %s -p %i -s %s -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s 2>&1" -#define FIREWD_DNAT_RULE_ARGS "--direct --passthrough ipv4 -t %s -p %i -s %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s --to-destination %s:%i 2>&1" -#define FIREWD_SNAT_RULE_ARGS "--direct --passthrough ipv4 -t %s -p %i -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s %s 2>&1" -#define FIREWD_TMP_COMMENT_ARGS "--direct --passthrough ipv4 -t %s -I %s %i -s 127.0.0.2 -m comment --comment " TMP_COMMENT " -j %s 2>&1" -#define FIREWD_TMP_CHK_RULE_ARGS "--direct --passthrough ipv4 -t %s -I %s %i -s 127.0.0.2 -p udp -j %s 2>&1" -#define FIREWD_TMP_VERIFY_CHK_ARGS "--direct --passthrough ipv4 -t %s -C %s -s 127.0.0.2 -p udp -j %s 2>&1" -#define FIREWD_DEL_RULE_ARGS "--direct --passthrough ipv4 -t %s -D %s %i 2>&1" -#define FIREWD_NEW_CHAIN_ARGS "--direct --passthrough ipv4 -t %s -N %s 2>&1" -#define FIREWD_FLUSH_CHAIN_ARGS "--direct --passthrough ipv4 -t %s -F %s 2>&1" -#define FIREWD_CHAIN_EXISTS_ARGS "--direct --passthrough ipv4 -t %s -L %s -n 2>&1" -#define FIREWD_DEL_CHAIN_ARGS "--direct --passthrough ipv4 -t %s -X %s 2>&1" -#define FIREWD_CHK_JUMP_RULE_ARGS "--direct --passthrough ipv4 -t %s -j %s 2>&1" -#define FIREWD_ADD_JUMP_RULE_ARGS "--direct --passthrough ipv4 -t %s -I %s %i -j %s 2>&1" -#define FIREWD_DEL_JUMP_RULE_ARGS "--direct --passthrough ipv4 -t %s -D %s -j %s 2>&1" /* let firewalld work out the rule number */ -#define FIREWD_LIST_RULES_ARGS "--direct --passthrough ipv4 -t %s -L %s --line-numbers -n 2>&1" -#define FIREWD_LIST_ALL_RULES_ARGS "--direct --passthrough ipv4 -t %s -v -n -L --line-numbers 2>&1" +#define FIREWD_CHK_RULE_ARGS "-C %s %s" /* 2>&1 is always added in the second %s */ +#define FIREWD_RULE_ARGS "-t %s -p %i -s %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s 2>&1" +#define FIREWD_OUT_RULE_ARGS "-t %s -p %i -d %s --sport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s 2>&1" +#define FIREWD_FWD_RULE_ARGS "-t %s -p %i -s %s -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s 2>&1" +#define FIREWD_DNAT_RULE_ARGS "-t %s -p %i -s %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s --to-destination %s:%i 2>&1" +#define FIREWD_SNAT_RULE_ARGS "-t %s -p %i -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s %s 2>&1" +#define FIREWD_TMP_COMMENT_ARGS "-t %s -I %s %i -s 127.0.0.2 -m comment --comment " TMP_COMMENT " -j %s 2>&1" +#define FIREWD_TMP_CHK_RULE_ARGS "-t %s -I %s %i -s 127.0.0.2 -p udp -j %s 2>&1" +#define FIREWD_TMP_VERIFY_CHK_ARGS "-t %s -C %s -s 127.0.0.2 -p udp -j %s 2>&1" +#define FIREWD_DEL_RULE_ARGS "-t %s -D %s %i 2>&1" +#define FIREWD_NEW_CHAIN_ARGS "-t %s -N %s 2>&1" +#define FIREWD_FLUSH_CHAIN_ARGS "-t %s -F %s 2>&1" +#define FIREWD_CHAIN_EXISTS_ARGS "-t %s -L %s -n 2>&1" +#define FIREWD_DEL_CHAIN_ARGS "-t %s -X %s 2>&1" +#define FIREWD_CHK_JUMP_RULE_ARGS "-t %s -j %s 2>&1" +#define FIREWD_ADD_JUMP_RULE_ARGS "-t %s -I %s %i -j %s 2>&1" +#define FIREWD_DEL_JUMP_RULE_ARGS "-t %s -D %s -j %s 2>&1" /* let firewalld work out the rule number */ +#define FIREWD_LIST_RULES_ARGS "-t %s -L %s --line-numbers -n 2>&1" +#define FIREWD_LIST_ALL_RULES_ARGS "-t %s -v -n -L --line-numbers 2>&1" int validate_firewd_chain_conf(const char * const chain_str); From 4fe549c4512ddd21d86bdcea52041baa48aa1dda Mon Sep 17 00:00:00 2001 From: Gerry Reno Date: Sun, 31 Aug 2014 21:13:42 -0400 Subject: [PATCH 10/12] added feature: firewalld --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index f095480b..ea67305d 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,10 @@ the `INSTALL` file for the general basics on using autoconf. --with-ipf=/path/to/ipf Specify path to the ipf executable [default=check path] + Examples: + + ./configure --disable-client --with-firewalld=/bin/firewall-cmd + ./configure --disable-client --with-iptables=/sbin/iptables --with-firewalld=no ## Notes ### Migrating from the Perl version of fwknop From f7f97d3f3004ed553d418c95f9cefa6675bea338 Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Wed, 3 Sep 2014 23:15:34 -0400 Subject: [PATCH 11/12] [server] firewalld reports 'success' as a string upon command success in contrast to iptables --- server/fw_util_firewalld.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/server/fw_util_firewalld.c b/server/fw_util_firewalld.c index cdf6e4f8..4afd3102 100644 --- a/server/fw_util_firewalld.c +++ b/server/fw_util_firewalld.c @@ -161,15 +161,15 @@ rule_exists_chk_support(const fko_srv_options_t * const opts, log_msg(LOG_DEBUG, "rule_exists_chk_support() CMD: '%s' (res: %d, err: %s)", cmd_buf, res, err_buf); - if(EXTCMD_IS_SUCCESS(res) && strlen(err_buf)) + if(strncmp(err_buf, "success", strlen("success")) == 0) { - log_msg(LOG_DEBUG, "rule_exists_chk_support() Rule : '%s' in %s does not exist", + rule_exists = 1; + log_msg(LOG_DEBUG, "rule_exists_chk_support() Rule : '%s' in %s already exists", rule, chain); } else { - rule_exists = 1; - log_msg(LOG_DEBUG, "rule_exists_chk_support() Rule : '%s' in %s already exists", + log_msg(LOG_DEBUG, "rule_exists_chk_support() Rule : '%s' in %s does not exist", rule, chain); } @@ -242,16 +242,16 @@ firewd_chk_support(const fko_srv_options_t * const opts) log_msg(LOG_DEBUG, "firewd_chk_support() CMD: '%s' (res: %d, err: %s)", cmd_buf, res, err_buf); - if(EXTCMD_IS_SUCCESS(res) && strlen(err_buf)) - { - log_msg(LOG_DEBUG, "firewd_chk_support() -C not supported"); - have_firewd_chk_support = 0; - } - else + if(strncmp(err_buf, "success", strlen("success")) == 0) { log_msg(LOG_DEBUG, "firewd_chk_support() -C supported"); have_firewd_chk_support = 1; } + else + { + log_msg(LOG_DEBUG, "firewd_chk_support() -C not supported"); + have_firewd_chk_support = 0; + } /* Delete the tmp rule */ From aae72a947026d96a43fe854079e92b9a31ad8b36 Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Wed, 3 Sep 2014 23:28:51 -0400 Subject: [PATCH 12/12] firewalld support from Gerry Reno --- CREDITS | 3 +++ ChangeLog | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/CREDITS b/CREDITS index 2a9c586d..74687201 100644 --- a/CREDITS +++ b/CREDITS @@ -175,6 +175,9 @@ Gerry Reno - Provided guidance on Android client issues along with testing candidate patches to update various things - this work is being tracked in the android4.4_support branch. + - Implemented support for firewalld in the fwknopd daemon running on RHEL 7 + and CentOS 7 systems. This is a major addition to handle yet another + firewall architecture. Tim Heckman - Homebrew fwknop package maintainer for Mac OS X systems. diff --git a/ChangeLog b/ChangeLog index 4a4d0d5f..c486fb86 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,11 @@ fwknop-2.6.4 (09//2014): + - (Gerry Reno) Added support for firewalld to the fwknopd daemon on RHEL 7 + CentOS 7. This is implemented using the current firewalld '--direct + --passthrough' capability which accepts raw iptables commands. More + information on firewalld can be found here: + + https://fedoraproject.org/wiki/FirewallD + - (Bill Stubbs) submitted a patch to fix a bug where fwknopd could not handle Ethernet frames that include the Frame Check Sequence (FCS) header. This header is four bytes long, and is placed at the end of each