-
-
Notifications
You must be signed in to change notification settings - Fork 34.3k
Description
Is your feature request related to a problem? Please describe.
dgram.Socket requires the socket type (udp4 or udp6) to be provided in its constructor (dgram.createSocket), and uses this socket type regardless of the local and remote addresses.
net.Socket does not require the socket type to be provided in advance, and performs dns.lookup() with the family parameter given in net.Socket#connect() to determine the socket type. Unlike dgram.Socket, it performs socket binding when a connection is requested, so the local address/port can also be provided as parameters if needed, but the socket type is still determined by the remote host (which makes sense as net.Server deals with bound but unconnected sockets).
net.Server uses an IPv6 socket by default, unless an IPv4 address is explicitly provided in net.Server#listen().
This results in inconsistent default behavior when comparing TCP and UDP, both for servers and clients. It should be possible to have the UDP socket type be determined by the provided addresses, both for servers and clients.
Even if udp6 is chosen, which would in theory work the same for both types of remote addresses, the DNS resolution is inconsistent for TCP/UDP clients. TCP resolution defaults to family type 0, while UDP would use family type 6, so the resulting IP address will be different if the nameserver normally resolves to IPv4 first.
See lib/internal/dgram.js#newHandle, lib/net.js#internalConnect and lib/net.js#createServerHandle.
Describe the solution you'd like
dgram.Socketshould not require a socket type in its constructor.dgram.Socket#bind()should match thenet.Server#listen()behavior and use an IPv6 socket by default, unless and IPv4 address is explicitly provided.dgram.Socket#connect()should match thenet.Socket#connect()behavior and resolve the remote address to determine the socket type, crucially before thebind()call is made.- If the socket is already bound when
connect()is called, the functionality should remain as it is currently, where thedns.lookup()call is made with the family parameter set. If only IPv6 is resolved on an IPv4 bound socket, an error is thrown. - The socket type currently provided in the constructor could set an internal default address for cases when no local or remote addresses are provided to
bind()andconnect(), until this method is deprecated, after which the default address would become ::1 in both cases.
Describe alternatives you've considered
dns.lookup()can be performed manually before the socket is created to decideudp4/udp6, but this greatly complicates the socket creation flow. This could be moved todgram.createConnectionor similar, but this wouldn't fully solve the TCP/UDP client inconsistency.- If using IPv6 by default is acceptable, the
lookupparameter ofdgram.createSocketcan be set to a wrapper around the defaultdns.lookup(), with the family type set to 0 instead of 6 and if the result is IPv4 it can be manually mapped to IPv6. This again complicates the socket creation flow. - The previous alternative could be simplified if
familyandhintscould be provided as is possible innet.Socket#connect(), but this doesn't solve the core problem.