PluginProbe ʕ •ᴥ•ʔ
Wordfence Security – Firewall, Malware Scan, and Login Security / 7.3.3
Wordfence Security – Firewall, Malware Scan, and Login Security v7.3.3
8.2.2 8.2.1 8.2.0 3.7.1 3.7.2 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.8.8 3.8.9 3.9.1 4.0.1 4.0.2 4.0.3 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.0.9 5.1.1 5.1.2 5.1.4 5.1.5 5.1.6 5.1.7 5.1.8 5.1.9 5.2.1 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.1 5.3.10 5.3.11 5.3.12 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.3.8 5.3.9 6.0.1 6.0.10 6.0.11 6.0.12 6.0.14 6.0.15 6.0.16 6.0.17 6.0.18 6.0.19 6.0.2 6.0.20 6.0.21 6.0.22 6.0.23 6.0.24 6.0.25 6.0.3 6.0.4 6.0.5 6.0.6 6.0.7 6.0.8 6.0.9 6.1.1 6.1.10 6.1.11 6.1.12 6.1.14 6.1.15 6.1.16 6.1.17 6.1.2 6.1.3 6.1.4 6.1.5 6.1.6 6.1.7 6.1.8 6.1.9 6.2.0 6.2.1 6.2.10 6.2.2 6.2.3 6.2.4 6.2.5 6.2.6 6.2.7 6.2.8 6.2.9 6.3.0 6.3.1 6.3.10 6.3.11 6.3.12 6.3.14 6.3.15 6.3.16 6.3.17 6.3.18 6.3.19 6.3.2 6.3.20 6.3.21 6.3.22 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.3.8 6.3.9 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1.0 7.1.1 7.1.10 7.1.11 7.1.12 7.1.14 7.1.15 7.1.16 7.1.17 7.1.18 7.1.19 7.1.2 7.1.20 7.1.3 7.1.4 7.1.5 7.1.6 7.1.7 7.1.8 7.1.9 7.10.0 7.10.1 7.10.2 7.10.3 7.10.4 7.10.5 7.10.6 7.10.7 7.11.0 7.11.1 7.11.2 7.11.3 7.11.4 7.11.5 7.11.6 7.11.7 7.2.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3.1 7.3.2 7.3.3 7.3.4 7.3.5 7.3.6 7.4.0 7.4.1 7.4.10 7.4.11 7.4.12 7.4.14 7.4.2 7.4.3 trunk 7.4.4 1.1 7.4.5 1.2 7.4.6 1.3 7.4.7 1.3.1 7.4.8 1.3.2 7.4.9 1.3.3 7.5.0 1.4.2 7.5.1 1.4.3 7.5.10 1.4.4 7.5.11 1.4.5 7.5.2 1.4.6 7.5.3 1.4.7 7.5.4 1.4.8 7.5.5 1.5.1 7.5.6 1.5.2 7.5.7 1.5.3 7.5.8 1.5.4 7.5.9 1.5.5 7.6.0 1.5.6 7.6.1 2.0.1 7.6.2 2.0.2 7.7.0 2.0.3 7.7.1 2.0.5 7.8.0 2.0.6 7.8.1 2.0.7 7.8.2 2.1.0 7.9.0 2.1.1 7.9.1 2.1.2 7.9.2 2.1.3 7.9.3 2.1.4 8.0.0 2.1.5 8.0.1 3.0.2 8.0.2 3.0.3 8.0.3 3.0.4 8.0.4 3.0.5 8.0.5 3.0.6 8.1.0 3.0.7 8.1.1 3.0.8 8.1.2 3.0.9 8.1.3 3.1.0 8.1.4 3.1.1 v1.4.1 3.1.2 3.1.4 3.1.6 3.2.1 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.4.1 3.4.4 3.4.5 3.5.1 3.5.2 3.6.1 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.6.9
wordfence / waf / wfWAFUserIPRange.php
wordfence / waf Last commit date
.htaccess 7 years ago bootstrap.php 7 years ago wfWAFGeoIP2.php 7 years ago wfWAFIPBlocksController.php 7 years ago wfWAFUserIPRange.php 7 years ago
wfWAFUserIPRange.php
261 lines
1 <?php
2 if (!defined('WFWAF_RUN_COMPLETE')) {
3
4 /**
5 *
6 */
7 class wfWAFUserIPRange {
8
9 /**
10 * @var string|null
11 */
12 private $ip_string;
13
14 /**
15 * @param string|null $ip_string
16 */
17 public function __construct($ip_string = null) {
18 $this->setIPString($ip_string);
19 }
20
21 public function isIPInRange($ip) {
22 $ip_string = $this->getIPString();
23
24 if (strpos($ip_string, '/') !== false) { //CIDR range -- 127.0.0.1/24
25 return wfWAFUtils::subnetContainsIP($ip_string, $ip);
26 }
27 else if (strpos($ip_string, '[') !== false) //Bracketed range -- 127.0.0.[1-100]
28 {
29 // IPv4 range
30 if (strpos($ip_string, '.') !== false && strpos($ip, '.') !== false) {
31 // IPv4-mapped-IPv6
32 if (preg_match('/:ffff:([^:]+)$/i', $ip_string, $matches)) {
33 $ip_string = $matches[1];
34 }
35 if (preg_match('/:ffff:([^:]+)$/i', $ip, $matches)) {
36 $ip = $matches[1];
37 }
38
39 // Range check
40 if (preg_match('/\[\d+\-\d+\]/', $ip_string)) {
41 $IPparts = explode('.', $ip);
42 $whiteParts = explode('.', $ip_string);
43 $mismatch = false;
44 if (count($whiteParts) != 4 || count($IPparts) != 4) {
45 return false;
46 }
47
48 for ($i = 0; $i <= 3; $i++) {
49 if (preg_match('/^\[(\d+)\-(\d+)\]$/', $whiteParts[$i], $m)) {
50 if ($IPparts[$i] < $m[1] || $IPparts[$i] > $m[2]) {
51 $mismatch = true;
52 }
53 }
54 else if ($whiteParts[$i] != $IPparts[$i]) {
55 $mismatch = true;
56 }
57 }
58 if ($mismatch === false) {
59 return true; // Is whitelisted because we did not get a mismatch
60 }
61 }
62 else if ($ip_string == $ip) {
63 return true;
64 }
65
66 // IPv6 range
67 }
68 else if (strpos($ip_string, ':') !== false && strpos($ip, ':') !== false) {
69 $ip = strtolower(wfWAFUtils::expandIPv6Address($ip));
70 $ip_string = strtolower(self::expandIPv6Range($ip_string));
71 if (preg_match('/\[[a-f0-9]+\-[a-f0-9]+\]/i', $ip_string)) {
72 $IPparts = explode(':', $ip);
73 $whiteParts = explode(':', $ip_string);
74 $mismatch = false;
75 if (count($whiteParts) != 8 || count($IPparts) != 8) {
76 return false;
77 }
78
79 for ($i = 0; $i <= 7; $i++) {
80 if (preg_match('/^\[([a-f0-9]+)\-([a-f0-9]+)\]$/i', $whiteParts[$i], $m)) {
81 $ip_group = hexdec($IPparts[$i]);
82 $range_group_from = hexdec($m[1]);
83 $range_group_to = hexdec($m[2]);
84 if ($ip_group < $range_group_from || $ip_group > $range_group_to) {
85 $mismatch = true;
86 break;
87 }
88 }
89 else if ($whiteParts[$i] != $IPparts[$i]) {
90 $mismatch = true;
91 break;
92 }
93 }
94 if ($mismatch === false) {
95 return true; // Is whitelisted because we did not get a mismatch
96 }
97 }
98 else if ($ip_string == $ip) {
99 return true;
100 }
101 }
102 }
103 else if (strpos($ip_string, '-') !== false) { //Linear range -- 127.0.0.1 - 127.0.1.100
104 list($ip1, $ip2) = explode('-', $ip_string);
105 $ip1N = wfWAFUtils::inet_pton($ip1);
106 $ip2N = wfWAFUtils::inet_pton($ip2);
107 $ipN = wfWAFUtils::inet_pton($ip);
108 return (strcmp($ip1N, $ipN) <= 0 && strcmp($ip2N, $ipN) >= 0);
109 }
110 else { //Treat as a literal IP
111 $ip1 = @wfWAFUtils::inet_pton($ip_string);
112 $ip2 = @wfWAFUtils::inet_pton($ip);
113 if ($ip1 !== false && $ip1 == $ip2) {
114 return true;
115 }
116 }
117
118 return false;
119 }
120
121 /**
122 * Expand a compressed printable range representation of an IPv6 address.
123 *
124 * @todo Hook up exceptions for better error handling.
125 * @todo Allow IPv4 mapped IPv6 addresses (::ffff:192.168.1.1).
126 * @param string $ip_range
127 * @return string
128 */
129 public static function expandIPv6Range($ip_range) {
130 $colon_count = substr_count($ip_range, ':');
131 $dbl_colon_count = substr_count($ip_range, '::');
132 if ($dbl_colon_count > 1) {
133 return false;
134 }
135 $dbl_colon_pos = strpos($ip_range, '::');
136 if ($dbl_colon_pos !== false) {
137 $ip_range = str_replace('::', str_repeat(':0000',
138 (($dbl_colon_pos === 0 || $dbl_colon_pos === strlen($ip_range) - 2) ? 9 : 8) - $colon_count) . ':', $ip_range);
139 $ip_range = trim($ip_range, ':');
140 }
141 $colon_count = substr_count($ip_range, ':');
142 if ($colon_count != 7) {
143 return false;
144 }
145
146 $groups = explode(':', $ip_range);
147 $expanded = '';
148 foreach ($groups as $group) {
149 if (preg_match('/\[([a-f0-9]{1,4})\-([a-f0-9]{1,4})\]/i', $group, $matches)) {
150 $expanded .= sprintf('[%s-%s]', str_pad(strtolower($matches[1]), 4, '0', STR_PAD_LEFT), str_pad(strtolower($matches[2]), 4, '0', STR_PAD_LEFT)) . ':';
151 } else if (preg_match('/[a-f0-9]{1,4}/i', $group)) {
152 $expanded .= str_pad(strtolower($group), 4, '0', STR_PAD_LEFT) . ':';
153 } else {
154 return false;
155 }
156 }
157 return trim($expanded, ':');
158 }
159
160 /**
161 * @return bool
162 */
163 public function isValidRange() {
164 return $this->isValidCIDRRange() || $this->isValidBracketedRange() || $this->isValidLinearRange() || filter_var($this->getIPString(), FILTER_VALIDATE_IP) !== false;
165 }
166
167 public function isValidCIDRRange() { //e.g., 192.0.2.1/24
168 $ip_string = $this->getIPString();
169 if (preg_match('/[^0-9a-f:\/\.]/i', $ip_string)) { return false; }
170 $components = explode('/', $ip_string);
171 if (count($components) != 2) { return false; }
172
173 list($ip, $prefix) = $components;
174 if (filter_var($ip, FILTER_VALIDATE_IP) === false) { return false; }
175
176 if (!preg_match('/^\d+$/', $prefix)) { return false; }
177
178 if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
179 if ($prefix < 0 || $prefix > 32) { return false; }
180 }
181 else {
182 if ($prefix < 1 || $prefix > 128) { return false; }
183 }
184
185 return true;
186 }
187
188 public function isValidBracketedRange() { //e.g., 192.0.2.[1-10]
189 $ip_string = $this->getIPString();
190 if (preg_match('/[^0-9a-f:\.\[\]\-]/i', $ip_string)) { return false; }
191 if (strpos($ip_string, '.') !== false) { //IPv4
192 if (preg_match_all('/(\d+)/', $ip_string, $matches) > 0) {
193 foreach ($matches[1] as $match) {
194 $group = (int) $match;
195 if ($group > 255 || $group < 0) {
196 return false;
197 }
198 }
199 }
200
201 $group_regex = '([0-9]{1,3}|\[[0-9]{1,3}\-[0-9]{1,3}\])';
202 return preg_match('/^' . str_repeat("{$group_regex}\\.", 3) . $group_regex . '$/i', $ip_string) > 0;
203 }
204
205 //IPv6
206 if (strpos($ip_string, '::') !== false) {
207 $ip_string = self::expandIPv6Range($ip_string);
208 }
209 if (!$ip_string) {
210 return false;
211 }
212 $group_regex = '([a-f0-9]{1,4}|\[[a-f0-9]{1,4}\-[a-f0-9]{1,4}\])';
213 return preg_match('/^' . str_repeat("$group_regex:", 7) . $group_regex . '$/i', $ip_string) > 0;
214 }
215
216 public function isValidLinearRange() { //e.g., 192.0.2.1-192.0.2.100
217 $ip_string = $this->getIPString();
218 if (preg_match('/[^0-9a-f:\.\-]/i', $ip_string)) { return false; }
219 list($ip1, $ip2) = explode("-", $ip_string);
220 $ip1N = @wfWAFUtils::inet_pton($ip1);
221 $ip2N = @wfWAFUtils::inet_pton($ip2);
222
223 if ($ip1N === false || filter_var($ip1, FILTER_VALIDATE_IP) === false || $ip2N === false || filter_var($ip2, FILTER_VALIDATE_IP) === false) {
224 return false;
225 }
226
227 return strcmp($ip1N, $ip2N) <= 0;
228 }
229
230 protected function _sanitizeIPRange($ip_string) {
231 $ip_string = preg_replace('/\s/', '', $ip_string); //Strip whitespace
232 $ip_string = preg_replace('/[\\x{2013}-\\x{2015}]/u', '-', $ip_string); //Non-hyphen dashes to hyphen
233 $ip_string = strtolower($ip_string);
234
235 if (preg_match('/^\d+-\d+$/', $ip_string)) { //v5 32 bit int style format
236 list($start, $end) = explode('-', $ip_string);
237 $start = long2ip($start);
238 $end = long2ip($end);
239 $ip_string = "{$start}-{$end}";
240 }
241
242 return $ip_string;
243 }
244
245
246 /**
247 * @return string|null
248 */
249 public function getIPString() {
250 return $this->ip_string;
251 }
252
253 /**
254 * @param string|null $ip_string
255 */
256 public function setIPString($ip_string) {
257 $this->ip_string = $this->_sanitizeIPRange($ip_string);
258 }
259 }
260 }
261