Skip to content

Commit

Permalink
ifup-post: always update nameserver & search entries in /etc/resolv.conf
Browse files Browse the repository at this point in the history
  This is complete rework of how we generate the /etc/resolv.conf.

  Fixes:
   * always update 'nameserver' & 'search' entries when DNS* & DOMAIN
     options (respectively) were updated in ifcfg-* files
   * always update the order of 'nameserver' entries when the order of
     DNS* options was updated

  Enhancements:
   * added support for DNS3 option (equals to MAXNS value in GLIBC)
   * added logic to process duplicate DNS* options
   * added logic to process randomly omitted DNS* options (e.g. omitting
     DNS1 while specifying DNS2 and/or DNS3 will still work now)

  This work was based on these two RHEL-7.5 BZs:
  https://bugzilla.redhat.com/show_bug.cgi?id=1364895
  https://bugzilla.redhat.com/show_bug.cgi?id=1357658
  • Loading branch information
deekej authored and Dee'Kej committed Nov 2, 2017
1 parent 995e8ad commit 4da9dba
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 75 deletions.
40 changes: 22 additions & 18 deletions sysconfig/network-scripts/ifdown-post
Expand Up @@ -18,35 +18,39 @@ source_config

/etc/sysconfig/network-scripts/ifdown-routes ${REALDEVICE} ${DEVNAME}

if [ "$PEERDNS" != "no" -o -n "$RESOLV_MODS" -a "$RESOLV_MODS" != "no" ] && \
# Remove duplicate DNS entries and shift them,
# to have always correct condition below...
update_DNS_entries

if ! is_false "${PEERDNS}" || ! is_false "${RESOLV_MODS}" && \
[ "${DEVICETYPE}" = "ppp" -o "${DEVICETYPE}" = "ippp" -o -n "${DNS1}" \
-o "${BOOTPROTO}" = "bootp" -o "${BOOTPROTO}" = "dhcp" ] ; then
if [ -f /etc/resolv.conf.save ]; then
change_resolv_conf /etc/resolv.conf.save
rm -f /etc/resolv.conf.save
fi
if [ "${DEVICETYPE}" = "ppp" -o "${DEVICETYPE}" = "ippp" ]; then
if [ -f /etc/ppp/peers/$DEVICE ] ; then
rm -f /etc/ppp/peers/$DEVICE
if [ -f /etc/resolv.conf.save ]; then
change_resolv_conf /etc/resolv.conf.save
rm -f /etc/resolv.conf.save
fi
if [ "${DEVICETYPE}" = "ppp" -o "${DEVICETYPE}" = "ippp" ]; then
if [ -f /etc/ppp/peers/$DEVICE ] ; then
rm -f /etc/ppp/peers/$DEVICE
fi
fi
fi
fi

# Reset the default route if this interface had a special one
if ! check_default_route ; then
# ISDN device needs special handling dial on demand
if [ "${DEVICETYPE}" = "ippp" -o "${DEVICETYPE}" = "isdn" ] && \
[ "$DIALMODE" = "auto" ] ; then
if [ -z "$GATEWAY" ] ; then
/sbin/ip route add default ${METRIC:+metric} \
${WINDOW:+window $WINDOW} dev ${DEVICE}
[ "$DIALMODE" = "auto" ] ; then
if [ -z "$GATEWAY" ] ; then
/sbin/ip route add default ${METRIC:+metric} \
${WINDOW:+window $WINDOW} dev ${DEVICE}
else
/sbin/ip route add default ${METRIC:+metric} \
${WINDOW:+window $WINDOW} via ${GATEWAY}
fi
else
/sbin/ip route add default ${METRIC:+metric} \
${WINDOW:+window $WINDOW} via ${GATEWAY}
add_default_route ${DEVICE}
fi
else
add_default_route ${DEVICE}
fi
fi

# Reset firewall ZONE to "default":
Expand Down
141 changes: 84 additions & 57 deletions sysconfig/network-scripts/ifup-post
Expand Up @@ -28,67 +28,94 @@ if ! is_true "$NOROUTESET"; then
fi


if ! is_false "$PEERDNS" || [ -n "$RESOLV_MODS" ] && ! is_false "$RESOLV_MODS"; then
[ -n "$MS_DNS1" ] && DNS1=$MS_DNS1
[ -n "$MS_DNS2" ] && DNS2=$MS_DNS2

if [ -z "$DNS1" -a -n "$DNS2" ]; then
DNS1=$DNS2
DNS2=
if ! is_false "${PEERDNS}" || ! is_false "${RESOLV_MODS}"; then
# Obtain the DNS entries when using PPP if necessary:
[ -n "${MS_DNS1}" ] && DNS1="${MS_DNS1}"
[ -n "${MS_DNS2}" ] && DNS2="${MS_DNS2}"

# Remove duplicate DNS entries and shift them, if necessary:
update_DNS_entries

