File Coverage

blib/lib/IO/Socket/Netlink/Route.pm
Criterion Covered Total %
statement 63 111 56.7
branch 1 22 4.5
condition 0 2 0.0
subroutine 21 42 50.0
pod 1 2 50.0
total 86 179 48.0


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2010-2011 -- leonerd@leonerd.org.uk
5              
6             package IO::Socket::Netlink::Route;
7              
8 1     1   2154 use strict;
  1         2  
  1         34  
9 1     1   5 use warnings;
  1         1  
  1         31  
10 1     1   943 use IO::Socket::Netlink 0.04;
  1         36232  
  1         9  
11 1     1   780 use base qw( IO::Socket::Netlink );
  1         2  
  1         87  
12              
13             our $VERSION = '0.05';
14              
15 1     1   5 use Carp;
  1         1  
  1         46  
16              
17 1     1   39 use Socket::Netlink::Route;
  1         1  
  1         545  
18              
19             __PACKAGE__->register_protocol( NETLINK_ROUTE );
20              
21             =head1 NAME
22              
23             C - Object interface to C netlink
24             protocol sockets
25              
26             =head1 DESCRIPTION
27              
28             This subclass of L implements the C
29             protocol. This protocol allows communication with the Linux kernel's
30             networking stack, allowing querying or modification of interfaces, addresses,
31             routes, and other networking properties.
32              
33             This module is currently a work-in-progress, and this documentation is fairly
34             minimal. The reader is expected to be familiar with C, as it
35             currently only gives a fairly minimal description of the Perl-level wrapping
36             of the kernel level concepts. For more information see the documentation in
37             F.
38              
39             =cut
40              
41             sub new
42             {
43 0     0 1   my $class = shift;
44 0           $class->SUPER::new( Protocol => NETLINK_ROUTE, @_ );
45             }
46              
47             sub message_class
48             {
49 0     0 0   return "IO::Socket::Netlink::Route::_Message";
50             }
51              
52             =head1 MESSAGE CLASSES
53              
54             Each message type falls into one of the following subclasses, chosen by the
55             value of the C field. Each subclass provides access to the field
56             headers of its message body, and netlink attributes.
57              
58             =cut
59              
60             package IO::Socket::Netlink::Route::_Message;
61              
62 1     1   6 use base qw( IO::Socket::Netlink::_Message );
  1         2  
  1         466  
63              
64 1     1   5 use Carp;
  1         1  
  1         56  
65              
66 1     1   5 use Socket::Netlink::Route qw( :DEFAULT );
  1         1  
  1         1302  
67              
68             __PACKAGE__->is_subclassed_by_type;
69              
70 0     0     sub pack_nlattr_lladdr { pack "C*", map hex($_), split /:/, $_[1] }
71 0     0     sub unpack_nlattr_lladdr { join ":", map sprintf("%02x",$_), unpack "C*", $_[1] }
72              
73 0     0     sub pack_nlattr_dottedhex { pack "C*", map hex($_), split /\./, $_[1] } # hex() will strip leading 0x on first byte
74 0     0     sub unpack_nlattr_dottedhex { "0x" . join ".", map sprintf("%02x",$_), unpack "C*", $_[1] }
75              
76             if( eval { require Socket && defined &Socket::inet_ntop } ) {
77             *inet_ntop = \&Socket::inet_ntop;
78             *inet_pton = \&Socket::inet_pton;
79             }
80             elsif( eval { require Socket6 } ) {
81             *inet_ntop = \&Socket6::inet_ntop;
82             *inet_pton = \&Socket6::inet_pton;
83             }
84             else {
85             require Socket;
86             *inet_ntop = sub {
87             my ( $family, $addr ) = @_;
88             return Socket::inet_ntoa($addr) if $family == Socket::AF_INET();
89             return undef;
90             };
91             *inet_pton = sub {
92             my ( $family, $protaddr ) = @_;
93             return Socket::inet_aton($protaddr) if $family == Socket::AF_INET();
94             return undef;
95             };
96             }
97              
98             sub pack_nlattr_protaddr
99             {
100 0     0     my ( $self, $protaddr ) = @_;
101 0 0         eval { defined $self->family and inet_pton( $self->family, $protaddr ) }
  0 0          
102             or $self->pack_nlattr_dottedhex( $protaddr );
103             }
104              
105             sub unpack_nlattr_protaddr
106             {
107 0     0     my ( $self, $addr ) = @_;
108 0 0         eval { defined $self->family and inet_ntop( $self->family, $addr ) }
  0 0          
109             or $self->unpack_nlattr_dottedhex( $addr );
110             }
111              
112             # Debug support
113             my @TYPES = grep m/^RTM_/, @Socket::Netlink::Route::EXPORT;
114              
115             sub nlmsg_type_string
116             {
117 0     0     my $self = shift;
118 0           my $type = $self->nlmsg_type;
119 0   0       $type == $self->$_ and return $_ for @TYPES;
120 0           return $self->SUPER::nlmsg_type_string;
121             }
122              
123             package IO::Socket::Netlink::Route::_IfinfoMsg;
124              
125 1     1   7 use base qw( IO::Socket::Netlink::Route::_Message );
  1         1  
  1         546  
