[PATCH] avoid multiple "domain" entries in resolv.conf

Corey Hickey bugfood-ml at fatooh.org
Mon Aug 15 10:50:07 PDT 2016


On 2016-08-10 14:05, Raghavendra Prabhu wrote:
> Hi,
> 
> Thanks for the patch.
> 
> I have following questions regarding this patch:
> 
>   a) In the patch I see that it is handling only for
> modify_resolvconf_generic. What about other modify_*. This issue
> affects them as well. (In my case it uses modify_resolvconf_manager).
> 
>   b)  Instead of choosing only the first domain, is it not possible to
> use 'search' followed by the list of domains.   At least this is how I
> updated the script to do, and that works fine.
> 
>             i) At least, that is how the modify_resolvconf_generic
> seems to be operating when it parses the backup resolv.conf for
> 'search' entries first, if present, appends to them, if not uses the
> 'domain' keyword.

Hmm. Your comments lead me to realize this is more complicated than I
had thought.

1. According to my resolv.conf man page on Debian:
    "The domain and search keywords are mutually exclusive. If more
    than one instance of these keywords is present, the last instance
    wins."
So, setting both "search" and "domain" is a bad idea. I don't know if
this reading is portable to other OSs though.


2. If I read the script correctly, it doesn't actually parse for search
first--it reads resolv.conf line by line, in order, and the presence of
"search" before "domain" in the case statement does not matter. What
does matter is that the script blanks out CISCO_DEF_DOMAIN when it
finds either "search" or "domain", so it only modifies the first one.


3. For "search", CISCO_DEF_DOMAIN is appended. For "domain"
CISCO_DEF_DOMAIN overrides whatever was present.



This all leads to some incorrect behaviors:

a. If "domain" is listed first in the original file, followed by a
later "search", then "domain" potentially gets multiple domains
appended (as noted), and "search" is unmodified. Since "search" is
still last in resolv.conf, this seems to be a no-op except that it
confuses some things that parse the file directly.

b. If "domain" is listed, but "search" is not, then the "domain" line
gets written incorrectly with no "search" line following. On my system,
this results in the first domain being recognized, and the rest ignored.

c. If "search" is first, followed by "domain", then "search" is
appended to but "domain" is ignored. Since "domain" comes later, this
is a syntactically valid no-op.



To be fair, many of these behaviors are the result of incorrect
situations in resolv.conf to begin with--"domain" and "search" should
not both be specified. We do want vpnc-script to do something correct
either way, though.

The following patch is a more intrusive rewrite, but should be much
better. Please let me know if I am missing something or making an
incorrect assumption.


commit cc3450ea460e59366ceeb6819eff1f698479eecc
Author: Corey Hickey <bugfood-ml at fatooh.org>
Date:   Mon 2016-08-15 10:29:50

    rewrite resolv.conf parsing
    
    This patch simplifies parsing and changes behavior in two ways:
    
    1. Domains for searching are now parsed from "search" and "domain"
    lines. Only a "search" line is outputted, since "search" supports
    multiple domains and is mutually exclusive with "domain". The motivation
    for this is to make vpnc-script behave sanely when there are existing
    resolv.conf files with only "domain" or with both "domain" and "search".
    
    2. All original "nameserver" lines are discarded and replaced rather
    than only the number of nameservers from $INTERNAL_IP4_DNS. The
    rationale here is that vpnc-script should be consistent and either
    retain all original nameservers or overwrite all of them. Retaining them
    is problematic because there is a limit of three, and overwriting is
    closer to the original behavior.
    
    The Darwin changes are untested, but are a simple search/replace and
    thus should work fine.
    
    Signed-off-by: Corey Hickey <bugfood-ml at fatooh.org>

