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