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:
- 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)
- 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.
- 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. - Update the
shields
script to point to the proper files. - 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 usesudo
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 perhaps744
. Directories744
if you’re using “concatenate all the files in this directory” type script on them. Files644
.
- 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. Trycd /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.
- Your
- Look at your hosts file (
sudo nano /etc/hosts
) - ping one of the blocked domains (
ping www.somethingblocked.com
) to make sure nothing comes back. - Test
shields down
andshields offline
as well. - Quit open browsers to update any host caching they’re doing.
More Resoruces
Other approaches
- (Windows) https://stackoverflow.com/questions/45758809/unable-to-edit-hosts-file-with-python
- https://github.com/mdomi/hosts
bash variable handling and checking
- Working with arguments: https://stackoverflow.com/questions/6482377/check-existence-of-input-argument-in-a-bash-shell-script
- Error handling: https://www.davidpashley.com/articles/writing-robust-shell-scripts/
Combining files
- https://coderwall.com/p/3iysdw/update-etc-hosts-file-efficiently
- https://www.howtogeek.com/278599/how-to-combine-text-files-using-the-cat-command-in-linux/
- https://thoughtbot.com/blog/input-output-redirection-in-the-shell
Pingback: DFN Happy Hour No. 2: Mental PPE : CRASH Space