This application supports FOAF profile import. This was one of the earlier features. It works although I’m not sure how useful it is at the moment. As part of the system, users are asked to enter the URL for a profile in XML format. We take this URL and request it. Before doing that however, we have to check that the URL is on a non-internal publicly accessible server. Without a check, a user could enter a domain on the LAN which could expose data.
Web applications implementing RSS checking, OpenID and other similar technologies should perform these checks. First, a bit of background information.
IP Addresses and Long Addresses
Every IP address has an equivalent long address. IP addresses are in the form of 0-255.0-255.0-255.0-255 giving a total of 4,294,967,296 possible combinations. A long IP address is a number between 0 and 4,294,967,295. Some of you may notice that this is also the 32-bit unsigned integer limit. In other words, any IP address can also be represented as an 32-bit integer. An address such as 127.0.0.1 is much easier to remember than something like 2130706433 so we tend to use them.
It is actually possible to use the long IP address format. If you don’t believe me, try it. If you’ve got a web server installed on your local machine and it’s turned on, try going to http://2130706433/. If you don’t, try Google (1113983336). This doesn’t work with all ISPs although the long IP address for localhost should always work. Try pinging 2130706433 from the command line.
Internal IP Address Ranges
There are several blocks reserved for internal IP addressing. These are 10.0.0.0 to 10.255.255.255, 172.16.0.0 to 172.31.255.255 and 192.168.0.0 to 192.168.255.255. In addition the block 169.254.0.0 to 169.254.255.255 is reserved for automatic private IP addressing and 127.0.0.0 to 127.255.255.255 is only really ever used for loopback so it makes sense to block access to these IPs.
In order to detect whether an IP is internal or publicly accessible, we need to check if the IP address is in this range. It’s possible to use regexps or other string matching techniques but this is more difficult. Instead, we convert the IP address from the dotted format to the long format. Luckily PHP provides us with a built in function to do this.
We need to generate a long format IP for the beginning and end IP for each range and then check whether the IP address are in those ranges by using greater than/lesser than comparison operators.
Here’s some code I cooked up earlier:
<?php
function urlIsPublic($url) {
/* Check URL is not private */
$parsedurl = parse_url($url);
$ip = gethostbyname($parsedurl['host']);
$long = ip2long($ip);
if (($long >= 167772160 AND $long <= 184549375) OR ($long >= -1408237568 AND $long <= -1407188993) OR ($long >= -1062731776 AND $long <= -1062666241) OR ($long >= 2130706432 AND $long <= 2147483647) OR $long == -1) {
return
false;
}
return
true;
// 167772160 - 10.0.0.0
// 184549375 - 10.255.255.255
//
// -1408237568 - 172.16.0.0
// -1407188993 - 172.31.255.255
//
// -1062731776 - 192.168.0.0
// -1062666241 - 192.168.255.255
//
// -1442971648 - 169.254.0.0
// -1442906113 - 169.254.255.255
//
// 2130706432 - 127.0.0.0
// 2147483647 - 127.255.255.255 (32 bit integer limit!!!)
//
// -1 is also b0rked
}
?>
Notice in the code I’ve also checked for ip2long() responding with a -1. This indicates an invalid IP address.
The first few lines take a URL and extracts the domain from it. It then converts the domain name into an IP address for use with the checker.