Net::DHCPClientLive - stateful DHCP client object
use Net::DHCPClientLive; my $client = new Net::DHCPClientLive( interface => "eth0", state => 'BOUND') or die "failed to move to BOUND state\n"; print "DHCP client $client->{cltmac} is created and assigned $client->{requestip} from server\n";
Net::DHCPClientLive allows you to create and manipulate DHCP client(s) so that you can test the behavior of your DHCP server upon client state transition.
DHCP client is a stateful host. It reaches "BOUND" state after the successful discover process, and will renew and/or rebind when T1/T2 timer expire. The state will be changed accordingly depending on the behavior of the server.
With this module you can move client's state, make transition, and even let it go freely. At each attempt of operation, it can tell whether it success or fail, so that you know if your server works as expected.
You can create many DHCP clients at the same time. In this way you can easily execute scalability test. Image you create 100 live DHCP clients, they are alive as though there were 100 hosts there, doing renew, rebind, or release interacting with your DHCP server for a few days, just like they do in real scenario.
I also provide some code showing how to do this in EXAMPLES section.
Client identifier - mac address is the identifier of a client, it's assigned when created and kept in the whole life cycle - xid is kept in the client life cycle until back to INIT, when xid is initialized
The following is the detail description of state transition. INIT->SELECT send DISCOVER, receive OFFER, check and report, return true if receiving DHCP OFFER from server, or false if no OFFER received. The state of client moves to SELECT anyway.
INIT->REQUEST SELECT->REQUEST send DISCOVER, receive OFFER, and send REQUEST, check ACK and report, return true if receiving both DHCP OFFER and ACK from server, or false otherwise The state of client moves to SELECT if no OFFER received or REQUEST if OFFER received. SELECT->SELECT same as INIT->SELECT, this allows you to test intensively the server response to DISCOVER REQUEST->REQUEST same as SELECT->REQUEST, this allows you to test intensively the server response to DISCOVER/REQUEST INIT->BOUND send DISCOVER, receive OFFER, and send REQUEST, receive ACK and update. return true only if the whole process correct. The state of client moves accordingly to SELECT, REQUEST, or BOUND SELECT if client sends DISCOVER REQUEST if client receives OFFER, then sends REQUEST BOUND if client receives ACK after sending REQUEST SELECT->BOUND back to INIT, then same to above REQUEST->BOUND send REQUEST, receive ACK and update (because client already has server offer info in obj) return true only if the client receives ACK. The state of client moves to BOUND if receives ACK, or stay at REQUEST if no ACK BOUND->BOUND Simulates T1 expire. Sends unicast REQUEST to server, and move to RENEW move to BOUND and refresh lease after receiving ACK from server return true if receives ACK Note: Linux server sends ARP request to client ip, client has to replay this ARP before Linux server sends ACK RENEW->BOUND REBIND->BOUND Simulates T2 expire. sends broadcase REQUEST, move to BOUND and refresh lease if receives ACK return true if receives ACK BOUND->RENEW Simulates T1 expire. Sends unicast REQUEST to server, and move to RENEW return true if receives ACK Note: Linux server sends ARP request to client ip, client also replay this ARP before Linux server sends ACK BOUND->REBIND Does BOUND->RENEW first Then ignore ACK and does RENEW->REBIND RENEW->REBIND Simulates T2 expire. sends broadcase REQUEST return true if receives ACK to this broadcase REQUEST REBIND->INIT RENEW->INIT Sends RELEASE and move to INIT RENEW->SELECT RENEW->REQUEST REBIND->SELECT REBIND->REQUEST 1. ->INIT 2. INIT->REQUEST undef->INIT do nothing SELECT->INIT clear XID REQUEST->INIT send DECLINE, clear XID
new - create a new Net::DHCPClientLive object
$clt = new Net::DHCPClientLive(interface => eth0, # interface name of your host state => 'BOUND', # state to be moved for this client, one of # INIT, SELECT,REQUEST,BOUND,RENEW,REBIND mac => '00:01:02:03:04:05', # default is auto-created randomly options => {key => value, ...}, # refer to rfc2131 for options verb => $verb); # print more pkt exchange info You don't need to specify options unless you have special interest, in which case, the dhcp packet exchangewill contain those options. If there is no "mac", the client is assgined one automatically, and it becomes the identifier of the client.
goState($state)
$clt->goState('RENEW'); The only argument to goState method is the state name you are driving the client to move to. It returns true if the client successfully move the state, otherwise returns false. Refer to "DESCRIPTION" section for detail of state transition Legal state name includes "INIT","SELECT","REQUEST","BOUND","RENEW", and "REBIND".
Other methods
These methods are called by goState. You probably don't need them. Just in case, you can use them to send some kind of DHCP packets. $clt->discover() $clt->request() $clt->renew() $clt->rebind() $clt->decline() $clt->release()
Here is a subroutine used to do state transition. It creates a client and try to move its state to $middleState, then it moves to $finalState if it is provided, It returns the client object on success, or false on failure.
sub stateTransition { my ($middleState,$finalState) = @_; my $clt; unless ($clt = new Net::DHCPClientLive( interface => "eth1", state => $middleState )) { print "server response abnormal to $clt->{cltmac}\n"; return 0; }else{ print "$clt->{cltmac} moved to $clt->{'state'}\n"; } return $clt unless($finalState); unless ($clt->goState($finalState)) { print "server response abnormal to $clt->{cltmac}\n"; return 0; }else{ print "$clt->{cltmac} moved to $clt->{'state'}\n"; } return $clt; }
Here is another example to simulate multiple live clients. Please note that each client exists as individual process in your host.
$SIG{CHLD} = sub {while( waitpid(-1, WNOHANG) > 0 ) {} }; $SIG{INT} = sub { kill 'KILL', 0 }; $SIG{QUIT} = sub { kill 'KILL', 0 }; my $clt; my @liveClt = (); # create $numClient clients for (my $k = 1; $k <= $numClient; $k++) { if ($clt = new Net::DHCPClientLive( interface => "$hostint", state => 'BOUND', verb => $verb)) { print "created live a client No.$k: $clt->{cltmac}\n"; my $W = gensym(); my $R = gensym(); my $pid; if (pipe($R,$W) && defined($pid = fork())) { if ($pid) { # keep the client close $W; $clt->{sock} = $R; push @liveClt, $clt; }else{ # a client is created close $R; open(STDOUT, ">&$W"); select $W; $| = 1; while (1) { my $now = time; while (time < $now + $clt->{t1}) {}; print "T1 expired, renewing ... "; unless ($clt->goState('BOUND')) { print "failed\n"; my $now = time; while (time < $now + $clt->{t2} - $clt->{t1}) {}; print "T2 expired, rebinding ..."; unless ($clt->goState('BOUND')) { print "rebinding failed, relasing the client\n"; $clt->goState('INIT'); exit 0; }else{ print "done\n"; } }else{ print "done\n"; } } } }else{ print("max clients has been created\n"); last; } }else{ print "No.$k client failed to go to BOUND\n"; } } # main process shows information printed by clients if (@liveClt) { print "Totally created ", scalar @liveClt, " client(s)\n"; my $liveCltSock = new IO::Select(); for (@liveClt) { $liveCltSock->add($_->{sock}); } while ( my @cltCanSay = $liveCltSock->can_read() ) { for my $cltSock (@cltCanSay) { my ($client) = grep {$_->{sock} eq $cltSock} @liveClt; my $msg = <$cltSock>; next if ($msg =~ /^\s*$/); print "$client->{cltmac}: $msg"; } } }
This module need to use the following modules Net::RawIP; Net::ARP; Net::PcapUtils; NetPacket::ARP; NetPacket::Ethernet; NetPacket::IP; NetPacket::UDP;
Ming Zhang, <ming2004@gmail.com
Copyright 2007 by Ming Zhang
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
To install Net::DHCPClientLive, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Net::DHCPClientLive
CPAN shell
perl -MCPAN -e shell install Net::DHCPClientLive
For more information on module installation, please visit the detailed CPAN module installation guide.