126 1         630 use Socket::Netlink::Route qw( :DEFAULT
127             pack_ifinfomsg unpack_ifinfomsg
128 1     1   7 );
  1         1  
129 1     1   6 use Socket qw( AF_UNSPEC );
  1         2  
  1         454  
130              
131             =head2 IfinfoMsg
132              
133             Relates to a network interface. Used by the following message types
134              
135             =over 4
136              
137             =item * RTM_NEWLINK
138              
139             =item * RTM_DELLINK
140              
141             =item * RTM_GETLINK
142              
143             =back
144              
145             =cut
146              
147             __PACKAGE__->register_nlmsg_type( $_ )
148             for RTM_NEWLINK, RTM_DELLINK, RTM_GETLINK;
149              
150             =pod
151              
152             Provides the following header field accessors
153              
154             =over 4
155              
156             =item * ifi_family
157              
158             =item * ifi_type
159              
160             =item * ifi_index
161              
162             =item * ifi_flags
163              
164             =item * ifi_change
165              
166             =back
167              
168             =cut
169              
170             __PACKAGE__->is_header(
171             data => "nlmsg",
172             fields => [
173             [ ifi_family => "decimal" ],
174             [ ifi_type => "decimal" ],
175             [ ifi_index => "decimal" ],
176             [ ifi_flags => "hex" ],
177             [ ifi_change => "hex" ],
178             [ ifinfo => "bytes" ],
179             ],
180             pack => \&pack_ifinfomsg,
181             unpack => \&unpack_ifinfomsg,
182             );
183              
184             =pod
185              
186             Provides the following netlink attributes
187              
188             =over 4
189              
190             =item * address => STRING
191              
192             =item * broadcast => STRING
193              
194             =item * ifname => STRING
195              
196             =item * mtu => INT
197              
198             =item * qdisc => STRING
199              
200             =item * stats => HASH
201              
202             =item * txqlen => INT
203              
204             =item * operstate => INT
205              
206             =item * linkmode => INT
207              
208             =back
209              
210             =cut
211              
212             __PACKAGE__->has_nlattrs(
213             "ifinfo",
214             address => [ IFLA_ADDRESS, "lladdr" ],
215             broadcast => [ IFLA_BROADCAST, "lladdr" ],
216             ifname => [ IFLA_IFNAME, "asciiz" ],
217             mtu => [ IFLA_MTU, "u32" ],
218             qdisc => [ IFLA_QDISC, "asciiz" ],
219             stats => [ IFLA_STATS, "stats" ],
220             txqlen => [ IFLA_TXQLEN, "u32" ],
221             map => [ IFLA_MAP, "raw" ],
222             operstate => [ IFLA_OPERSTATE, "u8" ],
223             linkmode => [ IFLA_LINKMODE, "u8" ],
224             linkinfo => [ IFLA_LINKINFO, "linkinfo" ],
225             );
226              
227             BEGIN {
228 1 50   1   7 if( defined &Socket::Netlink::Route::pack_rtnl_link_stats ) {
229 1     0   4 *pack_nlattr_stats = sub { Socket::Netlink::Route::pack_rtnl_link_stats $_[1] };
  0         0  
230 1     0   64 *unpack_nlattr_stats = sub { Socket::Netlink::Route::unpack_rtnl_link_stats $_[1] };
  0         0  
231             }
232             else {
233             # Just pass raw bytes
234 0         0 *pack_nlattr_stats = *unpack_nlattr_stats = sub { $_[1] };
  0         0  
235             }
236             }
237              
238 0     0     sub pack_nlattr_linkinfo { die }
239 0     0     sub unpack_nlattr_linkinfo { "LINKINFO" }
240              
241             package IO::Socket::Netlink::Route::_IfaddrMsg;
242              
243 1     1   6 use base qw( IO::Socket::Netlink::Route::_Message );
  1         2  
  1         515  
