1#!/bin/sh
2#
3# $NetBSD: network,v 1.85 2020/10/16 15:31:04 kim Exp $
4#
5
6# PROVIDE: network
7# REQUIRE: ipfilter ipsec CRITLOCALMOUNTED root tty sysctl
8# BEFORE:  NETWORKING
9
10$_rc_subr_loaded . /etc/rc.subr
11
12name="network"
13start_cmd="network_start"
14stop_cmd="network_stop"
15
16nl='
17' # a newline
18
19intmissing()
20{
21          local int="$1"
22          shift
23          for i; do
24                    if [ "$int" = "$i" ]; then
25                              return 1
26                    fi
27          done
28          return 0
29}
30
31have_inet6()
32{
33          /sbin/ifconfig lo0 inet6 >/dev/null 2>&1
34}
35
36network_start()
37{
38          # set hostname, turn on network
39          #
40          echo "Starting network."
41
42          network_start_hostname
43          network_start_domainname
44          network_start_loopback
45          have_inet6 &&
46          network_start_ipv6_route
47          [ "$net_interfaces" != NO ] &&
48          network_start_interfaces
49          network_start_aliases
50          network_start_defaultroute
51          network_start_defaultroute6
52          have_inet6 &&
53          network_wait_dad
54          network_start_resolv
55          network_start_local
56}
57
58network_start_hostname()
59{
60          # If $hostname is set, use it for my Internet name,
61          # otherwise use /etc/myname
62          #
63          if [ -z "$hostname" ] && [ -f /etc/myname ]; then
64                    hostname=$(kat /etc/myname)
65          fi
66          if [ -n "$hostname" ]; then
67                    echo "Hostname: $hostname"
68                    hostname $hostname
69          else
70                    # Don't warn about it if we're going to run
71                    # DHCP later, as we will probably get the
72                    # hostname at that time.
73                    #
74                    if ! checkyesno dhcpcd && \
75                              [ -z "$(hostname)" ]
76                    then
77                              warn "\$hostname not set."
78                    fi
79          fi
80}
81
82network_start_domainname()
83{
84          # Check $domainname first, then /etc/defaultdomain,
85          # for NIS/YP domain name
86          #
87          if [ -z "$domainname" ] && [ -f /etc/defaultdomain ]; then
88                    domainname=$(kat /etc/defaultdomain)
89          fi
90          if [ -n "$domainname" ]; then
91                    echo "NIS domainname: $domainname"
92                    domainname $domainname
93          fi
94
95          # Flush all routes just to make sure it is clean
96          if checkyesno flushroutes; then
97                    /sbin/route -qn flush
98          fi
99}
100
101network_start_loopback()
102{
103          # Set the address for the first loopback interface, so that the
104          # auto-route from a newly configured interface's address to lo0
105          # works correctly.
106          #
107          # NOTE: obscure networking problems will occur if lo0 isn't configured.
108          #
109          /sbin/ifconfig lo0 inet 127.0.0.1
110
111          # According to RFC1122, 127.0.0.0/8 must not leave the node.
112          #
113          /sbin/route -q add -inet 127.0.0.0 -netmask 0xff000000 127.0.0.1 -reject
114}
115
116network_start_ipv6_route()
117{
118          # IPv6 routing setups, and host/router mode selection.
119          #
120          # We have IPv6 support in kernel.
121
122          # disallow link-local unicast dest without outgoing scope
123          # identifiers.
124          #
125          /sbin/route -q add -inet6 fe80:: -prefixlen 10 ::1 -reject
126
127          # disallow the use of the RFC3849 documentation address
128          #
129          /sbin/route -q add -inet6 2001:db8:: -prefixlen 32 ::1 -reject
130
131          # IPv6 site-local scoped address prefix (fec0::/10)
132          # has been deprecated by RFC3879.
133          #
134          if [ -n "$ip6sitelocal" ]; then
135                    warn "\$ip6sitelocal is no longer valid"
136          fi
137
138          # disallow "internal" addresses to appear on the wire.
139          #
140          /sbin/route -q add -inet6 ::ffff:0.0.0.0 -prefixlen 96 ::1 -reject
141
142          # disallow packets to malicious IPv4 compatible prefix
143          #
144          /sbin/route -q add -inet6 ::224.0.0.0 -prefixlen 100 ::1 -reject
145          /sbin/route -q add -inet6 ::127.0.0.0 -prefixlen 104 ::1 -reject
146          /sbin/route -q add -inet6 ::0.0.0.0 -prefixlen 104 ::1 -reject
147          /sbin/route -q add -inet6 ::255.0.0.0 -prefixlen 104 ::1 -reject
148
149          # disallow packets to malicious 6to4 prefix
150          #
151          /sbin/route -q add -inet6 2002:e000:: -prefixlen 20 ::1 -reject
152          /sbin/route -q add -inet6 2002:7f00:: -prefixlen 24 ::1 -reject
153          /sbin/route -q add -inet6 2002:0000:: -prefixlen 24 ::1 -reject
154          /sbin/route -q add -inet6 2002:ff00:: -prefixlen 24 ::1 -reject
155
156          # Completely disallow packets to IPv4 compatible prefix.
157          # This may conflict with RFC1933 under following circumstances:
158          # (1) An IPv6-only KAME node tries to originate packets to IPv4
159          #     compatible destination.  The KAME node has no IPv4
160          #     compatible support.  Under RFC1933, it should transmit
161          #     native IPv6 packets toward IPv4 compatible destination,
162          #     hoping it would reach a router that forwards the packet
163          #     toward auto-tunnel interface.
164          # (2) An IPv6-only node originates a packet to IPv4 compatible
165          #     destination.  A KAME node is acting as an IPv6 router, and
166          #     asked to forward it.
167          # Due to rare use of IPv4 compatible address, and security
168          # issues with it, we disable it by default.
169          #
170          /sbin/route -q add -inet6 ::0.0.0.0 -prefixlen 96 ::1 -reject
171
172          /sbin/sysctl -qw net.inet6.ip6.forwarding=0
173
174          case $ip6mode in
175          router)
176                    echo 'IPv6 mode: router'
177                    /sbin/sysctl -qw net.inet6.ip6.forwarding=1
178
179                    # disallow unique-local unicast forwarding without
180                    # explicit configuration.
181                    if ! checkyesno ip6uniquelocal; then
182                              /sbin/route -q add -inet6 fc00:: -prefixlen 7 \
183                                  ::1 -reject
184                    fi
185                    ;;
186
187          autohost)
188                    if ! checkyesno dhcpcd; then
189                              warn "rtsol and kernel ra handling have been removed"
190                              warn "please configure dhcpcd in its place."
191                    fi
192                    ;;
193
194          host)
195                    echo 'IPv6 mode: host'
196                    ;;
197
198          *)        warn "invalid \$ip6mode value "\"$ip6mode\"
199                    ;;
200
201          esac
202}
203
204network_start_interfaces()
205{
206          # Configure all of the network interfaces listed in $net_interfaces;
207          # if $auto_ifconfig is YES, grab all interfaces from ifconfig.
208          # In the following, "xxN" stands in for interface names, like "le0".
209          #
210          # For any interfaces that has an $ifconfig_xxN variable
211          # associated, we break it into lines using ';' as a separator,
212          # then process it just like the contents of an /etc/ifconfig.xxN
213          # file.
214          #
215          # For each line from the $ifconfig_xxN variable or the
216          # /etc/ifconfig.xxN file, we ignore comments and blank lines,
217          # treat lines beginning with "!" as commands to execute, treat
218          # "dhcp" as a special case to invoke dhcpcd, treat "rtsol" as
219          # a special case to send a router solicitation, and for any other
220          # line we run "ifconfig xxN", using each line of the file as the
221          # arguments for a separate "ifconfig" invocation.
222          #
223          # In order to configure an interface reasonably, you at the very least
224          # need to specify "[addr_family] [hostname]" (e.g "inet my.domain.org"),
225          # and probably a netmask (as in "netmask 0xffffffe0"). You will
226          # frequently need to specify a media type, as in "media UTP", for
227          # interface cards with multiple media connections that do not
228          # autoconfigure. See the ifconfig manual page for details.
229          #
230          # Note that /etc/ifconfig.xxN takes multiple lines.  The following
231          # configuration is possible:
232          #         inet 10.1.1.1 netmask 0xffffff00
233          #         inet 10.1.1.2 netmask 0xffffff00 alias
234          #         inet6 2001:db8::1 prefixlen 64 alias
235          #
236          # You can put shell script fragment into /etc/ifconfig.xxN by
237          # starting a line with "!".  Refer to ifconfig.if(5) for details.
238          #
239          ifaces="$(/sbin/ifconfig -l)"
240          if checkyesno auto_ifconfig; then
241                    tmp="$ifaces"
242                    for cloner in $(/sbin/ifconfig -C); do
243                              for int in /etc/ifconfig.${cloner}[0-9]*; do
244                                        [ ! -f $int ] && break
245                                        tmp="$tmp ${int##*.}"
246                              done
247                    done
248          else
249                    tmp="$net_interfaces"
250          fi
251          echo -n 'Configuring network interfaces:'
252          for int in $tmp; do
253                    eval argslist=\$ifconfig_$int
254
255                    # Skip interfaces that do not have explicit
256                    # configuration information.  If auto_ifconfig is
257                    # false then also warn about such interfaces.
258                    #
259                    if [ -z "$argslist" ] && ! [ -f /etc/ifconfig.$int ]
260                    then
261                              if ! checkyesno auto_ifconfig; then
262                                        echo
263                                        warn \
264                    "/etc/ifconfig.$int missing and ifconfig_$int not set;"
265                                        warn "interface $int not configured."
266                              fi
267                              continue
268                    fi
269
270                    echo -n " $int"
271
272                    # Create the interface if necessary.
273                    # If the interface did not exist before,
274                    # then also resync ipf(4).
275                    #
276                    if intmissing $int $ifaces; then
277                              if /sbin/ifconfig $int create && \
278                                 checkyesno ipfilter; then
279                                        /sbin/ipf -y >/dev/null
280                              fi
281                    fi
282
283                    # If $ifconfig_xxN is empty, then use
284                    # /etc/ifconfig.xxN, which we know exists due to
285                    # an earlier test.
286                    #
287                    # If $ifconfig_xxN is non-empty and contains a
288                    # newline, then just use it as is.  (This allows
289                    # semicolons through unmolested.)
290                    #
291                    # If $ifconfig_xxN is non-empty and does not
292                    # contain a newline, then convert all semicolons
293                    # to newlines.
294                    #
295                    case "$argslist" in
296                    '')
297                              cat /etc/ifconfig.$int
298                              ;;
299                    *"${nl}"*)
300                              echo "$argslist"
301                              ;;
302                    *)
303                              (
304                                        set -o noglob
305                                        IFS=';'; set -- $argslist
306                                        #echo >&2 "[$#] [$1] [$2] [$3] [$4]"
307                                        IFS="$nl"; echo "$*"
308                              )
309                              ;;
310                    esac |
311                    collapse_backslash_newline |
312                    while read -r args; do
313                              case "$args" in
314                              ''|"#"*|create)
315                                        ;;
316                              "!"*)
317                                        # Run arbitrary command in a subshell.
318                                        ( eval "${args#*!}" )
319                                        ;;
320                              dhcp)
321                                        if ! checkyesno dhcpcd; then
322                                                  /sbin/dhcpcd -n --dhcp \
323                                                            ${dhcpcd_flags} $int
324                                        fi
325                                        ;;
326                              rtsol)
327                                        if ! checkyesno dhcpcd; then
328                                                  /sbin/dhcpcd -n6b \
329                                                            ${dhcpcd_flags} $int
330                                        fi
331                                        ;;
332                              *)
333                                        # Pass args to ifconfig.  Note
334                                        # that args may contain embedded
335                                        # shell metacharacters, such as
336                                        # "ssid 'foo;*>bar'". We eval
337                                        # one more time so that things
338                                        # like ssid "Columbia University" work.
339                                        (
340                                                  set -o noglob
341                                                  eval set -- $args
342                                                  #echo >&2 "[$#] [$1] [$2] [$3]"
343                                                  /sbin/ifconfig $int "$@"
344                                        )
345                                        ;;
346                              esac
347                    done
348                    configured_interfaces="$configured_interfaces $int"
349          done
350          echo "."
351}
352
353network_start_aliases()
354{
355          echo -n "Adding interface aliases:"
356
357          # Check if each configured interface xxN has an $ifaliases_xxN variable
358          # associated, then configure additional IP addresses for that interface.
359          # The variable contains a list of "address netmask" pairs, with
360          # "netmask" set to "-" if the interface default netmask is to be used.
361          #
362          # Note that $ifaliases_xxN works only in certain cases and its
363          # use is not recommended.  Use /etc/ifconfig.xxN or multiple
364          # commands in $ifconfig_xxN instead.
365          #
366          for int in lo0 $configured_interfaces; do
367                    eval args=\$ifaliases_$int
368                    if [ -n "$args" ]; then
369                              set -- $args
370                              while [ $# -ge 2 ]; do
371                                        addr=$1 ; net=$2 ; shift 2
372                                        if [ "$net" = "-" ]; then
373                                                  # for compatibility only, obsolete
374                                                  /sbin/ifconfig $int inet alias $addr
375                                        else
376                                                  /sbin/ifconfig $int inet alias $addr \
377                                                      netmask $net
378                                        fi
379                                        echo -n " $int:$addr"
380                              done
381                    fi
382          done
383
384          # /etc/ifaliases, if it exists, contains the names of additional IP
385          # addresses for each interface. It is formatted as a series of lines
386          # that contain
387          #         address interface netmask
388          #
389          # Note that /etc/ifaliases works only in certain cases and its
390          # use is not recommended.  Use /etc/ifconfig.xxN or multiple
391          # commands in $ifconfig_xxN instead.
392          #
393          if [ -f /etc/ifaliases ]; then
394                    while read addr int net; do
395                              if [ -z "$net" ]; then
396                                        # for compatibility only, obsolete
397                                        /sbin/ifconfig $int inet alias $addr
398                              else
399                                        /sbin/ifconfig $int inet alias $addr netmask $net
400                              fi
401                    done < /etc/ifaliases
402          fi
403
404          echo "." # for "Adding interface aliases:"
405}
406
407network_start_defaultroute()
408{
409          # Check $defaultroute, then /etc/mygate, for the name or address
410          # of my IPv4 gateway host. If using a name, that name must be in
411          # /etc/hosts.
412          #
413          if [ -z "$defaultroute" ] && [ -f /etc/mygate ]; then
414                    defaultroute=$(kat /etc/mygate)
415          fi
416          if [ -n "$defaultroute" ]; then
417                    /sbin/route add default $defaultroute
418          fi
419}
420
421network_start_defaultroute6()
422{
423          # Check $defaultroute6, then /etc/mygate6, for the name or address
424          # of my IPv6 gateway host. If using a name, that name must be in
425          # /etc/hosts.  Note that the gateway host address must be a link-local
426          # address if it is not using an stf* interface.
427          #
428          if [ -z "$defaultroute6" ] && [ -f /etc/mygate6 ]; then
429                    defaultroute6=$(kat /etc/mygate6)
430          fi
431          if [ -n "$defaultroute6" ]; then
432                    if [ "$ip6mode" = "autohost" ]; then
433                              echo
434                              warn \
435              "ip6mode is set to 'autohost' and a v6 default route is also set."
436                    fi
437                    /sbin/route add -inet6 default $defaultroute6
438          fi
439}
440
441network_wait_dad()
442{
443          # Wait for the DAD flags to clear from all addresses.
444          if [ -n "$ifconfig_wait_dad_flags" ]; then
445                    echo "Waiting for duplicate address detection to finish..."
446                    ifconfig $ifconfig_wait_dad_flags
447          fi
448}
449
450network_start_resolv()
451{
452          resconf=
453
454          if [ -n "$dns_domain" ]; then
455                    resconf="${resconf}domain $dns_domain$nl"
456          fi
457          if [ -n "$dns_search" ]; then
458                    resconf="${resconf}search $dns_search$nl"
459          fi
460          for n in $dns_nameservers; do
461                    resconf="${resconf}nameserver $n$nl"
462          done
463          if [ -n "$dns_sortlist" ]; then
464                    resconf="${resconf}sortlist $dns_sortlist$nl"
465          fi
466          if [ -n "$dns_options" ]; then
467                    resconf="${resconf}options $dns_options$nl"
468          fi
469          if [ -n "$resconf" ]; then
470                    resconf="# Generated by /etc/rc.d/network$nl$resconf"
471                    echo 'Configuring resolv.conf'
472                    printf %s "$resconf" | resolvconf -m "${dns_metric:-0}" -a network
473          fi
474}
475
476network_start_local()
477{
478          # XXX this must die
479          if [ -s /etc/netstart.local ]; then
480                    sh /etc/netstart.local start
481          fi
482}
483
484network_stop()
485{
486          echo "Stopping network."
487
488          network_stop_local
489          network_stop_resolv
490          network_stop_aliases
491          [ "$net_interfaces" != NO ] &&
492          network_stop_interfaces
493          network_stop_route
494}
495
496network_stop_local()
497{
498          # XXX this must die
499          if [ -s /etc/netstart.local ]; then
500                    sh /etc/netstart.local stop
501          fi
502}
503
504network_stop_resolv()
505{
506          resolvconf -f -d network
507}
508
509network_stop_aliases()
510{
511          echo "Deleting aliases."
512          if [ -f /etc/ifaliases ]; then
513                    while read addr int net; do
514                              /sbin/ifconfig $int inet delete $addr
515                    done < /etc/ifaliases
516          fi
517
518          for int in $(/sbin/ifconfig -lu); do
519                    eval args=\$ifaliases_$int
520                    if [ -n "$args" ]; then
521                              set -- $args
522                              while [ $# -ge 2 ]; do
523                                        addr=$1 ; net=$2 ; shift 2
524                                        /sbin/ifconfig $int inet delete $addr
525                              done
526                    fi
527          done
528}
529
530network_stop_interfaces()
531{
532          # down interfaces
533          #
534          echo -n 'Downing network interfaces:'
535          if checkyesno auto_ifconfig; then
536                    tmp=$(/sbin/ifconfig -l)
537          else
538                    tmp="$net_interfaces"
539          fi
540          for int in $tmp; do
541                    eval args=\$ifconfig_$int
542                    if [ -n "$args" ] || [ -f /etc/ifconfig.$int ]; then
543                              echo -n " $int"
544                              if [ -f /var/run/dhcpcd-$int.pid ]; then
545                                        /sbin/dhcpcd -k $int 2> /dev/null
546                              fi
547                              /sbin/ifconfig $int down
548                              if /sbin/ifconfig $int destroy 2>/dev/null && \
549                                 checkyesno ipfilter; then
550                                        # resync ipf(4)
551                                        /sbin/ipf -y >/dev/null
552                              fi
553                    fi
554          done
555          echo "."
556}
557
558network_stop_route()
559{
560          # flush routes
561          #
562          if checkyesno flushroutes; then
563                    /sbin/route -qn flush
564          fi
565}
566
567load_rc_config $name
568load_rc_config_var dhcpcd dhcpcd
569load_rc_config_var ipfilter ipfilter
570run_rc_command "$1"
571