Swapping /etc/hosts files quickly

Last week I wrote a command line script to print out what day of the week it is. This week I wanted to have a command that I could type that would block me from going to websites that get my mind racing and unable to work as part of the DFN “mental PPE” exercise.

One option would have been to set up a RaspberryPi Pi-hole project which works essentially as a DNS server on that can serve your whole network. I didn’t bother with that because I already have a process that mostly works for me involving updating my hosts file to redirect my computer to call up localhost instead of the problematic website.

I prefer to update my computer’s host rather than change the router softer or set up Pi-hole because it has the advantage of only applying to that one device, and it will always work no matter what network my computer joins. I’ve been doing it by hand (sudo nano /etc/host), but since domains frequently need multiple entries (www.website.com, website.com, mobile.website.com) this can make me reluctant to bother. So instead of spending the 5 minutes… I spend an hour+ in a web rabbit hole. Doh.

The shields script takes the inputs up, down and offline to swap in preprepared text files to the /etc/hosts file. Since the script lives in the utilities folder that I mentioned last week, I can run it from any terminal window. Unlike last week, I chose to write the scripts in pure bash instead of python. All of the scripts mentioned can be found in a repo called myutils on GitHub.

#!/bin/bash

##
#
# swaps in prepared files for /etc/hosts file
#
##

ERROR_OUT_MSG="I didn't understand. Try again. (up | down | offline)"

