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
ParseIPLiteralToNumber(const std::string & ip_literal,IPAddressNumber * ip_number)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
ConvertIPv4NumberToIPv6Number(const IPAddressNumber & ipv4_number)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
ParseCIDRBlock(const std::string & cidr_literal,IPAddressNumber * ip_number,size_t * prefix_length_in_bits)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 size_t 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
IPNumberMatchesPrefix(const IPAddressNumber & ip_number,const IPAddressNumber & ip_prefix,size_t prefix_length_in_bits)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