scapy icon indicating copy to clipboard operation
scapy copied to clipboard

DoIP functional addressing responses not associated with preceding request

Open d137297 opened this issue 1 year ago • 2 comments

Brief description

When sending a request over DoIP using functional addressing, the DoIP source addesses of the ECU responses will be different from the target address of the preceding request, as the ECUs respond from their actual address instead of the functional "broadcast address" used in the request. DoIP.hashret effectively filters out these "mismatched" packets, so when using DoIPSocket.sr(...) with a functional target address, no responses will ever be returned.

Scapy version

2.6.0

Python version

3.11

Operating system

Linux 6.1.21-v8+

Additional environment information

No response

How to reproduce

from scapy.contrib.automotive.doip import *
from scapy.contrib.automotive.uds import *

ip="169.254.207.236"
sock = DoIPSocket(ip)

ans, unans = sock.sr(DoIP(payload_type=0x8001, source_address=0xe80, target_address=0xe400) / UDS() / UDS_TP(), multi=True, timeout=2)

Actual result

INFO: Routing activation successful! Target address set to: 0x3107
Begin emission:
Finished sending 1 packets.
.........
Received 9 packets, got 0 answers, remaining 1 packets

Expected result

INFO: Routing activation successful! Target address set to: 0x3107
Begin emission:
Finished sending 1 packets.
.********
Received 9 packets, got 8 answers, remaining 0 packets

This result was obtained by monkey-patching DoIP.hashret to ignore the addresses, based on a config setting, analogous to how scapy handles IP broadcast traffic with the conf.checkIPaddr setting (see below)

Related resources

Just for reference, this is the monkey-patch I'm using at the moment to enable me to run functional addressing requests (by disabling the setting whenever I need it):

from scapy.config import conf
from scapy.contrib.automotive.doip import DoIP

def hashret_patched(self):
    if self.payload_type in [0x8001, 0x8002, 0x8003]:
        if conf.checkDoIPaddr:
            return bytes(self)[:2] + struct.pack(
                "H", self.target_address ^ self.source_address)
        return bytes(self)[:2]
    return bytes(self)[:2]

conf.checkDoIPaddr = True
DoIP.hashret = hashret_patched

But there is maybe/probably a better way.

d137297 avatar Oct 01 '24 11:10 d137297

Thanks for this issue.

Could you please reference a section in the DoIP Standard which describes this behaviour? I couldn't find anything related to this.

Besides this, you can also pin the target_address in the DoIPSocket.init function: https://github.com/secdev/scapy/blob/c38a5de175be8e59742be473f4fb2dd6edef5503/scapy/contrib/automotive/doip.py#L440

Additionally, you can do the routing activation request yourself and eliminate the automatical setting of the target_address.

Could you please proved a pcap file for analysis?

polybassa avatar Oct 03 '24 08:10 polybassa

Hey, thanks for taking a look.

I don't think there's anything in the spec that explicitly describes this behavior, it seems more like emergent behavior of the general principles where functionally addressed diagnostic requests are broadcast, and that responses sent always have the source address set according to the sending ECU. Otherwise (e.g. if the ECU responded with the source address set to the functional address the preceding request was addressed to), the recipient wouldn't be able to associate the individual diagnostic message responses with the ECU sending them, when they receive multiple responses for a single broadcast request, right?

I'm by no means an expert on this, I've just observed this behavior with the ECUs I'm working with, and it makes sense to me that this is how it works. Maybe I'm missing something? I have attached a pcap file that demonstrates the traffic I see when running the snippets I posted above: doip_functional_request.pcap.zip

d137297 avatar Oct 10 '24 15:10 d137297

Hi, I’ve checked the DoIP standard regarding the described behaviour. I found this: httpswww autosar orgfileadminstandardsR20-11CPAUTOSAR_SWS_DiagnosticOverIP pdf#page40

So you are doing a routing activation with SA 0x3107 but than your UDS packet is sent to Address 0xe400.

By strictly following the standard it should not even be possible to send a UDS packet to this TA.

To me, this behaviour looks like an out of specification behaviour. Neither the autosar standard nor the ISO13400 standard specify a broadcast mechanism as you show with your pcap file.

It would be great if you can provide any written reference for this feature.

polydroi avatar Oct 26 '24 12:10 polydroi

I guess it must not have been clear from my previous comments, but the setup I have here is that my test device is connected to a gateway (which has address 0x3107). The gateway is connected to a number of ECUs on the vehicle network side.

ISO 13400-2:2019(E) Section 7.8 reads:

[...] Functional logical addresses are used to address messages to groups of, or all of, the diagnostic application layer entities within a vehicle. [...] For a DoIP Gateway the reception of a functionally addressed diagnostics message implies a multi- or broadcast on the connected in-vehicle sub-networks. [...]

Thus, when sending functionally-addressed requests to the gateway, it will, in turn, broadcast them on the vehicle network, and route back any responses from the connected ECUs.

d137297 avatar Oct 28 '24 10:10 d137297