File Coverage

blib/lib/Net/Routing.pm
Criterion Covered Total %
statement 75 154 48.7
branch 8 64 12.5
condition 0 18 0.0
subroutine 23 27 85.1
pod 3 3 100.0
total 109 266 40.9


line stmt bran cond sub pod time code
1             #
2             # $Id: Routing.pm,v 717225574cff 2015/11/12 08:46:57 gomor $
3             #
4             package Net::Routing;
5 6     6   786 use strict;
  6         13  
  6         168  
6 6     6   32 use warnings;
  6         10  
  6         247  
7              
8             our $VERSION = '0.44';
9              
10 6     6   36 use base qw(Class::Gomor::Hash);
  6         14  
  6         4942  
11              
12             our @AS = qw(
13             path
14             lc_all
15             target
16             family
17             _target_type
18             _routing_module
19             _routes
20             );
21             __PACKAGE__->cgBuildAccessorsScalar(\@AS);
22              
23 6     6   63761 use Net::CIDR;
  6         36959  
  6         354  
24 6     6   4918 use Net::IPv4Addr;
  6         216657  
  6         327  
25 6     6   5812 use Net::IPv6Addr;
  6         989830  
  6         559  
26              
27             our $_routing_module;
28             our $Error;
29              
30 6     6   68 use constant NR_TARGET_ALL => 'all';
  6         12  
  6         344  
31 6     6   31 use constant NR_TARGET_DEFAULT => 'default';
  6         11  
  6         294  
32 6     6   33 use constant NR_FAMILY_INET4 => 'inet4';
  6         11  
  6         265  
33 6     6   33 use constant NR_FAMILY_INET6 => 'inet6';
  6         9  
  6         263  
34 6     6   29 use constant NR_DEFAULT_ROUTE4 => '0.0.0.0/0';
  6         10  
  6         262  
35 6     6   31 use constant NR_DEFAULT_ROUTE6 => '::/0';
  6         9  
  6         373  
36 6     6   29 use constant NR_LOCAL_ROUTE4 => '0.0.0.0';
  6         11  
  6         294  
37 6     6   49 use constant NR_LOCAL_ROUTE6 => '::';
  6         10  
  6         288  
38              
39 6     6   31 use constant _TARGET_TYPE_ALL => 'all';
  6         11  
  6         280  
40 6     6   30 use constant _TARGET_TYPE_DEFAULT => 'default';
  6         9  
  6         273  
41 6     6   29 use constant _TARGET_TYPE_IPv4 => 'ipv4';
  6         14  
  6         280  
42 6     6   29 use constant _TARGET_TYPE_IPv6 => 'ipv6';
  6         9  
  6         294  
43 6     6   32 use constant _TARGET_TYPE_INTERFACE => 'interface';
  6         11  
  6         1217  
