dhcp 0.0.1 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
|