mirror of
https://github.com/nmap/nmap.git
synced 2025-12-22 07:29:01 +00:00
Document the packet NSE module.
This commit is contained in:
@@ -8,16 +8,18 @@ require "bit"
|
|||||||
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------------------
|
||||||
-- extract number from binary string
|
--- Get an 8-bit integer at a 0-based byte offset in a binary string.
|
||||||
function u8(b, i)
|
function u8(b, i)
|
||||||
return string.byte(b, i+1)
|
return string.byte(b, i+1)
|
||||||
end
|
end
|
||||||
|
--- Get a 16-bit integer at a 0-based byte offset in a binary string.
|
||||||
function u16(b, i)
|
function u16(b, i)
|
||||||
local b1,b2
|
local b1,b2
|
||||||
b1, b2 = string.byte(b, i+1), string.byte(b, i+2)
|
b1, b2 = string.byte(b, i+1), string.byte(b, i+2)
|
||||||
-- 2^8 2^0
|
-- 2^8 2^0
|
||||||
return b1*256 + b2
|
return b1*256 + b2
|
||||||
end
|
end
|
||||||
|
--- Get a 32-bit integer at a 0-based byte offset in a binary string.
|
||||||
function u32(b,i)
|
function u32(b,i)
|
||||||
local b1,b2,b3,b4
|
local b1,b2,b3,b4
|
||||||
b1, b2 = string.byte(b, i+1), string.byte(b, i+2)
|
b1, b2 = string.byte(b, i+1), string.byte(b, i+2)
|
||||||
@@ -26,15 +28,20 @@ function u32(b,i)
|
|||||||
return b1*16777216 + b2*65536 + b3*256 + b4
|
return b1*16777216 + b2*65536 + b3*256 + b4
|
||||||
end
|
end
|
||||||
|
|
||||||
-- insert number to binary string
|
--- Set an 8-bit integer at a 0-based byte offset in a binary string
|
||||||
|
-- (big-endian).
|
||||||
function set_u8(b, i, num)
|
function set_u8(b, i, num)
|
||||||
local s = string.char(bit.band(num, 0xff))
|
local s = string.char(bit.band(num, 0xff))
|
||||||
return b:sub(0+1, i+1-1) .. s .. b:sub(i+1+1)
|
return b:sub(0+1, i+1-1) .. s .. b:sub(i+1+1)
|
||||||
end
|
end
|
||||||
|
--- Set a 16-bit integer at a 0-based byte offset in a binary string
|
||||||
|
-- (big-endian).
|
||||||
function set_u16(b, i, num)
|
function set_u16(b, i, num)
|
||||||
local s = string.char(bit.band(bit.rshift(num, 8), 0xff)) .. string.char(bit.band(num, 0xff))
|
local s = string.char(bit.band(bit.rshift(num, 8), 0xff)) .. string.char(bit.band(num, 0xff))
|
||||||
return b:sub(0+1, i+1-1) .. s .. b:sub(i+1+2)
|
return b:sub(0+1, i+1-1) .. s .. b:sub(i+1+2)
|
||||||
end
|
end
|
||||||
|
--- Set a 32-bit integer at a 0-based byte offset in a binary string
|
||||||
|
-- (big-endian).
|
||||||
function set_u32(b,i, num)
|
function set_u32(b,i, num)
|
||||||
local s = string.char(bit.band(bit.rshift(num,24), 0xff)) ..
|
local s = string.char(bit.band(bit.rshift(num,24), 0xff)) ..
|
||||||
string.char(bit.band(bit.rshift(num,16), 0xff)) ..
|
string.char(bit.band(bit.rshift(num,16), 0xff)) ..
|
||||||
@@ -45,7 +52,7 @@ end
|
|||||||
|
|
||||||
|
|
||||||
-- Checksum
|
-- Checksum
|
||||||
---- Standard BSD internet checksum routine check nmap/tcpip.cc
|
--- Calculate a standard Internet checksum.
|
||||||
function in_cksum(b)
|
function in_cksum(b)
|
||||||
local sum = 0
|
local sum = 0
|
||||||
local c
|
local c
|
||||||
@@ -92,14 +99,16 @@ IPPROTO_UDPLITE = 136 -- UDP-Lite (RFC 3828)
|
|||||||
----------------------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------------------
|
||||||
-- Packet is a class
|
-- Packet is a class
|
||||||
Packet = {}
|
Packet = {}
|
||||||
-- Constructor
|
|
||||||
-- packet - binary string with packet data
|
--- Create a new Packet object.
|
||||||
-- packet_len - packet length, it could be more than string.len(packet)
|
-- @param packet binary string with packet data.
|
||||||
-- force_continue - whether error in parsing headers should be fatal or not.
|
-- @param packet_len packet length, it could be more than string.len(packet).
|
||||||
-- especially usefull at parsing icmp packets, where on small icmp payload
|
-- @param force_continue whether error in parsing headers should be
|
||||||
-- could be tcp header. The problem is that parsing this payload normally
|
-- fatal or not. Especially useful at parsing ICMP packets, where a
|
||||||
-- would fail (broken packet, because tcp header is too small)
|
-- small ICMP payload could be a TCP header. The problem is that parsing
|
||||||
-- The basic question is if too short tcp header should be treated as fatal error.
|
-- this payload normally would fail (broken packet, because TCP header
|
||||||
|
-- is too small) The basic question is if too short TCP header should be
|
||||||
|
-- treated as fatal error.
|
||||||
function Packet:new(packet, packet_len, force_continue)
|
function Packet:new(packet, packet_len, force_continue)
|
||||||
local o = setmetatable({}, {__index = Packet})
|
local o = setmetatable({}, {__index = Packet})
|
||||||
o.buf = packet
|
o.buf = packet
|
||||||
@@ -122,7 +131,8 @@ end
|
|||||||
-- Helpers
|
-- Helpers
|
||||||
|
|
||||||
|
|
||||||
-- from ip notation as string (like 1.2.3.4) to raw_string(4 bytes long)
|
--- Convert a dotted-quad IP address string (like 1.2.3.4) to a raw
|
||||||
|
-- string four bytes long.
|
||||||
function iptobin(str)
|
function iptobin(str)
|
||||||
local ret = ""
|
local ret = ""
|
||||||
for c in string.gmatch(str, "[0-9]+") do
|
for c in string.gmatch(str, "[0-9]+") do
|
||||||
@@ -130,41 +140,50 @@ function iptobin(str)
|
|||||||
end
|
end
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
-- from raw_ip (four bytes string) to dot-notation (like 1.2.3.4)
|
--- Convert a four-byte raw string to a dotted-quad IP address string.
|
||||||
function toip(raw_ip_addr)
|
function toip(raw_ip_addr)
|
||||||
if not raw_ip_addr then
|
if not raw_ip_addr then
|
||||||
return "?.?.?.?"
|
return "?.?.?.?"
|
||||||
end
|
end
|
||||||
return string.format("%i.%i.%i.%i", string.byte(raw_ip_addr,1,4))
|
return string.format("%i.%i.%i.%i", string.byte(raw_ip_addr,1,4))
|
||||||
end
|
end
|
||||||
-- get unsigned byte
|
--- Get an 8-bit integer at a 0-based byte offset in the packet.
|
||||||
function Packet:u8(index)
|
function Packet:u8(index)
|
||||||
return u8(self.buf, index)
|
return u8(self.buf, index)
|
||||||
end
|
end
|
||||||
|
--- Get a 16-bit integer at a 0-based byte offset in the packet.
|
||||||
function Packet:u16(index)
|
function Packet:u16(index)
|
||||||
return u16(self.buf, index)
|
return u16(self.buf, index)
|
||||||
end
|
end
|
||||||
|
--- Get a 32-bit integer at a 0-based byte offset in the packet.
|
||||||
function Packet:u32(index)
|
function Packet:u32(index)
|
||||||
return u32(self.buf, index)
|
return u32(self.buf, index)
|
||||||
end
|
end
|
||||||
|
--- Return the packet contents as a byte string.
|
||||||
function Packet:raw(index, length)
|
function Packet:raw(index, length)
|
||||||
return string.char(string.byte(self.buf, index+1, index+1+length-1))
|
return string.char(string.byte(self.buf, index+1, index+1+length-1))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set an 8-bit integer at a 0-based byte offset in the packet.
|
||||||
|
-- (big-endian).
|
||||||
function Packet:set_u8(index, num)
|
function Packet:set_u8(index, num)
|
||||||
self.buf = set_u8(self.buf, index, num)
|
self.buf = set_u8(self.buf, index, num)
|
||||||
return self.buf
|
return self.buf
|
||||||
end
|
end
|
||||||
|
--- Set a 16-bit integer at a 0-based byte offset in the packet.
|
||||||
|
-- (big-endian).
|
||||||
function Packet:set_u16(index, num)
|
function Packet:set_u16(index, num)
|
||||||
self.buf = set_u16(self.buf, index, num)
|
self.buf = set_u16(self.buf, index, num)
|
||||||
return self.buf
|
return self.buf
|
||||||
end
|
end
|
||||||
|
--- Set a 32-bit integer at a 0-based byte offset in the packet.
|
||||||
|
-- (big-endian).
|
||||||
function Packet:set_u32(index, num)
|
function Packet:set_u32(index, num)
|
||||||
self.buf = set_u32(self.buf, index, num)
|
self.buf = set_u32(self.buf, index, num)
|
||||||
return self.buf
|
return self.buf
|
||||||
end
|
end
|
||||||
|
|
||||||
-- PARSE IP PACKET HEADER
|
--- Parse an IP packet header.
|
||||||
function Packet:ip_parse(force_continue)
|
function Packet:ip_parse(force_continue)
|
||||||
self.ip_offset = 0
|
self.ip_offset = 0
|
||||||
if string.len(self.buf) < 20 then -- too short
|
if string.len(self.buf) < 20 then -- too short
|
||||||
@@ -196,43 +215,44 @@ function Packet:ip_parse(force_continue)
|
|||||||
self.ip_data_offset = self.ip_offset + self.ip_hl*4
|
self.ip_data_offset = self.ip_offset + self.ip_hl*4
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
-- set header length field
|
--- Set the header length field.
|
||||||
function Packet:ip_set_hl(len)
|
function Packet:ip_set_hl(len)
|
||||||
self:set_u8(self.ip_offset + 0, bit.bor(bit.lshift(self.ip_v, 4), bit.band(len, 0x0F)))
|
self:set_u8(self.ip_offset + 0, bit.bor(bit.lshift(self.ip_v, 4), bit.band(len, 0x0F)))
|
||||||
self.ip_v = bit.rshift(bit.band(self:u8(self.ip_offset + 0), 0xF0), 4)
|
self.ip_v = bit.rshift(bit.band(self:u8(self.ip_offset + 0), 0xF0), 4)
|
||||||
self.ip_hl = bit.band(self:u8(self.ip_offset + 0), 0x0F) -- header_length or data_offset
|
self.ip_hl = bit.band(self:u8(self.ip_offset + 0), 0x0F) -- header_length or data_offset
|
||||||
end
|
end
|
||||||
-- set packet length field
|
--- Set the packet length field.
|
||||||
function Packet:ip_set_len(len)
|
function Packet:ip_set_len(len)
|
||||||
self:set_u16(self.ip_offset + 2, len)
|
self:set_u16(self.ip_offset + 2, len)
|
||||||
end
|
end
|
||||||
-- set ttl
|
--- Set the TTL.
|
||||||
function Packet:ip_set_ttl(ttl)
|
function Packet:ip_set_ttl(ttl)
|
||||||
self:set_u8(self.ip_offset + 8, ttl)
|
self:set_u8(self.ip_offset + 8, ttl)
|
||||||
end
|
end
|
||||||
-- set checksum
|
--- Set the checksum.
|
||||||
function Packet:ip_set_checksum(checksum)
|
function Packet:ip_set_checksum(checksum)
|
||||||
self:set_u16(self.ip_offset + 10, checksum)
|
self:set_u16(self.ip_offset + 10, checksum)
|
||||||
end
|
end
|
||||||
-- count checksum for packet and save it
|
--- Count checksum for packet and save it.
|
||||||
function Packet:ip_count_checksum()
|
function Packet:ip_count_checksum()
|
||||||
self:ip_set_checksum(0)
|
self:ip_set_checksum(0)
|
||||||
local csum = in_cksum( self.buf:sub(0, self.ip_offset + self.ip_hl*4) )
|
local csum = in_cksum( self.buf:sub(0, self.ip_offset + self.ip_hl*4) )
|
||||||
self:ip_set_checksum(csum)
|
self:ip_set_checksum(csum)
|
||||||
end
|
end
|
||||||
-- set source ip
|
--- Set the source IP address.
|
||||||
function Packet:ip_set_bin_src(binip)
|
function Packet:ip_set_bin_src(binip)
|
||||||
nrip = u32(binip, 0)
|
nrip = u32(binip, 0)
|
||||||
self:set_u32(self.ip_offset + 12, nrip)
|
self:set_u32(self.ip_offset + 12, nrip)
|
||||||
self.ip_bin_src = self:raw(self.ip_offset + 12,4) -- raw 4-bytes string
|
self.ip_bin_src = self:raw(self.ip_offset + 12,4) -- raw 4-bytes string
|
||||||
end
|
end
|
||||||
-- set destination ip
|
--- Set the destination IP address.
|
||||||
function Packet:ip_set_bin_dst(binip)
|
function Packet:ip_set_bin_dst(binip)
|
||||||
nrip = u32(binip, 0)
|
nrip = u32(binip, 0)
|
||||||
self:set_u32(self.ip_offset + 16, nrip)
|
self:set_u32(self.ip_offset + 16, nrip)
|
||||||
self.ip_bin_dst = self:raw(self.ip_offset + 16,4)
|
self.ip_bin_dst = self:raw(self.ip_offset + 16,4)
|
||||||
end
|
end
|
||||||
-- set ip options field (and move the data, count new length etc)
|
--- Set the IP options field (and move the data, count new length,
|
||||||
|
-- etc.).
|
||||||
function Packet:ip_set_options(ipoptions)
|
function Packet:ip_set_options(ipoptions)
|
||||||
-- packet = <ip header> + ipoptions + <payload>
|
-- packet = <ip header> + ipoptions + <payload>
|
||||||
local buf = self.buf:sub(0+1,self.ip_offset + 20) .. ipoptions .. self.buf:sub(self.ip_data_offset+1)
|
local buf = self.buf:sub(0+1,self.ip_offset + 20) .. ipoptions .. self.buf:sub(self.ip_data_offset+1)
|
||||||
@@ -251,7 +271,7 @@ function Packet:ip_set_options(ipoptions)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- return short information about ip header
|
--- Return a short string representation of the IP header.
|
||||||
function Packet:ip_tostring()
|
function Packet:ip_tostring()
|
||||||
return string.format(
|
return string.format(
|
||||||
"IP %s -> %s",
|
"IP %s -> %s",
|
||||||
@@ -259,7 +279,7 @@ function Packet:ip_tostring()
|
|||||||
self.ip_dst)
|
self.ip_dst)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- parse ip/tcp options to dict structure
|
--- Parse IP/TCP options into a table.
|
||||||
function Packet:parse_options(offset, length)
|
function Packet:parse_options(offset, length)
|
||||||
local options = {}
|
local options = {}
|
||||||
local op = 1
|
local op = 1
|
||||||
@@ -287,7 +307,7 @@ function Packet:parse_options(offset, length)
|
|||||||
return options
|
return options
|
||||||
end
|
end
|
||||||
|
|
||||||
-- print short information about current packet
|
--- Return a short string representation of the packet.
|
||||||
function Packet:tostring()
|
function Packet:tostring()
|
||||||
if self.tcp then
|
if self.tcp then
|
||||||
return self:tcp_tostring()
|
return self:tcp_tostring()
|
||||||
@@ -300,7 +320,7 @@ function Packet:tostring()
|
|||||||
end
|
end
|
||||||
|
|
||||||
----------------------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------------------
|
||||||
-- PARSE ICMP PACKET HEADER
|
--- Parse an ICMP packet header.
|
||||||
function Packet:icmp_parse(force_continue)
|
function Packet:icmp_parse(force_continue)
|
||||||
self.icmp_offset = self.ip_data_offset
|
self.icmp_offset = self.ip_data_offset
|
||||||
if string.len(self.buf) < self.icmp_offset + 8 then -- let's say 8 bytes minimum
|
if string.len(self.buf) < self.icmp_offset + 8 then -- let's say 8 bytes minimum
|
||||||
@@ -322,13 +342,13 @@ function Packet:icmp_parse(force_continue)
|
|||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
-- return short information about icmp header
|
--- Return a short string representation of the ICMP header.
|
||||||
function Packet:icmp_tostring()
|
function Packet:icmp_tostring()
|
||||||
return self:ip_tostring() .. " ICMP(" .. self.icmp_payload:tostring() .. ")"
|
return self:ip_tostring() .. " ICMP(" .. self.icmp_payload:tostring() .. ")"
|
||||||
end
|
end
|
||||||
|
|
||||||
----------------------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------------------
|
||||||
-- PARSE TCP HEADER FROM PACKET
|
-- Parse a TCP packet header.
|
||||||
function Packet:tcp_parse(force_continue)
|
function Packet:tcp_parse(force_continue)
|
||||||
self.tcp = true
|
self.tcp = true
|
||||||
self.tcp_offset = self.ip_data_offset
|
self.tcp_offset = self.ip_data_offset
|
||||||
@@ -368,7 +388,7 @@ function Packet:tcp_parse(force_continue)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- return short information about tcp packet
|
--- Return a short string representation of the TCP packet.
|
||||||
function Packet:tcp_tostring()
|
function Packet:tcp_tostring()
|
||||||
return string.format(
|
return string.format(
|
||||||
"TCP %s:%i -> %s:%i",
|
"TCP %s:%i -> %s:%i",
|
||||||
@@ -377,7 +397,7 @@ function Packet:tcp_tostring()
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- parse options for tcp header
|
--- Parse options for TCP header.
|
||||||
function Packet:tcp_parse_options()
|
function Packet:tcp_parse_options()
|
||||||
local eoo = false
|
local eoo = false
|
||||||
for _,opt in ipairs(self.tcp_options) do
|
for _,opt in ipairs(self.tcp_options) do
|
||||||
@@ -399,29 +419,31 @@ function Packet:tcp_parse_options()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set the TCP source port.
|
||||||
function Packet:tcp_set_sport(port)
|
function Packet:tcp_set_sport(port)
|
||||||
self:set_u16(self.tcp_offset + 0, port)
|
self:set_u16(self.tcp_offset + 0, port)
|
||||||
end
|
end
|
||||||
|
--- Set the TCP destination port.
|
||||||
function Packet:tcp_set_dport(port)
|
function Packet:tcp_set_dport(port)
|
||||||
self:set_u16(self.tcp_offset + 2, port)
|
self:set_u16(self.tcp_offset + 2, port)
|
||||||
end
|
end
|
||||||
-- set tcp sequence field
|
--- Set the TCP sequence field.
|
||||||
function Packet:tcp_set_seq(new_seq)
|
function Packet:tcp_set_seq(new_seq)
|
||||||
self:set_u32(self.tcp_offset + 4, new_seq)
|
self:set_u32(self.tcp_offset + 4, new_seq)
|
||||||
end
|
end
|
||||||
-- set tcp flags field (like syn, ack, rst)
|
--- Set the TCP flags field (like SYN, ACK, RST).
|
||||||
function Packet:tcp_set_flags(new_flags)
|
function Packet:tcp_set_flags(new_flags)
|
||||||
self:set_u8(self.tcp_offset + 13, new_flags)
|
self:set_u8(self.tcp_offset + 13, new_flags)
|
||||||
end
|
end
|
||||||
-- set urgent pointer field
|
--- Set the urgent pointer field.
|
||||||
function Packet:tcp_set_urp(urg_ptr)
|
function Packet:tcp_set_urp(urg_ptr)
|
||||||
self:set_u16(self.tcp_offset + 18, urg_ptr)
|
self:set_u16(self.tcp_offset + 18, urg_ptr)
|
||||||
end
|
end
|
||||||
-- set tcp checksum field
|
--- Set the TCP checksum field.
|
||||||
function Packet:tcp_set_checksum(checksum)
|
function Packet:tcp_set_checksum(checksum)
|
||||||
self:set_u16(self.tcp_offset + 16, checksum)
|
self:set_u16(self.tcp_offset + 16, checksum)
|
||||||
end
|
end
|
||||||
-- count and save tcp checksum field
|
--- Count and save the TCP checksum field.
|
||||||
function Packet:tcp_count_checksum()
|
function Packet:tcp_count_checksum()
|
||||||
self:tcp_set_checksum(0)
|
self:tcp_set_checksum(0)
|
||||||
local proto = self.ip_p
|
local proto = self.ip_p
|
||||||
@@ -436,7 +458,7 @@ function Packet:tcp_count_checksum()
|
|||||||
self:tcp_set_checksum(in_cksum(b))
|
self:tcp_set_checksum(in_cksum(b))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- small database, mtu to link type string. Stolen from p0f.
|
--- Map an MTU to a link type string. Stolen from p0f.
|
||||||
function Packet:tcp_lookup_link()
|
function Packet:tcp_lookup_link()
|
||||||
local mtu_def = {
|
local mtu_def = {
|
||||||
{["mtu"]=256, ["txt"]= "radio modem"},
|
{["mtu"]=256, ["txt"]= "radio modem"},
|
||||||
@@ -498,7 +520,8 @@ end
|
|||||||
----------------------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
-- UTILS
|
-- UTILS
|
||||||
-- get binary string as hex string
|
|
||||||
|
--- Convert a binary string to a hex string.
|
||||||
function bintohex(str)
|
function bintohex(str)
|
||||||
local b = ""
|
local b = ""
|
||||||
if not str then -- nil
|
if not str then -- nil
|
||||||
@@ -512,12 +535,13 @@ end
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Parse specifically printed hex string as binary
|
--- Convert a hex string to a binary string.
|
||||||
|
-- \n\n
|
||||||
-- Only bytes [a-f0-9A-F] from input are interpreted. The rest is ignored.
|
-- Only bytes [a-f0-9A-F] from input are interpreted. The rest is ignored.
|
||||||
-- Number of interpreted bytes _must_ be even. *The input is interpreted in pairs*.
|
-- Number of interpreted bytes _must_ be even. *The input is interpreted in pairs*.\n
|
||||||
-- hextobin("20 20 20") -> " "
|
-- hextobin("20 20 20") -> " "\n
|
||||||
-- hextobin("414243") -> "ABC"
|
-- hextobin("414243") -> "ABC"\n
|
||||||
-- hextobin("\\41\\42\\43") -> "ABC"
|
-- hextobin("\\41\\42\\43") -> "ABC"\n
|
||||||
-- hextobin(" 41 42 43 ")-> "ABC"
|
-- hextobin(" 41 42 43 ")-> "ABC"
|
||||||
function hextobin(str)
|
function hextobin(str)
|
||||||
local ret = ""
|
local ret = ""
|
||||||
|
|||||||
Reference in New Issue
Block a user