diff --git a/tests/sys/netinet/fibs_test.sh b/tests/sys/netinet/fibs_test.sh index a57d999496fc..b58a45b26f3e 100644 --- a/tests/sys/netinet/fibs_test.sh +++ b/tests/sys/netinet/fibs_test.sh @@ -1,828 +1,828 @@ # # Copyright (c) 2014 Spectra Logic Corporation # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions, and the following disclaimer, # without modification. # 2. Redistributions in binary form must reproduce at minimum a disclaimer # substantially similar to the "NO WARRANTY" disclaimer below # ("Disclaimer") and any redistribution must be conditioned upon # including a substantially similar Disclaimer requirement for further # binary redistribution. # # NO WARRANTY # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGES. # # Authors: Alan Somers (Spectra Logic Corporation) # # arpresolve should check the interface fib for routes to a target when # creating an ARP table entry. This is a regression for kern/167947, where # arpresolve only checked the default route. # # Outline: # Create two connected epair(4) interfaces # Use nping (from security/nmap) to send an ICMP echo request from one # interface to the other, spoofing the source IP. The source IP must be # spoofed, or else it will already have an entry in the arp table. # Check whether an arp entry exists for the spoofed IP atf_test_case arpresolve_checks_interface_fib cleanup arpresolve_checks_interface_fib_head() { atf_set "descr" "arpresolve should check the interface fib, not the default fib, for routes" atf_set "require.user" "root" atf_set "require.progs" "nping" } arpresolve_checks_interface_fib_body() { # Configure the TAP interfaces to use a RFC5737 nonrouteable addresses # and a non-default fib ADDR0="192.0.2.2" ADDR1="192.0.2.3" SUBNET="192.0.2.0" # Due to bug TBD (regressed by multiple_fibs_on_same_subnet) we need # diffferent subnet masks, or FIB1 won't have a subnet route. MASK0="24" MASK1="25" # Spoof a MAC that is reserved per RFC7042 SPOOF_ADDR="192.0.2.4" SPOOF_MAC="00:00:5E:00:53:00" # Check system configuration if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then atf_skip "This test requires net.add_addr_allfibs=0" fi get_fibs 2 # Configure epair interfaces get_epair setup_iface "$EPAIRA" "$FIB0" inet ${ADDR0} ${MASK0} setup_iface "$EPAIRB" "$FIB1" inet ${ADDR1} ${MASK1} # Send an ICMP echo request with a spoofed source IP setfib "$FIB0" nping -c 1 -e ${EPAIRA} -S ${SPOOF_ADDR} \ --source-mac ${SPOOF_MAC} --icmp --icmp-type "echo-request" \ --icmp-code 0 --icmp-id 0xdead --icmp-seq 1 --data 0xbeef \ ${ADDR1} # For informational and debugging purposes only, look for the # characteristic error message dmesg | grep "llinfo.*${SPOOF_ADDR}" # Check that the ARP entry exists atf_check -o match:"${SPOOF_ADDR}.*expires" setfib "$FIB1" arp ${SPOOF_ADDR} } arpresolve_checks_interface_fib_cleanup() { cleanup_ifaces } # Regression test for kern/187549 atf_test_case loopback_and_network_routes_on_nondefault_fib cleanup loopback_and_network_routes_on_nondefault_fib_head() { atf_set "descr" "When creating and deleting loopback IPv4 routes, use the interface's fib" atf_set "require.user" "root" } loopback_and_network_routes_on_nondefault_fib_body() { # Configure the TAP interface to use an RFC5737 nonrouteable address # and a non-default fib ADDR="192.0.2.2" SUBNET="192.0.2.0" MASK="24" # Check system configuration if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then atf_skip "This test requires net.add_addr_allfibs=0" fi get_fibs 1 # Configure a TAP interface setup_tap ${FIB0} inet ${ADDR} ${MASK} # Check whether the host route exists in only the correct FIB setfib ${FIB0} netstat -rn -f inet | grep -q "^${ADDR}.*UHS.*lo0" if [ 0 -ne $? ]; then setfib ${FIB0} netstat -rn -f inet atf_fail "Host route did not appear in the correct FIB" fi setfib 0 netstat -rn -f inet | grep -q "^${ADDR}.*UHS.*lo0" if [ 0 -eq $? ]; then setfib 0 netstat -rn -f inet atf_fail "Host route appeared in the wrong FIB" fi # Check whether the network route exists in only the correct FIB setfib ${FIB0} netstat -rn -f inet | \ grep -q "^${SUBNET}/${MASK}.*${TAPD}" if [ 0 -ne $? ]; then setfib ${FIB0} netstat -rn -f inet atf_fail "Network route did not appear in the correct FIB" fi setfib 0 netstat -rn -f inet | \ grep -q "^${SUBNET}/${MASK}.*${TAPD}" if [ 0 -eq $? ]; then setfib 0 netstat -rn -f inet atf_fail "Network route appeared in the wrong FIB" fi } loopback_and_network_routes_on_nondefault_fib_cleanup() { cleanup_ifaces } atf_test_case loopback_and_network_routes_on_nondefault_fib_inet6 cleanup loopback_and_network_routes_on_nondefault_fib_inet6_head() { atf_set "descr" "When creating and deleting loopback IPv6 routes, use the interface's fib" atf_set "require.user" "root" } loopback_and_network_routes_on_nondefault_fib_inet6_body() { # Configure the TAP interface to use a nonrouteable RFC3849 # address and a non-default fib ADDR="2001:db8::2" SUBNET="2001:db8::" MASK="64" # Check system configuration if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then atf_skip "This test requires net.add_addr_allfibs=0" fi get_fibs 1 # Configure a TAP interface setup_tap ${FIB0} inet6 ${ADDR} ${MASK} # Check whether the host route exists in only the correct FIB setfib ${FIB0} netstat -rn -f inet6 | grep -q "^${ADDR}.*UHS.*lo0" if [ 0 -ne $? ]; then setfib ${FIB0} netstat -rn -f inet6 atf_fail "Host route did not appear in the correct FIB" fi setfib 0 netstat -rn -f inet6 | grep -q "^${ADDR}.*UHS.*lo0" if [ 0 -eq $? ]; then setfib 0 netstat -rn -f inet6 atf_fail "Host route appeared in the wrong FIB" fi # Check whether the network route exists in only the correct FIB setfib ${FIB0} netstat -rn -f inet6 | \ grep -q "^${SUBNET}/${MASK}.*${TAPD}" if [ 0 -ne $? ]; then setfib ${FIB0} netstat -rn -f inet6 atf_fail "Network route did not appear in the correct FIB" fi setfib 0 netstat -rn -f inet6 | \ grep -q "^${SUBNET}/${MASK}.*${TAPD}" if [ 0 -eq $? ]; then setfib 0 netstat -rn -f inet6 atf_fail "Network route appeared in the wrong FIB" fi } loopback_and_network_routes_on_nondefault_fib_inet6_cleanup() { cleanup_ifaces } # Regression test for kern/187552 atf_test_case default_route_with_multiple_fibs_on_same_subnet cleanup default_route_with_multiple_fibs_on_same_subnet_head() { atf_set "descr" "Multiple interfaces on the same subnet but with different fibs can both have default IPv4 routes" atf_set "require.user" "root" } default_route_with_multiple_fibs_on_same_subnet_body() { # Configure the TAP interfaces to use a RFC5737 nonrouteable addresses # and a non-default fib ADDR0="192.0.2.2" ADDR1="192.0.2.3" GATEWAY="192.0.2.1" SUBNET="192.0.2.0" MASK="24" # Check system configuration if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then atf_skip "This test requires net.add_addr_allfibs=0" fi get_fibs 2 # Configure TAP interfaces setup_tap "$FIB0" inet ${ADDR0} ${MASK} TAP0=$TAP setup_tap "$FIB1" inet ${ADDR1} ${MASK} TAP1=$TAP # Attempt to add default routes setfib ${FIB0} route add default ${GATEWAY} setfib ${FIB1} route add default ${GATEWAY} # Verify that the default route exists for both fibs, with their # respective interfaces. - atf_check -o match:"^0\.0\.0\.0.*${TAP0}$" \ + atf_check -o match:"^default.*${TAP0}$" \ setfib ${FIB0} netstat -rn -f inet - atf_check -o match:"^0\.0\.0\.0.*${TAP1}$" \ + atf_check -o match:"^default.*${TAP1}$" \ setfib ${FIB1} netstat -rn -f inet } default_route_with_multiple_fibs_on_same_subnet_cleanup() { cleanup_ifaces } atf_test_case default_route_with_multiple_fibs_on_same_subnet_inet6 cleanup default_route_with_multiple_fibs_on_same_subnet_inet6_head() { atf_set "descr" "Multiple interfaces on the same subnet but with different fibs can both have default IPv6 routes" atf_set "require.user" "root" } default_route_with_multiple_fibs_on_same_subnet_inet6_body() { # Configure the TAP interfaces to use nonrouteable RFC3849 # addresses and non-default FIBs ADDR0="2001:db8::2" ADDR1="2001:db8::3" GATEWAY="2001:db8::1" SUBNET="2001:db8::" MASK="64" # Check system configuration if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then atf_skip "This test requires net.add_addr_allfibs=0" fi get_fibs 2 # Configure TAP interfaces setup_tap "$FIB0" inet6 ${ADDR0} ${MASK} TAP0=$TAP setup_tap "$FIB1" inet6 ${ADDR1} ${MASK} TAP1=$TAP # Attempt to add default routes setfib ${FIB0} route -6 add default ${GATEWAY} setfib ${FIB1} route -6 add default ${GATEWAY} # Verify that the default route exists for both fibs, with their # respective interfaces. - atf_check -o match:"^::/0.*${TAP0}$" \ + atf_check -o match:"^default.*${TAP0}$" \ setfib ${FIB0} netstat -rn -f inet6 - atf_check -o match:"^::/0.*${TAP1}$" \ + atf_check -o match:"^default.*${TAP1}$" \ setfib ${FIB1} netstat -rn -f inet6 } default_route_with_multiple_fibs_on_same_subnet_inet6_cleanup() { cleanup_ifaces } # Regression test for PR kern/189089 # Create two tap interfaces and assign them both the same IP address but with # different netmasks, and both on the default FIB. Then remove one's IP # address. Hopefully the machine won't panic. atf_test_case same_ip_multiple_ifaces_fib0 cleanup same_ip_multiple_ifaces_fib0_head() { atf_set "descr" "Can remove an IPv4 alias from an interface when the same IPv4 is also assigned to another interface." atf_set "require.user" "root" } same_ip_multiple_ifaces_fib0_body() { ADDR="192.0.2.2" MASK0="24" MASK1="32" # Unlike most of the tests in this file, this is applicable regardless # of net.add_addr_allfibs # Setup the interfaces, then remove one alias. It should not panic. setup_tap 0 inet ${ADDR} ${MASK0} TAP0=${TAP} setup_tap 0 inet ${ADDR} ${MASK1} TAP1=${TAP} ifconfig ${TAP1} -alias ${ADDR} # Do it again, in the opposite order. It should not panic. setup_tap 0 inet ${ADDR} ${MASK0} TAP0=${TAP} setup_tap 0 inet ${ADDR} ${MASK1} TAP1=${TAP} ifconfig ${TAP0} -alias ${ADDR} } same_ip_multiple_ifaces_fib0_cleanup() { cleanup_ifaces } # Regression test for PR kern/189088 # Test that removing an IP address works even if the same IP is assigned to a # different interface, on a different FIB. Tests the same code that whose # panic was regressed by same_ip_multiple_ifaces_fib0. # Create two tap interfaces and assign them both the same IP address but with # different netmasks, and on different FIBs. Then remove one's IP # address. Hopefully the machine won't panic. Also, the IP's hostroute should # dissappear from the correct fib. atf_test_case same_ip_multiple_ifaces cleanup same_ip_multiple_ifaces_head() { atf_set "descr" "Can remove an IPv4 alias from an interface when the same address is also assigned to another interface, on non-default FIBs." atf_set "require.user" "root" } same_ip_multiple_ifaces_body() { atf_expect_fail "kern/189088 Assigning the same IP to multiple interfaces in different FIBs creates a host route for only one" ADDR="192.0.2.2" MASK0="24" MASK1="32" # Unlike most of the tests in this file, this is applicable regardless # of net.add_addr_allfibs get_fibs 2 # Setup the interfaces, then remove one alias. It should not panic. setup_tap ${FIB0} inet ${ADDR} ${MASK0} TAP0=${TAP} setup_tap ${FIB1} inet ${ADDR} ${MASK1} TAP1=${TAP} ifconfig ${TAP1} -alias ${ADDR} atf_check -o not-match:"^${ADDR}[[:space:]]" \ setfib ${FIB1} netstat -rn -f inet # Do it again, in the opposite order. It should not panic. setup_tap ${FIB0} inet ${ADDR} ${MASK0} TAP0=${TAP} setup_tap ${FIB1} inet ${ADDR} ${MASK1} TAP1=${TAP} ifconfig ${TAP0} -alias ${ADDR} atf_check -o not-match:"^${ADDR}[[:space:]]" \ setfib ${FIB0} netstat -rn -f inet } same_ip_multiple_ifaces_cleanup() { # Due to PR kern/189088, we must destroy the interfaces in LIFO order # in order for the routes to be correctly cleaned up. for TAPD in `tail -r "ifaces_to_cleanup"`; do echo ifconfig ${TAPD} destroy ifconfig ${TAPD} destroy done } atf_test_case same_ip_multiple_ifaces_inet6 cleanup same_ip_multiple_ifaces_inet6_head() { atf_set "descr" "Can remove an IPv6 alias from an interface when the same address is also assigned to another interface, on non-default FIBs." atf_set "require.user" "root" } same_ip_multiple_ifaces_inet6_body() { ADDR="2001:db8::2" MASK0="64" MASK1="128" # Unlike most of the tests in this file, this is applicable regardless # of net.add_addr_allfibs get_fibs 2 # Setup the interfaces, then remove one alias. It should not panic. setup_tap ${FIB0} inet6 ${ADDR} ${MASK0} TAP0=${TAP} setup_tap ${FIB1} inet6 ${ADDR} ${MASK1} TAP1=${TAP} atf_check -s exit:0 ifconfig ${TAP1} inet6 ${ADDR} -alias atf_check -o not-match:"^${ADDR}[[:space:]]" \ setfib ${FIB1} netstat -rn -f inet6 ifconfig ${TAP1} destroy ifconfig ${TAP0} destroy # Do it again, in the opposite order. It should not panic. setup_tap ${FIB0} inet6 ${ADDR} ${MASK0} TAP0=${TAP} setup_tap ${FIB1} inet6 ${ADDR} ${MASK1} TAP1=${TAP} atf_check -s exit:0 ifconfig ${TAP0} inet6 ${ADDR} -alias atf_check -o not-match:"^${ADDR}[[:space:]]" \ setfib ${FIB0} netstat -rn -f inet6 } same_ip_multiple_ifaces_inet6_cleanup() { cleanup_ifaces } atf_test_case slaac_on_nondefault_fib6 cleanup slaac_on_nondefault_fib6_head() { atf_set "descr" "SLAAC correctly installs routes on non-default FIBs" atf_set "require.user" "root" atf_set "require.config" "allow_sysctl_side_effects" } slaac_on_nondefault_fib6_body() { # Configure the epair interfaces to use nonrouteable RFC3849 # addresses and non-default FIBs PREFIX="2001:db8:$(printf "%x" `jot -r 1 0 65535`):$(printf "%x" `jot -r 1 0 65535`)" ADDR="$PREFIX::2" GATEWAY="$PREFIX::1" SUBNET="$PREFIX:" MASK="64" # Check system configuration if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then atf_skip "This test requires net.add_addr_allfibs=0" fi get_fibs 2 sysctl -n "net.inet6.ip6.rfc6204w3" >> "rfc6204w3.state" sysctl -n "net.inet6.ip6.forwarding" >> "forwarding.state" # Enable forwarding so the kernel will send RAs sysctl net.inet6.ip6.forwarding=1 # Enable RFC6204W3 mode so the kernel will enable default router # selection while also forwarding packets sysctl net.inet6.ip6.rfc6204w3=1 # Configure epair interfaces get_epair setup_iface "$EPAIRA" "$FIB0" inet6 ${ADDR} ${MASK} echo setfib $FIB1 ifconfig "$EPAIRB" inet6 -ifdisabled accept_rtadv fib $FIB1 up setfib $FIB1 ifconfig "$EPAIRB" inet6 -ifdisabled accept_rtadv fib $FIB1 up rtadvd -p rtadvd.pid -C rtadvd.sock -c /dev/null "$EPAIRA" rtsol "$EPAIRB" # Check SLAAC address atf_check -o match:"inet6 ${SUBNET}.*prefixlen ${MASK}.*autoconf" \ ifconfig "$EPAIRB" # Check local route atf_check -o match:"${SUBNET}.*\.*lo0" \ netstat -rnf inet6 -F $FIB1 # Check subnet route atf_check -o match:"${SUBNET}:/${MASK}.*\.*$EPAIRB" \ netstat -rnf inet6 -F $FIB1 # Check default route - atf_check -o match:"^::/0.*\.*$EPAIRB" \ + atf_check -o match:"default.*\.*$EPAIRB" \ netstat -rnf inet6 -F $FIB1 # Check that none of the above routes appeared on other routes for fib in $( seq 0 $(($(sysctl -n net.fibs) - 1))); do if [ "$fib" = "$FIB1" -o "$fib" = "$FIB0" ]; then continue fi atf_check -o not-match:"${SUBNET}.*\.*lo0" \ netstat -rnf inet6 -F $fib atf_check -o not-match:"${SUBNET}:/${MASK}.*\.*$EPAIRB" \ netstat -rnf inet6 -F $fib atf_check -o not-match:"default.*\.*$EPAIRB" \ netstat -rnf inet6 -F $fib done } slaac_on_nondefault_fib6_cleanup() { if [ -f "rtadvd.pid" ]; then # rtadvd can take a long time to shutdown. Use SIGKILL to kill # it right away. The downside to using SIGKILL is that it # won't send final RAs to all interfaces, but we don't care # because we're about to destroy its interface anyway. pkill -kill -F rtadvd.pid rm -f rtadvd.pid fi cleanup_ifaces if [ -f "forwarding.state" ] ; then sysctl "net.inet6.ip6.forwarding"=`cat "forwarding.state"` rm "forwarding.state" fi if [ -f "rfc6204w3.state" ] ; then sysctl "net.inet6.ip6.rfc6204w3"=`cat "rfc6204w3.state"` rm "rfc6204w3.state" fi } # Regression test for kern/187550 atf_test_case subnet_route_with_multiple_fibs_on_same_subnet cleanup subnet_route_with_multiple_fibs_on_same_subnet_head() { atf_set "descr" "Multiple FIBs can have IPv4 subnet routes for the same subnet" atf_set "require.user" "root" } subnet_route_with_multiple_fibs_on_same_subnet_body() { # Configure the TAP interfaces to use a RFC5737 nonrouteable addresses # and a non-default fib ADDR0="192.0.2.2" ADDR1="192.0.2.3" SUBNET="192.0.2.0" MASK="24" # Check system configuration if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then atf_skip "This test requires net.add_addr_allfibs=0" fi get_fibs 2 # Configure TAP interfaces setup_tap "$FIB0" inet ${ADDR0} ${MASK} setup_tap "$FIB1" inet ${ADDR1} ${MASK} # Check that a subnet route exists on both fibs atf_check -o ignore setfib "$FIB0" route get $ADDR1 atf_check -o ignore setfib "$FIB1" route get $ADDR0 } subnet_route_with_multiple_fibs_on_same_subnet_cleanup() { cleanup_ifaces } atf_test_case subnet_route_with_multiple_fibs_on_same_subnet_inet6 cleanup subnet_route_with_multiple_fibs_on_same_subnet_inet6_head() { atf_set "descr" "Multiple FIBs can have IPv6 subnet routes for the same subnet" atf_set "require.user" "root" } subnet_route_with_multiple_fibs_on_same_subnet_inet6_body() { # Configure the TAP interfaces to use a RFC3849 nonrouteable addresses # and a non-default fib ADDR0="2001:db8::2" ADDR1="2001:db8::3" SUBNET="2001:db8::" MASK="64" # Check system configuration if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then atf_skip "This test requires net.add_addr_allfibs=0" fi get_fibs 2 # Configure TAP interfaces setup_tap "$FIB0" inet6 ${ADDR0} ${MASK} setup_tap "$FIB1" inet6 ${ADDR1} ${MASK} # Check that a subnet route exists on both fibs atf_check -o ignore setfib "$FIB0" route -6 get $ADDR1 atf_check -o ignore setfib "$FIB1" route -6 get $ADDR0 } subnet_route_with_multiple_fibs_on_same_subnet_inet6_cleanup() { cleanup_ifaces } # Test that source address selection works correctly for UDP packets with # SO_DONTROUTE set that are sent on non-default FIBs. # This bug was discovered with "setfib 1 netperf -t UDP_STREAM -H some_host" # Regression test for kern/187553 # # The root cause was that ifa_ifwithnet() did not have a fib argument. It # would return an address from an interface on any FIB that had a subnet route # for the destination. If more than one were available, it would choose the # most specific. This is most easily tested by creating a FIB without a # default route, then trying to send a UDP packet with SO_DONTROUTE set to an # address which is not routable on that FIB. Absent the fix for this bug, # in_pcbladdr would choose an interface on any FIB with a default route. With # the fix, you will get EUNREACH or ENETUNREACH. atf_test_case udp_dontroute cleanup udp_dontroute_head() { atf_set "descr" "Source address selection for UDP packets with SO_DONTROUTE on non-default FIBs works" atf_set "require.user" "root" } udp_dontroute_body() { # Configure the TAP interface to use an RFC5737 nonrouteable address # and a non-default fib ADDR0="192.0.2.2" ADDR1="192.0.2.3" SUBNET="192.0.2.0" MASK="24" # Use a different IP on the same subnet as the target TARGET="192.0.2.100" SRCDIR=`atf_get_srcdir` # Check system configuration if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then atf_skip "This test requires net.add_addr_allfibs=0" fi get_fibs 2 # Configure the TAP interfaces setup_tap ${FIB0} inet ${ADDR0} ${MASK} TARGET_TAP=${TAP} setup_tap ${FIB1} inet ${ADDR1} ${MASK} # Send a UDP packet with SO_DONTROUTE. In the failure case, it will # return ENETUNREACH, or send the packet to the wrong tap atf_check -o ignore setfib ${FIB0} \ ${SRCDIR}/udp_dontroute ${TARGET} /dev/${TARGET_TAP} cleanup_ifaces # Repeat, but this time target the other tap setup_tap ${FIB0} inet ${ADDR0} ${MASK} setup_tap ${FIB1} inet ${ADDR1} ${MASK} TARGET_TAP=${TAP} atf_check -o ignore setfib ${FIB1} \ ${SRCDIR}/udp_dontroute ${TARGET} /dev/${TARGET_TAP} } udp_dontroute_cleanup() { cleanup_ifaces } atf_test_case udp_dontroute6 cleanup udp_dontroute6_head() { atf_set "descr" "Source address selection for UDP IPv6 packets with SO_DONTROUTE on non-default FIBs works" atf_set "require.user" "root" } udp_dontroute6_body() { if [ "$(atf_config_get ci false)" = "true" ]; then atf_skip "https://bugs.freebsd.org/244172" fi # Configure the TAP interface to use an RFC3849 nonrouteable address # and a non-default fib ADDR0="2001:db8::2" ADDR1="2001:db8::3" SUBNET="2001:db8::" MASK="64" # Use a different IP on the same subnet as the target TARGET="2001:db8::100" SRCDIR=`atf_get_srcdir` # Check system configuration if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then atf_skip "This test requires net.add_addr_allfibs=0" fi get_fibs 2 # Configure the TAP interfaces. Use no_dad so the addresses will be # ready right away and won't be marked as tentative until DAD # completes. setup_tap ${FIB0} inet6 ${ADDR0} ${MASK} no_dad TARGET_TAP=${TAP} setup_tap ${FIB1} inet6 ${ADDR1} ${MASK} no_dad # Send a UDP packet with SO_DONTROUTE. In the failure case, it will # return ENETUNREACH, or send the packet to the wrong tap atf_check -o ignore setfib ${FIB0} \ ${SRCDIR}/udp_dontroute -6 ${TARGET} /dev/${TARGET_TAP} cleanup_ifaces # Repeat, but this time target the other tap setup_tap ${FIB0} inet6 ${ADDR0} ${MASK} no_dad setup_tap ${FIB1} inet6 ${ADDR1} ${MASK} no_dad TARGET_TAP=${TAP} atf_check -o ignore setfib ${FIB1} \ ${SRCDIR}/udp_dontroute -6 ${TARGET} /dev/${TARGET_TAP} } udp_dontroute6_cleanup() { cleanup_ifaces } atf_init_test_cases() { atf_add_test_case arpresolve_checks_interface_fib atf_add_test_case loopback_and_network_routes_on_nondefault_fib atf_add_test_case loopback_and_network_routes_on_nondefault_fib_inet6 atf_add_test_case default_route_with_multiple_fibs_on_same_subnet atf_add_test_case default_route_with_multiple_fibs_on_same_subnet_inet6 atf_add_test_case same_ip_multiple_ifaces_fib0 atf_add_test_case same_ip_multiple_ifaces atf_add_test_case same_ip_multiple_ifaces_inet6 atf_add_test_case slaac_on_nondefault_fib6 atf_add_test_case subnet_route_with_multiple_fibs_on_same_subnet atf_add_test_case subnet_route_with_multiple_fibs_on_same_subnet_inet6 atf_add_test_case udp_dontroute atf_add_test_case udp_dontroute6 } # Looks up one or more fibs from the configuration data and validates them. # Returns the results in the env varilables FIB0, FIB1, etc. # parameter numfibs The number of fibs to lookup get_fibs() { NUMFIBS=$1 net_fibs=`sysctl -n net.fibs` if [ $net_fibs -lt $(($NUMFIBS + 1)) ]; then atf_check -o ignore sysctl net.fibs=$(($NUMFIBS + 1)) net_fibs=`sysctl -n net.fibs` fi i=0 while [ $i -lt "$NUMFIBS" ]; do eval FIB${i}=$(($i + 1)) i=$(( $i + 1 )) done } # Creates a new pair of connected epair(4) interface, registers them for # cleanup, and returns their namen via the environment variables EPAIRA and # EPAIRB get_epair() { local EPAIRD if (which pfctl && pfctl -s info | grep -q 'Status: Enabled') || [ `sysctl -n net.inet.ip.fw.enable` = "1" ] || (which ipf && ipf -V); then atf_skip "firewalls interfere with this test" fi if EPAIRD=`ifconfig epair create`; then # Record the epair device so we can clean it up later echo ${EPAIRD} >> "ifaces_to_cleanup" EPAIRA=${EPAIRD} EPAIRB=${EPAIRD%a}b else atf_skip "Could not create epair(4) interfaces" fi } # Creates a new tap(4) interface, registers it for cleanup, and returns the # name via the environment variable TAP get_tap() { local TAPD if TAPD=`ifconfig tap create`; then # Record the TAP device so we can clean it up later echo ${TAPD} >> "ifaces_to_cleanup" TAP=${TAPD} else atf_skip "Could not create a tap(4) interface" fi } # Configure an ethernet interface # parameters: # Interface name # fib # Protocol (inet or inet6) # IP address # Netmask in number of bits (eg 24 or 8) # Extra flags # Return: None setup_iface() { local IFACE=$1 local FIB=$2 local PROTO=$3 local ADDR=$4 local MASK=$5 local FLAGS=$6 atf_check setfib ${FIB} ifconfig $IFACE ${PROTO} ${ADDR}/${MASK} fib $FIB $FLAGS } # Create a tap(4) interface, configure it, and register it for cleanup. # parameters: # fib # Protocol (inet or inet6) # IP address # Netmask in number of bits (eg 24 or 8) # Extra flags # Return: the tap interface name as the env variable TAP setup_tap() { get_tap setup_iface "$TAP" "$@" } cleanup_ifaces() { if [ -f ifaces_to_cleanup ]; then for iface in $(cat ifaces_to_cleanup); do echo ifconfig "${iface}" destroy ifconfig "${iface}" destroy 2>/dev/null || true done rm -f ifaces_to_cleanup fi } diff --git a/tests/sys/netinet6/ndp.sh b/tests/sys/netinet6/ndp.sh index 24c0853d7361..038a640f331e 100755 --- a/tests/sys/netinet6/ndp.sh +++ b/tests/sys/netinet6/ndp.sh @@ -1,196 +1,196 @@ #!/usr/bin/env atf-sh #- # SPDX-License-Identifier: BSD-2-Clause # # Copyright (c) 2021 Alexander V. Chernikov # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # . $(atf_get_srcdir)/../common/vnet.subr atf_test_case "ndp_add_gu_success" "cleanup" ndp_add_gu_success_head() { atf_set descr 'Test static ndp record addition' atf_set require.user root } ndp_add_gu_success_body() { local epair0 jname vnet_init jname="v6t-ndp_add_success" epair0=$(vnet_mkepair) vnet_mkjail ${jname} ${epair0}a jexec ${jname} ndp -i ${epair0}a -- -disabled jexec ${jname} ifconfig ${epair0}a up jexec ${jname} ifconfig ${epair0}a inet6 2001:db8::1/64 # wait for DAD to complete while [ `jexec ${jname} ifconfig | grep inet6 | grep -c tentative` != "0" ]; do sleep 0.1 done atf_check jexec ${jname} ndp -s 2001:db8::2 90:10:00:01:02:03 t=`jexec ${jname} ndp -an | grep 2001:db8::2 | awk '{print $1, $2, $3, $4}'` if [ "${t}" != "2001:db8::2 90:10:00:01:02:03 ${epair0}a permanent" ]; then atf_fail "Wrong output: ${t}" fi echo "T='${t}'" } ndp_add_gu_success_cleanup() { vnet_cleanup } atf_test_case "ndp_del_gu_success" "cleanup" ndp_del_gu_success_head() { atf_set descr 'Test ndp record deletion' atf_set require.user root } ndp_del_gu_success_body() { local epair0 jname vnet_init jname="v6t-ndp_del_gu_success" epair0=$(vnet_mkepair) vnet_mkjail ${jname} ${epair0}a jexec ${jname} ndp -i ${epair0}a -- -disabled jexec ${jname} ifconfig ${epair0}a up jexec ${jname} ifconfig ${epair0}a inet6 2001:db8::1/64 # wait for DAD to complete while [ `jexec ${jname} ifconfig | grep inet6 | grep -c tentative` != "0" ]; do sleep 0.1 done jexec ${jname} ping -c1 -t1 2001:db8::2 atf_check -o match:"2001:db8::2 \(2001:db8::2\) deleted" jexec ${jname} ndp -nd 2001:db8::2 } ndp_del_gu_success_cleanup() { vnet_cleanup } ndp_if_up() { local ifname=$1 local jname=$2 if [ -n "$jname" ]; then jname="jexec ${jname}" fi atf_check ${jname} ifconfig ${ifname} up atf_check ${jname} ifconfig ${ifname} inet6 -ifdisabled while ${jname} ifconfig ${ifname} inet6 | grep tentative; do sleep 0.1 done } ndp_if_lladdr() { local ifname=$1 local jname=$2 if [ -n "$jname" ]; then jname="jexec ${jname}" fi ${jname} ifconfig ${ifname} inet6 | \ awk '/inet6 fe80:/{split($2, addr, "%"); print addr[1]}' } atf_test_case "ndp_slaac_default_route" "cleanup" ndp_slaac_default_route_head() { atf_set descr 'Test default route installation via SLAAC' atf_set require.user root atf_set require.progs "python" } ndp_slaac_default_route_body() { local epair0 jname lladdr vnet_init jname="v6t-ndp_slaac_default_route" epair0=$(vnet_mkepair) vnet_mkjail ${jname} ${epair0}a ndp_if_up ${epair0}a ${jname} ndp_if_up ${epair0}b atf_check jexec ${jname} ifconfig ${epair0}a inet6 accept_rtadv # Send an RA advertising a prefix. atf_check -e ignore python $(atf_get_srcdir)/ra.py \ --sendif ${epair0}b \ --dst $(ndp_if_lladdr ${epair0}a ${jname}) \ --src $(ndp_if_lladdr ${epair0}b) \ --prefix "2001:db8:ffff:1000::" --prefixlen 64 # Wait for a default router to appear. while [ -z "$(jexec ${jname} ndp -r)" ]; do sleep 0.1 done - atf_check -o match:"^::/0[[:space:]]+fe80:" \ + atf_check -o match:"^default[[:space:]]+fe80:" \ jexec ${jname} netstat -rn -6 # Get rid of the default route. jexec ${jname} route -6 flush - atf_check -o not-match:"^::/0[[:space:]]+fe80:" \ + atf_check -o not-match:"^default[[:space:]]+fe80:" \ jexec ${jname} netstat -rn -6 # Send another RA, make sure that the default route is installed again. atf_check -e ignore python $(atf_get_srcdir)/ra.py \ --sendif ${epair0}b \ --dst $(ndp_if_lladdr ${epair0}a ${jname}) \ --src $(ndp_if_lladdr ${epair0}b) \ --prefix "2001:db8:ffff:1000::" --prefixlen 64 while [ -z "$(jexec ${jname} ndp -r)" ]; do sleep 0.1 done - atf_check -o match:"^::/0[[:space:]]+fe80:" \ + atf_check -o match:"^default[[:space:]]+fe80:" \ jexec ${jname} netstat -rn -6 } ndp_slaac_default_route_cleanup() { vnet_cleanup } atf_init_test_cases() { atf_add_test_case "ndp_add_gu_success" atf_add_test_case "ndp_del_gu_success" atf_add_test_case "ndp_slaac_default_route" } diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c index 97509ea6798b..371216f4be59 100644 --- a/usr.bin/netstat/main.c +++ b/usr.bin/netstat/main.c @@ -1,944 +1,945 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1983, 1988, 1993 * Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #ifdef JAIL #include #endif #include #include #include #include #include #ifdef NETGRAPH #include #endif #include #include #ifdef JAIL #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "netstat.h" #include "nl_defs.h" #include static struct protox { int pr_index; /* index into nlist of cb head */ int pr_sindex; /* index into nlist of stat block */ u_char pr_wanted; /* 1 if wanted, 0 otherwise */ void (*pr_cblocks)(u_long, const char *, int, int); /* control blocks printing routine */ void (*pr_stats)(u_long, const char *, int, int); /* statistics printing routine */ void (*pr_istats)(char *); /* per/if statistics printing routine */ const char *pr_name; /* well-known name */ int pr_usesysctl; /* non-zero if we use sysctl, not kvm */ int pr_protocol; } protox[] = { { -1 , N_TCPSTAT, 1, protopr, tcp_stats, NULL, "tcp", 1, IPPROTO_TCP }, { -1 , N_UDPSTAT, 1, protopr, udp_stats, NULL, "udp", 1, IPPROTO_UDP }, #ifdef SCTP { -1, N_SCTPSTAT, 1, sctp_protopr, sctp_stats, NULL, "sctp", 1, IPPROTO_SCTP }, #endif #ifdef SDP { -1, -1, 1, protopr, NULL, NULL, "sdp", 1, IPPROTO_TCP }, #endif { -1 , -1, 1, protopr, divert_stats, NULL, "divert", 1, 0 }, { -1 , N_IPSTAT, 1, protopr, ip_stats, NULL, "ip", 1, IPPROTO_RAW }, { -1 , N_ICMPSTAT, 1, protopr, icmp_stats, NULL, "icmp", 1, IPPROTO_ICMP }, { -1 , N_IGMPSTAT, 1, protopr, igmp_stats, NULL, "igmp", 1, IPPROTO_IGMP }, #ifdef IPSEC { -1, N_IPSEC4STAT, 1, NULL, /* keep as compat */ ipsec_stats, NULL, "ipsec", 1, 0}, { -1, N_AHSTAT, 1, NULL, ah_stats, NULL, "ah", 1, 0}, { -1, N_ESPSTAT, 1, NULL, esp_stats, NULL, "esp", 1, 0}, { -1, N_IPCOMPSTAT, 1, NULL, ipcomp_stats, NULL, "ipcomp", 1, 0}, #endif { -1 , N_PIMSTAT, 1, protopr, pim_stats, NULL, "pim", 1, IPPROTO_PIM }, { -1, N_CARPSTATS, 1, NULL, carp_stats, NULL, "carp", 1, 0 }, #ifdef PF { -1, N_PFSYNCSTATS, 1, NULL, pfsync_stats, NULL, "pfsync", 1, 0 }, { -1, N_PFLOWSTATS, 1, NULL, pflow_stats, NULL, "pflow", 1, 0 }, #endif { -1, N_ARPSTAT, 1, NULL, arp_stats, NULL, "arp", 1, 0 }, { -1, -1, 0, NULL, NULL, NULL, NULL, 0, 0 } }; #ifdef INET6 static struct protox ip6protox[] = { { -1 , N_TCPSTAT, 1, protopr, tcp_stats, NULL, "tcp", 1, IPPROTO_TCP }, { -1 , N_UDPSTAT, 1, protopr, udp_stats, NULL, "udp", 1, IPPROTO_UDP }, { -1 , N_IP6STAT, 1, protopr, ip6_stats, ip6_ifstats, "ip6", 1, IPPROTO_RAW }, { -1 , N_ICMP6STAT, 1, protopr, icmp6_stats, icmp6_ifstats, "icmp6", 1, IPPROTO_ICMPV6 }, #ifdef SDP { -1, -1, 1, protopr, NULL, NULL, "sdp", 1, IPPROTO_TCP }, #endif #ifdef IPSEC { -1, N_IPSEC6STAT, 1, NULL, ipsec_stats, NULL, "ipsec6", 1, 0 }, #endif #ifdef notyet { -1, N_PIM6STAT, 1, NULL, pim6_stats, NULL, "pim6", 1, 0 }, #endif { -1, N_RIP6STAT, 1, NULL, rip6_stats, NULL, "rip6", 1, 0 }, { -1, -1, 0, NULL, NULL, NULL, NULL, 0, 0 } }; #endif /*INET6*/ #ifdef IPSEC static struct protox pfkeyprotox[] = { { -1, N_PFKEYSTAT, 1, NULL, pfkey_stats, NULL, "pfkey", 0, 0 }, { -1, -1, 0, NULL, NULL, NULL, NULL, 0, 0 } }; #endif #ifdef NETGRAPH static struct protox netgraphprotox[] = { { N_NGSOCKLIST, -1, 1, netgraphprotopr, NULL, NULL, "ctrl", 0, 0 }, { N_NGSOCKLIST, -1, 1, netgraphprotopr, NULL, NULL, "data", 0, 0 }, { -1, -1, 0, NULL, NULL, NULL, NULL, 0, 0 } }; #endif static struct protox *protoprotox[] = { protox, #ifdef INET6 ip6protox, #endif #ifdef IPSEC pfkeyprotox, #endif NULL }; static void printproto(struct protox *, const char *, bool *); static void usage(void) __dead2; static struct protox *name2protox(const char *); static struct protox *knownname(const char *); static int kresolve_list(struct nlist *_nl); static kvm_t *kvmd; static char *nlistf = NULL, *memf = NULL; int Aflag; /* show addresses of protocol control block */ int aflag; /* show all sockets (including servers) */ static int Bflag; /* show information about bpf consumers */ int bflag; /* show i/f total bytes in/out */ int cflag; /* show TCP congestion control stack */ int Cflag; /* show congestion control algo and vars */ int dflag; /* show i/f dropped packets */ int gflag; /* show group (multicast) routing or stats */ int hflag; /* show counters in human readable format */ int iflag; /* show interfaces */ int Lflag; /* show size of listen queues */ int mflag; /* show memory stats */ int noutputs = 0; /* how much outputs before we exit */ -int numeric_addr; /* show addresses numerically */ -int numeric_port; /* show ports numerically */ +u_int numeric_addr = 0; /* show addresses numerically */ +bool numeric_port; /* show ports numerically */ int Oflag; /* show nhgrp objects*/ int oflag; /* show nexthop objects*/ int Pflag; /* show TCP log ID */ static int pflag; /* show given protocol */ static int Qflag; /* show netisr information */ int rflag; /* show routing tables (or routing stats) */ int Rflag; /* show flow / RSS statistics */ int sflag; /* show protocol statistics */ int Wflag; /* wide display */ int Tflag; /* TCP Information */ int xflag; /* extra information, includes all socket buffer info */ int zflag; /* zero stats */ int interval; /* repeat interval for i/f stats */ char *interface; /* desired i/f for stats, or NULL for all i/fs */ int unit; /* unit number for above */ #ifdef JAIL char *jail_name; /* desired jail to operate in */ #endif static int af; /* address family */ int live; /* true if we are examining a live system */ int main(int argc, char *argv[]) { struct protox *tp = NULL; /* for printing cblocks & stats */ int ch; int fib = -1; char *endptr; bool first = true; #ifdef JAIL int jid; #endif af = AF_UNSPEC; argc = xo_parse_args(argc, argv); if (argc < 0) exit(EXIT_FAILURE); while ((ch = getopt(argc, argv, "46AaBbCcdF:f:ghI:ij:LlM:mN:nOoPp:Qq:RrSTsuWw:xz")) != -1) switch(ch) { case '4': #ifdef INET af = AF_INET; #else xo_errx(EX_UNAVAILABLE, "IPv4 support is not compiled in"); #endif break; case '6': #ifdef INET6 af = AF_INET6; #else xo_errx(EX_UNAVAILABLE, "IPv6 support is not compiled in"); #endif break; case 'A': Aflag = 1; break; case 'a': aflag = 1; break; case 'B': Bflag = 1; break; case 'b': bflag = 1; break; case 'c': cflag = 1; break; case 'C': Cflag = 1; break; case 'd': dflag = 1; break; case 'F': fib = strtol(optarg, &endptr, 0); if (*endptr != '\0' || (fib == 0 && (errno == EINVAL || errno == ERANGE))) xo_errx(EX_DATAERR, "%s: invalid fib", optarg); break; case 'f': if (strcmp(optarg, "inet") == 0) af = AF_INET; #ifdef INET6 else if (strcmp(optarg, "inet6") == 0) af = AF_INET6; #endif #ifdef IPSEC else if (strcmp(optarg, "pfkey") == 0) af = PF_KEY; #endif else if (strcmp(optarg, "unix") == 0 || strcmp(optarg, "local") == 0) af = AF_UNIX; #ifdef NETGRAPH else if (strcmp(optarg, "ng") == 0 || strcmp(optarg, "netgraph") == 0) af = AF_NETGRAPH; #endif else if (strcmp(optarg, "link") == 0) af = AF_LINK; else { xo_errx(EX_DATAERR, "%s: unknown address family", optarg); } break; case 'g': gflag = 1; break; case 'h': hflag = 1; break; case 'I': { char *cp; iflag = 1; for (cp = interface = optarg; isalpha(*cp); cp++) continue; unit = atoi(cp); break; } case 'i': iflag = 1; break; case 'j': #ifdef JAIL if (optarg == NULL) usage(); jail_name = optarg; #else xo_errx(EX_UNAVAILABLE, "Jail support is not compiled in"); #endif break; case 'L': Lflag = 1; break; case 'M': memf = optarg; break; case 'm': mflag = 1; break; case 'N': nlistf = optarg; break; case 'n': - numeric_addr = numeric_port = 1; + numeric_addr++; + numeric_port = true; break; case 'o': oflag = 1; break; case 'O': Oflag = 1; break; case 'P': Pflag = 1; break; case 'p': if ((tp = name2protox(optarg)) == NULL) { xo_errx(EX_DATAERR, "%s: unknown or uninstrumented " "protocol", optarg); } pflag = 1; break; case 'Q': Qflag = 1; break; case 'q': noutputs = atoi(optarg); if (noutputs != 0) noutputs++; break; case 'r': rflag = 1; break; case 'R': Rflag = 1; break; case 's': ++sflag; break; case 'S': numeric_addr = 1; break; case 'u': af = AF_UNIX; break; case 'W': case 'l': Wflag = 1; break; case 'w': interval = atoi(optarg); iflag = 1; break; case 'T': Tflag = 1; break; case 'x': xflag = 1; break; case 'z': zflag = 1; break; case '?': default: usage(); } argv += optind; argc -= optind; #define BACKWARD_COMPATIBILITY #ifdef BACKWARD_COMPATIBILITY if (*argv) { if (isdigit(**argv)) { interval = atoi(*argv); if (interval <= 0) usage(); ++argv; iflag = 1; } if (*argv) { nlistf = *argv; if (*++argv) memf = *argv; } } #endif #ifdef JAIL if (jail_name != NULL) { jid = jail_getid(jail_name); if (jid == -1) xo_errx(EX_UNAVAILABLE, "Jail not found"); if (jail_attach(jid) != 0) xo_errx(EX_UNAVAILABLE, "Cannot attach to jail"); } #endif /* * Discard setgid privileges if not the running kernel so that bad * guys can't print interesting stuff from kernel memory. */ live = (nlistf == NULL && memf == NULL); if (!live) { if (setgid(getgid()) != 0) xo_err(EX_OSERR, "setgid"); /* Load all necessary kvm symbols */ kresolve_list(nl); } if (xflag && Tflag) xo_errx(EX_USAGE, "-x and -T are incompatible, pick one."); if (Bflag) { if (!live) usage(); bpf_stats(interface); if (xo_finish() < 0) xo_err(EX_IOERR, "stdout"); exit(EX_OK); } if (mflag) { if (!live) { if (kread(0, NULL, 0) == 0) mbpr(kvmd, nl[N_SFSTAT].n_value); } else mbpr(NULL, 0); if (xo_finish() < 0) xo_err(EX_IOERR, "stdout"); exit(EX_OK); } if (Qflag) { if (!live) { if (kread(0, NULL, 0) == 0) netisr_stats(); } else netisr_stats(); if (xo_finish() < 0) xo_err(EX_IOERR, "stdout"); exit(EX_OK); } #if 0 /* * Keep file descriptors open to avoid overhead * of open/close on each call to get* routines. */ sethostent(1); setnetent(1); #else /* * This does not make sense any more with DNS being default over * the files. Doing a setXXXXent(1) causes a tcp connection to be * used for the queries, which is slower. */ #endif if (iflag && !sflag) { xo_open_container("statistics"); xo_set_version(NETSTAT_XO_VERSION); intpr(NULL, af); xo_close_container("statistics"); if (xo_finish() < 0) xo_err(EX_IOERR, "stdout"); exit(EX_OK); } if (rflag) { xo_open_container("statistics"); xo_set_version(NETSTAT_XO_VERSION); if (sflag) rt_stats(); else routepr(fib, af); xo_close_container("statistics"); if (xo_finish() < 0) xo_err(EX_IOERR, "stdout"); exit(EX_OK); } if (oflag) { xo_open_container("statistics"); xo_set_version(NETSTAT_XO_VERSION); nhops_print(fib, af); xo_close_container("statistics"); if (xo_finish() < 0) xo_err(EX_IOERR, "stdout"); exit(EX_OK); } if (Oflag) { xo_open_container("statistics"); xo_set_version(NETSTAT_XO_VERSION); nhgrp_print(fib, af); xo_close_container("statistics"); if (xo_finish() < 0) xo_err(EX_IOERR, "stdout"); exit(EX_OK); } if (gflag) { xo_open_container("statistics"); xo_set_version(NETSTAT_XO_VERSION); if (sflag) { if (af == AF_INET || af == AF_UNSPEC) mrt_stats(); #ifdef INET6 if (af == AF_INET6 || af == AF_UNSPEC) mrt6_stats(); #endif } else { if (af == AF_INET || af == AF_UNSPEC) mroutepr(); #ifdef INET6 if (af == AF_INET6 || af == AF_UNSPEC) mroute6pr(); #endif } xo_close_container("statistics"); if (xo_finish() < 0) xo_err(EX_IOERR, "stdout"); exit(EX_OK); } if (tp) { xo_open_container("statistics"); xo_set_version(NETSTAT_XO_VERSION); printproto(tp, tp->pr_name, &first); if (!first) xo_close_list("socket"); xo_close_container("statistics"); if (xo_finish() < 0) xo_err(EX_IOERR, "stdout"); exit(EX_OK); } xo_open_container("statistics"); xo_set_version(NETSTAT_XO_VERSION); if (af == AF_INET || af == AF_UNSPEC) for (tp = protox; tp->pr_name; tp++) printproto(tp, tp->pr_name, &first); #ifdef INET6 if (af == AF_INET6 || af == AF_UNSPEC) for (tp = ip6protox; tp->pr_name; tp++) printproto(tp, tp->pr_name, &first); #endif /*INET6*/ #ifdef IPSEC if (af == PF_KEY || af == AF_UNSPEC) for (tp = pfkeyprotox; tp->pr_name; tp++) printproto(tp, tp->pr_name, &first); #endif /*IPSEC*/ #ifdef NETGRAPH if (af == AF_NETGRAPH || af == AF_UNSPEC) for (tp = netgraphprotox; tp->pr_name; tp++) printproto(tp, tp->pr_name, &first); #endif /* NETGRAPH */ if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag) unixpr(nl[N_UNP_COUNT].n_value, nl[N_UNP_GENCNT].n_value, nl[N_UNP_DHEAD].n_value, nl[N_UNP_SHEAD].n_value, nl[N_UNP_SPHEAD].n_value, &first); if (!first) xo_close_list("socket"); xo_close_container("statistics"); if (xo_finish() < 0) xo_err(EX_IOERR, "stdout"); exit(EX_OK); } static int fetch_stats_internal(const char *sysctlname, u_long off, void *stats, size_t len, kreadfn_t kreadfn, int zero) { int error; if (live) { memset(stats, 0, len); if (zero) error = sysctlbyname(sysctlname, NULL, NULL, stats, len); else error = sysctlbyname(sysctlname, stats, &len, NULL, 0); if (error == -1 && errno != ENOENT) xo_warn("sysctl %s", sysctlname); } else { if (off == 0) return (1); error = kreadfn(off, stats, len); } return (error); } int fetch_stats(const char *sysctlname, u_long off, void *stats, size_t len, kreadfn_t kreadfn) { return (fetch_stats_internal(sysctlname, off, stats, len, kreadfn, zflag)); } int fetch_stats_ro(const char *sysctlname, u_long off, void *stats, size_t len, kreadfn_t kreadfn) { return (fetch_stats_internal(sysctlname, off, stats, len, kreadfn, 0)); } /* * Print out protocol statistics or control blocks (per sflag). * If the interface was not specifically requested, and the symbol * is not in the namelist, ignore this one. */ static void printproto(struct protox *tp, const char *name, bool *first) { void (*pr)(u_long, const char *, int, int); u_long off; bool doingdblocks = false; if (sflag) { if (iflag) { if (tp->pr_istats) intpr(tp->pr_istats, af); else if (pflag) xo_message("%s: no per-interface stats routine", tp->pr_name); return; } else { pr = tp->pr_stats; if (!pr) { if (pflag) xo_message("%s: no stats routine", tp->pr_name); return; } if (tp->pr_usesysctl && live) off = 0; else if (tp->pr_sindex < 0) { if (pflag) xo_message("%s: stats routine doesn't " "work on cores", tp->pr_name); return; } else off = nl[tp->pr_sindex].n_value; } } else { doingdblocks = true; pr = tp->pr_cblocks; if (!pr) { if (pflag) xo_message("%s: no PCB routine", tp->pr_name); return; } if (tp->pr_usesysctl && live) off = 0; else if (tp->pr_index < 0) { if (pflag) xo_message("%s: PCB routine doesn't work on " "cores", tp->pr_name); return; } else off = nl[tp->pr_index].n_value; } if (pr != NULL && (off || (live && tp->pr_usesysctl) || af != AF_UNSPEC)) { if (doingdblocks && *first) { xo_open_list("socket"); *first = false; } (*pr)(off, name, af, tp->pr_protocol); } } static int kvmd_init(void) { char errbuf[_POSIX2_LINE_MAX]; if (kvmd != NULL) return (0); kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); if (setgid(getgid()) != 0) xo_err(EX_OSERR, "setgid"); if (kvmd == NULL) { xo_warnx("kvm not available: %s", errbuf); return (-1); } return (0); } /* * Resolve symbol list, return 0 on success. */ static int kresolve_list(struct nlist *_nl) { if ((kvmd == NULL) && (kvmd_init() != 0)) return (-1); if (_nl[0].n_type != 0) return (0); if (kvm_nlist(kvmd, _nl) < 0) { if (nlistf) xo_errx(EX_UNAVAILABLE, "%s: kvm_nlist: %s", nlistf, kvm_geterr(kvmd)); else xo_errx(EX_UNAVAILABLE, "kvm_nlist: %s", kvm_geterr(kvmd)); } return (0); } /* * Wrapper of kvm_dpcpu_setcpu(). */ void kset_dpcpu(u_int cpuid) { if ((kvmd == NULL) && (kvmd_init() != 0)) xo_errx(EX_UNAVAILABLE, "%s: kvm is not available", __func__); if (kvm_dpcpu_setcpu(kvmd, cpuid) < 0) xo_errx(EX_UNAVAILABLE, "%s: kvm_dpcpu_setcpu(%u): %s", __func__, cpuid, kvm_geterr(kvmd)); return; } /* * Read kernel memory, return 0 on success. */ int kread(u_long addr, void *buf, size_t size) { if (kvmd_init() < 0) return (-1); if (!buf) return (0); if (kvm_read(kvmd, addr, buf, size) != (ssize_t)size) { xo_warnx("%s", kvm_geterr(kvmd)); return (-1); } return (0); } /* * Read single counter(9). */ uint64_t kread_counter(u_long addr) { if (kvmd_init() < 0) return (-1); return (kvm_counter_u64_fetch(kvmd, addr)); } /* * Read an array of N counters in kernel memory into array of N uint64_t's. */ int kread_counters(u_long addr, void *buf, size_t size) { uint64_t *c; u_long *counters; size_t i, n; if (kvmd_init() < 0) return (-1); if (size % sizeof(uint64_t) != 0) { xo_warnx("kread_counters: invalid counter set size"); return (-1); } n = size / sizeof(uint64_t); if ((counters = malloc(n * sizeof(u_long))) == NULL) xo_err(EX_OSERR, "malloc"); if (kread(addr, counters, n * sizeof(u_long)) < 0) { free(counters); return (-1); } c = buf; for (i = 0; i < n; i++) c[i] = kvm_counter_u64_fetch(kvmd, counters[i]); free(counters); return (0); } const char * plural(uintmax_t n) { return (n != 1 ? "s" : ""); } const char * plurales(uintmax_t n) { return (n != 1 ? "es" : ""); } const char * pluralies(uintmax_t n) { return (n != 1 ? "ies" : "y"); } /* * Find the protox for the given "well-known" name. */ static struct protox * knownname(const char *name) { struct protox **tpp, *tp; for (tpp = protoprotox; *tpp; tpp++) for (tp = *tpp; tp->pr_name; tp++) if (strcmp(tp->pr_name, name) == 0) return (tp); return (NULL); } /* * Find the protox corresponding to name. */ static struct protox * name2protox(const char *name) { struct protox *tp; char **alias; /* alias from p->aliases */ struct protoent *p; /* * Try to find the name in the list of "well-known" names. If that * fails, check if name is an alias for an Internet protocol. */ if ((tp = knownname(name)) != NULL) return (tp); setprotoent(1); /* make protocol lookup cheaper */ while ((p = getprotoent()) != NULL) { /* assert: name not same as p->name */ for (alias = p->p_aliases; *alias; alias++) if (strcmp(name, *alias) == 0) { endprotoent(); return (knownname(p->p_name)); } } endprotoent(); return (NULL); } static void usage(void) { xo_error("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", "usage: netstat [-j jail] [-46AaCcLnRSTWx] [-f protocol_family | -p protocol]\n" " [-M core] [-N system]", " netstat [-j jail] -i | -I interface [-46abdhnW] [-f address_family]\n" " [-M core] [-N system]", " netstat [-j jail] -w wait [-I interface] [-46d] [-M core] [-N system]\n" " [-q howmany]", " netstat [-j jail] -s [-46sz] [-f protocol_family | -p protocol]\n" " [-M core] [-N system]", " netstat [-j jail] -i | -I interface -s [-46s]\n" " [-f protocol_family | -p protocol] [-M core] [-N system]", " netstat [-j jail] -m [-M core] [-N system]", " netstat [-j jail] -B [-z] [-I interface]", " netstat [-j jail] -r [-46AnW] [-F fibnum] [-f address_family]\n" " [-M core] [-N system]", " netstat [-j jail] -rs [-s] [-M core] [-N system]", " netstat [-j jail] -g [-46W] [-f address_family] [-M core] [-N system]", " netstat [-j jail] -gs [-46s] [-f address_family] [-M core] [-N system]", " netstat [-j jail] -Q"); exit(EX_USAGE); } diff --git a/usr.bin/netstat/netstat.1 b/usr.bin/netstat/netstat.1 index a5bbfc2f1b35..559cb1932080 100644 --- a/usr.bin/netstat/netstat.1 +++ b/usr.bin/netstat/netstat.1 @@ -1,938 +1,944 @@ .\" Copyright (c) 1983, 1990, 1992, 1993 .\" The Regents of the University of California. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd July 29, 2024 +.Dd January 29, 2025 .Dt NETSTAT 1 .Os .Sh NAME .Nm netstat .Nd show network status and statistics .Sh SYNOPSIS .Bk -words .Bl -tag -width "netstat" .It Nm .Op Fl j Ar jail .Op Fl -libxo .Op Fl 46AaCLnPRSTWx .Op Fl f Ar protocol_family | Fl p Ar protocol .It Nm Fl i | I Ar interface .Op Fl j Ar jail .Op Fl -libxo .Op Fl 46abdhnW .Op Fl f Ar address_family .Op Fl M Ar core .Op Fl N Ar system .It Nm Fl w Ar wait .Op Fl j Ar jail .Op Fl -libxo .Op Fl I Ar interface .Op Fl 46d .Op Fl M Ar core .Op Fl N Ar system .Op Fl q Ar howmany .It Nm Fl s .Op Fl j Ar jail .Op Fl -libxo .Op Fl 46sz .Op Fl f Ar protocol_family | Fl p Ar protocol .Op Fl M Ar core .Op Fl N Ar system .It Nm Fl i | I Ar interface Fl s .Op Fl j Ar jail .Op Fl -libxo .Op Fl 46s .Op Fl f Ar protocol_family | Fl p Ar protocol .Op Fl M Ar core .Op Fl N Ar system .It Nm Fl m .Op Fl j Ar jail .Op Fl -libxo .Op Fl M Ar core .Op Fl N Ar system .It Nm Fl B .Op Fl j Ar jail .Op Fl -libxo .Op Fl z .Op Fl I Ar interface .It Nm Fl r .Op Fl j Ar jail .Op Fl -libxo .Op Fl 46nW .Op Fl F Ar fibnum .Op Fl f Ar address_family .It Nm Fl rs .Op Fl j Ar jail .Op Fl -libxo .Op Fl s .Op Fl M Ar core .Op Fl N Ar system .It Nm Fl g .Op Fl j Ar jail .Op Fl -libxo .Op Fl 46W .Op Fl f Ar address_family .It Nm Fl gs .Op Fl j Ar jail .Op Fl -libxo .Op Fl 46s .Op Fl f Ar address_family .Op Fl M Ar core .Op Fl N Ar system .It Nm Fl Q .Op Fl j Ar jail .Op Fl -libxo .El .Ek .Sh DESCRIPTION The .Nm command shows the contents of various network-related data structures. The arguments passed determine which of the below output formats the command uses. .Bl -tag -width indent .It Xo .Bk -words .Nm .Op Fl 46AaCLnRSTWx .Op Fl f Ar protocol_family | Fl p Ar protocol .Op Fl j Ar jail .Ek .Xc Display a list of active sockets (protocol control blocks) for each network protocol. .Pp The default display for active sockets shows the local and remote addresses, send and receive queue sizes (in bytes), protocol, and the internal state of the protocol. Address formats are of the form .Dq host.port or .Dq network.port if a socket's address specifies a network but no specific host address. When known, the host and network addresses are displayed symbolically according to the databases .Xr hosts 5 and .Xr networks 5 , respectively. If a symbolic name for an address is unknown, or if the .Fl n option is specified, the address is printed numerically, according to the address family. For more information regarding the Internet IPv4 .Dq dot format , refer to .Xr inet 3 . Unspecified, or .Dq wildcard , addresses and ports appear as .Dq Li * . .Bl -tag -width indent .It Fl -libxo Generate output via .Xr libxo 3 in a selection of different human and machine readable formats. See .Xr xo_parse_args 3 for details on command line arguments. .It Fl 4 Show IPv4 only. See .Sx GENERAL OPTIONS . .It Fl 6 Show IPv6 only. See .Sx GENERAL OPTIONS . .It Fl A Show the address of a protocol control block (PCB) associated with a socket; used for debugging. .It Fl a Show the state of all sockets; normally sockets used by server processes are not shown. .It Fl c Show the used TCP stack for each session. .It Fl C Show the congestion control algorithm and diagnostic information of TCP sockets. .It Fl L Show the size of the various listen queues. The first count shows the number of unaccepted connections, the second count shows the amount of unaccepted incomplete connections, and the third count is the maximum number of queued connections. .It Fl n Do not resolve numeric addresses and port numbers to names. See .Sx GENERAL OPTIONS . .It Fl P Display the log ID for each socket. .It Fl R Display the flowid and flowtype for each socket. flowid is a 32 bit hardware specific identifier for each flow. flowtype defines which protocol fields are hashed to produce the id. A complete listing is available in .Pa sys/mbuf.h under .Dv M_HASHTYPE_* . .It Fl S Show network addresses as numbers (as with .Fl n ) but show ports symbolically. .It Fl T Display diagnostic information from the TCP control block. Fields include the number of packets requiring retransmission, received out-of-order, and those advertising a zero-sized window. .It Fl W Avoid truncating addresses even if this causes some fields to overflow. .It Fl x Display socket buffer and TCP timer statistics for each internet socket. .Pp The .Fl x flag causes .Nm to output all the information recorded about data stored in the socket buffers. The fields are: .Bl -column ".Li R-HIWA" .It Li R-HIWA Ta Receive buffer high water mark, in bytes. .It Li S-HIWA Ta Send buffer high water mark, in bytes. .It Li R-LOWA Ta Receive buffer low water mark, in bytes. .It Li S-LOWA Ta Send buffer low water mark, in bytes. .It Li R-BCNT Ta Receive buffer byte count. .It Li S-BCNT Ta Send buffer byte count. .It Li R-BMAX Ta Maximum bytes that can be used in the receive buffer. .It Li S-BMAX Ta Maximum bytes that can be used in the send buffer. .It Li rexmt Ta Time, in seconds, to fire Retransmit Timer, or 0 if not armed. .It Li persist Ta Time, in seconds, to fire Retransmit Persistence, or 0 if not armed. .It Li keep Ta Time, in seconds, to fire Keep Alive, or 0 if not armed. .It Li 2msl Ta Time, in seconds, to fire 2*msl TIME_WAIT Timer, or 0 if not armed. .It Li delack Ta Time, in seconds, to fire Delayed ACK Timer, or 0 if not armed. .It Li rcvtime Ta Time, in seconds, since last packet received. .El .It Fl f Ar protocol_family Filter by .Ar protocol_family . See .Sx GENERAL OPTIONS . .It Fl p Ar protocol Filter by .Ar protocol . See .Sx GENERAL OPTIONS . .It Fl j Ar jail Run inside a jail. See .Sx GENERAL OPTIONS . .El .It Xo .Bk -words .Nm .Fl i | I Ar interface .Op Fl 46abdhnW .Op Fl f Ar address_family .Op Fl M Ar core .Op Fl N Ar system .Op Fl j Ar jail .Ek .Xc Show the state of all network interfaces or a single .Ar interface which have been auto-configured (interfaces statically configured into a system, but not located at boot time are not shown). An asterisk .Pq Dq Li * after an interface name indicates that the interface is .Dq down . .Pp When .Nm is invoked with .Fl i .Pq all interfaces or .Fl I Ar interface , it provides a table of cumulative statistics regarding packets transferred, errors, and collisions. The network addresses of the interface and the maximum transmission unit .Pq Dq mtu are also displayed. If both .Fl i and .Fl I are specified, .Fl I overrides any instances of .Fl i . .Bl -tag -width indent .It Fl 4 Show IPv4 only. See .Sx GENERAL OPTIONS . .It Fl 6 Show IPv6 only. See .Sx GENERAL OPTIONS . .It Fl a Multicast addresses currently in use are shown for each Ethernet interface and for each IP interface address. Multicast addresses are shown on separate lines following the interface address with which they are associated. .It Fl b Show the number of bytes in and out. .It Fl d Show the number of dropped output packets. .It Fl h Print all counters in human readable form. .It Fl n Do not resolve numeric addresses and port numbers to names. See .Sx GENERAL OPTIONS . .It Fl W Avoid truncating addresses even if this causes some fields to overflow. See .Sx GENERAL OPTIONS . However, in most cases field widths are determined automatically with the .Fl i option, and this option has little effect. .It Fl f Ar protocol_family Filter by .Ar protocol_family . See .Sx GENERAL OPTIONS . .It Fl j Ar jail Run inside a jail. See .Sx GENERAL OPTIONS . .El .It Xo .Bk -words .Nm .Fl w Ar wait .Op Fl I Ar interface .Op Fl 46d .Op Fl M Ar core .Op Fl N Ar system .Op Fl q Ar howmany .Op Fl j Ar jail .Ek .Xc At intervals of .Ar wait seconds, display the information regarding packet traffic on all configured network interfaces or a single .Ar interface . .Pp When .Nm is invoked with the .Fl w option and a .Ar wait interval argument, it displays a running count of statistics related to network interfaces. An obsolescent version of this option used a numeric parameter with no option, and is currently supported for backward compatibility. By default, this display summarizes information for all interfaces. Information for a specific interface may be displayed with the .Fl I Ar interface option. .Bl -tag -width indent .It Fl I Ar interface Only show information regarding .Ar interface .It Fl 4 Show IPv4 only. See .Sx GENERAL OPTIONS . .It Fl 6 Show IPv6 only. See .Sx GENERAL OPTIONS . .It Fl d Show the number of dropped output packets. .It Fl M Use an alternative core. See .Sx GENERAL OPTIONS . .It Fl N Use an alternative kernel image. See .Sx GENERAL OPTIONS . .It Fl q Exit after .Ar howmany outputs. .It Fl j Ar jail Run inside a jail. See .Sx GENERAL OPTIONS . .El .It Xo .Bk -words .Nm .Fl s .Op Fl 46sz .Op Fl f Ar protocol_family | Fl p Ar protocol .Op Fl M Ar core .Op Fl N Ar system .Op Fl j Ar jail .Ek .Xc Display system-wide statistics for each network protocol. .Bl -tag -width indent .It Fl 4 Show IPv4 only. See .Sx GENERAL OPTIONS . .It Fl 6 Show IPv6 only. See .Sx GENERAL OPTIONS . .It Fl s If .Fl s is repeated, counters with a value of zero are suppressed. .It Fl z Reset statistic counters after displaying them. .It Fl f Ar protocol_family Filter by .Ar protocol_family . See .Sx GENERAL OPTIONS . .It Fl p Ar protocol Filter by .Ar protocol . See .Sx GENERAL OPTIONS . .It Fl M Use an alternative core. See .Sx GENERAL OPTIONS . .It Fl N Use an alternative kernel image See .Sx GENERAL OPTIONS . .It Fl j Ar jail Run inside a jail. See .Sx GENERAL OPTIONS . .El .It Xo .Bk -words .Nm .Fl i | I Ar interface Fl s .Op Fl 46s .Op Fl f Ar protocol_family | Fl p Ar protocol .Op Fl M Ar core .Op Fl N Ar system .Op Fl j Ar jail .Ek .Xc Display per-interface statistics for each network protocol. If both .Fl i and .Fl I are specified, .Fl I overrides any instances of .Fl i . .Bl -tag -width indent .It Fl 4 Show IPv4 only See .Sx GENERAL OPTIONS . .It Fl 6 Show IPv6 only See .Sx GENERAL OPTIONS . .It Fl s If .Fl s is repeated, counters with a value of zero are suppressed. .It Fl f Ar protocol_family Filter by .Ar protocol_family . See .Sx GENERAL OPTIONS . .It Fl p Ar protocol Filter by .Ar protocol . See .Sx GENERAL OPTIONS . .It Fl M Use an alternative core See .Sx GENERAL OPTIONS . .It Fl N Use an alternative kernel image See .Sx GENERAL OPTIONS . .It Fl j Ar jail Run inside a jail. See .Sx GENERAL OPTIONS . .El .It Xo .Bk -words .Nm .Fl m .Op Fl M Ar core .Op Fl N Ar system .Op Fl j Ar jail .Ek .Xc Show statistics recorded by the memory management routines .Pq Xr mbuf 9 . The network manages a private pool of memory buffers. .Bl -tag -width indent .It Fl M Use an alternative core See .Sx GENERAL OPTIONS . .It Fl N Use an alternative kernel image See .Sx GENERAL OPTIONS . .It Fl j Ar jail Run inside a jail. See .Sx GENERAL OPTIONS . .El .It Xo .Bk -words .Nm .Fl B .Op Fl z .Op Fl I Ar interface .Op Fl j Ar jail .Ek .Xc Show statistics about .Xr bpf 4 peers. This includes information like how many packets have been matched, dropped and received by the bpf device, also information about current buffer sizes and device states. .Pp The .Xr bpf 4 flags displayed when .Nm is invoked with the .Fl B option represent the underlying parameters of the bpf peer. Each flag is represented as a single lower case letter. The mapping between the letters and flags in order of appearance are: .Bl -column ".Li i" .It Li p Ta Set if listening promiscuously .It Li i Ta Dv BIOCIMMEDIATE No has been set on the device .It Li f Ta Dv BIOCGHDRCMPLT No status: source link addresses are being filled automatically .It Li s Ta Dv BIOCGSEESENT No status: see packets originating locally and remotely on the interface. .It Li a Ta Packet reception generates a signal .It Li l Ta Dv BIOCLOCK No status: descriptor has been locked .El .Pp For more information about these flags, please refer to .Xr bpf 4 . .Bl -tag -width indent .It Fl z Reset statistic counters after displaying them. .It Fl j Ar jail Run inside a jail. See .Sx GENERAL OPTIONS . .El .It Xo .Bk -words .Nm .Fl r .Op Fl 46AnW .Op Fl F Ar fibnum .Op Fl f Ar address_family .Op Fl M Ar core .Op Fl N Ar system .Op Fl j Ar jail .Ek .Xc Display the contents of routing tables. .Pp When .Nm is invoked with the routing table option .Fl r , it lists the available routes and their status. Each route consists of a destination host or network, and a gateway to use in forwarding packets. The flags field shows a collection of information about the route stored as binary choices. The individual flags are discussed in more detail in the .Xr route 8 and .Xr route 4 manual pages. The mapping between letters and flags is: .Bl -column ".Li W" ".Dv RTF_WASCLONED" .It Li 1 Ta Dv RTF_PROTO1 Ta "Protocol specific routing flag #1" .It Li 2 Ta Dv RTF_PROTO2 Ta "Protocol specific routing flag #2" .It Li 3 Ta Dv RTF_PROTO3 Ta "Protocol specific routing flag #3" .It Li B Ta Dv RTF_BLACKHOLE Ta "Just discard pkts (during updates)" .It Li b Ta Dv RTF_BROADCAST Ta "The route represents a broadcast address" .It Li D Ta Dv RTF_DYNAMIC Ta "Created dynamically (by redirect)" .It Li G Ta Dv RTF_GATEWAY Ta "Destination requires forwarding by intermediary" .It Li H Ta Dv RTF_HOST Ta "Host entry (net otherwise)" .It Li L Ta Dv RTF_LLINFO Ta "Valid protocol to link address translation" .It Li M Ta Dv RTF_MODIFIED Ta "Modified dynamically (by redirect)" .It Li R Ta Dv RTF_REJECT Ta "Host or net unreachable" .It Li S Ta Dv RTF_STATIC Ta "Manually added" .It Li U Ta Dv RTF_UP Ta "Route usable" .It Li X Ta Dv RTF_XRESOLVE Ta "External daemon translates proto to link address" .El .Pp Direct routes are created for each interface attached to the local host; the gateway field for such entries shows the address of the outgoing interface. The refcnt field gives the current number of active uses of the route. Connection oriented protocols normally hold on to a single route for the duration of a connection while connectionless protocols obtain a route while sending to the same destination. The use field provides a count of the number of packets sent using that route. The interface entry indicates the network interface utilized for the route. .Bl -tag -width indent .It Fl 4 Show IPv4 only. See .Sx GENERAL OPTIONS . .It Fl 6 Show IPv6 only. See .Sx GENERAL OPTIONS . .It Fl n Do not resolve numeric addresses and port numbers to names. See .Sx GENERAL OPTIONS . .It Fl W Show the path MTU for each route, and print interface names with a wider field size. .It Fl F Display the routing table with the number .Ar fibnum . If the specified .Ar fibnum is -1 or .Fl F is not specified, the default routing table is displayed. .It Fl f Display the routing table for a particular .Ar address_family . .It Fl M Use an alternative core See .Sx GENERAL OPTIONS . .It Fl N Use an alternative kernel image See .Sx GENERAL OPTIONS . .It Fl j Ar jail Run inside a jail. See .Sx GENERAL OPTIONS . .El .It Xo .Bk -words .Nm .Fl rs .Op Fl s .Op Fl M Ar core .Op Fl N Ar system .Op Fl j Ar jail .Ek .Xc Display routing statistics. .Bl -tag -width indent .It Fl s If .Fl s is repeated, counters with a value of zero are suppressed. .It Fl M Use an alternative core See .Sx GENERAL OPTIONS . .It Fl N Use an alternative kernel image See .Sx GENERAL OPTIONS . .It Fl j Ar jail Run inside a jail. See .Sx GENERAL OPTIONS . .El .It Xo .Bk -words .Nm .Fl g .Op Fl 46W .Op Fl f Ar address_family .Op Fl M Ar core .Op Fl N Ar system .Op Fl j Ar jail .Ek .Xc Display the contents of the multicast virtual interface tables, and multicast forwarding caches. Entries in these tables will appear only when the kernel is actively forwarding multicast sessions. This option is applicable only to the .Cm inet and .Cm inet6 address families. .Bl -tag -width indent .It Fl 4 Show IPv4 only See .Sx GENERAL OPTIONS . .It Fl 6 Show IPv6 only See .Sx GENERAL OPTIONS . .It Fl W Avoid truncating addresses even if this causes some fields to overflow. .It Fl f Ar protocol_family Filter by .Ar protocol_family . See .Sx GENERAL OPTIONS . .It Fl M Use an alternative core See .Sx GENERAL OPTIONS . .It Fl N Use an alternative kernel image See .Sx GENERAL OPTIONS . .It Fl j Ar jail Run inside a jail. See .Sx GENERAL OPTIONS . .El .It Xo .Bk -words .Nm .Fl gs .Op Fl 46s .Op Fl f Ar address_family .Op Fl M Ar core .Op Fl N Ar system .Op Fl j Ar jail .Ek .Xc Show multicast routing statistics. .Bl -tag -width indent .It Fl 4 Show IPv4 only See .Sx GENERAL OPTIONS . .It Fl 6 Show IPv6 only See .Sx GENERAL OPTIONS . .It Fl s If .Fl s is repeated, counters with a value of zero are suppressed. .It Fl f Ar protocol_family Filter by .Ar protocol_family . See .Sx GENERAL OPTIONS . .It Fl M Use an alternative core See .Sx GENERAL OPTIONS . .It Fl N Use an alternative kernel image See .Sx GENERAL OPTIONS . .It Fl j Ar jail Run inside a jail. See .Sx GENERAL OPTIONS . .El .It Xo .Bk -words .Nm .Fl Q .Op Fl j Ar jail .Ek .Xc Show .Xr netisr 9 statistics. The flags field shows available ISR handlers: .Bl -column ".Li W" ".Dv NETISR_SNP_FLAGS_DRAINEDCPU" .It Li C Ta Dv NETISR_SNP_FLAGS_M2CPUID Ta "Able to map mbuf to cpu id" .It Li D Ta Dv NETISR_SNP_FLAGS_DRAINEDCPU Ta "Has queue drain handler" .It Li F Ta Dv NETISR_SNP_FLAGS_M2FLOW Ta "Able to map mbuf to flow id" .It Fl j Ar jail Run inside a jail. See .Sx GENERAL OPTIONS . .El .El .Ss GENERAL OPTIONS Some options have the general meaning: .Bl -tag -width flag .It Fl 4 Is shorthand for .Fl f .Ar inet .Pq Show only IPv4 .It Fl 6 Is shorthand for .Fl f .Ar inet6 .Pq Show only IPv6 .It Fl f Ar address_family , Fl p Ar protocol Limit display to those records of the specified .Ar address_family or a single .Ar protocol . The following address families and protocols are recognized: .Pp .Bl -tag -width ".Cm netgraph , ng Pq Dv AF_NETGRAPH" -compact .It Em Family .Em Protocols .It Cm inet Pq Dv AF_INET .Cm divert , icmp , igmp , ip , ipsec , pim, sctp , tcp , udp .It Cm inet6 Pq Dv AF_INET6 .Cm icmp6 , ip6 , ipsec6 , rip6 , sctp , tcp , udp .It Cm pfkey Pq Dv PF_KEY .Cm pfkey .It Cm netgraph , ng Pq Dv AF_NETGRAPH .Cm ctrl , data .It Cm unix Pq Dv AF_UNIX .It Cm link Pq Dv AF_LINK .El .Pp The program will complain if .Ar protocol is unknown or if there is no statistics routine for it. .It Fl M Extract values associated with the name list from the specified core instead of the default .Pa /dev/kmem . .It Fl N Extract the name list from the specified system instead of the default, which is the kernel image the system has booted from. .It Fl n Show network addresses and ports as numbers. Normally .Nm attempts to resolve addresses and ports, and display them symbolically. +Specifying +.Fl n +twice will also disable printing the keyword +.Qq Dv default +for the default IPv4 and IPv6 routes when displaying contents of routing +tables. .It Fl W Wider output; expand address fields, etc, to avoid truncation. Non-numeric values such as domain names may still be truncated; use the .Fl n option if necessary to avoid ambiguity. .It Fl j Ar jail Perform the actions inside the .Ar jail . This allows network state to be accessed even if the .Cm netstat binary is not available in the .Ar jail . .El .Sh EXAMPLES Show packet traffic information (packets, bytes, errors, packet drops, etc) for interface re0 updated every 2 seconds and exit after 5 outputs: .Bd -literal -offset indent $ netstat -w 2 -q 5 -I re0 .Ed .Pp Show statistics for ICMP on any interface: .Bd -literal -offset indent $ netstat -s -p icmp .Ed .Pp Show routing tables: .Bd -literal -offset indent $ netstat -r .Ed .Pp Same as above, but without resolving numeric addresses and port numbers to names: .Bd -literal -offset indent $ netstat -rn .Ed .Sh SEE ALSO .Xr fstat 1 , .Xr nfsstat 1 , .Xr procstat 1 , .Xr ps 1 , .Xr sockstat 1 , .Xr libxo 3 , .Xr xo_parse_args 3 , .Xr bpf 4 , .Xr inet 4 , .Xr route 4 , .Xr unix 4 , .Xr hosts 5 , .Xr networks 5 , .Xr protocols 5 , .Xr services 5 , .Xr iostat 8 , .Xr route 8 , .Xr vmstat 8 , .Xr mbuf 9 .Sh HISTORY The .Nm command appeared in .Bx 4.2 . .Pp IPv6 support was added by WIDE/KAME project. .Sh BUGS The notion of errors is ill-defined. diff --git a/usr.bin/netstat/netstat.h b/usr.bin/netstat/netstat.h index 7ebfc5180f44..7e37b9e5e820 100644 --- a/usr.bin/netstat/netstat.h +++ b/usr.bin/netstat/netstat.h @@ -1,168 +1,168 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1992, 1993 * Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #define NETSTAT_XO_VERSION "1" #define satosin(sa) ((struct sockaddr_in *)(sa)) #define satosin6(sa) ((struct sockaddr_in6 *)(sa)) #define sin6tosa(sin6) ((struct sockaddr *)(sin6)) extern int Aflag; /* show addresses of protocol control block */ extern int aflag; /* show all sockets (including servers) */ extern int bflag; /* show i/f total bytes in/out */ extern int cflag; /* show congestion control stats */ extern int Cflag; /* show congestion control algo and stack */ extern int dflag; /* show i/f dropped packets */ extern int gflag; /* show group (multicast) routing or stats */ extern int hflag; /* show counters in human readable format */ extern int iflag; /* show interfaces */ extern int Lflag; /* show size of listen queues */ extern int mflag; /* show memory stats */ extern int noutputs; /* how much outputs before we exit */ -extern int numeric_addr; /* show addresses numerically */ -extern int numeric_port; /* show ports numerically */ +extern u_int numeric_addr; /* show addresses numerically */ +extern bool numeric_port; /* show ports numerically */ extern int Pflag; /* show TCP log ID */ extern int rflag; /* show routing tables (or routing stats) */ extern int Rflag; /* show flowid / RSS information */ extern int sflag; /* show protocol statistics */ extern int Tflag; /* show TCP control block info */ extern int Wflag; /* wide display */ extern int xflag; /* extended display, includes all socket buffer info */ extern int zflag; /* zero stats */ extern int interval; /* repeat interval for i/f stats */ extern char *interface; /* desired i/f for stats, or NULL for all i/fs */ extern int unit; /* unit number for above */ extern int live; /* true if we are examining a live system */ typedef int kreadfn_t(u_long, void *, size_t); int fetch_stats(const char *, u_long, void *, size_t, kreadfn_t); int fetch_stats_ro(const char *, u_long, void *, size_t, kreadfn_t); int kread(u_long addr, void *buf, size_t size); uint64_t kread_counter(u_long addr); int kread_counters(u_long addr, void *buf, size_t size); void kset_dpcpu(u_int); const char *plural(uintmax_t); const char *plurales(uintmax_t); const char *pluralies(uintmax_t); struct sockaddr; struct socket; struct xsocket; int sotoxsocket(struct socket *, struct xsocket *); void protopr(u_long, const char *, int, int); void tcp_stats(u_long, const char *, int, int); void udp_stats(u_long, const char *, int, int); #ifdef SCTP void sctp_protopr(u_long, const char *, int, int); void sctp_stats(u_long, const char *, int, int); #endif void arp_stats(u_long, const char *, int, int); void divert_stats(u_long, const char *, int, int); void ip_stats(u_long, const char *, int, int); void icmp_stats(u_long, const char *, int, int); void igmp_stats(u_long, const char *, int, int); void pim_stats(u_long, const char *, int, int); void carp_stats(u_long, const char *, int, int); void pfsync_stats(u_long, const char *, int, int); void pflow_stats(u_long, const char *, int, int); #ifdef IPSEC void ipsec_stats(u_long, const char *, int, int); void esp_stats(u_long, const char *, int, int); void ah_stats(u_long, const char *, int, int); void ipcomp_stats(u_long, const char *, int, int); #endif #ifdef INET struct in_addr; char *inetname(struct in_addr *); #endif #ifdef INET6 struct in6_addr; char *inet6name(struct in6_addr *); void ip6_stats(u_long, const char *, int, int); void ip6_ifstats(char *); void icmp6_stats(u_long, const char *, int, int); void icmp6_ifstats(char *); void pim6_stats(u_long, const char *, int, int); void rip6_stats(u_long, const char *, int, int); void mroute6pr(void); void mrt6_stats(void); struct sockaddr_in6; struct in6_addr; void in6_fillscopeid(struct sockaddr_in6 *); void inet6print(const char *, struct in6_addr *, int, const char *, int); #endif /*INET6*/ #ifdef IPSEC void pfkey_stats(u_long, const char *, int, int); #endif void mbpr(void *, u_long); void netisr_stats(void); void hostpr(u_long, u_long); void impstats(u_long, u_long); void intpr(void (*)(char *), int); void pr_family(int); void rt_stats(void); char *routename(struct sockaddr *, int); const char *netname(struct sockaddr *, struct sockaddr *); void routepr(int, int); int p_sockaddr(const char *name, struct sockaddr *sa, struct sockaddr *mask, int flags, int width); const char *fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags); #ifdef NETGRAPH void netgraphprotopr(u_long, const char *, int, int); #endif void unixpr(u_long, u_long, u_long, u_long, u_long, bool *); void mroutepr(void); void mrt_stats(void); void bpf_stats(char *); void nhops_print(int fibnum, int af); void nhgrp_print(int fibnum, int af); diff --git a/usr.bin/netstat/route.c b/usr.bin/netstat/route.c index c54b1e61aa11..697c7ba2e9e1 100644 --- a/usr.bin/netstat/route.c +++ b/usr.bin/netstat/route.c @@ -1,724 +1,724 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1983, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "netstat.h" #include "common.h" #include "nl_defs.h" /* * Definitions for showing gateway flags. */ struct bits rt_bits[] = { { RTF_UP, 'U', "up" }, { RTF_GATEWAY, 'G', "gateway" }, { RTF_HOST, 'H', "host" }, { RTF_REJECT, 'R', "reject" }, { RTF_DYNAMIC, 'D', "dynamic" }, { RTF_MODIFIED, 'M', "modified" }, { RTF_DONE, 'd', "done" }, /* Completed -- for routing msgs only */ { RTF_XRESOLVE, 'X', "xresolve" }, { RTF_STATIC, 'S', "static" }, { RTF_PROTO1, '1', "proto1" }, { RTF_PROTO2, '2', "proto2" }, { RTF_PROTO3, '3', "proto3" }, { RTF_BLACKHOLE,'B', "blackhole" }, { RTF_BROADCAST,'b', "broadcast" }, #ifdef RTF_LLINFO { RTF_LLINFO, 'L', "llinfo" }, #endif { 0 , 0, NULL } }; #ifdef WITHOUT_NETLINK static struct ifmap_entry *ifmap; static size_t ifmap_size; #endif static struct timespec uptime; static const char *netname4(in_addr_t, in_addr_t); #ifdef INET6 static const char *netname6(struct sockaddr_in6 *, struct sockaddr_in6 *); #endif #ifdef WITHOUT_NETLINK static void p_rtable_sysctl(int, int); static void p_rtentry_sysctl(const char *name, struct rt_msghdr *); #endif static void domask(char *, size_t, u_long); const uint32_t rt_default_weight = RT_DEFAULT_WEIGHT; /* * Print routing tables. */ void routepr(int fibnum, int af) { size_t intsize; int numfibs; if (live == 0) return; intsize = sizeof(int); if (fibnum == -1 && sysctlbyname("net.my_fibnum", &fibnum, &intsize, NULL, 0) == -1) fibnum = 0; if (sysctlbyname("net.fibs", &numfibs, &intsize, NULL, 0) == -1) numfibs = 1; if (fibnum < 0 || fibnum > numfibs - 1) xo_errx(EX_USAGE, "%d: invalid fib", fibnum); /* * Since kernel & userland use different timebase * (time_uptime vs time_second) and we are reading kernel memory * directly we should do rt_expire --> expire_time conversion. */ if (clock_gettime(CLOCK_UPTIME, &uptime) < 0) xo_err(EX_OSERR, "clock_gettime() failed"); xo_open_container("route-information"); xo_emit("{T:Routing tables}"); if (fibnum) xo_emit(" ({L:fib}: {:fib/%d})", fibnum); xo_emit("\n"); #ifdef WITHOUT_NETLINK p_rtable_sysctl(fibnum, af); #else p_rtable_netlink(fibnum, af); #endif xo_close_container("route-information"); } /* * Print address family header before a section of the routing table. */ void pr_family(int af1) { const char *afname; switch (af1) { case AF_INET: afname = "Internet"; break; #ifdef INET6 case AF_INET6: afname = "Internet6"; break; #endif /*INET6*/ case AF_ISO: afname = "ISO"; break; case AF_CCITT: afname = "X.25"; break; case AF_NETGRAPH: afname = "Netgraph"; break; default: afname = NULL; break; } if (afname) xo_emit("\n{k:address-family/%s}:\n", afname); else xo_emit("\n{L:Protocol Family} {k:address-family/%d}:\n", af1); } /* column widths; each followed by one space */ #define WID_IF_DEFAULT (Wflag ? IFNAMSIZ : 12) /* width of netif column */ #ifndef INET6 #define WID_DST_DEFAULT(af) 18 /* width of destination column */ #define WID_GW_DEFAULT(af) 18 /* width of gateway column */ #else #define WID_DST_DEFAULT(af) \ ((af) == AF_INET6 ? (numeric_addr ? 33: 18) : 18) #define WID_GW_DEFAULT(af) \ ((af) == AF_INET6 ? (numeric_addr ? 29 : 18) : 18) #endif /*INET6*/ struct _wid wid; /* * Print header for routing table columns. */ void pr_rthdr(int af1 __unused) { if (Wflag) { xo_emit("{T:/%-*.*s} {T:/%-*.*s} {T:/%-*.*s} {T:/%*.*s} " "{T:/%*.*s} {T:/%*.*s} {T:/%*s}\n", wid.dst, wid.dst, "Destination", wid.gw, wid.gw, "Gateway", wid.flags, wid.flags, "Flags", wid.mtu, wid.mtu, "Nhop#", wid.mtu, wid.mtu, "Mtu", wid.iface, wid.iface, "Netif", wid.expire, "Expire"); } else { xo_emit("{T:/%-*.*s} {T:/%-*.*s} {T:/%-*.*s} {T:/%*.*s} " "{T:/%*s}\n", wid.dst, wid.dst, "Destination", wid.gw, wid.gw, "Gateway", wid.flags, wid.flags, "Flags", wid.iface, wid.iface, "Netif", wid.expire, "Expire"); } } void set_wid(int fam) { wid.dst = WID_DST_DEFAULT(fam); wid.gw = WID_GW_DEFAULT(fam); wid.flags = 6; wid.pksent = 8; wid.mtu = 6; wid.iface = WID_IF_DEFAULT; wid.expire = 6; } #ifdef WITHOUT_NETLINK static void p_rtable_sysctl(int fibnum, int af) { size_t needed; int mib[7]; char *buf, *next, *lim; struct rt_msghdr *rtm; struct sockaddr *sa; int fam = AF_UNSPEC; int need_table_close = false; ifmap = prepare_ifmap(&ifmap_size); mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = af; mib[4] = NET_RT_DUMP; mib[5] = 0; mib[6] = fibnum; if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0) xo_err(EX_OSERR, "sysctl: net.route.0.%d.dump.%d estimate", af, fibnum); if ((buf = malloc(needed)) == NULL) xo_errx(EX_OSERR, "malloc(%lu)", (unsigned long)needed); if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) xo_err(EX_OSERR, "sysctl: net.route.0.%d.dump.%d", af, fibnum); lim = buf + needed; xo_open_container("route-table"); xo_open_list("rt-family"); for (next = buf; next < lim; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; if (rtm->rtm_version != RTM_VERSION) continue; /* * Peek inside header to determine AF */ sa = (struct sockaddr *)(rtm + 1); /* Only print family first time. */ if (fam != sa->sa_family) { if (need_table_close) { xo_close_list("rt-entry"); xo_close_instance("rt-family"); } need_table_close = true; fam = sa->sa_family; set_wid(fam); xo_open_instance("rt-family"); pr_family(fam); xo_open_list("rt-entry"); pr_rthdr(fam); } p_rtentry_sysctl("rt-entry", rtm); } if (need_table_close) { xo_close_list("rt-entry"); xo_close_instance("rt-family"); } xo_close_list("rt-family"); xo_close_container("route-table"); free(buf); } static void p_rtentry_sysctl(const char *name, struct rt_msghdr *rtm) { struct sockaddr *sa, *addr[RTAX_MAX]; char buffer[128]; char prettyname[128]; int i, protrusion; xo_open_instance(name); sa = (struct sockaddr *)(rtm + 1); for (i = 0; i < RTAX_MAX; i++) { if (rtm->rtm_addrs & (1 << i)) { addr[i] = sa; sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa)); } } protrusion = p_sockaddr("destination", addr[RTAX_DST], addr[RTAX_NETMASK], rtm->rtm_flags, wid.dst); protrusion = p_sockaddr("gateway", addr[RTAX_GATEWAY], NULL, RTF_HOST, wid.gw - protrusion); snprintf(buffer, sizeof(buffer), "{[:-%d}{:flags/%%s}{]:} ", wid.flags - protrusion); p_flags(rtm->rtm_flags, buffer); /* Output path weight as non-visual property */ xo_emit("{e:weight/%u}", rtm->rtm_rmx.rmx_weight); if (Wflag) { /* XXX: use=0? */ xo_emit("{t:nhop/%*lu} ", wid.mtu, rtm->rtm_rmx.rmx_nhidx); if (rtm->rtm_rmx.rmx_mtu != 0) xo_emit("{t:mtu/%*lu} ", wid.mtu, rtm->rtm_rmx.rmx_mtu); else xo_emit("{P:/%*s} ", wid.mtu, ""); } memset(prettyname, 0, sizeof(prettyname)); if (rtm->rtm_index < ifmap_size) { strlcpy(prettyname, ifmap[rtm->rtm_index].ifname, sizeof(prettyname)); if (*prettyname == '\0') strlcpy(prettyname, "---", sizeof(prettyname)); } if (Wflag) xo_emit("{t:interface-name/%*s}", wid.iface, prettyname); else xo_emit("{t:interface-name/%*.*s}", wid.iface, wid.iface, prettyname); if (rtm->rtm_rmx.rmx_expire) { time_t expire_time; if ((expire_time = rtm->rtm_rmx.rmx_expire - uptime.tv_sec) > 0) xo_emit(" {:expire-time/%*d}", wid.expire, (int)expire_time); } xo_emit("\n"); xo_close_instance(name); } #endif int p_sockaddr(const char *name, struct sockaddr *sa, struct sockaddr *mask, int flags, int width) { const char *cp; char buf[128]; int protrusion; cp = fmt_sockaddr(sa, mask, flags); if (width < 0) { snprintf(buf, sizeof(buf), "{:%s/%%s} ", name); xo_emit(buf, cp); protrusion = 0; } else { if (Wflag != 0 || numeric_addr) { snprintf(buf, sizeof(buf), "{[:%d}{:%s/%%s}{]:} ", -width, name); xo_emit(buf, cp); protrusion = strlen(cp) - width; if (protrusion < 0) protrusion = 0; } else { snprintf(buf, sizeof(buf), "{[:%d}{:%s/%%-.*s}{]:} ", -width, name); xo_emit(buf, width, cp); protrusion = 0; } } return (protrusion); } const char * fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags) { static char buf[128]; const char *cp; if (sa == NULL) return ("null"); switch(sa->sa_family) { #ifdef INET6 case AF_INET6: /* * The sa6->sin6_scope_id must be filled here because * this sockaddr is extracted from kmem(4) directly * and has KAME-specific embedded scope id in * sa6->sin6_addr.s6_addr[2]. */ in6_fillscopeid(satosin6(sa)); /* FALLTHROUGH */ #endif /*INET6*/ case AF_INET: if (flags & RTF_HOST) cp = routename(sa, numeric_addr); else if (mask) cp = netname(sa, mask); else cp = netname(sa, NULL); break; case AF_NETGRAPH: { strlcpy(buf, ((struct sockaddr_ng *)sa)->sg_data, sizeof(buf)); cp = buf; break; } case AF_LINK: { #if 0 struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; /* Interface route. */ if (sdl->sdl_nlen) cp = sdl->sdl_data; else #endif cp = routename(sa, 1); break; } default: { u_char *s = (u_char *)sa->sa_data, *slim; char *cq, *cqlim; cq = buf; slim = sa->sa_len + (u_char *) sa; cqlim = cq + sizeof(buf) - sizeof(" ffff"); snprintf(cq, sizeof(buf), "(%d)", sa->sa_family); cq += strlen(cq); while (s < slim && cq < cqlim) { snprintf(cq, sizeof(" ff"), " %02x", *s++); cq += strlen(cq); if (s < slim) { snprintf(cq, sizeof("ff"), "%02x", *s++); cq += strlen(cq); } } cp = buf; } } return (cp); } void p_flags(int f, const char *format) { print_flags_generic(f, rt_bits, format, "flags_pretty"); } char * routename(struct sockaddr *sa, int flags) { static char line[NI_MAXHOST]; int error, f; f = (flags) ? NI_NUMERICHOST : 0; error = getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, f); if (error) { const void *src; switch (sa->sa_family) { #ifdef INET case AF_INET: src = &satosin(sa)->sin_addr; break; #endif /* INET */ #ifdef INET6 case AF_INET6: src = &satosin6(sa)->sin6_addr; break; #endif /* INET6 */ default: return(line); } inet_ntop(sa->sa_family, src, line, sizeof(line) - 1); return (line); } trimdomain(line, strlen(line)); return (line); } #define NSHIFT(m) ( \ (m) == IN_CLASSA_NET ? IN_CLASSA_NSHIFT : \ (m) == IN_CLASSB_NET ? IN_CLASSB_NSHIFT : \ (m) == IN_CLASSC_NET ? IN_CLASSC_NSHIFT : \ 0) static void domask(char *dst, size_t buflen, u_long mask) { int b, i; if (mask == 0) { *dst = '\0'; return; } i = 0; for (b = 0; b < 32; b++) if (mask & (1 << b)) { int bb; i = b; for (bb = b+1; bb < 32; bb++) if (!(mask & (1 << bb))) { i = -1; /* noncontig */ break; } break; } if (i == -1) snprintf(dst, buflen, "&0x%lx", mask); else snprintf(dst, buflen, "/%d", 32-i); } /* * Return the name of the network whose address is given. */ const char * netname(struct sockaddr *sa, struct sockaddr *mask) { switch (sa->sa_family) { case AF_INET: if (mask != NULL) return (netname4(satosin(sa)->sin_addr.s_addr, satosin(mask)->sin_addr.s_addr)); else return (netname4(satosin(sa)->sin_addr.s_addr, INADDR_ANY)); break; #ifdef INET6 case AF_INET6: return (netname6(satosin6(sa), satosin6(mask))); #endif /* INET6 */ default: return (NULL); } } static const char * netname4(in_addr_t in, in_addr_t mask) { char *cp = 0; static char line[MAXHOSTNAMELEN + sizeof("&0xffffffff")]; char nline[INET_ADDRSTRLEN]; struct netent *np = 0; in_addr_t i; - if (!numeric_addr && in == INADDR_ANY && mask == 0) { + if (numeric_addr < 2 && in == INADDR_ANY && mask == 0) { strlcpy(line, "default", sizeof(line)); return (line); } /* It is ok to supply host address. */ in &= mask; i = ntohl(in); if (!numeric_addr && i) { np = getnetbyaddr(i >> NSHIFT(ntohl(mask)), AF_INET); if (np != NULL) { cp = np->n_name; trimdomain(cp, strlen(cp)); } } if (cp != NULL) strlcpy(line, cp, sizeof(line)); else { inet_ntop(AF_INET, &in, nline, sizeof(nline)); strlcpy(line, nline, sizeof(line)); domask(line + strlen(line), sizeof(line) - strlen(line), ntohl(mask)); } return (line); } #undef NSHIFT #ifdef INET6 void in6_fillscopeid(struct sockaddr_in6 *sa6) { #if defined(__KAME__) /* * XXX: This is a special workaround for KAME kernels. * sin6_scope_id field of SA should be set in the future. */ if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) || IN6_IS_ADDR_MC_NODELOCAL(&sa6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sa6->sin6_addr)) { if (sa6->sin6_scope_id == 0) sa6->sin6_scope_id = ntohs(*(u_int16_t *)&sa6->sin6_addr.s6_addr[2]); sa6->sin6_addr.s6_addr[2] = sa6->sin6_addr.s6_addr[3] = 0; } #endif } /* Mask to length table. To check an invalid value, (length + 1) is used. */ static const u_char masktolen[256] = { [0xff] = 8 + 1, [0xfe] = 7 + 1, [0xfc] = 6 + 1, [0xf8] = 5 + 1, [0xf0] = 4 + 1, [0xe0] = 3 + 1, [0xc0] = 2 + 1, [0x80] = 1 + 1, [0x00] = 0 + 1, }; static const char * netname6(struct sockaddr_in6 *sa6, struct sockaddr_in6 *mask) { static char line[NI_MAXHOST + sizeof("/xxx") - 1]; struct sockaddr_in6 addr; char nline[NI_MAXHOST]; char maskbuf[sizeof("/xxx")]; u_char *p, *lim; u_char masklen; int i; bool illegal = false; if (mask) { p = (u_char *)&mask->sin6_addr; for (masklen = 0, lim = p + 16; p < lim; p++) { if (masktolen[*p] > 0) { /* -1 is required. */ masklen += (masktolen[*p] - 1); } else illegal = true; } if (illegal) xo_error("illegal prefixlen\n"); memcpy(&addr, sa6, sizeof(addr)); for (i = 0; i < 16; ++i) addr.sin6_addr.s6_addr[i] &= mask->sin6_addr.s6_addr[i]; sa6 = &addr; } else masklen = 128; - if (!numeric_addr && masklen == 0 && + if (numeric_addr < 2 && masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr)) return("default"); getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, nline, sizeof(nline), NULL, 0, NI_NUMERICHOST); if (numeric_addr) strlcpy(line, nline, sizeof(line)); else getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line), NULL, 0, 0); if (numeric_addr || strcmp(line, nline) == 0) { snprintf(maskbuf, sizeof(maskbuf), "/%d", masklen); strlcat(line, maskbuf, sizeof(line)); } return (line); } #endif /*INET6*/ /* * Print routing statistics */ void rt_stats(void) { struct rtstat rtstat; if (fetch_stats("net.route.stats", nl[N_RTSTAT].n_value, &rtstat, sizeof(rtstat), kread_counters) != 0) return; xo_emit("{T:routing}:\n"); #define p(f, m) if (rtstat.f || sflag <= 1) \ xo_emit(m, rtstat.f, plural(rtstat.f)) p(rts_badredirect, "\t{:bad-redirects/%ju} " "{N:/bad routing redirect%s}\n"); p(rts_dynamic, "\t{:dynamically-created/%ju} " "{N:/dynamically created route%s}\n"); p(rts_newgateway, "\t{:new-gateways/%ju} " "{N:/new gateway%s due to redirects}\n"); p(rts_unreach, "\t{:unreachable-destination/%ju} " "{N:/destination%s found unreachable}\n"); p(rts_wildcard, "\t{:wildcard-uses/%ju} " "{N:/use%s of a wildcard route}\n"); #undef p }