# Determine what regexp we should use (for testing below):
if [ -n "${DNS3}" ]; then
grep_regexp="[^#]?nameserver[[:space:]]+${DNS1}[^#]?nameserver[[:space:]]+${DNS2}[^#]?nameserver[[:space:]]+${DNS3}"
elif [ -n "${DNS2}" ]; then
grep_regexp="[^#]?nameserver[[:space:]]+${DNS1}[^#]?nameserver[[:space:]]+${DNS2}"
elif [ -n "${DNS1}" ]; then
grep_regexp="[^#]?nameserver[[:space:]]+${DNS1}"
else
# No DNS entries used at all ->> match everything.
grep_regexp=".*"
fi

if ( [ -n "$DNS1" ] && ! grep -q "^nameserver $DNS1" /etc/resolv.conf ) ||
( [ -n "$DNS2" ] && ! grep -q "^nameserver $DNS2" /etc/resolv.conf ) &&
tr=$(mktemp /tmp/XXXXXX) ; then
current_replacement="$DNS1"
next_replacement="$DNS2"
search=
(cat /etc/resolv.conf ; echo EOF ; echo EOF) | while read answer ; do
case $answer in
nameserver*|EOF)
if [ -n "$current_replacement" ] ; then
echo "nameserver $current_replacement" >> $tr
if [ -n "$next_replacement" ] ; then
current_replacement="$next_replacement"
next_replacement=
else
current_replacement=
fi
else
if [ "$answer" != EOF ] ; then
echo "$answer" >> $tr
fi
fi
;;
domain*|search*)
if [ -n "$DOMAIN" ]; then
echo "$answer" | while read key value ; do
search="$search $value"
done
else
echo "$answer" >> $tr
fi
;;
*)
echo "$answer" >> $tr
;;
esac
done
if [ -n "$DOMAIN" ]; then
echo "search $DOMAIN $search" >> $tr
# Test if the search field needs updating, or
# if the nameserver entries order should be updated:
if [ -n "${DOMAIN}" ] && ! grep -q "^search.*${DOMAIN}.*$" /etc/resolv.conf ||
! tr --delete '\n' < /etc/resolv.conf | grep -E -q "${grep_regexp}"; then

if tmp_file=$(mktemp); then
search_str=''

while read line; do
case ${line} in

# Skip nameserver entries when at least one DNS option was given
# (at this stage we know that we have to update all the nameserver
# enries anyway -- see below), or copy them if we are changing just
# the 'search' field in /etc/resolv.conf:
nameserver*)
if [[ "${grep_regexp}" != ".*" ]]; then
continue
else
echo "${line}" >> "${tmp_file}"
fi
;;

domain* | search*)
if [ -n "${DOMAIN}" ]; then
read search value < <(echo ${line})
search_str+=" ${value}"
else
echo "${line}" >> "${tmp_file}"
fi
;;

# Keep the rest of the /etc/resolv.conf as it was:
*)
echo "${line}" >> "${tmp_file}"
;;
esac
done < /etc/resolv.conf

# Insert the domain into 'search' field:
if [ -n "${DOMAIN}" ]; then
echo "search ${DOMAIN}${search_str}" >> "${tmp_file}"
fi

# Add the requested nameserver entries:
[ -n "${DNS1}" ] && echo "nameserver ${DNS1}" >> "${tmp_file}"
[ -n "${DNS2}" ] && echo "nameserver ${DNS2}" >> "${tmp_file}"
[ -n "${DNS3}" ] && echo "nameserver ${DNS3}" >> "${tmp_file}"

# backup resolv.conf
cp -af /etc/resolv.conf /etc/resolv.conf.save

# Maintain permissions, but set umask in case it doesn't exist:
umask_old=$(umask)
umask 022

# Update the resolv.conf:
change_resolv_conf "${tmp_file}"

rm -f "${tmp_file}"
umask ${umask_old}
unset tmp_file search_str umask_old
else
net_log $"/etc/resolv.conf was not updated: failed to create temporary file" 'err' 'ifup-post'
fi

# backup resolv.conf
cp -af /etc/resolv.conf /etc/resolv.conf.save

# maintain permissions
# but set umask in case it doesn't exist!
oldumask=$(umask)
umask 022
change_resolv_conf $tr
rm -f $tr
umask $oldumask
fi

unset grep_regexp
fi

# don't set hostname on ppp/slip connections
Expand Down
29 changes: 29 additions & 0 deletions sysconfig/network-scripts/network-functions
Expand Up @@ -697,3 +697,32 @@ net_log()
fi
return 0
}

update_DNS_entries()
{
# Remove duplicate values from DNS options if any:
if [ -n "${DNS3}" ] && [[ "${DNS3}" == "${DNS2}" || "${DNS3}" == "${DNS1}" ]]; then
unset DNS3
fi

if [ -n "${DNS2}" ] && [[ "${DNS2}" == "${DNS1}" ]]; then
unset DNS2
fi

# Shift the DNS options if necessary:
if [ -z "${DNS1}" ] && [ -n "${DNS2}" ]; then
DNS1="${DNS2}"
unset DNS2
fi

if [ -z "${DNS2}" ] && [ -n "${DNS3}" ]; then
DNS2="${DNS3}"
unset DNS3
fi

# We need to check DNS1 again in case only DNS3 was set at all:
if [ -z "${DNS1}" ] && [ -n "${DNS2}" ]; then
DNS1="${DNS2}"
unset DNS2
fi
}

0 comments on commit 4da9dba

Please sign in to comment.