#!/bin/bash
#
# Copyright (c) 2008 SUSE LINUX Products GmbH, Nuernberg, Germany.
# 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 2 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 .
#
# Author: Michael Calmer
# Sven Schober
# Marius Tomaschewski
#
##
unset POSIXLY_CORRECT ; set +o posix # we're using non-posix bash features
if test "$UID" != "0" -a "$USER" != root -a -z "$ROOT" ; then
echo "You must be root to start $0." >&2
exit 1
fi
# The environment variable ROOT indicates the root of the system to be
# managed by SuSEconfig when that root is not '/'
r="$ROOT"
. "$r/etc/sysconfig/network/scripts/functions.netconfig"
PROGNAME="${0##*/}"
STATEDIR="$r/var/run/netconfig"
debug "$PROGNAME Module called"
. "$r/etc/sysconfig/network/config"
unset DNS_SERVERS ${!DNS_SERVERS_*}
DESTFILE="$r/var/run/dnsmasq-forwarders.conf"
TMP_FILE=""
# *********************
# FUNCTIONS
# *********************
function write_dnsmasq_forwarders ()
{
test -z "$1" && return 1
debug "write_dnsmasq_forwarders: $1 "
local NAMESERVER=()
# DESTFILE may be a symlink on a read only /-fs
DST_FILE=`read_symlink "${DESTFILE}"`
TMP_FILE=`mktemp "${DST_FILE}.XXXXXX" 2>/dev/null || \
mktemp -t "${DST_FILE##*/}.XXXXXX"` || return 1
if test ! -s "$DST_FILE" ; then
touch "$DST_FILE" ; chmod 644 "$DST_FILE"
fi
# * copy dest => tmp to get the file attributes
# * remove the content
# * print a warning on top of this file
#cp -p "$DST_FILE" "$TMP_FILE"
# set explicit mode on tmp file instead to preserve the
# mode of original file that can be wrong (bnc#428458)
chmod 644 "$TMP_FILE"
cat << EOT > "$TMP_FILE"
### $DESTFILE file autogenerated by netconfig!
#
# Before you change this file manually, consider to define the
# static DNS configuration using the following variables in the
# /etc/sysconfig/network/config file:
# NETCONFIG_DNS_STATIC_SEARCHLIST
# NETCONFIG_DNS_STATIC_SERVERS
# NETCONFIG_DNS_FORWARDER
# or disable DNS configuration updates via netconfig by setting:
# NETCONFIG_DNS_POLICY=''
#
# See also the netconfig(8) manual page and other documentation.
#
# Note: Manual change of this file disables netconfig too, but
# may get lost when this file contains comments or empty lines
# only, the netconfig settings are same with settings in this
# file and in case of a "netconfig update -f" call.
#
### Please remove (at least) this line when you modify the file!
EOT
for ns in $1; do
# skip duplicates
for os in ${NAMESERVER[@]} ; do
[ "x$ns" == "x$os" ] && continue 2
done
# resolv.conf supports up to 3 nameserver,
# but AFAIK not for dnsmasq ...
#[ ${#NAMESERVER[@]} -lt 3 ] || break
NAMESERVER=(${NAMESERVER[@]} ${ns})
done
if [ ${#NAMESERVER[@]} -gt 0 ]; then
{
for ns in ${NAMESERVER[@]}; do
echo "nameserver ${ns}"
done
} >> "$TMP_FILE"
fi
netconfig_check_md5_and_move "$TMP_FILE" "$DESTFILE" ".netconfig" TMP_FILE
return $?
}
function get_dns_settings()
{
local cfg=$1 ; shift
test "x$cfg" = x && return 1
local SERVICE DNSSERVERS
local var idx DNS_SERVERS
debug "exec get_dns_settings: $cfg"
get_variable "SERVICE" "$cfg"
idx=`get_ranking_idx "$SERVICE" "$@"`
debug " get_dns_settings: service '$SERVICE' => rank '$idx'"
var="DNS_SERVERS_$idx"
DNS_SERVERS=(${!var})
get_variable "DNSSERVERS" "$cfg"
if [ "x$DNSSERVERS" != "x" ]; then
DNS_SERVERS=(${DNS_SERVERS[@]} $DNSSERVERS)
fi
unset DNSSERVERS
eval "${var}='${DNS_SERVERS[@]}'"
debug " get_dns_settings: ${var}='${!var}'"
debug "exit get_dns_settings: $cfg"
return 0
}
function manage_interfaceconfig()
{
local cfg dir="$1" ; shift
test "x$dir" != x -a -d "$dir" || return 1
debug "exec manage_interfaceconfig: $dir"
for cfg in `ls -X -r "$dir/" 2>/dev/null`; do
get_dns_settings "$dir/$cfg" "$@"
done
debug "exit manage_interfaceconfig: $dir"
return 0
}
# *********************
# EXECUTION STARTS HERE
# *********************
if [ "$NETCONFIG_DNS_FORWARDER" != "dnsmasq" ]; then
exit 0;
fi
# just for the case we need the original value...
_NETCONFIG_DNS_RANKING="$NETCONFIG_DNS_RANKING"
case "$_NETCONFIG_DNS_RANKING" in
auto) _NETCONFIG_DNS_RANKING="$NETCONFIG_DNS_RANKING_DEFAULT" ;;
none) _NETCONFIG_DNS_RANKING="" ;;
esac
# just for the case we need the original value...
_NETCONFIG_DNS_POLICY=`netconfig_policy "$NETCONFIG_DNS_POLICY"`
if [ "x$_NETCONFIG_DNS_POLICY" = "x" ]; then
#
# empty policy means do not touch anything.
# successful exit.
#
exit 0;
fi
sf=0
_g=1
# disable filename glob expansion if needed
shopt -o -q noglob || _g=0
[ $_g ] && shopt -o -s noglob
for POL in $_NETCONFIG_DNS_POLICY; do
shopt -o -u noglob
case "$POL" in
(NetworkManager)
debug "Use NetworkManager policy merged settings"
cfg="$STATEDIR/NetworkManager.netconfig"
if [ -r "$cfg" ] ; then
get_dns_settings "$cfg" "$_NETCONFIG_DNS_RANKING"
fi
break
;;
(STATIC)
debug "Keep Static"
DNS_SERVERS_1="$DNS_SERVERS_1 $NETCONFIG_DNS_STATIC_SERVERS"
;;
(STATIC_FALLBACK)
debug "Static Fallback"
sf=1
;;
(*)
debug "Other: $POL"
for IFDIR in $STATEDIR/$POL; do
test -d "$IFDIR" -a \
-d "/sys/class/net/${IFDIR##*/}" || continue
# proceed every interface we find with this match
manage_interfaceconfig "$IFDIR" "$_NETCONFIG_DNS_RANKING"
done
;;
esac
done
[ $_g ] && shopt -o -u noglob
if [ $sf -eq 1 -a -z "$DNS_SERVERS_0" \
-a -z "$DNS_SERVERS_1" ]; then
DNS_SERVERS_2="$DNS_SERVERS_2 $NETCONFIG_DNS_STATIC_SERVERS"
fi
# filter out loopback addresses and all own IPs that would case a loop
own_ips=(`ip addr show 2>/dev/null | \
LANG=C LC_ALL=C gawk '/[ ]+(inet|inet6)[ ]+/ { sub("/.*","",$2); print $2; }' 2>/dev/null`)
for idx in 0 1 2 ; do
var="DNS_SERVERS_$idx"
val=(${!var})
new=()
for ns in ${val[@]} ; do
case $ns in
127.*|::1) ;;
*)
for ip in "${own_ips[@]}" ; do
test "x$ip" = "x" && continue
test "x$ip" = "x$ns" && continue 2
done
new+=("$ns")
;;
esac
done
eval "${var}='${new[@]}'"
done
write_dnsmasq_forwarders "$DNS_SERVERS_0 $DNS_SERVERS_1 $DNS_SERVERS_2"
RET=$?
if [ $RET -eq 1 ]; then
# nothing changed; we are finished
exit 0
elif [ $RET -eq 2 ]; then
# user modified the config. Copy aborted
echo "ATTENTION: You have modified $DESTFILE. Leaving it untouched..."
echo "You can find my version in $TMP_FILE ..."
exit 20
fi
# here we should restart services if needed
# => not needed, dnsmasq polls and reloads itself
exit 0;
# vim: set ts=8 sts=4 sw=4 ai et: