How DNS Works with Twingate
Looking for a primer on DNS?
If you aren’t familiar with DNS, we recommend you check out how DNS works
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 to100.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 now100.95.0.251
What’s a CGNAT IP?
For the purpose of this article, a CGNAT IP is a public IP within a range reserved for public use by Carriers. If you want to know more, head over here and enjoy the read 🙂
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:
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 --dnsDNS 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 utun7default link#29 UCSIg utun710.0.0.5/32 link#29 UCS utun710.0.1.25/32 link#29 UCS utun710.0.1.102/32 link#29 UCS utun710.0.1.244/32 link#29 UCS utun710.128.0.5/32 link#29 UCS utun710.128.0.8/32 link#29 UCS utun710.128.0.112/32 link#29 UCS utun7100.95.0.251 172.16.30.1 UGHS utun7100.95.0.252 172.16.30.1 UGHS utun7100.95.0.253 172.16.30.1 UGHS utun7100.95.0.254 172.16.30.1 UGHS utun7100.96/12 link#29 UCS utun7172.16.30.1 172.16.30.1 UH utun7172.16.62.242/32 link#29 UCS utun7224.0.0/4 link#29 UmCSI utun7255.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 can Twingate see?
The packets are encrypted client-side so Twingate cannot decrypt network traffic in any way.
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.
- as a source: the local IP address of the Twingate network interface (in this case,
If you have made it this far down, thank you for giving this article a read!
Next, you might want to check our Careers page, we are often looking for people as interested in this stuff as we are :).
Last updated 5 months ago