Why is fopen() giving me a different IP than $_SERVER['SERVER_ADDR']? - php

Using this code:
On server A I have this:
$handle = fopen('http://www.server_b.com/get_ip.php', 'r'); //This is just a PHP file that echoes the REMOTE_ADDR
echo "IP looks like ".fread($handle, '100000')." to external server.\n";
fclose($handle);
echo "IP looks like ".$_SERVER['SERVER_ADDR']." to this server.";
on server B I have this:
echo $_SERVER['REMOTE_ADDR'];
I'm getting the following output from server A:
IP looks like xxx.xxx.223.90 to external server. //xxx.xxx on both lines are the same
IP looks like xxx.xxx.223.94 to this server.
Why am I getting two different IPs? Note, we do own the IP range from .90-.94

Since it's a VPS, what you're probably seeing on server_b is the IP address of the host machine of the VPS that server_a is running on.
Either that, or there's some other proxying mechanism going on.
There may be a way around this:
Do a print_r() of $_SERVER on server_b.
Depending on the config of the various servers involved, in addition to the REMOTE_ADDR you may also get a value like $_SERVER['HTTP_FORWARDED']. This will be the IP address of the originating machine being passed on by the proxy, and should be the one you're expecting.
This question may help you further: What is the most accurate way to retrieve a user's correct IP address in PHP?

Related

How to restrict website accessing, if user is on remote device and not on a work computer? (work time tracker app)

I would like to make a PHP website, where employees can log in/out themselves and these logs will count as a time when they started and ended their working day. I would like to allow them to do that only on their work computer and not for example on their phone while they are still on the way, but they want to avoid "being late".
So I'm struggling with a few ideas, but any of them seems to be the right solution.
Allow using the website only for specific IP addresses. But then I realized that in our place IP address is dynamic and changing it for static costs too much in our area.
Check user location. But then I saw that when I'm checking my public IP address, the location is completely wrong! Our building isn't even close to the loaded area.
Using a COOKIE/token on a work computer. But it's very easy to set the same cookie on your own device and I'm not the only IT employee here.
Checking MAC address. As I read here it's possible only in specific cases.
Block access for mobiles. But detecting a mobile is based on browser and if the user click "Request Desktop Site" scripts will say that's a computer.
Is there another method, which I can use to achieve my goal? Am I missing something?
May I bind my app for example with some other technologies that will allow me to do that? Or maybe I should try a combination of all of them?
I couldn't find any script, which would take care of that. In the worst case it doesn't have to be "perfectly secure", but I would like to be it at least hard, annoying, or time-consuming to try to "cheat" in this system.
I would run your app in the office LAN. Nobody will be able to access it from outside except if they can do remote desktop to the office computer or if they have VPN. But if you are in the IT team you may could fix IP ranges for the office computers so that you could exclude the VPN.
In terms of security, in any case it may be better having it running in your LAN. I'm sure you've got a server somewhere and if it's not the case then you could use a NAS (Synology offers NGINX, Apache, PHP and much more) or a little Rasperry Pie or something similar.
If you haven't got a fixed IP, you could also use DynDNS and have it mapped to a sub-domain such as company-name.dyndns.org and then on your PHP app you could have a cron job that gets the IP address from the domain name and updates it every minutes (I'm sure it's quickly run). It could then store it inside a config file, this way:
<?php
define('ALLOWED_IP_FILE', 'allowed-ips.inc.php');
$ALLOWED_DOMAINS = [
'your-company.dyndns.org',
'you-at-home.dyndns.org',
];
$allowed_ips = [];
foreach ($ALLOWED_DOMAINS as $allowed_domain) {
$ip = gethostbyname($allowed_domain);
if ($ip !== $allowed_domain) {
// Store with the IP in the key and value for ease when checking the IP validity.
$allowed_ips[$ip] = $ip;
} else {
fprintf(STDERR, "ERROR: Could not find the IP of $allowed_domain!\n");
}
}
$allowed_ips_export = var_export($allowed_ips, true);
$config_file_content = <<<END_OF_CONFIG
<?php
// Don't edit! This config file is generated by cron-ip-address.php.
\$ALLOWED_IPS = $allowed_ips_export;
END_OF_CONFIG;
if (file_put_contents(ALLOWED_IP_FILE, $config_file_content) === false) {
fprintf(STDERR, 'ERROR: Could not write config file ' . ALLOWED_IP_FILE . "\n");
}
This generates a config file to include in your app. Example of content generated if you run the script I wrote above:
<?php
// Don't edit! This config file is generated by cron-ip-address.php.
$ALLOWED_IPS = array (
'142.250.203.99' => '142.250.203.99',
'23.201.250.169' => '23.201.250.169',
);
Now, in your app, just include it and test the presence of the IP in the $ALLOWED_IPS array:
<?php
include ALLOWED_IP_FILE; // If this is declared in a common config file.
// include 'allowed-ips.inc.php'; // If you haven't got a common config file.
if (!isset($ALLOWED_IPS[$_SERVER['REMOTE_ADDR']])) {
http_response_code(403);
die('Sorry, you cannot access it from here.');
}
Ideally, if what you actually want to track is when employees are in the workplace and logged on / for how long, it would be probably better to just track local machine-logins via a domain controller - a method reachable from the internet is suboptimal exactly for the reasons you mentioned.
If you have an intranet which users cannot tunnel into but can access from their work machines, I'd say hosting your login-page only inside that intranet is the easiest way to achieve what you want with the methods you suggest.
Alternatively, if employee work-machines use windows under a domain controller - you can restrict access to Windows certificate-storage, then install/push a certificate and require that to be present via your server-configuration. In that case, it doesn't matter if the website is accessible from the internet. I'm sure there are similar solutions if work-machines are not on Windows.
This admittely old question gives some pointers in the right direction on how to require client certificates from a Webserver (IIS in that case).

