librex 0.0.42 → 0.0.43
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.
- data/README.markdown +1 -1
- data/lib/rex/compat.rb +10 -0
- data/lib/rex/post/meterpreter/channels/pools/file.rb +1 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb +20 -18
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +11 -22
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/file_stat.rb +2 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun.rb.ts.rb +4 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb +27 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb.ut.rb +7 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_advapi32.rb +498 -242
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_iphlpapi.rb +18 -18
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_kernel32.rb +695 -694
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_netapi32.rb +6 -5
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_ntdll.rb +24 -24
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_shell32.rb +5 -4
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_user32.rb +551 -551
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_ws2_32.rb +93 -93
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll.rb +56 -42
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll.rb.ut.rb +4 -4
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_helper.rb.ut.rb +5 -5
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_wrapper.rb +26 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_wrapper.rb.ut.rb +63 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/multicall.rb +4 -4
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb +151 -96
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb.ut.rb +80 -5
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb +3 -3
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb +11 -11
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb +3 -3
- data/lib/rex/post/meterpreter/packet.rb +12 -11
- data/lib/rex/proto/dhcp/server.rb +36 -42
- data/lib/rex/socket/range_walker.rb +1 -1
- data/lib/rex/text.rb +18 -1
- data/lib/rex/ui/text/table.rb +1 -1
- metadata +5 -3
@@ -15,8 +15,48 @@ module Stdapi
|
|
15
15
|
module Railgun
|
16
16
|
class Railgun::UnitTest < Test::Unit::TestCase
|
17
17
|
|
18
|
+
# DLLs we know should be available at the time of this writing,
|
19
|
+
# and DLLs that because of changes since then should be available
|
20
|
+
STOCK_DLLS =
|
21
|
+
['kernel32', 'ntdll', 'user32', 'ws2_32',
|
22
|
+
'iphlpapi', 'netapi32', 'advapi32', 'shell32'] | Railgun::BUILTIN_DLLS
|
23
|
+
|
18
24
|
include MockMagic
|
19
25
|
|
26
|
+
def test_known_dll_names
|
27
|
+
railgun = Railgun.new(make_mock_client())
|
28
|
+
|
29
|
+
dll_names = railgun.known_dll_names
|
30
|
+
|
31
|
+
assert_equal(dll_names.length, dll_names.uniq.length,
|
32
|
+
"known_dll_names should not have duplicates")
|
33
|
+
|
34
|
+
STOCK_DLLS.each do |name|
|
35
|
+
assert(dll_names.include?(name),
|
36
|
+
"known_dll_names should include #{name}")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
#
|
40
|
+
# TODO:
|
41
|
+
# def test_multi
|
42
|
+
# mock_function_descriptions.each do |func|
|
43
|
+
# railgun = Railgun.new(make_mock_client(func[:platform]))
|
44
|
+
#
|
45
|
+
# functions = [
|
46
|
+
# [func[:dll_name], func[:name], func[:ruby_args]]
|
47
|
+
# ]
|
48
|
+
#
|
49
|
+
# results = railgun.multi(functions)
|
50
|
+
# end
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
def test_const
|
54
|
+
railgun = Railgun.new(make_mock_client())
|
55
|
+
|
56
|
+
assert_equal(0, railgun.const('SUCCESS'),
|
57
|
+
"const should look up constants like SUCCESS")
|
58
|
+
end
|
59
|
+
|
20
60
|
def test_add_dll
|
21
61
|
railgun = Railgun.new(make_mock_client())
|
22
62
|
|
@@ -33,11 +73,46 @@ class Railgun::UnitTest < Test::Unit::TestCase
|
|
33
73
|
assert_equal(actual_dll.dll_path, target_windows_name,
|
34
74
|
"add_dll should set a dll path when specified")
|
35
75
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
76
|
+
wrapper = railgun.send(target_dll_name.to_sym)
|
77
|
+
|
78
|
+
assert_same(wrapper._dll, actual_dll,
|
79
|
+
"railgun instance responds with dll wrapper of requested dll")
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_method_missing
|
83
|
+
railgun = Railgun.new(make_mock_client())
|
84
|
+
|
85
|
+
STOCK_DLLS.each do |dll_name|
|
86
|
+
assert_nothing_raised do
|
87
|
+
railgun.send(dll_name.to_sym)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_get_dll
|
93
|
+
railgun = Railgun.new(make_mock_client())
|
94
|
+
|
95
|
+
STOCK_DLLS.each do |dll_name|
|
96
|
+
dll = railgun.get_dll(dll_name)
|
97
|
+
|
98
|
+
# We want to ensure autoloading is working
|
99
|
+
assert(dll.instance_of?(DLL),
|
100
|
+
"get_dll should be able to return a value for dll #{dll_name}")
|
101
|
+
|
102
|
+
assert(dll.frozen?,
|
103
|
+
"Stock DLLs loaded lazily in get_dll should be frozen")
|
104
|
+
|
105
|
+
# adding a function should create a local unfrozen instance
|
106
|
+
railgun.add_function(dll_name, '__lolz', 'VOID', [])
|
107
|
+
|
108
|
+
unfrozen_dll = railgun.get_dll(dll_name)
|
109
|
+
|
110
|
+
assert_not_same(dll, unfrozen_dll,
|
111
|
+
"add_function should create a local unfrozen instance that get_dll can then access")
|
112
|
+
|
113
|
+
assert(!unfrozen_dll.frozen?,
|
114
|
+
"add_function should create a local unfrozen instance that get_dll can then access")
|
115
|
+
end
|
41
116
|
end
|
42
117
|
|
43
118
|
def test_add_function
|
@@ -30,7 +30,7 @@ class Config
|
|
30
30
|
def getuid
|
31
31
|
request = Packet.create_request('stdapi_sys_config_getuid')
|
32
32
|
response = client.send_request(request)
|
33
|
-
return response.get_tlv_value(TLV_TYPE_USER_NAME)
|
33
|
+
return Rex::Text.unicode_filter_encode( response.get_tlv_value(TLV_TYPE_USER_NAME) )
|
34
34
|
end
|
35
35
|
|
36
36
|
#
|
@@ -62,7 +62,7 @@ class Config
|
|
62
62
|
req = Packet.create_request('stdapi_sys_config_steal_token')
|
63
63
|
req.add_tlv(TLV_TYPE_PID, pid.to_i)
|
64
64
|
res = client.send_request(req)
|
65
|
-
return res.get_tlv_value(TLV_TYPE_USER_NAME)
|
65
|
+
return Rex::Text.unicode_filter_encode( res.get_tlv_value(TLV_TYPE_USER_NAME) )
|
66
66
|
end
|
67
67
|
|
68
68
|
#
|
@@ -71,7 +71,7 @@ class Config
|
|
71
71
|
def drop_token
|
72
72
|
req = Packet.create_request('stdapi_sys_config_drop_token')
|
73
73
|
res = client.send_request(req)
|
74
|
-
return res.get_tlv_value(TLV_TYPE_USER_NAME)
|
74
|
+
return Rex::Text.unicode_filter_encode( res.get_tlv_value(TLV_TYPE_USER_NAME) )
|
75
75
|
end
|
76
76
|
|
77
77
|
#
|
@@ -151,7 +151,7 @@ class Process < Rex::Post::Process
|
|
151
151
|
end
|
152
152
|
end
|
153
153
|
|
154
|
-
request.add_tlv(TLV_TYPE_PROCESS_PATH, path);
|
154
|
+
request.add_tlv(TLV_TYPE_PROCESS_PATH, Rex::Text.unicode_filter_decode( path ));
|
155
155
|
|
156
156
|
# If process arguments were supplied
|
157
157
|
if (arguments != nil)
|
@@ -177,7 +177,7 @@ class Process < Rex::Post::Process
|
|
177
177
|
# Return a process instance
|
178
178
|
return self.new(pid, handle, channel)
|
179
179
|
end
|
180
|
-
|
180
|
+
|
181
181
|
#
|
182
182
|
# Kills one or more processes.
|
183
183
|
#
|
@@ -223,7 +223,7 @@ class Process < Rex::Post::Process
|
|
223
223
|
|
224
224
|
response.each(TLV_TYPE_PROCESS_GROUP) { |p|
|
225
225
|
arch = ""
|
226
|
-
|
226
|
+
|
227
227
|
pa = p.get_tlv_value( TLV_TYPE_PROCESS_ARCH )
|
228
228
|
if( pa != nil )
|
229
229
|
if pa == 1 # PROCESS_ARCH_X86
|
@@ -232,15 +232,15 @@ class Process < Rex::Post::Process
|
|
232
232
|
arch = ARCH_X86_64
|
233
233
|
end
|
234
234
|
end
|
235
|
-
|
235
|
+
|
236
236
|
processes <<
|
237
237
|
{
|
238
238
|
'pid' => p.get_tlv_value(TLV_TYPE_PID),
|
239
239
|
'parentid' => p.get_tlv_value(TLV_TYPE_PARENT_PID),
|
240
|
-
'name' => p.get_tlv_value(TLV_TYPE_PROCESS_NAME),
|
241
|
-
'path' => p.get_tlv_value(TLV_TYPE_PROCESS_PATH),
|
240
|
+
'name' => Rex::Text.unicode_filter_encode( p.get_tlv_value(TLV_TYPE_PROCESS_NAME) ),
|
241
|
+
'path' => Rex::Text.unicode_filter_encode( p.get_tlv_value(TLV_TYPE_PROCESS_PATH) ),
|
242
242
|
'session' => p.get_tlv_value(TLV_TYPE_PROCESS_SESSION),
|
243
|
-
'user' => p.get_tlv_value(TLV_TYPE_USER_NAME),
|
243
|
+
'user' => Rex::Text.unicode_filter_encode( p.get_tlv_value(TLV_TYPE_USER_NAME) ),
|
244
244
|
'arch' => arch
|
245
245
|
}
|
246
246
|
}
|
@@ -291,7 +291,7 @@ class Process < Rex::Post::Process
|
|
291
291
|
def self.finalize(client,handle)
|
292
292
|
proc { self.close(client,handle) }
|
293
293
|
end
|
294
|
-
|
294
|
+
|
295
295
|
#
|
296
296
|
# Returns the executable name of the process.
|
297
297
|
#
|
@@ -316,7 +316,7 @@ class Process < Rex::Post::Process
|
|
316
316
|
handle = nil;
|
317
317
|
return true
|
318
318
|
end
|
319
|
-
|
319
|
+
|
320
320
|
#
|
321
321
|
# Instance method
|
322
322
|
#
|
@@ -358,8 +358,8 @@ protected
|
|
358
358
|
response = client.send_request(request)
|
359
359
|
|
360
360
|
# Populate the hash
|
361
|
-
info['name'] = response.get_tlv_value(TLV_TYPE_PROCESS_NAME)
|
362
|
-
info['path'] = response.get_tlv_value(TLV_TYPE_PROCESS_PATH)
|
361
|
+
info['name'] = Rex::Text.unicode_filter_encode( response.get_tlv_value(TLV_TYPE_PROCESS_NAME) )
|
362
|
+
info['path'] = Rex::Text.unicode_filter_encode( response.get_tlv_value(TLV_TYPE_PROCESS_PATH) )
|
363
363
|
|
364
364
|
return info
|
365
365
|
end
|
@@ -44,8 +44,8 @@ class Registry
|
|
44
44
|
request = Packet.create_request('stdapi_registry_load_key')
|
45
45
|
request.add_tlv(TLV_TYPE_ROOT_KEY, root_key)
|
46
46
|
request.add_tlv(TLV_TYPE_BASE_KEY, base_key)
|
47
|
-
request.add_tlv(TLV_TYPE_FILE_PATH,hive_file)
|
48
|
-
|
47
|
+
request.add_tlv(TLV_TYPE_FILE_PATH, Rex::Text.unicode_filter_decode( hive_file ))
|
48
|
+
|
49
49
|
response = client.send_request(request)
|
50
50
|
return response.get_tlv(TLV_TYPE_RESULT).value
|
51
51
|
end
|
@@ -95,7 +95,7 @@ class Registry
|
|
95
95
|
return Rex::Post::Meterpreter::Extensions::Stdapi::Sys::RegistrySubsystem::RemoteRegistryKey.new(
|
96
96
|
client, target_host, root_key, response.get_tlv(TLV_TYPE_HKEY).value)
|
97
97
|
end
|
98
|
-
|
98
|
+
|
99
99
|
#
|
100
100
|
# Creates the supplied registry key or opens it if it already exists.
|
101
101
|
#
|
@@ -113,7 +113,7 @@ class Tlv
|
|
113
113
|
def initialize(type, value = nil, compress=false)
|
114
114
|
@type = type
|
115
115
|
@compress = compress
|
116
|
-
|
116
|
+
|
117
117
|
if (value != nil)
|
118
118
|
if (type & TLV_META_TYPE_STRING == TLV_META_TYPE_STRING)
|
119
119
|
if (value.kind_of?(Fixnum))
|
@@ -219,7 +219,7 @@ class Tlv
|
|
219
219
|
# Serializers
|
220
220
|
#
|
221
221
|
##
|
222
|
-
|
222
|
+
|
223
223
|
#
|
224
224
|
# Converts the TLV to raw.
|
225
225
|
#
|
@@ -240,14 +240,14 @@ class Tlv
|
|
240
240
|
raw = [0].pack("c")
|
241
241
|
end
|
242
242
|
end
|
243
|
-
|
243
|
+
|
244
244
|
# check if the tlv is to be compressed...
|
245
245
|
if( @compress )
|
246
246
|
raw_uncompressed = raw
|
247
247
|
# compress the raw data
|
248
248
|
raw_compressed = Rex::Text.zlib_deflate( raw_uncompressed )
|
249
249
|
# check we have actually made the raw data smaller...
|
250
|
-
# (small blobs often compress slightly larger then the origional)
|
250
|
+
# (small blobs often compress slightly larger then the origional)
|
251
251
|
# if the compressed data is not smaller, we dont use the compressed data
|
252
252
|
if( raw_compressed.length < raw_uncompressed.length )
|
253
253
|
# if so, set the TLV's type to indicate compression is used
|
@@ -257,7 +257,7 @@ class Tlv
|
|
257
257
|
raw = [ raw_uncompressed.length ].pack("N") + raw_compressed
|
258
258
|
end
|
259
259
|
end
|
260
|
-
|
260
|
+
|
261
261
|
return [raw.length + 8, self.type].pack("NN") + raw
|
262
262
|
end
|
263
263
|
|
@@ -273,7 +273,7 @@ class Tlv
|
|
273
273
|
if( self.type & TLV_META_TYPE_COMPRESSED == TLV_META_TYPE_COMPRESSED )
|
274
274
|
# set this TLV as using compression
|
275
275
|
@compress = true
|
276
|
-
# remove the TLV_META_TYPE_COMPRESSED flag from the tlv type to restore the
|
276
|
+
# remove the TLV_META_TYPE_COMPRESSED flag from the tlv type to restore the
|
277
277
|
# tlv type to its origional, allowing for transparent data compression.
|
278
278
|
self.type = self.type ^ TLV_META_TYPE_COMPRESSED
|
279
279
|
# decompress the compressed data (skipping the length and type DWORD's)
|
@@ -283,7 +283,7 @@ class Tlv
|
|
283
283
|
# update the raw buffer with the new length, decompressed data and updated type.
|
284
284
|
raw = [length, self.type].pack("NN") + raw_decompressed
|
285
285
|
end
|
286
|
-
|
286
|
+
|
287
287
|
if (self.type & TLV_META_TYPE_STRING == TLV_META_TYPE_STRING)
|
288
288
|
if (raw.length > 0)
|
289
289
|
self.value = raw[8..length-2]
|
@@ -293,7 +293,7 @@ class Tlv
|
|
293
293
|
elsif (self.type & TLV_META_TYPE_UINT == TLV_META_TYPE_UINT)
|
294
294
|
self.value = raw.unpack("NNN")[2]
|
295
295
|
elsif (self.type & TLV_META_TYPE_QWORD == TLV_META_TYPE_QWORD)
|
296
|
-
self.value = raw.unpack("NNQ")[2]
|
296
|
+
self.value = raw.unpack("NNQ")[2]
|
297
297
|
self.value = self.ntohq( self.value )
|
298
298
|
elsif (self.type & TLV_META_TYPE_BOOL == TLV_META_TYPE_BOOL)
|
299
299
|
self.value = raw.unpack("NNc")[2]
|
@@ -309,9 +309,9 @@ class Tlv
|
|
309
309
|
|
310
310
|
return length;
|
311
311
|
end
|
312
|
-
|
312
|
+
|
313
313
|
protected
|
314
|
-
|
314
|
+
|
315
315
|
def htonq( value )
|
316
316
|
if( [1].pack( 's' ) == [1].pack( 'n' ) )
|
317
317
|
return value
|
@@ -322,7 +322,7 @@ class Tlv
|
|
322
322
|
def ntohq( value )
|
323
323
|
return htonq( value )
|
324
324
|
end
|
325
|
-
|
325
|
+
|
326
326
|
end
|
327
327
|
|
328
328
|
###
|
@@ -685,5 +685,6 @@ class Packet < GroupTlv
|
|
685
685
|
end
|
686
686
|
end
|
687
687
|
|
688
|
+
|
688
689
|
end; end; end
|
689
690
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: server.rb
|
1
|
+
# $Id: server.rb 13165 2011-07-14 02:34:25Z scriptjunkie $
|
2
2
|
|
3
3
|
require 'rex/socket'
|
4
4
|
require 'rex/proto/dhcp'
|
@@ -27,8 +27,6 @@ class Server
|
|
27
27
|
self.context = context
|
28
28
|
self.sock = nil
|
29
29
|
|
30
|
-
@shutting_down = false
|
31
|
-
|
32
30
|
self.myfilename = hash['FILENAME'] || ""
|
33
31
|
self.myfilename << ("\x00" * (128 - self.myfilename.length))
|
34
32
|
|
@@ -74,17 +72,10 @@ class Server
|
|
74
72
|
end
|
75
73
|
|
76
74
|
self.served = {}
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
end
|
82
|
-
|
83
|
-
if (hash['PXE'])
|
84
|
-
self.servePXE = true
|
85
|
-
else
|
86
|
-
self.servePXE = false
|
87
|
-
end
|
75
|
+
self.serveOnce = hash.include?('SERVEONCE')
|
76
|
+
|
77
|
+
self.servePXE = (hash.include?('PXE') or hash.include?('FILENAME') or hash.include?('PXEONLY'))
|
78
|
+
self.serveOnlyPXE = hash.include?('PXEONLY')
|
88
79
|
|
89
80
|
# Always assume we don't give out hostnames ...
|
90
81
|
self.give_hostname = false
|
@@ -120,8 +111,8 @@ class Server
|
|
120
111
|
|
121
112
|
# Stop the DHCP server
|
122
113
|
def stop
|
123
|
-
@shutting_down = true
|
124
114
|
self.thread.kill
|
115
|
+
self.served = {}
|
125
116
|
self.sock.close rescue nil
|
126
117
|
end
|
127
118
|
|
@@ -131,7 +122,7 @@ class Server
|
|
131
122
|
allowed_options = [
|
132
123
|
:serveOnce, :servePXE, :relayip, :leasetime, :dnsserv,
|
133
124
|
:pxeconfigfile, :pxepathprefix, :pxereboottime, :router,
|
134
|
-
:give_hostname, :served_hostname, :served_over
|
125
|
+
:give_hostname, :served_hostname, :served_over, :serveOnlyPXE
|
135
126
|
]
|
136
127
|
|
137
128
|
opts.each_pair { |k,v|
|
@@ -158,7 +149,7 @@ class Server
|
|
158
149
|
attr_accessor :listen_host, :listen_port, :context, :leasetime, :relayip, :router, :dnsserv
|
159
150
|
attr_accessor :sock, :thread, :myfilename, :ipstring, :served, :serveOnce
|
160
151
|
attr_accessor :current_ip, :start_ip, :end_ip, :broadcasta, :netmaskn
|
161
|
-
attr_accessor :servePXE, :pxeconfigfile, :pxepathprefix, :pxereboottime
|
152
|
+
attr_accessor :servePXE, :pxeconfigfile, :pxepathprefix, :pxereboottime, :serveOnlyPXE
|
162
153
|
attr_accessor :give_hostname, :served_hostname, :served_over
|
163
154
|
|
164
155
|
protected
|
@@ -242,24 +233,26 @@ protected
|
|
242
233
|
end
|
243
234
|
end
|
244
235
|
|
245
|
-
if
|
246
|
-
|
247
|
-
return
|
248
|
-
end
|
236
|
+
# don't serve if only serving PXE and not PXE request
|
237
|
+
return if pxeclient == false and self.serveOnlyPXE == true
|
249
238
|
|
250
239
|
# prepare response
|
251
240
|
pkt = [Response].pack('C')
|
252
241
|
pkt << buf[1..7] #hwtype, hwlen, hops, txid
|
253
242
|
pkt << "\x00\x00\x00\x00" #elapsed, flags
|
254
243
|
pkt << clientip
|
255
|
-
|
256
|
-
|
244
|
+
|
245
|
+
# if this is somebody we've seen before, use the saved IP
|
246
|
+
if self.served.include?( buf[28..43] )
|
247
|
+
pkt << Rex::Socket.addr_iton(self.served[buf[28..43]][0])
|
248
|
+
else # otherwise go to next ip address
|
257
249
|
self.current_ip += 1
|
258
250
|
if self.current_ip > self.end_ip
|
259
251
|
self.current_ip = self.start_ip
|
260
252
|
end
|
253
|
+
self.served.merge!( buf[28..43] => [ self.current_ip, messageType == DHCPRequest ] )
|
254
|
+
pkt << Rex::Socket.addr_iton(self.current_ip)
|
261
255
|
end
|
262
|
-
pkt << Rex::Socket.addr_iton(self.current_ip)
|
263
256
|
pkt << self.ipstring #next server ip
|
264
257
|
pkt << self.relayip
|
265
258
|
pkt << buf[28..43] #client hw address
|
@@ -270,15 +263,17 @@ protected
|
|
270
263
|
|
271
264
|
if messageType == DHCPDiscover #DHCP Discover - send DHCP Offer
|
272
265
|
pkt << [DHCPOffer].pack('C')
|
273
|
-
# check if already served based on hw addr (MAC address)
|
274
|
-
if
|
275
|
-
|
266
|
+
# check if already served an Ack based on hw addr (MAC address)
|
267
|
+
# if serveOnce & PXE, don't reply to another PXE request
|
268
|
+
# if serveOnce & ! PXE, don't reply to anything
|
269
|
+
if self.serveOnce == true and self.served.has_key?(buf[28..43]) and
|
270
|
+
self.served[buf[28..43]][1] and (pxeclient == true or self.servePXE == false)
|
276
271
|
return
|
277
272
|
end
|
278
273
|
elsif messageType == DHCPRequest #DHCP Request - send DHCP ACK
|
274
|
+
self.served[buf[28..43]][1] = true # mark as requested
|
279
275
|
pkt << [DHCPAck].pack('C')
|
280
276
|
# now we ignore their discovers (but we'll respond to requests in case a packet was lost)
|
281
|
-
self.served.merge!( buf[28..43] => true )
|
282
277
|
if ( self.served_over != 0 )
|
283
278
|
# NOTE: this is sufficient for low-traffic net
|
284
279
|
# for high-traffic, this will probably lead to
|
@@ -286,8 +281,7 @@ protected
|
|
286
281
|
self.served_over += 1
|
287
282
|
end
|
288
283
|
else
|
289
|
-
#
|
290
|
-
return
|
284
|
+
return # ignore unknown DHCP request
|
291
285
|
end
|
292
286
|
|
293
287
|
# Options!
|
@@ -296,20 +290,20 @@ protected
|
|
296
290
|
pkt << dhcpoption(OpSubnetMask, self.netmaskn)
|
297
291
|
pkt << dhcpoption(OpRouter, self.router)
|
298
292
|
pkt << dhcpoption(OpDns, self.dnsserv)
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
293
|
+
if self.servePXE # PXE options
|
294
|
+
pkt << dhcpoption(OpPXEMagic, PXEMagic)
|
295
|
+
pkt << dhcpoption(OpPXEConfigFile, self.pxeconfigfile)
|
296
|
+
pkt << dhcpoption(OpPXEPathPrefix, self.pxepathprefix)
|
297
|
+
pkt << dhcpoption(OpPXERebootTime, [self.pxereboottime].pack('N'))
|
298
|
+
if ( self.give_hostname == true )
|
299
|
+
send_hostname = self.served_hostname
|
300
|
+
if ( self.served_over != 0 )
|
301
|
+
# NOTE : see above comments for the 'uniqueness' of this value
|
302
|
+
send_hostname += self.served_over.to_s
|
303
|
+
end
|
304
|
+
pkt << dhcpoption(OpHostname, send_hostname)
|
309
305
|
end
|
310
|
-
pkt << dhcpoption(OpHostname, send_hostname)
|
311
306
|
end
|
312
|
-
|
313
307
|
pkt << dhcpoption(OpEnd)
|
314
308
|
|
315
309
|
pkt << ("\x00" * 32) #padding
|