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