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