Project: IPFire
Code Location: git://git.ipfire.org/network.gitmaster
Browse
/
Download File
functions.dns
#!/bin/bash
###############################################################################
#                                                                             #
# IPFire.org - A linux based firewall                                         #
# Copyright (C) 2012  IPFire Network Development Team                         #
#                                                                             #
# This program is free software: you can redistribute it and/or modify        #
# it under the terms of the GNU General Public License as published by        #
# the Free Software Foundation, either version 3 of the License, or           #
# (at your option) any later version.                                         #
#                                                                             #
# This program is distributed in the hope that it will be useful,             #
# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
# GNU General Public License for more details.                                #
#                                                                             #
# You should have received a copy of the GNU General Public License           #
# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
#                                                                             #
###############################################################################

# Set this to true if localhost should be added as the first DNS server.
DNS_USE_LOCAL_RESOLVER=true
NETWORK_CONFIG_FILE_PARAMS="${NETWORK_CONFIG_FILE_PARAMS} DNS_USE_LOCAL_RESOLVER"

# Set this option to true if the DNS servers should be queried in a random order.
# This is useful to load balance between multiple servers.
DNS_RANDOMIZE=false
NETWORK_CONFIG_FILE_PARAMS="${NETWORK_CONFIG_FILE_PARAMS} DNS_RANDOMIZE"

DNS_SEARCH_DOMAINS=""
NETWORK_CONFIG_FILE_PARAMS="${NETWORK_CONFIG_FILE_PARAMS} DNS_SEARCH_DOMAINS"

# Set this option to true if the DNS servers should be advertised by
# radvd.
DNS_ADVERTISE_SERVERS="true"

DNS_SERVER_CONFIG_FILE="${NETWORK_CONFIG_DIR}/dns-servers"
NETWORK_CONFIG_DNS_SERVER_PARAMS="server priority"

# Set the default priority for DNS servers.
DNS_SERVER_DEFAULT_PRIORITY="100"
DNS_SERVER_DYNAMIC_PRIORITY="10"

# Path to the configuration file of the DNS resolver.
RESOLV_CONF="/etc/resolv.conf"

function dns_get_hostname() {
	local address=${1}
	assert isset address

	(
		unset HOSTNAME
		eval $(ipcalc -h ${address} 2>/dev/null)
		echo "${HOSTNAME}"
	)
}

function dns_server_list() {
	[ -r "${DNS_SERVER_CONFIG_FILE}" ] || return ${EXIT_OK}

	local line
	local ${NETWORK_CONFIG_DNS_SERVER_PARAMS}

	local format="%-20s %-8s"
	print "${format}" "SERVER" "PRIORITY"

	while read -r line; do
		dns_server_parse_line ${line} || continue

		print "${format}" "${server}" "${priority}"
	done < ${DNS_SERVER_CONFIG_FILE}

	return ${EXIT_OK}
}

function dns_server_list_sorted() {
	[ -r "${DNS_SERVER_CONFIG_FILE}" ] || return ${EXIT_OK}

	local servers=$(
		# First get all servers from the configuration file.
		while read -r line; do
			dns_server_parse_line ${line} || continue

			print "%d %s" "${priority}" "${server}"
		done < ${DNS_SERVER_CONFIG_FILE}

		# Then get all dynamically assigned DNS servers.
		dns_server_get_zone_name_servers
	)

	# Nothing to do if we have got no DNS servers.
	isset servers || return ${EXIT_OK}

	# Sort everything we have got.
	servers=$(sort -g -k1 <<< "${servers}")

	# Remove the priority bit.
	local server server_list
	while read -r priority server; do
		list_append server_list "${server}"
	done <<< "${servers}"

	# Return the list but remove duplicate entries, keeping
	# the first and removing all others.
	list_unique ${server_list}

	return ${EXIT_OK}
}

function dns_server_add() {
	local server=${1}
	assert isset server

	local priority=${2}
	if ! isset priority; then
		priority="${DNS_SERVER_DEFAULT_PRIORITY}"
	fi
	assert isinteger priority

	# Add a new line to the configuration file.
	print "server=\"%s\" priority=\"%d\"" "${server}" "${priority}" \
		>> ${DNS_SERVER_CONFIG_FILE}

	return ${EXIT_OK}
}

