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 base::SplitString(ip_pattern
, is_ipv4_
? '.' : ':', &components
);
97 if (components
.size() != (is_ipv4_
? 4u : 8u)) {
98 DVLOG(1) << "Invalid component count: " << ip_pattern
;
101 for (Strings::iterator component_it
= components
.begin();
102 component_it
!= components
.end(); ++component_it
) {
103 if (component_it
->empty()) {
104 DVLOG(1) << "Empty component: " << ip_pattern
;
107 if (*component_it
== "*") {
108 // Let standard code handle this below.
109 *component_it
= is_ipv4_
? "[0-255]" : "[0-FFFF]";
110 } else if ((*component_it
)[0] != '[') {
111 // This value will just have a specific integer to match.
113 if (!ValueTextToInt(*component_it
, &value
))
115 ip_mask_
.push_back(true);
116 component_values_
.push_back(value
);
119 if ((*component_it
)[component_it
->size() - 1] != ']') {
120 DVLOG(1) << "Missing close bracket: " << ip_pattern
;
123 // Now we know the size() is at least 2.
124 if (component_it
->size() == 2) {
125 DVLOG(1) << "Empty bracket: " << ip_pattern
;
128 // We'll need a pattern to match this bracketed component.
129 scoped_ptr
<ComponentPattern
> component_pattern(new ComponentPattern
);
130 // Trim leading and trailing bracket before calling for parsing.
131 if (!ParseComponentPattern(base::StringPiece(component_it
->data() + 1,
132 component_it
->size() - 2), component_pattern
.get())) {
135 ip_mask_
.push_back(false);
136 component_patterns_
.push_back(component_pattern
.release());
141 bool IPPattern::ParseComponentPattern(const base::StringPiece
& text
,
142 ComponentPattern
* pattern
) const {
143 // We're given a comma separated set of ranges, some of which may be simple
146 base::SplitString(text
.as_string(), ',', &ranges
);
147 for (Strings::iterator range_it
= ranges
.begin();
148 range_it
!= ranges
.end(); ++range_it
) {
149 base::StringTokenizer
range_pair(*range_it
, "-");
151 range_pair
.GetNext();
152 if (!ValueTextToInt(range_pair
.token(), &min
))
154 uint32_t max
= min
; // Sometimes we have no distinct max.
155 if (range_pair
.GetNext()) {
156 if (!ValueTextToInt(range_pair
.token(), &max
))
159 if (range_pair
.GetNext()) {
160 // Too many "-" in this range specifier.
161 DVLOG(1) << "Too many hyphens in range: ";
164 pattern
->AppendRange(min
, max
);
169 bool IPPattern::ValueTextToInt(const base::StringPiece
& input
,
170 uint32_t* output
) const {
171 bool ok
= is_ipv4_
? base::StringToUint(input
, output
) :
172 base::HexStringToUInt(input
, output
);
174 DVLOG(1) << "Could not convert value to number: " << input
;
177 if (is_ipv4_
&& *output
> 255u) {
178 DVLOG(1) << "IPv4 component greater than 255";
181 if (!is_ipv4_
&& *output
> 0xFFFFu
) {
182 DVLOG(1) << "IPv6 component greater than 0xFFFF";