blob: b755134cc05b958b809c4d1ebec596e6ddc0e210 [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
12#include <gtest/gtest.h>
13
14#include "shill/arp_packet.h"
Paul Stewartac1328e2012-07-20 11:55:40 -070015#include "shill/mock_log.h"
Peter Qiu8d6b5972014-10-28 15:33:34 -070016#include "shill/net/ip_address.h"
17#include "shill/net/mock_sockets.h"
Paul Stewartac1328e2012-07-20 11:55:40 -070018
19using testing::_;
20using testing::AnyNumber;
21using testing::HasSubstr;
22using testing::InSequence;
23using testing::Invoke;
24using testing::Mock;
Paul Stewartac1328e2012-07-20 11:55:40 -070025using testing::Return;
26using testing::StrictMock;
27using testing::Test;
28
29namespace shill {
30
31class ArpClientTest : public Test {
32 public:
33 ArpClientTest() : client_(kInterfaceIndex) {}
34 virtual ~ArpClientTest() {}
35
36 virtual void SetUp() {
37 sockets_ = new StrictMock<MockSockets>();
38 // Passes ownership.
39 client_.sockets_.reset(sockets_);
40 memset(&recvfrom_sender_, 0, sizeof(recvfrom_sender_));
41 }
42
43 virtual void TearDown() {
44 if (GetSocket() == kSocketFD) {
45 EXPECT_CALL(*sockets_, Close(kSocketFD));
46 client_.Stop();
47 }
48 }
49
Paul Stewart3b30ca52015-06-16 13:13:10 -070050 ssize_t SimulateRecvFrom(int sockfd, void* buf, size_t len, int flags,
51 struct sockaddr* src_addr, socklen_t* addrlen);
Paul Stewartac1328e2012-07-20 11:55:40 -070052
53 protected:
54 static const int kInterfaceIndex;
55 static const int kSocketFD;
56 static const char kLocalIPAddress[];
Ben Chan7fab8972014-08-10 17:14:46 -070057 static const uint8_t kLocalMACAddress[];
Paul Stewartac1328e2012-07-20 11:55:40 -070058 static const char kRemoteIPAddress[];
Ben Chan7fab8972014-08-10 17:14:46 -070059 static const uint8_t kRemoteMACAddress[];
Paul Stewartac1328e2012-07-20 11:55:40 -070060 static const int kArpOpOffset;
61
Paul Stewart417e5f02014-10-09 08:52:35 -070062 bool CreateSocket() { return client_.CreateSocket(ARPOP_REPLY); }
Paul Stewartac1328e2012-07-20 11:55:40 -070063 int GetInterfaceIndex() { return client_.interface_index_; }
64 size_t GetMaxArpPacketLength() { return ArpClient::kMaxArpPacketLength; }
65 int GetSocket() { return client_.socket_; }
Paul Stewart3b30ca52015-06-16 13:13:10 -070066 void SetupValidPacket(ArpPacket* packet);
Paul Stewartac1328e2012-07-20 11:55:40 -070067 void StartClient() { StartClientWithFD(kSocketFD); }
68 void StartClientWithFD(int fd);
69
70 // Owned by ArpClient, and tracked here only for mocks.
Paul Stewart3b30ca52015-06-16 13:13:10 -070071 MockSockets* sockets_;
Paul Stewartac1328e2012-07-20 11:55:40 -070072 ArpClient client_;
73 ByteString recvfrom_reply_data_;
74 sockaddr_ll recvfrom_sender_;
75};
76
77
78const int ArpClientTest::kInterfaceIndex = 123;
79const int ArpClientTest::kSocketFD = 456;
80const char ArpClientTest::kLocalIPAddress[] = "10.0.1.1";
Ben Chan7fab8972014-08-10 17:14:46 -070081const uint8_t ArpClientTest::kLocalMACAddress[] = { 0, 1, 2, 3, 4, 5 };
Paul Stewartac1328e2012-07-20 11:55:40 -070082const char ArpClientTest::kRemoteIPAddress[] = "10.0.1.2";
Ben Chan7fab8972014-08-10 17:14:46 -070083const uint8_t ArpClientTest::kRemoteMACAddress[] = { 6, 7, 8, 9, 10, 11 };
Paul Stewartac1328e2012-07-20 11:55:40 -070084const int ArpClientTest::kArpOpOffset = 7;
85
86
87MATCHER_P2(IsLinkAddress, interface_index, destination_mac, "") {
Paul Stewart3b30ca52015-06-16 13:13:10 -070088 const struct sockaddr_ll* socket_address =
89 reinterpret_cast<const struct sockaddr_ll*>(arg);
Paul Stewartac1328e2012-07-20 11:55:40 -070090 ByteString socket_mac(
Paul Stewart3b30ca52015-06-16 13:13:10 -070091 reinterpret_cast<const unsigned char*>(&socket_address->sll_addr),
Paul Stewartac1328e2012-07-20 11:55:40 -070092 destination_mac.GetLength());
93 return socket_address->sll_family == AF_PACKET &&
94 socket_address->sll_protocol == htons(ETHERTYPE_ARP) &&
95 socket_address->sll_ifindex == interface_index &&
96 destination_mac.Equals(socket_mac);
97}
98
99MATCHER_P(IsByteData, byte_data, "") {
Paul Stewart3b30ca52015-06-16 13:13:10 -0700100 return ByteString(reinterpret_cast<const unsigned char*>(arg),
Paul Stewartac1328e2012-07-20 11:55:40 -0700101 byte_data.GetLength()).Equals(byte_data);
102}
103
Paul Stewart3b30ca52015-06-16 13:13:10 -0700104void ArpClientTest::SetupValidPacket(ArpPacket* packet) {
Paul Stewartac1328e2012-07-20 11:55:40 -0700105 IPAddress local_ip(IPAddress::kFamilyIPv4);
106 EXPECT_TRUE(local_ip.SetAddressFromString(kLocalIPAddress));
107 packet->set_local_ip_address(local_ip);
108 IPAddress remote_ip(IPAddress::kFamilyIPv4);
109 EXPECT_TRUE(remote_ip.SetAddressFromString(kRemoteIPAddress));
110 packet->set_remote_ip_address(remote_ip);
111 ByteString local_mac(kLocalMACAddress, arraysize(kLocalMACAddress));
112 packet->set_local_mac_address(local_mac);
113 ByteString remote_mac(kRemoteMACAddress, arraysize(kRemoteMACAddress));
114 packet->set_remote_mac_address(remote_mac);
115}
116
Paul Stewart3b30ca52015-06-16 13:13:10 -0700117ssize_t ArpClientTest::SimulateRecvFrom(int sockfd, void* buf, size_t len,
118 int flags, struct sockaddr* src_addr,
119 socklen_t* addrlen) {
Paul Stewartac1328e2012-07-20 11:55:40 -0700120 memcpy(buf, recvfrom_reply_data_.GetConstData(),
121 recvfrom_reply_data_.GetLength());
122 memcpy(src_addr, &recvfrom_sender_, sizeof(recvfrom_sender_));
123 return recvfrom_reply_data_.GetLength();
124}
125
126void ArpClientTest::StartClientWithFD(int fd) {
127 EXPECT_CALL(*sockets_, Socket(PF_PACKET, SOCK_DGRAM, htons(ETHERTYPE_ARP)))
128 .WillOnce(Return(fd));
129 EXPECT_CALL(*sockets_, AttachFilter(fd, _)).WillOnce(Return(0));
130 EXPECT_CALL(*sockets_, SetNonBlocking(fd)).WillOnce(Return(0));
131 EXPECT_CALL(*sockets_, Bind(fd,
132 IsLinkAddress(kInterfaceIndex, ByteString()),
133 sizeof(sockaddr_ll))).WillOnce(Return(0));
134 EXPECT_TRUE(CreateSocket());
135 EXPECT_EQ(fd, client_.socket_);
136}
137
138TEST_F(ArpClientTest, Constructor) {
139 EXPECT_EQ(kInterfaceIndex, GetInterfaceIndex());
140 EXPECT_EQ(-1, GetSocket());
141}
142
143TEST_F(ArpClientTest, SocketOpenFail) {
144 ScopedMockLog log;
145 EXPECT_CALL(log,
146 Log(logging::LOG_ERROR, _,
147 HasSubstr("Could not create ARP socket"))).Times(1);
148
149 EXPECT_CALL(*sockets_, Socket(PF_PACKET, SOCK_DGRAM, htons(ETHERTYPE_ARP)))
150 .WillOnce(Return(-1));
151 EXPECT_FALSE(CreateSocket());
152}
153
154TEST_F(ArpClientTest, SocketFilterFail) {
155 ScopedMockLog log;
156 EXPECT_CALL(log,
157 Log(logging::LOG_ERROR, _,
158 HasSubstr("Could not attach packet filter"))).Times(1);
159
160 EXPECT_CALL(*sockets_, Socket(_, _, _)).WillOnce(Return(kSocketFD));
161 EXPECT_CALL(*sockets_, AttachFilter(kSocketFD, _)).WillOnce(Return(-1));
162 EXPECT_FALSE(CreateSocket());
163}
164
165TEST_F(ArpClientTest, SocketNonBlockingFail) {
166 ScopedMockLog log;
167 EXPECT_CALL(log,
168 Log(logging::LOG_ERROR, _,
169 HasSubstr("Could not set socket to be non-blocking"))).Times(1);
170
171 EXPECT_CALL(*sockets_, Socket(_, _, _)).WillOnce(Return(kSocketFD));
172 EXPECT_CALL(*sockets_, AttachFilter(kSocketFD, _)).WillOnce(Return(0));
173 EXPECT_CALL(*sockets_, SetNonBlocking(kSocketFD)).WillOnce(Return(-1));
174 EXPECT_FALSE(CreateSocket());
175}
176
177TEST_F(ArpClientTest, SocketBindFail) {
178 ScopedMockLog log;
179 EXPECT_CALL(log,
180 Log(logging::LOG_ERROR, _,
181 HasSubstr("Could not bind socket to interface"))).Times(1);
182
183 EXPECT_CALL(*sockets_, Socket(_, _, _)).WillOnce(Return(kSocketFD));
184 EXPECT_CALL(*sockets_, AttachFilter(kSocketFD, _)).WillOnce(Return(0));
185 EXPECT_CALL(*sockets_, SetNonBlocking(kSocketFD)).WillOnce(Return(0));
186 EXPECT_CALL(*sockets_, Bind(kSocketFD, _, _)).WillOnce(Return(-1));
187 EXPECT_FALSE(CreateSocket());
188}
189
190TEST_F(ArpClientTest, StartSuccess) {
191 StartClient();
192}
193
194TEST_F(ArpClientTest, StartMultipleTimes) {
195 const int kFirstSocketFD = kSocketFD + 1;
196 StartClientWithFD(kFirstSocketFD);
197 EXPECT_CALL(*sockets_, Close(kFirstSocketFD));
198 StartClient();
199}
200
201TEST_F(ArpClientTest, Receive) {
202 StartClient();
203 EXPECT_CALL(*sockets_,
204 RecvFrom(kSocketFD, _, GetMaxArpPacketLength(), 0, _, _))
205 .WillOnce(Return(-1))
206 .WillRepeatedly(Invoke(this, &ArpClientTest::SimulateRecvFrom));
207 ArpPacket reply;
208 ByteString sender;
209
210 ScopedMockLog log;
211 EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber());
212 {
213 InSequence seq;
214
215 // RecvFrom returns an error.
216 EXPECT_CALL(log,
217 Log(logging::LOG_ERROR, _,
218 HasSubstr("Socket recvfrom failed"))).Times(1);
Paul Stewart417e5f02014-10-09 08:52:35 -0700219 EXPECT_FALSE(client_.ReceivePacket(&reply, &sender));
Paul Stewartac1328e2012-07-20 11:55:40 -0700220
221 // RecvFrom returns an empty response which fails to parse.
222 EXPECT_CALL(log,
223 Log(logging::LOG_ERROR, _,
Paul Stewart417e5f02014-10-09 08:52:35 -0700224 HasSubstr("Failed to parse ARP packet"))).Times(1);
225 EXPECT_FALSE(client_.ReceivePacket(&reply, &sender));
Paul Stewartac1328e2012-07-20 11:55:40 -0700226
227 ArpPacket packet;
228 SetupValidPacket(&packet);
229 packet.FormatRequest(&recvfrom_reply_data_);
230
231 // Hack: Force this packet to be an ARP repsonse instead of an ARP request.
232 recvfrom_reply_data_.GetData()[kArpOpOffset] = ARPOP_REPLY;
233
Ben Chan7fab8972014-08-10 17:14:46 -0700234 static const uint8_t kSenderBytes[] = { 0xa, 0xb, 0xc, 0xd, 0xe, 0xf };
Paul Stewartac1328e2012-07-20 11:55:40 -0700235 memcpy(&recvfrom_sender_.sll_addr, kSenderBytes, sizeof(kSenderBytes));
236 recvfrom_sender_.sll_halen = sizeof(kSenderBytes);
Paul Stewart417e5f02014-10-09 08:52:35 -0700237 EXPECT_TRUE(client_.ReceivePacket(&reply, &sender));
Paul Stewartac1328e2012-07-20 11:55:40 -0700238 EXPECT_TRUE(reply.local_ip_address().Equals(packet.local_ip_address()));
239 EXPECT_TRUE(reply.local_mac_address().Equals(packet.local_mac_address()));
240 EXPECT_TRUE(reply.remote_ip_address().Equals(packet.remote_ip_address()));
241 EXPECT_TRUE(reply.remote_mac_address().Equals(packet.remote_mac_address()));
242 EXPECT_TRUE(
243 sender.Equals(ByteString(kSenderBytes, arraysize(kSenderBytes))));
244 }
245}
246
247TEST_F(ArpClientTest, Transmit) {
248 ArpPacket packet;
249 StartClient();
250 // Packet isn't valid.
251 EXPECT_FALSE(client_.TransmitRequest(packet));
252
253 SetupValidPacket(&packet);
Paul Stewart3b30ca52015-06-16 13:13:10 -0700254 const ByteString& remote_mac = packet.remote_mac_address();
Paul Stewartac1328e2012-07-20 11:55:40 -0700255 ByteString packet_bytes;
256 ASSERT_TRUE(packet.FormatRequest(&packet_bytes));
257 EXPECT_CALL(*sockets_, SendTo(kSocketFD,
258 IsByteData(packet_bytes),
259 packet_bytes.GetLength(),
260 0,
261 IsLinkAddress(kInterfaceIndex, remote_mac),
262 sizeof(sockaddr_ll)))
263 .WillOnce(Return(-1))
264 .WillOnce(Return(0))
265 .WillOnce(Return(packet_bytes.GetLength() - 1))
266 .WillOnce(Return(packet_bytes.GetLength()));
267 {
268 InSequence seq;
269 ScopedMockLog log;
270 EXPECT_CALL(log,
271 Log(logging::LOG_ERROR, _,
272 HasSubstr("Socket sendto failed"))).Times(1);
273 EXPECT_CALL(log,
274 Log(logging::LOG_ERROR, _,
275 HasSubstr("different from expected result"))).Times(2);
276
277 EXPECT_FALSE(client_.TransmitRequest(packet));
278 EXPECT_FALSE(client_.TransmitRequest(packet));
279 EXPECT_FALSE(client_.TransmitRequest(packet));
280 EXPECT_TRUE(client_.TransmitRequest(packet));
281 }
282
283 // If the destination MAC address is unset, it should be sent to the
284 // broadcast MAC address.
Ben Chan7fab8972014-08-10 17:14:46 -0700285 static const uint8_t kZeroBytes[] = { 0, 0, 0, 0, 0, 0 };
Paul Stewartac1328e2012-07-20 11:55:40 -0700286 packet.set_remote_mac_address(ByteString(kZeroBytes, arraysize(kZeroBytes)));
287 ASSERT_TRUE(packet.FormatRequest(&packet_bytes));
Ben Chan7fab8972014-08-10 17:14:46 -0700288 static const uint8_t kBroadcastBytes[] =
289 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
Paul Stewartac1328e2012-07-20 11:55:40 -0700290 ByteString broadcast_mac(kBroadcastBytes, arraysize(kBroadcastBytes));
291 EXPECT_CALL(*sockets_, SendTo(kSocketFD,
292 IsByteData(packet_bytes),
293 packet_bytes.GetLength(),
294 0,
295 IsLinkAddress(kInterfaceIndex, broadcast_mac),
296 sizeof(sockaddr_ll)))
297 .WillOnce(Return(packet_bytes.GetLength()));
298 EXPECT_TRUE(client_.TransmitRequest(packet));
299}
300
301} // namespace shill