6
6
# scapy.contrib.description = HSFZ - BMW High-Speed-Fahrzeug-Zugang
7
7
# scapy.contrib.status = loads
8
8
import logging
9
- import struct
10
9
import socket
10
+ import struct
11
11
import time
12
-
13
- from scapy .contrib .automotive import log_automotive
14
- from scapy .packet import Packet , bind_layers , bind_bottom_up
15
- from scapy .fields import IntField , ShortEnumField , XByteField
16
- from scapy .layers .inet import TCP
17
- from scapy .supersocket import StreamSocket
18
- from scapy .contrib .automotive .uds import UDS , UDS_TP
19
- from scapy .data import MTU
20
-
21
12
from typing import (
22
13
Any ,
23
14
Optional ,
28
19
Union ,
29
20
)
30
21
22
+ from scapy .contrib .automotive import log_automotive
23
+ from scapy .contrib .automotive .uds import UDS , UDS_TP
24
+ from scapy .data import MTU
25
+ from scapy .fields import (IntField , ShortEnumField , XByteField ,
26
+ ConditionalField , StrFixedLenField )
27
+ from scapy .layers .inet import TCP , UDP
28
+ from scapy .packet import Packet , bind_layers , bind_bottom_up
29
+ from scapy .supersocket import StreamSocket
31
30
32
31
"""
33
32
BMW HSFZ (High-Speed-Fahrzeug-Zugang / High-Speed-Car-Access).
34
33
BMW specific diagnostic over IP protocol implementation.
35
34
The physical interface for this connection is called ENET.
36
35
"""
37
36
37
+
38
38
# #########################HSFZ###################################
39
39
40
40
41
41
class HSFZ (Packet ):
42
+ control_words = {
43
+ 0x01 : "diagnostic_req_res" ,
44
+ 0x02 : "acknowledge_transfer" ,
45
+ 0x10 : "terminal15" ,
46
+ 0x11 : "vehicle_ident_data" ,
47
+ 0x12 : "alive_check" ,
48
+ 0x13 : "status_data_inquiry" ,
49
+ 0x40 : "incorrect_tester_address" ,
50
+ 0x41 : "incorrect_control_word" ,
51
+ 0x42 : "incorrect_format" ,
52
+ 0x43 : "incorrect_dest_address" ,
53
+ 0x44 : "message_too_large" ,
54
+ 0x45 : "diag_app_not_ready" ,
55
+ 0xFF : "out_of_memory"
56
+ }
42
57
name = 'HSFZ'
43
58
fields_desc = [
44
59
IntField ('length' , None ),
45
- ShortEnumField ('type' , 1 , {0x01 : "message" ,
46
- 0x02 : "echo" }),
47
- XByteField ('src' , 0 ),
48
- XByteField ('dst' , 0 ),
60
+ ShortEnumField ('control' , 1 , control_words ),
61
+ ConditionalField (
62
+ XByteField ('source' , 0 ), lambda p : p .control == 1 ),
63
+ ConditionalField (
64
+ XByteField ('target' , 0 ), lambda p : p .control == 1 ),
65
+ ConditionalField (
66
+ StrFixedLenField ("identification_string" ,
67
+ None , None , lambda p : p .length ),
68
+ lambda p : p .control == 0x11 )
49
69
]
50
70
51
71
def hashret (self ):
52
72
# type: () -> bytes
53
- hdr_hash = struct .pack ("B" , self .src ^ self .dst )
73
+ hdr_hash = struct .pack ("B" , self .source ^ self .target )
54
74
pay_hash = self .payload .hashret ()
55
75
return hdr_hash + pay_hash
56
76
@@ -71,6 +91,11 @@ def post_build(self, pkt, pay):
71
91
bind_bottom_up (TCP , HSFZ , sport = 6801 )
72
92
bind_bottom_up (TCP , HSFZ , dport = 6801 )
73
93
bind_layers (TCP , HSFZ , sport = 6801 , dport = 6801 )
94
+
95
+ bind_bottom_up (UDP , HSFZ , sport = 6811 )
96
+ bind_bottom_up (UDP , HSFZ , dport = 6811 )
97
+ bind_layers (UDP , HSFZ , sport = 6811 , dport = 6811 )
98
+
74
99
bind_layers (HSFZ , UDS )
75
100
76
101
@@ -111,11 +136,11 @@ def recv(self, x=MTU, **kwargs):
111
136
112
137
113
138
class UDS_HSFZSocket (HSFZSocket ):
114
- def __init__ (self , src , dst , ip = '127.0.0.1' , port = 6801 , basecls = UDS ):
139
+ def __init__ (self , source , target , ip = '127.0.0.1' , port = 6801 , basecls = UDS ):
115
140
# type: (int, int, str, int, Type[Packet]) -> None
116
141
super (UDS_HSFZSocket , self ).__init__ (ip , port )
117
- self .src = src
118
- self .dst = dst
142
+ self .source = source
143
+ self .target = target
119
144
self .basecls = HSFZ
120
145
self .outputcls = basecls
121
146
@@ -128,7 +153,7 @@ def send(self, x):
128
153
129
154
try :
130
155
return super (UDS_HSFZSocket , self ).send (
131
- HSFZ (src = self .src , dst = self .dst ) / x )
156
+ HSFZ (source = self .source , target = self .target ) / x )
132
157
except Exception as e :
133
158
# Workaround:
134
159
# This catch block is currently necessary to detect errors
@@ -153,7 +178,7 @@ def recv(self, x=MTU, **kwargs):
153
178
154
179
def hsfz_scan (ip , # type: str
155
180
scan_range = range (0x100 ), # type: Iterable[int]
156
- src = 0xf4 , # type: int
181
+ source = 0xf4 , # type: int
157
182
timeout = 0.1 , # type: Union[int, float]
158
183
verbose = True # type: bool
159
184
):
@@ -166,7 +191,7 @@ def hsfz_scan(ip, # type: str
166
191
167
192
:param ip: IPv4 address of target to scan
168
193
:param scan_range: Range for HSFZ destination address
169
- :param src : HSFZ source address, used during the scan
194
+ :param source : HSFZ source address, used during the scan
170
195
:param timeout: Timeout for each request
171
196
:param verbose: Show information during scan, if True
172
197
:return: A list of open UDS_HSFZSockets
@@ -175,7 +200,7 @@ def hsfz_scan(ip, # type: str
175
200
log_automotive .setLevel (logging .DEBUG )
176
201
results = list ()
177
202
for i in scan_range :
178
- with UDS_HSFZSocket (src , i , ip ) as sock :
203
+ with UDS_HSFZSocket (source , i , ip ) as sock :
179
204
try :
180
205
resp = sock .sr1 (UDS () / UDS_TP (),
181
206
timeout = timeout ,
@@ -184,8 +209,8 @@ def hsfz_scan(ip, # type: str
184
209
results .append ((i , resp ))
185
210
if resp :
186
211
log_automotive .debug (
187
- "Found endpoint %s, src =0x%x, dst =0x%x" % (ip , src , i ))
212
+ "Found endpoint %s, source =0x%x, target =0x%x" % (ip , source , i ))
188
213
except Exception as e :
189
214
log_automotive .exception (
190
215
"Error %s at destination address 0x%x" % (e , i ))
191
- return [UDS_HSFZSocket (0xf4 , dst , ip ) for dst , _ in results ]
216
+ return [UDS_HSFZSocket (0xf4 , target , ip ) for target , _ in results ]
0 commit comments