How to get the Public IP

I'm trying to get the Public IP of someone that use the form of the page I do.
I don't know with which programming language would do that. I was reading on the web and I found some:
// PHP Code
$_SERVER["REMOTE_ADDR"]
This outputs: 127.0.0.1 (Local IP).
Then I found this too:
// PHP Code
$externalContent = file_get_contents('http://checkip.dyndns.com/');
preg_match('/\b(?:\d{1,3}\.){3}\d{1,3}\b/', $externalContent, $m);
$externalIp = $m[0];
This outputs the correct IP (Public IP), but that needs to use other web page (http://checkip.dyndns.com/).
I wonder How do the pages like that get the Public IP?. I am looking for a way to get it without need to use other web page. Thanks.
The $_SERVER["REMOTE_ADDR"] should work fine for what you are trying to do here. The reason you are getting 127.0.0.1 is because you are running this in a local environment.
If you put this script on a live webserver and I access it, you will get the same IP from $_SERVER["REMOTE_ADDR"] as I get when I check whatismyip
And anyhow, having the server call:
$externalContent = file_get_contents('http://checkip.dyndns.com/');
will only get you successful in returning your servers IP address, not the visitors.
This problem had me stumped for a long while.
If you have access to your own remote server, what I did to solve this problem was create a simple server-side script echo $_SERVER['REMOTE_ADDR']; to give me the public IP assigned by my ISP to my device from my localhost.

How to know domain name from IP address in PHP

As we know about PHP has an inbuilt function to get IP address of a domain name
<?php
$ip = gethostbyname('www.example.com');
echo $ip;
?>
But is there any way to know domain name from Ip address?
I have tried using gethostbyaddr but it din't worked.
<?php echo gethostbyaddr( '198.252.206.16' ); ?>
I think there should be some way of using the command dig in combination with PHP in Linux but I am not sure.
You can get the A adress of that server. If there are multiple websites on that webserver you do not get that information
Try using a valid IP address. I tried going to the IP address that you provided, but nothing was there.
If you have shell access, Unix/Linux servers can use this for a
timeout response:
shell_exec('host -W 2 0.0.0.0');
Where 0.0.0.0 is of course the IP, and '2' is the number of seconds
for the timeout. This returns a more detailed string of info, with
some additional text which might vary depending on the system, so if
you want a string with the hostname and nothing else, you'll have to
do some substring cutting.
Try this.

inet_pton does not work on local ip addresses like 10.0.1.4

<?php
//$ipaddress = $_SERVER['REMOTE_ADDR'];
$ipaddress = '10.0.1.4';
$binip = inet_pton($ipaddress);
echo $binip;
?>
It returns blank. If i use my public facing IP it returns the right result. It will return a result for 192.168.1.2(My old LinkSys router had a ip similar to this). I'm testing my app on a Linux machine i have with a local ip. All Machines that connect to it uses a internal ip 10.0.1.XX. My app uses MySQL and if the binip is blank, it gives me a error. So i am not sure of a work around for local ip. I was thinking maybe it has to do with detecting if its a local ip in that format and then edit the ipaddress variable so its valid for inet_pton some how. Any ideas?
It works for me. I get a binary structure from your example code (although, there's no printable characters in it so if you run it in a web browser you'll probably get nothing).
Actually, I even tried this code which outputs the original address and shows that there's no information loss going on:
<?php
$ipaddress = '10.0.1.4';
$binip = inet_pton($ipaddress);
echo inet_ntop($binip);
?>
Maybe you are more interested in ip2long which converts the address to an integer? Or maybe your problem is elsewhere, for example in escaping the data before putting it into a database?
You have similar issues here:
http://php.net/manual/en/function.inet-pton.php
You can find out solutions from there too. Check out how that function returns FALSE.

PHP - Domain to IP

I current have a system which works like this:
Insert IP and it will post the IP to another .php page. However, when I try post http://google.com it does not turn the domain into a IP.
How would I do that? E.g. when a user inserts http://google.com or any domain it will auto resolve the IP.
I know the function gethostbyadd, I dont know how to structure it out e.g. Forms, table, post data.
Thanks if any can help.
What have you got together so far? How is it failing?
A wild guess is that you're typing in http://google.com/ and trying to get an IP from that, and that will fail, as the URL contains protocol information as well. You need to pass the domain name, and only the domain name to gethostbyname:
gethostbyname('www.google.com'); // Works
gethostbyname('http://www.google.com'); // Will not work
If you have the protocol part (http://) in the beginning, you can use parse_url:
gethostbyname(parse_url('http://www.google.com', PHP_URL_HOST));
If you're having some other, specific problem, let us know. If you don't know where to start, I suggest start by reading up on a programming manual ;)
I think you're looking for gethostbyname:
$ip = gethostbyname('www.google.com');
Note, make sure you strip the http:// and any white space/trailing characters as this will likely prevent accurate results.
the function you are looking for is $x = gethostbyname('stackoverflow.com');
You probably need to look into using http://www.php.net/manual/en/function.gethostbynamel.php
In some people the function gethostbyname is running slowly or running once in a while. Some say that the apache needs rebooting to get the function started. I can not confirm this, but I want to give an alternative method how to find IP by Domain using nslookup
function getAddrByHost($host, $timeout = 1) {
$query = `nslookup -timeout=$timeout -retry=1 $host`;
if(preg_match('/\nAddress: (.*)\n/', $query, $matches))
return trim($matches[1]);
}
echo getAddrByHost('example.com');
speed test using XHProf:
attempt 1
gethostbyname 5,014,593 microsec
getAddrByHost 29,656 microsec
attempt 2
gethostbyname 5,016,678 microsec
getAddrByHost 13,887 microsec
attempt 3
gethostbyname 5,014,640 microsec
getAddrByHost 8,297 microsec
Conclusion: the function gethostbyname is performed for more than 5 seconds, which is very long. Therefore, I advise you to use a faster function getAddrByHost
note: php use this file /etc/resolv.conf to get DNS servers:
In my case I use BIND (named) which works on the host 127.0.0.1
# /etc/resolv.conf
nameserver 127.0.0.1
nameserver 8.8.8.8
nameserver 4.4.4.4

Categories