#!/sbin/sh
#
# Copyright (c) 1999-2001 by Sun Microsystems, Inc.
# All rights reserved.
#
# $Id: nddconfig,v 1.9 2001/11/09 17:18:32 kaw Exp $
#
# INTRODUCTION
#
#  This script sets network driver parameters to prevent some network
#  attacks.  Install this script to make changes at system boot.  For
#  further information on the parameters set in this script, see
#  the Sun Blueprints(tm) OnLine article entitled "Solaris Operating
#  Environment Network Settings for Security - updated for 8".
#
#	http://www.sun.com/blueprints/1200/network-updt1.pdf
#
#  The latest version of this script is available from the Blueprints
#  Online tools area at:
#
#	http://www.sun.com/blueprints/tools/
#
#  This script is written for the Solaris 2.5.1, 2.6, 7, and 8 Operating
#  Environment releases.
#
# WARNING
#
#  This script makes changes to the system default network driver
#  parameters.  The settings included in this script are considered safe
#  in terms of security.  However, some settings may not work in your
#  environment.  The comments provided for each parameter explain the
#  effect the setting has.
#
# INSTALLATION
#
#	# cp <script> /etc/init.d/nddconfig
#	# chmod 744 /etc/init.d/nddconfig
#	# chown root:sys /etc/init.d/nddconfig
#	# ln /etc/init.d/nddconfig /etc/rc2.d/S70nddconfig
#
# WARNING MESSAGES
#
#  When adding specific privileged ports ({tcp|udp}_extra_priv_ports_add),
#  if a specific port number has already been applied, the following
#  warning message is displayed:
#
#	operation failed, File exists
#
#  This is a very poor ndd warning message.  It can be safely ignored.
#
#  Keith A. Watson <keith.watson@Sun.COM>
#

PATH=/usr/bin:/usr/sbin

#
# A note about parameter values:
#     '0' == false/off/disable
#     '1' == true/on/enable
#

#
# verbose
#
#  This option enables verbose output generated by this script.
#
verbose=1

#
# arp_cleanup_interval
#
#  This option determines the period of time the Address Resolution
#  Protocol (ARP) cache maintains entries. ARP attacks may be effective
#  with the default interval. Shortening the timeout interval should
#  reduce the effectiveness of such an attack.
#  The default value is 300000 milliseconds (5 minutes).
#
arp_cleanup_interval=60000

#
# ip_forward_directed_broadcasts
#
#  This option determines whether to forward broadcast packets directed
#  to a specific net or subnet, if that net or subnet is directly
#  connected to the machine. If the system is acting as a router, this
#  option can be exploited to generate a great deal of broadcast network
#  traffic. Turning this option off will help prevent broadcast traffic
#  attacks.
#  The default value is 1 (true).
#
ip_forward_directed_broadcasts=0

#
# ip_forward_src_routed 
# ip6_forward_src_routed (Solaris 8)
#
#  This option determines whether to forward packets that are source
#  routed. These packets define the path the packet should take instead
#  of allowing network routers to define the path.
#  The default value is 1 (true).
#
ip_forward_src_routed=0
ip6_forward_src_routed=0

#
# ip_ignore_redirect
# ip6_ignore_redirect (Solaris 8)
#
#  This option determines whether to ignore Internet Control Message
#  Protocol (ICMP) packets that define new routes. If the system is
#  acting as a router, an attacker may send redirect messages to alter
#  routing tables as part of sophisticated attack (man in the middle
#  attack) or a simple denial of service.
#  The default value is 0 (false).
#
ip_ignore_redirect=1
ip6_ignore_redirect=1

#
# ip_ire_flush_interval (Solaris 2.5.1, 2.6, and 7)
# ip_ire_arp_interval   (Solaris 8)
#
#  This option determines the period of time at which a specific route
#  will be kept, even if currently in use. ARP attacks may be effective
#  with the default interval. Shortening the time interval may reduce
#  the effectiveness of attacks.
#  The default interval is 1200000 milliseconds (20 minutes).
#
ip_ire_flush_interval=60000
ip_ire_arp_interval=60000

#
# ip_respond_to_address_mask_broadcast
#
#  This options determines whether to respond to ICMP netmask requests
#  which are typically sent by diskless clients when booting. An
#  attacker may use the netmask information for determining network
#  topology or the broadcast address for the subnet.
#  The default value is 0 (false).
#
ip_respond_to_address_mask_broadcast=0

