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. 4 5 #include "net/base/ip_pattern.h" 6 7 #include <string> 8 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" 15 16 namespace net { 17 18 class IPPattern::ComponentPattern { 19 public: 20 ComponentPattern(); 21 void AppendRange(uint32 min, uint32 max); 22 bool Match(uint32 value) const; 23 24 private: 25 struct Range { 26 public: 27 Range(uint32 min, uint32 max) : minimum(min), maximum(max) {} 28 uint32 minimum; 29 uint32 maximum; 30 }; 31 typedef std::vector<Range> RangeVector; 32 33 RangeVector ranges_; 34 35 DISALLOW_COPY_AND_ASSIGN(ComponentPattern); 36 }; 37 38 IPPattern::ComponentPattern::ComponentPattern() {} 39 40 void IPPattern::ComponentPattern::AppendRange(uint32 min, uint32 max) { 41 ranges_.push_back(Range(min, max)); 42 } 43 44 bool IPPattern::ComponentPattern::Match(uint32 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) 50 return true; 51 } 52 return false; 53 } 54 55 IPPattern::IPPattern() : is_ipv4_(true) {} 56 57 IPPattern::~IPPattern() { 58 STLDeleteElements(&component_patterns_); 59 } 60 61 bool IPPattern::Match(const IPAddressNumber& address) const { 62 if (ip_mask_.empty()) 63 return false; 64 bool address_is_ipv4 = address.size() == kIPv4AddressSize; 65 if (address_is_ipv4 != is_ipv4_) 66 return false; 67 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 value_to_test = address[address_index++]; 75 if (!is_ipv4_) { 76 value_to_test = (value_to_test << 8) + address[address_index++]; 77 } 78 if (ip_mask_[i]) { 79 if (component_values_[fixed_value_index++] != value_to_test) 80 return false; 81 continue; 82 } 83 if (!(*pattern_it)->Match(value_to_test)) 84 return false; 85 ++pattern_it; 86 } 87 return true; 88 } 89 90 bool IPPattern::ParsePattern(const std::string& ip_pattern) { 91 DCHECK(ip_mask_.empty()); 92 if (ip_pattern.find(':') != std::string::npos) { 93 is_ipv4_ = false; 94 } 95 Strings components; 96 base::SplitString(ip_pattern, is_ipv4_ ? '.' : ':', &components); 97 if (components.size() != (is_ipv4_ ? 4u : 8u)) { 98 DVLOG(1) << "Invalid component count: " << ip_pattern; 99 return false; 100 } 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; 105 return false; 106 } 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. 112 uint32 value; 113 if (!ValueTextToInt(*component_it, &value)) 114 return false; 115 ip_mask_.push_back(true); 116 component_values_.push_back(value); 117 continue; 118 } 119 if ((*component_it)[component_it->size() - 1] != ']') { 120 DVLOG(1) << "Missing close bracket: " << ip_pattern; 121 return false; 122 } 123 // Now we know the size() is at least 2. 124 if (component_it->size() == 2) { 125 DVLOG(1) << "Empty bracket: " << ip_pattern; 126 return false; 127 } 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())) { 133 return false; 134 } 135 ip_mask_.push_back(false); 136 component_patterns_.push_back(component_pattern.release()); 137 } 138 return true; 139 } 140 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 144 // constants. 145 Strings ranges; 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, "-"); 150 uint32 min = 0; 151 range_pair.GetNext(); 152 if (!ValueTextToInt(range_pair.token(), &min)) 153 return false; 154 uint32 max = min; // Sometimes we have no distinct max. 155 if (range_pair.GetNext()) { 156 if (!ValueTextToInt(range_pair.token(), &max)) 157 return false; 158 } 159 if (range_pair.GetNext()) { 160 // Too many "-" in this range specifier. 161 DVLOG(1) << "Too many hyphens in range: "; 162 return false; 163 } 164 pattern->AppendRange(min, max); 165 } 166 return true; 167 } 168 169 bool IPPattern::ValueTextToInt(const base::StringPiece& input, 170 uint32* output) const { 171 bool ok = is_ipv4_ ? base::StringToUint(input, output) : 172 base::HexStringToUInt(input, output); 173 if (!ok) { 174 DVLOG(1) << "Could not convert value to number: " << input; 175 return false; 176 } 177 if (is_ipv4_ && *output > 255u) { 178 DVLOG(1) << "IPv4 component greater than 255"; 179 return false; 180 } 181 if (!is_ipv4_ && *output > 0xFFFFu) { 182 DVLOG(1) << "IPv6 component greater than 0xFFFF"; 183 return false; 184 } 185 return ok; 186 } 187 188 } // namespace net 189