File Coverage

blib/lib/LinkLocal/IPv4/Interface.pm
Criterion Covered Total %
statement 12 27 44.4
branch n/a
condition n/a
subroutine 4 7 57.1
pod 1 1 100.0
total 17 35 48.5


line stmt bran cond sub pod time code
1             package LinkLocal::IPv4::Interface;
2              
3             our $VERSION = '0.19_01';
4              
5             require 5.010_000;
6              
7             # require Exporter;
8             # our @ISA = qw(Exporter);
9             # our %EXPORT_TAGS = ();
10             # our @EXPORT_OK = ();
11             # our @EXPORT = qw();
12              
13             # Copyright (C) 2010 Raymond Mroz
14             #
15             # This program is free software: you can redistribute it and/or modify
16             # it under the terms of the GNU General Public License as published by
17             # the Free Software Foundation, either version 3 of the License, or
18             # (at your option) any later version.
19             #
20             # This program is distributed in the hope that it will be useful,
21             # but WITHOUT ANY WARRANTY; without even the implied warranty of
22             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23             # GNU General Public License for more details.
24             #
25             # You should have received a copy of the GNU General Public License
26             # along with this program. If not, see <http://www.gnu.org/licenses/>.
27             #
28             # Requires:
29             # Moose
30             # Moose::Util::TypeConstraints
31             # IO::Interface::Simple
32             # Regexp::Common
33              
34 1     1   22954 use Moose;
  1         627658  
  1         8  
35 1     1   7750 use Moose::Util::TypeConstraints;
  1         3  
  1         12  
36 1     1   2761 use LinkLocal::IPv4::Interface::Types;
  1         4  
  1         419  
37              
38             # =============
39             # = interface =
40             # =============
41             has 'interface' => (
42             is => 'bare',
43             isa => 'LinkLocalInterface',
44             handles => {
45             get_if_device => 'name',
46             get_if_index => 'index',
47             get_if_list => 'interfaces',
48             get_if_addr => 'address',
49             set_if_addr => 'address',
50             get_if_mac => 'hwaddr',
51             },
52             coerce => 1,
53             );
54              
55             # ================
56             # = address_list =
57             # ================
58             has 'address_list' => (
59             is => 'ro',
60             isa => 'ArrayRef[IpAddress]',
61             reader => '_get_address_list',
62             builder => '_build_address_list',
63             lazy => 1,
64             init_arg => undef,
65             );
66              
67             # =============
68             # = BUILDARGS =
69             # =============
70             around BUILDARGS => sub {
71             my $orig = shift;
72             my $this = shift;
73              
74             if ( @_ == 1 && !ref $_[0] ) {
75             return $this->$orig( interface => $_[0] );
76             }
77             else {
78             return $this->$orig(@_);
79             }
80             };
81              
82             # =======================
83             # = _build_address_list =
84             # =======================
85             sub _build_address_list {
86 0     0     my $this = shift;
87              
88             # Generate srand() seed from mac address
89 0           my $mac = $this->get_if_mac;
90 0           my @split_mac = split( /':'/, $mac );
91 0           my $seed = 0;
92 0           foreach my $element (@split_mac) {
93 0           $seed += hex($element);
94             }
95              
96             # Seed for pseudo-random address generation
97 0           srand($seed);
98              
99             # Create a list of 10 pseudo-random link-local addresses
100 0           my @llv4_ip_list = ();
101 0           for ( my $iter = 0 ; $iter < 10 ; $iter++ ) {
102 0           $llv4_ip_list[$iter] =
103             join( '.', '169.254', ( 1 + int( rand(254) ) ), int( rand(256) ) );
104             }
105              
106 0           return \@llv4_ip_list;
107             }
108              
109             # ====================
110             # = get_next_address =
111             # ====================
112             sub _get_next_address {
113 0     0     my $this = shift;
114              
115             # TODO Fix this, it will break after 10 pulls
116 0           return shift( @{ $this->_get_address_list() } );
  0            
117             }
118              
119             # =============
120             # = if_config =
121             # =============
122             sub if_config {
123 0     0 1   my $this = shift;
124            
125             # TODO Call back end code here
126             }
127              
128 1     1   15 no Moose;
  1         2  
  1         7  
