Current File : //lib/svc/share/net_include.sh
#!/bin/sh
#
# Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
#
# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T.
# All rights reserved.
#

# commands
CAT=/usr/bin/cat
CP=/usr/bin/cp
DLADM=/usr/sbin/dladm
GREP=/usr/bin/grep
IFCONFIG=/usr/sbin/ifconfig
IPADM=/usr/sbin/ipadm
NAWK=/usr/bin/nawk
NETADM=/usr/sbin/netadm
NETCFG=/usr/sbin/netcfg
NETSTAT=/usr/bin/netstat
NSCFG=/usr/sbin/nscfg
PFEXEC=/usr/bin/pfexec
RM=/usr/bin/rm
SVCADM=/usr/sbin/svcadm
SVCCFG=/usr/sbin/svccfg
SVCPROP=/usr/bin/svcprop

# FMRI consts
AUTOFS_FMRI="svc:/system/filesystem/autofs:default"
DNS_CLIENT_FMRI="svc:/network/dns/client:default"
IPSEC_IKE_FMRI="svc:/network/ipsec/ike:default"
IPSEC_IKEV2_FMRI="svc:/network/ipsec/ike:ikev2"
IPSEC_POLICY_FMRI="svc:/network/ipsec/policy:default"
IPFILTER_FMRI="svc:/network/ipfilter:default"
LDAP_CLIENT_FMRI="svc:/network/ldap/client:default"
MAPID_FMRI="svc:/network/nfs/mapid:default"
NIS_CLIENT_FMRI="svc:/network/nis/client:default"
NIS_DOMAIN_FMRI="svc:/network/nis/domain:default"
NP_DEFAULT_FMRI="svc:/network/physical:default"
NS_SWITCH_FMRI="svc:/system/name-service/switch"
ROUTING_SETUP_FMRI="svc:/network/routing-setup:default"

# location of directories
LOC_PATH=/etc/nwam/loc
VOL_NETCFG_PATH=$SMF_SYSVOL_FS/netcfg

NET_INADDR_ANY="0.0.0.0"
NET_IN6ADDR_ANY_INIT="::0"

# properties
SRTS_FILE_PROP="config/static_routes_file"

# Print warnings to console
warn_failed_ifs() {
	echo "Failed to $1 interface(s):$2" >/dev/msglog
}

