Load iptables rules from systemd unit file, not from nether program 63/104863/6
authorRafal Krypa <r.krypa@samsung.com>
Wed, 28 Dec 2016 10:42:29 +0000 (11:42 +0100)
committerRafal Krypa <r.krypa@samsung.com>
Fri, 26 May 2017 12:09:00 +0000 (14:09 +0200)
Drop nether support for loading iptables rules. Such rules should ideally be
managed from a central place that implements multiple requirements, not only
nether. It is not right for nether to be the manager of iptables policy.

For now nether daemon will stop managing the rules, they will be loaded from
systemd unit files. It is already done for ip6tables rules, as nether never
handled ip6tables for IPv6, only iptables for IPv4.

Change-Id: Icb0cf1f42b54e0859c182a6a4baac42e85294388

README.md
conf/nether_ipv6.rules
conf/systemd/nether.service.in
include/nether_Manager.h
include/nether_Types.h
packaging/nether.spec
src/CMakeLists.txt
src/nether_Main.cpp
src/nether_Manager.cpp

index f0ec5761a3005a4c98a31f5a08486f5176b3a1d3..979fefaac6b9093a045f6bfd1dee9d6144fdbf4c 100644 (file)
--- a/README.md
+++ b/README.md
@@ -16,7 +16,6 @@ backend stops working.
 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)
@@ -34,8 +33,6 @@ Usage: nether [OPTIONS]
   -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
 ```
 
@@ -57,8 +54,6 @@ Usage: nether [OPTIONS]
 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
@@ -81,10 +76,6 @@ There is just one argument that is the path to the location of the policy file.
 
 -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.
index 185d746ceb30ca8518840b23414d24aa67d6b0cd..5976193ab95569a557213defd2e86fd37754104a 100644 (file)
@@ -16,7 +16,7 @@
 #  limitations under the License
 #
 
-# nether iptables rules
+# nether ip6tables rules
 *mangle
 :PREROUTING ACCEPT
 :INPUT ACCEPT
index a3b776b9136b4854417b4c73e773d07665f527e0..ac99fb4a2724c757ef2a973681131df5898bacb7 100644 (file)
@@ -21,16 +21,18 @@ Description=nether service
 
 [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
index 23e7557f059725d375f5fbb526ade402d4a77f64..9ba67ab3dd9e7db6e03db44ccf8b6af8d3a343e7 100644 (file)
@@ -41,10 +41,8 @@ class NetherManager : public NetherVerdictListener, public NetherProcessedPacket
                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);
index 07c6edf9cc70396837d929a6c6a94a0698c3d167..7a85bb82418b346b8c73413ab7254422e74a36d5 100644 (file)
 
 #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
 {
@@ -183,13 +178,10 @@ struct NetherConfig
        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;
 };
index f24bb3628d27dcfa0406572f340fc02d32eb9c83..252cd1ca3ce6763e9517964dc27ba88699462c78 100755 (executable)
@@ -16,7 +16,7 @@ This is a network privilege enforcing service.
 %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
index 76620925a352dea487e4a5a7a811edc2e08ba5cf..3056da1362b37c83646ac2db7b338ec199ddcea7 100644 (file)
@@ -80,7 +80,6 @@ TARGET_LINK_LIBRARIES (nether
        "-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)
index 7a815ed4664228506b01c21cb30fbf48bd54e496..203d0d8d5a41292efcbd3729fc98e90192baeb27 100644 (file)
@@ -42,7 +42,6 @@ int main(int argc, char *argv[])
                {"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},
@@ -56,8 +55,6 @@ int main(int argc, char *argv[])
                {"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}
        };
@@ -78,10 +75,6 @@ int main(int argc, char *argv[])
                                netherConfig.daemonMode             = 1;
                                break;
 
-                       case 'x':
-                               netherConfig.noRules                = 1;
-                               break;
-
                        case 'c':
                                netherConfig.copyPackets                        = 1;
                                break;
@@ -154,14 +147,6 @@ int main(int argc, char *argv[])
                                netherConfig.markAllowAndLog        = atoi(optarg);
                                break;
 
-                       case 'r':
-                               netherConfig.rulesPath              = optarg;
-                               break;
-
-                       case 'i':
-                               netherConfig.iptablesRestorePath    = optarg;
-                               break;
-
                        case 'h':
                                showHelp(argv[0]);
                                exit(1);
@@ -203,12 +188,9 @@ int main(int argc, char *argv[])
                 << " 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);
@@ -246,7 +228,6 @@ void showHelp(char *arg)
 {
        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";
@@ -275,8 +256,6 @@ void showHelp(char *arg)
 #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";
 }
 
index efe109466fb37797cbb5c4c45899113ac97e8dd7..1b0725cea148ee7b719d7c4e18b7512c46b9d8fb 100644 (file)
@@ -113,14 +113,6 @@ bool NetherManager::initialize()
                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()");
@@ -321,44 +313,3 @@ void NetherManager::packetReceived(const NetherPacket &packet)
        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);
-}