Merged all of the scruby patches, fixed Dot11 support with regards to RadioTap headers.

git-svn-id: file:///home/svn/framework3/trunk@5446 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
HD Moore 2008-03-17 04:46:42 +00:00
parent 4ee248bf3e
commit c3a4cda127
8 changed files with 842 additions and 163 deletions

View File

@ -99,7 +99,7 @@ module Exploit::Capture
return if not pkt
raw = pkt.raw_data
off = 0
case pkt.datalink
when 119
off = 144
@ -128,8 +128,10 @@ module Exploit::Capture
def each_packet
return if not self.capture
# print_status("Link type is #{capture.datalink}")
capture.each do |packet|
dec = Scruby.linklayer_dissector(capture.datalink, packet)
if(dec)

View File

@ -52,10 +52,6 @@ module Scruby
end
end
def method_missing(method, *args)
Scruby.method_missing(method, *args)
end
# Same as above, for fields
def self.field(method, *args)

View File

@ -13,11 +13,17 @@
module Scruby
# Scruby version
SCRUBY_VERSION = '0.2.1-hdm-2'
SCRUBY_VERSION = '0.3-hdm'
# Completion for functions
FUNCTIONS_LIST = %w[sendp sniff ls lsc]
# Link types that are not implented in Pcap
DLT_OPENBSD = 12
# Pcap::DLT_IEEE802 is 6 but on my system, sniffing on ath0 return 105 as link type
DLT_IEEE80211 = 105
# History
RECORD_HISTORY = true
@ -31,25 +37,111 @@ module Scruby
TIMEOUT = 1
LOOPBACK_DEVICE_PREFIX = 'lo'
# If two layers are to be bound every time
BIND_ALWAYS = ''
# Constants for Ethernet
ETHERTYPE_IPv4 = 0x800
ETHERTYPE_ARP = 0x806
ETHERTYPE_ALL = { ETHERTYPE_IPv4 => "IPv4",
ETHERTYPE_ARP => "ARP"}
ETHERTYPE_ARP = 0x806
ETHERTYPE_ALL = { ETHERTYPE_IPv4 => 'IPv4',
ETHERTYPE_ARP => 'ARP' }
ETHERADDR_ANY = '00:00:00:00:00:00'
# Constants for ARP
ARPTYPE_WHOAS = 1
ARPTYPE_ISAT = 2
ARPTYPE_RARP_REQ = 3
ARPTYPE_RARP_RES = 4
ARPTYPE_DYN_RARP_REQ = 5
ARPTYPE_DYN_RARP_REP = 6
ARPTYPE_DYN_RARP_ERR = 7
ARPTYPE_IN_ARP_REQ = 8
ARPTYPE_IN_ARP_REP = 9
ARPTYPE_ALL = { ARPTYPE_WHOAS => 'who-as',
ARPTYPE_ISAT => 'is-at',
ARPTYPE_RARP_REQ => 'RARP-req',
ARPTYPE_RARP_RES => 'RARP-rep',
ARPTYPE_DYN_RARP_REQ => 'DynRARP-req',
ARPTYPE_DYN_RARP_REP => 'DynRARP-rep',
ARPTYPE_DYN_RARP_ERR => 'DynRARP-err',
ARPTYPE_IN_ARP_REQ => 'InARP-req',
ARPTYPE_IN_ARP_REP => 'InARP-rep' }
ARPHWTYPE_ETHER = 1
ARPHWTYPE_FRAME_RELAY = 15
ARPHWTYPE_ALL = { ARPHWTYPE_ETHER => 'Ethernet',
ARPHWTYPE_FRAME_RELAY => 'FrameRelay' }
ARPHWLEN_TOKEN_RING = 1
ARPHWLEN_ETHER = 6
ARPHWLEN_ALL = { ARPHWLEN_TOKEN_RING => 'TokenRing',
ARPHWLEN_ETHER => 'Ethernet' }
ARPPROTOLEN_IPv4 = 4
ARPPROTOLEN_IPv6 = 16
ARPPROTOLEN_ALL = { ARPPROTOLEN_IPv4 => 'IPv4',
ARPPROTOLEN_IPv6 => 'IPv6' }
# Constants for BSD loopback interfaces
BSDLOOPBACKTYPE_IPv4 = 2
# Constants for IP
IPFLAGS = %w[MF DF evil]
IPPROTO_ICMP = 1
IPPROTO_TCP = 6
IPPROTO_UDP = 17
IPPROTO_ALL = { IPPROTO_ICMP => "ICMP",
IPPROTO_TCP => "TCP",
IPPROTO_UDP => "UDP" }
IPPROTO_ALL = { IPPROTO_ICMP => 'ICMP',
IPPROTO_TCP => 'TCP',
IPPROTO_UDP => 'UDP' }
# Constants for TCP
TCPFLAGS = %w[FIN SYN RST PSH ACK URG ECN RES]
# Constants for ICMP
ICMPTYPE_ECHO = 8
ICMPTYPE_ECHO_REQ = 8
ICMPTYPE_ALL = { ICMPTYPE_ECHO_REQ => 'echo request' }
# Constants for 802.11
DOT11TYPE_MANAGEMENT = 0
DOT11TYPE_CONTROL = 1
DOT11TYPE_DATA = 2
DOT11TYPE_RESERVED = 3
DOT11TYPE_ALL = { DOT11TYPE_MANAGEMENT => 'Management',
DOT11TYPE_CONTROL => 'Control',
DOT11TYPE_DATA => 'Data',
DOT11TYPE_RESERVED => 'Reserved' }
DOT11SUBTYPE_PS_POLL = 0b1010
DOT11SUBTYPE_RTS = 0b1011
DOT11SUBTYPE_CF_END = 0b1110
DOT11SUBTYPE_CF_END_CF_ACK = 0b1111
DOT11_FC_FLAGS = %w[to-DS from-DS MF retry pw-mgt MD wep order]
DOT11_CAPABILITIES = %w[res8 res9 short-slot res11 res12 DSSS-OFDM res14 res15 ESS IBSS CFP CFP-req privacy short-preamble PBCC agility]
DOT11_ID = {0 => 'SSID', 1 => 'Rates', 2 => 'FHset', 3 => 'DSset', 4 => 'CFset', 5 => 'TIM', 6 => 'IBSSset', 16 => 'challenge', 42 => 'ERPinfo', 46 => 'QoS Capability', 47 => 'ERPinfo', 48 => 'RSNinfo', 50 => 'ESRates',221 => 'vendor',68 => 'reserved'}
DOT11_REASON = {0 => 'reserved',1 => 'unspec', 2 => 'auth-expired',
3 => 'deauth-ST-leaving',
4 => 'inactivity', 5 => 'AP-full', 6 => 'class2-from-nonauth',
7 => 'class3-from-nonass', 8 => 'disas-ST-leaving',
9 => 'ST-not-auth'}
DOT11_AUTH_ALGO = {0 => 'open', 1 => 'sharedkey'}
DOT11_STATUS = {0 => 'success', 1 => 'failure', 10 => 'cannot-support-all-cap',
11 => 'inexist-asso', 12 => 'asso-denied', 13 => 'algo-unsupported',
14 => 'bad-seq-num', 15 => 'challenge-failure',
16 => 'timeout', 17 => 'AP-full', 18 => 'rate-unsupported'}
RADIOTAP_PRESENT = %w[TSFT Flags Rate Channel FHSS dBm_AntSignal dBm_AntNoise Lock_Quality TX_Attenuation dB_TX_Attenuation
dBm_TX_Power Antenna dB_AntSignal dB_AntNoise
b14 b15 b16 b17 b18 b19 b20 b21 b22 b23
b24 b25 b26 b27 b28 b29 b30 Ext]
def self.aware_proto
@@aware_proto

