2929class CDP (dpkt .Packet ):
3030 """Cisco Discovery Protocol.
3131
32- See more about the BGP on \
32+ See more on
3333 https://en.wikipedia.org/wiki/Cisco_Discovery_Protocol
3434
3535 Attributes:
@@ -43,69 +43,106 @@ class CDP(dpkt.Packet):
4343 ('sum' , 'H' , 0 )
4444 )
4545
46- class Address (dpkt .Packet ):
47- # XXX - only handle NLPID/IP for now
48- __hdr__ = (
49- ('ptype' , 'B' , 1 ), # protocol type (NLPID)
50- ('plen' , 'B' , 1 ), # protocol length
51- ('p' , 'B' , 0xcc ), # IP
52- ('alen' , 'H' , 4 ) # address length
53- )
54-
55- def unpack (self , buf ):
56- dpkt .Packet .unpack (self , buf )
57- self .data = self .data [:self .alen ]
58-
5946 class TLV (dpkt .Packet ):
47+ """When constructing the packet, len is not mandatory:
48+ if not provided, then self.data must be this exact TLV payload"""
49+
6050 __hdr__ = (
6151 ('type' , 'H' , 0 ),
62- ('len' , 'H' , 4 )
52+ ('len' , 'H' , 0 )
6353 )
6454
55+ def data_len (self ):
56+ if self .len :
57+ return self .len - self .__hdr_len__
58+ return len (self .data )
59+
6560 def unpack (self , buf ):
6661 dpkt .Packet .unpack (self , buf )
67- self .data = self .data [:self .len - 4 ]
68- if self .type == CDP_ADDRESS :
69- n = struct .unpack ('>I' , self .data [:4 ])[0 ]
70- buf = self .data [4 :]
71- l = []
72- for i in range (n ):
73- a = CDP .Address (buf )
74- l .append (a )
75- buf = buf [len (a ):]
76- self .data = l
62+ self .data = self .data [:self .data_len ()]
7763
7864 def __len__ (self ):
79- if self .type == CDP_ADDRESS :
80- n = 4 + sum (map (len , self .data ))
81- else :
82- n = len (self .data )
83- return self .__hdr_len__ + n
65+ return self .__hdr_len__ + len (self .data )
8466
8567 def __bytes__ (self ):
86- self .len = len (self )
87- if self .type == CDP_ADDRESS :
88- s = struct .pack ('>I' , len (self .data )) + \
89- b'' .join (map (bytes , self .data ))
90- else :
91- s = self .data
92- return self .pack_hdr () + s
68+ if hasattr (self , 'len' ) and not self .len :
69+ self .len = len (self )
70+ return self .pack_hdr () + bytes (self .data )
71+
72+ class Address (TLV ):
73+ # XXX - only handle NLPID/IP for now
74+ __hdr__ = (
75+ ('ptype' , 'B' , 1 ), # protocol type (NLPID)
76+ ('plen' , 'B' , 1 ), # protocol length
77+ ('p' , 'B' , 0xcc ), # IP
78+ ('alen' , 'H' , 4 ) # address length
79+ )
80+ def data_len (self ):
81+ return self .alen
82+
83+ class TLV_Addresses (TLV ):
84+ __hdr__ = (
85+ ('type' , 'H' , CDP_ADDRESS ),
86+ ('len' , 'H' , 0 ), #17),
87+ ('Addresses' , 'L' , 1 ),
88+ )
9389
9490 def unpack (self , buf ):
9591 dpkt .Packet .unpack (self , buf )
9692 buf = self .data
9793 l = []
9894 while buf :
99- tlv = self .TLV (buf )
100- l .append (tlv )
95+ # find the right TLV according to Type value
96+ tlv_find_type = self .TLV (buf ).type
97+ # if this TLV is not in tlv_types, use the default TLV class
98+ tlv = self .tlv_types .get (tlv_find_type , self .TLV )(buf )
99+ l .append (bytes (tlv ))
101100 buf = buf [len (tlv ):]
102- self .data = l
101+ self .tlvs = l
102+ self .data = b'' .join (l )
103103
104104 def __len__ (self ):
105- return self .__hdr_len__ + sum ( map ( len , self .data ) )
105+ return self .__hdr_len__ + len ( self .data )
106106
107107 def __bytes__ (self ):
108- data = b'' . join ( map ( bytes , self .data ) )
108+ data = bytes ( self .data )
109109 if not self .sum :
110110 self .sum = dpkt .in_cksum (self .pack_hdr () + data )
111111 return self .pack_hdr () + data
112+
113+ # keep here the TLV classes whose header is different from the generic TLV header (example : TLV_Addresses)
114+ tlv_types = {CDP_ADDRESS : TLV_Addresses }
115+
116+
117+ def test_cdp ():
118+ import socket
119+ from . import ethernet
120+
121+ ss = (b'\x02 \xb4 \xdf \x93 \x00 \x01 \x00 \x09 \x63 \x69 \x73 \x63 \x6f \x00 \x02 \x00 \x11 \x00 \x00 \x00 \x01 \x01 \x01 \xcc \x00 \x04 \xc0 \xa8 \x01 \x67 ' )
122+ rr1 = CDP (ss )
123+ assert bytes (rr1 ) == ss
124+
125+ # construction
126+ ss = (b'\x02 \xb4 \xdf \x93 \x00 \x01 \x00 \x09 \x63 \x69 \x73 \x63 \x6f \x00 \x02 \x00 \x11 \x00 \x00 \x00 \x01 \x01 \x01 \xcc \x00 \x04 \xc0 \xa8 \x01 \x67 ' )
127+ p1 = CDP .TLV_Addresses (data = CDP .Address (data = socket .inet_aton ('192.168.1.103' )))
128+ p2 = CDP .TLV (type = CDP_DEVID , data = b'cisco' )
129+ data = p2 .pack () + p1 .pack ()
130+ rr2 = CDP (data = data )
131+ assert bytes (rr2 ) == ss
132+
133+ s = (b'\x01 \x00 \x0c \xcc \xcc \xcc \xc4 \x02 2k\x00 \x00 \x01 T\xaa \xaa \x03 \x00 \x00 \x0c \x00 \x02 \xb4 ,B'
134+ b'\x00 \x01 \x00 \x06 R2\x00 \x05 \x00 \xff Cisco IOS Software, 3700 Software (C3745-ADVENTERPRI'
135+ b'SEK9_SNA-M), Version 12.4(25d), RELEASE SOFTWARE (fc1)\n Technical Support: http://www.'
136+ b'cisco.com/techsupport\n Copyright (c) 1986-2010 by Cisco Systems, Inc.\n Compiled Wed 18'
137+ b'-Aug-10 08:18 by prod_rel_team\x00 \x06 \x00 \x0e Cisco 3745\x00 \x02 \x00 \x11 \x00 \x00 \x00 \x01 '
138+ b'\x01 \x01 \xcc \x00 \x04 \n \x00 \x00 \x02 \x00 \x03 \x00 \x13 FastEthernet0/0\x00 \x04 \x00 \x08 \x00 '
139+ b'\x00 \x00 )\x00 \t \x00 \x04 \x00 \x0b \x00 \x05 \x00 ' )
140+ eth = ethernet .Ethernet (s )
141+ assert isinstance (eth .data .data , CDP )
142+ assert len (eth .data .data .tlvs ) == 8 # number of CDP TLVs; ensures they are decoded
143+ assert str (eth ) == str (s )
144+ assert len (eth ) == len (s )
145+
146+ if __name__ == '__main__' :
147+ test_cdp ()
148+ print ('Tests Successful...' )
0 commit comments