diff --git a/vpnc-script b/vpnc-script
index c3aafa4..9cf5e33 100755
--- a/vpnc-script
+++ b/vpnc-script
@@ -369,49 +369,31 @@ modify_resolvconf_generic() {
 # and will be overwritten by vpnc
 # as long as the above mark is intact"
 
-	# If multiple domains are listed, prefer the first for "domain".
-	DOMAIN="${CISCO_DEF_DOMAIN%% *}"
-	# Remember the original value of CISCO_DEF_DOMAIN we need it later
-	CISCO_DEF_DOMAIN_ORIG="$CISCO_DEF_DOMAIN"
-	# Don't step on INTERNAL_IP4_DNS value, use a temporary variable
-	INTERNAL_IP4_DNS_TEMP="$INTERNAL_IP4_DNS"
+	DOMAINS=$CISCO_DEF_DOMAIN
+
 	exec 6< "$RESOLV_CONF_BACKUP"
 	while read LINE <&6 ; do
 		case "$LINE" in
-			nameserver*)
-				if [ -n "$INTERNAL_IP4_DNS_TEMP" ]; then
-					read ONE_NAMESERVER INTERNAL_IP4_DNS_TEMP <<-EOF
-	$INTERNAL_IP4_DNS_TEMP
-EOF
-					LINE="nameserver $ONE_NAMESERVER"
-				else
-					LINE=""
-				fi
-				;;
-			search*)
-				if [ -n "$CISCO_DEF_DOMAIN" ]; then
-					LINE="$LINE $CISCO_DEF_DOMAIN"
-					CISCO_DEF_DOMAIN=""
-				fi
-				;;
-			domain*)
-				if [ -n "$DOMAIN" ]; then
-					LINE="domain $DOMAIN"
-				fi
-				;;
+			# omit; we will overwrite these
+			nameserver*) ;;
+			# extract listed domains and prepend to list
+			domain* | search*) DOMAINS="${LINE#* } $DOMAINS" ;;
+			# retain other lines
+			*) NEW_RESOLVCONF="$NEW_RESOLVCONF
+$LINE" ;;
 		esac
-		NEW_RESOLVCONF="$NEW_RESOLVCONF
-$LINE"
 	done
 	exec 6<&-
 
-	for i in $INTERNAL_IP4_DNS_TEMP ; do
+	for i in $INTERNAL_IP4_DNS ; do
 		NEW_RESOLVCONF="$NEW_RESOLVCONF
 nameserver $i"
 	done
-	if [ -n "$CISCO_DEF_DOMAIN" ]; then
+	# note that "search" is mutually exclusive with "domain";
+	# "search" allows multiple domains to be listed, so use that
+	if [ -n "$DOMAINS" ]; then
 		NEW_RESOLVCONF="$NEW_RESOLVCONF
-search $CISCO_DEF_DOMAIN"
+search $DOMAINS"
 	fi
 	echo "$NEW_RESOLVCONF" > /etc/resolv.conf
 
@@ -453,7 +435,7 @@ search $CISCO_DEF_DOMAIN"
 				# DNS matching when available.  When multiple DNS matching
 				# is present, anything reading the /etc/resolv.conf file
 				# directly will probably not work as intended.
-				#if [ -z "$CISCO_DEF_DOMAIN_ORIG" ]; then
+				#if [ -z "$$CISCO_DEF_DOMAIN" ]; then
 					# Cannot use multiple DNS matching without a domain
 					OVERRIDE_PRIMARY='d.add OverridePrimary # 1'
 				#fi
@@ -471,13 +453,13 @@ search $CISCO_DEF_DOMAIN"
 					set State:/Network/Service/$TUNDEV/IPv4
 					close
 				EOF
-				if [ -n "$CISCO_DEF_DOMAIN_ORIG" ]; then
+				if [ -n "$$CISCO_DEF_DOMAIN" ]; then
 					scutil >/dev/null 2>&1 <<-EOF
 						open
 						get State:/Network/Service/$TUNDEV/DNS
-						d.add DomainName $CISCO_DEF_DOMAIN_ORIG
-						d.add SearchDomains * $CISCO_DEF_DOMAIN_ORIG
-						d.add SupplementalMatchDomains * $CISCO_DEF_DOMAIN_ORIG
+						d.add DomainName $$CISCO_DEF_DOMAIN
+						d.add SearchDomains * $$CISCO_DEF_DOMAIN
+						d.add SupplementalMatchDomains * $$CISCO_DEF_DOMAIN
 						set State:/Network/Service/$TUNDEV/DNS
 						close
 					EOF


Thanks,
Corey



More information about the openconnect-devel mailing list