I have a script which sends a request to another server but problem is that IPv6 does not supported so if I send IPv6 then give error so i need this one of two:
Get IPv4 address all time
or
Get both IPv4 and IPv6 addresses
I use this code to get the IP address
function getRealIP()
{
if (isset($_SERVER["HTTP_CLIENT_IP"])) {
$ip = $_SERVER["HTTP_CLIENT_IP"];
} elseif (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) {
$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
} elseif (isset($_SERVER["HTTP_X_FORWARDED"])) {
$ip = $_SERVER["HTTP_X_FORWARDED"];
} elseif (isset($_SERVER["HTTP_FORWARDED_FOR"])) {
$ip = $_SERVER["HTTP_FORWARDED_FOR"];
} elseif (isset($_SERVER["HTTP_FORWARDED"])) {
$ip = $_SERVER["HTTP_FORWARDED"];
} else {
$ip = $_SERVER["REMOTE_ADDR"];
}
// Strip any secondary IP etc from the IP address
if (strpos($ip, ',') > 0) {
$ip = substr($ip, 0, strpos($ip, ','));
}
return $ip;
}
But this function only returns one IPv address. How can I get all time IPv4 or get both addresses?
A client will send a request to your server using only one protocol. It doesn't send the request using both IPv4 and IPv6 at the same time, and there's no way to interleave both protocols, and IPv4 addresses also don't translate into equivalent IPv6 addresses. If the client sent the request using IPv4, then you'll get the IPv4 address. If they sent the request using IPv6, you'll get the IPv6 address. Period. End of story.
If you require an IPv4 address, then you have to disable IPv6 support on your server/DNS entry, so all clients are forced to use IPv4 as the only available protocol. But that would also be a terrible step backwards in this day and age.
You can't.
Only the IP address the request came from is available.
There's no reliable way to identify other IP addresses (my laptop currently has 12 IP addresses) that route to the same computer.
This is just a thought but maybe the trick is how said client queries the server.
Its what I use to gain my Public WAN_IPv4 & Public WAN_IPv6 with a simple Cron job to fire every xx mins and update one of my DNS records
Why not go up a layer and query the hostname NS A and AAAA records itself?
$ dig dom.domain -A | grep "ip ..." [with some some regex to extract specific pattern.]
Or a combination of approaches, maybe even employ curl to grab the -ipv4 address and then use a direct call to "ping" the myip6.php script for IPv6 return.?
Or keep it simple via dns resolving on interface with cURL
$ curl --help all
...
--dns-interface <interface> Interface to use for DNS requests
--dns-ipv4-addr <address> IPv4 address to use for DNS requests
--dns-ipv6-addr <address> IPv6 address to use for DNS requests
--dns-servers <addresses> DNS server addrs to use
...
--interface <name> Use network INTERFACE (or address)
-4, --ipv4 Resolve names to IPv`enter code here`4 addresses
-6, --ipv6 Resolve names to IPv6 addresses
...
if using curl you can specify option -4 and -6 to indicate which IP stack to return its result
$ curl -4 dom.domain
OUTPUT:
> 255.255.255.255
The same can be done for IPv6 by using -6
$ curl -6 dom.domin
OUTPUT:
> 20a1:efef:ffff::0
Above can then of course can be piped out to either console or stored inside a _VAR for later use.
I mean this is not a direct method to answer your specific question BUT it does give you options when managing dual-ipstack machines and its what I do.
There is also a very good example on how you could use curl for this exact job [name-resolve-tricks-with-c-ares][1]
[1]: https://everything.curl.dev/usingcurl/connections/name#name-resolve-tricks-with-c-ares
Related
I am trying to code a PHP script for getting the client's IP address using this function:
public function getIpAddress() {
$ipAddress = '';
if (! empty($_SERVER['HTTP_CLIENT_IP']) && $this->isValidIpAddress($_SERVER['HTTP_CLIENT_IP'])) {
// check for shared ISP IP
$ipAddress = $_SERVER['HTTP_CLIENT_IP'];
} else if (! empty($_SERVER['HTTP_X_FORWARDED_FOR']) && $this->isValidIpAddress($_SERVER['HTTP_CLIENT_IP'])) {
// check for IPs passing through proxy servers
// check if multiple IP addresses are set and take the first one
$ipAddressList = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach ($ipAddressList as $ip) {
if ($this->isValidIpAddress($ip)) {
$ipAddress = $ip;
break;
}
}
} else if (! empty($_SERVER['HTTP_X_FORWARDED']) && $this->isValidIpAddress($_SERVER['HTTP_X_FORWARDED'])) {
$ipAddress = $_SERVER['HTTP_X_FORWARDED'];
} else if (! empty($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']) && $this->isValidIpAddress($_SERVER['HTTP_X_CLUSTER_CLIENT_IP'])) {
$ipAddress = $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
} else if (! empty($_SERVER['HTTP_FORWARDED_FOR']) && $this->isValidIpAddress($_SERVER['HTTP_FORWARDED_FOR'])) {
$ipAddress = $_SERVER['HTTP_FORWARDED_FOR'];
} else if (! empty($_SERVER['HTTP_FORWARDED']) && $this->isValidIpAddress($_SERVER['HTTP_FORWARDED'])) {
$ipAddress = $_SERVER['HTTP_FORWARDED'];
} else if (! empty($_SERVER['REMOTE_ADDR']) && $this->isValidIpAddress($_SERVER['REMOTE_ADDR'])) {
$ipAddress = $_SERVER['REMOTE_ADDR'];
}else{
$ipAddress = 'error';
}
return $ipAddress;
}
I tried it many times and it's working. But I tried to connect to a VPN and it retrieved IPv6 instead of IPv4!
This could be a normal situation but I need to get the IPv4 of the visitor of that PHP script.
I googled a lot about converting IPv6 to IPv4 and I know that it cannot be converted.
But I notices some IP geolocation services are retrieving IPv4 for the same VPN (on the same device)! For example: canyouseeme.org and api.ipify.org.
That's mean that even if the IPv6 cannot be converted into IPv4, there's a method can be implemented to get IPv4 even if the visitor is using IPv6!
My questions:
If the conversion is not possible between these two versions, how did these IP geolocation services retrieved the IPv4 of the visitor?
If they are not converting the IPv6 into IPv4. So, they are retrieving the IPv4 directly without touching the IPv6. But, how did they do that if the $_SERVER does not contain an IPv4?
In additional to that, I noticed that when I visited whatismyipaddress.com, they retrieved the IPv6 first then it start loading beside the IPv4 field then they retrieved it!
Note: All these sites has retrieved the same IPv4.
Thanks.
Just drop the AAAA record from your DNS name (or disable ipv6 in your webservrr - this might introduce delays as browsers are supposed to prefer ipv6), then, however, people w/o ipv4 cannot access your service any more. As #MagnusEriksson said: "Instead of fighting the future, wouldn't it be better to fix your application so it works with IPv6 as well?"
Also, please be aware, if the ip address is so important for you, that http headers can be easily spoofed by clients (i.e., don't trust user provided data) or proxy servers might provide private ips as defined in RFC1918. You should only consider/use the headers you know a trusted proxy infront of your server uses - in all other cases you cannot trust the user provided headers.
if you are using apache, you may want to check if there are any IPv6 Bindings or VirtualHosts. there will be similar settings for other web servers
if you don't have access to the web server config, you can see if there's an option to disable IPv6 in your webhost panel
also, this could be client-controlled, i.e. when you connect using a VPN then IPv6 is enabled for that network interface (or tunnel). in which case you cannot force the visitor to disable IPv6 on their device / router, but you could try to disable it on your end. unlike HTTPS Everywhere which only accepts port 443 or nothing, I don't think IP addresses are at the stage where it is only possible to accept IPv6 with no fallback to IPv4, so this recommendation should be safe
the code below used php functions to get me MX hostnames and their just ip version 4:
$results = dns_get_record($domain, DNS_MX);
foreach ($results as $res) {
$hostip = gethostbyname($res['target']);
}
i googled a lot about 'dig' and found "dig -t MX redhat.com +noall +answer" but it returns just the MX hostnames without their IPV4 and IPV6.
Is there a way to get the job done using "dig" or PHP Functions?
The MX record contains only hostnames, never IP addresses.
If you want to look up the IP address of a hostname you received, you will need to perform another DNS lookup. It appears that your code is already doing this (and then throwing away some of the results, which is a bug). But unless you intend to do something with the IP address other than open a connection, then you should probably just use the hostname.
Hello i am using this function to get IP Address of different systems..but everytime it returns the same value: 117.239.82.182
function getRealIpAddr()
{
if (!empty($_SERVER['HTTP_CLIENT_IP'])) //check ip from share internet
{
$ip=$_SERVER['HTTP_CLIENT_IP'];
}
elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) //to check ip is pass from proxy
{
$ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
}
else
{
$ip=$_SERVER['REMOTE_ADDR'];
}
return $ip;
}
EDIT: (The answer changed radically after some clarifications in the comments)
You could edit the User-Agent setting of the user's browsers. To see how to change the setting in various browsers follow this link. Then you should modify your PHP script to read User-Agent of the browser.
In PHP,$_SERVER['HTTP_USER_AGENT'] returns the browser's User-Agent setting. Eg. you can define as User-Agent something like Company/System/1.02 Bla bla bla. Then when you receive that same string you can assume it is coming from a known host.
Attention that the User-Agent can be easily spoofed. So this method is not secure. The secure solution would be to implement a VPN solution.
117.239.82.182 is an external IP address. If all the systems that connect to the PHP server are behind the same external IP address, all of them will be notet as the same IP address.
Your script doesn't take the local IP. Don't think it's even possible. The IP you are seeing, is the IP of the firewall of your company.
I would like to know whether there is any easy method to check whether an IP address is publicly accessible or is private.
More specifically. I know for example, that 127.0.0.1 is a private IP address that point into the same machine, 255.255.255.255 if for broadcasting into the same network, 192.168.1.0 is for local network addresses and so on. But how can I distinguish whether a given IP address is not one of the private IP and is publicly accessible?
http://en.wikipedia.org/wiki/Private_network lists the various ranges. Just construct an if statement.
Pulic/private IPv4 addresses are defined in RFC 5735. In short:
0.0.0.0/8 is invalid
127.0.0.0/8 is localhost
169.254.0.0/16 is an unconfigured IP. You should treat it like a local address
10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 are private networks
224.0.0.0/4 is multicast
Everything else is publicly reachable, or reserved
For IPv6, refer to RFC 5165. In short:
::/128 is the unspecified address, ::1/128 is localhost
::ffff:0:0/96 are IPv4-mapped addresses
fe80::/10 and fc00::/7 are private networks
ff00::/8 is multicast
Everything else is publicly reachable, or reserved
Note that services on machines without a public IP may still be reachable from the internet with the help of port forwarding or other firewall rules.
function validateIpAddress($ip_addr)
{
$result = true;
if(preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/",$ip_addr))
{
$parts=explode(".",$ip_addr);
foreach($parts as $ip_parts)
{
if(intval($ip_parts)>255 || intval($ip_parts)<0)
$result=false;
}
if (intval($parts[0])==0 || intval($parts[0])==10 || intval($parts[0])==127 || (intval($parts[0])>223 && intval($parts[0])<240))
{
$result=false;
}
if ((intval($parts[0])==192 && intval($parts[1])==168) || (intval($parts[0])==169 && intval($parts[1])==254))
{
$result=false;
}
if (intval($parts[0])==172 && intval($parts[1])>15 && intval($parts[1])<32 )
{
$result=false;
}
}
else
{
$result = false; //if format of ip address doesn't matches
}
return $result;
}
One solution is mentioned by Ed Heal, but there is another one:
Just connect to some external host and ask it for the IP it sees, like that (example for PHP):
$my_public_ip = file_get_contents('http://ip.42.pl/raw');
This specific example I know will return single string containing only an IP address. I do not know other services offering this, although there are probably plenty of them. The main page of the above script / service is: http://ip.42.pl/.
If you know similar services, please post their URLs in the comments, so future readers have other options.
I am this code to get the IP address on my locolhost and I get
::1
result
code is:
function ip()
{
if (!empty($_SERVER['HTTP_CLIENT_IP']))
{
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
{
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
else
{
$ip = $_SERVER['REMOTE_ADDR'];
}
return $ip;
}
echo ip();
where is error?
Actually, I want to get country & city name after I get IP... Any other solution?
Thanks
::1 is shorthand for localhost, using IPv6 terminology, so it is working. Try connecting using your hostname, and you should see the address change to be more obviously an address...
As #Roland writes it is an IPv6 address. If you don't intend on using IPv6 in your application then you should tell your web server to stop listening on IPv6 ports. When you send a request the client will try IPv6 first if it doesn't work then it will fall back to IPv4 and you should get the much more familiar looking 127.0.0.1.
You could use the following:
$server_address = $_SERVER['SERVER_ADDR'];
$port_used = $_SERVER['SERVER_PORT'];
$ip_address = $_SERVER['REMOTE_ADDR'];
// on my test machine this gives the following results:
$server_address = 127.0.0.1
$port_used = 80
$ip_address = 127.0.0.1
Edited: to include the geo-location aspect of the question, that I hadn't noticed 'til after I submitted the original answer.
Rather than repeat answers found elsewhere, I'll first link to this (well-answered) SO question:
google-geolocation-api-library, and then to the Google results page for the search terms geolocation php site:stackoverflow.com, which links to many other -probably relevant- answers that might better address your questions than I'm able.
If you print_r($_SERVER) you will see what information is available, what it looks like, and what fields might be empty.