📄 packet.lua
字号:
-- license = "See nmaps COPYING for license"module("packet" ,package.seeall)-- Raw package parsing functions. Used with raw sockets-- in nse.-- Author: Marek Majkowski <majek04+nse@gmail.com>--[[--]]require "bit"------------------------------------------------------------------------------------------------------------------ extract number from binary stringfunction u8(b, i) return string.byte(b, i+1)endfunction u16(b, i) local b1,b2 b1, b2 = string.byte(b, i+1), string.byte(b, i+2) -- 2^8 2^0 return b1*256 + b2endfunction u32(b,i) local b1,b2,b3,b4 b1, b2 = string.byte(b, i+1), string.byte(b, i+2) b3, b4 = string.byte(b, i+3), string.byte(b, i+4) -- 2^24 2^16 2^8 2^0 return b1*16777216 + b2*65536 + b3*256 + b4end-- insert number to binary stringfunction set_u8(b, i, num) local s = string.char(bit.band(num, 0xff)) return b:sub(0+1, i+1-1) .. s .. b:sub(i+1+1)endfunction set_u16(b, i, num) 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)endfunction set_u32(b,i, num) 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,8), 0xff)) .. string.char(bit.band(num, 0xff)) return b:sub(0+1, i+1-1) .. s .. b:sub(i+1+4)end-- Checksum---- Standard BSD internet checksum routine check nmap/tcpip.ccfunction in_cksum(b) local sum = 0 local c local x = b while x:len() > 1 do c = x:sub(1,2) x = x:sub(3) sum = sum + u16(c, 0) end sum = bit.rshift(sum, 16) + bit.band(sum, 0xffff) sum = sum + bit.rshift(sum, 16) sum = bit.bnot(sum) sum = bit.band(sum, 0xffff) -- trunctate to 16 bits return sumend-- ip protocol fieldIPPROTO_IP = 0 -- Dummy protocol for TCPIPPROTO_ICMP = 1 -- Internet Control Message ProtocolIPPROTO_IGMP = 2 -- Internet Group Management ProtocolIPPROTO_IPIP = 4 -- IPIP tunnels (older KA9Q tunnels use 94)IPPROTO_TCP = 6 -- Transmission Control ProtocolIPPROTO_EGP = 8 -- Exterior Gateway ProtocolIPPROTO_PUP = 12 -- PUP protocolIPPROTO_UDP = 17 -- User Datagram ProtocolIPPROTO_IDP = 22 -- XNS IDP protocolIPPROTO_DCCP = 33 -- Datagram Congestion Control ProtocolIPPROTO_RSVP = 46 -- RSVP protocolIPPROTO_GRE = 47 -- Cisco GRE tunnels (rfc 1701,1702)IPPROTO_IPV6 = 41 -- IPv6-in-IPv4 tunnellingIPPROTO_ESP = 50 -- Encapsulation Security Payload protocolIPPROTO_AH = 51 -- Authentication Header protocolIPPROTO_BEETPH = 94 -- IP option pseudo header for BEETIPPROTO_PIM = 103 -- Protocol Independent MulticastIPPROTO_COMP = 108 -- Compression Header protocolIPPROTO_SCTP = 132 -- Stream Control Transport ProtocolIPPROTO_UDPLITE = 136 -- UDP-Lite (RFC 3828)------------------------------------------------------------------------------------------------------------------ Packet is a classPacket = {}-- Constructor-- packet - binary string with packet data-- packet_len - packet length, it could be more than string.len(packet)-- force_continue - whether error in parsing headers should be fatal or not.-- especially usefull at parsing icmp packets, where on small icmp payload-- could be tcp header. The problem is that parsing 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) local o = setmetatable({}, {__index = Packet}) o.buf = packet o.packet_len = packet_len if not o:ip_parse(force_continue) then return nil end if o.ip_p == IPPROTO_TCP then if not o:tcp_parse(force_continue) then io.write("Error while parsing TCP packet\n") end elseif o.ip_p == IPPROTO_ICMP then if not o:icmp_parse(force_continue) then io.write("Error while parsing ICMP packet\n") end end return oend-- Helpers-- from ip notation as string (like 1.2.3.4) to raw_string(4 bytes long)function iptobin(str) local ret = "" for c in string.gmatch(str, "[0-9]+") do ret = ret .. string.char(c+0) -- automatic conversion to int end return retend-- from raw_ip (four bytes string) to dot-notation (like 1.2.3.4)function toip(raw_ip_addr) if not raw_ip_addr then return "?.?.?.?" end return string.format("%i.%i.%i.%i", string.byte(raw_ip_addr,1,4))end-- get unsigned bytefunction Packet:u8(index) return u8(self.buf, index)endfunction Packet:u16(index) return u16(self.buf, index)endfunction Packet:u32(index) return u32(self.buf, index)endfunction Packet:raw(index, length) return string.char(string.byte(self.buf, index+1, index+1+length-1))endfunction Packet:set_u8(index, num) self.buf = set_u8(self.buf, index, num) return self.bufendfunction Packet:set_u16(index, num) self.buf = set_u16(self.buf, index, num) return self.bufendfunction Packet:set_u32(index, num) self.buf = set_u32(self.buf, index, num) return self.bufend-- PARSE IP PACKET HEADERfunction Packet:ip_parse(force_continue) self.ip_offset = 0 if string.len(self.buf) < 20 then -- too short return false end 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 if self.ip_v ~= 4 then -- not ip return false end self.ip = true self.ip_tos = self:u8(self.ip_offset + 1) self.ip_len = self:u16(self.ip_offset + 2) self.ip_id = self:u16(self.ip_offset + 4) self.ip_off = self:u16(self.ip_offset + 6) self.ip_rf = bit.band(self.ip_off, 0x8000)~=0 -- true/false self.ip_df = bit.band(self.ip_off, 0x4000)~=0 self.ip_mf = bit.band(self.ip_off, 0x2000)~=0 self.ip_off = bit.band(self.ip_off, 0x1FFF) -- fragment offset self.ip_ttl = self:u8(self.ip_offset + 8) self.ip_p = self:u8(self.ip_offset + 9) self.ip_sum = self:u16(self.ip_offset + 10) self.ip_bin_src = self:raw(self.ip_offset + 12,4) -- raw 4-bytes string self.ip_bin_dst = self:raw(self.ip_offset + 16,4) self.ip_src = toip(self.ip_bin_src) -- formatted string self.ip_dst = toip(self.ip_bin_dst) self.ip_opt_offset = self.ip_offset + 20 self.ip_options = self:parse_options(self.ip_opt_offset, ((self.ip_hl*4)-20)) self.ip_data_offset = self.ip_offset + self.ip_hl*4 return trueend-- set header length fieldfunction 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.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_offsetend-- set packet length fieldfunction Packet:ip_set_len(len) self:set_u16(self.ip_offset + 2, len)end-- set ttlfunction Packet:ip_set_ttl(ttl) self:set_u8(self.ip_offset + 8, ttl)end-- set checksumfunction Packet:ip_set_checksum(checksum) self:set_u16(self.ip_offset + 10, checksum)end-- count checksum for packet and save itfunction Packet:ip_count_checksum() self:ip_set_checksum(0) local csum = in_cksum( self.buf:sub(0, self.ip_offset + self.ip_hl*4) ) self:ip_set_checksum(csum)end-- set source ipfunction Packet:ip_set_bin_src(binip) nrip = u32(binip, 0) self:set_u32(self.ip_offset + 12, nrip) self.ip_bin_src = self:raw(self.ip_offset + 12,4) -- raw 4-bytes stringend-- set destination ipfunction Packet:ip_set_bin_dst(binip) nrip = u32(binip, 0) self:set_u32(self.ip_offset + 16, nrip) self.ip_bin_dst = self:raw(self.ip_offset + 16,4)end-- set ip options field (and move the data, count new length etc)function Packet:ip_set_options(ipoptions) -- 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) self.buf = buf -- set ip_len self:ip_set_len(self.buf:len()) -- set ip_hl self:ip_set_hl(5 + ipoptions:len()/4) -- set data offset correctly self.ip_options = self:parse_options(self.ip_opt_offset, ((self.ip_hl*4)-20)) self.ip_data_offset = self.ip_offset + self.ip_hl*4 if self.tcp then self.tcp_offset = self.ip_data_offset elseif self.icmp then self.icmp_offset = self.ip_data_offset endend-- return short information about ip headerfunction Packet:ip_tostring() return string.format( "IP %s -> %s", self.ip_src, self.ip_dst)end-- parse ip/tcp options to dict structurefunction Packet:parse_options(offset, length) local options = {} local op = 1 local opt_ptr = 0 while opt_ptr < length do local t, l, d options[op] = {} t = self:u8(offset + opt_ptr) options[op].type = t if t==0 or t==1 then l = 1 d = nil
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -