2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
4 * Contact: Roman Kubiak (r.kubiak@samsung.com)
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License
21 * @author Roman Kubiak (r.kubiak@samsung.com)
22 * @brief Manager class implementation for nether
25 #include "nether_Manager.h"
26 #include "nether_CynaraBackend.h"
27 #include "nether_FileBackend.h"
28 #include "nether_DummyBackend.h"
30 NetherManager::NetherManager(const NetherConfig &_netherConfig)
31 : netherPrimaryPolicyBackend(nullptr),
32 netherBackupPolicyBackend(nullptr),
33 netherFallbackPolicyBackend(nullptr),
34 netherConfig(_netherConfig)
36 netherNetlink = std::unique_ptr<NetherNetlink> (new NetherNetlink(netherConfig));
37 netherNetlink->setListener(this);
39 netherPrimaryPolicyBackend = std::unique_ptr<NetherPolicyBackend> (getPolicyBackend(netherConfig));
40 netherPrimaryPolicyBackend->setListener(this);
42 netherBackupPolicyBackend = std::unique_ptr<NetherPolicyBackend> (getPolicyBackend(netherConfig, false));
43 netherBackupPolicyBackend->setListener(this);
45 netherFallbackPolicyBackend = std::unique_ptr<NetherPolicyBackend> (new NetherDummyBackend(netherConfig));
48 NetherManager::~NetherManager()
50 close(signalDescriptor);
53 bool NetherManager::initialize()
55 sigemptyset(&signalMask);
56 sigaddset(&signalMask, SIGHUP);
58 if(sigprocmask(SIG_BLOCK, &signalMask, NULL) == -1)
60 LOGE("Failed to block signals sigprocmask()");
64 signalDescriptor = signalfd(-1, &signalMask, 0);
65 if(signalDescriptor == -1)
67 LOGE("Failed acquire signalfd descriptor");
72 if(netherConfig.enableAudit)
74 if((auditDescriptor = audit_open()) == -1)
76 LOGE("Failed to open an audit netlink socket: " << strerror(errno));
80 if(audit_set_enabled(auditDescriptor, 1) <= 0)
82 LOGE("Failed to enable auditing: " << strerror(errno));
87 LOGD("Auditing enabled");
92 if(!netherNetlink->initialize())
94 LOGE("Failed to initialize netlink subsystem, exiting");
98 if(!netherPrimaryPolicyBackend->initialize())
100 LOGE("Failed to initialize primary policy backend, exiting");
104 if(!netherBackupPolicyBackend->initialize())
106 LOGE("Failed to initialize backup backend, exiting");
110 if((netlinkDescriptor = netherNetlink->getDescriptor()) == -1)
112 LOGE("Netlink subsystem did not return a valid descriptor, exiting");
116 /* Load the rules as last, in case we have a problem with any
117 above subsystems, we won't leave hanging useless rules */
118 if(netherConfig.noRules == 0 && restoreRules() == false)
120 LOGE("Failed to setup iptables rules");
124 if((backendDescriptor = netherPrimaryPolicyBackend->getDescriptor()) == -1)
126 LOGI("Policy backend does not provide descriptor for select()");
132 bool NetherManager::process()
134 fd_set watchedReadDescriptorsSet, watchedWriteDescriptorsSet;
135 struct timeval timeoutSpecification;
139 setupSelectSockets(watchedReadDescriptorsSet, watchedWriteDescriptorsSet, timeoutSpecification);
141 if(select(FD_SETSIZE, &watchedReadDescriptorsSet, &watchedWriteDescriptorsSet, NULL, &timeoutSpecification) < 0)
143 LOGE("select error " << strerror(errno));
147 if(FD_ISSET(signalDescriptor, &watchedReadDescriptorsSet))
151 if(FD_ISSET(netlinkDescriptor, &watchedReadDescriptorsSet))
153 if(!handleNetlinkpacket())
157 if(FD_ISSET(backendDescriptor, &watchedReadDescriptorsSet) || FD_ISSET(backendDescriptor, &watchedWriteDescriptorsSet))
159 netherPrimaryPolicyBackend->processEvents();
163 LOGD("select() timeout");
170 void NetherManager::handleSignal()
172 LOGD("received signal");
174 struct signalfd_siginfo signalfdSignalInfo;
176 signalRead = read(signalDescriptor, &signalfdSignalInfo, sizeof(struct signalfd_siginfo));
178 if(signalRead != sizeof(struct signalfd_siginfo))
180 LOGW("Received incomplete signal information, ignore");
184 if(signalfdSignalInfo.ssi_signo == SIGHUP)
186 LOGI("SIGHUP received, reloading");
187 if(!netherPrimaryPolicyBackend->reload())
188 LOGW("primary backend failed to reload");
189 if(!netherBackupPolicyBackend->reload())
190 LOGW("backup backend failed to reload");
191 if(!netherNetlink->reload())
192 LOGW("netlink failed to reload");
196 bool NetherManager::handleNetlinkpacket()
198 LOGD("netlink descriptor active");
200 NetherPacket receivedPacket;
201 char packetBuffer[NETHER_PACKET_BUFFER_SIZE] __attribute__((aligned));
203 /* some data arrives on netlink, read it */
204 if((packetReadSize = recv(netlinkDescriptor, packetBuffer, sizeof(packetBuffer), 0)) >= 0)
206 /* try to process the packet using netfilter_queue library, fetch packet info
207 needed for making a decision about it */
208 if(netherNetlink->processPacket(packetBuffer, packetReadSize))
214 /* if we can't process the incoming packets, it's bad. Let's exit now */
215 LOGE("Failed to process netlink received packet, refusing to continue");
220 if(packetReadSize < 0 && errno == ENOBUFS)
222 LOGI("NetherManager::process losing packets! [bad things might happen]");
226 LOGE("NetherManager::process recv failed " << strerror(errno));
230 void NetherManager::setupSelectSockets(fd_set &watchedReadDescriptorsSet, fd_set &watchedWriteDescriptorsSet, struct timeval &timeoutSpecification)
232 FD_ZERO(&watchedReadDescriptorsSet);
233 FD_ZERO(&watchedWriteDescriptorsSet);
235 /* Always listen for signals */
236 FD_SET(signalDescriptor, &watchedReadDescriptorsSet);
238 if((netlinkDescriptor = netherNetlink->getDescriptor()) >= 0)
240 FD_SET(netlinkDescriptor, &watchedReadDescriptorsSet);
243 if((backendDescriptor = netherPrimaryPolicyBackend->getDescriptor()) >= 0)
245 if(netherPrimaryPolicyBackend->getDescriptorStatus() == NetherDescriptorStatus::readOnly)
247 FD_SET(backendDescriptor, &watchedReadDescriptorsSet);
250 if(netherPrimaryPolicyBackend->getDescriptorStatus() == NetherDescriptorStatus::readWrite)
252 FD_SET(backendDescriptor, &watchedReadDescriptorsSet);
253 FD_SET(backendDescriptor, &watchedWriteDescriptorsSet);
257 timeoutSpecification.tv_sec = 240;
258 timeoutSpecification.tv_usec = 0;
261 NetherConfig &NetherManager::getConfig()
263 return (netherConfig);
266 NetherPolicyBackend *NetherManager::getPolicyBackend(const NetherConfig &netherConfig, const bool primary)
268 switch(primary ? netherConfig.primaryBackendType : netherConfig.backupBackendType)
270 case NetherPolicyBackendType::cynaraBackend:
272 return new NetherCynaraBackend(netherConfig);
274 return new NetherDummyBackend(netherConfig);
276 case NetherPolicyBackendType::fileBackend:
277 return new NetherFileBackend(netherConfig);
278 case NetherPolicyBackendType::dummyBackend:
280 return new NetherDummyBackend(netherConfig);
284 bool NetherManager::verdictCast(const u_int32_t packetId, const NetherVerdict verdict, int mark)
288 netherNetlink->setVerdict(packetId, verdict, mark);
292 LOGE("Netlink subsystem is invalid, can't decide on packet");
299 void NetherManager::packetReceived(const NetherPacket &packet)
301 LOGD(packetToString(packet).c_str());
303 if(netherPrimaryPolicyBackend && netherPrimaryPolicyBackend->enqueueVerdict(packet))
305 LOGD("Primary policy accepted packet");
309 if(netherBackupPolicyBackend && netherBackupPolicyBackend->enqueueVerdict(packet))
311 LOGI("Primary policy backend failed, using backup policy backend");
315 /* In this situation no policy backend wants to deal with this packet
316 there propably isn't any rule in either of them
318 we need to make a generic decision based on whatever is hard-coded
319 or passed as a parameter to the service */
320 LOGW("All policy backends failed, using DUMMY backend");
321 netherFallbackPolicyBackend->enqueueVerdict(packet);
324 bool NetherManager::restoreRules()
326 if(!isCommandAvailable(netherConfig.iptablesRestorePath))
331 std::stringstream cmdline;
332 cmdline << netherConfig.iptablesRestorePath;
334 cmdline << netherConfig.rulesPath;
336 if(system(cmdline.str().c_str()))
338 LOGE("system() failed for: " << cmdline.str());
342 LOGD("iptables-restore succeeded with rules from: " << netherConfig.rulesPath);
346 bool NetherManager::isCommandAvailable(const std::string &command)
348 struct stat iptablesRestoreStat;
350 if(stat(command.c_str(), &iptablesRestoreStat) == 0)
352 if(! iptablesRestoreStat.st_mode & S_IXUSR)
354 LOGE("Execute bit is not set for owner on:" << command);
361 LOGE("Failed to stat command at: " << command << " error: " << strerror(errno));