View File

@ -37,21 +37,18 @@ module Scruby
# Dissector for Ethernet
class Ether<Layer
Scruby.register_dissector(self)
def method_missing(method, *args)
return Scruby.field(method, *args)
end
attr_accessor :dst, :src, :type
def init
@protocol = 'Ethernet'
@fields_desc = [ MACField('dst', '00:00:00:00:00:00'),
MACField('src', '00:00:00:00:00:00'),
XShortField('type', ETHERTYPE_IPv4) ]
@fields_desc = [ MACField('dst', ETHERADDR_ANY),
MACField('src', ETHERADDR_ANY),
XShortEnumField('type', ETHERTYPE_IPv4, ETHERTYPE_ALL) ]
end
end
# Dissector for ARP
class ARP<Layer
Scruby.register_dissector(self)
@ -83,27 +80,23 @@ module Scruby
underlayer.type = ETHERTYPE_ARP
end
end
end
end
# Dissector for IPv4
class IP<Layer
Scruby.register_dissector(self)
def method_missing(method, *args)
return Scruby.field(method, *args)
end
attr_accessor :version, :ihl, :tos, :len, :id, :flags, :frag
attr_accessor :ttl, :proto, :chksum, :src, :dst
def init
@protocol = 'IPv4'
@fields_desc = [ BitField("version", 4, 4),
BitField("ihl", 5, 4),
@fields_desc = [ BitField('version', 4, 4),
BitField('ihl', 5, 4),
XByteField('tos', 0),
ShortField('len', 20),
XShortField('id', 0),
BitField('flags', 0, 3),
FlagsField('flags', 0, 3, IPFLAGS),
BitField('frag', 0, 13),
ByteField('ttl', 64),
ByteEnumField('proto', IPPROTO_TCP, IPPROTO_ALL),
@ -126,15 +119,12 @@ module Scruby
# Dissector for ICMP
class ICMP<Layer
Scruby.register_dissector(self)
def method_missing(method, *args)
return Scruby.field(method, *args)
end
attr_accessor :type, :code, :chksum, :id, :seq
def init
@protocol = 'ICMP'
@fields_desc = [ ByteField('type', ICMPTYPE_ECHO),
@fields_desc = [ ByteEnumField('type', ICMPTYPE_ECHO_REQ, ICMPTYPE_ALL),
ByteField('code', 0),
XShortField('chksum', 0),
XShortField('id', 0),
@ -152,10 +142,7 @@ module Scruby
# Dissector for Raw
class Raw<Layer
Scruby.register_dissector(self)
def method_missing(method, *args)
return Scruby.field(method, *args)
end
attr_accessor :load
def init
@ -168,9 +155,6 @@ module Scruby
# Dissector for TCP
class TCP<Layer
Scruby.register_dissector(self)
def method_missing(method, *args)
return Scruby.field(method, *args)
end
attr_accessor :sport, :dport, :seq, :ack, :dataofs, :reserved
attr_accessor :flags, :window, :chksum, :urgptr
@ -181,9 +165,9 @@ module Scruby
ShortField('dport', 80),
IntField('seq', 0),
IntField('ack', 0),
BitField("dataofs", 5, 4),
BitField("reserved", 0, 4),
XByteField('flags', 0x2),
BitField('dataofs', 5, 4),
BitField('reserved', 0, 4),
FlagsField('flags', 0x2, 8, TCPFLAGS),
ShortField('window', 8192),
XShortField('chksum', 0),
ShortField('urgptr', 0) ]
@ -217,10 +201,7 @@ module Scruby
# Dissector for UDP
class UDP<Layer
Scruby.register_dissector(self)
def method_missing(method, *args)
return Scruby.field(method, *args)
end
attr_accessor :sport, :dport, :len, :chksum
def init
@ -263,10 +244,7 @@ module Scruby
# Dissector for the classic BSD loopback header (NetBSD, FreeBSD and Mac OS X)
class ClassicBSDLoopback<Layer
Scruby.register_dissector(self)
def method_missing(method, *args)
return Scruby.field(method, *args)
end
attr_accessor :header
def init
@ -279,10 +257,7 @@ module Scruby
# Dissector for the OpenBSD loopback header
class OpenBSDLoopback<Layer
Scruby.register_dissector(self)
def method_missing(method, *args)
return Scruby.field(method, *args)
end
attr_accessor :header
def init
@ -296,10 +271,7 @@ module Scruby
# Dissector for the Prism header
class Prism<Layer
Scruby.register_dissector(self)
def method_missing(method, *args)
return Scruby.field(method, *args)
end
attr_accessor :header
def init
@ -352,43 +324,12 @@ module Scruby
end
end
=begin
class Dot11<Layer
Scruby.register_dissector(self)
def method_missing(method, *args)
return Scruby.field(method, *args)
end
attr_accessor :header
def init
@protocol = '802.11'
@fields_desc = [
BitField("subtype", 0, 4),
BitEnumField("type", 0, 2, ["Management", "Control", "Data", "Reserved"]),
BitField("proto", 0, 2),
FlagsField("FCfield", 0, 8, ["to-DS", "from-DS", "MF", "retry", "pw-mgt", "MD", "wep", "order"]),
ShortField("ID",0),
MACField("addr1", ETHER_ANY),
Dot11Addr2MACField("addr2", ETHER_ANY),
Dot11Addr3MACField("addr3", ETHER_ANY),
Dot11SCField("SC", 0),
Dot11Addr4MACField("addr4", ETHER_ANY)
]
end
end
=end
# Dissector for RIFF file format header
class RIFF<Layer
Scruby.register_dissector(self)
def method_missing(method, *args)
return Scruby.field(method, *args)
end
attr_accessor :id, :size
attr_accessor :id, :size, :headerid
def init
@protocol = 'RIFF chunk'
@ -402,11 +343,8 @@ module Scruby
# Dissector for ANI header chunk format
class ANI<Layer
Scruby.register_dissector(self)
def method_missing(method, *args)
return Scruby.field(method, *args)
end
attr_accessor :headersize, :frames, :steps, :width, :height, :bitcount, :planes
attr_accessor :id, :size, :headersize, :frames, :steps, :width, :height, :bitcount, :planes
attr_accessor :displayrate, :reserved, :sequence, :icon
def init
@ -428,6 +366,239 @@ module Scruby
end
# Dot11 dissectors
class RadioTap<Layer
Scruby.register_dissector(self)
attr_accessor :version, :pad, :len, :notdecoded, :present
def init
@protocol = 'RadioTap'
@fields_desc = [ ByteField('version', 0),
ByteField('pad', 0),
FieldLenField('len', 0, 'radiotap', 's', { :adjust => -8 } ),
FlagsField('present', 0, 32, RADIOTAP_PRESENT),
StrLenField('radiotap', '', 'len')
]
end
end
# Dot11 dissectors
class Dot11<Layer
Scruby.register_dissector(self)
attr_accessor :subtype, :type, :proto, :FCfield, :ID, :addr1, :addr2, :addr3, :SC, :addr4
def init
@protocol = '802.11'
@fields_desc = [ BitField('subtype', 0, 4),
BitEnumField('type', DOT11TYPE_DATA, 2, DOT11TYPE_ALL),
BitField('proto', 0, 2),
FlagsField('FCfield', 0, 8, DOT11_FC_FLAGS),
ShortField('ID', 0),
MACField('addr1', ETHERADDR_ANY),
Dot11Addr2MACField('addr2', ETHERADDR_ANY),
Dot11Addr3MACField('addr3', ETHERADDR_ANY),
Dot11SCField('SC', 0),
Dot11Addr4MACField('addr4', ETHERADDR_ANY) ]
end
end
class Dot11QoS<Layer
Scruby.register_dissector(self)
attr_accessor :TID, :EOSP, :AckPolicy, :Reserved, :TXOP
def init
@protocol = '802.11 QoS'
@fields_desc = [ BitField('TID',0,4),
BitField('EOSP',0,1),
BitField('AckPolicy',0,2),
BitField('Reserved',0,1),
ByteField('TXOP',0) ]
end
end
class Dot11Beacon<Layer
Scruby.register_dissector(self)
attr_accessor :timestamp, :beacon_interval, :cap
def init
@protocol = '802.11 Beacon'
@fields_desc = [ LongField('timestamp', 0), # Bug: should be little endian
LEShortField('beacon_interval', 0x64),
FlagsField('cap', 0, 16, DOT11_CAPABILITIES) ]
end
end
class Dot11Elt<Layer
Scruby.register_dissector(self)
attr_accessor :ID, :len, :info
def init
@protocol = '802.11 Information Element'
@fields_desc = [ ByteEnumField('ID', 0, DOT11_ID),
FieldLenField('len', 0, 'info', 'C'),
StrLenField('info', '', 'len') ]
end
end
class Dot11ATIM<Layer
Scruby.register_dissector(self)
def init
@protocol = '802.11 ATIM'
end
end
class Dot11Disas<Layer
Scruby.register_dissector(self)
attr_accessor :reason
def init
@protocol = '802.11 Disassociation'
@fields_desc = [ LEShortEnumField('reason', 1, DOT11_REASON) ]
end
end
class Dot11AssoReq<Layer
Scruby.register_dissector(self)
attr_accessor :cap, :listen_interval
def init
@protocol = '802.11 Association Request'
@fields_desc = [ FlagsField('cap', 0, 16, DOT11_CAPABILITIES),
LEShortField('listen_interval', 0xc8) ]
end
end
class Dot11AssoResp<Layer
Scruby.register_dissector(self)
attr_accessor :cap, :status, :AID
def init
@protocol = '802.11 Association Response'
@fields_desc = [ FlagsField('cap', 0, 16, DOT11_CAPABILITIES),
LEShortField('status', 0),
LEShortField('AID', 0) ]
end
end
class Dot11ReassoReq<Layer
Scruby.register_dissector(self)
attr_accessor :cap, :current_AP, :listen_interval
def init
@protocol = '802.11 Reassociation Request'
@fields_desc = [ FlagsField('cap', 0, 16, DOT11_CAPABILITIES),
MACField('current_AP', ETHERADDR_ANY),
LEShortField('listen_interval', 0xc8) ]
end
end
class Dot11ReassoResp<Dot11AssoResp
Scruby.register_dissector(self)
def init
@protocol = '802.11 Reassociation Response'
end
end
class Dot11ProbeReq<Layer
Scruby.register_dissector(self)
def init
@protocol = '802.11 Probe Request'
end
end
class Dot11ProbeResp<Layer
Scruby.register_dissector(self)
attr_accessor :timestamp, :beacon_interval, :cap
def init
@protocol = '802.11 Probe Response'
@fields_desc = [ LongField('timestamp', 0), # Bug: should be little endian
LEShortField('beacon_interval', 0x64),
FlagsField('cap', 0, 16, DOT11_CAPABILITIES) ]
end
end
class Dot11Auth<Layer
Scruby.register_dissector(self)
attr_accessor :algo, :seqnum, :status
def init
@protocol = '802.11 Authentication'
@fields_desc = [ LEShortEnumField('algo', 0, DOT11_AUTH_ALGO),
LEShortField('seqnum', 0),
LEShortEnumField('status', 0, DOT11_STATUS) ]
end
end
class Dot11Deauth<Layer
Scruby.register_dissector(self)
attr_accessor :reason
def init
@protocol = '802.11 Deauthentication'
@fields_desc = [ LEShortEnumField('reason', 1, DOT11_REASON) ]
end
end
class Dot11WEP<Layer
Scruby.register_dissector(self)
attr_accessor :iv, :keyid, :wepdata, :icv
def init
@protocol = '802.11 WEP packet'
@fields_desc = [ StrFixedLenField('iv', "\0\0\0", 3),
ByteField('keyid', 0),
StrField('wepdata', ''), # Bug: 4 bytes remains
IntField('icv', 0) ]
end
end
class LLC<Layer
Scruby.register_dissector(self)
attr_accessor :dsap, :ssap, :ctrl
def init
@protocol = 'LLC'
@fields_desc = [ XByteField('dsap', 0),
XByteField('ssap', 0),
ByteField('ctrl', 0) ]
end
end
# Layer bounds
@@layer_bounds =
{
@ -436,7 +607,63 @@ module Scruby
['type', ETHERTYPE_IPv4, IP],
['type', ETHERTYPE_ARP, ARP]
],
'RadioTap' =>
[
[BIND_ALWAYS, BIND_ALWAYS, Dot11]
],
'Prism' =>
[
[BIND_ALWAYS, BIND_ALWAYS, Dot11]
],
'Dot11' => [
['type', 2, LLC],
['subtype', 0, Dot11AssoReq],
['subtype', 1, Dot11AssoResp],
['subtype', 2, Dot11ReassoReq],
['subtype', 3, Dot11ReassoResp],
['subtype', 4, Dot11ProbeReq],
['subtype', 5, Dot11ProbeResp],
['subtype', 8, Dot11Beacon],
['subtype', 9, Dot11ATIM],
['subtype', 10, Dot11Disas],
['subtype', 11, Dot11Auth],
['subtype', 12, Dot11Deauth],
],
'Dot11QoS' => [
[BIND_ALWAYS, BIND_ALWAYS, LLC]
],
'Dot11Beacon' => [
[BIND_ALWAYS, BIND_ALWAYS, Dot11Elt]
],
'Dot11AssoReq' => [
[BIND_ALWAYS, BIND_ALWAYS, Dot11Elt]
],
'Dot11AssoResp' => [
[BIND_ALWAYS, BIND_ALWAYS, Dot11Elt]
],
'Dot11ReassoReq' => [
[BIND_ALWAYS, BIND_ALWAYS, Dot11Elt]
],
'Dot11ReassoResp' => [
[BIND_ALWAYS, BIND_ALWAYS, Dot11Elt]
],
'Dot11ProbeReq' => [
[BIND_ALWAYS, BIND_ALWAYS, Dot11Elt]
],
'Dot11ProbeResp' => [
[BIND_ALWAYS, BIND_ALWAYS, Dot11Elt]
],
'Dot11Auth' => [
[BIND_ALWAYS, BIND_ALWAYS, Dot11Elt]
],
'Dot11Elt' => [
[BIND_ALWAYS, BIND_ALWAYS, Dot11Elt]
],
'ClassicBSDLoopback' =>
[
['header', BSDLOOPBACKTYPE_IPv4, IP]
@ -466,10 +693,17 @@ module Scruby
Ether(pkt)
when Pcap::DLT_NULL
ClassicBSDLoopback(pkt)
when Pcap::DLT_RAW
when DLT_OPENBSD
OpenBSDLoopback(pkt)
when Pcap::DLT_PRISM_HEADER
Prism(pkt)
when Pcap::DLT_IEEE802
when Pcap::DLT_IEEE802_11
Dot11(pkt)
when Pcap::DLT_IEEE802_11_RADIO
RadioTap(pkt)
when Pcap::DLT_IEEE802_11_RADIO_AVS
RadioTap(pkt)
when 101,
IP(pkt)
else
@ -494,6 +728,23 @@ Scruby packet dissectors/types:
Raw
TCP
UDP
LLC
ARP
Prism
Dot11
Dot11Beacon
Dot11Elt
Dot11ATIM
Dot11Disas
Dot11AssoReq
Dot11AssoResp
Dot11ReassoReq
Dot11ReassoResp
Dot11ProbeReq
Dot11ProbeResp
Dot11Auth
Dot11Deauth
Dot11WEP
Scapy (1.2.0.1) packet dissectors/types:
========================================

View File

@ -45,6 +45,9 @@ module Scruby
# Retrieves the field value from a string. This may be redefined by subclasses.
def dissect(layer, string)
# Preparing the packet for building
self.pre_build()
part = string.unpack(self.format + 'a*')
# Returning if nothing could be unpacked
@ -73,7 +76,7 @@ module Scruby
end
# Converts from human to internal encoding
# e.g. allows TCP(:sport=>'http')
# e.g. allows TCP(:proto=>'ICMP')
def from_human(value)
return value
end
@ -84,12 +87,23 @@ module Scruby
return value.to_s
end
# Same as tuhuman() but displays more information
# Same as to_human() but displays more information
# e.g. "6 (TCP)" instead of "6" for IP protocol
def to_human_complete(value)
return value.to_s
end
# Returns yes if the field is to be added to the dissectors, e.g. depending
# on the value of another field of the layer (see Dot11*)
def is_applicable?(layer)
return true
end
# Prepares the packet for building
# e.g. for StrLenField, retrieves the right format size from the associated FieldLenField
def pre_build
end
end
# Shortcut mixins for reducing code size
@ -102,6 +116,24 @@ module Scruby
return sprintf('0x%x', value)
end
end
# Shortcut mixins for reducing code size
module FieldHumanHexEnum
def to_human(value)
return sprintf('0x%x', value)
end
def to_human_complete(value)
# Checking if the value is in the enumeration keys
if @enum.keys.include?(value)
return sprintf('0x%x', value) + ' (' + @enum[value].to_s + ')'
# Otherwise, just returning the value
else
return sprintf('0x%x', value)
end
end
end
# Shortcut mixins for signed conversion
module SignedValue
@ -147,7 +179,7 @@ module Scruby
end
def to_human_complete(value)
puts "ok"
# Checking if the value is in the enumeration keys
if @enum.keys.include?(value)
return value.to_s + ' (' + @enum[value].to_s + ')'
@ -201,18 +233,6 @@ module Scruby
@format = 'A' + size.to_s
end
def to_net(value)
return value.to_s
end
def to_human(value)
return value.to_s.inspect
end
def to_human_complete(value)
return value.to_s.inspect
end
end
# Field for a set of bits
@ -235,6 +255,7 @@ module Scruby
def dissect(layer, string)
@@bitsdone ||= 0
# Cannot dissect if the wanted size is greater than the length of the string
# e.g. "IP('A'*7)" should not set frag=65
return '' if (@@bitsdone + @size)/8 > string.length
@ -276,6 +297,9 @@ module Scruby
end
def to_net(value)
@@bitsdone ||= 0
# OR'ing this value the value the previous ones
@@byte <<= @size
@@byte |= value
@ -326,7 +350,7 @@ module Scruby
# Same as ByteEnumField, displayed in hexadecimal form
class XByteEnumField<ByteEnumField
include FieldHumanHex
include FieldHumanHexEnum
end
# Field for one short (big endian/network order)
@ -350,7 +374,7 @@ module Scruby
# Same as ShortEnumField, displayed in hexadecimal form
class XShortEnumField<ShortEnumField
include FieldHumanHex
include FieldHumanHexEnum
end
# Field for a short (little endian order)
@ -374,7 +398,7 @@ module Scruby
# Same as LEShortField, displayed in hexadecimal form
class XLEShortEnumField<LEShortEnumField
include FieldHumanHex
include FieldHumanHexEnum
end
# Field for one integer
@ -406,7 +430,7 @@ module Scruby
# Same as LEIntField, displayed in hexadecimal form
class XIntEnumField<IntEnumField
include FieldHumanHex
include FieldHumanHexEnum
end
# Field for one integer with enumeration
@ -446,7 +470,7 @@ module Scruby
# Same as LEIntField, displayed in hexadecimal form
class XLEIntEnumField<LEIntEnumField
include FieldHumanHex
include FieldHumanHexEnum
end
# Field for one integer (host order)
@ -472,7 +496,7 @@ module Scruby
# Same as HostOrderIntEnumField, displayed in hexadecimal form
class XHostOrderIntEnumField<HostOrderIntEnumField
include FieldHumanHex
include FieldHumanHexEnum
end
# Field for a float (big endian/network order)
@ -630,7 +654,7 @@ module Scruby
# Checking if the value is in the enumeration keys
if @enum.keys.include?(value)
return value.to_s + ' (' + @enum[value].to_s + ')'
# Otherwise, just returning the value
# Otherwise, just returning the value
else
return value.to_s
end
@ -649,6 +673,203 @@ module Scruby
end
# Field for a set of flags (e.g. each bit has a label)
class FlagsField<BitField
def initialize(name, default_value, size, flags)
@name = name
@default_value = default_value
@format = 'B'
@flags = flags
# Number of bits in the field
@size = size
# Number of bits processed so far within the current byte (class/static variable)
@@bitsdone = 0
# Byte being processed (class/static variable)
@@byte = 0
end
def from_human(value)
return value if not value.is_a?(String)
# Run through the flags and set the corresponding bit if it matches
out = 0
@flags.length.times do |index|
out |= 2**index if value.include?(@flags[index])
end
return out
end
def to_human_complete(value)
loops = 0
out = ''
begin
bit = value & (2**loops)
out = @flags[loops] + ' ' + out if bit != 0
loops += 1
end until loops == @size
# Removing the last space
out = out[0, out.length - 1] if out.length > 0
return value.to_s + ' (' + out + ')'
end
end
# Field for one long (big endian/network order)
class LongField<Field
def init
@format = 'Q'
end
end
# Same as LongField, displayed in hexadecimal form
class XLongField<LongField
include FieldHumanHex
end
# Field for one long (big endian/network order) with enumeration
class LongEnumField<EnumField
def init
@format = 'n'
end
end
# Same as LongEnumField, displayed in hexadecimal form
class XLongEnumField<LongEnumField
include FieldHumanHexEnum
end
# Field that holds the length of a subsequent field
class FieldLenField<IntField
def initialize(name, default_value, length_of, format, opts={})
@name = name
@default_value = default_value
@format = format
@length_of = length_of
@opts = opts
# Length of the other field (class/static variable)
@@length = {}
# Saving the size of the associated field
@@length[@length_of] = @default_value
end
def from_net(value)
@opts ||= {}
value[0] = (value[0].to_i + @opts[:adjust].to_i)
# Saving the size of the associated field
@@length[@length_of] = value[0]
end
def to_net(value)
@opts ||= {}
# value -= @opts[:adjust].to_i
[ value ].pack(@format)
end
end
# Field holding a string whose size is given by a previous FieldLenField
# NB : in Scapy, the third field is a lambda-function indicating how to compute the value.
# This is not implemented in Scruby yet.
class StrLenField<FieldLenField
def initialize(name, default_value, length_from)
@name = name
@default_value = default_value
@length_from = length_from
@size = @@length[name]
@format = 'a' + @size.to_s
end
def pre_build
@size = @@length[@name]
@format = 'a' + @size.to_s
end
def to_net(value)
@size = @@length[@name]
@format = 'a' + @size.to_s
# By default, value is ''
if value
return value[0, @size].to_s
else
return ''
end
end
def from_net(value)
value[0]
end
def to_human(value)
return value.inspect
end
def to_human_complete(value)
return value.inspect
end
end
# NB for Dot11* fields:
# These functions have different 'is_applicable?' methods, to build different
# kinds of packets with the same dissector, depending on its type.
# http://trac.secdev.org/scapy/ticket/4 (second point)
# http://sss-mag.com/pdf/802_11tut.pdf
# Field for a 802.11 address field
class Dot11AddrMACField<MACField
end
# Field for a 802.11 address field #2
class Dot11Addr2MACField<MACField
def is_applicable?(layer)
if layer.type == DOT11TYPE_CONTROL
should = [DOT11SUBTYPE_PS_POLL, DOT11SUBTYPE_RTS, DOT11SUBTYPE_CF_END, DOT11SUBTYPE_CF_END_CF_ACK]
return should.include?(layer.subtype)
else
return true
end
end
end
# Field for a 802.11 address field #3
class Dot11Addr3MACField<MACField
def is_applicable?(layer)
return true if layer.type == DOT11TYPE_MANAGEMENT or layer.type == DOT11TYPE_DATA
return false
end
end
# Field for a 802.11 address field #4
class Dot11Addr4MACField<MACField
def is_applicable?(layer)
return true if layer.type == DOT11TYPE_DATA and layer.FCfield & 0x3 == 0x3
return false
end
end
# Field for a 802.11 SC field
class Dot11SCField<LEShortField
def is_applicable?(layer)
return layer.type != DOT11TYPE_CONTROL
end
end
# Grep out our field list here
self.constants.grep(/^([a-zA-Z0-9]+)Field$/).each do |f|
@ -685,7 +906,6 @@ Scapy (1.2.0.1) fields that Scruby is missing:
==============================================
ARPSourceMACField
BCDFloatField
BitEnumField
BitFieldLenField
CharEnumField
DHCPOptionsField
@ -694,21 +914,13 @@ Scapy (1.2.0.1) fields that Scruby is missing:
DNSRRField
DNSStrField
DestMACField
Dot11Addr2MACField
Dot11Addr3MACField
Dot11Addr4MACField
Dot11AddrMACField
Dot11SCField
FieldLenField
FieldListField
FlagsField
IPoptionsField
ISAKMPTransformSetField
LEFieldLenField
LELongField
LESignedIntField
LenField
LongField
NetBIOSNameField
PacketField
PacketLenField
@ -720,7 +932,6 @@ Scapy (1.2.0.1) fields that Scruby is missing:
SignedIntField
SourceIPField
SourceMACField
StrLenField
StrNullField
StrStopField
TCPOptionsField

View File

@ -17,9 +17,9 @@ def help(command = nil)
if command.nil?
print <<EOF
This is Scruby, a portable, customizable packet creation and sending/sniffing tool written in Ruby. It was tested on NetBSD and GNU/Linux, and should theoretically work on some other platforms such as FreeBSD, OpenBSD, Mac OS X and proprietary Unixes.
This is Scruby, a portable, customizable packet creation and sending/sniffing tool written in Ruby. It was tested on NetBSD, GNU/Linux and MacOS X, and should theoretically work on some other platforms such as FreeBSD, OpenBSD and proprietary Unixes.
See http://sylvainsarmejeanne.free.fr/projects/scruby for more information.
See http://sylv1.tuxfamily.org/projects/scruby.html for more information.
With Scruby, you can:
- create custom packet: p=IP(:src=>"1.2.3.4", :dst=>"www.google.com")/TCP()/"GET / HTTP 1.0\\r\\n\\r\\n"
@ -29,10 +29,10 @@ With Scruby, you can:
- dissect a string to a recreate the packet: s=p.to_net;puts "string=\#{s.inspect}\\nresult=\#{IP(s)}"
Available dissectors (type "ls 'MyDissector'" to have detailed information):
#{DISSECTORS_LIST_S.inspect}
#{Scruby.dissectors.keys.sort.join(", ")}
Available functions (type "lsc 'myfunction'" to have detailed information):
#{FUNCTIONS_LIST.inspect}
#{(Scruby.methods - Object.methods).sort.join(", ")}
EOF
else
# Executing the specific help function

View File

@ -67,7 +67,7 @@ class Layer
# e.g. for ['type', ETHERTYPE_IPv4, IP], if the field "type"
# in the current Ethernet layer is 0x800, then the upper layer
# is (may be) IP.
if self.instance_variable_get("@#{triplet[0]}") == triplet[1]
if triplet[0] == BIND_ALWAYS or self.instance_variable_get("@#{triplet[0]}") == triplet[1]
# Adding this possibility
@guesses.push(triplet[2])
break
@ -104,6 +104,11 @@ class Layer
return Packet./(self, upper)
end
# To use 'MyField(foo, bar)' in dissectors, instead of Scruby.MyField(foo, bar)'
def method_missing(method, *args)
return Scruby.field(method, *args)
end
# Converts an object to a string
def to_s
@ -144,7 +149,9 @@ class Layer
out = ''
@fields_desc.each do |field|
out += field.to_net(self.instance_variable_get("@#{field.name}"))
if field.is_applicable?(self)
out += field.to_net(self.instance_variable_get("@#{field.name}"))
end
end
return out
@ -159,8 +166,10 @@ class Layer
def dissect(string)
@fields_desc.each do |field|
string = field.dissect(self, string)
return "" if string.nil?
if field.is_applicable?(self)
string = field.dissect(self, string)
end
return '' if string.nil?
end
return string

View File

@ -16,6 +16,7 @@ def test(is, should)
eval("module Scruby;require 'scruby';$r = #{is}.to_s == '#{should}';end;")
if not $r
puts "\n## test #{$test_nb} FALSE##"
puts is.to_s
else
print "."
end
@ -30,39 +31,75 @@ $test_nb = 1
puts "BEGIN"
# Constructor arguments
test("IP(nil)", "<IP |>") #1
test("IP(nil)", "<IP |>")
test("IP('')", "<IP |>")
test("IP(:foobar)", "<IP |>")
test("IP(Hash.new)", "<IP |>")
test("IP(Array.new)", "<IP |>")
# All dissectors
test("Ether()", "<Ether |>") #6
test("Ether()", "<Ether |>")
test("ARP()", "<ARP |>")
test("IP()", "<IP |>")
test("TCP()", "<TCP |>")
test("UDP()", "<UDP |>")
test("ICMP()", "<ICMP |>")
test("Raw()", "<Raw |>")
test("TCP()", "<TCP |>")
test("UDP()", "<UDP |>")
test("ClassicBSDLoopback()", "<ClassicBSDLoopback |>")
test("OpenBSDLoopback()", "<OpenBSDLoopback |>")
test("RIFF()", "<RIFF |>")
test("ANI()", "<ANI |>")
test("Dot11()", "<Dot11 |>")
test("Dot11QoS()", "<Dot11QoS |>")
test("Dot11Beacon()", "<Dot11Beacon |>")
test("Dot11Elt()", "<Dot11Elt |>")
test("Dot11ATIM()", "<Dot11ATIM |>")
test("Dot11Disas()", "<Dot11Disas |>")
test("Dot11AssoReq()", "<Dot11AssoReq |>")
test("Dot11AssoResp()", "<Dot11AssoResp |>")
test("Dot11ReassoReq()", "<Dot11ReassoReq |>")
test("Dot11ReassoResp()", "<Dot11ReassoResp |>")
test("Dot11ProbeReq()", "<Dot11ProbeReq |>")
test("Dot11ProbeResp()", "<Dot11ProbeResp |>")
test("Dot11Auth()", "<Dot11Auth |>")
test("Dot11Deauth()", "<Dot11Deauth |>")
test("Dot11WEP()", "<Dot11WEP |>")
test("LLC()", "<LLC |>")
# All dissectors with arguments
test("Ether(:dst=>'11:11:11:11:11:11', :src=>'22:22:22:22:22:22', :type=>666)", "<Ether dst=11:11:11:11:11:11 src=22:22:22:22:22:22 type=0x29a |>") #14
test("IP(:version=>3, :ihl=>4, :tos=>101, :len=>102, :id=>103, :flags=>2, :frag=>104, :ttl=>105, :proto=>106, :chksum=>107, :src=>'10.0.0.1', :dst=>'10.0.0.2')", "<IP version=3 ihl=4 tos=0x65 len=102 id=0x67 flags=2 frag=104 ttl=105 proto=106 chksum=0x6b src=\"10.0.0.1\" dst=\"10.0.0.2\" |>")
test("TCP(:sport=>100, :dport=>101, :seq=>102, :ack=>103, :dataofs=>109, :reserved=>104, :flags=>105, :window=>106, :chksum=>107, :urgptr=>108)", "<TCP sport=100 dport=101 seq=102 ack=103 dataofs=109 reserved=104 flags=0x69 window=106 chksum=0x6b urgptr=108 |>")
test("Ether(:dst=>'11:11:11:11:11:11', :src=>'22:22:22:22:22:22', :type=>666)", "<Ether dst=11:11:11:11:11:11 src=22:22:22:22:22:22 type=0x29a |>")
test("ARP(:hwtype=>'FrameRelay', :ptype=>3, :hwlen=>1, :plen=>'IPv6', :op=>2, :hwsrc=>'11:22:33:44:55:66', :psrc=>'192.168.0.1', :hwdst=>'66:55:44:33:22:11', :pdst=>'192.168.0.2')", "<ARP hwtype=0xf ptype=0x3 hwlen=1 plen=16 op=2 hwsrc=11:22:33:44:55:66 psrc=\"192.168.0.1\" hwdst=66:55:44:33:22:11 pdst=\"192.168.0.2\" |>")
test("IP(:version=>3, :ihl=>4, :tos=>101, :len=>102, :id=>103, :flags=>'DF', :frag=>104, :ttl=>105, :proto=>106, :chksum=>107, :src=>'10.0.0.1', :dst=>'10.0.0.2')", "<IP version=3 ihl=4 tos=0x65 len=102 id=0x67 flags=2 frag=104 ttl=105 proto=106 chksum=0x6b src=\"10.0.0.1\" dst=\"10.0.0.2\" |>")
test("TCP(:sport=>100, :dport=>101, :seq=>102, :ack=>103, :dataofs=>109, :reserved=>104, :flags=>'SYN ACK', :window=>106, :chksum=>107, :urgptr=>108)", "<TCP sport=100 dport=101 seq=102 ack=103 dataofs=109 reserved=104 flags=18 window=106 chksum=0x6b urgptr=108 |>")
test("UDP(:sport=>100, :dport=>101, :len=>102, :chksum=>103)", "<UDP sport=100 dport=101 len=102 chksum=0x67 |>")
test("ICMP(:type=>100, :code=>101, :chksum=>102, :id=>103, :seq=>104)", "<ICMP type=100 code=101 chksum=0x66 id=0x67 seq=0x68 |>")
test("Raw(:load=>'foobar')", "<Raw load=\"foobar\" |>")
test("ClassicBSDLoopback(:header=>100)", "<ClassicBSDLoopback header=100 |>")
test("OpenBSDLoopback(:header=>100)", "<OpenBSDLoopback header=100 |>")
test("RIFF(:id=>'FOOB', :size=>66, :headerid=>'BARZ')", "<RIFF id=\"FOOB\" size=66 headerid=\"BARZ\" |>")
test("ANI(:id=>'foob', :size=>12, :headersize=>21, :frames=>3, :steps=>1, :width=>2, :height=>3, :bitcount=>4, :planes=>5, :displayrate=>6, :icon=>1, :sequence=>1, :reserved=>1)", "<ANI id=\"foob\" size=12 headersize=21 frames=3 steps=1 width=2 height=3 bitcount=4 planes=5 displayrate=6 icon=1 sequence=1 reserved=1 |>")
test("Dot11(:subtype=>1, :type=>1, :proto=>1, :FCfield=>1, :ID=>1, :addr1=>'11:11:11:11:11:11', :addr2=>'22:22:22:22:22:22', :addr3=>'33:33:33:33:33:33')", "<Dot11 subtype=1 type=1 proto=1 FCfield=1 ID=1 addr1=11:11:11:11:11:11 addr2=22:22:22:22:22:22 addr3=33:33:33:33:33:33 |>")
test("Dot11Elt(:ID=>1, :len=>2, :info=>'ab')", "<Dot11Elt ID=1 len=2 info=\"ab\" |>")
test("LLC(:dsap=>1, :ssap=>1, :ctrl=>1)", "<LLC dsap=0x1 ssap=0x1 ctrl=1 |>")
# Fields for Ether
test("Ether().dst", "00:00:00:00:00:00") #22
test("Ether().dst", "00:00:00:00:00:00")
test("Ether().src", "00:00:00:00:00:00")
test("Ether().type", "2048")
# Fields for ARP
test("ARP().hwtype", "1")
test("ARP().ptype", "2048")
test("ARP().hwlen", "6")
test("ARP().plen", "4")
test("ARP().op", "1")
test("ARP().hwsrc", "00:00:00:00:00:00")
test("ARP().psrc", "127.0.0.1")
test("ARP().hwdst", "00:00:00:00:00:00")
test("ARP().pdst", "127.0.0.1")
# Fields for IP
test("IP().version", "4") #25
test("IP().version", "4")
test("IP().ihl", "5")
test("IP().tos", "0")
test("IP().len", "20")
@ -76,7 +113,7 @@ test("IP().src", "127.0.0.1")
test("IP().dst", "127.0.0.1")
# Fields for TCP
test("TCP().sport", "1024") #37
test("TCP().sport", "1024")
test("TCP().dport", "80")
test("TCP().seq", "0")
test("TCP().ack", "0")
@ -88,20 +125,20 @@ test("TCP().chksum", "0")
test("TCP().urgptr", "0")
# Fields for UDP
test("UDP().sport", "53") #47
test("UDP().sport", "53")
test("UDP().dport", "53")
test("UDP().len", "8")
test("UDP().chksum", "0")
# Fields for ICMP
test("ICMP().type", "8") #51
test("ICMP().type", "8")
test("ICMP().code", "0")
test("ICMP().chksum", "0")
test("ICMP().id", "0")
test("ICMP().seq", "0")
# Fields for Raw
test("Raw().load", "") #56
test("Raw().load", "")
# Fields for ClassicBSDLoopback
test("ClassicBSDLoopback().header", "2")
@ -109,14 +146,56 @@ test("ClassicBSDLoopback().header", "2")
# Fields for OpenBSDLoopback
test("OpenBSDLoopback().header", "2")
# Dissecting a string
test("Raw('foobar')", "<Raw load=\"foobar\" |>")
# Fields for RIFF
test("RIFF().id", "RIFF")
test("RIFF().size", "0")
test("RIFF().headerid", "ACON")
# Ether packet #60
# Fields for ANI
test("ANI().id", "anih")
test("ANI().size", "36")
test("ANI().headersize", "36")
test("ANI().frames", "2")
test("ANI().steps", "0")
test("ANI().width", "0")
test("ANI().height", "0")
test("ANI().bitcount", "0")
test("ANI().planes", "0")
test("ANI().displayrate", "0")
test("ANI().icon", "0")
test("ANI().sequence", "0")
test("ANI().reserved", "0")
# Fields for Dot11
test("Dot11().subtype", "0")
test("Dot11().type", "2")
test("Dot11().proto", "0")
test("Dot11().FCfield", "0")
test("Dot11().ID", "0")
test("Dot11().addr1", "00:00:00:00:00:00")
test("Dot11().addr2", "00:00:00:00:00:00")
test("Dot11().addr3", "00:00:00:00:00:00")
test("Dot11().SC", "0")
test("Dot11().addr4", "00:00:00:00:00:00")
# Fields for Dot11Elt
test("Dot11Elt().ID", "0")
test("Dot11Elt().len", "0")
test("Dot11Elt().info", "")
# Fields for LLC
test("LLC().dsap", "0")
test("LLC().ssap", "0")
test("LLC().ctrl", "0")
# Ether packet
test("Ether(:src=>'ba:98:76:54:32:10', :type=>123).to_net.inspect", "\000\000\000\000\000\000\272\230vT2\020\000{".inspect)
test("Ether(:dst=>'01:23:45:67:89:ab', :src=>'ba:98:76:54:32:10', :type=>123).to_net.inspect", "\001#Eg\211\253\272\230vT2\020\000{".inspect)
# IP packet #62
# ARP packet
test("(Ether(:type=>'ARP')/ARP(:hwtype=>'Ethernet', :ptype=>0x800, :hwlen=>6, :plen=>'IPv4', :op=>2, :hwsrc=>'11:22:33:44:55:66', :psrc=>'192.168.0.1', :hwdst=>'66:55:44:33:22:11', :pdst=>'192.168.0.2')).to_net.inspect", "\000\000\000\000\000\000\000\000\000\000\000\000\b\006\000\001\b\000\006\004\000\002\021\"3DUf\300\250\000\001fUD3\"\021\300\250\000\002".inspect)
# IP packet
test("(IP(:version=>4, :ihl=>5, :tos=>13, :id=>103, :flags=>2, :frag=>104, :ttl=>105, :proto=>106, :src=>'1.2.3.4', :dst=>'4.3.2.1')/Raw(:load=>\"foobar\")).to_net.inspect", "E\r\000\032\000g@hij\006\225\001\002\003\004\004\003\002\001foobar".inspect)
# TCP packet
@ -128,14 +207,32 @@ test("(IP(:proto=>17)/UDP(:sport=>100, :dport=>101)/Raw(:load=>\"foobar\")).to_n
# ICMP packet
test("(IP(:proto=>1)/ICMP(:type=>0, :code=>101, :id=>103, :seq=>104)).to_net.inspect", "E\000\000\034\000\000\000\000@\001|\337\177\000\000\001\177\000\000\001\000e\376\313\000g\000h".inspect)
# Dissecting Ether #66
# RIFF packet
test("RIFF(:id=>'FOOB', :size=>67, :headerid=>'BARZ').to_net.inspect", "FOOBC\000\000\000BARZ".inspect)
# ANI packet
test("ANI(:id=>'foob', :size=>12, :headersize=>21, :frames=>3, :steps=>1, :width=>2, :height=>3, :bitcount=>4, :planes=>5, :displayrate=>6, :icon=>1, :sequence=>1, :reserved=>1).to_net.inspect", "foob\f\000\000\000\025\000\000\000\003\000\000\000\001\000\000\000\002\000\000\000\003\000\000\000\004\000\000\000\005\000\000\000\006\000\000\000\300\000\000\001".inspect)
# Dot11 packet
test("Dot11(:subtype=>1, :type=>1, :proto=>1, :FCfield=>1, :ID=>1, :addr1=>'11:11:11:11:11:11', :addr2=>'22:22:22:22:22:22', :addr3=>'33:33:33:33:33:33').to_net.inspect", "\025\001\000\001\021\021\021\021\021\021".inspect)
# Dot11Elt packet
test("Dot11Elt(:ID=>1, :len=>2, :info=>'ab').to_net.inspect", "\001\002ab".inspect)
# LLC
test("LLC(:dsap=>1, :ssap=>1, :ctrl=>1).to_net.inspect", "\001\001\001".inspect)
# Dissecting Ether
test("Ether(\"\001#Eg\211\253\272\230vT2\020\000{\")", "<Ether dst=01:23:45:67:89:ab src=ba:98:76:54:32:10 type=0x7b |>")
# Dissecting ARP
test('ARP("\000\001\b\000\006\004\000\002\021\"3DUf\300\250\000\001fUD3\"\021\300\250\000\002")', "<ARP op=2 hwsrc=11:22:33:44:55:66 psrc=\"192.168.0.1\" hwdst=66:55:44:33:22:11 pdst=\"192.168.0.2\" |>")
# Dissecting IP
test("IP(\"E\r\000\032\000g@hij\006\225\001\002\003\004\004\003\002\001foobar\")", "<IP tos=0xd len=26 id=0x67 flags=2 frag=104 ttl=105 proto=106 chksum=0x695 src=\"1.2.3.4\" dst=\"4.3.2.1\" |><Raw load=\"foobar\" |>")
# Dissecting TCP
test("TCP(\"\000d\000e\000\000\000f\000\000\000gS\003\000j\254s\000l\")", "<TCP sport=100 dport=101 seq=102 ack=103 reserved=3 flags=0x3 window=106 chksum=0xac73 urgptr=108 |>")
test("TCP(\"\000d\000e\000\000\000f\000\000\000gS\003\000j\254s\000l\")", "<TCP sport=100 dport=101 seq=102 ack=103 reserved=3 flags=3 window=106 chksum=0xac73 urgptr=108 |>")
# Dissecting UDP
test("UDP(\"\000d\000e\000\016\311\302foobar\")", "<UDP sport=100 dport=101 len=14 chksum=0xc9c2 |><Raw load=\"foobar\" |>")
@ -143,7 +240,28 @@ test("UDP(\"\000d\000e\000\016\311\302foobar\")", "<UDP sport=100 dport=101 len=
# Dissecting ICMP
test("ICMP(\"\000e\376\313\000g\000h\")", "<ICMP type=0 code=101 chksum=0xfecb id=0x67 seq=0x68 |>")
# Operations on layers # 71
# Dissecting a string
test("Raw('foobar')", "<Raw load=\"foobar\" |>")
# Dissecting RIFF
test('RIFF("FOOBC\000\000\000BARZ")', "<RIFF id=\"FOOB\" size=67 headerid=\"BARZ\" |>")
# Dissecting ANI
test('ANI("foob\f\000\000\000\025\000\000\000\003\000\000\000\001\000\000\000\002\000\000\000\003\000\000\000\004\000\000\000\005\000\000\000\006\000\000\000\300\000\000\001")', "<ANI id=\"foob\" size=12 headersize=21 frames=3 steps=1 width=2 height=3 bitcount=4 planes=5 displayrate=6 icon=1 sequence=1 reserved=1 |>")
# Dissecting Dot11
test('Dot11("\025\001\000\001\021\021\021\021\021\021")', "<Dot11 subtype=1 type=1 proto=1 FCfield=1 ID=1 addr1=11:11:11:11:11:11 |>")
# Dissecting Dot11Elt
test('Dot11Elt("\001\002ab")', "<Dot11Elt ID=1 len=2 info=\"ab\" |>")
# Dissecting a real Dot11 string
test('Dot11("\x80\x00\x00\x00\xff\xff\xff\xff\xff\xff\x00\x19}\x01Y\xc4\x00\x19}\x01Y\xc4\xf0\x1e\x8bA\x9f\t)\x0c\x00\x00d\x00\x11\x04\x00\x0cLivebox-6708\x01\x08\x82\x84\x8b\x96$0Hl\x03\x01\x01\x05\x04\x00\x03\x00\x00*\x01\x00/\x01\x002\x04\x0c\x12\x18`\xdd\x16\x00P\x02\x01\x01\x00\x00P\x02\x02\x01\x00\x00P\x02\x02\x01\x00\x00P\x02\x02\xdd\x18\x00P\x02\x02")', "<Dot11 subtype=8 type=0 addr1=ff:ff:ff:ff:ff:ff addr2=00:19:7d:01:59:c4 addr3=00:19:7d:01:59:c4 SC=7920 |><Dot11Beacon timestamp=13370394624395 cap=4356 |><Dot11Elt len=12 info=\"Livebox-6708\" |><Dot11Elt ID=1 len=8 info=\"\\202\\204\\213\\226$0Hl\" |><Dot11Elt ID=3 len=1 info=\"\\001\" |><Dot11Elt ID=5 len=4 info=\"\\000\\003\\000\\000\" |><Dot11Elt ID=42 len=1 info=\"\\000\" |><Dot11Elt ID=47 len=1 info=\"\\000\" |><Dot11Elt ID=50 len=4 info=\"\\f\\022\\030`\" |><Dot11Elt ID=221 len=22 info=\"\\000P\\002\\001\\001\\000\\000P\\002\\002\\001\\000\\000P\\002\\002\\001\\000\\000P\\002\\002\" |><Dot11Elt ID=221 len=24 info=\"\\000P\\002\\002\" |>")
# Dissecting LLC
test('LLC("\001\001\001")', "<LLC dsap=0x1 ssap=0x1 ctrl=1 |>")
# Operations on layers
$p=Ether()/"E\000\000.\000\000\000\000@\006|\310\177\000\000\001\177\000\000\001\004\000\000P\000\000\000\000\000\000\000\000P\002 \000VF\000\000foobar"
$p.decode_payload_as(IP)
@ -154,11 +272,11 @@ test("$p.last_layer", "<Raw load=\"foobar\" |>")
test("$p.get_layer(TCP)", "<TCP chksum=0x5646 |><Raw load=\"foobar\" |>")
# Dissecting a string byte after byte
test("IP('A')", "<IP ihl=1 |>") # 76
test("IP('A')", "<IP ihl=1 |>")
test("IP('A'*2)", "<IP ihl=1 tos=0x41 |>")
test("IP('A'*3)", "<IP ihl=1 tos=0x41 |>")
test("IP('A'*4)", "<IP ihl=1 tos=0x41 len=16705 |>")
test("IP('A'*5)", "<IP ihl=1 tos=0x41 len=16705 |>") # 80
test("IP('A'*5)", "<IP ihl=1 tos=0x41 len=16705 |>")
test("IP('A'*6)", "<IP ihl=1 tos=0x41 len=16705 id=0x4141 |>")
test("IP('A'*7)", "<IP ihl=1 tos=0x41 len=16705 id=0x4141 flags=2 |>")
test("IP('A'*8)", "<IP ihl=1 tos=0x41 len=16705 id=0x4141 flags=2 frag=321 |>")
@ -168,7 +286,7 @@ test("IP('A'*11)", "<IP ihl=1 tos=0x41 len=16705 id=0x4141 flags=2 frag=321 ttl=
test("IP('A'*12)", "<IP ihl=1 tos=0x41 len=16705 id=0x4141 flags=2 frag=321 ttl=65 proto=65 chksum=0x4141 |>")
test("IP('A'*13)", "<IP ihl=1 tos=0x41 len=16705 id=0x4141 flags=2 frag=321 ttl=65 proto=65 chksum=0x4141 |>")
test("IP('A'*14)", "<IP ihl=1 tos=0x41 len=16705 id=0x4141 flags=2 frag=321 ttl=65 proto=65 chksum=0x4141 |>")
test("IP('A'*15)", "<IP ihl=1 tos=0x41 len=16705 id=0x4141 flags=2 frag=321 ttl=65 proto=65 chksum=0x4141 |>") # 90
test("IP('A'*15)", "<IP ihl=1 tos=0x41 len=16705 id=0x4141 flags=2 frag=321 ttl=65 proto=65 chksum=0x4141 |>")
test("IP('A'*16)", "<IP ihl=1 tos=0x41 len=16705 id=0x4141 flags=2 frag=321 ttl=65 proto=65 chksum=0x4141 src=\"65.65.65.65\" |>")
test("IP('A'*17)", "<IP ihl=1 tos=0x41 len=16705 id=0x4141 flags=2 frag=321 ttl=65 proto=65 chksum=0x4141 src=\"65.65.65.65\" |>")
test("IP('A'*18)", "<IP ihl=1 tos=0x41 len=16705 id=0x4141 flags=2 frag=321 ttl=65 proto=65 chksum=0x4141 src=\"65.65.65.65\" |>")