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

Detecting Symmetric NAT #2356

Open
laduke opened this issue Sep 4, 2024 · 0 comments
Open

Detecting Symmetric NAT #2356

laduke opened this issue Sep 4, 2024 · 0 comments
Labels
Type: Feature Request or Suggestion Enhancements, performance concerns, etc.

Comments

@laduke
Copy link
Contributor

laduke commented Sep 4, 2024

For discussion.

I'd like to add some info to zerotier-cli status -j in the interest of making it more obvious, to us and the user, when Hard NAT is causing a problem.

We currently have these two objects in status

 "listeningOn": [
    "192.168.82.193/9993",
    "192.168.82.193/63095",
    "192.168.82.193/37301"
  ],
 "surfaceAddresses": [
    "198.51.100.2/50261",
    "198.51.100.2/63095",
    "198.51.100.2/37301"
   ],

If the surfaceAddresses are growing bigger than the listeningOns, you can guess that Symmetric NAT is happening.

I think if there was some kind of map between these two sets, and maybe with the roots, it will be easier to manually read what is happening, and to make tools that can read this and display it to the user.
One of the main heuristics is, are the different roots seeing the same mapped port?

I don't know if we have access to the right info in the right place to build this output.

I'm not sure what the shape should be yet.
I noodled on some shapes and liked this best so far. It's verbose.
You could do nested objects to make it smaller, but those are more of a pain to deal with in my experience.

// easy nat. each listen port gets the same surface port for every root
{
  "surface": [
    { listenAddress: "192.168.82.193", listenPort: 9993, surfaceAddress: "198.51.100.2", surfacePort: 12345, root: "cafe04eba9" },
    { listenAddress: "192.168.82.193", listenPort: 9993, surfaceAddress: "198.51.100.2", surfacePort: 12345, root: "cafe9ccda7" },
    { listenAddress: "192.168.82.193", listenPort: 9993, surfaceAddress: "198.51.100.2", surfacePort: 12345, root: "778cde7190" },
    { listenAddress: "192.168.82.193", listenPort: 9993, surfaceAddress: "198.51.100.2", surfacePort: 12345, root: "cafe9efeb9" },

    { listenAddress: "192.168.82.193", listenPort: 12345, surfaceAddress: "198.51.100.2", surfacePort: 10001, root: "cafe04eba9" },
    { listenAddress: "192.168.82.193", listenPort: 12345, surfaceAddress: "198.51.100.2", surfacePort: 10001, root: "cafe9ccda7" },
    { listenAddress: "192.168.82.193", listenPort: 12345, surfaceAddress: "198.51.100.2", surfacePort: 10001, root: "778cde7190" },
    { listenAddress: "192.168.82.193", listenPort: 12345, surfaceAddress: "198.51.100.2", surfacePort: 10001, root: "cafe9efeb9" },

    { listenAddress: "192.168.82.193", listenPort: 24680, surfaceAddress: "198.51.100.2", surfacePort: 20002, root: "cafe04eba9" },
    { listenAddress: "192.168.82.193", listenPort: 24680, surfaceAddress: "198.51.100.2", surfacePort: 20002, root: "cafe9ccda7" },
    { listenAddress: "192.168.82.193", listenPort: 24680, surfaceAddress: "198.51.100.2", surfacePort: 20002, root: "778cde7190" },
    { listenAddress: "192.168.82.193", listenPort: 24680, surfaceAddress: "198.51.100.2", surfacePort: 20002, root: "cafe9efeb9" },
  ]
}

// hard nat. surfacePort mapped to unique port for every connection

{
  "surface": [
    { listenAddress: "192.168.82.193", listenPort: 9993, surfaceAddress: "198.51.100.2", surfacePort: 12345, root: "cafe04eba9" },
    { listenAddress: "192.168.82.193", listenPort: 9993, surfaceAddress: "198.51.100.2", surfacePort: 55555, root: "cafe9ccda7" },
    { listenAddress: "192.168.82.193", listenPort: 9993, surfaceAddress: "198.51.100.2", surfacePort: 24680, root: "778cde7190" },
    { listenAddress: "192.168.82.193", listenPort: 9993, surfaceAddress: "198.51.100.2", surfacePort: 36912, root: "cafe9efeb9" },

    etc...
  ]
}

(by the way the address/port format we commonly use is kind of a pain to deal with in external tools IMO. easier to select addr, port and proto fields, than grepping for colons and slashes. )

highly normalized could look something like this;

{
  "surface": {
    "192.168.82.193/9993": {
      "cafe04eba9": {
        "surfaceAddress": "198.51.100.2/12345"
      },
      "cafe9ccda7": {
        "surfaceAddress": "198.51.100.2/12345"
      }
    }
  }
}

But again I think it's harder to deal maps with in js and in typed languages. and it's not clearer to just read; the "types" are implicit.

Does the cache of surface address hold more than one mapping per address/port/root? Like if you move locations or your router changes the mapping?

for example, could this happen?

   { listenAddress: "192.168.82.193", listenPort: 9993, surfaceAddress: "198.51.100.2", surfacePort: 12345, root: "cafe04eba9" },
   { listenAddress: "192.168.82.193", listenPort: 9993, surfaceAddress: "198.51.100.2", surfacePort: 22222, root: "cafe04eba9" },

It the info was ouput to a terminal or html table, it would probably look like

listenAddr listenAddrPort surfaceAddr surfacePort rootAddress
192.168.82.3 9993 198.51.100.2 9993 cafe04eba9
192.168.82.3 9993 198.51.100.2 9993 cafe9ccda7

if a UI reduced it down:

listeningOn mappings ok?
192.168.82.3/9993 1 good
listeningOn mappings ok?
192.168.82.3/9993 4 bad

or to simplify further:

Connection type :
WAN 💯
Easy NAT👍
Hard NAT 🙁 (Link to fixing here)

@laduke laduke added the Type: Feature Request or Suggestion Enhancements, performance concerns, etc. label Sep 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Feature Request or Suggestion Enhancements, performance concerns, etc.
Projects
None yet
Development

No branches or pull requests

1 participant