#
# shcat file
#   Simulates cat in sh so it doesn't need to be on the root filesystem.
#
shcat() {
        while [ $# -ge 1 ]; do
                while read i; do
                        echo "$i"
                done < $1
                shift
        done
}

net_record_err()
{
	message=$1
	err=$2

	echo "$message" | smf_console
	if [ $err -ne 0 ]; then
		echo "Error code = $err" | smf_console
	fi
}

#
# Check for use of the default "Port VLAN Identifier" (PVID) -- VLAN 1.
# If there is one for a given interface, then warn the user and force the
# PVID to zero (if it's not already set).  We do this by generating a list
# of interfaces with VLAN 1 in use first, and then parsing out the
# corresponding base datalink entries to check for ones without a
# "default_tag" property.
#
update_pvid()
{
	datalink=/etc/dladm/datalink.conf

	(
		# Find datalinks using VLAN 1 explicitly
		# configured by dladm
		$NAWK '
			/^#/ || NF < 2 { next }
			{ linkdata[$1]=$2; }
			/;vid=int,1;/ {
				sub(/.*;linkover=int,/, "", $2);
				sub(/;.*/, "", $2);
				link=linkdata[$2];
				sub(/name=string,/, "", link);
				sub(/;.*/, "", link);
				print link;
			}' $datalink
	) | ( /usr/bin/sort -u; echo END; $CAT $datalink ) | $NAWK '
	    /^END$/ { state=1; }
	    state == 0 { usingpvid[++nusingpvid]=$1; next; }
	    /^#/ || NF < 2 { next; }
	    {
		# If it is already present and has a tag set,
		# then believe it.
		if (!match($2, /;default_tag=/))
			next;
		sub(/name=string,/, "", $2);
		sub(/;.*/, "", $2);
		for (i = 1; i <= nusingpvid; i++) {
			if (usingpvid[i] == $2)
				usingpvid[i]="";
		}
	    }
	    END {
		for (i = 1; i <= nusingpvid; i++) {
			if (usingpvid[i] != "") {
				printf("Warning: default VLAN tag set to 0" \
				    " on %s\n", usingpvid[i]);
				cmd=sprintf("$DLADM set-linkprop -p " \
				    "default_tag=0 %s\n", usingpvid[i]);
				system(cmd);
			}
		}
	    }'
}

#
# service_exists fmri
#
# returns success (0) if the service exists, 1 otherwise.
#
service_exists()
{
	$SVCCFG -s $1 listpg > /dev/null 2>&1
	if [ $? -eq 0 ]; then
		return 0;
	fi
	return 1;
}

#
# service_is_enabled fmri
#
# returns success (0) if the service is enabled (permanently or
# temporarily), 1 otherwise.
#
service_is_enabled()
{
	#
	# The -c option must be specified to use the composed view
	# because the general/enabled property takes immediate effect.
	# See Example 2 in svcprop(1).
	#
	# Look at the general_ovr/enabled (if it is present) first to
	# determine the temporarily enabled state.
	#
	tstate=$($SVCPROP -c -p general_ovr/enabled $1 2>/dev/null)
	if [ $? -eq 0 ]; then
		[ "$tstate" = "true" ] && return 0
		return 1
	fi

        state=$($SVCPROP -c -p general/enabled $1 2>/dev/null)
	[ "$state" = "true" ] && return 0
	return 1
}

#
# service_is_in_maintenance fmri
#
# return success (0) if the service is in maintenance state, 1 otherwise.
#
service_is_in_maintenance()
{
	state=$(/usr/bin/svcs -Ho STATE $1 2>/dev/null)
	[ "$state" = "maintenance" ] && return 0
	return 1
}

#
# is_valid_v4addr addr
#
# Returns 0 if a valid IPv4 address is given, 1 otherwise.
#
is_valid_v4addr()
{ 
	echo $1 | /usr/xpg4/bin/awk 'NF != 1 { exit 1 } \
	$1 !~ /^((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}\
(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])$/ \
	{ exit 1 }'
	return $?
}

#
# is_valid_v6addr addr
#
# Returns 0 if a valid IPv6 address is given, 1 otherwise.
#
is_valid_v6addr()
{
	echo $1 | /usr/xpg4/bin/awk 'NF != 1 { exit 1 } \
	# 1:2:3:4:5:6:7:8
	$1 !~ /^([a-fA-F0-9]{1,4}:){7}[a-fA-F0-9]{1,4}$/ &&
	# 1:2:3::6:7:8
	$1 !~ /^([a-fA-F0-9]{1,4}:){0,6}:([a-fA-F0-9]{1,4}:){0,6}\
[a-fA-F0-9]{1,4}$/ && 
	# 1:2:3::
	$1 !~ /^([a-fA-F0-9]{1,4}:){0,7}:$/ &&
	# ::7:8
	$1 !~ /^:(:[a-fA-F0-9]{1,4}){0,6}:[a-fA-F0-9]{1,4}$/ && 
	# ::f:1.2.3.4
	$1 !~ /^:(:[a-fA-F0-9]{1,4}){0,5}:\
((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}\
(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])$/ &&
	# a:b:c:d:e:f:1.2.3.4
	$1 !~ /^([a-fA-F0-9]{1,4}:){6}\
((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}\
(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])$/ \
{ exit 1 }'
	return $?
}

#
# is_valid_addr addr
#
# Returns 0 if a valid IPv4 or IPv6 address is given, 1 otherwise.
#
is_valid_addr()
{
	is_valid_v4addr $1 || is_valid_v6addr $1
}

#
# netmask2plen netmask
#
# Converts a subnet mask to its CIDR prefixlen.
#
netmask2plen ()
{
	mask=$1
	plen=0
	ocnt=1
	done=0

	pmask=$mask
	while [ $ocnt -le 4 -a "$pmask" != "" ]
	do
		octet=`echo $pmask | /usr/bin/cut -f 1-1 -d '.'`
		ocnt=`expr $ocnt + 1`

		if [ $octet -lt 0 -o $octet -ge 256 ]; then
			echo "Failed to compute prefixlen from subnet mask."
			echo "$mask is not a valid subnet mask."
			return 1
		fi

		if [ $done -ne 0 -a $octet -ne 0 ]; then
			echo "Failed to compute prefixlen from" \
			    "subnet mask."
			echo "$mask is a non-contiguous subnet mask."
			return 1
		fi

		case $octet in
		'255' )
			plen=`expr $plen + 8`
			;;
		'0' )
			;;
		'254' )
			plen=`expr $plen + 7`
			;;
		'252' )
			plen=`expr $plen + 6`
			;;
		'248' )
			plen=`expr $plen + 5`
			;;
		'240' )
			plen=`expr $plen + 4`
			;;
		'224' )
			plen=`expr $plen + 3`
			;;
		'192' )
			plen=`expr $plen + 2`
			;;
		'128' )
			plen=`expr $plen + 1`
			;;
		*)
			echo "Failed to compute prefixlen from" \
			    "subnet mask."
			echo "$mask is a non-contiguous subnet mask."
			return 1
			;;
		esac

		if [ $octet -ne 255 ]; then
			done=1
		fi

		tmask=`echo $pmask | /usr/bin/cut -f 2- -d '.'`
		if [ "$tmask" = "$pmask" ]; then
			pmask=""
		else
			pmask=$tmask
		fi
	done
	if [ "$pmask" != "" ]; then
		echo "Failed to compute prefixlen from subnet mask."
		echo "$mask is not a valid subnet mask."
		return 1
	fi

	echo $plen
	return 0
}

# get_active_ncp
#
# echoes the name of the currently active ncp
# return:
#	0 => active_ncp is set
#	1 => active_ncp is not set
#
get_active_ncp()
{
	ncp=`$SVCPROP -cp netcfg/active_ncp $NP_DEFAULT_FMRI`
	rtn=$?
	echo $ncp
	return $rtn
}

