Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Determine which route to take

by mhearse (Hermit)
on Aug 02, 2013 at 21:25 UTC ( #1047658=perlquestion: print w/ replies, xml ) Need Help??
mhearse has asked for the wisdom of the Perl Monks concerning the following question:

How do I programmatically determine which route to use for a given IP address? I would like actual code, but a module::method will give me the same thing.

Example routes on a unix machine:

192.168.0.0/24 192.168.0.1 10.10.10.0/24 10.10.10.1 12.162.8.11/28 default
Example IP address:
10.10.10.12

Comment on Determine which route to take
Select or Download Code
Re: Determine which route to take
by Perlbotics (Canon) on Aug 02, 2013 at 22:52 UTC

    You could try NetAddr::IP:

    use strict; use warnings; use Test::More; use NetAddr::IP; my @routes = ( [ qw(192.168.0.0/24 192.168.0.1) ], [ qw(10.10.10.0/24 10.10.10.1) ], [ qw(12.162.8.11/28 default) ], ); is( calc_route( "192.168.0.88" ), "192.168.0.1", "first route" ); is( calc_route( "192.168.1.88" ), "default", "close to first rout +e but default" ); is( calc_route( "10.10.10.12" ), "10.10.10.1", "second route (examp +le IP)" ); is( calc_route( "12.162.8.3" ), "default", "explicit default" ) +; is( calc_route( "1.2.3.4" ), "default", "else: default" ); done_testing; sub calc_route { my $ip = NetAddr::IP->new( shift ); for my $test_subnet ( @routes ) { if ( $ip->within( NetAddr::IP->new( $test_subnet->[0] ) ) ) { return $test_subnet->[1]; } } return 'default'; }

    Result:

    ok 1 - first route ok 2 - close to first route but default ok 3 - second route (example IP) ok 4 - explicit default ok 5 - else: default 1..5

    Use hashes and pre-computed objects for better performance (left as an exercise ;-).

      Thanks for your reply. For some reason I though it would be a simple bitwise AND. My knowledge of bitwise operators is pathetic.
Re: Determine which route to take
by rjt (Deacon) on Aug 03, 2013 at 02:15 UTC

    I'd use a module, too, but if you want/need to know how the math works, it's actually pretty simple:

    Update: Add this summary of the math:

    Convert IP address (or route subnet) to integer:

    my $ip = ($A << 24) + ($B << 16) + ($C << 8) + $D; # Do the same for each route address ($net)

    Convert /24 CIDR notation to 0xffffff00 netmask:

        my $mask = 0xffffffff ^ (1 << 32 - $cidr) - 1;

    Check if a destination IP matches a route:

        ($ip & $mask) == $net;

    Full example:

    #!/usr/bin/env perl use 5.012; use warnings FATAL => 'all'; # Use an array instead if order is important my %routes = ( '192.168.0.1' => [ '192.168.0.0' => 24 ], '10.10.10.1' => [ '10.10.10.0' => 24 ], 'default' => [ '12.162.8.11' => 28 ], ); printf "%15s -> %s\n", $_, route($_) for qw< 10.10.10.12 128.127.126.125 192.168.0.51 192.168.1.1 10.10.10.5 >; sub ip { $_[0] =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/ or die "Invalid IP"; die "Octet out of range" if ($1 & $2 & $3 & $4) > 255; ($1 << 24) + ($2 << 16) + ($3 << 8) + $4 } sub route { my $ip = ip($_[0]); while (my ($dest, $route) = each %routes) { my ($net, $cidr) = @$route; my $mask = 0xffffffff ^ (1 << 32 - $cidr) - 1; return $dest if ($ip & $mask) == ip($net); } return 'default'; }

    Output:

    10.10.10.12 -> 10.10.10.1 128.127.126.125 -> default 192.168.0.51 -> 192.168.0.1 192.168.1.1 -> default 10.10.10.5 -> 10.10.10.1
      Excellent! Thanks so much. I could learn a lot by reading your code. Do you have a github page? Or webpage? With code? Also... where did you learn about bitshifting and netmasking? Can you recommend a book?

        Thanks for the kind words, mhearse. I don't have a public GitHub or web presence, aside from my sundry answers on PerlMonks.

        Also... where did you learn about bitshifting and netmasking?

        I'd better not answer that one directly. :-)

        Have a look at Bitwise_operation, maybe Truth_table for some background. Once you have a decent handle on that, IP subnetting (which I've only just skimmed), looks like a decent intro to IPv4 math.

        Can you recommend a book?

        Unfortunately, my brain's bibliography is in serious need of trie optimization. Any relatively current text on IP networking will probably be a good start, though.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1047658]
Approved by Perlbotics
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (6)
As of 2015-05-23 03:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    In my home, the TV remote control is ...









    Results (465 votes), past polls