Home | History | Annotate | Download | only in shill
      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 
     32 ArpPacket::ArpPacket()
     33     : operation_(0),
     34       local_ip_address_(IPAddress::kFamilyUnknown),
     35       remote_ip_address_(IPAddress::kFamilyUnknown) {}
     36 
     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 
     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 // +-----------------------------------------------------------------------+
     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.
    134 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 
    185 bool ArpPacket::IsReply() const {
    186   return operation_ == ARPOP_REPLY;
    187 }
    188 
    189 }  // namespace shill
    190