Home | History | Annotate | Download | only in src
      1 // Copyright (c) 2011 The Chromium 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 
      6 #include <algorithm>
      7 #include <iterator>
      8 #include <map>
      9 
     10 #include <fcntl.h>
     11 #include <netdb.h>
     12 #include <net/if.h>
     13 #include <netinet/in.h>
     14 #include <arpa/inet.h>
     15 
     16 #include <string.h>
     17 
     18 #include "net_util.h"
     19 
     20 namespace net {
     21 
     22 #ifndef INET6_ADDRSTRLEN  /* for non IPv6 machines */
     23 #define INET6_ADDRSTRLEN 46
     24 #endif
     25 
     26 bool ParseIPLiteralToNumber(const std::string& ip_literal,
     27                             IPAddressNumber* ip_number) {
     28   char buf[sizeof(struct in6_addr)];
     29   int size = sizeof(struct in_addr);
     30   int mode = AF_INET;
     31   if (ip_literal.find(':') != std::string::npos) {
     32     mode = AF_INET6;
     33     size = sizeof(struct in6_addr);
     34   }
     35   if (inet_pton(mode, ip_literal.c_str(), buf) != 1) {
     36     return false;
     37   }
     38   ip_number->resize(size);
     39   for (int i = 0; i < size; i++) {
     40     (*ip_number)[i] = buf[i];
     41   }
     42   return true;
     43 }
     44 
     45 IPAddressNumber ConvertIPv4NumberToIPv6Number(
     46     const IPAddressNumber& ipv4_number) {
     47   // IPv4-mapped addresses are formed by:
     48   // <80 bits of zeros>  + <16 bits of ones> + <32-bit IPv4 address>.
     49   IPAddressNumber ipv6_number;
     50   ipv6_number.reserve(16);
     51   ipv6_number.insert(ipv6_number.end(), 10, 0);
     52   ipv6_number.push_back(0xFF);
     53   ipv6_number.push_back(0xFF);
     54   ipv6_number.insert(ipv6_number.end(), ipv4_number.begin(), ipv4_number.end());
     55   return ipv6_number;
     56 }
     57 
     58 bool ParseCIDRBlock(const std::string& cidr_literal,
     59                     IPAddressNumber* ip_number,
     60                     size_t* prefix_length_in_bits) {
     61   // We expect CIDR notation to match one of these two templates:
     62   //   <IPv4-literal> "/" <number of bits>
     63   //   <IPv6-literal> "/" <number of bits>
     64 
     65   std::vector<std::string> parts;
     66   unsigned int split = cidr_literal.find('/');
     67   if (split == std::string::npos)
     68     return false;
     69   parts.push_back(cidr_literal.substr(0, split));
     70   parts.push_back(cidr_literal.substr(split + 1));
     71   if (parts[1].find('/') != std::string::npos)
     72     return false;
     73 
     74   // Parse the IP address.
     75   if (!ParseIPLiteralToNumber(parts[0], ip_number))
     76     return false;
     77 
     78   // Parse the prefix length.
     79   int number_of_bits = atoi(parts[1].c_str());
     80 
     81   // Make sure the prefix length is in a valid range.
     82   if (number_of_bits < 0 ||
     83       number_of_bits > static_cast<int>(ip_number->size() * 8))
     84     return false;
     85 
     86   *prefix_length_in_bits = static_cast<size_t>(number_of_bits);
     87   return true;
     88 }
     89 
     90 bool IPNumberMatchesPrefix(const IPAddressNumber& ip_number,
     91                            const IPAddressNumber& ip_prefix,
     92                            size_t prefix_length_in_bits) {
     93   // Both the input IP address and the prefix IP address should be
     94   // either IPv4 or IPv6.
     95 
     96   // In case we have an IPv6 / IPv4 mismatch, convert the IPv4 addresses to
     97   // IPv6 addresses in order to do the comparison.
     98   if (ip_number.size() != ip_prefix.size()) {
     99     if (ip_number.size() == 4) {
    100       return IPNumberMatchesPrefix(ConvertIPv4NumberToIPv6Number(ip_number),
    101                                    ip_prefix, prefix_length_in_bits);
    102     }
    103     return IPNumberMatchesPrefix(ip_number,
    104                                  ConvertIPv4NumberToIPv6Number(ip_prefix),
    105                                  96 + prefix_length_in_bits);
    106   }
    107 
    108   // Otherwise we are comparing two IPv4 addresses, or two IPv6 addresses.
    109   // Compare all the bytes that fall entirely within the prefix.
    110   int num_entire_bytes_in_prefix = prefix_length_in_bits / 8;
    111   for (int i = 0; i < num_entire_bytes_in_prefix; ++i) {
    112     if (ip_number[i] != ip_prefix[i])
    113       return false;
    114   }
    115 
    116   // In case the prefix was not a multiple of 8, there will be 1 byte
    117   // which is only partially masked.
    118   int remaining_bits = prefix_length_in_bits % 8;
    119   if (remaining_bits != 0) {
    120     unsigned char mask = 0xFF << (8 - remaining_bits);
    121     int i = num_entire_bytes_in_prefix;
    122     if ((ip_number[i] & mask) != (ip_prefix[i] & mask))
    123       return false;
    124   }
    125 
    126   return true;
    127 }
    128 
    129 }  // namespace net
    130