1//
2// Copyright (C) 2012 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "shill/arp_packet.h"
18
19#include <net/ethernet.h>
20#include <net/if_arp.h>
21#include <netinet/in.h>
22#include <string.h>
23
24#include <limits>
25
26#include "shill/logging.h"
27
28namespace shill {
29
30const size_t ArpPacket::kMinPayloadSize = ETH_ZLEN - ETH_HLEN;
31
32ArpPacket::ArpPacket()
33    : operation_(0),
34      local_ip_address_(IPAddress::kFamilyUnknown),
35      remote_ip_address_(IPAddress::kFamilyUnknown) {}
36
37ArpPacket::ArpPacket(
38    const IPAddress& local_ip, const IPAddress& remote_ip,
39    const ByteString& local_mac, const ByteString& remote_mac)
40    : local_ip_address_(local_ip),
41      remote_ip_address_(remote_ip),
42      local_mac_address_(local_mac),
43      remote_mac_address_(remote_mac) {}
44
45ArpPacket::~ArpPacket() {}
46
47// Format of an ARP packet (all multi-byte values are big-endian):
48//
49//       Byte 0            Byte 1           Byte 2             Byte 3
50// +-----------------+-----------------+-----------------+-----------------+
51// | Format of hardware address (ether)| Format of Protocol Address (IP)   |
52// +-----------------+-----------------+-----------------------------------+
53// | Hardware Length | Protocol Length |       ARP Protocol OpCode         |
54// +-----------------+-----------------+-----------------------------------+
55//
56// plus a variable length section...
57//
58// +-----------------------------------------------------------------------+
59// | Sender Hardware Address (of length "Hardware Length")...              |
60// +-----------------------------------------------------------------------+
61// | Sender IP Address (of length "Protocol Length")...                    |
62// +-----------------------------------------------------------------------+
63// | Target Hardware Address (of length "Hardware Length")...              |
64// +-----------------------------------------------------------------------+
65// | Target IP Address (of length "Protocol Length")...                    |
66// +-----------------------------------------------------------------------+
67bool ArpPacket::Parse(const ByteString& packet) {
68  arphdr header;
69  if (packet.GetLength() < sizeof(header)) {
70    LOG(ERROR) << "Packet size " << packet.GetLength()
71               << " is too short to contain ARP header.";
72    return false;
73  }
74
75  memcpy(&header, packet.GetConstData(), sizeof(header));
76
77  const uint16_t hardware_type = ntohs(header.ar_hrd);
78  if (hardware_type != ARPHRD_ETHER) {
79    NOTIMPLEMENTED() << "Packet is of unknown ARPHRD type "
80                     << hardware_type;
81    return false;
82  }
83  const uint16_t protocol = ntohs(header.ar_pro);
84  IPAddress::Family family = IPAddress::kFamilyUnknown;
85  if (protocol == ETHERTYPE_IP) {
86    family = IPAddress::kFamilyIPv4;
87  } else if (protocol == ETHERTYPE_IPV6) {
88    family = IPAddress::kFamilyIPv6;
89  } else {
90    NOTIMPLEMENTED() << "Packet has unknown protocol "
91                     << protocol;
92    return false;
93  }
94  if (header.ar_hln != ETH_ALEN) {
95    LOG(ERROR) << "Packet has unexpected hardware address length "
96               << static_cast<int>(header.ar_hln) << "; expected " << ETH_ALEN;
97    return false;
98  }
99  size_t ip_address_length = IPAddress::GetAddressLength(family);
100  if (header.ar_pln != ip_address_length) {
101    LOG(ERROR) << "Packet has unexpected protocol address length "
102               << static_cast<int>(header.ar_hln) << "; expected "
103               << ip_address_length;
104    return false;
105  }
106  const uint16_t operation = ntohs(header.ar_op);
107  if (operation != ARPOP_REPLY && operation != ARPOP_REQUEST) {
108    NOTIMPLEMENTED() << "Packet is not an ARP reply or request but of type "
109                     << operation;
110    return false;
111  }
112  size_t min_packet_size =
113      sizeof(header) + 2 * ip_address_length + 2 * ETH_ALEN;
114  if (packet.GetLength() < min_packet_size) {
115    NOTIMPLEMENTED() << "Packet of size "
116                     << packet.GetLength()
117                     << " is too small to contain entire ARP payload; "
118                     << "expected at least "
119                     << min_packet_size;
120    return false;
121  }
122  operation_ = operation;
123  local_mac_address_ = packet.GetSubstring(sizeof(header), ETH_ALEN);
124  local_ip_address_ = IPAddress(family, packet.GetSubstring(
125      sizeof(header) + ETH_ALEN, ip_address_length));
126  remote_mac_address_ = packet.GetSubstring(
127      sizeof(header) + ETH_ALEN + ip_address_length, ETH_ALEN);
128  remote_ip_address_ = IPAddress(family, packet.GetSubstring(
129      sizeof(header) + ETH_ALEN * 2 + ip_address_length, ip_address_length));
130  return true;
131}
132
133// Output a payload from local parameters.
134bool ArpPacket::FormatRequest(ByteString* packet) const {
135  if (!local_ip_address_.IsValid() || !remote_ip_address_.IsValid()) {
136    LOG(ERROR) << "Local or remote IP address is not valid.";
137    return false;
138  }
139  if (local_ip_address_.family() != remote_ip_address_.family()) {
140    LOG(ERROR) << "Local and remote IP address families do not match!";
141    return false;
142  }
143  uint16_t protocol;
144  IPAddress::Family family = local_ip_address_.family();
145  if (family == IPAddress::kFamilyIPv4) {
146    protocol = ETHERTYPE_IP;
147  } else if (family == IPAddress::kFamilyIPv6) {
148    protocol = ETHERTYPE_IPV6;
149  } else {
150    NOTIMPLEMENTED() << "Address family "
151                     << IPAddress::GetAddressFamilyName(family)
152                     << " is not supported.";
153    return false;
154  }
155  size_t ip_address_length = IPAddress::GetAddressLength(family);
156  CHECK(ip_address_length < std::numeric_limits<uint8_t>::max());
157  if (local_mac_address_.GetLength() != ETH_ALEN ||
158      remote_mac_address_.GetLength() != ETH_ALEN) {
159    LOG(ERROR) << "Local or remote MAC address length is incorrect.";
160    return false;
161  }
162
163  arphdr header;
164  header.ar_hrd = htons(ARPHRD_ETHER);
165  header.ar_pro = htons(protocol);
166  header.ar_hln = ETH_ALEN;
167  header.ar_pln = ip_address_length;
168  header.ar_op = htons(ARPOP_REQUEST);
169
170  *packet = ByteString(reinterpret_cast<const unsigned char*>(&header),
171                       sizeof(header));
172
173  packet->Append(local_mac_address_);
174  packet->Append(local_ip_address_.address());
175  packet->Append(remote_mac_address_);
176  packet->Append(remote_ip_address_.address());
177
178  if (packet->GetLength() < kMinPayloadSize) {
179    packet->Append(ByteString(kMinPayloadSize - packet->GetLength()));
180  }
181
182  return true;
183}
184
185bool ArpPacket::IsReply() const {
186  return operation_ == ARPOP_REPLY;
187}
188
189}  // namespace shill
190