diff --git a/scapy/fields.py b/scapy/fields.py index f3022a09617..b51635760f0 100644 --- a/scapy/fields.py +++ b/scapy/fields.py @@ -2152,27 +2152,54 @@ class FlagsField(BitField): Make sure all your flags have a label - Example: + Example (list): >>> from scapy.packet import Packet >>> class FlagsTest(Packet): fields_desc = [FlagsField("flags", 0, 8, ["f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7"])] # noqa: E501 >>> FlagsTest(flags=9).show2() ###[ FlagsTest ]### flags = f0+f3 - >>> FlagsTest(flags=0).show2().strip() + + Example (str): + >>> from scapy.packet import Packet + >>> class TCPTest(Packet): + fields_desc = [ + BitField("reserved", 0, 7), + FlagsField("flags", 0x2, 9, "FSRPAUECN") + ] + >>> TCPTest(flags=3).show2() ###[ FlagsTest ]### - flags = + reserved = 0 + flags = FS + + Example (dict): + >>> from scapy.packet import Packet + >>> class FlagsTest2(Packet): + fields_desc = [ + FlagsField("flags", 0x2, 16, { + 1: "1", # 1st bit + 8: "2" # 8th bit + }) + ] :param name: field's name :param default: default value for the field :param size: number of bits in the field (in bits) - :param names: (list or dict) label for each flag, Least Significant Bit tag's name is written first # noqa: E501 + :param names: (list or str or dict) label for each flag + If it's a str or a list, the least Significant Bit tag's name + is written first. """ ismutable = True - __slots__ = ["multi", "names"] + __slots__ = ["names"] def __init__(self, name, default, size, names): - self.multi = isinstance(names, list) + # Convert the dict to a list + if isinstance(names, dict): + tmp = ["bit_%d" % i for i in range(size)] + for i, v in six.viewitems(names): + tmp[i] = v + names = tmp + # Store the names as str or list self.names = names BitField.__init__(self, name, default, size) diff --git a/scapy/layers/smb2.py b/scapy/layers/smb2.py index 4e5596969c2..d8308b53721 100644 --- a/scapy/layers/smb2.py +++ b/scapy/layers/smb2.py @@ -8,12 +8,31 @@ """ from scapy.config import conf -from scapy.packet import Packet, bind_layers -from scapy.fields import StrFixedLenField, LEIntField, LEShortEnumField, \ - ShortEnumField, XLEIntField, LEShortField, FlagsField, LELongField, \ - XLELongField, XNBytesField, FieldLenField, IntField, FieldListField, \ - XStrLenField, ShortField, IntEnumField, StrFieldUtf16, XLEShortField, \ - UUIDField, XLongField, PacketListField, PadField +from scapy.packet import Packet, bind_layers, bind_top_down +from scapy.fields import ( + FieldLenField, + FieldListField, + FlagsField, + IntEnumField, + IntField, + LEIntField, + LELongField, + LEShortEnumField, + LEShortField, + PacketListField, + PadField, + ShortEnumField, + ShortField, + StrFieldUtf16, + StrFixedLenField, + UUIDField, + XLEIntField, + XLELongField, + XLEShortField, + XLongField, + XNBytesField, + XStrLenField, +) # EnumField @@ -35,13 +54,13 @@ # FlagField SMB2_CAPABILITIES = { - 30: "CapabilitiesEncryption", - 29: "CapabilitiesDirectoryLeasing", - 28: "CapabilitiesPersistentHandles", - 27: "CapabilitiesMultiChannel", - 26: "CapabilitiesLargeMTU", - 25: "CapabilitiesLeasing", - 24: "CapabilitiesDFS", + 30: "Encryption", + 29: "DirectoryLeasing", + 28: "PersistentHandles", + 27: "MultiChannel", + 26: "LargeMTU", + 25: "Leasing", + 24: "DFS", } # EnumField @@ -76,6 +95,13 @@ class SMB2_Header(Packet): XNBytesField("Signature", 0, 16), ] + def guess_payload_class(self, payload): + if self.Command == 0x0000: + if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR: + return SMB2_Negociate_Protocol_Response_Header + return SMB2_Negociate_Protocol_Request_Header + return super(SMB2_Header, self).guess_payload_class(payload) + class SMB2_Compression_Transform_Header(Packet): name = "SMB2 Compression Transform Header" @@ -270,17 +296,17 @@ class SMB2_Negociate_Protocol_Response_Header(Packet): bind_layers(SMB2_Encryption_Capabilities, conf.padding_layer) bind_layers(SMB2_Compression_Capabilities, conf.padding_layer) bind_layers(SMB2_Netname_Negociate_Context_ID, conf.padding_layer) -bind_layers( +bind_top_down( SMB2_Header, SMB2_Negociate_Protocol_Request_Header, Command=0x0000, - Flags=lambda f: (f >> 24) & 1 == 0 + Flags=0 ) -bind_layers( +bind_top_down( SMB2_Header, SMB2_Negociate_Protocol_Response_Header, Command=0x0000, - Flags=lambda f: (f >> 24) & 1 == 1 + Flags=2 ** 24 # SMB2_FLAGS_SERVER_TO_REDIR ) bind_layers( SMB2_Negociate_Context, diff --git a/scapy/packet.py b/scapy/packet.py index 9e90125565a..1231035032e 100644 --- a/scapy/packet.py +++ b/scapy/packet.py @@ -886,14 +886,8 @@ def guess_payload_class(self, payload): for t in self.aliastypes: for fval, cls in t.payload_guess: try: - for k, v in six.iteritems(fval): - # case where v is a function - if callable(v): - if not v(self.getfieldval(k)): - break - elif v != self.getfieldval(k): - break - else: + if all(v == self.getfieldval(k) + for k, v in six.iteritems(fval)): return cls except AttributeError: pass diff --git a/test/fields.uts b/test/fields.uts index c281fe58809..9a93eaa2f24 100644 --- a/test/fields.uts +++ b/test/fields.uts @@ -1487,6 +1487,35 @@ assert "f2" in flags assert "f4" in flags assert "f0" in flags += FlagsField with str + +class TCPTest(Packet): + fields_desc = [ + BitField("reserved", 0, 7), + FlagsField("flags", 0x2, 9, "FSRPAUECN") + ] + +a = TCPTest(flags=3) +assert a.flags.F +assert a.flags.S +assert a.sprintf("%flags%") == "FS" + += FlagsField with dict + +class FlagsTest2(Packet): + fields_desc = [ + FlagsField("flags", 0x2, 16, { + 0: "A", # 0 bit + 7: "B" # 7 bit + }) + ] + +a = FlagsTest2(flags=255) +a.sprintf("%flags%") +assert a.flags.A +assert a.flags.B +assert a.sprintf("%flags%") == "A+bit_1+bit_2+bit_3+bit_4+bit_5+bit_6+B" + ######## ######## diff --git a/test/smb2.uts b/test/smb2.uts index 11753841785..051fad6e05c 100644 --- a/test/smb2.uts +++ b/test/smb2.uts @@ -1,7 +1,3 @@ -############ -############ -~ SMB2 - + SMB2 Header = SMB2 Header dissecting @@ -59,15 +55,6 @@ assert pkt[NBTSession].TYPE == 0x00 # session message smb2 = pkt[SMB2_Header] assert smb2.Start == b'\xfeSMB' - - - - - - - - - + SMB2 Negociate Procotol Request Header dissecting = Common fields in header @@ -145,29 +132,12 @@ assert netname.ContextType == 0x5 assert netname.DataLength == 28 assert netname.NetName == '192.168.178.21' - - - - - - - - - -+ test SMB2 Negociate Protocol Request Header - assembling += test SMB2 Negociate Protocol Request Header - assembling pkt = IP() / TCP() / NBTSession() / SMB2_Header() / SMB2_Negociate_Protocol_Request_Header() +pkt = IP(raw(pkt)) assert SMB2_Negociate_Protocol_Request_Header in pkt - - - - - - - - - + SMB2 Negociate Protocol Response Header dissecting = Common fields in header @@ -229,16 +199,8 @@ assert comp.CompressionAlgorithmCount == 1 assert len(comp.CompressionAlgorithms) == 1 assert comp.CompressionAlgorithms[0] == 1 - - - - - - - - - -+ SMB2 Negociate Protocol Response Header assembling += SMB2 Negociate Protocol Response Header assembling pkt = IP() / TCP() / NBTSession() / SMB2_Header() / SMB2_Negociate_Protocol_Response_Header() +pkt = IP(raw(pkt)) assert SMB2_Negociate_Protocol_Response_Header in pkt