How DNS Works with Twingate

Twingate is not a VPN, and instead uses a transparent proxy system to connect users to private Resources. By taking this approach, user devices never join your private network and also require neither direct routing nor private DNS resolver access to complete network connections. This allows you to simultaneously achieve a much stronger default security posture and a much-improved end user experience. Users can only access Resources that they have explicitly been granted access to, and Resource addresses are shielded from public inspection.

The step-by-step example flow and diagram below explains how users can access private DNS addresses without having access to the private DNS resolver. (Note that the same flow applies for Resources with public DNS entries: resolution will still pass through the configured Connector on your private network, overriding the public DNS lookup route directly from the user’s device.)

DNS resolution flow with Twingate

  • An application on the client device sends a DNS request for a private Resource to the operating system, which is intercepted by the Twingate Client application. The Twingate Client app runs a DNS resolver for this purpose.
  • The Twingate Client’s DNS resolver responds with an IP address uniquely assigned to the Resource. Note that this assigned IP address is not related to the actual private IP of the Resource in question. IP addresses are assigned from the shared 100.64.0.0/10 CGNAT range so as not to conflict with any local or configured network ranges.
  • The application on the user’s device initiates communication with the Twingate-assigned IP address and the Client acts as a transparent proxy, forwarding traffic to the appropriate Twingate Connector. The Twingate Client keeps a mapping between assigned IPs and Resources, with the effect being that local applications see DNS resolution for Twingate-defined private DNS entries.
  • The Connector, upon receiving the connection request, sends a DNS request to the network’s private DNS server. As long as the Connector is able to resolve the DNS resource you have defined in Twingate and route traffic to the destination, the connection to the private Resource will succeed.
  • The private DNS server responds with the private IP address of the Resource in question. This allows traffic to be routed to the destination host. The destination host’s IP address is not revealed to the Client or application as it sits behind the transparent proxy connection that Twingate has established.
  • Finally, the Connector initiates communication with the requested Resource’s private IP, proxying traffic from the application on the user’s device. This completes the end-to-end connection.

Why does DNS matter for Twingate?

Because most of our customers use Resources as FQDNs (Fully Qualified Domain Names aka DNS-style resources like nas.home.int) as opposed to IP addresses (like 192.168.1.50) or CIDR ranges (a CIDR Range is simply a range of consecutive IPs):

So the central question around how the Twingate Client works now becomes:

“How does the Twingate Client resolve a FQDN like nas.home.int which is only resolvable by my internal DNS at home, when I am in fact NOT at home?”

This is an essential component of how we make it seamless for people to work remotely. After the Twingate Client is installed, users can access Resources in the same way that they’d access them when physically in the office (or at home, in the case of this example). Let’s dive deeper.

The Twingate Client knows what Resources it can access

Let’s assume nas.home.int is a Twingate Resource our Twingate Client & User have legitimate access to.

Our local Twingate Client is given a copy of all the FQDNs and IP addresses it has legitimate access to (including nas.home.int). Our client uses this list locally to intercept the right traffic. For example, it will intercept everything destined for nas.home.int but will ignore anything for, say, server.home.int because the latter isn’t a Twingate Resource.

How the Twingate Client resolves nas.home.int

In order to check the IP address the Client resolves for it, let’s use dig and find out. (dig is a command you can use on macOS & Linux to resolve the IP from the FQDN.)

Let’s first look at the dig command with the Twingate Client OFF and resolve our local resource nas.home.int while on our home network:

my-mbp16 git % dig nas.home.int
; <<>> DiG 9.10.6 <<>> nas.home.int
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12309
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;nas.home.int. IN A
;; ANSWER SECTION:
nas.home.int. 86400 IN A 192.168.1.50
;; AUTHORITY SECTION:
home.int. 86400 IN NS ns.home.int.
;; ADDITIONAL SECTION:
ns.home.int. 86400 IN A 192.168.1.1
;; Query time: 153 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Mon Jun 27 19:05:27 EDT 2022
;; MSG SIZE rcvd: 90

Great! it resolves to 192.168.1.50 which is indeed a local IP on my home network.

Now let’s run the same command but with the Twingate Client ON:

my-mbp16 git % dig nas.home.int
; <<>> DiG 9.10.6 <<>> nas.home.int
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 57867
;; flags: qr aa rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;nas.home.int. IN A
;; ANSWER SECTION:
nas.home.int. 15 IN A 100.108.194.142
;; Query time: 83 msec
;; SERVER: 100.95.0.251#53(100.95.0.251)
;; WHEN: Mon Jun 27 19:01:55 EDT 2022
;; MSG SIZE rcvd: 46

Hmm, the address resolved is no longer a local IP address but a public IP within the CGNAT range.

In fact, you will notice 2 big differences once the Twingate Client is switched on:

  • nas.home.int now resolves to 100.108.194.142 which is NOT a local IP address on our home network (it’s a public IP in the CGNAT Range)
  • the DNS Server is no longer 192.168.1.1 but is now 100.95.0.251

