get_first_wan_ip.php
#78
by
doekia
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
<?php
trait get_first_wan_ip {
/**
* Recover the first wild (wan) ip of the client if proxies get traversed
* Return the first ip skipping all combination of LAN<->Trusted
*
* @copyright (c)2017 doekia Enter-Solutions
* @licence GPL
* If you like it, you can support the author https://ko-fi.com/A153227G
*
* @param array $trusted the list of trusted proxies (i.e: the information they passthru is guaranteed not to have be tampered)
* @return string the first non trusted ip
*/
public function get_first_wan_ip($trusted = array()) {
$wan_ip = $_SERVER['REMOTE_ADDR'];
// Filter out non routable ips. They are treated separatedly
foreach($trusted as &$t) {
if ( filter_var($t, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE|FILTER_FLAG_NO_RES_RANGE|FILTER_FLAG_IPV4|FILTER_FLAG_IPV6) === false ) {
$t = null;
}
}
unset($t);
$trusted = array_filter($trusted);
// Always trust the current local ip if this is not already a loopback/lan (alternate ip should be in the trusted list)
if (filter_var($_SERVER['SERVER_ADDR'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE|FILTER_FLAG_NO_RES_RANGE|FILTER_FLAG_IPV4|FILTER_FLAG_IPV6) !== false) {
$trusted[] = $_SERVER['SERVER_ADDR'];
}
$ip_fields = array(
'HTTP_CLIENT_IP',
'HTTP_X_FORWARDED_FOR',
'HTTP_X_FORWARDED',
'HTTP_FORWARDED_FOR',
'HTTP_FORWARDED',
'HTTP_X_CLUSTER_CLIENT_IP',
'HTTP_CF_CONNECTING_IP',
);
foreach ( $ip_fields as $key ) {
if ( array_key_exists( $key, $_SERVER ) === true ) {
$proxy_list = explode( ',', $_SERVER[$key]);
// Reverse the list so we start from the closest proxy
$proxy_list = array_reverse($proxy_list);
$last = null;
$lan = false;
// Check loopback / LAN based forwarder
if(filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4|FILTER_FLAG_IPV6) !== false) {
// valid ip ?
if ( filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE|FILTER_FLAG_IPV4|FILTER_FLAG_IPV6) === false ) {
// valid but private ? this is LAN or LOOPBACK, let's trust
$last = $_SERVER['REMOTE_ADDR'];
$lan = true;
}
}
foreach ( $proxy_list as $k => &$ip ) {
$ip = trim( $ip );
if(is_null($last) || filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4|FILTER_FLAG_IPV6) === false) {
// There is no trusted last or this is an invalid ip, bailout
break;
}
if ($lan && filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE|FILTER_FLAG_IPV4|FILTER_FLAG_IPV6) === false ) {
// Seems we are in the LAN still, continue to trust
$last = $ip;
continue;
}
(in_array($last, $trusted) || $lan) && $wan_ip = $ip;
!in_array($ip, $trusted) && $lan = false;
if (in_array($ip, $trusted)) {
$last = $ip;
}
else {
$last = null;
}
}
}
}
return $wan_ip;
}
}