Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/support/startup/preamble-utils.php
12240 views
1
<?php
2
3
/**
4
* Parse the "X_FORWARDED_FOR" HTTP header to determine the original client
5
* address.
6
*
7
* @param int Number of devices to trust.
8
* @return void
9
*/
10
function preamble_trust_x_forwarded_for_header($layers = 1) {
11
if (!is_int($layers) || ($layers < 1)) {
12
echo
13
'preamble_trust_x_forwarded_for_header(<layers>): '.
14
'"layers" parameter must an integer larger than 0.'."\n";
15
echo "\n";
16
exit(1);
17
}
18
19
if (!isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
20
return;
21
}
22
23
$forwarded_for = $_SERVER['HTTP_X_FORWARDED_FOR'];
24
if ($forwarded_for === null || !strlen($forwarded_for)) {
25
return;
26
}
27
28
$address = preamble_get_x_forwarded_for_address($forwarded_for, $layers);
29
30
$_SERVER['REMOTE_ADDR'] = $address;
31
}
32
33
function preamble_get_x_forwarded_for_address($raw_header, $layers) {
34
// The raw header may be a list of IPs, like "1.2.3.4, 4.5.6.7", if the
35
// request the load balancer received also had this header. In particular,
36
// this happens routinely with requests received through a CDN, but can also
37
// happen illegitimately if the client just makes up an "X-Forwarded-For"
38
// header full of lies.
39
40
// We can only trust the N elements at the end of the list which correspond
41
// to network-adjacent devices we control. Usually, we're behind a single
42
// load balancer and "N" is 1, so we want to take the last element in the
43
// list.
44
45
// In some cases, "N" may be more than 1, if the network is configured so
46
// that that requests are routed through multiple layers of load balancers
47
// and proxies. In this case, we want to take the Nth-to-last element of
48
// the list.
49
50
$addresses = explode(',', $raw_header);
51
52
// If we have more than one trustworthy device on the network path, discard
53
// corresponding elements from the list. For example, if we have 7 devices,
54
// we want to discard the last 6 elements of the list.
55
56
// The final device address does not appear in the list, since devices do
57
// not append their own addresses to "X-Forwarded-For".
58
59
$discard_addresses = ($layers - 1);
60
61
// However, we don't want to throw away all of the addresses. Some requests
62
// may originate from within the network, and may thus not have as many
63
// addresses as we expect. If we have fewer addresses than trustworthy
64
// devices, discard all but one address.
65
66
$max_discard = (count($addresses) - 1);
67
68
$discard_count = min($discard_addresses, $max_discard);
69
if ($discard_count) {
70
$addresses = array_slice($addresses, 0, -$discard_count);
71
}
72
73
$original_address = end($addresses);
74
$original_address = trim($original_address);
75
76
return $original_address;
77
}
78
79