Usage: nether [OPTIONS]
-d,--daemon Run as daemon in the background (default:no)
- -x,--no-rules Don't load iptables rules on start (default:no)
-c,--copy-packets Copy entire packets, needed to read TCP/IP information (default:no)
-I,--interface-info Get interface info for every packet (default:no)
-R,--relaxed Run in relaxed mode, instrad of deny do ACCEPT_LOG(default:no)
-m,--mark-deny=<mark> Packet mark to use for DENY verdicts (default:3)
-M,--mark-allow-log=<mark> Packet mark to use for ALLOW_LOG verdicts (default:4)
-a,--enable-audit Enable the auditing subsystem (default: no)
- -r,--rules-path=<path> Path to iptables rules file (default:/etc/nether/nether.rules)
- -i,--iptables-restore-path=<path> Path to iptables-restore command (default:/usr/sbin/iptables-restore)
-h,--help show help information
```
There is just one argument that is the path to the location of the policy file.
## Details:
--x - by default nether loads iptables rules needed for nethet to catch packets it should make descisions about, the default set of rules can be found in CMAKE_INSTALL_PREFIX/etc/nether/nether.rules. Default rules catch first packets of each TCP/IP connection and ignore all traffic on the loopback interface. If you wish to change the default set of rules, edit this file. Or set the rules on your own and start nether with this option
-
-c - by default nether does not receive the entire network packet, it's not needed to get the meta information about a packet (UID/GID and the security context of each packet). But if you policy backend needs more information about the network specifc part of a packet, setting this option will provide TCP/IP information to the backend (destination and source interface if available, destination and source IP address, destination and source PORT if the protocol is TCP/UDP). This option is used to gain more performance if the policy backend does not require network information.
-I - same as -c but for network interface information
-a - if audit headers are available, nether will activate auditing on start
--r - the path to the default set of rules nether should apply on start, by default this is set to ${CMAKE_INSTALL_DIR}/etc/nether/nether.rules
-
--i - the path to the iptables-restore program, it's needed to set the initial nether rules. No api is provided by netfilter to set the rules. iptables-restore is a preferred way to restore rules in the system.
-
## Poking holes in cynara policy:
In order to exclude some traffic from the cynara policy, you can define custom privileges and paths they should take inside iptables. This is done by specifying a custom cynara.policy file with privilege|mark pairs. If a defined privilege gets a ALLOW response the packet that was beeing matched gets marked with the defined mark. Using the initial nether.rules you can add custom rules for those matched packets and do whatever you want with them.
# limitations under the License
#
-# nether iptables rules
+# nether ip6tables rules
*mangle
:PREROUTING ACCEPT
:INPUT ACCEPT
[Service]
Type=simple
-ExecStart=${CMAKE_INSTALL_PREFIX}/bin/nether -l JOURNAL -P policy=${SYSCONF_INSTALL_DIR}/nether/cynara.policy -B ${SYSCONF_INSTALL_DIR}/nether/file.policy -r ${SYSCONF_INSTALL_DIR}/nether/nether.rules
-ExecStartPost=${SBIN_INSTALL_DIR}/ip6tables-restore ${SYSCONF_INSTALL_DIR}/nether/nether_ipv6.rules
+ExecStartPre=${SBIN_INSTALL_DIR}/iptables-restore ${SYSCONF_INSTALL_DIR}/nether/nether.rules
+ExecStartPre=${SBIN_INSTALL_DIR}/ip6tables-restore ${SYSCONF_INSTALL_DIR}/nether/nether_ipv6.rules
+ExecStart=${CMAKE_INSTALL_PREFIX}/bin/nether -l JOURNAL -P policy=${SYSCONF_INSTALL_DIR}/nether/cynara.policy -B ${SYSCONF_INSTALL_DIR}/nether/file.policy
Restart=always
ExecReload=/bin/kill -HUP $MAINPID
User=security_fw
Group=security_fw
SecureBits=keep-caps
-Capabilities=cap_net_admin,cap_net_raw=eip
-CapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN
+Capabilities=cap_net_admin=i
+CapabilityBoundingSet=CAP_NET_ADMIN
SmackProcessLabel=System
+PermissionsStartOnly=true
[Install]
WantedBy=multi-user.target
static NetherPolicyBackend *getPolicyBackend(const NetherConfig &netherConfig, const bool primary = true);
bool verdictCast(const u_int32_t packetId, const NetherVerdict verdict, int mark);
void packetReceived(const NetherPacket &packet);
- bool restoreRules();
private:
- static bool isCommandAvailable(const std::string &command);
void handleSignal();
bool handleNetlinkpacket();
void setupSelectSockets(fd_set &watchedReadDescriptorsSet, fd_set &watchedWriteDescriptorsSet, struct timeval &timeoutSpecification);
#define NETLINK_INTERFACE_INFO 0
-#ifndef NETHER_RULES_PATH
-#define NETHER_RULES_PATH "/etc/nether/nether.rules"
-#endif // NETHER_RULES_PATH
-
#ifndef NETHER_POLICY_FILE
#define NETHER_POLICY_FILE "/etc/nether/file.policy"
#endif // NETHER_POLICY_FILE
#define NETLINK_ALLOWLOG_MARK 4
#define NETLINK_QUEUE_NUM 0
#define NETHER_LOG_BACKEND NetherLogBackendType::stderrBackend
-#define NETHER_IPTABLES_RESTORE_PATH "/usr/sbin/iptables-restore"
enum class NetherPolicyBackendType : std::uint8_t
{
int daemonMode = 0;
int queueNumber = NETLINK_QUEUE_NUM;
int enableAudit = 0;
- int noRules = 0;
int copyPackets = NETLINK_COPY_PACKETS;
int relaxed = 0;
int interfaceInfo = NETLINK_INTERFACE_INFO;
std::string backupBackendArgs = NETHER_POLICY_FILE;
- std::string rulesPath = NETHER_RULES_PATH;
- std::string iptablesRestorePath = NETHER_IPTABLES_RESTORE_PATH;
std::string primaryBackendArgs;
std::string logBackendArgs;
};
%files
%license LICENSE
%defattr(644,root,root,755)
-%caps(cap_net_admin,cap_net_raw=ei) %attr(755,root,root) %{_bindir}/nether
+%caps(cap_net_admin=ei) %attr(755,root,root) %{_bindir}/nether
%dir %{_sysconfdir}/nether
%config %{_sysconfdir}/nether/file.policy
%config %{_sysconfdir}/nether/nether.rules
"-pie"
)
-ADD_DEFINITIONS (-DNETHER_RULES_PATH="${CMAKE_INSTALL_DIR}/etc/nether/nether.rules"
- -DNETHER_POLICY_FILE="${CMAKE_INSTALL_DIR}/etc/nether/file.policy")
+ADD_DEFINITIONS (-DNETHER_POLICY_FILE="${CMAKE_INSTALL_DIR}/etc/nether/file.policy")
INSTALL (TARGETS nether RUNTIME DESTINATION bin)
{"enable-audit", no_argument, &netherConfig.enableAudit, 0},
#endif
{"daemon", no_argument, &netherConfig.daemonMode, 0},
- {"no-rules", no_argument, &netherConfig.noRules, 0},
{"copy-packets", no_argument, &netherConfig.copyPackets, 0},
{"interface-info", no_argument, &netherConfig.interfaceInfo, 0},
{"relaxed", no_argument, &netherConfig.relaxed, 0},
{"queue-num", required_argument, 0, 'q'},
{"mark-deny", required_argument, 0, 'm'},
{"mark-allow-log", required_argument, 0, 'M'},
- {"rules-path", required_argument, 0, 'r'},
- {"iptables-restore-path", required_argument, 0, 'i'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
netherConfig.daemonMode = 1;
break;
- case 'x':
- netherConfig.noRules = 1;
- break;
-
case 'c':
netherConfig.copyPackets = 1;
break;
netherConfig.markAllowAndLog = atoi(optarg);
break;
- case 'r':
- netherConfig.rulesPath = optarg;
- break;
-
- case 'i':
- netherConfig.iptablesRestorePath = optarg;
- break;
-
case 'h':
showHelp(argv[0]);
exit(1);
<< " mark-allow-log=" << (int)netherConfig.markAllowAndLog);
LOGD("log-backend=" << logBackendTypeToString(netherConfig.logBackend)
<< " log-backend-args=" << netherConfig.logBackendArgs);
- LOGD("enable-audit=" << (netherConfig.enableAudit ? "yes" : "no")
- << " rules-path=" << netherConfig.rulesPath);
- LOGD("no-rules=" << (netherConfig.noRules ? "yes" : "no")
- << " iptables-restore-path=" << netherConfig.iptablesRestorePath);
- LOGD("interface-info=" << (netherConfig.interfaceInfo ? "yes" : "no")
- << " copy-packets=" << (netherConfig.copyPackets ? "yes" : "no"));
+ LOGD("enable-audit=" << (netherConfig.enableAudit ? "yes" : "no"));
+ LOGD("interface-info=" << (netherConfig.interfaceInfo ? "yes" : "no"));
+ LOGD("copy-packets=" << (netherConfig.copyPackets ? "yes" : "no"));
LOGD("relaxed=" << (netherConfig.relaxed ? "yes" : "no"));
NetherManager manager(netherConfig);
{
cout<< "Usage:\t"<< arg << " [OPTIONS]\n\n";
cout<< " -d,--daemon\t\t\t\tRun as daemon in the background (default:no)\n";
- cout<< " -x,--no-rules\t\t\t\tDon't load iptables rules on start (default:no)\n";
cout<< " -c,--copy-packets\t\t\tCopy entire packets, needed to read TCP/IP information (default:no)\n";
cout<< " -I,--interface-info\t\t\tGet interface info for every packet (default:no)\n";
cout<< " -R,--relaxed\t\t\t\tRun in relaxed mode, instead of deny do ACCEPT_LOG(default:no)\n";
#if defined(HAVE_AUDIT)
cout<< " -a,--enable-audit\t\t\tEnable the auditing subsystem (default: no)\n";
#endif
- cout<< " -r,--rules-path=<path>\t\tPath to iptables rules file (default:" << NETHER_RULES_PATH << ")\n";
- cout<< " -i,--iptables-restore-path=<path>\tPath to iptables-restore command (default:" << NETHER_IPTABLES_RESTORE_PATH << ")\n";
cout<< " -h,--help\t\t\t\tshow help information\n";
}
return (false);
}
- /* Load the rules as last, in case we have a problem with any
- above subsystems, we won't leave hanging useless rules */
- if(netherConfig.noRules == 0 && restoreRules() == false)
- {
- LOGE("Failed to setup iptables rules");
- return (false);
- }
-
if((backendDescriptor = netherPrimaryPolicyBackend->getDescriptor()) == -1)
{
LOGI("Policy backend does not provide descriptor for select()");
LOGW("All policy backends failed, using DUMMY backend");
netherFallbackPolicyBackend->enqueueVerdict(packet);
}
-
-bool NetherManager::restoreRules()
-{
- if(!isCommandAvailable(netherConfig.iptablesRestorePath))
- {
- return (false);
- }
-
- std::stringstream cmdline;
- cmdline << netherConfig.iptablesRestorePath;
- cmdline << " ";
- cmdline << netherConfig.rulesPath;
-
- if(system(cmdline.str().c_str()))
- {
- LOGE("system() failed for: " << cmdline.str());
- return (false);
- }
-
- LOGD("iptables-restore succeeded with rules from: " << netherConfig.rulesPath);
- return (true);
-}
-
-bool NetherManager::isCommandAvailable(const std::string &command)
-{
- struct stat iptablesRestoreStat;
-
- if(stat(command.c_str(), &iptablesRestoreStat) == 0)
- {
- if(! (iptablesRestoreStat.st_mode & S_IXUSR))
- {
- LOGE("Execute bit is not set for owner on:" << command);
- return (false);
- }
-
- return (true);
- }
-
- LOGE("Failed to stat command at: " << command << " error: " << strerror(errno));
- return (false);
-}