#!/bin/sh # Script to handle local DNS testing via dnsmasq # supports add/remove/list of CNAME and TXT records # on dnsmasq config changes it will restart the dnsmasq container # it also asks to add the record to the /etc/hosts file if --no-hosts is not used # prep set -e # ensure directory exists before using the file mkdir -p ./docker/dnsmasq/dnsmasq.d # dedicated sndev.conf file DNSMASQ_CONF_PATH="./docker/dnsmasq/dnsmasq.d/sndev.conf" # check if running on Windows or macOS # this script doesn't support Windows /etc/hosts editing # sed -i has different syntax on macOS/BSD and Linux IS_WINDOWS=false IS_DARWIN=false OS_NAME=$(uname -s) case "$OS_NAME" in MINGW*|CYGWIN*|MSYS*) IS_WINDOWS=true ;; Darwin*) IS_DARWIN=true ;; esac # general usage usage() { cat < [--no-hosts] remove [--no-hosts] list FLAGS --no-hosts Skip asking to add/remove record to /etc/hosts Useful if you're using dnsmasq [127.0.0.1:5353] as your DNS server. EXAMPLES $ sndev domains dns add cname www.pizza.sndev sn.sndev $ sndev domains dns remove txt _snverify.www.pizza.sndev "7vfyvQO...vMALqvqkTQ" $ sndev domains dns list cname|txt EOF exit 1 } # handle flags while [ $# -gt 0 ]; do case "$1" in -h|--help) usage ;; *) break ;; esac done INTENT=$1 # add, remove, list TYPE=$2 # cname, txt NAME=$3 # www.pizza.com VALUE=$4 # stacker.news or "7vfyvQO...vMALqvqkTQ=" NO_HOSTS=false # handled via --no-hosts flag # creates a line compatible with dnsmasq config file prepare_line() { if [ "$TYPE" = "cname" ]; then LINE="cname=${NAME},${VALUE}" elif [ "$TYPE" = "txt" ]; then escaped_quotes=$(printf '%s' "$VALUE" | sed 's/"/\\"/g') LINE="txt-record=${NAME},\"${escaped_quotes}\"" else echo "Invalid record type: $TYPE" usage fi } # if we're adding or removing a record, we need to check for required args if [ "$INTENT" = "add" ] || [ "$INTENT" = "remove" ]; then if [ $# -lt 4 ]; then echo "Not enough arguments" usage else prepare_line # prepare the line for the dnsmasq config file shift 4 # 4 args: intent, type, name, value # we need to get the --no-hosts flag if it's present if [ "$1" = "--no-hosts" ]; then NO_HOSTS=true shift fi fi # if we're listing records, we need to have at least the TYPE arg elif [ "$INTENT" = "list" ] && [ $# -lt 2 ]; then echo "No type provided" usage fi # add a record to the dnsmasq config add_record() { # check if the record already exists if grep -Fxq "$LINE" "$DNSMASQ_CONF_PATH"; then echo "Record already exists: $LINE" exit 1 fi # add the record to the dnsmasq config echo "Adding record: $LINE" printf "%s\n" "$LINE" >> "$DNSMASQ_CONF_PATH" # if we're adding a CNAME record and --no-hosts is not used, we need to ask to add the record to the /etc/hosts file if [ "$TYPE" = "cname" ] && [ "$NO_HOSTS" = false ]; then # dnsmasq pamphlet printf " While sndev will use dnsmasq DNS server, your system won't use it by default. You can either manually point DNS to 127.0.0.1:5353 to access it system-wide, or add this record to /etc/hosts to access it via browser.\n\n" # ask to add the record to the /etc/hosts file printf "[sudo] Do you want to add '127.0.0.1 %s' to /etc/hosts? [y/N] " "$NAME" read -r response case "$response" in [Yy]*) # add the record to the /etc/hosts file if ! add_record_to_hosts "$NAME"; then echo "/etc/hosts hasn't been touched." fi ;; esac fi echo "Done." exit 0 } # remove a record from the dnsmasq config remove_record() { # check if the record exists if ! grep -Fxq "$LINE" "$DNSMASQ_CONF_PATH"; then echo "Can't find record: $LINE" echo "The record may have been removed or the name/value is incorrect or incomplete." echo "Use 'sndev domains dns list' to see all records." exit 1 fi # remove the record from the dnsmasq config echo "Removing record: $LINE" if [ "$IS_DARWIN" = true ]; then sed -i '' "/^$LINE$/d" "$DNSMASQ_CONF_PATH" else sed -i "/^$LINE$/d" "$DNSMASQ_CONF_PATH" fi # if we're removing a CNAME record and --no-hosts is not used, we need to ask to remove the record from the /etc/hosts file if [ "$TYPE" = "cname" ] && [ "$NO_HOSTS" = false ]; then # ask to remove the record from the /etc/hosts file printf "[sudo] Do you want to remove this record from /etc/hosts? [y/N] " read -r response case "$response" in [Yy]*) # remove the record from the /etc/hosts file if ! remove_record_from_hosts "$NAME"; then echo "/etc/hosts hasn't been touched." fi ;; esac fi echo "Done." exit 0 } # list all records of a given type list_records() { if [ "$TYPE" = "txt" ]; then TYPE="txt-record" fi grep "^$TYPE=" "$DNSMASQ_CONF_PATH" || echo "No $TYPE records found." } # add a record to the /etc/hosts file add_record_to_hosts() { domain="$1" # this script doesn't support Windows /etc/hosts editing if [ "$IS_WINDOWS" = true ]; then echo "Adding records to /etc/hosts via this script is not supported on Windows" return 1 fi # check if the record already exists in the /etc/hosts file if check_record_hosts_exists "$domain"; then echo "Record already exists in /etc/hosts: $domain" return 1 fi # add the record to the /etc/hosts file echo "Adding record to /etc/hosts: $domain" echo "This operation will require sudo privileges" if ! echo "127.0.0.1 $domain" | sudo tee -a "/etc/hosts" > /dev/null; then echo "Failed to add record to /etc/hosts" return 1 fi echo "$domain added to /etc/hosts." echo "You can now access http://$domain:3000 via browser." return 0 } remove_record_from_hosts() { domain="$1" # this script doesn't support Windows /etc/hosts editing if [ "$IS_WINDOWS" = true ]; then echo "Removing records from /etc/hosts via this script is not supported on Windows" return 1 fi # check if the record exists in the /etc/hosts file if ! check_record_hosts_exists "$domain"; then echo "Record not found in /etc/hosts: $domain" return 1 fi # remove the record from the /etc/hosts file echo "Removing record from /etc/hosts: $domain" echo "This operation will require sudo privileges" if [ "$IS_DARWIN" = true ]; then if ! sudo sed -i '' "/^127.0.0.1 $domain$/d" "/etc/hosts" 2>/dev/null; then echo "Failed to remove record from /etc/hosts." return 1 fi else if ! sudo sed -i "/^127.0.0.1 $domain$/d" "/etc/hosts" 2>/dev/null; then echo "Failed to remove record from /etc/hosts." return 1 fi fi echo "$domain removed from /etc/hosts." return 0 } # check if a record exists in the /etc/hosts file check_record_hosts_exists() { domain="$1" # grep for the record if grep -Fxq "127.0.0.1 $domain" "/etc/hosts"; then return 0 fi return 1 } # switch intents case "$INTENT" in add) add_record ;; remove) remove_record ;; list) list_records ;; *) usage ;; esac