244 1     1   7 use Carp;
  1         3  
  1         76  
245 1         1117 use Socket::Netlink::Route qw( :DEFAULT
246             pack_ifaddrmsg unpack_ifaddrmsg
247             pack_ifa_cacheinfo unpack_ifa_cacheinfo
248 1     1   7 );
  1         2  
249              
250             =head2 IfaddrMsg
251              
252             Relates to an address present on an interface. Used by the following message
253             types
254              
255             =over 4
256              
257             =item * RTM_NEWADDR
258              
259             =item * RTM_DELADDR
260              
261             =item * RTM_GETADDR
262              
263             =back
264              
265             =cut
266              
267             __PACKAGE__->register_nlmsg_type( $_ )
268             for RTM_NEWADDR, RTM_DELADDR, RTM_GETADDR;
269              
270             =pod
271              
272             Provides the following header field accessors
273              
274             =over 4
275              
276             =item * ifa_family
277              
278             =item * ifa_prefixlen
279              
280             =item * ifa_flags
281              
282             =item * ifa_scope
283              
284             =item * ifa_index
285              
286             =back
287              
288             =cut
289              
290             __PACKAGE__->is_header(
291             data => "nlmsg",
292             fields => [
293             [ ifa_family => "decimal" ],
294             [ ifa_prefixlen => "decimal" ],
295             [ ifa_flags => "hex" ],
296             [ ifa_scope => "decimal" ],
297             [ ifa_index => "decimal" ],
298             [ ifaddr => "bytes" ],
299             ],
300             pack => \&pack_ifaddrmsg,
301             unpack => \&unpack_ifaddrmsg,
302             );
303              
304             *family = \&ifa_family;
305              
306             =pod
307              
308             Provides the following netlink attributes
309              
310             =over 4
311              
312             =item * address => STRING
313              
314             =item * local => STRING
315              
316             =item * label => STRING
317              
318             =item * broadcast => STRING
319              
320             =item * anycast => STRING
321              
322             =item * cacheinfo => HASH
323              
324             =back
325              
326             =cut
327              
328             __PACKAGE__->has_nlattrs(
329             "ifaddr",
330             address => [ IFA_ADDRESS, "protaddr" ],
331             local => [ IFA_LOCAL, "protaddr" ],
332             label => [ IFA_LABEL, "asciiz" ],
333             broadcast => [ IFA_BROADCAST, "protaddr" ],
334             anycast => [ IFA_ANYCAST, "protaddr" ],
335             cacheinfo => [ IFA_CACHEINFO, "cacheinfo" ],
336             );
337              
338 0     0     sub pack_nlattr_cacheinfo { pack_ifa_cacheinfo $_[1] }
339 0     0     sub unpack_nlattr_cacheinfo { unpack_ifa_cacheinfo $_[1] }
340              
341             =head3 $message->prefix
342              
343             Sets or returns both the C
netlink attribute, and the
344             C header value, in the form
345              
346             address/ifa_prefixlen
347              
348             =cut
349              
350             sub prefix
351             {
352 0     0     my $self = shift;
353              
354 0 0         if( @_ ) {
355 0 0         my ( $addr, $len ) = $_[0] =~ m{^(.*)/(\d+)$} or
356             croak "Expected 'ADDRESS/PREFIXLEN'";
357 0           $self->change_nlattrs( address => $addr );
358 0           $self->ifa_prefixlen( $len );
359             }
360             else {
361 0           sprintf "%s/%d", $self->get_nlattr( 'address' ), $self->ifa_prefixlen;
362             }
363             }
364              
365             package IO::Socket::Netlink::Route::_RtMsg;
366              
367 1     1   6 use base qw( IO::Socket::Netlink::Route::_Message );
  1         2  
  1         437  