function dns_server_exists() {
	local entry=${1}
	assert isset entry

	[ -r "${DNS_SERVER_CONFIG_FILE}" ] || return ${EXIT_FALSE}

	local line ${NETWORK_CONFIG_DNS_SERVER_PARAMS}
	while read -r line; do
		dns_server_parse_line ${line} || continue

		[ "${entry}" = "${server}" ] && return ${EXIT_TRUE}
	done < ${DNS_SERVER_CONFIG_FILE}

	return ${EXIT_FALSE}
}

function dns_server_remove() {
	local entry=${1}
	assert isset entry

	# Check if the DNS server configuration file exists.
	[ -r "${DNS_SERVER_CONFIG_FILE}" ] || return ${EXIT_ERROR}

	# Create a tempfile.
	local tempfile=$(mktemp)

	local line ${NETWORK_CONFIG_DNS_SERVER_PARAMS}
	while read -r line; do
		dns_server_parse_line ${line} || continue

		# Skip the line with the server we are searching for.
		[ "${entry}" = "${server}" ] && continue

		# Re-add the old line.
		print "${line}"
	done < ${DNS_SERVER_CONFIG_FILE} > ${tempfile}

	# Overwrite the old content without the entry that has just been removed.
	fread "${tempfile}" > ${DNS_SERVER_CONFIG_FILE}

	# Remove the temporary file.
	rm -f ${tempfile}

	return ${EXIT_OK}
}

function dns_server_flush() {
	: > ${DNS_SERVER_CONFIG_FILE}
}

function dns_server_parse_line() {
	local arg

	for arg in ${NETWORK_CONFIG_DNS_SERVER_PARAMS}; do
		assign "${arg}" ""
	done

	while read -r arg; do
		case "${arg}" in
			server=*)
				server=$(cli_get_val ${arg})
				;;
			priority=*)
				priority=$(cli_get_val ${arg})
				;;
		esac
	done <<< "$(args $@)"

	# The server address must be set.
	isset server || return ${EXIT_ERROR}

	# The server address must also be a valid IP address.
	ip_is_valid ${server} || return ${EXIT_ERROR}

	# If priority is set, it must be an integer number.
	if isset priority; then
		isinteger priority || return ${EXIT_ERROR}

	# Otherwise assign the default priority.
	else
		priority=${DNS_SERVER_DEFAULT_PRIORITY}
	fi

	return ${EXIT_OK}
}

# Update resolv.conf(5) when initializing the network.
init_register dns_generate_resolvconf

function dns_generate_resolvconf() {
	local file=${RESOLV_CONF}

	log INFO "Updating resolver configuration..."

	config_header "resolver configutation file" > ${file}

	if enabled DNS_RANDOMIZE; then
		print "option rotate\n" >> ${file}
	fi

	# Write search domains to file.
	print "# Search domains" >> ${file}

	local domain
	for domain in $(dns_get_search_domains); do
		print "search ${domain}"
	done >> ${file}

	print "\n# Nameservers" >> ${file}

	# Add the local resolver as the first DNS server if enabled.
	if enabled DNS_USE_LOCAL_RESOLVER; then
		print "nameserver ::1" >> ${file}
	fi

	# Dump all DNS servers.
	for server in $(dns_server_list_sorted); do
		print "nameserver ${server}"
	done >> ${file}
}

function dns_get_search_domains() {
	# Add search domains.
	local search_domains="$(unquote ${DNS_SEARCH_DOMAINS})"

	# Get search domains from DHCP clients, etc.
	local domain proto zone

	for zone in $(zones_get_all); do
		for proto in ${IP_SUPPORTED_PROTOCOLS}; do
			domain=$(routing_db_get ${zone} ${proto} domain-name)
			isset domain || continue

			list_append search_domains "${domainname}"
		done
	done

	# Sort out duplicate entries.
	list_unique ${search_domains}
}

function dns_server_get_zone_name_servers() {
	local priority proto server servers zone

	for zone in $(zones_get_all); do
		for proto in ${IP_SUPPORTED_PROTOCOLS}; do
			priority=$(routing_db_get ${zone} ${proto} domain-name-servers-priority)
			isset priority || priority="${DNS_SERVER_DYNAMIC_PRIORITY}"

			servers=$(routing_db_get ${zone} ${proto} domain-name-servers)
			for server in ${servers}; do
				print "${priority} ${server}"
			done
		done
	done
}