1 // Copyright 2014 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.
5 #include "net/base/ip_pattern.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_split.h"
14 #include "base/strings/string_tokenizer.h"
18 class IPPattern::ComponentPattern
{
21 void AppendRange(uint32_t min
, uint32_t max
);
22 bool Match(uint32_t value
) const;
27 Range(uint32_t min
, uint32_t max
) : minimum(min
), maximum(max
) {}
31 typedef std::vector
<Range
> RangeVector
;
35 DISALLOW_COPY_AND_ASSIGN(ComponentPattern
);
38 IPPattern::ComponentPattern::ComponentPattern() {}
40 void IPPattern::ComponentPattern::AppendRange(uint32_t min
, uint32_t max
) {
41 ranges_
.push_back(Range(min
, max
));
44 bool IPPattern::ComponentPattern::Match(uint32_t value
) const {
45 // Simple linear search should be fine, as we usually only have very few
46 // distinct ranges to test.
47 for (RangeVector::const_iterator range_it
= ranges_
.begin();
48 range_it
!= ranges_
.end(); ++range_it
) {
49 if (range_it
->maximum
>= value
&& range_it
->minimum
<= value
)
55 IPPattern::IPPattern() : is_ipv4_(true) {}
57 IPPattern::~IPPattern() {
58 STLDeleteElements(&component_patterns_
);
61 bool IPPattern::Match(const IPAddressNumber
& address
) const {
64 bool address_is_ipv4
= address
.size() == kIPv4AddressSize
;
65 if (address_is_ipv4
!= is_ipv4_
)
68 ComponentPatternList::const_iterator
pattern_it(component_patterns_
.begin());
69 int fixed_value_index
= 0;
70 // IPv6 |address| vectors have 16 pieces, while our |ip_mask_| has only
71 // 8, so it is easier to count separately.
72 int address_index
= 0;
73 for (size_t i
= 0; i
< ip_mask_
.size(); ++i
) {
74 uint32_t value_to_test
= address
[address_index
++];
76 value_to_test
= (value_to_test
<< 8) + address
[address_index
++];
79 if (component_values_
[fixed_value_index
++] != value_to_test
)
83 if (!(*pattern_it
)->Match(value_to_test
))
90 bool IPPattern::ParsePattern(const std::string
& ip_pattern
) {
91 DCHECK(ip_mask_
.empty());
92 if (ip_pattern
.find(':') != std::string::npos
) {
96 std::vector
<base::StringPiece
> components
=
97 base::SplitStringPiece(ip_pattern
, is_ipv4_
? "." : ":",
98 base::TRIM_WHITESPACE
, base::SPLIT_WANT_ALL
);
99 if (components
.size() != (is_ipv4_
? 4u : 8u)) {
100 DVLOG(1) << "Invalid component count: " << ip_pattern
;
103 for (base::StringPiece component
: components
) {
104 if (component
.empty()) {
105 DVLOG(1) << "Empty component: " << ip_pattern
;
108 if (component
== "*") {
109 // Let standard code handle this below.
110 component
= is_ipv4_
? "[0-255]" : "[0-FFFF]";
111 } else if (component
[0] != '[') {
112 // This value will just have a specific integer to match.
114 if (!ValueTextToInt(component
, &value
))
116 ip_mask_
.push_back(true);
117 component_values_
.push_back(value
);
120 if (component
[component
.size() - 1] != ']') {
121 DVLOG(1) << "Missing close bracket: " << ip_pattern
;
124 // Now we know the size() is at least 2.
125 if (component
.size() == 2) {
126 DVLOG(1) << "Empty bracket: " << ip_pattern
;
129 // We'll need a pattern to match this bracketed component.
130 scoped_ptr
<ComponentPattern
> component_pattern(new ComponentPattern
);
131 // Trim leading and trailing bracket before calling for parsing.
132 if (!ParseComponentPattern(component
.substr(1, component
.size() - 2),
133 component_pattern
.get())) {
136 ip_mask_
.push_back(false);
137 component_patterns_
.push_back(component_pattern
.release());
142 bool IPPattern::ParseComponentPattern(const base::StringPiece
& text
,
143 ComponentPattern
* pattern
) const {
144 // We're given a comma separated set of ranges, some of which may be simple
146 for (const std::string
& range
: base::SplitString(
147 text
, ",", base::TRIM_WHITESPACE
, base::SPLIT_WANT_ALL
)) {
148 base::StringTokenizer
range_pair(range
, "-");
150 range_pair
.GetNext();
151 if (!ValueTextToInt(range_pair
.token_piece(), &min
))
153 uint32_t max
= min
; // Sometimes we have no distinct max.
154 if (range_pair
.GetNext()) {
155 if (!ValueTextToInt(range_pair
.token_piece(), &max
))
158 if (range_pair
.GetNext()) {
159 // Too many "-" in this range specifier.
160 DVLOG(1) << "Too many hyphens in range: ";
163 pattern
->AppendRange(min
, max
);
168 bool IPPattern::ValueTextToInt(const base::StringPiece
& input
,
169 uint32_t* output
) const {
170 bool ok
= is_ipv4_
? base::StringToUint(input
, output
) :
171 base::HexStringToUInt(input
, output
);
173 DVLOG(1) << "Could not convert value to number: " << input
;
176 if (is_ipv4_
&& *output
> 255u) {
177 DVLOG(1) << "IPv4 component greater than 255";
180 if (!is_ipv4_
&& *output
> 0xFFFFu
) {
181 DVLOG(1) << "IPv6 component greater than 0xFFFF";