#
# ip_respond_to_echo_broadcast
# ip6_respond_to_echo_multicast (Solaris 8)
#
#  This option determines whether to respond to ICMP broadcast echo
#  requests (ping). An attacker may try to create a denial of service
#  attack on subnets by sending many broadcast echo requests to which all
#  systems will respond. This also provides information on systems that
#  are available on the network.
#  The default value is 1 (true).
#
ip_respond_to_echo_broadcast=0
ip6_respond_to_echo_multicast=0

#
# ip_respond_to_timestamp
#
#  This option determines whether to respond to ICMP timestamp requests
#  which some systems use to discover the time on a remote system. An
#  attacker may use the time information to schedule an attack at a
#  period of time when the system may run a cron job (or other time-
#  based event) or otherwise be busy. It may also be possible predict
#  ID or sequence numbers that are based on the time of day for spoofing
#  services.
#  The default value is 1 (true).
#
ip_respond_to_timestamp=0

#
# ip_respond_to_timestamp_broadcast
#
#  This option determines whether to respond to ICMP broadcast timestamp
#  requests which are used to discover the time on all systems in the
#  broadcast range. This option is dangerous for the same reasons as 
#  responding to a single timestamp request. Additionally, an attacker
#  may try to create a denial of service attack by generating many
#  broadcast timestamp requests.
#  The default value is 1 (true).
#
ip_respond_to_timestamp_broadcast=0

#
# ip_send_redirects
# ip6_send_redirects (Solaris 8)
#
#  This option determines whether to send ICMP redirect messages which
#  can introduce changes into remote system's routing table. It should
#  only be used on systems that act as routers.
#  The default value is 1 (true).
#
ip_send_redirects=0
ip6_send_redirects=0

#
# ip_strict_dst_multihoming
# ip6_strict_dst_multihoming (Solaris 8)
#
#  This option determines whether to enable strict destination
#  multihoming. If this is set to 1 and ip_forwarding is set to 0, then
#  a packet sent to an interface from which it did not arrive will be
#  dropped. This setting prevents an attacker from passing packets across
#  a machine with multiple interfaces that is not acting a router.
#  The default value is 0 (false).
#
#  NOTE: Strict destination multihoming may prevent SunCluster 2.x
#  systems from operating as intended.  This script will NOT enable
#  strict destination multihoming if SunCluster 2.x software is installed.
#
ip_strict_dst_multihoming=1
ip6_strict_dst_multihoming=1

#
# ip_def_ttl
#
#  This option sets the default time to live (TTL) value for IP packets.
#  Normally, this should not be altered from the default value.
#  Changing it to a different value may fool some OS "fingerprinting"
#  tools such as queso or nmap.
#  The default value is 255.
#
ip_def_ttl=255

#
# tcp_conn_req_max_q0
# 
#  This option sets the size of the queue containing unestablished
#  connections. This queue is part of a protection mechanism against
#  SYN flood attacks. The queue size default is adequate for most
#  systems but should be increased for busy servers.
#  The default value is 1024.
#
tcp_conn_req_max_q0=4096

#
# tcp_conn_req_max_q
#
#  This option sets the maximum number fully established connections.
#  Increasing the size of this queue provides some limited protection
#  against resource consumption attacks. The queue size default is
#  adequate for most systems but should be increased for busy servers.
#  The default value is 128.
#
tcp_conn_req_max_q=1024

#
# tcp_rev_src_routes (Solaris 8)
#
#  This option determines whether the specified route in a source
#  routed packet will be used in returned packets.  TCP source routed
#  packets may be used in spoofing attacks, so the reverse route should 
#  not be used.
#  The default value is 0 (false).
#
tcp_rev_src_routes=0

#
# Adding specific privileged ports (Solaris 2.6, 7, and 8)
#
#  These options define additional TCP and UDP privileged ports outside
#  of the 1-1023 range.  Any program that attempts to bind the ports
#  listed here must run as root.  This prevents normal users from
#  starting server processes on specific ports.  Multiple ports can be
#  specifed by quoting and separating them with spaces.
#
#  Defaults values:
#	tcp_extra_priv_ports: 2049 (nfsd) 4045 (lockd)
#	udp_extra_priv_ports: 2049 (nfsd) 4045 (lockd)
#
tcp_extra_priv_ports_add="6112"
udp_extra_priv_ports_add=""

