added dhcp scripts
This commit is contained in:
parent
00530f7f44
commit
6560762504
1 changed files with 640 additions and 0 deletions
640
dhcp/gendhcp.pl
Executable file
640
dhcp/gendhcp.pl
Executable file
|
@ -0,0 +1,640 @@
|
||||||
|
#! /usr/bin/perl
|
||||||
|
#
|
||||||
|
# File: gendhcp.p
|
||||||
|
# Author: Darin Davis, Copyright 1998
|
||||||
|
# Date: 19 January 1998
|
||||||
|
# Update: 28 October 1998
|
||||||
|
# Desc: gendhcp.p is designed to test the ability of a DHCP server
|
||||||
|
# to respond to a large number of DHCP client requests submitted
|
||||||
|
# in rapid succession. Each DISCOVER message contains a unique:
|
||||||
|
#
|
||||||
|
# - Hardware address (CHADDR), beginning with '0fffffff'
|
||||||
|
# and ending with a unique 16-bit number (starting by
|
||||||
|
# default with 1).
|
||||||
|
# - Client ID, identical to the hardware address
|
||||||
|
# - XID, beginning with 'eeee' and ending with the same
|
||||||
|
# ending number as the hardware address
|
||||||
|
# - Hostname, beginning with 'dhcp-client-' and ending
|
||||||
|
# with the same ending number as the hardware address
|
||||||
|
# except in decimal rather than hex
|
||||||
|
#
|
||||||
|
# The script logic can be outlined as follows:
|
||||||
|
#
|
||||||
|
# 1 - Blast out all the DISCOVER msgs and optionally wait a
|
||||||
|
# user-specified number of seconds to give the server a chance
|
||||||
|
# to respond.
|
||||||
|
#
|
||||||
|
# 2 - Send REQUESTS for all the OFFERs in my input socket.
|
||||||
|
#
|
||||||
|
# 3 - Make note of any ACKs I receive.
|
||||||
|
#
|
||||||
|
# 4 - If I haven't received all the OFFERs, then resend DISCOVERs
|
||||||
|
# for each DISCOVER as yet unOFFERed and optionally wait a
|
||||||
|
# user-specified number of seconds to give the server a chance
|
||||||
|
# to respond and go to step 2.
|
||||||
|
#
|
||||||
|
# 5 - If I have received all the OFFERs but not all the ACKs, then
|
||||||
|
# resend a DISCOVER for each ACK I am missing and go to step 2.
|
||||||
|
# Note that this is a departure from the RFC which suggests the
|
||||||
|
# client should reREQUEST not reDISCOVER. But the implementation
|
||||||
|
# was simpler this way.
|
||||||
|
#
|
||||||
|
# When the reDISCOVER is performed, the same XID is used.
|
||||||
|
# This can cause problems for later versions of the QIP DHCP
|
||||||
|
# server which have a configuration parameter "CheckTransactionID".
|
||||||
|
# This parameter defaults to TRUE, meaning that the server will
|
||||||
|
# not issue an address for a previously detected Transaction ID
|
||||||
|
# (XID)/MAC address tuple. To suppress this behavior, set the
|
||||||
|
# "CheckTransactionID" policy to FALSE by putting the following
|
||||||
|
# into the dhcpd.pcy file:
|
||||||
|
#
|
||||||
|
# CheckTransactionID=0
|
||||||
|
#
|
||||||
|
# Thanks to Gary DiFazio for providing this information about QIP.
|
||||||
|
#
|
||||||
|
# There are no timeouts in the script. Only the optional wait.
|
||||||
|
#
|
||||||
|
# gendhcp.p simulates the four packet exchange DISCOVER-OFFER-
|
||||||
|
# REQUEST-ACK, and maintains two associative arrays, one for
|
||||||
|
# outstanding OFFERs and one for outstanding ACKs. The arrays
|
||||||
|
# are indexed by the CHADDR of the DISCOVER packet. gendhcp.p
|
||||||
|
# first blasts out all the DISCOVER messages, noting the CHADDRs
|
||||||
|
# in the Offers and Acks arrays, and then goes into a loop waiting
|
||||||
|
# for responses. If it receives an OFFER, it sends a REQUEST and
|
||||||
|
# deletes the CHADDR from the Offers array. If it receives an ACK,
|
||||||
|
# it deletes the CHADDR from the Acks array. If there are no
|
||||||
|
# responses from a server to read but there are still outstanding
|
||||||
|
# OFFERs or ACKs, it reDISCOVERS everything in the Offers array (or
|
||||||
|
# if empty, the Acks array). It continues this process until all
|
||||||
|
# ACKs have been received.
|
||||||
|
#
|
||||||
|
# Some DHCP servers send their OFFER messages to the IP broadcast
|
||||||
|
# address. Others (such as NTS IPserver) address the OFFER to the
|
||||||
|
# IP address which it is offering. Because the OFFER is not
|
||||||
|
# addressed to the machine on which you run gendhcp.p, gendhcp.p
|
||||||
|
# can't receive the offer. So, to test a server of the latter
|
||||||
|
# variety, use the '-r' option. This puts gendhcp.p in "relay
|
||||||
|
# agent" mode. It puts your machine's address in the GIADDR field,
|
||||||
|
# convincing the unsuspecting DHCP server that your machine is
|
||||||
|
# actually a router. So, the DHCP server addressees the OFFER to
|
||||||
|
# your machine.
|
||||||
|
#
|
||||||
|
# The author used tcpdump (on the same machine as gendhcp.p) in
|
||||||
|
# attempt to measure the effectiveness of the script. tcpdump
|
||||||
|
# didn't capture all the packets sent and received. Therefore,
|
||||||
|
# you would do well to use a standalone Sniffer-like device for
|
||||||
|
# any tracing.
|
||||||
|
#
|
||||||
|
# gendhcp.p is intended for testing a single DHCP server. If
|
||||||
|
# multiple DHCP servers are active, gendhcp.p will REQUEST only
|
||||||
|
# one IP address for a given hardware address (just as a normal
|
||||||
|
# DHCP client would).
|
||||||
|
#
|
||||||
|
# Developed for Linux with modifications for Solaris.
|
||||||
|
#
|
||||||
|
# Usage: See &usage().
|
||||||
|
|
||||||
|
|
||||||
|
########################
|
||||||
|
### GLOBAL CONSTANTS ###
|
||||||
|
########################
|
||||||
|
|
||||||
|
# define which OS this is
|
||||||
|
if (system("test `uname` = SunOS") == 0) {
|
||||||
|
$OS = "SunOS";
|
||||||
|
}
|
||||||
|
else { $OS = "Linux" }
|
||||||
|
#print "OS = $OS\n";
|
||||||
|
|
||||||
|
$AF_INET = 2; # define address family
|
||||||
|
|
||||||
|
if ($OS eq "Linux") { # Linux-specific definitions
|
||||||
|
$SOCK_DGRAM = 2; # define socket type
|
||||||
|
$SO_BROADCAST = 6;
|
||||||
|
$SOL_SOCKET = 1;
|
||||||
|
}
|
||||||
|
else { # Solaris-specific definitions
|
||||||
|
$SOCK_DGRAM = 1; # define socket type
|
||||||
|
$SO_BROADCAST = 32;
|
||||||
|
$SOL_SOCKET = 65535;
|
||||||
|
}
|
||||||
|
|
||||||
|
$SOCKADDR_FMT = 'S n a4 x8'; # set pack format
|
||||||
|
$DHCP_SERVER_PORT = 67;
|
||||||
|
$DHCP_CLIENT_PORT = 68;
|
||||||
|
$MAX_LEN = 1024; # max length of datagram
|
||||||
|
$FLAGS = 0; # flags for recv()
|
||||||
|
$DISC_MAX = 65000; # maximum number of discover msgs
|
||||||
|
# to be generated
|
||||||
|
$INADDR_ANY = pack("C4", split(/\./, "0.0.0.0"));
|
||||||
|
$SO_RCVBUF = 8;
|
||||||
|
$OPT_VAL = 1;
|
||||||
|
$TRUE = 1 == 1;
|
||||||
|
$DISC_MSG = 1;
|
||||||
|
$OFFER_MSG = 2;
|
||||||
|
$RQST_MSG = 3;
|
||||||
|
$ACK_MSG = 5;
|
||||||
|
$DELAY_MAX = 10; # limit on how long to wait before
|
||||||
|
# reading server replies
|
||||||
|
|
||||||
|
|
||||||
|
########################
|
||||||
|
### GLOBAL VARIABLES ###
|
||||||
|
########################
|
||||||
|
|
||||||
|
$Server_hostname = "255.255.255.255"; # default name of server host
|
||||||
|
$Server_pport; # packed remote port number
|
||||||
|
@Server_ipaddr; # server's IP address
|
||||||
|
@Client_ipaddr; # my IP address
|
||||||
|
*CS; # descriptor of socket bound to
|
||||||
|
# local DHCP client port
|
||||||
|
*SS; # descriptor of socket bound to
|
||||||
|
# local DHCP server port
|
||||||
|
$Protocol_name; # name of UDP protocol
|
||||||
|
$Protocol_aliases; # aliases of UDP
|
||||||
|
$Protocol_number; # UDP's protocol number
|
||||||
|
$Addr_family; # client's address family
|
||||||
|
$Discover_count = 1; # number of discover msgs to send
|
||||||
|
$Datagram; # server's reply message
|
||||||
|
$Suppress_request = ! $TRUE; # DO send requests
|
||||||
|
$Offer_cnt = 0; # number of OFFERs received
|
||||||
|
$Ack_cnt = 0; # number of ACKs received
|
||||||
|
$Relay = ! $TRUE; # boolean flag: should I act like a
|
||||||
|
# BOOTP relay agent (by listening
|
||||||
|
# for offers on the BOOTPS port)?
|
||||||
|
$Haddr = 1; # initial hardware address suffix
|
||||||
|
$Rc; # Return Code for system calls
|
||||||
|
%Offers; # outstanding (unreceived) OFFER msgs
|
||||||
|
%Acks; # outstanding (unreceived) ACK msgs
|
||||||
|
@Start_times; # user, system and elapsed start times
|
||||||
|
@End_times; # user, system and elapsed end times
|
||||||
|
$Delay = 0; # how long to wait before trying to
|
||||||
|
# read replies from server
|
||||||
|
$Retry = 0; # how many times we have to reDISCOVER
|
||||||
|
$Last_ack_cnt = 0; # last count of ACKs received
|
||||||
|
$Progress = ! $TRUE; # boolean flag: should I show the
|
||||||
|
# number of ACKs received?
|
||||||
|
|
||||||
|
###################
|
||||||
|
### SUBROUTINES ###
|
||||||
|
###################
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
# defines functions needed to set
|
||||||
|
# socket to non-blocking using fcntl
|
||||||
|
#####################################
|
||||||
|
sub F_SETFL {4;}
|
||||||
|
|
||||||
|
if ($OS eq "Linux") { # Linux-specific definition
|
||||||
|
sub O_NONBLOCK {04000;}
|
||||||
|
}
|
||||||
|
else { # Solaris-specific definition
|
||||||
|
sub O_NONBLOCK {0x80;}
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################
|
||||||
|
# creates socket and binds to
|
||||||
|
# DHCP client port
|
||||||
|
# GLOBAL VARS: Server_hostname,
|
||||||
|
# Server_pport, Client_ipaddr, CS, SS
|
||||||
|
######################################
|
||||||
|
sub setup_socket {
|
||||||
|
local($client_hostname, # name of this host
|
||||||
|
$client_pport # packed local port number
|
||||||
|
);
|
||||||
|
|
||||||
|
chop($client_hostname = `hostname`); # get my hostname
|
||||||
|
|
||||||
|
# get UDP's protocol number
|
||||||
|
($Protocol_name,$Protocol_aliases,$Protocol_number) = getprotobyname('udp');
|
||||||
|
|
||||||
|
# get my IP address
|
||||||
|
($Protocol_name,$Protocol_aliases,$type,$len,@Client_ipaddr) = gethostbyname($client_hostname);
|
||||||
|
|
||||||
|
# get server's IP address
|
||||||
|
($Protocol_name,$Protocol_aliases,$type,$len,@Server_ipaddr) = gethostbyname($Server_hostname);
|
||||||
|
|
||||||
|
# define fully-specified port addrs
|
||||||
|
$client_pport = pack($SOCKADDR_FMT, $AF_INET, $DHCP_CLIENT_PORT, $INADDR_ANY);
|
||||||
|
$Server_pport = pack($SOCKADDR_FMT, $AF_INET, $DHCP_SERVER_PORT, $Server_ipaddr[0]);
|
||||||
|
|
||||||
|
# create UDP socket
|
||||||
|
socket(CS, $AF_INET, $SOCK_DGRAM, $Protocol_number) ||
|
||||||
|
die("$0: cannot create CS socket ($!)");
|
||||||
|
|
||||||
|
# set socket to non-blocking
|
||||||
|
($Rc = fcntl(CS, &F_SETFL, &O_NONBLOCK)) ||
|
||||||
|
printf("error (%d) setting CS to non-blocking\n", $Rc);
|
||||||
|
|
||||||
|
|
||||||
|
# enable send/recv broadcasts
|
||||||
|
$Rc = setsockopt(CS, $SOL_SOCKET, $SO_BROADCAST, $OPT_VAL);
|
||||||
|
if (! defined($Rc)) { print "error calling setsockopt(SO_BROADCAST) for CS\n"; }
|
||||||
|
|
||||||
|
# bind to the socket
|
||||||
|
bind(CS, $client_pport) || die("$0: cannot bind CS socket to DHCP client port ($!)");
|
||||||
|
|
||||||
|
# setup extra socket in case we
|
||||||
|
# have to act as the relay agent
|
||||||
|
if ($Relay) {
|
||||||
|
$client_pport = pack($SOCKADDR_FMT, $AF_INET, $DHCP_SERVER_PORT, $INADDR_ANY);
|
||||||
|
|
||||||
|
# create UDP socket
|
||||||
|
socket(SS, $AF_INET, $SOCK_DGRAM, $Protocol_number) ||
|
||||||
|
die("$0: cannot create SS socket ($!)");
|
||||||
|
|
||||||
|
# set socket to non-blocking
|
||||||
|
($Rc = fcntl(SS, &F_SETFL, &O_NONBLOCK)) ||
|
||||||
|
printf("error (%d) setting SS to non-blocking\n", $Rc);
|
||||||
|
|
||||||
|
# enable send/recv broadcasts
|
||||||
|
$Rc = setsockopt(SS, $SOL_SOCKET, $SO_BROADCAST, $OPT_VAL);
|
||||||
|
if (! defined($Rc)) { print "error calling setsockopt(SO_BROADCAST) for SS\n"; }
|
||||||
|
|
||||||
|
# bind to the socket
|
||||||
|
bind(SS, $client_pport) || die("$0: cannot bind SS socket to DHCP server port ($!)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
# builds and sends $discover_count
|
||||||
|
# number of DHCP DISCOVER messages
|
||||||
|
# GLOBAL VARS: CS, FLAGS, Server_pport
|
||||||
|
# Haddr
|
||||||
|
#####################################
|
||||||
|
sub send_discovers {
|
||||||
|
local($discover_count) = @_;
|
||||||
|
local($xid, $msg, $hostname, $hnlen, $tmp);
|
||||||
|
|
||||||
|
$xid = $Haddr; # initialize incremental variables
|
||||||
|
|
||||||
|
# build and send DISCOVER messages
|
||||||
|
while ($discover_count-- > 0) {
|
||||||
|
|
||||||
|
$msg = sprintf("0fffffff%04x", $Haddr);
|
||||||
|
$Offers{$msg} = $TRUE; # this DISCOVER msg has an outstanding
|
||||||
|
# OFFER msg
|
||||||
|
$Acks{$msg} = $TRUE; # this DISCOVER msg has an outstanding
|
||||||
|
# ACK msg
|
||||||
|
|
||||||
|
# op, htype, hlen, hops
|
||||||
|
$msg = pack("H2" x 4, "01", "01", "06", "00");
|
||||||
|
# xid, secs, flags
|
||||||
|
$msg .= pack("H4 n H8", "eeee", $xid++, 0);
|
||||||
|
# ciaddr, yiaddr, siaddr, giaddr
|
||||||
|
if ($Relay) {
|
||||||
|
$msg .= pack("H8 H8 H8 C4", 0, 0, 0, unpack("C4", $Client_ipaddr[0]));
|
||||||
|
}
|
||||||
|
else { $msg .= pack("H8 H8 H8 H8", 0, 0, 0, 0); }
|
||||||
|
|
||||||
|
# chaddr
|
||||||
|
$msg .= pack("H8 n H20", "0fffffff", $Haddr, 0);
|
||||||
|
$msg .= pack("H384", "0"); # sname, file
|
||||||
|
$msg .= pack("H8", "63825363"); # magic cookie
|
||||||
|
$msg .= pack("H6", "350101"); # message type DISCOVER
|
||||||
|
# client ID = chaddr
|
||||||
|
$msg .= pack("H4 H8 n", "3d06", "0fffffff", $Haddr);
|
||||||
|
|
||||||
|
### create unique hostname ###
|
||||||
|
$tmp = sprintf("dhcp-client-%05d", $Haddr++);
|
||||||
|
$hostname = "";
|
||||||
|
while (length($tmp) > 0) { # convert string to hex
|
||||||
|
$hostname .= sprintf("%02x", ord($tmp));
|
||||||
|
$tmp =~ s/^.//;
|
||||||
|
}
|
||||||
|
$hnlen = length($hostname); # hostname length
|
||||||
|
$msg .= pack("H2 C H$hnlen", "0c", $hnlen/2, "$hostname");
|
||||||
|
|
||||||
|
$msg .= pack("H2", "ff"); # end of options
|
||||||
|
# send msg
|
||||||
|
send(CS, $msg, $FLAGS, $Server_pport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#####################################
|
||||||
|
# resends DHCP DISCOVER messages
|
||||||
|
# for each HW addr in %Offers
|
||||||
|
# GLOBAL VARS: CS, FLAGS, Server_pport
|
||||||
|
# Haddr, Retry, Delay
|
||||||
|
# RETURNS: number of DISCOVERs sent
|
||||||
|
#####################################
|
||||||
|
sub rediscover {
|
||||||
|
local($xid, $msg, $cnt, $hostname, $hnlen, $tmp);
|
||||||
|
|
||||||
|
$cnt = 0;
|
||||||
|
$Retry++;
|
||||||
|
# build and send DISCOVER messages
|
||||||
|
foreach $Haddr (keys %Offers) {
|
||||||
|
$xid = $Haddr;
|
||||||
|
$xid =~ s/^0fffffff//; # behead MAC addr prefix
|
||||||
|
|
||||||
|
# op, htype, hlen, hops
|
||||||
|
$msg = pack("H2" x 4, "01", "01", "06", "00");
|
||||||
|
# xid, secs, flags
|
||||||
|
$msg .= pack("H4 n H8", "eeee", $xid, 0);
|
||||||
|
# ciaddr, yiaddr, siaddr, giaddr
|
||||||
|
if ($Relay) {
|
||||||
|
$msg .= pack("H8 H8 H8 C4", 0, 0, 0, unpack("C4", $Client_ipaddr[0]));
|
||||||
|
}
|
||||||
|
else { $msg .= pack("H8 H8 H8 H8", 0, 0, 0, 0); }
|
||||||
|
|
||||||
|
# chaddr
|
||||||
|
$msg .= pack("H12 H20", $Haddr, 0);
|
||||||
|
$msg .= pack("H384", "0"); # sname, file
|
||||||
|
$msg .= pack("H8", "63825363"); # magic cookie
|
||||||
|
$msg .= pack("H6", "350101"); # message type DISCOVER
|
||||||
|
# client ID = chaddr
|
||||||
|
$msg .= pack("H4 H12", "3d06", $Haddr);
|
||||||
|
|
||||||
|
### create unique hostname ###
|
||||||
|
$tmp = sprintf("dhcp-client-%05d", $xid);
|
||||||
|
$hostname = "";
|
||||||
|
while (length($tmp) > 0) { # convert string to hex
|
||||||
|
$hostname .= sprintf("%02x", ord($tmp));
|
||||||
|
$tmp =~ s/^.//;
|
||||||
|
}
|
||||||
|
$hnlen = length($hostname); # hostname length
|
||||||
|
$msg .= pack("H2 C H$hnlen", "0c", $hnlen/2, "$hostname");
|
||||||
|
|
||||||
|
$msg .= pack("H2", "ff"); # end of options
|
||||||
|
|
||||||
|
# send msg
|
||||||
|
send(CS, $msg, $FLAGS, $Server_pport);
|
||||||
|
$cnt++; # incr count of msgs sent
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($Delay > 0) { sleep($Delay); } # give server a chance to respond
|
||||||
|
return($cnt);
|
||||||
|
}
|
||||||
|
###################################
|
||||||
|
# builds and sends a single DHCP
|
||||||
|
# REQUEST message (if the message
|
||||||
|
# from the server is an OFFER not
|
||||||
|
# an ACK)
|
||||||
|
# GLOBAL VARS: CS and almost every
|
||||||
|
# other "local" var used herein
|
||||||
|
# RETURNS: DHCP msg type
|
||||||
|
###################################
|
||||||
|
sub send_request {
|
||||||
|
local($datagram) = @_;
|
||||||
|
local($server_id, $msg_type, $tmp_chaddr,
|
||||||
|
$client_id, $tmp, $hostname, $hnlen);
|
||||||
|
|
||||||
|
$msg_type = 0; # init local vars
|
||||||
|
$server_id = "";
|
||||||
|
|
||||||
|
$DHCP_STRUCT = "H2 H2 H2 H2 H8 H4 H4 H8 H8 H8 H8 H32 H384 H8 H*";
|
||||||
|
($op, $htype, $hlen, $hops, $xid, $secs, $flags, $ciaddr, $yiaddr, $siaddr, $giaddr, $chaddr, $sname_file, $cookie, $options) = unpack($DHCP_STRUCT, $datagram);
|
||||||
|
|
||||||
|
$tmp_opt = $options;
|
||||||
|
$tmp_chaddr = substr($chaddr, 0, 12); # trunc trailing zeros
|
||||||
|
|
||||||
|
# determine whether this is an ACK
|
||||||
|
# or OFFER by searching through
|
||||||
|
# options
|
||||||
|
while (length($tmp_opt) > 3) {
|
||||||
|
# ASSUMES no pad options!
|
||||||
|
$option = substr($tmp_opt, 0, 2); # extract option
|
||||||
|
$length = substr($tmp_opt, 2, 2); # extract length
|
||||||
|
# extract value
|
||||||
|
$value = substr($tmp_opt, 4, 2 * hex($length));
|
||||||
|
# behead leading option
|
||||||
|
$tmp_opt = substr($tmp_opt, 4 + 2 * hex($length));
|
||||||
|
|
||||||
|
if ($option eq "35") { # if this is DHCP_Msg_Type option
|
||||||
|
$msg_type = hex($value);
|
||||||
|
if ($msg_type == $ACK_MSG) { # if this is an ACK
|
||||||
|
|
||||||
|
# if I haven't yet seen this addr's ACK
|
||||||
|
if (defined($Acks{$tmp_chaddr})) {
|
||||||
|
delete($Acks{$tmp_chaddr}); # remove addr from ACK list
|
||||||
|
$Ack_cnt++; # increment number of ACKs recv'd
|
||||||
|
}
|
||||||
|
return($msg_type); # stop processing
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($msg_type != $OFFER_MSG) { # if this is NOT an OFFER
|
||||||
|
return($msg_type); # then stop processing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($option eq "36") { # if this is Server_ID option
|
||||||
|
$server_id = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($msg_type != $OFFER_MSG) { # there was no DHCP_Msg_Type option
|
||||||
|
return($msg_type); # so stop processing
|
||||||
|
}
|
||||||
|
# this addr no longer has an
|
||||||
|
# outstanding OFFER
|
||||||
|
if (defined($Offers{$tmp_chaddr})) {
|
||||||
|
delete($Offers{$tmp_chaddr}); # remove addr from list
|
||||||
|
$Offer_cnt++; # increment number of OFFERs recv'd
|
||||||
|
}
|
||||||
|
else { return($msg_type); }
|
||||||
|
|
||||||
|
$rqst_msg = "350103"; # build REQUEST message type
|
||||||
|
$addr_rqst = "3204$yiaddr"; # build address request
|
||||||
|
if ($server_id) {
|
||||||
|
$srvr_id = "3604$server_id"; # server identifier
|
||||||
|
}
|
||||||
|
else { $srvr_id = "3604$siaddr"; }
|
||||||
|
|
||||||
|
$client_id = "3d06$tmp_chaddr"; # client identifier
|
||||||
|
|
||||||
|
### create unique hostname ###
|
||||||
|
$tmp_chaddr =~ s/^0fffffff//; # behead prefix
|
||||||
|
$tmp = sprintf("dhcp-client-%05d", hex($tmp_chaddr));
|
||||||
|
$hostname = "";
|
||||||
|
while (length($tmp) > 0) { # convert string to hex
|
||||||
|
$hostname .= sprintf("%02x", ord($tmp));
|
||||||
|
$tmp =~ s/^.//;
|
||||||
|
}
|
||||||
|
$hnlen = length($hostname); # hostname length
|
||||||
|
$hostname = sprintf("0c%02x$hostname", $hnlen/2);
|
||||||
|
|
||||||
|
$end_opt = "ff"; # end of options
|
||||||
|
|
||||||
|
$datagram = pack($DHCP_STRUCT, "01", $htype, $hlen, $hops, $xid, $secs, $flags, $ciaddr, "00000000", "00000000", $giaddr, $chaddr, $sname_file, $cookie, "$rqst_msg$addr_rqst$srvr_id$client_id$hostname$end_opt");
|
||||||
|
|
||||||
|
# send REQUEST msg
|
||||||
|
send(CS, $datagram, $FLAGS, $Server_pport);
|
||||||
|
|
||||||
|
return($msg_type);
|
||||||
|
}
|
||||||
|
#########################
|
||||||
|
# prints program usage
|
||||||
|
#########################
|
||||||
|
sub usage {
|
||||||
|
print <<END_USAGE;
|
||||||
|
|
||||||
|
Usage: $0 <flag> <value>
|
||||||
|
|
||||||
|
\tFlags\tValues
|
||||||
|
\t-a\tstarting hardware Address (default: 1)
|
||||||
|
\t-d\tnumber of Discover messages to send (default: 1)
|
||||||
|
\t-h, -?\tshow Help
|
||||||
|
\t-p\tshow Progress (number of ACKs received)
|
||||||
|
\t-r\tact like a Relay agent
|
||||||
|
\t-R\tsuppress sending REQUEST messages
|
||||||
|
\t-s\tServer hostname or IP address (default: broadcast)
|
||||||
|
\t-w\tWait time (in seconds) between retries (default: 0)
|
||||||
|
|
||||||
|
END_USAGE
|
||||||
|
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
#################
|
||||||
|
### MAIN CODE ###
|
||||||
|
#################
|
||||||
|
|
||||||
|
$| = 1; # flush writes
|
||||||
|
|
||||||
|
# ensure we're root so we can
|
||||||
|
# bind to priviledged sockets
|
||||||
|
chomp($USER = `whoami`);
|
||||||
|
if ($USER ne "root") {
|
||||||
|
print "\n\t*** You must be root to run this program. ***\n";
|
||||||
|
&usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
# process arguments
|
||||||
|
while($#ARGV >= 0) {
|
||||||
|
ARG_SWITCH: {
|
||||||
|
if ($ARGV[0] =~ /^(-h|-\?)$/) { &usage; }
|
||||||
|
|
||||||
|
# show progress
|
||||||
|
if ($ARGV[0] =~ /^-p$/) {
|
||||||
|
shift(@ARGV); # discard flag
|
||||||
|
$Progress = $TRUE;
|
||||||
|
last ARG_SWITCH;
|
||||||
|
}
|
||||||
|
# don't send request messages
|
||||||
|
if ($ARGV[0] =~ /^-R$/) {
|
||||||
|
shift(@ARGV); # discard flag
|
||||||
|
$Suppress_request = $TRUE;
|
||||||
|
last ARG_SWITCH;
|
||||||
|
}
|
||||||
|
# act as a relay agent
|
||||||
|
if ($ARGV[0] =~ /^-r$/) {
|
||||||
|
shift(@ARGV); # discard flag
|
||||||
|
$Relay = $TRUE;
|
||||||
|
last ARG_SWITCH;
|
||||||
|
}
|
||||||
|
# user specified server
|
||||||
|
if ($ARGV[0] =~ /^-s$/) {
|
||||||
|
shift(@ARGV); # discard flag
|
||||||
|
$Server_hostname = $ARGV[0];
|
||||||
|
shift(@ARGV); # discard server hostname
|
||||||
|
last ARG_SWITCH;
|
||||||
|
}
|
||||||
|
# user specified DISCOVER count
|
||||||
|
if ($ARGV[0] =~ /^-d$/) {
|
||||||
|
shift(@ARGV); # discard flag
|
||||||
|
$Discover_count = $ARGV[0];
|
||||||
|
if ($Discover_count < 1 || $Discover_count > $DISC_MAX) {
|
||||||
|
print "Discover count must be between 1 and $DISC_MAX.\n";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
shift(@ARGV); # discard server hostname
|
||||||
|
last ARG_SWITCH;
|
||||||
|
}
|
||||||
|
# user specified Wait time
|
||||||
|
if ($ARGV[0] =~ /^-w$/) {
|
||||||
|
shift(@ARGV); # discard flag
|
||||||
|
$Delay = $ARGV[0];
|
||||||
|
if ($Delay < 0 || $Delay > $DELAY_MAX) {
|
||||||
|
print "Wait time be between 0 and $DELAY_MAX.\n";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
shift(@ARGV); # discard Wait time
|
||||||
|
last ARG_SWITCH;
|
||||||
|
}
|
||||||
|
# user specified starting HW addr
|
||||||
|
if ($ARGV[0] =~ /^-a$/) {
|
||||||
|
shift(@ARGV); # discard flag
|
||||||
|
$Haddr = $ARGV[0];
|
||||||
|
if ($Haddr < 1 || $Haddr > $DISC_MAX) {
|
||||||
|
print "Starting hardware address must be between 1 and $DISC_MAX.\n";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
shift(@ARGV); # discard server hostname
|
||||||
|
last ARG_SWITCH;
|
||||||
|
}
|
||||||
|
print "Unknown flag '$ARGV[0]'.\n";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# create socket capable of broadcasts
|
||||||
|
&setup_socket($Server_hostname);
|
||||||
|
|
||||||
|
# get the start user, system, and...
|
||||||
|
($Start_times[0], $Start_times[1], $junk, $junk) = times;
|
||||||
|
$Start_times[2] = time; # ...absolute times
|
||||||
|
|
||||||
|
# blast out all the DISCOVER msgs
|
||||||
|
print "Sending $Discover_count DISCOVER messages...\n";
|
||||||
|
&send_discovers($Discover_count);
|
||||||
|
|
||||||
|
if ($Delay > 0) { sleep($Delay); } # give server a chance to respond
|
||||||
|
|
||||||
|
if ($Suppress_request) { exit; } # should I process the OFFER msgs?
|
||||||
|
|
||||||
|
# yes
|
||||||
|
print "Waiting for $Discover_count ACKs...\n";
|
||||||
|
while ($Ack_cnt < $Discover_count) {
|
||||||
|
|
||||||
|
# if I'm supposed to report progress
|
||||||
|
# then do so
|
||||||
|
if ($Progress) {
|
||||||
|
if (($Ack_cnt % 10) == 0 && $Ack_cnt > $Last_ack_cnt) {
|
||||||
|
print "$Ack_cnt ACKs...\n";
|
||||||
|
$Last_ack_cnt = $Ack_cnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# receive the OFFER/ACK msg
|
||||||
|
if ($Relay) {
|
||||||
|
$Rc = recv(SS, $Datagram, $MAX_LEN, $FLAGS);
|
||||||
|
}
|
||||||
|
else { $Rc = recv(CS, $Datagram, $MAX_LEN, $FLAGS); }
|
||||||
|
|
||||||
|
if (! defined($Rc)) { # if no more incoming messages
|
||||||
|
# to process
|
||||||
|
if ($Offer_cnt < $Discover_count) {
|
||||||
|
&rediscover;
|
||||||
|
}
|
||||||
|
else { # we've received all the OFFERs
|
||||||
|
|
||||||
|
if ($Ack_cnt < $Discover_count) { # if we're missing some ACKs
|
||||||
|
%Offers = %Acks; # then reDISCOVER (rather than
|
||||||
|
# reREQUEST as advised in RFC2131;
|
||||||
|
# this choice is for the sake of
|
||||||
|
# simplicity in this program)
|
||||||
|
$Offer_cnt = $Ack_cnt;
|
||||||
|
&rediscover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { # I have a reply to process
|
||||||
|
&send_request($Datagram); # send the REQUEST msg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
### print statistics ###
|
||||||
|
|
||||||
|
print "Received $Ack_cnt Acks.\n";
|
||||||
|
|
||||||
|
# get the ending user, system, and...
|
||||||
|
($End_times[0], $End_times[1], $junk, $junk) = times;
|
||||||
|
$End_times[2] = time; # ...absolute times
|
||||||
|
|
||||||
|
printf("\nTimes: %.2f user, %.2f system, %d elapsed\n",
|
||||||
|
$End_times[0] - $Start_times[0],
|
||||||
|
$End_times[1] - $Start_times[1],
|
||||||
|
$End_times[2] - $Start_times[2]);
|
||||||
|
|
||||||
|
print "Number of reDISCOVERies: $Retry\n";
|
||||||
|
|
||||||
|
close(CS); # close client socket
|
||||||
|
|
||||||
|
if ($Relay) { close(SS); } # close server socket
|
Loading…
Add table
Add a link
Reference in a new issue