Closed pmorch closed 7 years ago
You can already pass in net.PacketConn in one of the methods. This is redundant.
Listening on a specific upd port won't help you perform nat traversal as the UDP port given to you by tye NAT is still not known.
You can already pass in net.PacketConn in one of the methods. This is redundant.
You are right. NewConn()
does in fact let me pass in net.PacketConn
. So extending or modifying DialWithOptions
is not necessary. Sorry I missed that. I'll modify my derivative of kcptun/client/main.go to use NewConn()
instead of DialWithOptions()
.
Listening on a specific upd port won't help you perform nat traversal as the UDP port given to you by the NAT is still not known.
That is what UDP hole punching is for. It involves STUN for well-behaved NATs and a coordinating server somewhere and this is a challenge I am prepared to implement code to overcome. I have it working here with my port 20000 hack above, so yes, it does in fact work. But only if I can control the UDP source port for the client.
I am well aware of how stun works, as I've implemented it in syncthing (yet I've hit other issues related to this library which I haven't solved it yet).
You do not need to control the client/server ports, as long as you can work out your external port mapped by the NAT via the STUN server that's all that matters.
Then perhaps there is something I don't understand.
I'm planning on implementing this in a couple of steps, (assuming Alice wants to connect to Bob). This works when done manually:
Since the outside UDP ports depend on the inside UDP ports, how would you use STUN to determine the outside UDP port if KCP (or the OS?) later chooses a random port?
Or are you letting KCP choose an inside UDP port, and then afterwards using STUN to get the outside (IP,port) for the inside port chosen by KCP?
This is definitely getting off-topic for an issue called "Setting the UDP source port (adding laddr parameter to DialWithOptions in sess.go?)" but I would appreciate any feedback you'd care to give. Either here or to peter@morch.com.
Use those same inside UDP source ports and external (IP, port) sets for KCP to establish the connection. This is where this issue, "Setting the UDP source port" becomes important.
This does not matter, internal (ip, port) on Alice does not need to be the same as Bob. They don't even need to know what their internal pair is. As long as Bob knows that it's externally available on (Bip, Bp), and Alice is externally available on (Aip, Ap), Bob connects to (Aip, Ap), and Alice connects to (Bip, Bp), regardless of what the internal mapping is.
One thing you do need to do, is to make sure that you perform STUN via the same socket you are establishing a connection to the other side, so that (Xip, Xp) remains the same between discovering it and using it, though you do it not by listening on the same address pair twice (in fact, in some kernels this will even fail), you reuse the same socket descriptor you used for stun, and after stun is done, you pass it to kcp.
Actually, it's a bit more involved than that, as technically you should do test1 of stun every 20-24 seconds to keep the NAT mapping alive, because if you didn't manage to connect in the first 24 seconds, the NAP mapping is likely to get torn down, which essentially means you need to multiplex STUN and KCP over the same socket, and somehow be able to recognize the packets coming in and direct them to the right "virtual" connection.
This library had a nice interface, which allowed reading out of bound packets (packets that are not identified as being of the right protocol), which means you could share the same underlying connection for utp and offload the out of bound packets to STUN. Sadly, in my tests it wasn't a very reliable library.
Sadly, kcp does not support that and I had to roll my own library to support that.
Though as I said, I discovered other issues with KCP, where it maintains some state between connections/disconnections/reconnections, plus doesn't work very well when we have a sending socket and a receiving socket on the same underlying socket descriptor.
Thank you for your aid, Audrius!
I find this concerning:
Though as I said, I discovered other issues with KCP, where it maintains some state between connections/disconnections/reconnections, plus doesn't work very well when we have a sending socket and a receiving socket on the same underlying socket descriptor.
I don't see any open issues or anything involving AudriusButkevicius relating to these two kcp-go issues. Did I miss something?
(I think I've found the reliability issue you had with "this library": Starts stalling under load · Issue #13 · anacrolix/utp)
This is actually a duplicate of #36.
I haven't yet debugged to understand the cause, so perhapsits my own code.
Any update? Same problem here.
Hi,
In order to do UDP hole punching when using kcptun's client, I'd like to be able to set the UDP source port. This does not seem possible with the current implementation in sess.go. I first demonstrate that it is easy to hack, but would like to ask what the appropriate API should be, if this were to be considered for inclusion in kcp-go.
Setting the UDP source port would require the current call in
DialWithOptions()
in sess.go:to provide a
laddr
parameter to net.DialUDP instead ofnil
. This hack makes kcptun'sclient_linux_amd64
use source port 20000:However, current the function signature of
func DialWithOptions
doesn't really make it possible/easy to add a laddr parameter.I don't know of any alternative to or workaround for setting the UDP source port in order to do UDP hole punching and it seems like such a cool use of the KCP family of libraries so I really hope this possibility can be included. To that end I would like to ask @xtaci:
laddr
?laddr
parameter tofunc DialWithOptions
?DialWithOptions
type DialParams struct
containing theraddr
,block
,dataShards
,parityShards
plus a newladdr
element, and then create a newfunc DialWithParams
that takes such a DialParams struct as a single parameter. MarkDialWithOptions
as deprecated and implement it as a wrapper aroundDialWithParams
.DialWithOptions
.func DialWithParams
and a deprecatedfunc DialWithOptions
.func DialWithOptionsAndLaddr
that takes all the parameters ofDialWithOptions
+laddr
?DialWithOptions
would then be a wrapper aroundDialWithOptionsAndLaddr
using anil
laddr
. Choosing a good name for this func is tricky (it could also be calledDialWithMoreOptions
) - I guess because it ideally should be calledDialWithOptions
:-)DialWithOptions
and it maintains backwards compatibility withDialWithOptions
.someNewParam
needs to be added in the future