#
# Ephemeral port range adjustment (Solaris 2.5.1, 2.6, 7, and 8)
#
#  These options define the upper and lower bounds on ephemeral ports.
#  Ephemeral (means short-lived) ports are used when establishing
#  outbound network connections.
#
#  Defaults values:
#	tcp_smallest_anon_port=32768
#	tcp_largest_anon_port=65535
#	udp_smallest_anon_port=32768
#	udp_largest_anon_port=65535
#
tcp_smallest_anon_port=32768
tcp_largest_anon_port=65535
udp_smallest_anon_port=32768
udp_largest_anon_port=65535

#
# Nonprivileged port range adjustment (Solaris 2.5.1, 2.6, 7, and 8)
#
#  These options define the start of nonprivileged TCP and UDP ports. 
#  The nonprivileged port range normally starts at 1024.  Any program
#  that attempts to bind a nonprivileged port does not have to run as
#  root.
# 
#  Defaults values:
#	tcp_smallest_nonpriv_port=1024
#	udp_smallest_nonpriv_port=1024
#
tcp_smallest_nonpriv_port=1024
udp_smallest_nonpriv_port=1024


#		+-----------------------------------------+
#		| No modification needed below this line. |
#		+-----------------------------------------+


#
# base parameters (the same across the 2.5.1, 2.6, 7, 8, and 9 (alpha)
#  releases)
#
base_parameters="arp_cleanup_interval \
		 ip_forward_directed_broadcasts \
		 ip_forward_src_routed \
		 ip_ignore_redirect \
		 ip_respond_to_address_mask_broadcast \
		 ip_respond_to_echo_broadcast \
		 ip_respond_to_timestamp \
		 ip_respond_to_timestamp_broadcast \
		 ip_send_redirects \
		 ip_strict_dst_multihoming \
		 ip_def_ttl \
		 tcp_conn_req_max_q0 \
		 tcp_conn_req_max_q \
		 tcp_smallest_anon_port \
		 tcp_largest_anon_port \
		 udp_smallest_anon_port \
		 udp_largest_anon_port \
		 tcp_smallest_nonpriv_port \
		 udp_smallest_nonpriv_port"

#
# OS_revision specific parameters
#

# Solaris 2.5.1 specific parameters
SunOS5_5_1="ip_ire_flush_interval"

# Solaris 2.6 specific parameters
SunOS5_6="ip_ire_flush_interval \
	  tcp_extra_priv_ports_add \
	  udp_extra_priv_ports_add"

# Solaris 7 specific parameters
SunOS5_7="ip_ire_flush_interval \
	  tcp_extra_priv_ports_add \
	  udp_extra_priv_ports_add"

# Solaris 8 specific parameters
SunOS5_8="ip_ire_arp_interval \
	  tcp_extra_priv_ports_add \
	  udp_extra_priv_ports_add \
	  tcp_rev_src_routes"

# Solaris 9 (alpha) specific parameters
SunOS5_9="ip_ire_arp_interval \
	  tcp_extra_priv_ports_add \
	  udp_extra_priv_ports_add \
	  tcp_rev_src_routes"

#
# IPv6 parameters (apply to Solaris 8 and 9 (alpha))
#
ip6_parameters="ip6_forward_src_routed \
		ip6_respond_to_echo_multicast \
		ip6_send_redirects \
		ip6_ignore_redirect \
		ip6_strict_dst_multihoming"

#
# system privilege ports defaults
#
extra_priv_ports_defaults="2049 4045 "

#
# check for the presence of SunCluster 2.x software 
#  (disables strict destination multihoming if SunCluster 2.x is installed)
#
if [ -f /opt/SUNWcluster/bin/scconf ]; then
    [ "$verbose" = "1" ] && \
	echo "SunCluster 2.2 detected; disabling IP strict destination multihoming."
    ip_strict_dst_multihoming=0
    ip6_strict_dst_multihoming=0
fi

#
# get OS name and revision information
#
os=`uname -s`
revision=`uname -r`
OSRev=$os`echo $revision | sed -e 's/\./_/g'`

