Subject: [Int-area] Fwd: Add new udp connect command to draft-olteanu-intarea-socks-6

From: Vladimir Olteanu <[email-masked]>
Date: Sun, 10 Jan 2021 19:35:12 +0200

-------- Forwarded Message --------
Subject: 	Add new udp connect command to draft-olteanu-intarea-socks-6
Resent-Date: 	Thu, 7 Jan 2021 22:54:48 -0800 (PST)
Resent-From: 	[email-masked]
Resent-To: 	[email-masked], [email-masked]
Date: 	Fri, 8 Jan 2021 06:54:41 +0000
From: 	张 敬强 <[email-masked]>
To: 	[email-masked] 
<[email-masked]>

Hi,

The udp associate command in socks5 and current sock6 draft
is not very efficient for proxy servers, as each packet may
have a different target address, which will be a burden for
ACL checking and route selection.

For protocols like DNS / UDP based RTMP / QUIC , the target
address will remain the same for the socks proxy session.
For these protocols a new udp connect  command is much more
suited than the udp associate command.

At the proxy side, the proxy server could get the target udp
address just like the connect command, then setup a socket of
the same address family and connect to the target address,
on linux hosts this socket can be set with bind_addr_no_port sockopt,
so the socket number won't be limited by 65535 binding ports per ip
address. The ACL checking and route selection can be done at the
very early stage of the socks proxy session, which can somehow improve
the udp packet processing efficiency.

So I suggest to add a new udp connect command, with the address and port
in socks request to be the target udp address and port. A new option
is also recommended to be added to tell the proxy server the address and 
port
of the client, so port reuse for the client-proxy udp connections can be 
enabled
when the proxy server setup the client side udp socket.

I didn't subscribe to this mailing list, so please CC me if needed.
Thanks

---

From: Zhang Jingqiang <[email-masked]>
Date: Wed, 13 Jan 2021 09:54:03 +0800

Hi,

> 
> I think you're right. Unless you're hosting some UDP server, the
> communication involves only one remote peer in most cases. ACL selection
> does become easier, but route selection is done in the kernel on a
> per-packet basis, so route lookup won't get optimized.

The route selection I mean here is sometimes we need to bind the local
socket to IP addresses from different ISP on the same host, that's the case
I care the most for a fixed remote peer, as for cdn domains, we need to
decide which ISP should be used before resolving.

> > in socks request to be the target udp address and port.
> 
> I think adding a Remote Peer option (containing the address and port) to
> the already-existing UDP ASSOCIATE command would be a more elegant
> solution. Some protocols, like RTP, still require control over the
> source port, so we also need the Associate semantics for Connect either way.
> 
> 
> To complement this new option, a null SOCKS address type could be added.
> The actual "null" address should be empty, i. e. not take any space. If
> the remote peer negotiation is successful, the client can go ahead and
> use null addresses for its datagrams.
> 
> 
> I can see some other benefits:
> 
>   * The datagram header becomes smaller.
> 
>   * If the remote host is known by hostname, rather than by IP address,
> the client no longer has to do a DNS query beforehand. (It's also
> possible to place the hostname into each datagram header, but that's
> impractical.)

I have thought about this method this morning, and yes it's better than adding
a new command.
 
> > A new option
> > is also recommended to be added to tell the proxy server the address
> > and port
> > of the client, so port reuse for the client-proxy udp connections can
> > be enabled
> That is no longer an issue in SOCKS 6. Now all UDP flows go to the same
> port, 1080 by default for plain UDP and TBD for DTLS.

Oh, I have missed this point in socks6.

The following is not about the protocol, but just some thoughts about the 
implementation:
I haven't experienced with UDP traffic multiplexing, it seems to be the same way 
as QUIC. But I still have some worry, as at the app layer we need to receive 
packets one per syscall, will it be enough for more than 60000 sessions? Port 
binding per cpu and large send/recv buffer are needed. I have thought using 
XDP+ring on linux to decrease the recv/send syscall used, or is there any 
better ways?

---

From: Vladimir Olteanu <[email-masked]>
Date: Wed, 13 Jan 2021 13:59:27 +0200

Hello,

> XDP+ring on linux to decrease the recv/send syscall used, or is there any

I agree that the kernel is slow, and UDP traffic can be accelerated by 
bypassing the stack.

If you're willing to dedicate a whole interface to UDP traffic, you can 
use DPDK or netmap. (I'm not sure about how well the latter works on 
recent Linux versions.) The NIC will do RSS for you, and you can spawn 
one thread per ring. You can pin the interrupts to the same cores as the 
threads doing the work for maximum efficiency.

Alternatively, you can set aside a single ring for UDP traffic: 
https://blog.cloudflare.com/single-rx-queue-kernel-bypass-with-netmap/

I don't have any experience with XDP, but I guess you can get similar 
results with it as well.

Cheers,

Vlad