views:

254

answers:

4

Here's the scenario... I have a table of subnets. (see below) I have an ip address. I would like to find out what subnet the ip address belongs to based on a lookup in the table. This association will then be used to determine what location the user is at. It's a private network space so the standard internet to location lookups wouldn't apply. What would be the best approach? Would I need to break the ip address into it's numeric parts and to a bitwise comparison against all the subnets.. or are there built-in tools in Java API that could make my life easier for comparing IP address to subnet mask?

I'm mainly looking for best way to compare ipaddress to a given subnetmask and determining yes this matches, or no it doesn't.. Optionally. Any tips on how to store the list and search with minimal operations would be appreciated also.

Ideally I'd be doing something similar to this:

List subnetInfo = null;

subnetInfo = findSubnet('192.168.0.1');  //value null if nothing found

....

//return null if nothing found
List findSubnet(String ipaddress) {
   List subnetDetails = null;
   .... code here ...
   return subnetDetails;
}

Table 1: Sample list of subnets

dk-ballerup-gen-off-v411        10.172.80.0/21  NANR-denmark-ballerup-metallbuen66-ground-first-floors-incl-dhcp-(sr14585203)
ae-dubai-ofssl-gen-off-v410  10.172.88.0/24  NANR-arab-emirates-ofssl-iflex-general-office-v410-(sr12781477)
ru-stpetersburg-gen-off-v411    10.172.89.0/24  NANR-russia-stpetersburg-general-office-incl-dhcp (bsteinba)
+2  A: 

Remember, that IP address is just an int value for historic reasons represented as 4 octets in decimal form.

For the same token, the subnet is really a range of consecutive ints from network address to a broadcast address.

Therefore if your IP address object has an int converter, you can simply check if that integer is in range of the subnet by doing simple int comparisons.

Alexander Pogrebnyak
A: 

If your table is a SQL table AND your database is PostgreSql, you can use PostgreSQL types and functions.

Well that's a lot of conditions ...

chburd
A: 

Turn the IP address and the netmask into ints and AND them together. If the result equals the IP address it is an address in that netmask. Note that you may get more than one match if your netmasks aren't distinct.

EJP
This is only true for IPv4. The same technique works for IPv6, but the addresses are not ints. They're not even longs. They're 128-bit numbers, which Java represents as a byte array.
Ian McLaird
+2  A: 

Apache Commons Net has a SubnetUtils for this sort of thing, including determining if a given IP address is within a given subnet.

Trivial example:

    String[] subnetsMasks = { ... };
    Collection<SubnetInfo> subnets = new ArrayList<SubnetInfo>();
    for (String subnetMask : subnetsMasks) {
        subnets.add(new SubnetUtils(subnetMask).getInfo());
    }

    String ipAddress = ...;
    for (SubnetInfo subnet : subnets) {
        if (subnet.isInRange(ipAddress)) {
            System.out.println("IP Address " + ipAddress + " is in range " + subnet.getCidrSignature());
        }
    }
skaffman
EJP
Because turning a CIDR mask into a number is the sort of task that you can easily get wrong. WHy re-implement it, when you can get it off the shelf?
skaffman
You're kidding, right? You don't even have to convert the bytes into an integer, you can just mask the bytes in a loop. About 4 lines of code.
EJP
And if the CIDR mask crosses the byte boundary? More lines of code. And more bugs. This problem has been solved in libraries, there are better things to spend our energy on.
skaffman