#
# check if IPv6 is enabled
#
ip6_interfaces="`echo /etc/hostname6.*[0-9] 2> /dev/null`"
[ "$ip6_interfaces" != "/etc/hostname6.*[0-9]" ] && ip6_enabled=true

#
# do_in_order -- This function executes the specified functions with
#   the appropriate parameters for the local OS, revision, and
#   configuration.  Currently it acts on a specific base set of
#   parameters, OS and revision specific parameters, and IPv6 
#   parameters.
#
do_in_order() { # function_name

    function_name=$1

    # handle the base parameters
    for param in $base_parameters; do
	$function_name $param
    done

    # handle the OS/revision specific parameters
    eval OSRev_params=\$$OSRev
    for param in $OSRev_params; do
	$function_name $param
    done

    # handle IPv6 parameters
    if [ "$ip6_enabled" = "true" ]; then
	for param in $ip6_parameters; do
	    $function_name $param
	done
    fi

}

#
# set_parameter -- This function uses ndd to set a parameter.
#   The supplied parameter name has a shell variable with the same
#   name which contains the value for the parameter.
#
set_parameter() { # parameter

    # definition for local variable
    param=$1

    # determine the driver from the first substring in the parameter name
    driver=/dev/`echo $param | sed -e 's/_.*//'`

    eval values=\$$param

    # First check that a value for the parameter exists. If not, skip it.
    if [ -n "$values" ]; then
	
	# Some parameters may have multiple values specified in one
	#  assignment further up in the script.  ndd only accepts one
	#  parameter at a time.  Loop through and set each value.
	for value in $values; do
	    [ "$verbose" = "1" ] && \
		echo "Setting $driver $param to $value"
	    ndd -set $driver $param $value
	done
    fi
}

#
# display_parameter -- This function uses ndd to extract the value of
#   a parameter and display it.
#
display_parameter() { # parameter

    # definition for local variable
    param=$1

    # hack for the "write only" extra privileged ports parameters
    param=`echo $param | sed -e 's/_add$//'`

    # determine the driver from the first substring in the parameter name
    driver=/dev/`echo $param | sed -e 's/_.*//'`

    # execute the ndd command to retrieve settings and remove newlines
    value=`ndd $driver $param | tr -d '\n'`

    # print parameter value
    echo "   $driver $param = '$value'"
}

#
# compare_parameter -- This function uses ndd to extract the value of
#   a parameter.  It compares the current parameter value to the one
#   defined in this script.
#
compare_parameter() { # parameter

    # definition for local variable
    originalParam=$1

    # hack for the "write only" extra privileged ports parameters
    modifiedParam=`echo $originalParam | sed -e 's/_add$//'`

    # determine the driver from the first substring in the parameter name
    driver=/dev/`echo $modifiedParam | sed -e 's/_.*//'`

    # execute the ndd command to retrieve settings and remove newlines
    currentValue=`ndd $driver $modifiedParam | tr -d '\n'`

    eval intendedValue="\$$originalParam"

    # if the modified parameter name is different from the original 
    #  parameter, then we are dealing with the privileged port parameters
    if [ "$modifiedParam" != "$originalParam" ]; then

	# the privileged port parameters have system defaults that must
	#  be accounted for in the comparison
	if [ -n "$intendedValue" ]; then
	    intendedValue="$extra_priv_ports_defaults$intendedValue "
	else
	    intendedValue="$extra_priv_ports_defaults"
	fi
    fi

    # print parameter value and note all deviations
    echo "   $driver $modifiedParam = '$currentValue'\c"
    if [ "$intendedValue" != "$currentValue" ]; then
	echo " (should be '$intendedValue')"
    else
	echo " (ok)"
    fi
}

# Process the command argument
case "$1" in

    'start')

	# set the parameters in the defined order
	do_in_order set_parameter
	;;

    'show')

	echo "Current ndd parameter settings:"
	do_in_order display_parameter
	;;

    'compare')

	echo "Comparison of ndd parameter settings:"
	do_in_order compare_parameter
	;;

    'stop')
	# ignored
	[ "$verbose" = "1" ] && \
	    echo "$0: 'stop' ignored.  No network changes applied."
	;;

    *)
	echo "Usage: $0 { start | stop | show | compare }"
	exit 1
	;;
esac

exit 0
