PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/nselib/rpcap.lua

https://github.com/prakashgamit/nmap
Lua | 441 lines | 291 code | 79 blank | 71 comment | 18 complexity | c5c2305d6d2488690abc678390bf3b68 MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0, LGPL-2.0, LGPL-2.1
  1. ---
  2. -- This library implements the fundamentals needed to communicate with the
  3. -- WinPcap Remote Capture Deamon. It currently supports authenticating to
  4. -- the service using either NULL-, or Password-based authentication.
  5. -- In addition it has the capabilities to list the interfaces that may be
  6. -- used for sniffing.
  7. --
  8. -- The library consist of classes handling <code>Request</code> and classes
  9. -- handling <code>Response</code>. The communication with the service is
  10. -- handled by the <code>Comm</code> class, and the main interface for script
  11. -- writers is kept under the <code>Helper</code> class.
  12. --
  13. -- The following code snipplet illustrates how to connect to the service and
  14. -- extract information about network interfaces:
  15. -- <code>
  16. -- local helper = rpcap.Helper:new(host, port)
  17. -- helper:connect()
  18. -- helper:login()
  19. -- helper:findAllInterfaces()
  20. -- helper:close()
  21. -- </code>
  22. --
  23. -- For a more complete example, consult the rpcap-info.nse script.
  24. --
  25. -- @author "Patrik Karlsson <patrik@cqure.net>"
  26. local bin = require "bin"
  27. local ipOps = require "ipOps"
  28. local match = require "match"
  29. local nmap = require "nmap"
  30. local stdnse = require "stdnse"
  31. local table = require "table"
  32. _ENV = stdnse.module("rpcap", stdnse.seeall)
  33. RPCAP = {
  34. MessageType = {
  35. ERROR = 1,
  36. FIND_ALL_INTERFACES = 2,
  37. AUTH_REQUEST = 8,
  38. },
  39. -- Holds the two supported authentication mechanisms PWD and NULL
  40. Authentication = {
  41. PWD = {
  42. new = function(self, username, password)
  43. local o = {
  44. type = 1,
  45. username = username,
  46. password = password,
  47. }
  48. setmetatable(o, self)
  49. self.__index = self
  50. return o
  51. end,
  52. __tostring = function(self)
  53. local DUMMY = 0
  54. return bin.pack(">SSSSAA", self.type, DUMMY, #self.username, #self.password, self.username, self.password)
  55. end,
  56. },
  57. NULL = {
  58. new = function(self)
  59. local o = {
  60. type = 0,
  61. }
  62. setmetatable(o, self)
  63. self.__index = self
  64. return o
  65. end,
  66. __tostring = function(self)
  67. local DUMMY = 0
  68. return bin.pack(">SSSS", self.type, DUMMY, 0, 0)
  69. end,
  70. }
  71. },
  72. -- The common request and response header
  73. Header = {
  74. size = 8,
  75. new = function(self, type, value, length)
  76. local o = {
  77. version = 0,
  78. type = type,
  79. value= value or 0,
  80. length = length or 0
  81. }
  82. setmetatable(o, self)
  83. self.__index = self
  84. return o
  85. end,
  86. parse = function(data)
  87. local header = RPCAP.Header:new()
  88. local pos
  89. pos, header.version, header.type, header.value, header.length = bin.unpack(">CCSI", data)
  90. return header
  91. end,
  92. __tostring = function(self)
  93. return bin.pack(">CCSI", self.version, self.type, self.value, self.length)
  94. end,
  95. },
  96. -- The implemented request types are kept here
  97. Request = {
  98. Authentication = {
  99. new = function(self, data)
  100. local o = {
  101. header = RPCAP.Header:new(RPCAP.MessageType.AUTH_REQUEST, nil, #data),
  102. data = data,
  103. }
  104. setmetatable(o, self)
  105. self.__index = self
  106. return o
  107. end,
  108. __tostring = function(self)
  109. return tostring(self.header) .. tostring(self.data)
  110. end,
  111. },
  112. FindAllInterfaces = {
  113. new = function(self)
  114. local o = {
  115. header = RPCAP.Header:new(RPCAP.MessageType.FIND_ALL_INTERFACES)
  116. }
  117. setmetatable(o, self)
  118. self.__index = self
  119. return o
  120. end,
  121. __tostring = function(self)
  122. return tostring(self.header)
  123. end,
  124. }
  125. },
  126. -- Parsers for responses are kept here
  127. Response = {
  128. Authentication = {
  129. new = function(self)
  130. local o = { }
  131. setmetatable(o, self)
  132. self.__index = self
  133. return o
  134. end,
  135. parse = function(data)
  136. local resp = RPCAP.Response.Authentication:new()
  137. local pos = RPCAP.Header.size + 1
  138. resp.header = RPCAP.Header.parse(data)
  139. return resp
  140. end
  141. },
  142. Error = {
  143. new = function(self)
  144. local o = { }
  145. setmetatable(o, self)
  146. self.__index = self
  147. return o
  148. end,
  149. parse = function(data)
  150. local err = RPCAP.Response.Error:new()
  151. local pos = RPCAP.Header.size + 1
  152. err.header = RPCAP.Header.parse(data)
  153. pos, err.error = bin.unpack("A" .. err.header.length, data, pos)
  154. return err
  155. end
  156. },
  157. FindAllInterfaces = {
  158. new = function(self)
  159. local o = { }
  160. setmetatable(o, self)
  161. self.__index = self
  162. return o
  163. end,
  164. parse = function(data)
  165. -- Each address is made up of 4 128 byte fields, this function
  166. -- parses these fields and return the response, if it
  167. -- understands it. Otherwise it simply increases the pos by the
  168. -- correct offset, to get us to the next field.
  169. local function parseField(data, pos)
  170. local offset = pos
  171. local family, port
  172. pos, family, port = bin.unpack(">SS", data, pos)
  173. if ( family == 0x0017 ) then
  174. -- not sure why...
  175. pos = pos + 4
  176. local ipv6
  177. pos, ipv6 = bin.unpack("B16", data, pos)
  178. return offset + 128, ipOps.bin_to_ip(ipv6)
  179. elseif ( family == 0x0002 ) then
  180. local ipv4
  181. pos, ipv4 = bin.unpack("B4", data, pos)
  182. return offset + 128, ipOps.bin_to_ip(ipv4)
  183. end
  184. return offset + 128, nil
  185. end
  186. -- Parses one of X addresses returned for an interface
  187. local function parseAddress(data, pos)
  188. local fields = {"ip", "netmask", "bcast", "p2p"}
  189. local addr = {}
  190. for _, f in ipairs(fields) do
  191. pos, addr[f] = parseField(data, pos)
  192. end
  193. return pos, addr
  194. end
  195. local resp = RPCAP.Response.FindAllInterfaces:new()
  196. local pos = RPCAP.Header.size + 1
  197. resp.header = RPCAP.Header.parse(data)
  198. resp.ifaces = {}
  199. for i=1, resp.header.value do
  200. local name_len, desc_len, iface_flags, addr_count, dummy
  201. pos, name_len, desc_len, iface_flags, addr_count, dummy = bin.unpack(">SSISS", data, pos)
  202. local name, desc
  203. pos, name, desc = bin.unpack("A" .. name_len .. "A" .. desc_len, data, pos)
  204. local addrs = {}
  205. for j=1, addr_count do
  206. local addr
  207. pos, addr = parseAddress(data, pos)
  208. local cidr
  209. if ( addr.netmask ) then
  210. local bits = ipOps.ip_to_bin(addr.netmask)
  211. local ones = bits:match("^(1*)")
  212. cidr = #ones
  213. table.insert(addrs, ("%s/%d"):format(addr.ip,cidr))
  214. else
  215. table.insert(addrs, addr.ip)
  216. end
  217. end
  218. table.insert(resp.ifaces, { name = name, desc = desc, addrs = addrs })
  219. end
  220. return resp
  221. end,
  222. }
  223. }
  224. }
  225. -- Maps packet types to classes
  226. RPCAP.TypeToClass = {
  227. [1] = RPCAP.Response.Error,
  228. [130] = RPCAP.Response.FindAllInterfaces,
  229. [136] = RPCAP.Response.Authentication,
  230. }
  231. -- The communication class
  232. Comm = {
  233. -- Creates a new instance of the Comm class
  234. -- @param host table
  235. -- @param port table
  236. -- @return o instance of Comm
  237. new = function(self, host, port)
  238. local o = { host = host, port = port, socket = nmap.new_socket() }
  239. setmetatable(o, self)
  240. self.__index = self
  241. return o
  242. end,
  243. -- Connects the socket to the server
  244. connect = function(self)
  245. return self.socket:connect(self.host, self.port)
  246. end,
  247. -- Sends an instance of the request class to the server
  248. -- @param req class instance
  249. -- @return status true on success, false on failure
  250. -- @return err string containing error message if status is false
  251. send = function(self, req)
  252. return self.socket:send(req)
  253. end,
  254. -- receives a packet and attempts to parse it if it has a supported parser
  255. -- in RPCAP.TypeToClass
  256. -- @return status true on success, false on failure
  257. -- @return resp instance of a Response class or
  258. -- err string containing the error message
  259. recv = function(self)
  260. local status, hdr_data = self.socket:receive_buf(match.numbytes(RPCAP.Header.size), true)
  261. if ( not(status) ) then
  262. return status, hdr_data
  263. end
  264. local header = RPCAP.Header.parse(hdr_data)
  265. if ( not(header) ) then
  266. return false, "rpcap: Failed to parse header"
  267. end
  268. local status, data = self.socket:receive_buf(match.numbytes(header.length), true)
  269. if ( not(status) ) then
  270. return false, "rpcap: Failed to read packet data"
  271. end
  272. if ( RPCAP.TypeToClass[header.type] ) then
  273. local resp = RPCAP.TypeToClass[header.type].parse(hdr_data .. data)
  274. if ( resp ) then
  275. return true, resp
  276. end
  277. end
  278. return false, "Failed to receive response from server"
  279. end,
  280. -- Sends and request and receives the response
  281. -- @param req the instance of the Request class to send
  282. -- @return status true on success, false on failure
  283. -- @return resp instance of a Response class or
  284. -- err string containing the error message
  285. exch = function(self, req)
  286. local status, data = self:send(tostring(req))
  287. if ( not(status) ) then
  288. return status, data
  289. end
  290. return self:recv()
  291. end,
  292. -- closes the socket
  293. close = function(self)
  294. return self.socket:close()
  295. end,
  296. }
  297. Helper = {
  298. -- Creates a new instance of the Helper class
  299. -- @param host table
  300. -- @param port table
  301. -- @return o instance of Helper
  302. new = function(self, host, port)
  303. local o = {
  304. host = host,
  305. port = port,
  306. comm = Comm:new(host, port)
  307. }
  308. setmetatable(o, self)
  309. self.__index = self
  310. return o
  311. end,
  312. -- Connects to the server
  313. connect = function(self)
  314. return self.comm:connect(self.host, self.port)
  315. end,
  316. -- Authenticates to the service, in case no username or password is given
  317. -- NULL authentication is assumed.
  318. -- @param username [optional]
  319. -- @param password [optional]
  320. -- @return status true on success, false on failure
  321. -- @return err string containing error mesage on failure
  322. login = function(self, username, password)
  323. local auth
  324. if ( username and password ) then
  325. auth = RPCAP.Authentication.PWD:new(username, password)
  326. else
  327. auth = RPCAP.Authentication.NULL:new()
  328. end
  329. local req = RPCAP.Request.Authentication:new(tostring(auth))
  330. local status, resp = self.comm:exch(req)
  331. if ( not(status) ) then
  332. return false, resp
  333. end
  334. if ( status and resp.error ) then
  335. return false, resp.error
  336. end
  337. return true
  338. end,
  339. -- Requests a list of all interfaces
  340. -- @return table containing interfaces and addresses
  341. findAllInterfaces = function(self)
  342. local req = RPCAP.Request.FindAllInterfaces:new()
  343. local status, resp = self.comm:exch(req)
  344. if ( not(status) ) then
  345. return false, resp
  346. end
  347. local results = {}
  348. for _, iface in ipairs(resp.ifaces) do
  349. local entry = {}
  350. entry.name = iface.name
  351. table.insert(entry, iface.desc)
  352. table.insert(entry, { name = "Addresses", iface.addrs })
  353. table.insert(results, entry)
  354. end
  355. return true, results
  356. end,
  357. -- Closes the connection to the server
  358. close = function(self)
  359. return self.comm:close()
  360. end,
  361. }
  362. return _ENV;