Skip to content

Commit 6a4d398

Browse files
committed
Merge remote branch 'origin/feature/addp-modules'
2 parents ac6f984 + 80ebcf2 commit 6a4d398

File tree

4 files changed

+533
-0
lines changed

4 files changed

+533
-0
lines changed

lib/rex/proto/addp.rb

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
# -*- coding: binary -*-
2+
module Rex
3+
module Proto
4+
5+
#
6+
# This provides constants, encoding, and decoding routines for Digi International's ADDP protocol
7+
#
8+
class ADDP
9+
10+
require "rex/socket"
11+
12+
#
13+
# See the following URLs for more information:
14+
# - http://qbeukes.blogspot.com/2009/11/advanced-digi-discovery-protocol_21.html
15+
# - http://www.digi.com/wiki/developer/index.php/Advanced_Device_Discovery_Protocol_%28ADDP%29
16+
#
17+
18+
19+
MAGICS = %W{ DIGI DVKT DGDP }
20+
ERRORS = %W{ no_response unknown success authenticaton_failed unit_has_address invalid_value invalid_data unsupported_command }
21+
WLAN_ENC_MODES = %W{ unknown none wep40 wep128 }
22+
WLAN_AUTH_MODES = %W{ unknown open shared_key open_shared_key }
23+
HWTYPES = %W{
24+
unknown ps3_desk8 ps3_desk16 ps3_desk32 ps3_rack16 ps2_desk16 ps2_rack16
25+
lets_desk1 lets_desk2 lets_desk4 dorpia_dinrail1 nubox01 nubox02 nubox04
26+
digione_sp digione_ia digione_em
27+
}
28+
29+
CMD_CONF_REQ = 1
30+
CMD_CONF_REP = 2
31+
CMD_SET_ADDR_REQ = 3
32+
CMD_SET_ADDR_REP = 4
33+
CMD_REBOOT_REQ = 5
34+
CMD_REBOOT_REP = 6
35+
CMD_SET_DHCP_REQ = 7
36+
CMD_SET_DHCP_REP = 8
37+
CMD_SET_WL_REQ = 9
38+
CMD_SET_WL_REP = 10
39+
CMD_SET_WL_COUNTRIES_REQ = 11
40+
CMD_SET_WL_COUNTRIES_REP = 12
41+
CMD_EDP = 13
42+
CMD_CNT = 14
43+
44+
45+
def self.encode_password(pwd="dbps")
46+
[pwd.length].pack("C") + pwd
47+
end
48+
49+
def self.request_config(magic, dmac="\xff\xff\xff\xff\xff\xff")
50+
mac = (dmac.length == 6) ? dmac : Rex::Socket.eth_aton(dmac)
51+
req = magic + [ CMD_CONF_REQ, 6].pack("nn") + mac
52+
return req
53+
end
54+
55+
def self.request_config_all(dmac="\xff\xff\xff\xff\xff\xff")
56+
mac = (dmac.length == 6) ? dmac : Rex::Socket.eth_aton(dmac)
57+
res = []
58+
MAGICS.each { |m| res << self.request_config(m, dmac) }
59+
return res
60+
end
61+
62+
def self.request_static_ip(magic, dmac, ip, mask, gw, pwd="dbps")
63+
mac = (dmac.length == 6) ? dmac : Rex::Socket.eth_aton(dmac)
64+
buf =
65+
Rex::Socket.addr_aton(ip) +
66+
Rex::Socket.addr_aton(mask) +
67+
Rex::Socket.addr_aton(gw) +
68+
mac +
69+
self.encode_password(pwd)
70+
71+
req = magic + [CMD_SET_ADDR_REQ, buf.length].pack("nn") + buf
72+
return req
73+
end
74+
75+
def self.request_dhcp(magic, dmac, enabled, pwd="dbps")
76+
mac = (dmac.length == 6) ? dmac : Rex::Socket.eth_aton(dmac)
77+
buf =
78+
[ enabled ? 1 : 0 ].pack("C") +
79+
mac +
80+
self.encode_password(pwd)
81+
82+
req = magic + [CMD_SET_DHCP_REQ, buf.length].pack("nn") + buf
83+
return req
84+
end
85+
86+
def self.request_reboot(magic, dmac, pwd="dbps")
87+
mac = (dmac.length == 6) ? dmac : Rex::Socket.eth_aton(dmac)
88+
buf =
89+
mac +
90+
self.encode_password(pwd)
91+
92+
req = magic + [CMD_REBOOT_REQ, buf.length].pack("nn") + buf
93+
return req
94+
end
95+
96+
def self.decode_reply(data)
97+
res = {}
98+
r_magic = data[0,4]
99+
r_ptype = data[4,2].unpack("n").first
100+
r_plen = data[6,2].unpack("n").first
101+
buff = data[8, r_plen]
102+
bidx = 0
103+
104+
res[:magic] = data[0,4]
105+
res[:cmd] = r_ptype
106+
107+
while bidx < (buff.length - 2)
108+
i_type, i_len = buff[bidx, 2].unpack("CC")
109+
i_data = buff[bidx + 2, i_len]
110+
111+
break if i_data.length != i_len
112+
113+
case i_type
114+
when 0x01
115+
res[:mac] = Rex::Socket.eth_ntoa(i_data)
116+
when 0x02
117+
res[:ip] = Rex::Socket.addr_ntoa(i_data)
118+
when 0x03
119+
res[:mask] = Rex::Socket.addr_ntoa(i_data)
120+
when 0x04
121+
res[:hostname] = i_data
122+
when 0x05
123+
res[:domain] = i_data
124+
when 0x06
125+
res[:hwtype] = HWTYPES[ i_data.unpack("C").first ] || HWTYPES[ 0 ]
126+
when 0x07
127+
res[:hwrev] = i_data.unpack("C").first
128+
when 0x08
129+
res[:fwrev] = i_data
130+
when 0x09
131+
res[:msg] = i_data
132+
when 0x0a
133+
res[:result] = i_data.unpack("C").first
134+
when 0x0b
135+
res[:gw] = Rex::Socket.addr_ntoa(i_data)
136+
when 0x0c
137+
res[:advisory] = i_data.unpack("n").first
138+
when 0x0d
139+
res[:hwname] = i_data
140+
when 0x0e
141+
res[:realport] = i_data.unpack("N").first
142+
when 0x0f
143+
res[:dns] = Rex::Socket.addr_ntoa(i_data)
144+
when 0x10
145+
res[:dhcp] = (i_data.unpack("C").first == 0) ? false : true
146+
when 0x11
147+
res[:error] = ERRORS[ i_data.unpack("C").first ] || ERRORS[0]
148+
when 0x12
149+
res[:ports] = i_data.unpack("C").first
150+
when 0x13
151+
res[:realport_enc] = (i_data.unpack("C").first == 0) ? false : true
152+
when 0x14
153+
res[:version] = i_data.unpack("n").first
154+
when 0x15
155+
res[:vendor_guid] = i_data.unpack("H*") # GUID
156+
when 0x16
157+
res[:iftype] = i_data.unpack("C").first
158+
when 0x17
159+
res[:challenge] = i_data # Unknown format
160+
when 0x18
161+
res[:cap_port] = i_data.unpack("n").first
162+
when 0x19
163+
res[:edp_devid] = i_data.unpack("H*").first # Unknown format
164+
when 0x1a
165+
res[:edp_enabled] = (i_data.unpack("C").first == 0) ? false : true
166+
when 0x1b
167+
res[:edp_url] = i_data
168+
when 0x1c
169+
res[:wl_ssid] = i_data
170+
when 0x1d
171+
res[:wl_auto_ssid] = (i_data.unpack("n").first == 0) ? false : true
172+
when 0x1e
173+
res[:wl_tx_enh_power] = i_data.unpack("n").first
174+
when 0x1f
175+
res[:wl_auth_mode] = WLAN_AUTH_MODES[ i_data.unpack("n").first ] || WLAN_AUTH_MODES[ 0 ]
176+
when 0x20
177+
res[:wl_enc_mode] = WLAN_ENC_MODES[ i_data.unpack("n").first ] || WLAN_ENC_MODES[ 0 ]
178+
when 0x21
179+
res[:wl_enc_key] = i_data
180+
when 0x22
181+
res[:wl_cur_country] = i_data
182+
when 0x23
183+
res[:wl_country_list] = i_data
184+
else
185+
# Store unknown responses
186+
res["unknown_0x#{"%.2x" % i_type}".to_sym] = i_data
187+
end
188+
189+
bidx = bidx + 2 + i_len
190+
end
191+
return res
192+
end
193+
194+
def self.reply_to_string(res)
195+
str = ""
196+
197+
fields = [
198+
:hwname, :hwtype, :hwrev, :fwrev,
199+
:mac, :ip, :mask, :gw, :hostname, :domain, :dns, :dhcp,
200+
:msg, :result, :error,
201+
:advisory, :ports, :realport, :realport_enc,
202+
:version, :vendor_guid, :iftype, :challenge, :cap_port, :edp_devid, :edp_enabled,
203+
:edp_url, :wl_ssid, :wl_auto_ssid, :wl_tx_enh_power, :wl_auth_mode, :wl_enc_mode,
204+
:wl_enc_key, :wl_cur_country, :wl_country_list, :magic
205+
]
206+
207+
fields.each do |fname|
208+
next unless res.has_key?(fname)
209+
str << "#{fname}:#{res[fname]} "
210+
end
211+
return str
212+
end
213+
214+
end
215+
216+
end
217+
end
218+

lib/rex/socket.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,20 @@ def self.addr_iton(addr, v6=false)
455455
end
456456
end
457457

458+
#
459+
# Converts a colon-delimited MAC address into a 6-byte binary string
460+
#
461+
def self.eth_aton(mac)
462+
mac.split(":").map{|c| c.to_i(16) }.pack("C*")
463+
end
464+
465+
#
466+
# Converts a 6-byte binary string into a colon-delimited MAC address
467+
#
468+
def self.eth_ntoa(bin)
469+
bin.unpack("C6").map{|x| "%.2x" % x }.join(":").upcase
470+
end
471+
458472
#
459473
# Converts a CIDR subnet into an array (base, bcast)
460474
#

0 commit comments

Comments
 (0)