dhcp 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/{LICENSE → LICENSE.txt} +1 -1
- data/{README → README.rdoc} +7 -3
- data/Rakefile +17 -7
- data/dhcp.rb.bak +1047 -0
- data/lib/dhcp/client.rb +24 -0
- data/lib/dhcp/dhcp.rb +37 -923
- data/lib/dhcp/options.rb +652 -0
- data/lib/dhcp/packet.rb +353 -0
- data/lib/dhcp/server.rb +141 -0
- data/lib/dhcp/version.rb +3 -2
- data/lib/dhcp.rb +4 -1
- metadata +48 -48
data/lib/dhcp/packet.rb
ADDED
@@ -0,0 +1,353 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: ASCII-8BIT
|
3
|
+
|
4
|
+
require_relative 'options'
|
5
|
+
|
6
|
+
module DHCP
|
7
|
+
|
8
|
+
## Class representing a DHCP packet (a request or a response)
|
9
|
+
## for creating said packets, or for parsing them from a UDP
|
10
|
+
## DHCP packet data payload.
|
11
|
+
class Packet
|
12
|
+
def initialize(opt={})
|
13
|
+
data = nil
|
14
|
+
if opt.is_a?(String)
|
15
|
+
data = opt
|
16
|
+
opt = {}
|
17
|
+
end
|
18
|
+
## 1: Operation (BOOTREQUEST=1/BOOTREPLY=2)
|
19
|
+
@op = opt[:op]
|
20
|
+
raise "Invalid/unsupported operation type #{@op}" unless @op.nil? || @op == BOOTREQUEST || @op == BOOTREPLY
|
21
|
+
@htype_name = :htype_10mb_ethernet ## Only supported type currently...
|
22
|
+
@htype = HTYPE[@htype_name][0] ## 1: Hardware address type
|
23
|
+
@hlen = HTYPE[@htype_name][1] ## 1: Hardware address length
|
24
|
+
@hops = 0 ## 1: Client sets to zero, relays may increment
|
25
|
+
@xid = opt[:xid] || 0 ## 4: Client picks random 32-bit XID (session ID of sorts)
|
26
|
+
@secs = opt[:secs] || 0 ## 4: Seconds elapsed since client started transaction
|
27
|
+
@flags = opt[:flats] || 0 ## 2: Leftmost bit is the 'BROADCAST' flag (if set) - Others are zero (reserved for future use)
|
28
|
+
|
29
|
+
## 4: "Client IP" -- Only set by client if client state is BOUND/RENEW/REBINDING and client can respond to ARP requests
|
30
|
+
@ciaddr = IPAddress::IPv4.new(opt[:ciaddr] || '0.0.0.0').data
|
31
|
+
|
32
|
+
## 4: "Your IP" -- Server assigns IP to client
|
33
|
+
@yiaddr = IPAddress::IPv4.new(opt[:yiaddr] || '0.0.0.0').data
|
34
|
+
|
35
|
+
## 4: "Server IP" -- IP of server to use in NEXT step of client bootstrap process
|
36
|
+
@siaddr = IPAddress::IPv4.new(opt[:siaddr] || '0.0.0.0').data
|
37
|
+
|
38
|
+
## 4: "Gateway IP" -- Relay agent will set this to itself and modify replies
|
39
|
+
@giaddr = IPAddress::IPv4.new(opt[:giaddr] || '0.0.0.0').data
|
40
|
+
|
41
|
+
## 16: Client hardware address (see htype and hlen)
|
42
|
+
@chaddr = (opt[:chaddr] || ('00' * @hlen)).gsub(%r{[ :._-]},'').downcase
|
43
|
+
raise 'Invalid client hardware address.' unless @chaddr.size == @hlen*2 && %r{\A[a-f0-9]{2}+\Z}.match(@chaddr)
|
44
|
+
@chaddr = @chaddr.scan(%r{..}m).map{|b| b.to_i(16).chr}.join
|
45
|
+
|
46
|
+
## 64: Server host name (optional) as C-style null/zero terminated string (may instead contain options)
|
47
|
+
## If provided by caller, do NOT include the C-style null/zero termination character.
|
48
|
+
@sname = opt[:sname] || ''
|
49
|
+
raise 'Invalid server host name string.' unless @sname.size < 64
|
50
|
+
|
51
|
+
## 128: Boot file name (optional) as C-style null/zero terminated string (may instead contain options)
|
52
|
+
## If provided by caller, do NOT include the C-style null/zero termination character.
|
53
|
+
@file = opt[:file] || ''
|
54
|
+
raise 'Invalid boot file name string.' unless @sname.size < 128
|
55
|
+
|
56
|
+
## variable: Options - Up to 312 bytes in a 576-byte DHCP message - First four bytes are MAGIC
|
57
|
+
@options = '' ## Preserve any parsed packet's original binary option data - NOT set for non-parsed generated packets
|
58
|
+
@optlist = []
|
59
|
+
|
60
|
+
@type = nil
|
61
|
+
@type_name = 'UNKNOWN'
|
62
|
+
if opt[:type]
|
63
|
+
include_opt(DHCP.make_opt_name(:dhcp_message_type, opt[:type].is_a?(String) ? DHCP::MSG_STR_TO_TYPE[opt[:type]] : opt[:type]))
|
64
|
+
end
|
65
|
+
|
66
|
+
## Default to BOOTREQUEST when generating a blank (invalid) packet:
|
67
|
+
@op = BOOTREQUEST if @op.nil?
|
68
|
+
|
69
|
+
## If a packet was provided, parse it:
|
70
|
+
_parse(data) unless data.nil?
|
71
|
+
end
|
72
|
+
attr_reader :op, :htype_name, :htype, :hlen, :hops, :xid, :secs, :flags, :type, :type_name, :options, :optlist
|
73
|
+
attr_accessor :secs, :xid
|
74
|
+
|
75
|
+
## Both #clone and #dup will call this:
|
76
|
+
def initialize_copy(orig)
|
77
|
+
self.ciaddr = orig.ciaddr
|
78
|
+
self.yiaddr = orig.yiaddr
|
79
|
+
self.siaddr = orig.siaddr
|
80
|
+
self.giaddr = orig.giaddr
|
81
|
+
@chaddr = orig.raw_chaddr.dup
|
82
|
+
@file = orig.file.dup
|
83
|
+
@sname = orig.sname.dup
|
84
|
+
@options = orig.options.dup
|
85
|
+
@optlist = []
|
86
|
+
orig.optlist.each do |opt|
|
87
|
+
@optlist << opt.dup
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
## It is recommended that when creating a DHCP packet from scratch, use
|
92
|
+
## include_opt(opt) instead so that the "end" option will be correctly
|
93
|
+
## added or moved to the end. append_opt(opt) will not automatically
|
94
|
+
## add an "end" nor will it move an existing "end" option, possibly
|
95
|
+
## resulting in an invalid DHCP packet if not used carefully.
|
96
|
+
def append_opt(opt)
|
97
|
+
if opt.name == :dhcp_message_type
|
98
|
+
unless @type.nil?
|
99
|
+
raise "DHCP message type ALREADY SET in packet"
|
100
|
+
end
|
101
|
+
set_type(opt)
|
102
|
+
end
|
103
|
+
@optlist << opt
|
104
|
+
end
|
105
|
+
|
106
|
+
def sname
|
107
|
+
## If the option overload is value 2 or 3, look for a :tftp_server_name option:
|
108
|
+
opt = get_option(:option_overload)
|
109
|
+
return @sname if opt.nil? || opt.get == 1
|
110
|
+
opt = get_option(:tftp_server_name)
|
111
|
+
return opt.nil? ? '' : opt.get
|
112
|
+
end
|
113
|
+
|
114
|
+
def sname=(val)
|
115
|
+
@sname=val
|
116
|
+
end
|
117
|
+
|
118
|
+
def file
|
119
|
+
## If the option overload is value 1 or 3, look for a :bootfile_name option:
|
120
|
+
opt = get_option(:option_overload)
|
121
|
+
return @file if opt.nil? || opt.get == 2
|
122
|
+
opt = get_option(:bootfile_name)
|
123
|
+
return opt.nil? ? '' : opt.get
|
124
|
+
end
|
125
|
+
|
126
|
+
## This is the best way to add an option to a DHCP packet:
|
127
|
+
def include_opt(opt)
|
128
|
+
list = @optlist
|
129
|
+
@options = ''
|
130
|
+
@optlist = []
|
131
|
+
list.each do |o|
|
132
|
+
## This implementation currently doesn't support duplicate options yet:
|
133
|
+
raise "Duplicate option in packet." if o.name == opt.name
|
134
|
+
## Skip/ignore the end option:
|
135
|
+
@optlist << o unless o.name == :end
|
136
|
+
end
|
137
|
+
append_opt(opt)
|
138
|
+
@optlist << Opt.new(255, :end)
|
139
|
+
end
|
140
|
+
|
141
|
+
def _find_htype(htype)
|
142
|
+
HTYPE.each do |name, htype|
|
143
|
+
if htype[0] == @htype
|
144
|
+
return name
|
145
|
+
end
|
146
|
+
end
|
147
|
+
return nil
|
148
|
+
end
|
149
|
+
|
150
|
+
def _parse(msg)
|
151
|
+
raise "Packet is too short (#{msg.size} < 241)" if (msg.size < 241)
|
152
|
+
@op = msg[0,1].ord
|
153
|
+
raise 'Invalid OP (expected BOOTREQUEST or BOOTREPLY)' if @op != BOOTREQUEST && @op != BOOTREPLY
|
154
|
+
self.htype = msg[1,1].ord ## This will do sanity checking and raise an exception on unsupported HTYPE
|
155
|
+
raise "Invalid hardware address length #{msg[2,1].ord} (expected #{@hlen})" if msg[2,1].ord != @hlen
|
156
|
+
@hops = msg[3,1].ord
|
157
|
+
@xid = msg[4,4].unpack('N')[0]
|
158
|
+
@secs = msg[8,2].unpack('n')[0]
|
159
|
+
@flags = msg[10,2].unpack('n')[0]
|
160
|
+
@ciaddr = msg[12,4]
|
161
|
+
@yiaddr = msg[16,4]
|
162
|
+
@siaddr = msg[20,4]
|
163
|
+
@giaddr = msg[24,4]
|
164
|
+
@chaddr = msg[28,16]
|
165
|
+
@sname = msg[44,64]
|
166
|
+
@file = msg[108,128]
|
167
|
+
magic = msg[236,4]
|
168
|
+
raise "Invalid DHCP OPTION MAGIC #{magic.each_byte.map{|b| ('0'+b.to_s(16).upcase)[-2,2]}.join(':')} != #{MAGIC.each_byte.map{|b| ('0'+b.to_s(16).upcase)[-2,2]}.join(':')}" if magic != MAGIC
|
169
|
+
@options = msg[240,msg.size-240]
|
170
|
+
@optlist = []
|
171
|
+
parse_opts(@options)
|
172
|
+
opt = get_option(:option_overload)
|
173
|
+
unless opt.nil?
|
174
|
+
## RFC 2131: If "option overload" present, parse FILE field first, then SNAME (depending on overload value)
|
175
|
+
parse_opts(@file) if opt.get == 1 || opt.get == 3
|
176
|
+
parse_opts(@sname) if opt.get == 2 || opt.get == 3
|
177
|
+
raise "Invalid option overload value" if opt.val > 1 || opt.val > 3
|
178
|
+
end
|
179
|
+
opt = get_option(:dhcp_message_type)
|
180
|
+
raise "Not a valid DHCP packet (may be BOOTP): Missing DHCP MESSAGE TYPE" if opt.nil?
|
181
|
+
set_type(opt)
|
182
|
+
self
|
183
|
+
end
|
184
|
+
|
185
|
+
def set_type(opt)
|
186
|
+
@type = opt.get
|
187
|
+
if DHCP::MSG_TYPE_TO_OP.key?(@type)
|
188
|
+
@type_name = DHCP::MSG_TYPE_TO_STR[@type]
|
189
|
+
@op = DHCP::MSG_TYPE_TO_OP[@type] if @op.nil?
|
190
|
+
raise "Invalid OP #{@op} for #{@type_name}" unless @op == DHCP::MSG_TYPE_TO_OP[@type]
|
191
|
+
else
|
192
|
+
raise "Invalid or unsupported DHCP MESSAGE TYPE"
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
## Look through a packet's options for the option in question:
|
197
|
+
def get_option(opt)
|
198
|
+
@optlist.each do |o|
|
199
|
+
return o if (opt.is_a?(Symbol) && o.name == opt) || (opt.is_a?(Fixnum) && o.opt == opt)
|
200
|
+
end
|
201
|
+
nil
|
202
|
+
end
|
203
|
+
|
204
|
+
def parse_opts(opts)
|
205
|
+
msg = opts.dup
|
206
|
+
while msg.size > 0
|
207
|
+
opt = msg[0,1].ord
|
208
|
+
if opt == 0
|
209
|
+
## Don't add padding options to our list...
|
210
|
+
msg[0,1] = ''
|
211
|
+
elsif opt == 255
|
212
|
+
## Options end... Assume all the rest is padding (if any)
|
213
|
+
@optlist << Opt.new(255, :end)
|
214
|
+
msg = ''
|
215
|
+
else
|
216
|
+
## TODO: If an option value can't fit within a single option,
|
217
|
+
## it may span several and the values should be merged. We
|
218
|
+
## don't support this yet for parsing.
|
219
|
+
raise "Options end too soon" if msg.size == 1
|
220
|
+
len = msg[1,1].ord
|
221
|
+
raise "Options end too abruptly (expected #{len} more bytes, but found only #{msg.size - 2})" if msg.size < len + 2
|
222
|
+
val = msg[2,len]
|
223
|
+
msg[0,len+2] = ''
|
224
|
+
o = get_option(opt)
|
225
|
+
if o.nil?
|
226
|
+
o = DHCP::make_opt(opt)
|
227
|
+
if o.nil?
|
228
|
+
puts "WARNING: Ignoring unsupported option #{opt} (#{len} bytes)"
|
229
|
+
else
|
230
|
+
o.data = val unless len == 0
|
231
|
+
@optlist << o
|
232
|
+
end
|
233
|
+
else
|
234
|
+
## See above TODO note...
|
235
|
+
puts "WARNING: Duplicate option #{opt} (#{o.name}) of #{len} bytes skipped/ignored"
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def to_packet
|
242
|
+
packet =
|
243
|
+
@op.chr + @htype.chr + @hlen.chr + @hops.chr +
|
244
|
+
[@xid, @secs, @flags].pack('Nnn') +
|
245
|
+
@ciaddr + @yiaddr + @siaddr + @giaddr +
|
246
|
+
@chaddr + (0.chr * (16-@chaddr.size)) +
|
247
|
+
@sname + (0.chr * (64-@sname.size)) +
|
248
|
+
@file + (0.chr * (128-@file.size)) +
|
249
|
+
MAGIC +
|
250
|
+
@optlist.map{|x| x.to_opt}.join
|
251
|
+
packet + (packet.size < 300 ? 0.chr * (300 - packet.size) : '') ## Pad to minimum of 300 bytes - Minimum BOOTP/DHCP packet size (RFC 951) - Some devices will drop packets smaller than this.
|
252
|
+
end
|
253
|
+
|
254
|
+
def to_s
|
255
|
+
str = "op=#{@op} "
|
256
|
+
case @op
|
257
|
+
when BOOTREQUEST
|
258
|
+
str += '(BOOTREQUEST)'
|
259
|
+
when BOOTREPLY
|
260
|
+
str += '(BOOTREPLY)'
|
261
|
+
else
|
262
|
+
str += '(UNKNOWN)'
|
263
|
+
end
|
264
|
+
str += "\n"
|
265
|
+
|
266
|
+
str += "htype=#{@htype} "
|
267
|
+
found = false
|
268
|
+
HTYPE.each do |name, htype|
|
269
|
+
if htype[0] == @htype
|
270
|
+
found = true
|
271
|
+
str += name.to_s.upcase + "\n" + 'hlen=' + htype[1].to_s + "\n"
|
272
|
+
str += "*** INVALID HLEN #{@hlen} != #{htype[1]} ***\n" if @hlen != htype[1]
|
273
|
+
break
|
274
|
+
end
|
275
|
+
end
|
276
|
+
str += "UNKNOWN\nhlen=" + @hlen.to_s + "\n" unless found
|
277
|
+
str += "hops=#{@hops}\n"
|
278
|
+
str += "xid=#{@xid} (0x" + [@xid].pack('N').each_byte.map{|b| ('0'+b.to_s(16).upcase)[-2,2]}.join + ")\n"
|
279
|
+
str += "secs=#{@secs}\n"
|
280
|
+
str += "flags=#{@flags} (" + (broadcast? ? 'BROADCAST' : 'NON-BROADCAST') + ")\n"
|
281
|
+
str += 'ciaddr=' + ciaddr + "\n"
|
282
|
+
str += 'yiaddr=' + yiaddr + "\n"
|
283
|
+
str += 'siaddr=' + siaddr + "\n"
|
284
|
+
str += 'giaddr=' + giaddr + "\n"
|
285
|
+
str += 'chaddr=' + chaddr + "\n"
|
286
|
+
str += "sname='#{@sname.sub(/\x00.*$/,'')}' (#{@sname.sub(/\x00.*$/,'').size})\n"
|
287
|
+
str += "file='#{@file.sub(/\x00.*$/,'')}' (#{@file.sub(/\x00.*$/,'').size})\n"
|
288
|
+
str += 'MAGIC: (0x' + MAGIC.each_byte.map{|b| ('0'+b.to_s(16).upcase)[-2,2]}.join + ")\n"
|
289
|
+
str += "OPTIONS(#{@optlist.size}) = [\n "
|
290
|
+
str += @optlist.map{|x| x.to_s}.join(",\n ") + "\n]\n"
|
291
|
+
str += "DHCP_PACKET_TYPE='#{@type_name}' (#{@type}) " unless @type.nil?
|
292
|
+
str
|
293
|
+
end
|
294
|
+
|
295
|
+
def htype=(htype)
|
296
|
+
@htype_name = _find_htype(htype)
|
297
|
+
raise "Invalid/unsupported hardware type #{htype}" if @htype_name.nil?
|
298
|
+
@hlen = HTYPE[@htype_name][1]
|
299
|
+
@htype = HTYPE[@htype_name][0]
|
300
|
+
end
|
301
|
+
|
302
|
+
## Broadcast flag:
|
303
|
+
def broadcast?
|
304
|
+
@flags & 0x8000 != 0
|
305
|
+
end
|
306
|
+
def broadcast!
|
307
|
+
@flags |= 0x8000
|
308
|
+
end
|
309
|
+
|
310
|
+
## Hardware address (ethernet MAC style):
|
311
|
+
def chaddr
|
312
|
+
@chaddr[0,@hlen].each_byte.map{|b| ('0'+b.to_s(16).upcase)[-2,2]}.join(':')
|
313
|
+
end
|
314
|
+
def raw_chaddr
|
315
|
+
@chaddr
|
316
|
+
end
|
317
|
+
def chaddr=(addr)
|
318
|
+
raise "Invalid hardware address" if addr.size - @hlen + 1 != @hlen * 2 || !/^(?:[a-fA-F0-9]{2}[ \.:_\-])*[a-fA-F0-9]{2}$/.match(addr)
|
319
|
+
@chaddr = addr.split(/[ .:_-]/).map{|b| b.to_i(16).chr}.join
|
320
|
+
end
|
321
|
+
|
322
|
+
## IP accessors:
|
323
|
+
def ciaddr
|
324
|
+
IPAddress::IPv4::parse_data(@ciaddr).to_s
|
325
|
+
end
|
326
|
+
def ciaddr=(ip)
|
327
|
+
@ciaddr = IPAddress::IPv4.new(ip).data
|
328
|
+
end
|
329
|
+
|
330
|
+
def yiaddr
|
331
|
+
IPAddress::IPv4::parse_data(@yiaddr).to_s
|
332
|
+
end
|
333
|
+
def yiaddr=(ip)
|
334
|
+
@yiaddr = IPAddress::IPv4.new(ip).data
|
335
|
+
end
|
336
|
+
|
337
|
+
def siaddr
|
338
|
+
IPAddress::IPv4::parse_data(@siaddr).to_s
|
339
|
+
end
|
340
|
+
def siaddr=(ip)
|
341
|
+
@siaddr = IPAddress::IPv4.new(ip).data
|
342
|
+
end
|
343
|
+
|
344
|
+
def giaddr
|
345
|
+
IPAddress::IPv4::parse_data(@giaddr).to_s
|
346
|
+
end
|
347
|
+
def giaddr=(ip)
|
348
|
+
@giaddr = IPAddress::IPv4.new(ip).data
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
end
|
353
|
+
|
data/lib/dhcp/server.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: ASCII-8BIT
|
3
|
+
|
4
|
+
require_relative 'packet'
|
5
|
+
|
6
|
+
module DHCP # :nodoc:
|
7
|
+
class Server
|
8
|
+
def initialize(opt={})
|
9
|
+
@socket = nil ## UDP server socket
|
10
|
+
@interval = opt[:interval] || 0.5 ## Sleep interval
|
11
|
+
end
|
12
|
+
attr_reader :socket
|
13
|
+
|
14
|
+
## Main server event loop (non-blocking):
|
15
|
+
def run_once
|
16
|
+
end
|
17
|
+
|
18
|
+
## Main server event loop (blocking):
|
19
|
+
def run
|
20
|
+
loop do
|
21
|
+
resut = run_once
|
22
|
+
sleep @interval if !result ## Sleep if no data was received and no errors occured
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
## Hand off raw UDP packet data here for parsing and dispatch:
|
27
|
+
def dispatch_packet(data, source_ip, source_port)
|
28
|
+
now = Time.now
|
29
|
+
Syslog.info("Packet (#{data.size} bytes) from [#{source_ip}]:#{source_port} received at #{now}")
|
30
|
+
if data.size < 300
|
31
|
+
Syslog.info("Ignoring small packet (less than BOOTP minimum size.")
|
32
|
+
return
|
33
|
+
end
|
34
|
+
|
35
|
+
packet = nil
|
36
|
+
begin
|
37
|
+
packet = DHCP::Packet.new(data)
|
38
|
+
rescue => e
|
39
|
+
show_packet(packet)
|
40
|
+
Syslog.err("Error parsing DHCP packet.")
|
41
|
+
return
|
42
|
+
end
|
43
|
+
|
44
|
+
relay = nil
|
45
|
+
if source_port == 67 ## DHCP relay via an intermediary
|
46
|
+
relay = true
|
47
|
+
|
48
|
+
## Quick relay sanity-check on GIADDR:
|
49
|
+
if packet.giaddr == IPAddress.new('0.0.0.0')
|
50
|
+
Syslog.err("Packet from relay (port 67) has no GIADDR address set. Ignoring.")
|
51
|
+
return
|
52
|
+
end
|
53
|
+
|
54
|
+
unless relay_authorized?(source_ip, packet.giaddr)
|
55
|
+
Syslog.err("Ignoring DHCP packet from unauthorized relay [#{source_ip}].")
|
56
|
+
return
|
57
|
+
end
|
58
|
+
elsif source_port == 68 ## DHCP on directly attached subnet
|
59
|
+
relay = false
|
60
|
+
|
61
|
+
## Quick relay sanity-check on GIADDR:
|
62
|
+
if packet.giaddr != IPAddress.new('0.0.0.0')
|
63
|
+
Syslog.err("Direct (non-relay) packet has set GIADDR to [#{packet.giaddr}] in violation of RFC. Ignoring.")
|
64
|
+
return
|
65
|
+
end
|
66
|
+
else
|
67
|
+
Syslog.err("Ignoring packet from UDP port other than 67 (relay) or 68 (direct)")
|
68
|
+
return
|
69
|
+
end
|
70
|
+
|
71
|
+
## Ethernet hardware type sanity check:
|
72
|
+
if packet.htype != DHCP::HTYPE[:htype_10mb_ethernet][0] || packet.hlen != DHCP::HTYPE[:htype_10mb_ethernet][1]
|
73
|
+
Syslog.err("Request hardware type or length doesn't match ETHERNET type and length. Ignoring.")
|
74
|
+
return
|
75
|
+
end
|
76
|
+
|
77
|
+
if packet.op != DHCP::BOOTREQUEST
|
78
|
+
Syslog.err("Recived a non-BOOTREQUEST packet. Ignoring.")
|
79
|
+
return
|
80
|
+
end
|
81
|
+
|
82
|
+
## Dispatch packet:
|
83
|
+
case packet.type
|
84
|
+
when DHCP::DHCPDISCOVER
|
85
|
+
handle_discover(packet, source_ip, relay)
|
86
|
+
when DHCP::DHCPREQUEST
|
87
|
+
handle_request(packet, source_ip, relay)
|
88
|
+
when DHCP::DHCPINFORM
|
89
|
+
handle_inform(packet, source_ip, relay)
|
90
|
+
when DHCP::DHCPRELEASE
|
91
|
+
handle_release(packet, source_ip, relay)
|
92
|
+
when DHCP::DHCPDECLINE
|
93
|
+
handle_decline(packet, source_ip, relay)
|
94
|
+
when DHCP::DHCPLEASEQUERY
|
95
|
+
handle_leasequery(packet, source_ip, relay)
|
96
|
+
when DHCP::DHCPOFFER, DHCP::DHCPACK, DHCP::DHCPNAK, DHCP::DHCPFORCERENEW, DHCP::DHCPLEASEUNASSIGNED, DHCP::DHCPLEASEACTIVE, DHCP::DHCPLEASEUNKNOWN
|
97
|
+
show_packet(packet)
|
98
|
+
Syslog.err("Packet type #{packet.type_name} in a BOOTREQUEST is invalid.")
|
99
|
+
else
|
100
|
+
show_packet(packet)
|
101
|
+
Syslog.err("Invalid, unknown, or unhandled DHCP packet type received.")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def relay_authorized?(source_ip, giaddr)
|
106
|
+
true
|
107
|
+
end
|
108
|
+
|
109
|
+
## Handle DHCPDISCOVER packet:
|
110
|
+
def handle_discover(packet, source_ip, relay)
|
111
|
+
show_packet(packet)
|
112
|
+
Syslog.info("handle_discover")
|
113
|
+
end
|
114
|
+
|
115
|
+
## Handle DHCPREQUEST packet:
|
116
|
+
def handle_request(packet, source_ip, relay)
|
117
|
+
show_packet(packet)
|
118
|
+
Syslog.info("handle_request")
|
119
|
+
end
|
120
|
+
|
121
|
+
## Handle DHCPINFORM packet:
|
122
|
+
def handle_inform(packet, source_ip, relay)
|
123
|
+
show_packet(packet)
|
124
|
+
Syslog.info("handle_inform")
|
125
|
+
end
|
126
|
+
|
127
|
+
## Handle DHCPDECLINE packet:
|
128
|
+
def handle_decline(packet, source_ip, relay)
|
129
|
+
show_packet(packet)
|
130
|
+
Syslog.info("handle_decline")
|
131
|
+
end
|
132
|
+
|
133
|
+
## Handle DHCPLEASEQUERY packet:
|
134
|
+
def handle_leasequery(packet, source_ip, relay)
|
135
|
+
show_packet(packet)
|
136
|
+
Syslog.info("handle_leasequery")
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
data/lib/dhcp/version.rb
CHANGED
data/lib/dhcp.rb
CHANGED
metadata
CHANGED
@@ -1,69 +1,69 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: dhcp
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
segments:
|
6
|
-
- 0
|
7
|
-
- 0
|
8
|
-
- 1
|
9
|
-
version: 0.0.1
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
10
5
|
platform: ruby
|
11
|
-
authors:
|
6
|
+
authors:
|
12
7
|
- Aaron D. Gifford
|
13
8
|
autorequire:
|
14
9
|
bindir: bin
|
15
10
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
11
|
+
date: 2014-12-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ipaddress
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: A pure-ruby library for parsing and creating IPv4 DHCP packets (requests
|
28
|
+
or responses)
|
22
29
|
email:
|
23
30
|
executables: []
|
24
|
-
|
25
31
|
extensions: []
|
26
|
-
|
27
32
|
extra_rdoc_files: []
|
28
|
-
|
29
|
-
|
30
|
-
-
|
33
|
+
files:
|
34
|
+
- LICENSE.txt
|
35
|
+
- README.rdoc
|
31
36
|
- Rakefile
|
32
|
-
-
|
37
|
+
- dhcp.rb.bak
|
33
38
|
- lib/dhcp.rb
|
34
|
-
- lib/dhcp/
|
39
|
+
- lib/dhcp/client.rb
|
35
40
|
- lib/dhcp/dhcp.rb
|
36
|
-
|
41
|
+
- lib/dhcp/options.rb
|
42
|
+
- lib/dhcp/packet.rb
|
43
|
+
- lib/dhcp/server.rb
|
44
|
+
- lib/dhcp/version.rb
|
37
45
|
homepage: http://www.aarongifford.com/computers/dhcp/
|
38
|
-
licenses:
|
39
|
-
|
46
|
+
licenses:
|
47
|
+
- MIT
|
48
|
+
metadata: {}
|
40
49
|
post_install_message:
|
41
50
|
rdoc_options: []
|
42
|
-
|
43
|
-
require_paths:
|
51
|
+
require_paths:
|
44
52
|
- lib
|
45
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
requirements:
|
56
|
-
- - ">="
|
57
|
-
- !ruby/object:Gem::Version
|
58
|
-
segments:
|
59
|
-
- 0
|
60
|
-
version: "0"
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
61
63
|
requirements: []
|
62
|
-
|
63
64
|
rubyforge_project: dhcp
|
64
|
-
rubygems_version:
|
65
|
+
rubygems_version: 2.4.5
|
65
66
|
signing_key:
|
66
|
-
specification_version:
|
67
|
-
summary: dhcp-0.0.
|
67
|
+
specification_version: 4
|
68
|
+
summary: dhcp-0.0.3
|
68
69
|
test_files: []
|
69
|
-
|