5

I wish to detect if an address IP is local or external. In a web application, my customer wish to access files directly through samba on local network, and by a download link if you are not in the network.

I may just check if my IP is 172.30.*.*, but it won't work anymore if my customer switch to a 10.*.*.* or IPV6.

I may use a config var, so the customer may change it at will. I would like it to be automatic, with no config var.

How would you proceed ?

j0k
  • 22,600
  • 28
  • 79
  • 90
Perello
  • 633
  • 1
  • 7
  • 22
  • There's nothing in a normal request that would indicate internal or external origin. All you have to go on is the ip address sent in the request. – Mike B Jan 02 '13 at 16:44
  • 3
    To see if an IP is on the same network, you take your subnet mask and perform a bitwise AND with your own IP. If you perform the same result with the other IP (with your subnet mask), the results should equal if they're on the same network (subnet). – Matthew Jan 02 '13 at 16:45
  • 1
    @Matthew You may end up with funny results. Imagine the server running on a node with 192.168.1.17, and the router sends requests to port 80 of the external IP w.x.y.z to this node. A client comes from 192.168.1.37, which is NAT'ed to its external address a.b.c.d - yet the actual addresses are the same - but the nodes are on a different network. – Aleks G Jan 02 '13 at 16:51
  • @Matthew Shameless self-promotion: http://stackoverflow.com/a/13612479/889949 – DaveRandom Jan 02 '13 at 16:58

4 Answers4

10

Update the list of IP ranges as you please. I haven't updated this list in awhile, but it should have most. Sorry, I never added IPv6 support to it.

function reserved_ip($ip)
{
    $reserved_ips = array( // not an exhaustive list
    '167772160'  => 184549375,  /*    10.0.0.0 -  10.255.255.255 */
    '3232235520' => 3232301055, /* 192.168.0.0 - 192.168.255.255 */
    '2130706432' => 2147483647, /*   127.0.0.0 - 127.255.255.255 */
    '2851995648' => 2852061183, /* 169.254.0.0 - 169.254.255.255 */
    '2886729728' => 2887778303, /*  172.16.0.0 -  172.31.255.255 */
    '3758096384' => 4026531839, /*   224.0.0.0 - 239.255.255.255 */
    );

    $ip_long = sprintf('%u', ip2long($ip));

    foreach ($reserved_ips as $ip_start => $ip_end)
    {
        if (($ip_long >= $ip_start) && ($ip_long <= $ip_end))
        {
            return TRUE;
        }
    }
    return FALSE;
}

var_dump(reserved_ip('127.0.0.1')); // reserved (localhost)
var_dump(reserved_ip('74.125.140.101')); // not reserved (Google)
kittycat
  • 14,983
  • 9
  • 55
  • 80
  • See my comment to the original question: you can have the IP be internal, but the client be external - depending on your proxy setup. – Aleks G Jan 02 '13 at 16:53
  • @AleksG A valid point but if you have a local proxy you're kind of screwed anyway - you'd have to configure the proxy so that it informs you of the client IP and use that value for the test - but this code is not coupled to `$_SERVER['REMOTE_ADDR']` so it is still useful. A remote proxy would not matter as it would still be an external address and the check would still be a useful one. – DaveRandom Jan 02 '13 at 16:55
  • This solution seems good enough, and should work with my customer's network policies. I guess there is no perfect solution to this problem. – Perello Jan 03 '13 at 08:57
3

Unfortunately, there is no easy way to determine this with certainty. See my comment for an interesting example.

In IPv4 world, you can try doing this: determine your server's external IP address (using, for example http://ip-address.domaintools.com/myip.xml) and compare it with the client's socket remote address ($_SERVER['REMOTE_ADDR']). If they are the same, then you are running on the same network, if they are different, then it's a different network.

In IPv6 world (properly deployed networks), there is no such thing as a private network and every device everywhere has its own public IP address. In this case, the only way to determine whether you're local or not is to maintain a full list of local devices.

Aleks G
  • 56,435
  • 29
  • 168
  • 265
  • Really interesting (+1). I guess i won't be able to use your way. My customer is a french administration. I know that they don't provide internet access for (at least) some vpn users. – Perello Jan 03 '13 at 08:52
0

I assume you are defining internal as being 0 router hops away?

Use on of the solutions at:

How do I find my server's IP address in PHP(CLI)

to dynamically determine the SERVER'S IP Address and Netmask values. Then you should be able to determine if the client is remote or not.

If the internal network includes routed subnets (1 or more router hops away) I can't think of anyway to make the detection dynamic, you'd need to statically define internal IP ranges.

Community
  • 1
  • 1
Jay Lee
  • 13,415
  • 3
  • 28
  • 59
0

If you want to check it in SQL, you can use condition like this:

(INET_ATON(ip) & INET_ATON('255.0.0.0')) = INET_ATON('10.0.0.0') # 10.0.0.0/8
OR (INET_ATON(ip) & INET_ATON('255.0.0.0')) = INET_ATON('127.0.0.0')    # 127.0.0.0/8
OR (INET_ATON(ip) & INET_ATON('255.240.0.0')) = INET_ATON('172.16.0.0') # 172.16.0.0/12
OR (INET_ATON(ip) & INET_ATON('255.255.0.0')) = INET_ATON('192.168.0.0')    # 192.168.0.0/16
OR (INET_ATON(ip) & INET_ATON('240.0.0.0')) = INET_ATON('240.0.0.0')    # 240.0.0.0/4