44              
45             our %EXPORT_TAGS = (
46             constants => [qw(
47             NR_TARGET_ALL
48             NR_TARGET_DEFAULT
49             NR_FAMILY_INET4
50             NR_FAMILY_INET6
51             NR_DEFAULT_ROUTE4
52             NR_DEFAULT_ROUTE6
53             NR_LOCAL_ROUTE4
54             NR_LOCAL_ROUTE6
55             )],
56             );
57              
58             our @EXPORT_OK = (
59             '$Error',
60             @{$EXPORT_TAGS{constants}},
61             );
62              
63             BEGIN {
64 6 50   6   38 if ($^O eq 'linux') {
    0          
    0          
    0          
65 6         6998 return $_routing_module = "Net::Routing::Linux";
66             }
67             elsif ($^O eq 'freebsd') {
68 0         0 return $_routing_module = "Net::Routing::FreeBSD";
69             }
70             elsif ($^O eq 'netbsd') {
71 0         0 return $_routing_module = "Net::Routing::NetBSD";
72             }
73             elsif ($^O eq 'darwin') {
74 0         0 return $_routing_module = "Net::Routing::Darwin";
75             }
76             #elsif ($^O eq 'MSWin32') {
77             # return $_routing_module = "Net::Routing::MSWin32";
78             #}
79             #elsif ($^O eq 'openbsd') {
80             # return $_routing_module = "Net::Routing::OpenBSD";
81             #}
82              
83 0         0 die("[-] Net::Routing: Operating System not supported: $^O\n");
84             }
85              
86             sub new {
87 4     4 1 64 my $self = shift->SUPER::new(
88             path => [ qw(/bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin) ],
89             lc_all => 'en_GB.UTF-8',
90             target => NR_TARGET_ALL(),
91             family => NR_FAMILY_INET4(),
92             @_,
93             );
94              
95 4         1040 $self->path([ @{$self->path}, split(':', $ENV{PATH}) ]);
  4         31  
96              
97 4     4   389 eval("use $_routing_module;");
  4         30  
  4         7  
  4         143  
98 4 50       23 if ($@) {
99 0         0 chomp($@);
100 0         0 $Error = "unable to load routing module [$_routing_module]: $@";
101 0         0 return;
102             }
103              
104 4         36 $self->_routing_module($_routing_module);
105              
106 4 100       53 my $routes = $self->get or return;
107              
108 1         26 $self->_routes($routes);
109              
110 1         43 return $self;
111             }
112              
113             sub _get_target_type {
114 0     0   0 my $self = shift;
115 0         0 my ($target) = @_;
116              
117 0         0 my $target_type = '';
118              
119 0 0       0 if ($target eq NR_TARGET_ALL()) {
    0          
    0          
    0          
120 0         0 $target_type = _TARGET_TYPE_ALL();
121             }
122             elsif ($target eq NR_TARGET_DEFAULT()) {
123 0         0 $target_type = _TARGET_TYPE_DEFAULT();
124             }
125             elsif ($target =~ /^[0-9\.]+$/) {
126 0         0 eval {
127 0         0 my ($ip, $cidr) = Net::IPv4Addr::ipv4_parse($target);
128             };
129 0 0       0 if (! $@) {
130 0         0 $target_type = _TARGET_TYPE_IPv4();
131             }
132             }
133             elsif ($target =~ /^[0-9a-f:\/]+$/i) {
134 0         0 eval {
135 0         0 my $x = Net::IPv6Addr::ipv6_parse($target);
136             };
137 0 0       0 if (! $@) {
138 0         0 $target_type = _TARGET_TYPE_IPv6();
139             }
140             }
141             # If it is not an IPv4 nor IPv6 address or default nor all routes,
142             # we consider it is an interface.
143             else {
144 0         0 $target_type = _TARGET_TYPE_INTERFACE();
145             }
146              
147 0         0 return $target_type;
148             }
149              
150             sub get {
151 0     0 1 0 my $self = shift;
152              
153 0         0 my $target = $self->target;
154 0         0 my $family = $self->family;
155 0         0 my $target_type = $self->_get_target_type($target);
156              
157 0 0       0 if ($target_type eq _TARGET_TYPE_IPv4()) {
    0          
158 0         0 $family = NR_FAMILY_INET4();
159             }
160             elsif ($target_type eq _TARGET_TYPE_IPv6()) {
161 0         0 $family = NR_FAMILY_INET6();
162             }
163              
164 0 0       0 my $routes = $self->_routing_module_get or return;
165 0 0       0 if ($target_type eq _TARGET_TYPE_ALL()) {
166 0         0 return $routes;
167             }
168              
169             # Return only wanted routes
170 0         0 my @routes = ();
171 0         0 for my $route (@$routes) {
172             # Will return default route only.
173 0 0 0     0 if ($target_type eq _TARGET_TYPE_DEFAULT()) {
    0          
    0          
174 0 0       0 if ($route->{default}) {
175 0         0 push @routes, $route;
176             }
177             }
178             # Will return routes on interface only.
179             elsif ($target_type eq _TARGET_TYPE_INTERFACE()) {
180 0 0       0 if ($route->{interface} eq $target) {
181 0         0 push @routes, $route;
182             }
183             }
184             # Will return local route only.
185             elsif ($target_type eq _TARGET_TYPE_IPv4() || $target_type eq _TARGET_TYPE_IPv6()) {
186 0 0 0     0 if ($route->{route}
      0        
187             && $route->{route} ne NR_DEFAULT_ROUTE4()
188             && $route->{route} ne NR_DEFAULT_ROUTE6()) {
189 0         0 my $r;
190 0         0 eval {
191 0         0 $r = Net::CIDR::cidrlookup($target, $route->{route});
192             };
193 0 0 0     0 if (! $@ && $r) {
194 0         0 push @routes, $route;
195             }
196             }
197             }
198             }
199              
200             # If no route matches, we will return the default route for types 'ipv4' and 'ipv6'
201 0 0 0     0 if (@routes == 0
      0        
202             && ($target_type eq _TARGET_TYPE_IPv4() || $target_type eq _TARGET_TYPE_IPv6())
203             ) {
204 0         0 for my $route (@$routes) {
205 0 0       0 if ($route->{default}) {
206 0         0 push @routes, $route;
207             }
208             }
209             }
210              
211 0         0 return \@routes;
212             }
213              
214             sub _routing_module_get {
215 0     0   0 my $self = shift;
216              
217 0         0 my $routing_module = $self->_routing_module;
218              
219 0         0 my $routing;
220 0         0 eval {
221 0         0 $routing = $routing_module->new(
222             path => $self->path,
223             family => $self->family,
224             );
225             };
226 0 0       0 if ($@) {
227 0         0 chomp($@);
228 0         0 $Error = "unable to load module [$routing_module]: $@";
229 0         0 return;
230             }
231 0 0       0 if (! defined($routing)) {
232 0         0 return;
233             }
234              
235 0         0 my $routes = $routing->get;
236 0 0       0 if (! defined($routes)) {
237 0         0 return;
238             }
239              
240 0         0 return $routes;
241             }
242              
243             sub list {
244 0     0 1 0 my $self = shift;
245              
246 0         0 printf("%-33s %-33s %-10s\n", "Route", "Gateway", "Interface");
247              
248 0         0 my $routes = $self->_routes;
249 0         0 for my $route (@$routes) {
250 0         0 my $route2 = $route->{route};
251 0         0 my $gateway = $route->{gateway};
252 0         0 my $interface = $route->{interface};
253              
254 0         0 printf("%-33s %-33s %-10s", $route2, $gateway, $interface);
255 0 0       0 if ($route->{local}) {
    0          
256 0         0 print "[local]";
257             }
258             elsif ($route->{default}) {
259 0         0 print "[default]";
260             }
261              
262 0         0 print "\n";
263             }
264              
265 0         0 return 1;
266             }
267              
268             sub _to_psv {
269 72     72   137 my $self = shift;
270 72         141 my ($route) = @_;
271              
272             my $psv = $route->{route}.'|'.$route->{gateway}.'|'.$route->{interface}.'|'.
273 72 100       501 (exists($route->{default})?'1':'0').'|'.(exists($route->{local})?'1':'0');
    100          
274              
275 72         250 return $psv;
276             }
277              
278             1;
279              
280             __END__