3
votes

Based on the premise that UDP is a connectionless protocol I had presumed that whether a host is up or down would be irrelevant.

However, now that I'm doing testing I've discovered that when I have "connected" my UDP client socket, a write to that socket returns an error because the server has sent back a ICMP Port Unreachable error ..

The purpose of "connecting" the UDP port (According to Stevens Unix Network Programming) is to basically caches the entry from the routing table, rather than creating a new one for each packet, which is supposed to have performance benefits.

However, this ICMP packet is causing me to lose my client socket, which is very annoying.

Can anybody shed any light on why this could be? Are there any known workarounds?

I'm using a 3p java library that doesn't account for this and just disconnects and I'll probably have to hack it to reconnect, but before I do I was kind of hoping there was something I could do at the (Linux) operating system level maybe to prevent this happening ... all investigations into socket options etc. have turned out to be unfruitful.

EDIT

In summary this isn't possible and fixing the code is the only way to do this.

The only possibility appears to be configuring iptables to block the ICMP responses but that's a bit of a sledgehammer to crack this particular nut.

2
That said, I'm not sure I understand your question. You've attempted to connect a socket to an end point that isn't available, and got an ICMP error. Why wouldn't you get an error when you then try to write to it?Alnitak
Because it's connectionless - indeed if I hadn't connected then I would not get this error. Don't be mislead by the word connected, just cause that's what it's not what it means in a datagram context. Like I say, Stevens even appears mystified.robert
@EJP in further discussion with the OP, the underlying problem is a really crappy implementation of the UDPAppender in log4j, which uses connected sockets, but provides no means for recovery if the far end disappears. bz.apache.org/bugzilla/show_bug.cgi?id=57891Alnitak
The text in the next paragraph appears to be incorrect. It says "The only piece of information that recvfrom can return is an errno value; recvfrom has no way of returning the destination IP address and destination UDP port number of the datagram in error". That's odd, because that's precisely what the address field could be used for, it just seems that the BSD folks decided not to fill it in if there's an ICMP error. WRS is no longer with us, but I know one of the co-authors and could ask him about it.Alnitak

2 Answers

5
votes

Whilst your UDP socket is not strictly "connected", making a connect() call does create local "state" for that socket.

This state not only allows the system to cache the current routing entry for the destination, but also means that all subsequent output operations don't need to specify the destination - they'll use the one specified in the connect() call. It also ensures that the kernel will throw away inbound packets destined for your socket that don't come from the "connected" party.

This connected state also allows the kernel to deliver errors relating to that socket (signalled via ICMP) to the application - unconnected sockets don't get these - they're "fire and forget".

In the case of the log4j code that you've pointed me at offline, the problem appears to be entirely in user space code. The log4j UDPAppender just unilaterally throws away the socket when it gets an IOException on a write call, and provides no means to detect that condition so that you can fix it.

-2
votes

Well, UDP sits on top of IP. And the message you get, is from that layer. See https://en.wikipedia.org/wiki/User_Datagram_Protocol and https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol

So it's connection-less in the sense, that you don't have a persistent tunnel, so it won't be guaranteed that your packets arrive in order, and stuff. Or you won't necessarily recognise right away if there's an error.

But you still need to be able to connect to something, to start with. It just happens on a lower level.

But the kernel will still keep track of the socket, so it might notify you about ICMP packets it receives, let's say from routers along the way. The point is, that ICMP is a layer below.

UPDATE: By the way, I think, you could have the problem the other way around. Your router, or whatever sits inbetween could just ignore the fact, that it doesn't know where to connect forward the packet to, and just silently drop the packet, instead of replying with an ICMP error message.