DEV Community

Cover image for Quick terminal-based DNS switching
Stanley Nguyen
Stanley Nguyen

Posted on

Quick terminal-based DNS switching

This post was originally published on thecodecousins.

Motivation

Most of us, at some point of our lives, have used at least a custom DNS servers configurations for our computers.
Be it for avoiding censorship, faster browsing, security, or bypassing content restriction, we've all tried setting our DNS servers to some public DNS servers like one from Google (remember 8.8.8.8 and 8.8.4.4?).
I myself is also no exception as I have been using 1.1.1.1 for privacy and speed.
Unfortunately, having custom DNS nameservers also comes with some setbacks for someone who uses their computer all the time in all the different places.
With custom DNS servers, this is what you get on a network that tries to block them (together with VPN services etc.)

blocked by network

Another problem that we would have with custom DNS servers is that networks' login pages just don't show up as the default DNS is not being used to redirect us to local network login page.
Of course it would be easy to just remove the configurations as you (most likely) was the one who set them up, how hard would it be to remove?
But what if we need these alternate DNS servers again?
I personally find this way of manually removing and adding them back too much of a hassle.
Hence, I wrapped them in a bash function that does the job for me as all lazy programmers do.

1.1.1.1

Before starting with explaining what I did in the next section, I would like to do a big shout-out to this awesome project that's a combined effort from Cloudflare and APNIC - 1.1.1.1.
It's an effort to provide Internet users with a faster and more secure DNS (it is more than 2x faster than Google Public DNS 🚀🚀🚀).
But more than just that, it is a privacy-first DNS server.
Did you think only these companies like Google, Facebook trying to track all of your activities online (which can be blocked with the awesome Privacy Badger)?
Your ISP also eavesdrops on whichever site you are visiting and sell these data to target you with ads, and they do it through, guess what, DNS resolvers!

1.1.1.1 protects you from all of that for a price of $0 (yes, you read that right).
A FREE, fast, secure DNS server that respects your privacy - sounds too good to be true, doesn't it? But it's an effort towards building a better Internet.
You don't have to take my words for that, read more about it on Cloudflare's and APNIC's blogs.

Switching DNS nameservers via bash

As I mentioned previously, it's too much of a hassle for me to go manually update my DNS configurations via Network Settings UI whenever I jump back and forth between school's and home's networks.
Naturally, I would try to figure out how to do it via my terminal.
That's when I found out about this awesome tool that comes in-built with macOS - networksetup.
With networksetup, changing my DNS config is as simple as

# Adding 1.1.1.1 to my nameservers
networksetup -setdnsservers Wi-Fi 1.1.1.1
# Clear all my alternate nameservers
networksetup -setdnsservers Wi-Fi empty

Now I can easily configure my DNS resolvers to be the same as the instructions for 1.1.1.1 by

# 4 nameservers - 2 IPv4 & 2 IPv6
networksetup -setdnsservers Wi-Fi 1.1.1.1 1.0.0.1 2606:4700:4700::1111 2606:4700:4700::1001

But this is quite lengthy to type as well, even though I would prefer this over Network Preferences UI any day. So I went another level of laziness by wrapping it inside a bash function

function dns1111() {
    networksetup -setdnsservers Wi-Fi 1.1.1.1 1.0.0.1 2606:4700:4700::1111 2606:4700:4700::1001
}

This seems to be pretty neat and does the job, but hold on a second. How about switching it back to empty?
A flag/argument to this bash function would do the job fine but I want to use the least effort as possible and save myself the mental burden of remembering whether my alternate DNS config is empty.
So I thought to myself: "Why not detect the current state and switch the DNS config based on that? Like a literal switch button - you don't have to tell what state you want it to be, just the opposite of what comes before".
With that in mind, I found this option for networksetup that would tell me the current state

networksetup -getdnsservers Wi-Fi

It would list all of my alternate DNS servers, or print out this string There aren't any DNS Servers set on Wi-Fi if there isn't any.
And now I can complete my function, with some cool emojis to signify whether the config has just been applied or removed

function dns1111() {
  if [[ $(networksetup -getdnsservers Wi-Fi) == "There aren't any DNS Servers set on Wi-Fi"* ]]; then
    networksetup -setdnsservers Wi-Fi 1.1.1.1 1.0.0.1 2606:4700:4700::1111 2606:4700:4700::1001 && echo 🚀 🚀 🚀
  else
    networksetup -setdnsservers Wi-Fi empty && echo 🚦 🚦 🚦
  fi
}

Now I can easily switch back and forth between 1.1.1.1 and default DNS configs with just a short command dns1111

Bonus: Linux based machine

Since networksetup is not available not Linux based OSes, we would need to use a different package that helps handle DNS nameservers called dnsmasq.

Install it using your distro's package manager

# this is for Ubuntu
sudo apt-get install dnsmasq

Installing the package will come with a config file /etc/dnsmasq.conf for us to update the nameservers.
I have included my implementation below.
If you have a better approach, don't hesitate to reach out to me at hung.ngn.the@gmail.com

function dns1111() {
  # detect existence of the backup file to see whether the config is in place
  if [ -e /etc/dnsmasq.conf.bak ]]; then
    sudo mv /etc/dnsmasq.conf.bak /etc/dnsmasq.conf && echo 🚦 🚦 🚦
  else
    sudo cp /etc/dnsmasq.conf /etc/dnsmasq.conf.bak && \
    sudo echo "server=1.1.1.1
server=1.0.0.1
server=2606:4700:4700::1111
server=2606:4700:4700::1001" >> /etc/dnsmasq.conf && \
    sudo service dnsmasq restart && \
    sudo service network-manager restart && \
    echo 🚀 🚀 🚀
  fi
}

Top comments (2)

Collapse
 
moopet profile image
Ben Sinclair

I may be missing something; there are real reasons for changing nameservers.

If the problem you want to solve is that certain nameservers don't respond for certain domains - and you're happy to use a less-privacy-conscious nameserver in that case - can't you add all of them, in order of preference and let it all figure it out on its own?

Collapse
 
stanleynguyen profile image
Stanley Nguyen

Hey Ben, thanks for the great suggestion. I didn't think of this when I was trying to solve the problem.
Nevertheless, taking this approach wouldn't save much effort though as whenever I switch to a new network (which often happens if I travel from point to point) I will need to trigger a script to figure out the default NS and append them to the current list. Let me know if I didn't get you correctly