129              
130             __PACKAGE__->meta->make_immutable;
131             1;
132              
133             =head1 NAME
134              
135             LinkLocal::IPv4::Interface - IPv4 link-local interface wrapper
136              
137             =head1 SYNOPSIS
138              
139             use LinkLocal::IPv4::Interface;
140            
141             my $if_obj = LinkLocal::IPv4::Interface->new('eth0');
142            
143             # TODO: finalize method signature and process
144             $if_obj->if_config( $arg_a, $arg_b );
145              
146             =head1 DESCRIPTION
147              
148             This package represents a lightweight, pure Perl implementation of the specification
149             as outlined in RFC-3927, I<Dynamic Configuration of IPv4 Link-Local Addresses>.
150             This standard details a mechanism which provides a means of enabling automatic IPv4
151             address allocations to network addressable entities and devices which by happenstance
152             or design find themselves on an unmanaged, ad hoc IP network with no other means of
153             acquiring a fully routable, unicast IPv4 address. As the name implies, link-local IPv4
154             addresses are non-routable in the IANA reserved C<169.254/16> prefix, with all participating
155             devices connected to the same physical link; this fact all but dictates that such networks
156             are typically small. Home networks or other such small environments are well suited to the
157             deployment of this standard. While there are, in theory, upwards of 65,024 addresses available
158             in the range for allocations, the reality is that as more addresses from the reserved range
159             are allocated to hosts on the local link the number of collisions necessarily increases as
160             well which degrades overall performance. Products such as QIP meet this need in the enterprise.
161              
162             This standard is widely implemented in most major operating systems, most of which "more
163             or less" adhere to this specification. While I have remained true to the specification
164             and to the algorithms detailed therein I have in some ways made "enhancements"; one
165             example being my pseudorandom address selection will generate link-local addresses in
166             blocks of ten. This is similar to the implementation found in OS X and some of the
167             various offerings by Microsoft. This decision was simply a matter of convenience and
168             nothing more.
169              
170             This module, C<LinkLocal::IPv4::Interface> provides the main entry point into this
171             implementation. Because the specification recommends that link-local address are generated
172             in a pseudorandom fashion using something unique to the particular host on which they
173             are being generated such as a MAC address, I have by design coupled the selection of
174             addresses closely with the interface object itself; given that I am indeed using the
175             interface hardware MAC as a seed to C<srand()> this just made good sense to me. The primary
176             gateway into this process is the call to the C<if_config()> method. This method will step
177             through the various steps in the address selection process and will configure the interface
178             with a fully compliant IPv4 link-local address upon completion.
179              
180             There are some things I would like to note here. First, this implementation makes absolutely
181             no assumptions about the current state of the interface at any time. Client code should
182             know this. The specification is quite clear that IPv4 link-local addresses are to be used
183             only in the absence of a fully routable IPv4 address. The dynamic configuration of an
184             IPv4 link-local address is to never interfere with the operation of any of the other
185             processes whereby a host can acquire a standard, routable address such as a DHCP state
186             machine or static assignments under the direction of a network administrator. This
187             implementation is B<only> to be used at such a time that a determination has been made that
188             there are no operable and routable addresses configured on the interface. This library
189             does not at any time make any assumptions about the operability of any addresses assigned
190             to any interfaces on the host, nor does it in any way attempt to determine the management
191             status of any network in which it participates. This is an important point to consider here
192             as small networks have become ubiquitous and "network hopping" with portable devices is
193             certainly a scenario that is much more common today than it was ten or even five years ago.
194             Secondly, the configuration of an IPv4 link-local address is not something which is a
195             static thing; the implementation does not just probe the local physical link for the
196             address, configure the interface and forget about it. At any time an address conflict may
197             occur at which time the selection process may begin again. I have addressed this fact in my
198             design in a broad way. Client code will be expected to register a callback on a hook I
199             provide. Furthermore, I will also expose an optional pure Perl eventing mechanism which can be
200             set to monitor ARP on the local link for any requests or replies which contain the currently
201             configured link-local address. The other option here is that client code may wish to bring
202             its own eventing mechanism to the party. As such I have met both needs by way of Marc
203             Lehmann's AnyEvent module which has been described as the DBI of event loops. For those
204             not familiar with Marc's AnyEvent and Coro material, you might want to run over and check
205             out his stuff. In the world of asynchronous Perl eventing and coroutines, Marc is Master Yoda.
206              
207             B<NOTE:> This is still very much a work in progress. Much of this is pulled from some old
208             stuff which I had around, including bits and bobs of some UPnP stuff I had in C and which
209             I reimplemented in Perl. As such, some design is happening in situ. In addition to this, I
210             do, unfortunately, have to go to work and feed myself so I am unable to hack on this and
211             other things 24/7. I decided that I would push to CPAN early and chase my crufty push rather
212             than keep it in a git repo on my Mac and constantly pick and preen it and never get anything
213             actually out. So all that said, I will release as quickly and as often as I can and hopefully
214             I will have something here approaching actually useful before long at all, so please bear
215             with me and thanks for your patience.
216              
217             Also, this is fully intended to work along side such other protocols as Multicast Service
218             Discovery and other lightweight service announcement protocols. The ability to get a
219             valid address usable in communication with other hosts and devices on an unmanaged network
220             is not terribly useful if you cannot find anything out about the particular network in
221             question. As such I am toying with the idea of integrating, albeit very loosely, one or more
222             of the service discovery mechanisms out there as this is what makes link-local addressing
223             actually useful, scenarios such as plugging a laptop and a printer into a network and they
224             just work. While yes, there are full zero configuration suites out there in C and in other
225             languages, there is no lightweight equivalent in Perl.... yet.
226              
227             =head2 DEPENDENCIES
228              
229             L<Moose>
230              
231             L<Moose::Util::TypeConstraints>
232              
233             L<MooseX::Params::Validate>
234              
235             L<IO::Interface::Simple>
236              
237             L<Net::Frame::Layer::ARP>
238              
239             L<Net::Frame::Simple>
240              
241             L<Regexp::Common>
242              
243             =head2 ATTRIBUTES
244              
245             =over 4
246              
247             =item C<interface>
248              
249             The interface attribute contains a reference to the C<IO::Interface::Simple> object
250             type which is instantiated via a C<Moose> type coercion from a string representation of
251             the interface device name. The interface attribute also provides for a number of
252             mappings to the underlying objects methods and attributes by way of the very powerful
253             C<Moose> delegation feature.
254              
255             =item C<address_list>
256              
257             The address_list attribute is set to contain a list of ten MAC seeded, pseudorandomly
258             generated IPv4 link-local addresses. As interfaces are checked for collison on the
259             network by way of ARP probes to determine if they are already in use, they are popped
260             off of the list.
261              
262             =back
263              
264             =head2 CONSTRUCTORS
265              
266             =over 4
267              
268             =item C<new>
269              
270             This lone constructor takes the name of a network device on the system, as a string
271             and returns a Moose-wrapped C<IO::Interface::Simple> object.
272              
273             =back
274              
275             =head2 METHODS
276              
277             =over 4
278              
279             =item C<get_if_device>
280              
281             This call returns a string representation of the interface.
282              
283             =item C<get_if_index>
284              
285             Returns the interface index (only valid on BSD-style systems).
286              
287             =item C<get_if_list>
288              
289             Returns a list comprised of all detected interfaces on the system. Note, this
290             will not return a member for the loopback interface.
291              
292             =item C<get_if_addr>
293              
294             Returns the string representation of the IPv4 address to which the interface is
295             currently configured. The address is in dotted-decimal notation.
296              
297             =item C<set_if_addr>
298              
299             Attempts to set the interface to the IPv4 address string which it takes as its lone
300             parameter. The address must be in dotted-decimal format.
301              
302             =item C<get_if_mac>
303              
304             Returns the string representation of the hardware address of the interface. The
305             returned hardware address is in standard colon seperated, hexadecimal digit format.
306              
307             =item C<get_next_ip>
308              
309             Returns and pops the next available, pseudo-randomly generated IPv4 link-local address
310             from the attribute list, shrinking that list by one.
311              
312             =item C<if_config>
313              
314             General gateway method to this framework. A call to if_config begins the process of
315             dynamically configuring the specified interface with an IPv4 link-local address. This
316             call initiates the process of checking the link-local address cache for the last successfully
317             configured address otherwise a list of ten, new pseudo-random generated addresses is
318             created. The implementation fully adheres to the specification as defined in RFC-3927
319             as it ARP Probes the first address in the list or from the cache to determine if it is
320             already in use elsewhere on the local link. If it gets no response to its probe packets,
321             it configures the interface with the address and sends ARP Announce packets announcing
322             that it has claimed the address as well as to clear stale ARP cache entries which might
323             exist out on the link. If at any time an ARP packet, request or reply, is detected which
324             contains the address it has selected, it will either concede the address or make a single
325             attempt at address defense, depending upon the context of the packet and its current
326             state.
327              
328             =back
329              
330             =head2 EXPORT
331              
332             PROBE_WAIT => 1 second
333             PROBE_NUM => 3
334             PROBE_MIN => 1 second
335             PROBE_MAX => 2 seconds
336             ANNOUNCE_WAIT => 2 seconds
337             ANNOUNCE_NUM => 2
338             ANNOUNCE_INTERVAL => 2 seconds
339             MAX_CONFLICTS => 10
340             RATE_LIMIT_INTERVAL => 60 seconds
341             DEFEND_INTERVAL => 10 seconds
342              
343             =head1 SEE ALSO
344              
345             Refer to RFC-3927, I<Dynamic Configuration of IPv4 link-local Adresses>, the complete
346             text of which can be found in the top level of the package archive.
347              
348             L<perl>, L<IO::Interface::Simple>, L<Moose>
349              
350             This project is also hosted on github at:
351             git@github.com:raymroz/LinkLocal--IPv4.git
352            
353             =head1 BUGS
354              
355             What's a bug???
356              
357             =head1 AUTHOR
358              
359             Ray Mroz, E<lt>mroz@cpan.orgE<gt>
360              
361             =head1 COPYRIGHT AND LICENSE
362              
363             Copyright (C) 2010 Ray Mroz
364              
365             This program is free software: you can redistribute it and/or modify
366             it under the terms of the GNU General Public License as published by
367             the Free Software Foundation, either version 3 of the License, or
368             (at your option) any later version.
369              
370             This program is distributed in the hope that it will be useful,
371             but WITHOUT ANY WARRANTY; without even the implied warranty of
372             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
373             GNU General Public License for more details.
374              
375             You should have received a copy of the GNU General Public License
376             along with this program. If not, see <http://www.gnu.org/licenses/>.
377              
378              
379             =cut