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