1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// found in the LICENSE file. 4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/base/ip_pattern.h" 6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include <string> 8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/logging.h" 10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/stl_util.h" 12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/strings/string_number_conversions.h" 13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/strings/string_split.h" 14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/strings/string_tokenizer.h" 15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace net { 17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class IPPattern::ComponentPattern { 19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public: 20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ComponentPattern(); 21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) void AppendRange(uint32 min, uint32 max); 22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bool Match(uint32 value) const; 23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private: 25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) struct Range { 26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public: 27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Range(uint32 min, uint32 max) : minimum(min), maximum(max) {} 28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) uint32 minimum; 29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) uint32 maximum; 30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }; 31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) typedef std::vector<Range> RangeVector; 32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) RangeVector ranges_; 34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(ComponentPattern); 36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}; 37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)IPPattern::ComponentPattern::ComponentPattern() {} 39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void IPPattern::ComponentPattern::AppendRange(uint32 min, uint32 max) { 41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ranges_.push_back(Range(min, max)); 42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool IPPattern::ComponentPattern::Match(uint32 value) const { 45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Simple linear search should be fine, as we usually only have very few 46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // distinct ranges to test. 47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (RangeVector::const_iterator range_it = ranges_.begin(); 48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) range_it != ranges_.end(); ++range_it) { 49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (range_it->maximum >= value && range_it->minimum <= value) 50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return true; 51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)IPPattern::IPPattern() : is_ipv4_(true) {} 56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)IPPattern::~IPPattern() { 58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) STLDeleteElements(&component_patterns_); 59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool IPPattern::Match(const IPAddressNumber& address) const { 62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (ip_mask_.empty()) 63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bool address_is_ipv4 = address.size() == kIPv4AddressSize; 65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (address_is_ipv4 != is_ipv4_) 66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ComponentPatternList::const_iterator pattern_it(component_patterns_.begin()); 69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int fixed_value_index = 0; 70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // IPv6 |address| vectors have 16 pieces, while our |ip_mask_| has only 71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // 8, so it is easier to count separately. 72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int address_index = 0; 73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (size_t i = 0; i < ip_mask_.size(); ++i) { 74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) uint32 value_to_test = address[address_index++]; 75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!is_ipv4_) { 76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) value_to_test = (value_to_test << 8) + address[address_index++]; 77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (ip_mask_[i]) { 79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (component_values_[fixed_value_index++] != value_to_test) 80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) continue; 82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!(*pattern_it)->Match(value_to_test)) 84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ++pattern_it; 86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return true; 88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool IPPattern::ParsePattern(const std::string& ip_pattern) { 91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(ip_mask_.empty()); 92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (ip_pattern.find(':') != std::string::npos) { 93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) is_ipv4_ = false; 94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Strings components; 96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::SplitString(ip_pattern, is_ipv4_ ? '.' : ':', &components); 97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (components.size() != (is_ipv4_ ? 4u : 8u)) { 98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DVLOG(1) << "Invalid component count: " << ip_pattern; 99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (Strings::iterator component_it = components.begin(); 102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) component_it != components.end(); ++component_it) { 103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (component_it->empty()) { 104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DVLOG(1) << "Empty component: " << ip_pattern; 105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (*component_it == "*") { 108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Let standard code handle this below. 109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) *component_it = is_ipv4_ ? "[0-255]" : "[0-FFFF]"; 110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else if ((*component_it)[0] != '[') { 111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // This value will just have a specific integer to match. 112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) uint32 value; 113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!ValueTextToInt(*component_it, &value)) 114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ip_mask_.push_back(true); 116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) component_values_.push_back(value); 117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) continue; 118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if ((*component_it)[component_it->size() - 1] != ']') { 120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DVLOG(1) << "Missing close bracket: " << ip_pattern; 121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Now we know the size() is at least 2. 124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (component_it->size() == 2) { 125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DVLOG(1) << "Empty bracket: " << ip_pattern; 126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // We'll need a pattern to match this bracketed component. 129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_ptr<ComponentPattern> component_pattern(new ComponentPattern); 130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Trim leading and trailing bracket before calling for parsing. 131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!ParseComponentPattern(base::StringPiece(component_it->data() + 1, 132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) component_it->size() - 2), component_pattern.get())) { 133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ip_mask_.push_back(false); 136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) component_patterns_.push_back(component_pattern.release()); 137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return true; 139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool IPPattern::ParseComponentPattern(const base::StringPiece& text, 142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ComponentPattern* pattern) const { 143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // We're given a comma separated set of ranges, some of which may be simple 144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // constants. 145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Strings ranges; 146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::SplitString(text.as_string(), ',', &ranges); 147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (Strings::iterator range_it = ranges.begin(); 148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) range_it != ranges.end(); ++range_it) { 149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::StringTokenizer range_pair(*range_it, "-"); 150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) uint32 min = 0; 151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) range_pair.GetNext(); 152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!ValueTextToInt(range_pair.token(), &min)) 153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) uint32 max = min; // Sometimes we have no distinct max. 155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (range_pair.GetNext()) { 156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!ValueTextToInt(range_pair.token(), &max)) 157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (range_pair.GetNext()) { 160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Too many "-" in this range specifier. 161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DVLOG(1) << "Too many hyphens in range: "; 162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) pattern->AppendRange(min, max); 165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return true; 167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool IPPattern::ValueTextToInt(const base::StringPiece& input, 170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) uint32* output) const { 171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bool ok = is_ipv4_ ? base::StringToUint(input, output) : 172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::HexStringToUInt(input, output); 173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!ok) { 174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DVLOG(1) << "Could not convert value to number: " << input; 175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (is_ipv4_ && *output > 255u) { 178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DVLOG(1) << "IPv4 component greater than 255"; 179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!is_ipv4_ && *output > 0xFFFFu) { 182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DVLOG(1) << "IPv6 component greater than 0xFFFF"; 183a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return ok; 186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} // namespace net 189