blob: 956d76d14e413442aae919c1f009a87712b255be [file] [log] [blame]
Paul Stewartac1328e2012-07-20 11:55:40 -07001// Copyright (c) 2012 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 "shill/arp_client.h"
6
7#include <linux/if_packet.h>
8#include <net/ethernet.h>
9#include <net/if_arp.h>
10#include <netinet/in.h>
11#include <string.h>
12
Paul Stewartac1328e2012-07-20 11:55:40 -070013#include "shill/arp_packet.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070014#include "shill/logging.h"
Peter Qiu8d6b5972014-10-28 15:33:34 -070015#include "shill/net/byte_string.h"
16#include "shill/net/sockets.h"
Paul Stewartac1328e2012-07-20 11:55:40 -070017
18namespace shill {
19
Ben Chan7fab8972014-08-10 17:14:46 -070020// ARP opcode is the last uint16_t in the ARP header.
21const size_t ArpClient::kArpOpOffset = sizeof(arphdr) - sizeof(uint16_t);
Paul Stewartac1328e2012-07-20 11:55:40 -070022
23// The largest packet we expect is one with IPv6 addresses in it.
24const size_t ArpClient::kMaxArpPacketLength =
25 sizeof(arphdr) + sizeof(in6_addr) * 2 + ETH_ALEN * 2;
26
27ArpClient::ArpClient(int interface_index)
28 : interface_index_(interface_index),
29 sockets_(new Sockets()),
30 socket_(-1) {}
31
32ArpClient::~ArpClient() {}
33
Paul Stewart417e5f02014-10-09 08:52:35 -070034bool ArpClient::StartReplyListener() {
35 return Start(ARPOP_REPLY);
36}
37
38bool ArpClient::StartRequestListener() {
39 return Start(ARPOP_REQUEST);
40}
41
42bool ArpClient::Start(uint16_t arp_opcode) {
43 if (!CreateSocket(arp_opcode)) {
Paul Stewartac1328e2012-07-20 11:55:40 -070044 LOG(ERROR) << "Could not open ARP socket.";
45 Stop();
46 return false;
47 }
48 return true;
49}
50
51void ArpClient::Stop() {
52 socket_closer_.reset();
53}
54
55
Paul Stewart417e5f02014-10-09 08:52:35 -070056bool ArpClient::CreateSocket(uint16_t arp_opcode) {
Paul Stewartac1328e2012-07-20 11:55:40 -070057 int socket = sockets_->Socket(PF_PACKET, SOCK_DGRAM, htons(ETHERTYPE_ARP));
58 if (socket == -1) {
59 PLOG(ERROR) << "Could not create ARP socket";
60 return false;
61 }
62 socket_ = socket;
63 socket_closer_.reset(new ScopedSocketCloser(sockets_.get(), socket_));
64
Paul Stewart417e5f02014-10-09 08:52:35 -070065 // Create a packet filter incoming ARP packets.
Peter Qiuc528bf62015-01-26 11:19:30 -080066 const sock_filter arp_filter[] = {
Paul Stewart417e5f02014-10-09 08:52:35 -070067 // If a packet contains the ARP opcode we are looking for...
Paul Stewartac1328e2012-07-20 11:55:40 -070068 BPF_STMT(BPF_LD | BPF_H | BPF_ABS, kArpOpOffset),
Paul Stewart417e5f02014-10-09 08:52:35 -070069 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, arp_opcode, 0, 1),
Paul Stewartac1328e2012-07-20 11:55:40 -070070 // Return the the packet (up to largest expected packet size).
71 BPF_STMT(BPF_RET | BPF_K, kMaxArpPacketLength),
72 // Otherwise, drop it.
73 BPF_STMT(BPF_RET | BPF_K, 0),
74 };
75
76 sock_fprog pf;
Paul Stewarta794cd62015-06-16 13:13:10 -070077 pf.filter = const_cast<sock_filter*>(arp_filter);
Peter Qiuc528bf62015-01-26 11:19:30 -080078 pf.len = arraysize(arp_filter);
Paul Stewartac1328e2012-07-20 11:55:40 -070079 if (sockets_->AttachFilter(socket_, &pf) != 0) {
80 PLOG(ERROR) << "Could not attach packet filter";
81 return false;
82 }
83
84 if (sockets_->SetNonBlocking(socket_) != 0) {
85 PLOG(ERROR) << "Could not set socket to be non-blocking";
86 return false;
87 }
88
89 sockaddr_ll socket_address;
90 memset(&socket_address, 0, sizeof(socket_address));
91 socket_address.sll_family = AF_PACKET;
92 socket_address.sll_protocol = htons(ETHERTYPE_ARP);
93 socket_address.sll_ifindex = interface_index_;
94
95 if (sockets_->Bind(socket_,
Paul Stewarta794cd62015-06-16 13:13:10 -070096 reinterpret_cast<struct sockaddr*>(&socket_address),
Paul Stewartac1328e2012-07-20 11:55:40 -070097 sizeof(socket_address)) != 0) {
98 PLOG(ERROR) << "Could not bind socket to interface";
99 return false;
100 }
101
102 return true;
103}
104
Paul Stewarta794cd62015-06-16 13:13:10 -0700105bool ArpClient::ReceivePacket(ArpPacket* packet, ByteString* sender) const {
Paul Stewartac1328e2012-07-20 11:55:40 -0700106 ByteString payload(kMaxArpPacketLength);
107 sockaddr_ll socket_address;
108 memset(&socket_address, 0, sizeof(socket_address));
109 socklen_t socklen = sizeof(socket_address);
110 int result = sockets_->RecvFrom(
111 socket_,
112 payload.GetData(),
113 payload.GetLength(),
114 0,
Paul Stewarta794cd62015-06-16 13:13:10 -0700115 reinterpret_cast<struct sockaddr*>(&socket_address),
Paul Stewartac1328e2012-07-20 11:55:40 -0700116 &socklen);
117 if (result < 0) {
118 PLOG(ERROR) << "Socket recvfrom failed";
119 return false;
120 }
121
122 payload.Resize(result);
Paul Stewart417e5f02014-10-09 08:52:35 -0700123 if (!packet->Parse(payload)) {
124 LOG(ERROR) << "Failed to parse ARP packet.";
Paul Stewartac1328e2012-07-20 11:55:40 -0700125 return false;
126 }
127
128 // The socket address returned may only be big enough to contain
129 // the hardware address of the sender.
130 CHECK(socklen >=
131 sizeof(socket_address) - sizeof(socket_address.sll_addr) + ETH_ALEN);
132 CHECK(socket_address.sll_halen == ETH_ALEN);
133 *sender = ByteString(
Paul Stewarta794cd62015-06-16 13:13:10 -0700134 reinterpret_cast<const unsigned char*>(&socket_address.sll_addr),
Paul Stewartac1328e2012-07-20 11:55:40 -0700135 socket_address.sll_halen);
136 return true;
137}
138
Paul Stewarta794cd62015-06-16 13:13:10 -0700139bool ArpClient::TransmitRequest(const ArpPacket& packet) const {
Paul Stewartac1328e2012-07-20 11:55:40 -0700140 ByteString payload;
141 if (!packet.FormatRequest(&payload)) {
142 return false;
143 }
144
145 sockaddr_ll socket_address;
146 memset(&socket_address, 0, sizeof(socket_address));
147 socket_address.sll_family = AF_PACKET;
148 socket_address.sll_protocol = htons(ETHERTYPE_ARP);
149 socket_address.sll_hatype = ARPHRD_ETHER;
150 socket_address.sll_halen = ETH_ALEN;
151 socket_address.sll_ifindex = interface_index_;
152
153 ByteString remote_address = packet.remote_mac_address();
154 CHECK(sizeof(socket_address.sll_addr) >= remote_address.GetLength());
155 if (remote_address.IsZero()) {
156 // If the destination MAC address is unspecified, send the packet
157 // to the broadcast (all-ones) address.
158 remote_address.BitwiseInvert();
159 }
160 memcpy(&socket_address.sll_addr, remote_address.GetConstData(),
161 remote_address.GetLength());
162
163 int result = sockets_->SendTo(
164 socket_,
165 payload.GetConstData(),
166 payload.GetLength(),
167 0,
Paul Stewarta794cd62015-06-16 13:13:10 -0700168 reinterpret_cast<struct sockaddr*>(&socket_address),
Paul Stewartac1328e2012-07-20 11:55:40 -0700169 sizeof(socket_address));
170 const int expected_result = static_cast<int>(payload.GetLength());
171 if (result != expected_result) {
172 if (result < 0) {
173 PLOG(ERROR) << "Socket sendto failed";
174 } else if (result < static_cast<int>(payload.GetLength())) {
175 LOG(ERROR) << "Socket sendto returned "
176 << result
177 << " which is different from expected result "
178 << expected_result;
179 }
180 return false;
181 }
182
183 return true;
184}
185
186} // namespace shill