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 
28 namespace shill {
29 
30 const size_t ArpPacket::kMinPayloadSize = ETH_ZLEN - ETH_HLEN;
31 
ArpPacket()32 ArpPacket::ArpPacket()
33     : operation_(0),
34       local_ip_address_(IPAddress::kFamilyUnknown),
35       remote_ip_address_(IPAddress::kFamilyUnknown) {}
36 
ArpPacket(const IPAddress & local_ip,const IPAddress & remote_ip,const ByteString & local_mac,const ByteString & remote_mac)37 ArpPacket::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 
~ArpPacket()45 ArpPacket::~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 // +-----------------------------------------------------------------------+
Parse(const ByteString & packet)67 bool 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.
FormatRequest(ByteString * packet) const134 bool 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 
IsReply() const185 bool ArpPacket::IsReply() const {
186   return operation_ == ARPOP_REPLY;
187 }
188 
189 }  // namespace shill
190