iptables.cc revision 5affd8895f6879153fce488c3f92271349eeadc9
1// Copyright 2014 The Chromium OS Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "firewalld/iptables.h" 6 7#include <string> 8#include <vector> 9 10#include <base/logging.h> 11#include <base/strings/stringprintf.h> 12#include <chromeos/process.h> 13 14namespace { 15const char kIptablesPath[] = "/sbin/iptables"; 16} 17 18namespace firewalld { 19 20IpTables::IpTables() : IpTables{kIptablesPath} {} 21 22IpTables::IpTables(const std::string& path) : executable_path_{path} {} 23 24IpTables::~IpTables() { 25 // Plug all holes when destructed. 26 PlugAllHoles(); 27} 28 29bool IpTables::PunchTcpHole(uint16_t in_port) { 30 return PunchHole(in_port, &tcp_holes_, kProtocolTcp); 31} 32 33bool IpTables::PunchUdpHole(uint16_t in_port) { 34 return PunchHole(in_port, &udp_holes_, kProtocolUdp); 35} 36 37bool IpTables::PlugTcpHole(uint16_t in_port) { 38 return PlugHole(in_port, &tcp_holes_, kProtocolTcp); 39} 40 41bool IpTables::PlugUdpHole(uint16_t in_port) { 42 return PlugHole(in_port, &udp_holes_, kProtocolUdp); 43} 44 45bool IpTables::PunchHole(uint16_t port, 46 std::unordered_set<uint16_t>* holes, 47 enum ProtocolEnum protocol) { 48 if (port == 0) { 49 // Port 0 is not a valid TCP/UDP port. 50 return false; 51 } 52 53 if (holes->find(port) != holes->end()) { 54 // We have already punched a hole for |port|. 55 // Be idempotent: do nothing and succeed. 56 return true; 57 } 58 59 std::string sprotocol = protocol == kProtocolTcp ? "TCP" : "UDP"; 60 LOG(INFO) << "Punching hole for " << sprotocol << " port " << port; 61 if (!IpTables::AddAllowRule(protocol, port)) { 62 // If the 'iptables' command fails, this method fails. 63 LOG(ERROR) << "Calling 'iptables' failed"; 64 return false; 65 } 66 67 // Track the hole we just punched. 68 holes->insert(port); 69 70 return true; 71} 72 73bool IpTables::PlugHole(uint16_t port, 74 std::unordered_set<uint16_t>* holes, 75 enum ProtocolEnum protocol) { 76 if (port == 0) { 77 // Port 0 is not a valid TCP/UDP port. 78 return false; 79 } 80 81 if (holes->find(port) == holes->end()) { 82 // There is no firewall hole for |port|. 83 // Even though this makes |PlugHole| not idempotent, 84 // and Punch/Plug not entirely symmetrical, fail. It might help catch bugs. 85 return false; 86 } 87 88 std::string sprotocol = protocol == kProtocolTcp ? "TCP" : "UDP"; 89 LOG(INFO) << "Plugging hole for " << sprotocol << " port " << port; 90 if (!IpTables::DeleteAllowRule(protocol, port)) { 91 // If the 'iptables' command fails, this method fails. 92 LOG(ERROR) << "Calling 'iptables' failed"; 93 return false; 94 } 95 96 // Stop tracking the hole we just plugged. 97 holes->erase(port); 98 99 return true; 100} 101 102void IpTables::PlugAllHoles() { 103 // Copy the container so that we can remove elements from the original. 104 // TCP 105 std::unordered_set<uint16_t> holes = tcp_holes_; 106 for (auto port : holes) { 107 PlugHole(port, &tcp_holes_, kProtocolTcp); 108 } 109 110 // UDP 111 holes = udp_holes_; 112 for (auto port : holes) { 113 PlugHole(port, &udp_holes_, kProtocolUdp); 114 } 115 116 CHECK(tcp_holes_.size() == 0) << "Failed to plug all TCP holes."; 117 CHECK(udp_holes_.size() == 0) << "Failed to plug all UDP holes."; 118} 119 120bool IpTables::AddAllowRule(enum ProtocolEnum protocol, 121 uint16_t port) { 122 chromeos::ProcessImpl iptables; 123 iptables.AddArg(executable_path_); 124 iptables.AddArg("-A"); // append 125 iptables.AddArg("INPUT"); 126 iptables.AddArg("-p"); // protocol 127 iptables.AddArg(protocol == kProtocolTcp ? "tcp" : "udp"); 128 iptables.AddArg("--dport"); // destination port 129 std::string port_number = base::StringPrintf("%d", port); 130 iptables.AddArg(port_number.c_str()); 131 iptables.AddArg("-j"); 132 iptables.AddArg("ACCEPT"); 133 134 return iptables.Run() == 0; 135} 136 137bool IpTables::DeleteAllowRule(enum ProtocolEnum protocol, 138 uint16_t port) { 139 chromeos::ProcessImpl iptables; 140 iptables.AddArg(executable_path_); 141 iptables.AddArg("-D"); // delete 142 iptables.AddArg("INPUT"); 143 iptables.AddArg("-p"); // protocol 144 iptables.AddArg(protocol == kProtocolTcp ? "tcp" : "udp"); 145 iptables.AddArg("--dport"); // destination port 146 std::string port_number = base::StringPrintf("%d", port); 147 iptables.AddArg(port_number.c_str()); 148 iptables.AddArg("-j"); 149 iptables.AddArg("ACCEPT"); 150 151 return iptables.Run() == 0; 152} 153 154} // namespace firewalld 155