#
# get_ncp_prop ncp propname
#
# echoes the value of the specified property for the specified ncp.
# return:
#	0 => property is set
#	1 => property is not set
#
get_ncp_prop()
{
	value=`$NETCFG "select ncp \"$1\"; get -V $2" 2>/dev/null`
	rtn=$?
	echo $value
	return $rtn
}

#
# ncp_is_fixed() ncp
#
# Checks if specified ncp is fixed.  For now we compare name against DefaultFixed -
# if multiple fixed NCPs are added, this will need to change.
#
# return:
#	0 => ncp is fixed
#	1 => ncp is not fixed
#
ncp_is_fixed()
{
	[ "$1" = "DefaultFixed" ] && return 0
	return 1
}

#
# loc_exists location
#
# Checks if specified location exists
# return:
#	0 => location exists
#	1 => location does not exist
#
loc_exists()
{
	$NETCFG "select loc \"$1\"" >/dev/null 2>&1 && return 0
	return 1
}

#
# nwam_get_loc_prop location property
#
# echoes the value of the property for the given location
# return:
#	0 => property is set
#	1 => property is not set
#
nwam_get_loc_prop()
{
	value=`$NETCFG "select loc \"$1\"; get -V $2" 2>/dev/null`
	rtn=$?
	echo $value
	return $rtn
}

#
# nwam_get_loc_list_prop location property
#
# echoes a space-separated list of the property values for the given location
# return:
#	0 => property is set
#	1 => property is not set
#
nwam_get_loc_list_prop()
{
	clist=`$NETCFG "select loc \"$1\"; get -V $2" 2>/dev/null`
	rtn=$?
	#
	# netcfg gives us a comma-separated list; need to convert commas to
	# spaces.
	#
	slist=$(echo $clist | sed -e s/","/" "/g)
	echo $slist
	return $rtn
}

is_iptun ()
{
	intf=$(echo $1 | cut -f1 -d:)
	# Is this a persistent IP tunnel link?
	$DLADM show-iptun -P $intf > /dev/null 2>&1
	if [ $? -eq 0 ]; then
		return 0
	fi
	# Is this an implicit IP tunnel (i.e., ip.tun0)
	ORIGIFS="$IFS"
	IFS="$IFS."
	set -- $intf
	IFS="$ORIGIFS"
	if [ $# -eq 2 -a \( "$1" = "ip" -o "$1" = "ip6" \) ]; then
		#
		# It looks like one, but another type of link might be
		# using a name that looks like an implicit IP tunnel.
		# If dladm show-link -P finds it, then it's not an IP
		# tunnel.
		#
		$DLADM show-link -Pp $intf > /dev/null 2>&1
		if [ $? -eq 0 ]; then
			return 1
		else
			return 0
		fi
	fi
	return 1
}

#
# walk_static_routes cmd static_routes_file
#
# cmd should be add or delete. file is the static routes file to be used.
#
# Walks the static_routes file and applies the specified command to each
# line in the file.
#
walk_static_routes()
{
	cmd=$1
	srts_file="$2"
	if [ -f "$srts_file" ]; then
		/usr/bin/egrep -v "^(#|$)" "$srts_file" | while read line; do
			/usr/sbin/route $cmd $line >/dev/null
		done
	fi

	#
	# Record which static_routes file we added from so we can
	# delete from it later when stop method is called. Record
	# the filename even if it doesn't exist now, as routes might
	# be added while the ncp is active.
	#
	if [ "$cmd" = "add" ]; then
		$SVCCFG -s $ROUTING_SETUP_FMRI addpg config application P \
		    2>/dev/null
		$SVCCFG -s $ROUTING_SETUP_FMRI setprop \
		    $SRTS_FILE_PROP = astring: "$srts_file"
	fi
}

#
# get_smf_prop <fmri> <property name>
#
get_smf_prop ()
{
	$SVCPROP -cp $2 $1 2>/dev/null
}

#
# get_smf_comma_prop <fmri> <property name>
#
# Returns the SMF value separated by commas
#
get_smf_comma_prop ()
{
	$SVCPROP -cp $2 $1 2>/dev/null | /usr/bin/sed s/" "/","/g
}

# iscsi_is_active
#
# Returns zero (success) if iscsi targets are configured. 1 otherwise.
#
iscsi_is_active() {
	targets=`/usr/sbin/iscsiadm list target 2>/dev/null`
	if [ $? -eq 0 -a -n "$targets" ]; then
		return 0
	fi
	return 1
}

#
# Some services care about whether or not they are running in the install
# environment. Most notably is the identity:node service that will use
# netbootinfo to obtain a hostname if running in the install environment.
# The following service only exists in the install environment and
# can therefore be used to identify whether or not Solaris is running
# in an install environment.
#
is_install_environment() {
	/usr/bin/svcs svc:/application/manifest-locator >/dev/null 2>&1
	if [ $? -eq 0 ]; then
		return 1
	fi
	return 0
}