# If nothing specified, bounce out of the script.
if [ $# -eq 0 ]
  then
    echo $ERROR_OUT_MSG
    exit 1
fi

# Get the parameter
SHIELD_SETTING=$1
#Where do the files I'm looking for live
BASE_DIR="Developer/myutils/hosts_file_data_handling/ready"

if [ "$SHIELD_SETTING" = "up" ]; then
    WHICH_FILE="$HOME/$BASE_DIR/all.txt"
    MESSAGE_START="Engaging shields to maximum..."
    MESSAGE_END="Shields at full power..."
elif [ "$SHIELD_SETTING" = "down" ] || [ "$CONFIRM" = "N" ]; then
    WHICH_FILE="$HOME/$BASE_DIR/base.txt"
    MESSAGE_START="Shields being set to normal..."
    MESSAGE_END="Shields at neutral settings..."
elif [ "$SHIELD_SETTING" = "offline" ]; then
    WHICH_FILE="$HOME/$BASE_DIR/clear.txt"
    MESSAGE_START="Shields power down..."
    MESSAGE_END="Shields off"
else
    echo $ERROR_OUT_MSG
    exit 1
fi


say -v Fiona $MESSAGE_START

#Make sure the file exists and is what you want
printf "\n\nThis file?\n\n"
cat $WHICH_FILE || { echo " cat command failed, make sure proper hosts file has been assembled."; exit 1; }

printf "\nAre you sure (Y | N)?"
read CONFIRM

# If confimed, make swap, or confirm didn't make the swap. Exit if not correct confirm text.  
if [ "$CONFIRM" = "yes" ] || [ "$CONFIRM" = "Y" ]; then
    sudo cp $WHICH_FILE /etc/hosts
    echo "Updated hosts file."
    say -v Fiona $MESSAGE_END
elif [ "$CONFIRM" = "no" ] || [ "$CONFIRM" = "N" ]; then
    echo "No change."
else
    echo "I didn't understand. Try again from the top."
    exit 1
fi

echo "Please confirm by viewing hosts file: cat /etc/hosts"

The assemble_hosts_files collates the all.txt, base.txt and clear.txt a collection of files with different url’s in them. In the future this will allow me to make more named sets based on various combinations of files.

#!/bin/bash

##
#
# prepares files for the shields script in bin
#
##

echo "Which host-list set do you want to include? (all | base | clear )"
read WHICH_HOSTS

FILES_TO_MERGE="header.txt"
DESTINATION_FOLDER="ready"
SOURCE_FOLDER="more"
DESTINATION_FILE="$DESTINATION_FOLDER/what_happened.txt"

if [ "$WHICH_HOSTS" = "all" ]; then
    echo "Assembling all host files..."
    DESTINATION_FILE="$DESTINATION_FOLDER/$WHICH_HOSTS.txt"
    FILES_TO_MERGE+=" $SOURCE_FOLDER/*"
    MESSAGE="All files merged."
elif [ "$WHICH_HOSTS" = "base" ]; then
    echo "Getting just the usual suspects..."
    DESTINATION_FILE="$DESTINATION_FOLDER/$WHICH_HOSTS.txt"
    FILES_TO_MERGE+=" $SOURCE_FOLDER/base.txt"
    MESSAGE="Base files merged."
elif [ "$WHICH_HOSTS" = "clear" ]; then
      echo "Getting just the usual suspects..."
      DESTINATION_FILE="$DESTINATION_FOLDER/$WHICH_HOSTS.txt"
      FILES_TO_MERGE="header.txt"
      MESSAGE="Reverted to system defaults only."
  else
    echo "I didn't understand. Try again."
    exit 1
fi


cat $FILES_TO_MERGE > $DESTINATION_FILE

sudo chown root:wheel $DESTINATION_FILE
sudo chmod 644 $DESTINATION_FILE
echo "$DESTINATION_FILE Created and assigned to root."

At the end of this script the created file is set to be owned by root and and only root can write to it. (chown | chmod) This gives me some layer of protection since these files will be swapped in to the hosts file. The folder that contains both the prepared files and the source files also belongs to root.

To make changing the permissions easier, there is also a set_permissions script.

#!/bin/bash

##
#
# fast way to get the permissions shifted for
# the folder/files that root should own. 
#
##

DIRECTORY="ready"
echo updating permissions on $DIRECTORY directory

sudo chown root:wheel $DIRECTORY
sudo find $DIRECTORY -type f -exec chown root:wheel {} \;
sudo find $DIRECTORY -type f -exec chmod 644 {} \;

ls -al $DIRECTORY
#echo "Updated permissions."

The terminal will ask for a password when the script tries to do something over the user’s normal pay grade.

This handy script makes it faster for me to block out websites that distract me when I am working. I do not recommend setting up a chron job to swap in hosts files based on the time of day. While that would be super handy, a malicious change to the hosts file would be kinda a big deal. For a chron job to be safe for this specific script, not only would the script have to be secured, but all the support files (and directories) as well. It’s possible, but it requires care.

To set this up for yourself:

  1. Get the file shields and put it in a folder that is in your PATH if you want it to be runnable from a newly opened terminal window. (about the PATH)
  2. Create a header.txt or at least a back up of your current hosts file. All my files start with the content in a header.txt, containing basic necessary information. Do look at your current /etc/hosts to see how it is set up and save a backup copy.
  3. Make the files you’ll use for the swap. The shields script currently goes looking for an all.txt (everything), a base.txt (the header plus a base set that I pretty much always want to block) and a clear.txt (just the header info). You don’t have to use assemble_hosts_files to create them.
  4. Update the shields script to point to the proper files.
  5. Change the permissions on ALL the files.
    • shields. Since this script performs a sensitive operation, I suggest changing the file’s ownership to root (sudo chown root:wheel shields) and then making only readable, writeable or executable by it’s owner (sudo chmod 700 shields). You will have to use sudo to interact with the file from now on.
    • All the support files should also be transferred to root. Executable scripts and should be 700 or perhaps 744. Directories 744 if you’re using “concatenate all the files in this directory” type script on them. Files 644.
  6. Test that the script runs by typing “sudo shields up” in a new terminal window. Things that can go wrong include
    • Your shields script is not really in a folder in your PATH. Try cd /to/the/directory/with/the/script ; sudo bash shields up
    • Check permissions are what you’d expect (ls -la)
    • That the files you want to swap in actually exist where they’re supposed to.
  7. Look at your hosts file (sudo nano /etc/hosts)
  8. ping one of the blocked domains (ping www.somethingblocked.com) to make sure nothing comes back.
  9. Test shields down and shields offline as well.
  10. Quit open browsers to update any host caching they’re doing.

More Resoruces

Other approaches

bash variable handling and checking

Combining files

Pi-hole

carlyn

I make things that do stuff. The best, though, is teaching others to do the same. Founder of @crashspacela Alum of @ITP_NYU

One thought on “Swapping /etc/hosts files quickly

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.