Trigger EHOSTUNREACH

3 messages, 2 authors, 2016-12-05 · open the first message on its own page

Trigger EHOSTUNREACH

From: Marco Zunino <hidden>
Date: 2016-12-04 12:04:46

Hallo everyone, hope you are having a good day
we are building a networking testing tool to simulate network error
condition, and we are having difficulties triggering the EHOSTUNREACH
socket error.

We are trying to trigger this error by sending an ICMP packet type=3
code=3 on an open STREAM socket, but it has no effect.

Based on RFC1122 and the code here

https://github.com/torvalds/linux/blob/e76d21c40bd6c67fd4e2c1540d77e113df962b4d/net/ipv4/tcp_ipv4.c#L353

I would expect the this ICMP packet to abort the socket connection
with a EHOSTUNREACH error on the client side, but this does not
happen.

In RFC5927 we also see basically all hard_error should not be
considered so, and TCP connection never being aborted as a result of
ICMP error, for security and robustness reason.

If we send the same ICMP on a STREAM socket in SYN_SENT state (while
still waiting for the SYN_ACK to be received) the socket fails but
with an error ECONNREFUSED.

Could you give us a direction to better understand how ICMP errors
interact with TCP sockets? What about DGRAM sockets?

Thank you!

- Z

Re: Trigger EHOSTUNREACH

From: Neal Cardwell <ncardwell@google.com>
Date: 2016-12-04 17:52:04

On Sun, Dec 4, 2016 at 7:04 AM, Marco Zunino [off-list ref] wrote:
Hallo everyone, hope you are having a good day
we are building a networking testing tool to simulate network error
condition, and we are having difficulties triggering the EHOSTUNREACH
socket error.

We are trying to trigger this error by sending an ICMP packet type=3
code=3 on an open STREAM socket, but it has no effect.

Based on RFC1122 and the code here

https://github.com/torvalds/linux/blob/e76d21c40bd6c67fd4e2c1540d77e113df962b4d/net/ipv4/tcp_ipv4.c#L353

I would expect the this ICMP packet to abort the socket connection
with a EHOSTUNREACH error on the client side, but this does not
happen.
In my quick tests with packetdrill, it looks like Linux will not
immediately pass EHOSTUNREACH to the application unless the
application has requested this with setsockopt(SOL_IP, IP_RECVERR).

Specifically, the following packetdrill test passes for me:
---
0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
   +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
   +0 bind(3, ..., ...) = 0
   +0 listen(3, 1) = 0

   +0 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7>
   +0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 8>
+.020 < . 1:1(0) ack 1 win 257
   +0 accept(3, ..., ...) = 4
   +0 setsockopt(4, SOL_IP, IP_RECVERR, [1], 4) = 0
   +0 write(4, ..., 1000) = 1000
   +0 > P. 1:1001(1000) ack 1

+.010 < icmp unreachable host_unreachable [1:1461(1460)]

   +0 write(4, ..., 1) = -1 EHOSTUNREACH (No route to host)
---

But without the setsockopt(SOL_IP, IP_RECVERR) there is no error upon
the second write().

My reading of RFC 1122 is that this is consistent with the RFC.

RFC 1122 section 3.2.2.1 says:

            A Destination Unreachable message that is received with code
            0 (Net), 1 (Host), or 5 (Bad Source Route) may result from a
            routing transient and MUST therefore be interpreted as only
            a hint, not proof, that the specified destination is
            unreachable [IP:11].

So it seems that the RFC is suggesting that by default an ICMP host
unreachable should not cause an immediate error for the connection.
Instead, it should be used as a hint as to the cause of the problem if
TCP's normal reliable delivery mechanisms ultimately timeout and fail.

neal

Re: Trigger EHOSTUNREACH

From: Marco Zunino <hidden>
Date: 2016-12-05 19:07:16

Hi Neal, thank you!
I can succesfully repoduce the following socket error now after
setting the IP_RECVERR socket option:

    ICMP type=3, code=1 -> EHOSTUNREACH
    ICMP type=3, code=2 -> ENOPROTOOPT
    ICMP type=3, code=3 -> ECONNREFUSED
    ICMP type=3, code=4 -> No error
    ICMP type=3, code=5 -> ENOTSUP
    ICMP type=3, code=6 -> ENETUNREACH
    ICMP type=3, code=7 -> EHOSTDOWN
    ICMP type=3, code=8 -> ENONET

In my case, the errors are triggered while in recv(). I did not know
packetdrill, so I am triggering this error using our own tool.

I tried to send an ICMP type=3 code=1 on an ESTABLISHED TCP connection
opened by Chrome browser, and after about 20 minutes, I get
ERR_ADDRESS_UNREACHABLE error in the browser screen. It is curious how
it does not fail with a  CONNECTION_TIMEOUT, I think this reflect your
interpretation of RFC 1122 section 3.2.2.1.

If I try to run your packetdrill test case, I get an error: unknown
symbol: 'IP_RECVERR'.
In the testcase, I tried to replace IP_RECVERR with the corresponding
value '0x0b', but in this case the write() does not return any error.


On Sun, Dec 4, 2016 at 6:51 PM, Neal Cardwell [off-list ref] wrote:
On Sun, Dec 4, 2016 at 7:04 AM, Marco Zunino [off-list ref] wrote:
quoted
Hallo everyone, hope you are having a good day
we are building a networking testing tool to simulate network error
condition, and we are having difficulties triggering the EHOSTUNREACH
socket error.

We are trying to trigger this error by sending an ICMP packet type=3
code=3 on an open STREAM socket, but it has no effect.

Based on RFC1122 and the code here

https://github.com/torvalds/linux/blob/e76d21c40bd6c67fd4e2c1540d77e113df962b4d/net/ipv4/tcp_ipv4.c#L353

I would expect the this ICMP packet to abort the socket connection
with a EHOSTUNREACH error on the client side, but this does not
happen.
In my quick tests with packetdrill, it looks like Linux will not
immediately pass EHOSTUNREACH to the application unless the
application has requested this with setsockopt(SOL_IP, IP_RECVERR).

Specifically, the following packetdrill test passes for me:
---
0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
   +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
   +0 bind(3, ..., ...) = 0
   +0 listen(3, 1) = 0

   +0 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7>
   +0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 8>
+.020 < . 1:1(0) ack 1 win 257
   +0 accept(3, ..., ...) = 4
   +0 setsockopt(4, SOL_IP, IP_RECVERR, [1], 4) = 0
   +0 write(4, ..., 1000) = 1000
   +0 > P. 1:1001(1000) ack 1

+.010 < icmp unreachable host_unreachable [1:1461(1460)]

   +0 write(4, ..., 1) = -1 EHOSTUNREACH (No route to host)
---

But without the setsockopt(SOL_IP, IP_RECVERR) there is no error upon
the second write().

My reading of RFC 1122 is that this is consistent with the RFC.

RFC 1122 section 3.2.2.1 says:

            A Destination Unreachable message that is received with code
            0 (Net), 1 (Host), or 5 (Bad Source Route) may result from a
            routing transient and MUST therefore be interpreted as only
            a hint, not proof, that the specified destination is
            unreachable [IP:11].

So it seems that the RFC is suggesting that by default an ICMP host
unreachable should not cause an immediate error for the connection.
Instead, it should be used as a hint as to the cause of the problem if
TCP's normal reliable delivery mechanisms ultimately timeout and fail.

neal
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help