Update DHCP server for correctness, reliability, simplicity.
Actually keep track of which clients get which IP, only give PXE options to PXE clients, and provide more control over serving to PXE and/or normal clients. git-svn-id: file:///home/svn/framework3/trunk@13165 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
0318379ca8
commit
d1cfa7560f
|
@ -27,8 +27,6 @@ class Server
|
||||||
self.context = context
|
self.context = context
|
||||||
self.sock = nil
|
self.sock = nil
|
||||||
|
|
||||||
@shutting_down = false
|
|
||||||
|
|
||||||
self.myfilename = hash['FILENAME'] || ""
|
self.myfilename = hash['FILENAME'] || ""
|
||||||
self.myfilename << ("\x00" * (128 - self.myfilename.length))
|
self.myfilename << ("\x00" * (128 - self.myfilename.length))
|
||||||
|
|
||||||
|
@ -74,17 +72,10 @@ class Server
|
||||||
end
|
end
|
||||||
|
|
||||||
self.served = {}
|
self.served = {}
|
||||||
if (hash['SERVEONCE'])
|
self.serveOnce = hash.include?('SERVEONCE')
|
||||||
self.serveOnce = true
|
|
||||||
else
|
self.servePXE = (hash.include?('PXE') or hash.include?('FILENAME') or hash.include?('PXEONLY'))
|
||||||
self.serveOnce = false
|
self.serveOnlyPXE = hash.include?('PXEONLY')
|
||||||
end
|
|
||||||
|
|
||||||
if (hash['PXE'])
|
|
||||||
self.servePXE = true
|
|
||||||
else
|
|
||||||
self.servePXE = false
|
|
||||||
end
|
|
||||||
|
|
||||||
# Always assume we don't give out hostnames ...
|
# Always assume we don't give out hostnames ...
|
||||||
self.give_hostname = false
|
self.give_hostname = false
|
||||||
|
@ -120,8 +111,8 @@ class Server
|
||||||
|
|
||||||
# Stop the DHCP server
|
# Stop the DHCP server
|
||||||
def stop
|
def stop
|
||||||
@shutting_down = true
|
|
||||||
self.thread.kill
|
self.thread.kill
|
||||||
|
self.served = {}
|
||||||
self.sock.close rescue nil
|
self.sock.close rescue nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -131,7 +122,7 @@ class Server
|
||||||
allowed_options = [
|
allowed_options = [
|
||||||
:serveOnce, :servePXE, :relayip, :leasetime, :dnsserv,
|
:serveOnce, :servePXE, :relayip, :leasetime, :dnsserv,
|
||||||
:pxeconfigfile, :pxepathprefix, :pxereboottime, :router,
|
:pxeconfigfile, :pxepathprefix, :pxereboottime, :router,
|
||||||
:give_hostname, :served_hostname, :served_over
|
:give_hostname, :served_hostname, :served_over, :serveOnlyPXE
|
||||||
]
|
]
|
||||||
|
|
||||||
opts.each_pair { |k,v|
|
opts.each_pair { |k,v|
|
||||||
|
@ -158,7 +149,7 @@ class Server
|
||||||
attr_accessor :listen_host, :listen_port, :context, :leasetime, :relayip, :router, :dnsserv
|
attr_accessor :listen_host, :listen_port, :context, :leasetime, :relayip, :router, :dnsserv
|
||||||
attr_accessor :sock, :thread, :myfilename, :ipstring, :served, :serveOnce
|
attr_accessor :sock, :thread, :myfilename, :ipstring, :served, :serveOnce
|
||||||
attr_accessor :current_ip, :start_ip, :end_ip, :broadcasta, :netmaskn
|
attr_accessor :current_ip, :start_ip, :end_ip, :broadcasta, :netmaskn
|
||||||
attr_accessor :servePXE, :pxeconfigfile, :pxepathprefix, :pxereboottime
|
attr_accessor :servePXE, :pxeconfigfile, :pxepathprefix, :pxereboottime, :serveOnlyPXE
|
||||||
attr_accessor :give_hostname, :served_hostname, :served_over
|
attr_accessor :give_hostname, :served_hostname, :served_over
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
@ -242,24 +233,26 @@ protected
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if pxeclient == false && self.servePXE == true
|
# don't serve if only serving PXE and not PXE request
|
||||||
#dlog ("No tftp server request; ignoring (probably not PXE client)")
|
return if pxeclient == false and self.serveOnlyPXE == true
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
# prepare response
|
# prepare response
|
||||||
pkt = [Response].pack('C')
|
pkt = [Response].pack('C')
|
||||||
pkt << buf[1..7] #hwtype, hwlen, hops, txid
|
pkt << buf[1..7] #hwtype, hwlen, hops, txid
|
||||||
pkt << "\x00\x00\x00\x00" #elapsed, flags
|
pkt << "\x00\x00\x00\x00" #elapsed, flags
|
||||||
pkt << clientip
|
pkt << clientip
|
||||||
if messageType == DHCPDiscover
|
|
||||||
# give next ip address (not super reliable high volume but it should work for a basic server)
|
# if this is somebody we've seen before, use the saved IP
|
||||||
|
if self.served.include?( buf[28..43] )
|
||||||
|
pkt << Rex::Socket.addr_iton(self.served[buf[28..43]][0])
|
||||||
|
else # otherwise go to next ip address
|
||||||
self.current_ip += 1
|
self.current_ip += 1
|
||||||
if self.current_ip > self.end_ip
|
if self.current_ip > self.end_ip
|
||||||
self.current_ip = self.start_ip
|
self.current_ip = self.start_ip
|
||||||
end
|
end
|
||||||
|
self.served.merge!( buf[28..43] => [ self.current_ip, messageType == DHCPRequest ] )
|
||||||
|
pkt << Rex::Socket.addr_iton(self.current_ip)
|
||||||
end
|
end
|
||||||
pkt << Rex::Socket.addr_iton(self.current_ip)
|
|
||||||
pkt << self.ipstring #next server ip
|
pkt << self.ipstring #next server ip
|
||||||
pkt << self.relayip
|
pkt << self.relayip
|
||||||
pkt << buf[28..43] #client hw address
|
pkt << buf[28..43] #client hw address
|
||||||
|
@ -270,15 +263,17 @@ protected
|
||||||
|
|
||||||
if messageType == DHCPDiscover #DHCP Discover - send DHCP Offer
|
if messageType == DHCPDiscover #DHCP Discover - send DHCP Offer
|
||||||
pkt << [DHCPOffer].pack('C')
|
pkt << [DHCPOffer].pack('C')
|
||||||
# check if already served based on hw addr (MAC address)
|
# check if already served an Ack based on hw addr (MAC address)
|
||||||
if self.serveOnce == true && self.served.has_key?(buf[28..43])
|
# if serveOnce & PXE, don't reply to another PXE request
|
||||||
#dlog ("Already served; allowing normal boot")
|
# if serveOnce & ! PXE, don't reply to anything
|
||||||
|
if self.serveOnce == true and self.served.has_key?(buf[28..43]) and
|
||||||
|
self.served[buf[28..43]][1] and (pxeclient == true or self.servePXE == false)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
elsif messageType == DHCPRequest #DHCP Request - send DHCP ACK
|
elsif messageType == DHCPRequest #DHCP Request - send DHCP ACK
|
||||||
|
self.served[buf[28..43]][1] = true # mark as requested
|
||||||
pkt << [DHCPAck].pack('C')
|
pkt << [DHCPAck].pack('C')
|
||||||
# now we ignore their discovers (but we'll respond to requests in case a packet was lost)
|
# now we ignore their discovers (but we'll respond to requests in case a packet was lost)
|
||||||
self.served.merge!( buf[28..43] => true )
|
|
||||||
if ( self.served_over != 0 )
|
if ( self.served_over != 0 )
|
||||||
# NOTE: this is sufficient for low-traffic net
|
# NOTE: this is sufficient for low-traffic net
|
||||||
# for high-traffic, this will probably lead to
|
# for high-traffic, this will probably lead to
|
||||||
|
@ -286,8 +281,7 @@ protected
|
||||||
self.served_over += 1
|
self.served_over += 1
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
#dlog("ignoring unknown DHCP request - type #{messageType}")
|
return # ignore unknown DHCP request
|
||||||
return
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Options!
|
# Options!
|
||||||
|
@ -296,20 +290,20 @@ protected
|
||||||
pkt << dhcpoption(OpSubnetMask, self.netmaskn)
|
pkt << dhcpoption(OpSubnetMask, self.netmaskn)
|
||||||
pkt << dhcpoption(OpRouter, self.router)
|
pkt << dhcpoption(OpRouter, self.router)
|
||||||
pkt << dhcpoption(OpDns, self.dnsserv)
|
pkt << dhcpoption(OpDns, self.dnsserv)
|
||||||
pkt << dhcpoption(OpPXEMagic, PXEMagic)
|
if self.servePXE # PXE options
|
||||||
pkt << dhcpoption(OpPXEConfigFile, self.pxeconfigfile)
|
pkt << dhcpoption(OpPXEMagic, PXEMagic)
|
||||||
pkt << dhcpoption(OpPXEPathPrefix, self.pxepathprefix)
|
pkt << dhcpoption(OpPXEConfigFile, self.pxeconfigfile)
|
||||||
pkt << dhcpoption(OpPXERebootTime, [self.pxereboottime].pack('N'))
|
pkt << dhcpoption(OpPXEPathPrefix, self.pxepathprefix)
|
||||||
if ( self.give_hostname == true )
|
pkt << dhcpoption(OpPXERebootTime, [self.pxereboottime].pack('N'))
|
||||||
send_hostname = self.served_hostname
|
if ( self.give_hostname == true )
|
||||||
if ( self.served_over != 0 )
|
send_hostname = self.served_hostname
|
||||||
# NOTE : see above comments for the 'uniqueness'
|
if ( self.served_over != 0 )
|
||||||
# of this value
|
# NOTE : see above comments for the 'uniqueness' of this value
|
||||||
send_hostname += self.served_over.to_s
|
send_hostname += self.served_over.to_s
|
||||||
|
end
|
||||||
|
pkt << dhcpoption(OpHostname, send_hostname)
|
||||||
end
|
end
|
||||||
pkt << dhcpoption(OpHostname, send_hostname)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
pkt << dhcpoption(OpEnd)
|
pkt << dhcpoption(OpEnd)
|
||||||
|
|
||||||
pkt << ("\x00" * 32) #padding
|
pkt << ("\x00" * 32) #padding
|
||||||
|
|
Loading…
Reference in New Issue