Why does a local resource resolve to a public IP?

Because the Twingate Client needs to intercept all traffic meant for nas.home.int. To do this, the Client does a few things on your device:

1. The Twingate Client sets up its own network interface, visible in macOS under Network settings:

And on Windows via the Control Panel:

See the Twingate Interface (next to last)

2. Upon start up, the Twingate Client adds a Primary DNS Resolver (on top of the resolver list for my computer) that points to its own DNS servers (100.95.0.25[1-4])

my-mbp16 ~ % scutil --dns
DNS configuration
resolver #1
nameserver[0] : 100.95.0.251
nameserver[1] : 100.95.0.252
nameserver[2] : 100.95.0.253
nameserver[3] : 100.95.0.254
if_index : 29 (utun7)
flags : Supplemental, Request A records
reach : 0x00000003 (Reachable,Transient Connection)
order : 102400
resolver #2
nameserver[0] : 192.168.1.1
if_index : 14 (en0)
flags : Request A records
reach : 0x00020002 (Reachable,Directly Reachable Address)
order : 200000

3. Twingate reconfigures its own DNS

This is to map internal FQDN-like resources like nas.home.int to IP addresses in the CGNAT Range (in this case 100.108.194.142).

4. The Twingate Client modifies the local routing table on the device

This ensures all traffic addressed to IP addresses in the CGNAT range (100.96/12) are dealt with by the local Twingate network interface (utun7 in this case - see the screenshot below).

(Modifying the routing table basically tells the OS: “If you see traffic meant for an IP address in the CGNAT range, it needs to be handled by the Twingate network interface.”)

my-mbp16 ~ % netstat -rn | grep utun7
default link#29 UCSIg utun7
10.0.0.5/32 link#29 UCS utun7
10.0.1.25/32 link#29 UCS utun7
10.0.1.102/32 link#29 UCS utun7
10.0.1.244/32 link#29 UCS utun7
10.128.0.5/32 link#29 UCS utun7
10.128.0.8/32 link#29 UCS utun7
10.128.0.112/32 link#29 UCS utun7
100.95.0.251 172.16.30.1 UGHS utun7
100.95.0.252 172.16.30.1 UGHS utun7
100.95.0.253 172.16.30.1 UGHS utun7
100.95.0.254 172.16.30.1 UGHS utun7
100.96/12 link#29 UCS utun7
172.16.30.1 172.16.30.1 UH utun7
172.16.62.242/32 link#29 UCS utun7
224.0.0/4 link#29 UmCSI utun7
255.255.255.255/32 link#29 UCSI utun7

Altogether, this ensures that:

  • nas.home.int resolves to a CGNAT IP address
  • all traffic for nas.home.int gets handled by the Twingate network interface (because it resolves to a CGNAT IP address and because the routing table tells the OS that all CGNAT IP addresses need to be handled by the Twingate network interface)

What happens to network traffic once it reaches the Twingate network interface?

The Twingate Client has now successfully intercepted traffic for nas.home.int. Now what?

This is where the 3 proxies that are in the Twingate Client intervene. The Twingate Client has 3 proxies, one for each of the 3 protocols: TCP, UDP and ICMP (ping only).

How do network packets go from the Client to the Connector?

Before we answer this question, let’s take a look at what network packets actually contain.

To keep things simple, conceptually a network packet contains:

  • data / a payload (actual information that needs to reach the destination)
  • a destination IP address (where the payload should be delivered)
  • a source IP address (where response packets should be sent to)

In short, think of a single network packet as:

[SOURCE IP][payload][DESTINATION IP]

Back to proxies

The role of the proxy in the Twingate Client is to simply take the payload from the network traffic (without source or destination addresses), and forward it from the Client to the Connector’s proxy via the network.

What does the Connector do with the payload once it receives it?

At this point, the Connector locally resolves the original FQDN nas.home.int (which, from the perspective of the Connector, will correctly resolve to 192.168.1.50 via the private DNS on our home network) and reassembles the payload in a new network packet with:

  • as a source: the Connector’s own IP address (in our case 192.168.1.88)
  • as a destination: the resolved IP address (192.168.1.50)
  • as a payload: the payload sent by the Twingate Client’s proxy

The Connector then sends the packets to the right destination (192.168.1.50), which responds with new network traffic now destined for the Twingate Client.

How does traffic flow back from the Resource to the Client?

The traffic from the destination back to the Twingate Client works the exact opposite way:

  • the application responds with a payload to the Connector (which it gets from the “source IP address” in the original packets sent by the Connector)
  • the Connector’s proxy strips the network packets from source and destination, forwards them to the Twingate Client’s proxy, which in turn reassembles the payload into network packets with the same payload and:
    • as a source: the local IP address of the Twingate network interface (in this case, 172.16.30.1)
    • as a destination: the local IP address of the Client
      This will ensure the traffic from the application flows back to the Twingate Client and therefore the user’s device.

Last updated 5 months ago