Chromium Code Reviews| Index: chromeos/network/firewall_hole.cc |
| diff --git a/chromeos/network/firewall_hole.cc b/chromeos/network/firewall_hole.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..2f49d71e2e7ae5b05cd8b26df56ea149940b9a88 |
| --- /dev/null |
| +++ b/chromeos/network/firewall_hole.cc |
| @@ -0,0 +1,176 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chromeos/network/firewall_hole.h" |
| + |
| +#include <fcntl.h> |
| +#include <unistd.h> |
| + |
| +#include "base/bind.h" |
| +#include "base/location.h" |
| +#include "base/threading/worker_pool.h" |
| +#include "chromeos/dbus/dbus_thread_manager.h" |
| +#include "chromeos/dbus/permission_broker_client.h" |
| +#include "dbus/file_descriptor.h" |
| + |
| +namespace chromeos { |
| + |
| +namespace { |
| + |
| +// Creates a pair of file descriptors that form a "lifeline" between Chrome and |
| +// firewalld. If this pipe is closed unexpectedly (i.e. Chrome crashes) then |
| +// firewalld will notice and close the hole in the firewall. |
| +void CreateValidLifeline(dbus::FileDescriptor* lifeline_local, |
| + dbus::FileDescriptor* lifeline_remote) { |
| + int lifeline[2] = {-1, -1}; |
| + if (pipe2(lifeline, O_CLOEXEC) < 0) { |
| + PLOG(ERROR) << "Failed to create a lifeline pipe"; |
| + return; |
| + } |
| + |
| + lifeline_local->PutValue(lifeline[0]); |
| + lifeline_local->CheckValidity(); |
| + |
| + lifeline_remote->PutValue(lifeline[1]); |
| + lifeline_remote->CheckValidity(); |
| +} |
| + |
| +const char* PortTypeToString(FirewallHole::PortType type) { |
| + switch (type) { |
| + case FirewallHole::PortType::TCP: |
| + return "TCP"; |
| + case FirewallHole::PortType::UDP: |
| + return "UDP"; |
| + } |
| + NOTREACHED(); |
| + return nullptr; |
| +} |
| + |
| +void PortReleased(FirewallHole::PortType type, |
| + uint16_t port, |
| + const std::string& interface, |
| + FirewallHole::ScopedFileDescriptor lifeline_fd, |
| + bool success) { |
| + if (!success) { |
| + LOG(WARNING) << "Failed to release firewall hole for " |
| + << PortTypeToString(type) << " port " << port << " on " |
| + << interface << "."; |
| + } |
| +} |
| + |
| +} // namespace |
| + |
| +void CHROMEOS_EXPORT FirewallHole::FileDescriptorDeleter::operator()( |
| + dbus::FileDescriptor* fd) { |
| + base::WorkerPool::PostTask( |
| + FROM_HERE, base::Bind(&base::DeletePointer<dbus::FileDescriptor>, fd), |
| + false); |
| +} |
| + |
| +// static |
| +void FirewallHole::Open(PortType type, |
| + uint16_t port, |
| + const std::string& interface, |
| + const OpenCallback& callback) { |
| + ScopedFileDescriptor lifeline_local(new dbus::FileDescriptor()); |
| + ScopedFileDescriptor lifeline_remote(new dbus::FileDescriptor()); |
| + |
| + // This closure shares pointers with the one below. PostTaskAndReply |
| + // guarantees that it will always be deleted first. |
| + base::Closure create_lifeline_closure = base::Bind( |
| + &CreateValidLifeline, lifeline_local.get(), lifeline_remote.get()); |
| + |
| + base::WorkerPool::PostTaskAndReply( |
| + FROM_HERE, create_lifeline_closure, |
| + base::Bind(&FirewallHole::RequestPortAccess, type, port, interface, |
| + base::Passed(&lifeline_local), base::Passed(&lifeline_remote), |
| + callback), |
| + false); |
| +} |
| + |
| +FirewallHole::~FirewallHole() { |
| + base::Callback<void(bool)> port_released_closure = base::Bind( |
| + &PortReleased, type_, port_, interface_, base::Passed(&lifeline_fd_)); |
| + |
| + PermissionBrokerClient* client = |
| + DBusThreadManager::Get()->GetPermissionBrokerClient(); |
| + DCHECK(client) << "Could not get permission broker client."; |
| + if (client) { |
| + switch (type_) { |
| + case PortType::TCP: |
| + client->ReleaseTcpPort(port_, interface_, port_released_closure); |
| + return; |
| + case PortType::UDP: |
| + client->ReleaseUdpPort(port_, interface_, port_released_closure); |
| + return; |
| + } |
| + } |
| + |
| + NOTREACHED(); |
|
pneubeck (no reviews)
2015/03/10 08:49:21
this is equivalent to the DCHECK above.
and DCHECK
Reilly Grant (use Gerrit)
2015/03/10 20:15:16
Done.
|
| + port_released_closure.Run(false); |
| +} |
| + |
| +void FirewallHole::RequestPortAccess(PortType type, |
| + uint16_t port, |
| + const std::string& interface, |
| + ScopedFileDescriptor lifeline_local, |
| + ScopedFileDescriptor lifeline_remote, |
| + const OpenCallback& callback) { |
| + if (!lifeline_local->is_valid() || !lifeline_remote->is_valid()) { |
| + callback.Run(nullptr); |
| + return; |
| + } |
| + |
| + base::Callback<void(bool)> access_granted_closure = |
| + base::Bind(&FirewallHole::PortAccessGranted, type, port, interface, |
| + base::Passed(&lifeline_local), callback); |
| + |
| + PermissionBrokerClient* client = |
| + DBusThreadManager::Get()->GetPermissionBrokerClient(); |
| + DCHECK(client) << "Could not get permission broker client."; |
| + if (!client) { |
|
pneubeck (no reviews)
2015/03/10 08:49:21
same as above. DCHECKs should not be handled.
Plea
Reilly Grant (use Gerrit)
2015/03/10 20:15:16
Done.
|
| + callback.Run(nullptr); |
| + return; |
| + } |
| + |
| + switch (type) { |
| + case PortType::TCP: |
| + client->RequestTcpPortAccess(port, interface, *lifeline_remote, |
| + access_granted_closure); |
| + return; |
| + case PortType::UDP: |
| + client->RequestUdpPortAccess(port, interface, *lifeline_remote, |
| + access_granted_closure); |
| + return; |
| + } |
| + |
| + NOTREACHED(); |
| + callback.Run(nullptr); |
|
pneubeck (no reviews)
2015/03/10 08:49:21
NOTREACHED = DCHECK should not be handled.
Remove
Reilly Grant (use Gerrit)
2015/03/10 20:15:16
Done.
|
| +} |
| + |
| +void FirewallHole::PortAccessGranted(PortType type, |
| + uint16_t port, |
| + const std::string& interface, |
| + ScopedFileDescriptor lifeline_fd, |
| + const FirewallHole::OpenCallback& callback, |
| + bool success) { |
| + if (success) { |
| + callback.Run(make_scoped_ptr( |
| + new FirewallHole(type, port, interface, lifeline_fd.Pass()))); |
| + } else { |
| + callback.Run(nullptr); |
| + } |
| +} |
| + |
| +FirewallHole::FirewallHole(PortType type, |
| + uint16_t port, |
| + const std::string& interface, |
| + ScopedFileDescriptor lifeline_fd) |
| + : type_(type), |
| + port_(port), |
| + interface_(interface), |
| + lifeline_fd_(lifeline_fd.Pass()) { |
| +} |
| + |
| +} // namespace chromeos |