iptables.cc revision 8620868c44d58dc0632df3a7be7c48be1eb2421b
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
24bool IpTables::PunchHole(chromeos::ErrorPtr* error,
25                                uint16_t in_port,
26                                bool* out_success) {
27  *out_success = false;
28
29  if (in_port == 0) {
30    // Port 0 is not a valid TCP/UDP port.
31    *out_success = false;
32    return true;
33  }
34
35  if (tcp_holes_.find(in_port) != tcp_holes_.end()) {
36    // We have already punched a hole for |in_port|.
37    // Be idempotent: do nothing and succeed.
38    *out_success = true;
39    return true;
40  }
41
42  LOG(INFO) << "Punching hole for port " << in_port;
43  if (!IpTables::AddAllowRule(executable_path_, in_port)) {
44    // If the 'iptables' command fails, this method fails.
45    LOG(ERROR) << "Calling 'iptables' failed";
46    *out_success = false;
47    return true;
48  }
49
50  // Track the hole we just punched.
51  tcp_holes_.insert(in_port);
52
53  *out_success = true;
54  return true;
55}
56
57bool IpTables::PlugHole(chromeos::ErrorPtr* error,
58                               uint16_t in_port,
59                               bool* out_success) {
60  *out_success = false;
61
62  if (in_port == 0) {
63    // Port 0 is not a valid TCP/UDP port.
64    *out_success = false;
65    return true;
66  }
67
68  if (tcp_holes_.find(in_port) == tcp_holes_.end()) {
69    // There is no firewall hole for |in_port|.
70    // Even though this makes |PlugHole| not idempotent,
71    // and Punch/Plug not entirely symmetrical, fail. It might help catch bugs.
72    *out_success = false;
73    return true;
74  }
75
76  LOG(INFO) << "Plugging hole for port " << in_port;
77  if (!IpTables::DeleteAllowRule(executable_path_, in_port)) {
78    // If the 'iptables' command fails, this method fails.
79    LOG(ERROR) << "Calling 'iptables' failed";
80    *out_success = false;
81    return true;
82  }
83
84  // Stop tracking the hole we just plugged.
85  tcp_holes_.erase(in_port);
86
87  *out_success = true;
88  return true;
89}
90
91// static
92bool IpTables::AddAllowRule(const std::string& path, uint16_t port) {
93  chromeos::ProcessImpl iptables;
94  iptables.AddArg(path);
95  iptables.AddArg("-A");  // append
96  iptables.AddArg("INPUT");
97  iptables.AddArg("-p");  // protocol
98  iptables.AddArg("tcp");
99  iptables.AddArg("--dport");  // destination port
100  std::string port_number = base::StringPrintf("%d", port);
101  iptables.AddArg(port_number.c_str());
102  iptables.AddArg("-j");
103  iptables.AddArg("ACCEPT");
104
105  return iptables.Run() == 0;
106}
107
108// static
109bool IpTables::DeleteAllowRule(const std::string& path, uint16_t port) {
110  chromeos::ProcessImpl iptables;
111  iptables.AddArg(path);
112  iptables.AddArg("-D");  // delete
113  iptables.AddArg("INPUT");
114  iptables.AddArg("-p");  // protocol
115  iptables.AddArg("tcp");
116  iptables.AddArg("--dport");  // destination port
117  std::string port_number = base::StringPrintf("%d", port);
118  iptables.AddArg(port_number.c_str());
119  iptables.AddArg("-j");
120  iptables.AddArg("ACCEPT");
121
122  return iptables.Run() == 0;
123}
124
125}  // namespace firewalld
126