diff options
author | Ningyuan Wang <nywang@google.com> | 2016-03-31 10:53:42 -0700 |
---|---|---|
committer | Ningyuan Wang <nywang@google.com> | 2016-04-01 11:14:53 -0700 |
commit | 702e09977646efecbdc26eb348031a4ed583161a (patch) | |
tree | 406b6637ae78f5cb6a17882f29c79282eeb199f8 | |
parent | bb41434989fae91eb8e12e631786e23f8ce3bd89 (diff) | |
download | dhcp_client-nougat-mr1-wear-release.tar.gz |
dhcp client: create class SocketUtil to simplify class DHCPV4android-wear-n-preview-3android-wear-n-preview-2android-wear-n-preview-1android-wear-7.1.1_r1android-n-preview-5android-n-preview-4android-n-preview-3android-n-preview-2android-n-iot-preview-2nougat-mr1-wear-releasen-iot-preview-2
This takes part of the code for socket handling out of class
DHCPV4.
The new class SocketUtil is a helper class for creating
sockets and sending packet through socket.
while there, this also fixes a typo for broadcast address.
Bug: 25642025
TEST=compile, and test using python scripts
Change-Id: I5ae3018498bfbfa23f6e50c72c4845be808ba5c4
-rw-r--r-- | dhcp.h | 3 | ||||
-rw-r--r-- | dhcp_client.gyp | 1 | ||||
-rw-r--r-- | dhcpv4.cc | 179 | ||||
-rw-r--r-- | dhcpv4.h | 7 | ||||
-rw-r--r-- | socket_util.cc | 206 | ||||
-rw-r--r-- | socket_util.h | 60 |
6 files changed, 282 insertions, 174 deletions
@@ -42,6 +42,9 @@ class DHCP { REBOOT, RELEASE }; + // UDP port numbers for DHCP. + const static uint16_t kDHCPServerPort = 67; + const static uint16_t kDHCPClientPort = 68; }; } // namespace dhcp_client diff --git a/dhcp_client.gyp b/dhcp_client.gyp index 7ed15aa..48897e9 100644 --- a/dhcp_client.gyp +++ b/dhcp_client.gyp @@ -85,6 +85,7 @@ 'message_loop_event_dispatcher.cc', 'manager.cc', 'service.cc', + 'socket_util.cc', ], }, { @@ -17,11 +17,9 @@ #include "dhcp_client/dhcpv4.h" #include <arpa/inet.h> -#include <linux/filter.h> #include <linux/if_packet.h> #include <net/ethernet.h> #include <net/if.h> -#include <net/if_arp.h> #include <netinet/ip.h> #include <netinet/udp.h> @@ -36,6 +34,7 @@ #include "dhcp_client/dhcp_options.h" #include "dhcp_client/file_io.h" #include "dhcp_client/service_adaptor_interface.h" +#include "dhcp_client/socket_util.h" #include "shill/net/arp_packet.h" #include "shill/net/ip_address.h" @@ -47,9 +46,6 @@ using shill::IOHandlerFactoryContainer; namespace dhcp_client { namespace { -// UDP port numbers for DHCP. -const uint16_t kDHCPServerPort = 67; -const uint16_t kDHCPClientPort = 68; // Max length of a DHCP message. const size_t kDHCPMessageMaxLength = 548; // Renewal time in terms of lease duration percentage. @@ -76,22 +72,6 @@ const uint8_t kDefaultParameterRequestList[] = { const uint8_t kZeroHardwareAddress[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; const int kArpProbeReplyTimeoutSeconds = 1; -// Socket filter for dhcp packet. -const sock_filter dhcp_bpf_filter[] = { - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23 - ETH_HLEN), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6), - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20 - ETH_HLEN), - BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0), - BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14 - ETH_HLEN), - BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16 - ETH_HLEN), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, kDHCPClientPort, 0, 1), - BPF_STMT(BPF_RET + BPF_K, 0x0fffffff), - BPF_STMT(BPF_RET + BPF_K, 0), -}; - -const int dhcp_bpf_filter_len = - sizeof(dhcp_bpf_filter) / sizeof(dhcp_bpf_filter[0]); - // TODO(nywang): find a place for the lease file. const char kIPV4LeaseFilePathFormat[] = "/tmp/lease-ipv4-%s.conf"; @@ -142,6 +122,7 @@ DHCPV4::DHCPV4(ServiceAdaptorInterface* adaptor, raw_socket_(kInvalidSocketDescriptor), udp_socket_(kInvalidSocketDescriptor), sockets_(new shill::Sockets()), + socket_util_(new SocketUtil(interface_name_, interface_index_)), random_engine_(time(nullptr)) { ResetState(); } @@ -225,7 +206,7 @@ void DHCPV4::OnReadError(const std::string& error_msg) { } bool DHCPV4::Start() { - if (!CreateRawSocket()) { + if (!socket_util_->CreateRawSocket(&raw_socket_)) { return false; } input_handler_.reset(io_handler_factory_->CreateIOInputHandler( @@ -287,100 +268,6 @@ void DHCPV4::Stop() { arp_client_->Stop(); } -bool DHCPV4::CreateRawSocket() { - int fd = sockets_->Socket(PF_PACKET, - SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, - htons(ETHERTYPE_IP)); - if (fd == kInvalidSocketDescriptor) { - PLOG(ERROR) << "Failed to create socket"; - return false; - } - shill::ScopedSocketCloser socket_closer(sockets_.get(), fd); - - // Apply the socket filter. - sock_fprog pf; - memset(&pf, 0, sizeof(pf)); - pf.filter = const_cast<sock_filter*>(dhcp_bpf_filter); - pf.len = dhcp_bpf_filter_len; - - if (sockets_->AttachFilter(fd, &pf) != 0) { - PLOG(ERROR) << "Failed to attach filter"; - return false; - } - - if (sockets_->ReuseAddress(fd) == -1) { - PLOG(ERROR) << "Failed to reuse socket address"; - return false; - } - - if (sockets_->BindToDevice(fd, interface_name_) < 0) { - PLOG(ERROR) << "Failed to bind socket to device"; - return false; - } - - struct sockaddr_ll local; - memset(&local, 0, sizeof(local)); - local.sll_family = PF_PACKET; - local.sll_protocol = htons(ETHERTYPE_IP); - local.sll_ifindex = static_cast<int>(interface_index_); - - if (sockets_->Bind(fd, - reinterpret_cast<struct sockaddr*>(&local), - sizeof(local)) < 0) { - PLOG(ERROR) << "Failed to bind to address"; - return false; - } - - raw_socket_ = socket_closer.Release(); - return true; -} - -bool DHCPV4::CreateUdpSocket() { - // Close previous Udp Socket. - if (udp_socket_ != kInvalidSocketDescriptor) { - sockets_->Close(udp_socket_); - udp_socket_ = kInvalidSocketDescriptor; - } - - int fd = sockets_->Socket(PF_INET, - SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, - IPPROTO_IP); - if (fd == kInvalidSocketDescriptor) { - PLOG(ERROR) << "Failed to create socket"; - return false; - } - shill::ScopedSocketCloser socket_closer(sockets_.get(), fd); - - if (sockets_->ReuseAddress(fd) == -1) { - PLOG(ERROR) << "Failed to reuse socket address"; - return false; - } - - if (sockets_->BindToDevice(fd, interface_name_) < 0) { - PLOG(ERROR) << "Failed to bind socket to device"; - return false; - } - - struct sockaddr_in local; - memset(&local, 0, sizeof(local)); - local.sin_family = PF_INET; - // We do not receive packet from this socket. - // At this time the ip address may not be setup by shill yet. - // It is a safe choice to use INADDR_ANY. - local.sin_addr.s_addr = htonl(INADDR_ANY); - local.sin_port = htons(kDHCPClientPort); - - if (sockets_->Bind(fd, - reinterpret_cast<struct sockaddr*>(&local), - sizeof(local)) < 0) { - PLOG(ERROR) << "Failed to bind to address"; - return false; - } - - udp_socket_ = socket_closer.Release(); - return true; -} - void DHCPV4::HandleOffer(const DHCPMessage& msg) { LOG(INFO) << __func__; if (state_ != State::SELECT) { @@ -483,7 +370,7 @@ void DHCPV4::HandleAck(const DHCPMessage& msg) { // Set the option parameters. subnet_mask_ = msg.subnet_mask(); interface_mtu_ = msg.interface_mtu(); - broadcast_address = msg.broadcast_address(); + broadcast_address_ = msg.broadcast_address(); router_ = msg.router(); dns_server_ = msg.dns_server(); vendor_specific_info_ = msg.vendor_specific_info(); @@ -494,7 +381,7 @@ void DHCPV4::HandleAck(const DHCPMessage& msg) { } // Send the DHCP configuration to Shill. EmitEvent(kReasonBound); - CreateUdpSocket(); + socket_util_->CreateUdpSocket(&udp_socket_); } void DHCPV4::HandleNak(const DHCPMessage& msg) { @@ -551,7 +438,7 @@ bool DHCPV4::SendDiscover() { LOG(ERROR) << "Failed to serialize a DHCP discover message"; return false; } - if (!SendBroadcastPacket(packet)) { + if (!socket_util_->SendBroadcastPacket(raw_socket_, packet)) { LOG(ERROR) << "Failed to send a DHCP discover packet"; return false; } @@ -656,7 +543,7 @@ bool DHCPV4::SendRequest() { LOG(ERROR) << "Failed to make a DHCP request packet"; return false; } - if (!SendUnicastPacket(packet)) { + if (!socket_util_->SendUnicastPacket(udp_socket_, packet, server_ip_)) { LOG(ERROR) << "Failed to send a DHCP request packet"; return false; } @@ -666,7 +553,7 @@ bool DHCPV4::SendRequest() { LOG(ERROR) << "Failed to make a DHCP request raw packet"; return false; } - if (!SendBroadcastPacket(packet)) { + if (!socket_util_->SendBroadcastPacket(raw_socket_, packet)) { LOG(ERROR) << "Failed to send a DHCP request packet"; return false; } @@ -698,7 +585,7 @@ bool DHCPV4::SendRelease() { "there is no socket for unicast"; return false; } - if (!SendUnicastPacket(packet)) { + if (!socket_util_->SendUnicastPacket(udp_socket_, packet, server_ip_)) { LOG(ERROR) << "Failed to send a DHCP release packet"; return false; } @@ -780,53 +667,6 @@ bool DHCPV4::MakeRawPacket(const DHCPMessage& message, ByteString* output) { return true; } -bool DHCPV4::SendBroadcastPacket(const ByteString& packet) { - LOG(INFO) << __func__; - struct sockaddr_ll remote; - memset(&remote, 0, sizeof(remote)); - remote.sll_family = AF_PACKET; - remote.sll_protocol = htons(ETHERTYPE_IP); - remote.sll_ifindex = interface_index_; - remote.sll_hatype = htons(ARPHRD_ETHER); - // Use broadcast hardware address. - remote.sll_halen = IFHWADDRLEN; - memset(remote.sll_addr, 0xff, IFHWADDRLEN); - - size_t result = sockets_->SendTo(raw_socket_, - packet.GetConstData(), - packet.GetLength(), - 0, - reinterpret_cast<struct sockaddr *>(&remote), - sizeof(remote)); - - if (result != packet.GetLength()) { - PLOG(ERROR) << "Socket sento failed"; - return false; - } - return true; -} - -bool DHCPV4::SendUnicastPacket(const ByteString& packet) { - LOG(INFO) << __func__; - struct sockaddr_in remote; - memset(&remote, 0, sizeof(remote)); - remote.sin_family = AF_INET; - remote.sin_port = htons(kDHCPServerPort); - remote.sin_addr.s_addr = htonl(server_ip_); - - size_t result = sockets_->SendTo(udp_socket_, - packet.GetConstData(), - packet.GetLength(), - 0, - reinterpret_cast<struct sockaddr *>(&remote), - sizeof(remote)); - - if (result != packet.GetLength()) { - PLOG(ERROR) << "Socket sento failed"; - return false; - } - return true; -} bool DHCPV4::ValidateOptions(const DHCPMessage& msg) { uint32_t lease_time = msg.lease_time(); @@ -978,4 +818,3 @@ const std::string DHCPV4::IPtoString(uint32_t ip) { } } // namespace dhcp_client - @@ -36,6 +36,7 @@ namespace dhcp_client { class ServiceAdaptorInterface; +class SocketUtil; class DHCPV4 : public DHCP { public: @@ -58,8 +59,6 @@ class DHCPV4 : public DHCP { void ArpProbeReplyReceivedTask(int fd); void ArpProbeReplyTimeoutTask(); void CheckIpCollision(); - bool CreateRawSocket(); - bool CreateUdpSocket(); bool HasALease(); bool MakePacket(const DHCPMessage& message, shill::ByteString* buffer); bool MakeRawPacket(const DHCPMessage& message, shill::ByteString* buffer); @@ -70,8 +69,6 @@ class DHCPV4 : public DHCP { bool SendDiscover(); bool SendRequest(); bool SendRelease(); - bool SendBroadcastPacket(const shill::ByteString& buffer); - bool SendUnicastPacket(const shill::ByteString& buffer); // Validate the IP and UDP header and return the total headers length. // Return -1 if any header is invalid. int ValidatePacketHeader(const unsigned char* buffer, size_t len); @@ -157,6 +154,8 @@ class DHCPV4 : public DHCP { int udp_socket_; // Helper class with wrapped socket relavent functions. std::unique_ptr<shill::Sockets> sockets_; + // Helper class handling sockets for DHCP. + SocketUtil* socket_util_; std::default_random_engine random_engine_; diff --git a/socket_util.cc b/socket_util.cc new file mode 100644 index 0000000..d4fa1f0 --- /dev/null +++ b/socket_util.cc @@ -0,0 +1,206 @@ +// +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include "dhcp_client/socket_util.h" + +#include <linux/filter.h> +#include <linux/if_packet.h> +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_arp.h> + +#include <base/logging.h> + +#include "dhcp_client/dhcp.h" +#include "shill/net/byte_string.h" +#include "shill/net/sockets.h" + +namespace dhcp_client { + +namespace { + +// Socket filter for dhcp packet. +const sock_filter dhcp_bpf_filter[] = { + BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23 - ETH_HLEN), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6), + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20 - ETH_HLEN), + BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0), + BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14 - ETH_HLEN), + BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16 - ETH_HLEN), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP::kDHCPClientPort, 0, 1), + BPF_STMT(BPF_RET + BPF_K, 0x0fffffff), + BPF_STMT(BPF_RET + BPF_K, 0), +}; + +const int dhcp_bpf_filter_len = + sizeof(dhcp_bpf_filter) / sizeof(dhcp_bpf_filter[0]); + +} // namespace + +SocketUtil::SocketUtil(const std::string& interface_name, + unsigned int interface_index) + : sockets_(new shill::Sockets()), + interface_name_(interface_name), + interface_index_(interface_index) { +} + +SocketUtil::~SocketUtil() {} + +bool SocketUtil::CreateUdpSocket(int* udp_socket) { + // Close previous Udp Socket. + if (*udp_socket != shill::Sockets::kInvalidFileDescriptor) { + sockets_->Close(*udp_socket); + *udp_socket = shill::Sockets::kInvalidFileDescriptor; + } + int fd = sockets_->Socket(PF_INET, + SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, + IPPROTO_IP); + if (fd == shill::Sockets::kInvalidFileDescriptor) { + PLOG(ERROR) << "Failed to create socket"; + return false; + } + shill::ScopedSocketCloser socket_closer(sockets_, fd); + + if (sockets_->ReuseAddress(fd) == -1) { + PLOG(ERROR) << "Failed to reuse socket address"; + return false; + } + + if (sockets_->BindToDevice(fd, interface_name_) < 0) { + PLOG(ERROR) << "Failed to bind socket to device"; + return false; + } + + struct sockaddr_in local; + memset(&local, 0, sizeof(local)); + local.sin_family = PF_INET; + // We do not receive packet from this socket. + // At this time the ip address may not be setup by shill yet. + // It is a safe choice to use INADDR_ANY. + local.sin_addr.s_addr = htonl(INADDR_ANY); + local.sin_port = htons(DHCP::kDHCPServerPort); + + if (sockets_->Bind(fd, + reinterpret_cast<struct sockaddr*>(&local), + sizeof(local)) < 0) { + PLOG(ERROR) << "Failed to bind to address"; + return false; + } + + *udp_socket = socket_closer.Release(); + return true; +} + +bool SocketUtil::CreateRawSocket(int* raw_socket) { + int fd = sockets_->Socket(PF_PACKET, + SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, + htons(ETHERTYPE_IP)); + if (fd == shill::Sockets::kInvalidFileDescriptor) { + PLOG(ERROR) << "Failed to create socket"; + return false; + } + shill::ScopedSocketCloser socket_closer(sockets_, fd); + + // Apply the socket filter. + sock_fprog pf; + memset(&pf, 0, sizeof(pf)); + pf.filter = const_cast<sock_filter*>(dhcp_bpf_filter); + pf.len = dhcp_bpf_filter_len; + + if (sockets_->AttachFilter(fd, &pf) != 0) { + PLOG(ERROR) << "Failed to attach filter"; + return false; + } + + if (sockets_->ReuseAddress(fd) == -1) { + PLOG(ERROR) << "Failed to reuse socket address"; + return false; + } + + if (sockets_->BindToDevice(fd, interface_name_) < 0) { + PLOG(ERROR) << "Failed to bind socket to device"; + return false; + } + + struct sockaddr_ll local; + memset(&local, 0, sizeof(local)); + local.sll_family = PF_PACKET; + local.sll_protocol = htons(ETHERTYPE_IP); + local.sll_ifindex = static_cast<int>(interface_index_); + + if (sockets_->Bind(fd, + reinterpret_cast<struct sockaddr*>(&local), + sizeof(local)) < 0) { + PLOG(ERROR) << "Failed to bind to address"; + return false; + } + + *raw_socket = socket_closer.Release(); + return true; +} + +bool SocketUtil::SendBroadcastPacket(int raw_socket, + const shill::ByteString& packet) { + LOG(INFO) << __func__; + struct sockaddr_ll remote; + memset(&remote, 0, sizeof(remote)); + remote.sll_family = AF_PACKET; + remote.sll_protocol = htons(ETHERTYPE_IP); + remote.sll_ifindex = interface_index_; + remote.sll_hatype = htons(ARPHRD_ETHER); + // Use broadcast hardware address. + remote.sll_halen = IFHWADDRLEN; + memset(remote.sll_addr, 0xff, IFHWADDRLEN); + + size_t result = sockets_->SendTo(raw_socket, + packet.GetConstData(), + packet.GetLength(), + 0, + reinterpret_cast<struct sockaddr *>(&remote), + sizeof(remote)); + + if (result != packet.GetLength()) { + PLOG(ERROR) << "Socket sento failed"; + return false; + } + return true; +} + +bool SocketUtil::SendUnicastPacket(int udp_socket, + const shill::ByteString& packet, + uint32_t server_ip) { + LOG(INFO) << __func__; + struct sockaddr_in remote; + memset(&remote, 0, sizeof(remote)); + remote.sin_family = AF_INET; + remote.sin_port = htons(DHCP::kDHCPServerPort); + remote.sin_addr.s_addr = htonl(server_ip); + + size_t result = sockets_->SendTo(udp_socket, + packet.GetConstData(), + packet.GetLength(), + 0, + reinterpret_cast<struct sockaddr *>(&remote), + sizeof(remote)); + + if (result != packet.GetLength()) { + PLOG(ERROR) << "Socket sento failed"; + return false; + } + return true; +} + +} // namespace dhcp_client diff --git a/socket_util.h b/socket_util.h new file mode 100644 index 0000000..64e4528 --- /dev/null +++ b/socket_util.h @@ -0,0 +1,60 @@ +// +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef DHCP_CLIENT_SOCKET_UTIL_H_ +#define DHCP_CLIENT_SOCKET_UTIL_H_ + +#include <string> + +#include <base/macros.h> + +namespace shill { + +class ByteString; +class Sockets; + +} // namespace shill + +namespace dhcp_client { + +class SocketUtil { + public: + SocketUtil(const std::string& interface_name, + unsigned int interface_index); + virtual ~SocketUtil(); + // Create a raw socket and configure it with a UDP socket filter. + bool CreateRawSocket(int* raw_socket); + // Create a udp socket. + bool CreateUdpSocket(int* udp_socket); + // Send broadcast packet using a given raw socekt. + bool SendBroadcastPacket(int raw_socket, + const shill::ByteString& buffer); + // Send unicast packet using a given udp socekt. + bool SendUnicastPacket(int udp_socket, + const shill::ByteString& buffer, + uint32_t server_ip); + private: + // Helper class with wrapped socket relavent functions. + shill::Sockets* sockets_; + std::string interface_name_; + unsigned int interface_index_; + + DISALLOW_COPY_AND_ASSIGN(SocketUtil); +}; + +} // namespace dhcp_client + +#endif // DHCP_CLIENT_SOCKET_UTIL_H_ |