Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib/connections: Try TCP punchthrough #5753

Merged
merged 21 commits into from
Jun 16, 2020

Conversation

AudriusButkevicius
Copy link
Member

This is hopefully a PR with only the relevant changes, if I haven't failed to git.

lib/dialer/debug.go Outdated Show resolved Hide resolved
@syncthing syncthing deleted a comment from golangcibot May 29, 2019
@syncthing syncthing deleted a comment from golangcibot May 29, 2019
@syncthing syncthing deleted a comment from golangcibot May 29, 2019
@AudriusButkevicius
Copy link
Member Author

Ready for review maybe? Given 1.2.0 is out, and quic has not broken the world, let's try to do it again.

Copy link
Member

@imsodin imsodin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good generally, mostly nitpicks below.

Is my understanding of the mechanism correct: We now dial and listen on the same port. We announce an unspecified address to the discovery server, which then uses the port of the announcement. We expect this to be the same port that the NAT assigned to where we are listening/dialing on. The remote then uses that port for dialing, and thus we manage to dial and listen on the same port.

lib/dialer/control_unix.go Show resolved Hide resolved
lib/dialer/debug.go Outdated Show resolved Hide resolved
lib/util/utils.go Show resolved Hide resolved
lib/connections/tcp_listen.go Show resolved Hide resolved
lib/connections/tcp_listen.go Show resolved Hide resolved
lib/dialer/public.go Outdated Show resolved Hide resolved
lib/dialer/internal.go Outdated Show resolved Hide resolved
lib/dialer/internal.go Outdated Show resolved Hide resolved
lib/connections/tcp_dial.go Outdated Show resolved Hide resolved
lib/dialer/public.go Outdated Show resolved Hide resolved
lib/osutil/ping.go Outdated Show resolved Hide resolved
lib/relay/client/methods.go Outdated Show resolved Hide resolved
lib/dialer/public.go Outdated Show resolved Hide resolved
@AudriusButkevicius
Copy link
Member Author

I've addressed the review comments and unmarked some comments as done as it's not for me to judge when it's done.

Copy link
Member

@imsodin imsodin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am totally fine with you dismissing my utterly nit-picky and/or opinionated comments - it's still nice when you let me mark them done just for convenience when reading your answers ;)

I like the sneak attack, but I think there's a problem with how it's done currently. The other two comments are even worse nitpickery than before, ignore at will.

Otherwise this is lgtm from my side. I didn't look up the low-level stuff (syscall), I am sure you got that right.

lib/dialer/control_unix.go Outdated Show resolved Hide resolved
lib/dialer/public.go Show resolved Hide resolved
lib/relay/client/dynamic.go Outdated Show resolved Hide resolved
@AudriusButkevicius
Copy link
Member Author

Editing on the mobile on a train, yay.
Anyways, addressed comments.

Time for @calmh?

Copy link
Member

@calmh calmh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks reasonable, I'm going to see if I can do some testing...

