OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium 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 "chromeos/network/firewall_hole.h" |
| 6 |
| 7 #include <fcntl.h> |
| 8 #include <unistd.h> |
| 9 |
| 10 #include "base/bind.h" |
| 11 #include "base/location.h" |
| 12 #include "base/threading/worker_pool.h" |
| 13 #include "chromeos/dbus/dbus_thread_manager.h" |
| 14 #include "chromeos/dbus/permission_broker_client.h" |
| 15 #include "dbus/file_descriptor.h" |
| 16 |
| 17 namespace chromeos { |
| 18 |
| 19 namespace { |
| 20 |
| 21 // Creates a pair of file descriptors that form a "lifeline" between Chrome and |
| 22 // firewalld. If this pipe is closed unexpectedly (i.e. Chrome crashes) then |
| 23 // firewalld will notice and close the hole in the firewall. |
| 24 void CreateValidLifeline(dbus::FileDescriptor* lifeline_local, |
| 25 dbus::FileDescriptor* lifeline_remote) { |
| 26 int lifeline[2] = {-1, -1}; |
| 27 if (pipe2(lifeline, O_CLOEXEC) < 0) { |
| 28 PLOG(ERROR) << "Failed to create a lifeline pipe"; |
| 29 return; |
| 30 } |
| 31 |
| 32 lifeline_local->PutValue(lifeline[0]); |
| 33 lifeline_local->CheckValidity(); |
| 34 |
| 35 lifeline_remote->PutValue(lifeline[1]); |
| 36 lifeline_remote->CheckValidity(); |
| 37 } |
| 38 |
| 39 const char* PortTypeToString(FirewallHole::PortType type) { |
| 40 switch (type) { |
| 41 case FirewallHole::PortType::TCP: |
| 42 return "TCP"; |
| 43 case FirewallHole::PortType::UDP: |
| 44 return "UDP"; |
| 45 } |
| 46 NOTREACHED(); |
| 47 return nullptr; |
| 48 } |
| 49 |
| 50 void PortReleased(FirewallHole::PortType type, |
| 51 uint16_t port, |
| 52 const std::string& interface, |
| 53 FirewallHole::ScopedFileDescriptor lifeline_fd, |
| 54 bool success) { |
| 55 if (!success) { |
| 56 LOG(WARNING) << "Failed to release firewall hole for " |
| 57 << PortTypeToString(type) << " port " << port << " on " |
| 58 << interface << "."; |
| 59 } |
| 60 } |
| 61 |
| 62 } // namespace |
| 63 |
| 64 void CHROMEOS_EXPORT FirewallHole::FileDescriptorDeleter::operator()( |
| 65 dbus::FileDescriptor* fd) { |
| 66 base::WorkerPool::PostTask( |
| 67 FROM_HERE, base::Bind(&base::DeletePointer<dbus::FileDescriptor>, fd), |
| 68 false); |
| 69 } |
| 70 |
| 71 // static |
| 72 void FirewallHole::Open(PortType type, |
| 73 uint16_t port, |
| 74 const std::string& interface, |
| 75 const OpenCallback& callback) { |
| 76 ScopedFileDescriptor lifeline_local(new dbus::FileDescriptor()); |
| 77 ScopedFileDescriptor lifeline_remote(new dbus::FileDescriptor()); |
| 78 |
| 79 // This closure shares pointers with the one below. PostTaskAndReply |
| 80 // guarantees that it will always be deleted first. |
| 81 base::Closure create_lifeline_closure = base::Bind( |
| 82 &CreateValidLifeline, lifeline_local.get(), lifeline_remote.get()); |
| 83 |
| 84 base::WorkerPool::PostTaskAndReply( |
| 85 FROM_HERE, create_lifeline_closure, |
| 86 base::Bind(&FirewallHole::RequestPortAccess, type, port, interface, |
| 87 base::Passed(&lifeline_local), base::Passed(&lifeline_remote), |
| 88 callback), |
| 89 false); |
| 90 } |
| 91 |
| 92 FirewallHole::~FirewallHole() { |
| 93 base::Callback<void(bool)> port_released_closure = base::Bind( |
| 94 &PortReleased, type_, port_, interface_, base::Passed(&lifeline_fd_)); |
| 95 |
| 96 PermissionBrokerClient* client = |
| 97 DBusThreadManager::Get()->GetPermissionBrokerClient(); |
| 98 DCHECK(client) << "Could not get permission broker client."; |
| 99 switch (type_) { |
| 100 case PortType::TCP: |
| 101 client->ReleaseTcpPort(port_, interface_, port_released_closure); |
| 102 return; |
| 103 case PortType::UDP: |
| 104 client->ReleaseUdpPort(port_, interface_, port_released_closure); |
| 105 return; |
| 106 } |
| 107 } |
| 108 |
| 109 void FirewallHole::RequestPortAccess(PortType type, |
| 110 uint16_t port, |
| 111 const std::string& interface, |
| 112 ScopedFileDescriptor lifeline_local, |
| 113 ScopedFileDescriptor lifeline_remote, |
| 114 const OpenCallback& callback) { |
| 115 if (!lifeline_local->is_valid() || !lifeline_remote->is_valid()) { |
| 116 callback.Run(nullptr); |
| 117 return; |
| 118 } |
| 119 |
| 120 base::Callback<void(bool)> access_granted_closure = |
| 121 base::Bind(&FirewallHole::PortAccessGranted, type, port, interface, |
| 122 base::Passed(&lifeline_local), callback); |
| 123 |
| 124 PermissionBrokerClient* client = |
| 125 DBusThreadManager::Get()->GetPermissionBrokerClient(); |
| 126 DCHECK(client) << "Could not get permission broker client."; |
| 127 |
| 128 switch (type) { |
| 129 case PortType::TCP: |
| 130 client->RequestTcpPortAccess(port, interface, *lifeline_remote, |
| 131 access_granted_closure); |
| 132 return; |
| 133 case PortType::UDP: |
| 134 client->RequestUdpPortAccess(port, interface, *lifeline_remote, |
| 135 access_granted_closure); |
| 136 return; |
| 137 } |
| 138 } |
| 139 |
| 140 void FirewallHole::PortAccessGranted(PortType type, |
| 141 uint16_t port, |
| 142 const std::string& interface, |
| 143 ScopedFileDescriptor lifeline_fd, |
| 144 const FirewallHole::OpenCallback& callback, |
| 145 bool success) { |
| 146 if (success) { |
| 147 callback.Run(make_scoped_ptr( |
| 148 new FirewallHole(type, port, interface, lifeline_fd.Pass()))); |
| 149 } else { |
| 150 callback.Run(nullptr); |
| 151 } |
| 152 } |
| 153 |
| 154 FirewallHole::FirewallHole(PortType type, |
| 155 uint16_t port, |
| 156 const std::string& interface, |
| 157 ScopedFileDescriptor lifeline_fd) |
| 158 : type_(type), |
| 159 port_(port), |
| 160 interface_(interface), |
| 161 lifeline_fd_(lifeline_fd.Pass()) { |
| 162 } |
| 163 |
| 164 } // namespace chromeos |
OLD | NEW |