368 1     1   5 use Carp;
  1         2  
  1         74  
369 1     1   5 use Socket::Netlink::Route qw( :DEFAULT pack_rtmsg unpack_rtmsg );
  1         2  
  1         1055  
370              
371             =head2 RtMsg
372              
373             Relates to a routing table entry. Used by the following message types
374              
375             =over 4
376              
377             =item * RTM_NEWROUTE
378              
379             =item * RTM_DELROUTE
380              
381             =item * RTM_GETROUTE
382              
383             =back
384              
385             =cut
386              
387             __PACKAGE__->register_nlmsg_type( $_ )
388             for RTM_NEWROUTE, RTM_DELROUTE, RTM_GETROUTE;
389              
390             =pod
391              
392             Provides the following header field accessors
393              
394             =over 4
395              
396             =item * rtm_family
397              
398             =item * rtm_dst_len
399              
400             =item * rtm_src_len
401              
402             =item * rtm_tos
403              
404             =item * rtm_table
405              
406             =item * rtm_protocol
407              
408             =item * rtm_scope
409              
410             =item * rtm_type
411              
412             =item * rtm_flags
413              
414             =back
415              
416             =cut
417              
418             __PACKAGE__->is_header(
419             data => "nlmsg",
420             fields => [
421             [ rtm_family => "decimal" ],
422             [ rtm_dst_len => "decimal" ],
423             [ rtm_src_len => "decimal" ],
424             [ rtm_tos => "hex" ],
425             [ rtm_table => "decimal" ],
426             [ rtm_protocol => "decimal" ],
427             [ rtm_scope => "decimal" ],
428             [ rtm_type => "decimal" ],
429             [ rtm_flags => "hex" ],
430             [ rtm => "bytes" ],
431             ],
432             pack => \&pack_rtmsg,
433             unpack => \&unpack_rtmsg,
434             );
435              
436             *family = \&rtm_family;
437              
438             =pod
439              
440             Provides the following netlink attributes
441              
442             =over 4
443              
444             =item * dst => STRING
445              
446             =item * src => STRING
447              
448             =item * iif => INT
449              
450             =item * oif => INT
451              
452             =item * gateway => STRING
453              
454             =item * priority => INT
455              
456             =item * metrics => INT
457              
458             =back
459              
460             =cut
461              
462             __PACKAGE__->has_nlattrs(
463             "rtm",
464             dst => [ RTA_DST, "protaddr" ],
465             src => [ RTA_SRC, "protaddr" ],
466             iif => [ RTA_IIF, "u32" ],
467             oif => [ RTA_OIF, "u32" ],
468             gateway => [ RTA_GATEWAY, "protaddr" ],
469             priority => [ RTA_PRIORITY, "u32" ],
470             metrics => [ RTA_METRICS, "u32" ],
471             );
472              
473             =head3 $message->src
474              
475             Sets or returns the C netlink attribute and the C header
476             value, in the form
477              
478             address/prefixlen
479              
480             if the address is defined, or C if not.
481              
482             =head3 $message->dst
483              
484             Sets or returns the C netlink attribute and the C header
485             value, in the form given above.
486              
487             =cut
488              
489             sub _srcdst
490             {
491 0     0     my $self = shift;
492 0           my $type = shift;
493              
494 0           my $rtm_len = "rtm_${type}_len";
495              
496 0 0         if( @_ ) {
497 0 0         if( defined $_[0] ) {
498 0 0         my ( $addr, $len ) = $_[0] =~ m{^(.*)/(\d+)$} or
499             croak "Expected 'ADDRESS/PREFIXLEN'";
500 0           $self->change_nlattrs( $type => $addr );
501 0           $self->$rtm_len( $len );
502             }
503             else {
504 0           $self->change_nlattrs( $type => undef );
505 0           $self->$rtm_len( 0 );
506             }
507             }
508             else {
509 0 0         if( defined( my $addr = $self->get_nlattr( $type ) ) ) {
510 0           sprintf "%s/%d", $addr, $self->$rtm_len;
511             }
512             else {
513 0           undef;
514             }
515             }
516             }
517              
518 0     0     sub src { shift->_srcdst('src',@_) }
519 0     0     sub dst { shift->_srcdst('dst',@_) }
520              
521             package IO::Socket::Netlink::Route::_NdMsg;
522              
523 1     1   6 use base qw( IO::Socket::Netlink::Route::_Message );
  1         1  
  1         618  
524 1         1646 use Socket::Netlink::Route qw( :DEFAULT
525             pack_ndmsg unpack_ndmsg
526             pack_nda_cacheinfo unpack_nda_cacheinfo
527 1     1   7 );
  1         2  
528              
529             =head2 NdMsg
530              
531             Relates to a neighbour discovery table entry. Used by the following message types
532              
533             =over 4
534              
535             =item * RTM_NEWNEIGH
536              
537             =item * RTM_DELNEIGH
538              
539             =item * RTM_GETNEIGH
540              
541             =back
542              
543             =cut
544              
545             __PACKAGE__->register_nlmsg_type( $_ )
546             for RTM_NEWNEIGH, RTM_DELNEIGH, RTM_GETNEIGH;
547              
548             =pod
549              
550             Provides the following header field accessors
551              
552             =over 4
553              
554             =item * ndm_family
555              
556             =item * ndm_ifindex
557              
558             =item * ndm_state
559              
560             =item * ndm_flags
561              
562             =item * ndm_type
563              
564             =back
565              
566             =cut
567              
568             __PACKAGE__->is_header(
569             data => "nlmsg",
570             fields => [
571             [ ndm_family => "decimal" ],
572             [ ndm_ifindex => "decimal" ],
573             [ ndm_state => "decimal" ],
574             [ ndm_flags => "hex" ],
575             [ ndm_type => "decimal" ],
576             [ ndm => "bytes" ],
577             ],
578             pack => \&pack_ndmsg,
579             unpack => \&unpack_ndmsg,
580             );
581              
582             *family = \&ndm_family;
583              
584             =pod
585              
586             Provides the following netlink attributes
587              
588             =over 4
589              
590             =item * dst => STRING
591              
592             =item * lladdr => STRING
593              
594             =item * cacheinfo => HASH
595              
596             =back
597              
598             =cut
599              
600             __PACKAGE__->has_nlattrs(
601             "ndm",
602             dst => [ NDA_DST, "protaddr" ],
603             lladdr => [ NDA_LLADDR, "lladdr" ],
604             cacheinfo => [ NDA_CACHEINFO, "cacheinfo" ],
605             );
606              
607 0     0     sub pack_nlattr_cacheinfo { pack_nda_cacheinfo $_[1] }
608 0     0     sub unpack_nlattr_cacheinfo { unpack_nda_cacheinfo $_[1] }
609              
610             =head1 SEE ALSO
611              
612             =over 4
613              
614             =item *
615              
616             L - interface to Linux's C netlink
617             socket protocol
618              
619             =item *
620              
621             L - Object interface to C domain sockets
622              
623             =item *
624              
625             F - rtnetlink, NETLINK_ROUTE - Linux IPv4 routing socket
626              
627             =back
628              
629             =head1 AUTHOR
630              
631             Paul Evans
632              
633             =cut
634              
635             0x55AA;