lib/relay/client/dynamic.go Outdated Show resolved Hide resolved
lib/dialer/public.go Outdated Show resolved Hide resolved
lib/dialer/debug.go Outdated Show resolved Hide resolved
if localAddrInterface != nil {
if addr, ok := localAddrInterface.(*net.TCPAddr); !ok {
return nil, errUnexpectedInterfaceType
} else {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) (from golint)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are fucking stupid.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, it's right although you may not agree with the style choice

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I struggle to understand where the suggested style choice would be better.

@imsodin
Copy link
Member

imsodin commented Jul 27, 2019

The old go version check (go1.10.7) fails due to ListenConfig and Dialer.Control that have been introduced in go1.11: https://golang.org/doc/go1.11#net. go1.13 will be out soon and by using modules we already have a kind of "soft requirement" for go1.11, so I think we should be fine bumping the old go version check to go1.11.

@AudriusButkevicius
Copy link
Member Author

AudriusButkevicius commented Apr 29, 2020

So the announce part seems to work for me.
Added req.RemoteAddr to the typical log:

380704bb7b4d7c03 POST / 86.29.10.111:22000

And log the announcement addresses before and after the "fixup"

Announce: 2ERMYXS-ZKTQICW-AWCYDBJ-ZDSV4JA-5PYZHDV-6Q4COSC-3POAZJO-UDAYFAS got: [tcp://0.0.0.0:0 tcp://0.0.0.0:22000 quic://0.0.0.0:22000] made: [tcp://86.29.10.111:22000 tcp://86.29.10.111:22000 quic://86.29.10.111:22000] 

I suspect the problem you've seen is because nginx/caddy fronting the server does not forward the port in X-Forwarded-Port.

@AudriusButkevicius
Copy link
Member Author

How do we take this forward?

@calmh
Copy link
Member

calmh commented May 25, 2020

Some kind of reasonable testing I guess. Have you run this and seen it work? If so I'll take it for another spin and we can debug any issues. Last time I had the feeling it was all theoretical and hence I wasn't sure whether to debug my network or just assume that things didn't work as intended...

@AudriusButkevicius
Copy link
Member Author

Well the only thing I tested is that the source address connecting to discovery is port 22000, and that discovery correctly substitutes port 0 with that port (on a local discovery server). I have not tested actual punch through capabilities as I don't have two devices behind different domestic routers.

@AudriusButkevicius
Copy link
Member Author

I think the best way forward with this would be to cherry-pick and deploy the discovery changes and adding support for X-Forwarded-Port.

This should have no effect.

Then run with this PR for a week to verify it doesn't break anything existing in your setup, and then just merge it on good will and see if anything comes from the RC?

@AudriusButkevicius
Copy link
Member Author

@calmh @imsodin bhuump. What are we doing with this?

Copy link
Member

@imsodin imsodin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your plan from a week ago (sorry for the delay) sound good. If it works at all should be well discernable from the transport usage reporting and if it doesn't, reverting is easy (as longs as we don't redesign dialing in the meantime).

Comment on lines +394 to +395
if remote != nil {
if host == "" || ip.IsUnspecified() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be remote != nil && (host == "" || ip.IsUnspecified()) removing the need for an additional indentation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a block after the nested if which would have to repeat remote != nil then.

@AudriusButkevicius
Copy link
Member Author

AudriusButkevicius commented Jun 14, 2020

Soo, approve and lets go? 👯

@imsodin
Copy link
Member

imsodin commented Jun 14, 2020

Only @calmh can deploy, so the ball is in his court now, isn't it?
I might also just run a discovery server at home for testing, I just need to overcome the laziness to set the ports and clients up for that...

@calmh calmh changed the base branch from master to main June 15, 2020 19:31
@calmh
Copy link
Member

calmh commented Jun 16, 2020

I actually did deploy the discovery servers from this a while back (still running), but I can do so again. I'm generally not super excited about merging code that the person who wrote it hasn't been able to test at all for whether it actually does what it's supposed to, but if there's confidence that it doesn't sabotage existing connection setup and a plan for actual post-merge testing and reporting back, sure.

@calmh
Copy link
Member

calmh commented Jun 16, 2020

So looking at this it seems we want X-Forwarded-Port to be the source port of the client, while it's generally meant to be the (original) server port? I'll set it up with the client port

* main: (37 commits)
  various: Master is now main
  lib/model: Fix minor flakiness in TestModTimeWindow
  cmd/ursrv: Attempt to fix js failure to load (syncthing#6747)
  lib/osutil: Use filepath.Join in tests (syncthing#6740)
  cmd/strelaysrv: Fix JSON unmarshalling when joining a relay pool (fixes syncthing#6733) (syncthing#6729)
  gui, man, authors: Update docs, translations, and contributors
  build(deps): bump github.com/lucas-clemente/quic-go (syncthing#6722)
  lib/db: Remove unused keyer methods (syncthing#6723)
  gui: Fix auto dismissing auth notification (ref syncthing#6536)
  lib/scanner: Save one stat call per file (syncthing#6715)
  gui: Ignore permissions isn't just about FAT (syncthing#6713)
  lib/connections, lib/nat: Correctly dis-/enable nat (fixes syncthing#6552) (syncthing#6719)
  gui: Fix string and update translations (ref syncthing#6536) (syncthing#6716)
  lib/protocol: Avoid panic in DeviceIDFromBytes (syncthing#6714)
  build: Fix rebuild of strelaypoolsrv assets
  cmd/strelaysrv: Add note about relay operators
  cmd/stcrashreceiver: Pick up extra build tags and send to Sentry (syncthing#6710)
  lib/build: Add some env vars as synthetic build tags (syncthing#6709)
  build(deps): bump github.com/lucas-clemente/quic-go (syncthing#6695)
  gui, man, authors: Update docs, translations, and contributors
  ...
@calmh
Copy link
Member

calmh commented Jun 16, 2020

Well some cursory testing at home seems to indicate it doesn't in fact fuck anything up beyond repair, so that's good 👍

@calmh calmh merged commit f619a7f into syncthing:main Jun 16, 2020
@AudriusButkevicius
Copy link
Member Author

You are right, I should probably change it to X-Client-Port or something.

I'll also try to come with with something that atleast tries to show it working.

@calmh
Copy link
Member

calmh commented Jun 16, 2020

I would try it with one end tethered behind mobile, assuming the other is behind a "regular" router. But this still requires full cone (I think? or maybe just deterministic port mappings) so might not work in that setup even if everything is great on our side.

@calmh
Copy link
Member

calmh commented Jun 16, 2020

Anyway it's deployed server side, though we can redeploy with a different header name later

calmh added a commit to calmh/syncthing that referenced this pull request Jun 16, 2020
* main: (30 commits)
  lib/connections: Try TCP punchthrough (fixes syncthing#4259) (syncthing#5753)
  build(deps): bump github.com/lucas-clemente/quic-go (syncthing#6742)
  various: Master is now main
  lib/model: Fix minor flakiness in TestModTimeWindow
  cmd/ursrv: Attempt to fix js failure to load (syncthing#6747)
  lib/osutil: Use filepath.Join in tests (syncthing#6740)
  cmd/strelaysrv: Fix JSON unmarshalling when joining a relay pool (fixes syncthing#6733) (syncthing#6729)
  gui, man, authors: Update docs, translations, and contributors
  build(deps): bump github.com/lucas-clemente/quic-go (syncthing#6722)
  lib/db: Remove unused keyer methods (syncthing#6723)
  gui: Fix auto dismissing auth notification (ref syncthing#6536)
  lib/scanner: Save one stat call per file (syncthing#6715)
  gui: Ignore permissions isn't just about FAT (syncthing#6713)
  lib/connections, lib/nat: Correctly dis-/enable nat (fixes syncthing#6552) (syncthing#6719)
  gui: Fix string and update translations (ref syncthing#6536) (syncthing#6716)
  lib/protocol: Avoid panic in DeviceIDFromBytes (syncthing#6714)
  build: Fix rebuild of strelaypoolsrv assets
  cmd/strelaysrv: Add note about relay operators
  cmd/stcrashreceiver: Pick up extra build tags and send to Sentry (syncthing#6710)
  lib/build: Add some env vars as synthetic build tags (syncthing#6709)
  ...
@calmh calmh added this to the v1.7.1 milestone Jun 16, 2020
@st-review st-review added the frozen-due-to-age Issues closed and untouched for a long time, together with being locked for discussion label Jun 17, 2021
@syncthing syncthing locked and limited conversation to collaborators Jun 17, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
frozen-due-to-age Issues closed and untouched for a long time, together with being locked for discussion
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants