diff options
Diffstat (limited to 'sbin')
30 files changed, 655 insertions, 341 deletions
diff --git a/sbin/bectl/bectl.8 b/sbin/bectl/bectl.8 index cc88c7019d13..0e08b3383e9a 100644 --- a/sbin/bectl/bectl.8 +++ b/sbin/bectl/bectl.8 @@ -3,12 +3,12 @@ .\" .\" SPDX-License-Identifier: BSD-2-Clause .\" -.Dd April 9, 2024 +.Dd June 13, 2025 .Dt BECTL 8 .Os .Sh NAME .Nm bectl -.Nd Utility to manage boot environments on ZFS +.Nd manage ZFS boot environments .Sh SYNOPSIS .Nm .Op Fl h @@ -80,34 +80,31 @@ .Sh DESCRIPTION The .Nm -command is used to setup and interact with ZFS boot environments, which are -bootable clones of datasets. -.Pp -A boot environment allows the system to be upgraded, while preserving the -pre-upgrade system environment. -.Pp -.Nm -itself accepts an -.Fl r -flag specified before the command to indicate the -.Ar beroot -that should be used as the boot environment root, or the dataset whose children -are all boot environments. -Normally this information is derived from the bootfs property of the pool that -is mounted at -.Pa / , -but it is useful when the system has not been booted into a ZFS root or a -different pool should be operated on. -For instance, booting into the recovery media and manually importing a pool from -one of the system's resident disks will require the -.Fl r -flag to work. +utility manages bootable ZFS clones called boot environments. +Boot envionments allow system changes to be tested safely, +as they are selectable directly from the boot +.Xr loader 8 . +This utility can +.Cm create , +.Cm list , +.Cm mount , +or +.Cm jail +boot environments. +Once the changes have been tested, the boot environment can be +.Cm unmount Ns ed , +.Cm activate Ns d , +.Cm rename Ns d , +and +.Cm destroy Ns ed . .Ss Supported Subcommands and Flags -.Bl -tag -width activate -.It Xo -.Fl h -.Xc +.Bl -tag -width indent +.It Fl h Print usage information and exit. +.It Fl r Ar beroot Sy Ar subcommand +Specify a parent dataset for the boot environment to use for +.Ar subcommand +for operation on manually imported pools or unusual layouts. .It Xo .Cm activate .Op Fl t | Fl T @@ -122,19 +119,19 @@ flag is given, this takes effect only for the next boot. Flag .Fl T removes temporary boot once configuration. -Without temporary configuration, the next boot will use zfs dataset specified -in boot pool +Without temporary configuration, +the next boot will use zfs dataset specified in boot pool .Ar bootfs property. .It Xo .Cm check .Xc -Performs a silent sanity check on the current system. +Perform a check to see if the current system can use boot environments. If boot environments are supported and used, .Nm will exit with a status code of 0. -Any other status code is not currently defined and may, in the future, grow -special meaning for different degrees of sanity check failures. +Any other status code is not currently defined and may, in the future, +grow special meaning for different degrees of sanity check failures. .It Xo .Cm create .Op Fl r @@ -162,8 +159,8 @@ environment. .Pp If .Nm -is creating from another boot environment, a snapshot of that boot environment -will be created to clone from. +is creating from another boot environment, +a snapshot of that boot environment will be created to clone from. .It Xo .Cm create .Op Fl r @@ -174,8 +171,10 @@ Create a snapshot of the boot environment named .Pp If the .Fl r -flag is given, a recursive snapshot of the boot environment will be created. -A snapshot is created for each descendant dataset of the boot environment. +flag is given, +a recursive snapshot of the boot environment will be created. +A snapshot is created for each descendant dataset +of the boot environment. See .Sx Boot Environment Structures for a discussion on different layouts. @@ -241,8 +240,8 @@ If .Ar utility is specified, it will be executed instead of .Pa /bin/sh . -The jail will be destroyed and the boot environment unmounted when the command -finishes executing, unless the +The jail will be destroyed and the boot environment unmounted +when the command finishes executing, unless the .Fl U argument is specified. .Pp @@ -269,11 +268,11 @@ The following default parameters are provided: .It Va allow.mount Ta Cm true .It Va allow.mount.devfs Ta Cm true .It Va enforce_statfs Ta Cm 1 -.It Va name Ta Set to jail ID. +.It Va name Ta set to jail ID .It Va host.hostname Ta Va bootenv -.It Va path Ta Set to a path in Pa /tmp +.It Va path Ta set to a path in Pa /tmp generated by -.Xr libbe 3 . +.Xr libbe 3 .El .Pp All default parameters may be overwritten. @@ -298,8 +297,8 @@ or combination of .It Fl a Display all datasets. .It Fl D -Display the full space usage for each boot environment, assuming all -other boot environments were destroyed. +Display the full space usage for each boot environment, +assuming all other boot environments were destroyed. .It Fl H Used for scripting. Do not print headers and separate fields by a single tab instead of @@ -351,8 +350,8 @@ will make a directory such as .Pa be_mount.c6Sf in .Pa /tmp . -Randomness in the last four characters of the directory name will prevent -mount point conflicts. +Randomness in the last four characters of the directory name +will prevent mount point conflicts. Unmount of an environment, followed by mount of the same environment without giving a .Ar mountpoint , @@ -362,7 +361,7 @@ Rename the given .Ar origBeName to the given .Ar newBeName . -The boot environment will not be unmounted in order for this rename to occur. +The boot environment will not be unmounted for this rename to occur. .It Cm ujail Brq Ar jailId | jailName | beName .It Cm unjail Brq Ar jailId | jailName | beName Destroy the jail created from the given boot environment. @@ -390,8 +389,8 @@ boot environment layout, as created by the Auto ZFS option to .Xr bsdinstall 8 , is a .Dq shallow -boot environment structure, where boot environment datasets do not have any -directly subordinate datasets. +boot environment structure, where boot environment datasets +do not have any directly subordinate datasets. Instead, they're organized off in .Pa zroot/ROOT , and they rely on datasets elsewhere in the pool having @@ -419,7 +418,8 @@ set to .Dv off , thus files in .Pa /usr -typically fall into the boot environment because this dataset is not mounted. +typically fall into the boot environment +because this dataset is not mounted. .Pa zroot/usr/src is mounted, thus files in .Pa /usr/src @@ -445,8 +445,8 @@ Note that the subordinate datasets now have .Dv canmount set to .Dv noauto . -These are more obviously a part of the boot environment, as indicated by their -positioning in the layout. +These are more obviously a part of the boot environment, +as indicated by their positioning in the layout. These subordinate datasets will be mounted by the .Dv zfsbe .Xr rc 8 @@ -468,16 +468,25 @@ A future version of may default to handling both styles and deprecate the various .Fl r flags. -.\" .Sh EXAMPLES -.\" .Bl -bullet -.\" .It +.Sh EXAMPLES +Create a boot environment, named with today's date, +containing snapshots of the root dataset and of all child datasets: +.Pp +.Dl bectl create -r `date +%Y%m%d` +.Pp +Mount a previous boot environment, +.Ar yesterdaysbe , +to +.Pa /mnt : +.Pp +.Dl bectl mount yesterdaysbe /mnt .\" To fill in with jail upgrade example when behavior is firm. -.\" .El .Sh SEE ALSO .Xr libbe 3 , .Xr zfsprops 7 , .Xr beinstall.sh 8 , .Xr jail 8 , +.Xr loader 8 , .Xr zfs 8 , .Xr zpool 8 .Sh HISTORY diff --git a/sbin/devd/Makefile b/sbin/devd/Makefile index 4ff0187a5a22..5d5721d16884 100644 --- a/sbin/devd/Makefile +++ b/sbin/devd/Makefile @@ -46,6 +46,11 @@ HYPERV+= hyperv.conf HYPERVPACKAGE= hyperv-tools .endif +CONFGROUPS+= NVME +NVMEDIR= ${DEVDDIR} +NVME+= nvmf.conf +NVMEPACKAGE= nvme-tools + .if ${MK_USB} != "no" DEVD+= uath.conf ulpt.conf .endif diff --git a/sbin/devd/devd.conf.5 b/sbin/devd/devd.conf.5 index adeeec7fd611..baf4b9d3a183 100644 --- a/sbin/devd/devd.conf.5 +++ b/sbin/devd/devd.conf.5 @@ -38,7 +38,7 @@ .\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS .\" SOFTWARE. .\" -.Dd April 29, 2025 +.Dd July 9, 2025 .Dt DEVD.CONF 5 .Os .Sh NAME @@ -322,7 +322,7 @@ mechanism. .\" for each of the tables so that things line up in columns nicely. .\" Please do not omit the type column for notifiers that omit it. .Pp -.Bl -column "System" "Subsystem" "1234567" -compact +.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact .Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description" .It Li ACPI Ta Ta Ta Events related to the ACPI Subsystem. @@ -346,13 +346,13 @@ Suspend notification. Thermal zone events. .El .Pp -.Bl -column "System" "Subsystem" "1234567" -compact +.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact .Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description" .It Li AEON Ta Li power Ta Li press Ta The power button on an Amiga has been pressed. .El .Pp -.Bl -column "System" "Subsystem" "1234567" -compact +.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact .Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description" .It Li CAM Ta Ta Ta Events related to the @@ -366,24 +366,24 @@ Generic errors. Command timeouts. .El .Pp -.Bl -column "System" "Subsystem" "1234567" -compact +.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact .Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description" .It Li CARP Ta Ta Ta Events related to the .Xr carp 4 protocol. -.It CARP Ta Ar vhid@inet Ta Ta +.It Li CARP Ta Ar vhid@inet Ta Ta The .Dq subsystem contains the actual CARP vhid and the name of the network interface on which the event took place. -.It CARP Ta Ar vhid@inet Ta MASTER Ta +.It Li CARP Ta Ar vhid@inet Ta Li MASTER Ta Node become the master for a virtual host. -.It CARP Ta Ar vhid@inet Ta BACKUP Ta +.It Li CARP Ta Ar vhid@inet Ta Li BACKUP Ta Node become the backup for a virtual host. .El .Pp -.Bl -column "System" "Subsystem" "1234567" -compact +.Bl -column "CORETEMP" "SUBSYSTEM" "TEMPERATURE" -compact .Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description" .It Li coretemp Ta Ta Ta Events related to the @@ -395,7 +395,7 @@ Notification that the CPU core has reached critical temperature. String containing the temperature of the core that has become too hot. .El .Pp -.Bl -column "System" "Subsystem" "1234567" -compact +.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact .Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description" .It Li DEVFS .It Li DEVFS Ta Li CDEV Ta Li CREATE Ta @@ -408,7 +408,7 @@ The node is destroyed. .El .Pp -.Bl -column "System" "Subsystem" "1234567" -compact +.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact .Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description" .It Li ETHERNET Ta Ar inet Ta IFATTACH Ta Notification when the default VNET instance of the @@ -416,7 +416,7 @@ Notification when the default VNET instance of the interface is attached. .El .Pp -.Bl -column "System" "Subsystem" "1234567" -compact +.Bl -column "SYSTEM" "SUBSYSTEM" "GEOM::ROTATION_RATE" -compact .Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description" .It Li GEOM Ta Ta Ta Events related to the @@ -447,7 +447,7 @@ A provider size has changed. .El .Pp -.Bl -column "System" "Subsystem" "1234567" -compact +.Bl -column "SYSTEM" "SUBSYSTEM" "LINK_DOWN" -compact .Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description" .It Li IFNET .It Li IFNET Ta Em inet Ta Ta @@ -471,7 +471,7 @@ The network interface address added. The network interface address removed. .El .Pp -.Bl -column "System" "Subsystem" "1234567" -compact +.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact .Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description" .It Li kernel Ta Li signal Ta Li coredump Ta Notification that a process has crashed and dumped core. @@ -479,21 +479,33 @@ Notification that a process has crashed and dumped core. Notification that the system has woken from the suspended state. .El .Pp -.Bl -column "System" "Subsystem" "1234567" -compact +.Bl -column "SYSTEM" "SUBSYSTEM" "SMART_ERROR" -compact .Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description" +.It Li nvme Ta Li controller Ta Ta +Controller events provide the controller name +.Pq for example, Li nvme0 +in $name. .It Li nvme Ta Li controller Ta Li SMART_ERROR Ta A SMART Critical Warning State change has happened. $state has a hex bitmask of the bits that changed, as defined in the NVMe Standard for Critical Warning field of log page 2 .Dq SMART / Health Information Log : -.Bl -column "Bit Value" "Meaning" -compact -.Sy "Bit Value" Ta Sy "Meaning" -.It 0x1 Ta Spare capacity below threshold -.It 0x2 Ta Temperature outside acceptable range -.It 0x4 Ta Reliability of media degraded -.It 0x8 Ta Media placed into read-only mode -.It 0x10 Ta Volatime memory backup failure -.It 0x20 Ta Persistent memory read-only or degraded +.Pp +.Bl -tag -width "Bit Value" -compact +.It Sy "Bit Value" +.Sy Meaning +.It 0x1 +Spare capacity below threshold +.It 0x2 +Temperature outside acceptable range +.It 0x4 +Reliability of media degraded +.It 0x8 +Media placed into read-only mode +.It 0x10 +Volatime memory backup failure +.It 0x20 +Persistent memory read-only or degraded .El .It Li nvme Ta Li controller Ta Li RESET Ta A controller reset event has happened. @@ -503,11 +515,13 @@ $event is one of and .Dq timed_out representing the start of a controller reset, the successful completion of a -controller reset, and a timeout while waiting for the controller to reset +controller reset, or a timeout while waiting for the controller to reset, respectively. +.It Li nvme Ta Li controller Ta Li RECONNECT Ta +An NVMe over Fabrics host has disconnected and is requesting a reconnect. .El .Pp -.Bl -column "System" "Subsystem" "1234567" -compact +.Bl -column "SYSTEM" "SUBSYSTEM" "SHUTDOWN-THRESHOLD" -compact .Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description" .It Li PMU Ta Ta Ta Notification of events from various types of Power Management Units. @@ -520,25 +534,25 @@ Power has been applied to the AC power line. .It Li PMU Ta Li "AC" Ta Li unplugged Ta Power has been removed from the AC power line. .It Li PMU Ta Li Battery Ta Ta -.It Li PMU Ta Li Battery Ta absent Ta +.It Li PMU Ta Li Battery Ta Li absent Ta Battery is no longer absent. -.It Li PMU Ta Li Battery Ta charged Ta +.It Li PMU Ta Li Battery Ta Li charged Ta The battery has become charged. -.It Li PMU Ta Li Battery Ta charging Ta +.It Li PMU Ta Li Battery Ta Li charging Ta The battery has started charging. -.It Li PMU Ta Li Battery Ta disconnected Ta +.It Li PMU Ta Li Battery Ta Li disconnected Ta The battery has been disconnected. -.It Li PMU Ta Li Battery Ta high-temp Ta +.It Li PMU Ta Li Battery Ta Li high-temp Ta The battery reported a temperature over the limit. -.It Li PMU Ta Li Battery Ta low-temp Ta +.It Li PMU Ta Li Battery Ta Li low-temp Ta The battery reported a temperature under the limit. -.It Li PMU Ta Li Battery Ta plugged Ta +.It Li PMU Ta Li Battery Ta Li plugged Ta The battery has become plugged (eg connected). -.It Li PMU Ta Li Battery Ta shutdown-threshold Ta +.It Li PMU Ta Li Battery Ta Li shutdown-threshold Ta The power in the battery has fallen below the shutdown threshold. -.It Li PMU Ta Li Battery Ta warning-threshold Ta +.It Li PMU Ta Li Battery Ta Li warning-threshold Ta The power in the battery has fallen below the warn the user threshold. -.It Li PMU Ta Li Button Ta pressed Ta +.It Li PMU Ta Li Button Ta Li pressed Ta A button on a .Xr adb 4 or @@ -548,39 +562,39 @@ has been pressed. One of the keys on the .Xr adb 4 keyboard has been pressed. -.It Li PMU Ta Li keys Ta brightness Ta +.It Li PMU Ta Li keys Ta Li brightness Ta A brightness level change has been requested. Direction is in the $notify variable. -.It Li PMU Ta Li keys Ta mute Ta +.It Li PMU Ta Li keys Ta Li mute Ta The mute key -.It Li PMU Ta Li keys Ta volume Ta +.It Li PMU Ta Li keys Ta Li volume Ta A volume level change has been requested. Direction is in the $notify variable. -.It Li PMU Ta Li keys Ta eject Ta +.It Li PMU Ta Li keys Ta Li eject Ta An ejection has been requested. -.It Li PMU Ta Li lid Ta close Ta +.It Li PMU Ta Li lid Ta Li close Ta The .Xr pmc 4 device has detected the lid closing. -.It Li PMU Ta Li lid Ta open Ta +.It Li PMU Ta Li lid Ta Li open Ta The .Xr pmc 4 device has detected the lid openinging. -.It Li PMU Ta Li POWER Ta ACLINE Ta +.It Li PMU Ta Li POWER Ta Li ACLINE Ta The .Xr pmc 4 device has detected an AC line state ($notify=0x00 is offline, 0x01 is online). -.It Li PMU Ta Li USB Ta overvoltage Ta +.It Li PMU Ta Li USB Ta Li overvoltage Ta An over-voltage condition on the power lines for the USB power pins. -.It Li PMU Ta Li USB Ta plugged Ta +.It Li PMU Ta Li USB Ta Li plugged Ta A device has been plugged into a USB device. -.It Li PMU Ta Li USB Ta undervoltage Ta +.It Li PMU Ta Li USB Ta Li undervoltage Ta An under-voltage condition on the power lines for the USB power pins. -.It Li PMU Ta Li USB Ta unplugged Ta -A device has been unplugged into a USB device. +.It Li PMU Ta Li USB Ta Li unplugged Ta +A device has been unplugged from a USB device. .El .Pp -.Bl -column "System" "Subsystem" "1234567" -compact +.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact .Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description" .It Li RCTL Ta Ta Ta Events related to the @@ -590,7 +604,7 @@ framework. A rule with action specified as "devctl" was triggered. .El .Pp -.Bl -column "System" "Subsystem" "1234567" -compact +.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact .Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description" .It Li USB Ta Ta Ta Events related to the USB subsystem. @@ -604,7 +618,7 @@ USB interface is attached to a device. USB interface is detached from a device. .El .Pp -.Bl -column "System" "Subsystem" "1234567" -compact +.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact .Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description" .It Li VFS Ta Ta Ta Events from the vfs system. @@ -618,18 +632,18 @@ Notification of a filesystem is remounted (whether or not the options actually c Notification of a filesystem being unmounted. .El .Pp -.Bl -column "System" "Subsystem" "1234567" -compact +.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact .Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description" -.It Li VT Ta BELL Ta RING Ta +.It Li VT Ta Li BELL Ta Li RING Ta Notification that the console bell has rung. See .Xr vt 4 for details. .El .Pp -.Bl -column "System" "Subsystem" "1234567" -compact +.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact .Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description" -.It Li ZFS Ta ZFS Ta Ta +.It Li ZFS Ta Li ZFS Ta Ta Events about the ZFS subsystem. See .Xr zfsd 8 diff --git a/sbin/devd/nvmf.conf b/sbin/devd/nvmf.conf new file mode 100644 index 000000000000..eaf3ebe86cec --- /dev/null +++ b/sbin/devd/nvmf.conf @@ -0,0 +1,7 @@ +# Attempt to reconnect NVMeoF host devices when requested +notify 100 { + match "system" "nvme"; + match "subsystem" "controller"; + match "type" "RECONNECT"; + action "nvmecontrol reconnect $name"; +}; diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8 index 3fb8b5f02b76..b6e7d3ff2c63 100644 --- a/sbin/ifconfig/ifconfig.8 +++ b/sbin/ifconfig/ifconfig.8 @@ -28,7 +28,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd July 5, 2025 +.Dd July 14, 2025 .Dt IFCONFIG 8 .Os .Sh NAME @@ -2878,34 +2878,26 @@ interfaces previously configured with Another name for the .Fl tunnel parameter. -.It Cm accept_rev_ethip_ver -Set a flag to accept both correct EtherIP packets and ones -with reversed version field. -Enabled by default. -This is for backward compatibility with -.Fx 6.1 , -6.2, 6.3, 7.0, and 7.1. -.It Cm -accept_rev_ethip_ver -Clear a flag -.Cm accept_rev_ethip_ver . +.It Cm noclamp +This flag prevents the MTU from being clamped to 1280 bytes, the +minimum MTU for IPv6, when the outer protocol is IPv6. When the +flag is set, the MTU value configured on the interface will be +used instead of the fixed length of 1280 bytes. For more details, +please refer to the +.Ar MTU Configuration and Path MTU Discovery +section in +.Xr gif 4 . +.It Cm -noclamp +Clear the flag +.Cm noclamp . .It Cm ignore_source Set a flag to accept encapsulated packets destined to this host independently from source address. This may be useful for hosts, that receive encapsulated packets from the load balancers. .It Cm -ignore_source -Clear a flag +Clear the flag .Cm ignore_source . -.It Cm send_rev_ethip_ver -Set a flag to send EtherIP packets with reversed version -field intentionally. -Disabled by default. -This is for backward compatibility with -.Fx 6.1 , -6.2, 6.3, 7.0, and 7.1. -.It Cm -send_rev_ethip_ver -Clear a flag -.Cm send_rev_ethip_ver . .El .Ss GRE Tunnel Parameters The following parameters apply to GRE tunnel interfaces, diff --git a/sbin/ifconfig/ifgif.c b/sbin/ifconfig/ifgif.c index 991cf110678f..9b8be210a59e 100644 --- a/sbin/ifconfig/ifgif.c +++ b/sbin/ifconfig/ifgif.c @@ -49,6 +49,7 @@ #include "ifconfig.h" static const char *GIFBITS[] = { + [0] = "NOCLAMP", [1] = "IGNORE_SOURCE", }; @@ -90,6 +91,8 @@ setgifopts(if_ctx *ctx, const char *val __unused, int d) } static struct cmd gif_cmds[] = { + DEF_CMD("noclamp", GIF_NOCLAMP, setgifopts), + DEF_CMD("-noclamp", -GIF_NOCLAMP, setgifopts), DEF_CMD("ignore_source", GIF_IGNORE_SOURCE, setgifopts), DEF_CMD("-ignore_source", -GIF_IGNORE_SOURCE, setgifopts), }; diff --git a/sbin/kldstat/kldstat.c b/sbin/kldstat/kldstat.c index 79c647576440..3a90f1c97eb4 100644 --- a/sbin/kldstat/kldstat.c +++ b/sbin/kldstat/kldstat.c @@ -35,7 +35,7 @@ #include <libutil.h> #include <stdio.h> #include <stdlib.h> -#include <strings.h> +#include <string.h> #include <unistd.h> #define PTR_WIDTH ((int)(sizeof(void *) * 2 + 2)) @@ -51,7 +51,7 @@ printmod(int modid) { struct module_stat stat; - bzero(&stat, sizeof(stat)); + memset(&stat, 0, sizeof(stat)); stat.version = sizeof(struct module_stat); if (modstat(modid, &stat) < 0) { warn("can't stat module id %d", modid); diff --git a/sbin/mount/mount.8 b/sbin/mount/mount.8 index b584d71ea567..7bfc21ea41d5 100644 --- a/sbin/mount/mount.8 +++ b/sbin/mount/mount.8 @@ -28,7 +28,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd April 30, 2025 +.Dd July 16, 2025 .Dt MOUNT 8 .Os .Sh NAME @@ -80,7 +80,7 @@ Generate output via .Xr libxo 3 in a selection of different human and machine readable formats. See -.Xr xo_parse_args 3 +.Xr xo_options 7 for details on command line arguments. .It Fl a All the file systems described in @@ -573,7 +573,7 @@ support for a particular file system might be provided either on a static .Xr acl 3 , .Xr getmntinfo 3 , .Xr libxo 3 , -.Xr xo_parse_args 3 , +.Xr xo_options 7 , .Xr cd9660 4 , .Xr devfs 4 , .Xr ext2fs 4 , diff --git a/sbin/nvmecontrol/connect.c b/sbin/nvmecontrol/connect.c index c1d5d2cbaf5a..3d6d12bf2c48 100644 --- a/sbin/nvmecontrol/connect.c +++ b/sbin/nvmecontrol/connect.c @@ -31,6 +31,8 @@ static struct options { const char *subnqn; const char *hostnqn; uint32_t kato; + uint32_t reconnect_delay; + uint32_t controller_loss_timeout; uint16_t num_io_queues; uint16_t queue_size; bool data_digests; @@ -43,6 +45,8 @@ static struct options { .subnqn = NULL, .hostnqn = NULL, .kato = NVMF_KATO_DEFAULT / 1000, + .reconnect_delay = NVMF_DEFAULT_RECONNECT_DELAY, + .controller_loss_timeout = NVMF_DEFAULT_CONTROLLER_LOSS, .num_io_queues = 1, .queue_size = 0, .data_digests = false, @@ -107,7 +111,7 @@ connect_nvm_controller(enum nvmf_trtype trtype, int adrfam, const char *address, } error = nvmf_handoff_host(dle, hostnqn, admin, opt.num_io_queues, io, - &cdata); + &cdata, opt.reconnect_delay, opt.controller_loss_timeout); if (error != 0) { warnc(error, "Failed to handoff queues to kernel"); free(io); @@ -259,6 +263,11 @@ static const struct opts connect_opts[] = { "Number of entries in each I/O queue"), OPT("keep-alive-tmo", 'k', arg_uint32, opt, kato, "Keep Alive timeout (in seconds)"), + OPT("reconnect-delay", 'r', arg_uint32, opt, reconnect_delay, + "Delay between reconnect attempts after connection loss " + "(in seconds)"), + OPT("ctrl-loss-tmo", 'l', arg_uint32, opt, controller_loss_timeout, + "Controller loss timeout after connection loss (in seconds)"), OPT("hostnqn", 'q', arg_string, opt, hostnqn, "Host NQN"), OPT("flow_control", 'F', arg_none, opt, flow_control, diff --git a/sbin/nvmecontrol/nvmecontrol.8 b/sbin/nvmecontrol/nvmecontrol.8 index d886b60a2545..624a0c93719b 100644 --- a/sbin/nvmecontrol/nvmecontrol.8 +++ b/sbin/nvmecontrol/nvmecontrol.8 @@ -33,7 +33,7 @@ .\" .\" Author: Jim Harris <jimharris@FreeBSD.org> .\" -.Dd April 29, 2025 +.Dd July 9, 2025 .Dt NVMECONTROL 8 .Os .Sh NAME @@ -216,6 +216,8 @@ .Op Fl c Ar cntl-id .Op Fl i Ar queues .Op Fl k Ar seconds +.Op Fl l Ar seconds +.Op Fl r Ar seconds .Op Fl t Ar transport .Op Fl q Ar HostNQN .Op Fl Q Ar entries @@ -226,6 +228,8 @@ .Op Fl FGg .Op Fl i Ar queues .Op Fl k Ar seconds +.Op Fl l Ar seconds +.Op Fl r Ar seconds .Op Fl t Ar transport .Op Fl q Ar HostNQN .Op Fl Q Ar entries @@ -241,6 +245,8 @@ .Op Fl FGg .Op Fl i Ar queues .Op Fl k Ar seconds +.Op Fl l Ar seconds +.Op Fl r Ar seconds .Op Fl t Ar transport .Op Fl q Ar HostNQN .Op Fl Q Ar entries @@ -786,6 +792,29 @@ The default is 1. .It Fl k Ar seconds Keep Alive timer duration in seconds. The default is 120. +.It Fl l Ar seconds +Controller Loss timer duration in seconds. +The default is 600. +.Pp +This timer starts when an association is lost with a remote I/O controller +and is cancelled when a new association is established. +If the timer expires, the controller device is deleted. +A setting of zero disables this timer. +.It Fl r Ar seconds +Reconnect timer duration in seconds. +The default is 10. +.Pp +When an association is lost with a remote I/O controller, +the controller device will request reconnection via periodic +.Xr devctl 4 +notifications until either a new association is established or the controller +device is deleted. +This timer sets the interval between each +.Xr devctl 4 +notification. +Note that the first notification is triggered immediately after an association +is lost. +A setting of zero disables this timer. .It Fl t Ar transport Transport to use. The default is diff --git a/sbin/nvmecontrol/reconnect.c b/sbin/nvmecontrol/reconnect.c index adf1edac662b..06af40624177 100644 --- a/sbin/nvmecontrol/reconnect.c +++ b/sbin/nvmecontrol/reconnect.c @@ -27,6 +27,8 @@ static struct options { const char *transport; const char *hostnqn; uint32_t kato; + uint32_t reconnect_delay; + uint32_t controller_loss_timeout; uint16_t num_io_queues; uint16_t queue_size; bool data_digests; @@ -37,6 +39,8 @@ static struct options { .transport = "tcp", .hostnqn = NULL, .kato = NVMF_KATO_DEFAULT / 1000, + .reconnect_delay = NVMF_DEFAULT_RECONNECT_DELAY, + .controller_loss_timeout = NVMF_DEFAULT_CONTROLLER_LOSS, .num_io_queues = 1, .queue_size = 0, .data_digests = false, @@ -59,6 +63,7 @@ static int reconnect_nvm_controller(int fd, const struct nvmf_association_params *aparams, enum nvmf_trtype trtype, int adrfam, const char *address, const char *port, uint16_t cntlid, const char *subnqn, const char *hostnqn, uint32_t kato, + uint32_t reconnect_delay, uint32_t controller_loss_timeout, u_int num_io_queues, u_int queue_size, const struct nvme_discovery_log_entry *dle) { @@ -88,7 +93,7 @@ reconnect_nvm_controller(int fd, const struct nvmf_association_params *aparams, } error = nvmf_reconnect_host(fd, dle, hostnqn, admin, num_io_queues, io, - &cdata); + &cdata, reconnect_delay, controller_loss_timeout); if (error != 0) { warnc(error, "Failed to handoff queues to kernel"); free(io); @@ -137,7 +142,8 @@ reconnect_by_address(int fd, const nvlist_t *rparams, const char *addr) error = reconnect_nvm_controller(fd, &aparams, trtype, AF_UNSPEC, address, port, le16toh(dle->cntlid), subnqn, hostnqn, - opt.kato * 1000, opt.num_io_queues, opt.queue_size, NULL); + opt.kato * 1000, opt.reconnect_delay, opt.controller_loss_timeout, + opt.num_io_queues, opt.queue_size, NULL); free(subnqn); free(tofree); return (error); @@ -196,6 +202,8 @@ reconnect_by_params(int fd, const nvlist_t *rparams) address, port, le16toh(dle->cntlid), dle->subnqn, nvlist_get_string(rparams, "hostnqn"), dnvlist_get_number(rparams, "kato", 0), + dnvlist_get_number(rparams, "reconnect_delay", 0), + dnvlist_get_number(rparams, "controller_loss_timeout", 0), nvlist_get_number(rparams, "num_io_queues"), nvlist_get_number(rparams, "io_qsize"), dle); free(subnqn); @@ -291,6 +299,11 @@ static const struct opts reconnect_opts[] = { "Number of entries in each I/O queue"), OPT("keep-alive-tmo", 'k', arg_uint32, opt, kato, "Keep Alive timeout (in seconds)"), + OPT("reconnect-delay", 'r', arg_uint32, opt, reconnect_delay, + "Delay between reconnect attempts after connection loss " + "(in seconds)"), + OPT("ctrl-loss-tmo", 'l', arg_uint32, opt, controller_loss_timeout, + "Controller loss timeout after connection loss (in seconds)"), OPT("hostnqn", 'q', arg_string, opt, hostnqn, "Host NQN"), OPT("flow_control", 'F', arg_none, opt, flow_control, diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y index af1fb95398f8..358fa909fc50 100644 --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -95,7 +95,7 @@ static struct file { int eof_reached; int lineno; int errors; -} *file; +} *file, *topfile; struct file *pushfile(const char *, int); int popfile(void); int check_file_secrecy(int, const char *); @@ -367,6 +367,7 @@ static struct node_fairq_opts fairq_opts; static struct node_state_opt *keep_state_defaults = NULL; static struct pfctl_watermarks syncookie_opts; +int validate_range(uint8_t, uint16_t, uint16_t); int disallow_table(struct node_host *, const char *); int disallow_urpf_failed(struct node_host *, const char *); int disallow_alias(struct node_host *, const char *); @@ -3231,8 +3232,7 @@ logopts : logopt { $$ = $1; } logopt : ALL { $$.log = PF_LOG_ALL; $$.logif = 0; } | MATCHES { $$.log = PF_LOG_MATCHES; $$.logif = 0; } - | USER { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; } - | GROUP { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; } + | USER { $$.log = PF_LOG_USER; $$.logif = 0; } | TO string { const char *errstr; u_int i; @@ -3825,9 +3825,14 @@ port_item : portrange { err(1, "port_item: calloc"); $$->port[0] = $1.a; $$->port[1] = $1.b; - if ($1.t) + if ($1.t) { $$->op = PF_OP_RRG; - else + if (validate_range($$->op, $$->port[0], + $$->port[1])) { + yyerror("invalid port range"); + YYERROR; + } + } else $$->op = PF_OP_EQ; $$->next = NULL; $$->tail = $$; @@ -3844,6 +3849,10 @@ port_item : portrange { $$->port[0] = $2.a; $$->port[1] = $2.b; $$->op = $1; + if (validate_range($$->op, $$->port[0], $$->port[1])) { + yyerror("invalid port range"); + YYERROR; + } $$->next = NULL; $$->tail = $$; } @@ -3859,6 +3868,10 @@ port_item : portrange { $$->port[0] = $1.a; $$->port[1] = $3.a; $$->op = $2; + if (validate_range($$->op, $$->port[0], $$->port[1])) { + yyerror("invalid port range"); + YYERROR; + } $$->next = NULL; $$->tail = $$; } @@ -3905,7 +3918,7 @@ uid_item : uid { $$->tail = $$; } | unaryop uid { - if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { + if ($2 == -1 && $1 != PF_OP_EQ && $1 != PF_OP_NE) { yyerror("user unknown requires operator = or " "!="); YYERROR; @@ -3920,7 +3933,7 @@ uid_item : uid { $$->tail = $$; } | uid PORTBINARY uid { - if ($1 == UID_MAX || $3 == UID_MAX) { + if ($1 == -1 || $3 == -1) { yyerror("user unknown requires operator = or " "!="); YYERROR; @@ -3938,7 +3951,7 @@ uid_item : uid { uid : STRING { if (!strcmp($1, "unknown")) - $$ = UID_MAX; + $$ = -1; else { uid_t uid; @@ -3983,7 +3996,7 @@ gid_item : gid { $$->tail = $$; } | unaryop gid { - if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { + if ($2 == -1 && $1 != PF_OP_EQ && $1 != PF_OP_NE) { yyerror("group unknown requires operator = or " "!="); YYERROR; @@ -3998,7 +4011,7 @@ gid_item : gid { $$->tail = $$; } | gid PORTBINARY gid { - if ($1 == GID_MAX || $3 == GID_MAX) { + if ($1 == -1 || $3 == -1) { yyerror("group unknown requires operator = or " "!="); YYERROR; @@ -4016,7 +4029,7 @@ gid_item : gid { gid : STRING { if (!strcmp($1, "unknown")) - $$ = GID_MAX; + $$ = -1; else { gid_t gid; @@ -5197,6 +5210,19 @@ yyerror(const char *fmt, ...) } int +validate_range(uint8_t op, uint16_t p1, uint16_t p2) +{ + uint16_t a = ntohs(p1); + uint16_t b = ntohs(p2); + + if ((op == PF_OP_RRG && a > b) || /* 34:12, i.e. none */ + (op == PF_OP_IRG && a >= b) || /* 34><12, i.e. none */ + (op == PF_OP_XRG && a > b)) /* 34<>22, i.e. all */ + return 1; + return 0; +} + +int disallow_table(struct node_host *h, const char *fmt) { for (; h != NULL; h = h->next) @@ -5324,6 +5350,10 @@ filter_consistent(struct pfctl_rule *r, int anchor_call) "synproxy state or modulate state"); problems++; } + if ((r->keep_state == PF_STATE_SYNPROXY) && (r->direction != PF_IN)) + fprintf(stderr, "%s:%d: warning: " + "synproxy used for inbound rules only, " + "ignored for outbound\n", file->name, yylval.lineno); if (r->rule_flag & PFRULE_AFTO && r->rt) { if (r->rt != PF_ROUTETO && r->rt != PF_REPLYTO) { yyerror("dup-to " @@ -5458,7 +5488,7 @@ process_tabledef(char *name, struct table_opts *opts, int popts) name); else yyerror("cannot define table %s: %s", name, - pfr_strerror(errno)); + pf_strerror(errno)); goto _error; } @@ -6014,8 +6044,14 @@ apply_rdr_ports(struct pfctl_rule *r, struct pfctl_pool *rpool, struct redirspec if (!rs->rport.b && rs->rport.t) { rpool->proxy_port[1] = ntohs(rs->rport.a) + (ntohs(r->dst.port[1]) - ntohs(r->dst.port[0])); - } else + } else { + if (validate_range(rs->rport.t, rs->rport.a, + rs->rport.b)) { + yyerror("invalid rdr-to port range"); + return (1); + } r->rdr.proxy_port[1] = ntohs(rs->rport.b); + } if (rs->pool_opts.staticport) { yyerror("the 'static-port' option is only valid with nat rules"); @@ -6743,7 +6779,7 @@ lgetc(int quotec) if (quotec) { if ((c = igetc()) == EOF) { yyerror("reached end of file while parsing quoted string"); - if (popfile() == EOF) + if (file == topfile || popfile() == EOF) return (EOF); return (quotec); } @@ -6771,7 +6807,7 @@ lgetc(int quotec) return ('\n'); } while (c == EOF) { - if (popfile() == EOF) + if (file == topfile || popfile() == EOF) return (EOF); c = igetc(); } @@ -7069,17 +7105,17 @@ popfile(void) { struct file *prev; - if ((prev = TAILQ_PREV(file, files, entry)) != NULL) { + if ((prev = TAILQ_PREV(file, files, entry)) != NULL) prev->errors += file->errors; - TAILQ_REMOVE(&files, file, entry); - fclose(file->stream); - free(file->name); - free(file->ungetbuf); - free(file); - file = prev; - return (0); - } - return (EOF); + + TAILQ_REMOVE(&files, file, entry); + fclose(file->stream); + free(file->name); + free(file->ungetbuf); + free(file); + file = prev; + + return (file ? 0 : EOF); } int @@ -7102,6 +7138,7 @@ parse_config(char *filename, struct pfctl *xpf) warn("cannot open the main config file!"); return (-1); } + topfile = file; yyparse(); errors = file->errors; @@ -7201,19 +7238,11 @@ mv_rules(struct pfctl_ruleset *src, struct pfctl_ruleset *dst) struct pfctl_rule *r; for (i = 0; i < PF_RULESET_MAX; ++i) { - while ((r = TAILQ_FIRST(src->rules[i].active.ptr)) - != NULL) { - TAILQ_REMOVE(src->rules[i].active.ptr, r, entries); - TAILQ_INSERT_TAIL(dst->rules[i].active.ptr, r, entries); + TAILQ_FOREACH(r, src->rules[i].active.ptr, entries) dst->anchor->match++; - } + TAILQ_CONCAT(dst->rules[i].active.ptr, src->rules[i].active.ptr, entries); src->anchor->match = 0; - while ((r = TAILQ_FIRST(src->rules[i].inactive.ptr)) - != NULL) { - TAILQ_REMOVE(src->rules[i].inactive.ptr, r, entries); - TAILQ_INSERT_TAIL(dst->rules[i].inactive.ptr, - r, entries); - } + TAILQ_CONCAT(dst->rules[i].inactive.ptr, src->rules[i].inactive.ptr, entries); } } diff --git a/sbin/pfctl/pfctl.8 b/sbin/pfctl/pfctl.8 index 28efff896956..f582c6301124 100644 --- a/sbin/pfctl/pfctl.8 +++ b/sbin/pfctl/pfctl.8 @@ -24,7 +24,7 @@ .\" (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 2, 2025 +.Dd July 7, 2025 .Dt PFCTL 8 .Os .Sh NAME @@ -186,6 +186,13 @@ as the anchor name: .Bd -literal -offset indent # pfctl -a '*' -sr .Ed +.Pp +To flush all rulesets and tables recursively, specify only +.Sq * +as the anchor name: +.Bd -literal -offset indent +# pfctl -a '*' -Fa +.Ed .It Fl D Ar macro Ns = Ns Ar value Define .Ar macro @@ -231,6 +238,19 @@ for details. .It Fl F Cm all Flush all of the above. .El +.Pp +If +.Fl a +is specified as well and +.Ar anchor +is terminated with a +.Sq * +character, +.Cm rules , +.Cm Tables +and +.Cm all +flush the given anchor recursively. .It Fl f Ar file Load the rules contained in .Ar file . @@ -467,7 +487,10 @@ Show the contents of the source tracking table. Show filter information (statistics and counters). When used together with .Fl v , -source tracking statistics are also shown. +source tracking statistics, the firewall's 32-bit hostid number and the +main ruleset's MD5 checksum for use with +.Xr pfsync 4 +are also shown. .It Fl s Cm Running Show the running status and provide a non-zero exit status when disabled. .It Fl s Cm labels diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c index defba3b56c44..2015e0a09549 100644 --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -59,6 +59,8 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <stdarg.h> +#include <libgen.h> #include "pfctl_parser.h" #include "pfctl.h" @@ -72,7 +74,7 @@ void pfctl_check_skip_ifaces(char *); void pfctl_adjust_skip_ifaces(struct pfctl *); void pfctl_clear_interface_flags(int, int); void pfctl_flush_eth_rules(int, int, char *); -void pfctl_flush_rules(int, int, char *); +int pfctl_flush_rules(int, int, char *); void pfctl_flush_nat(int, int, char *); int pfctl_clear_altq(int, int); void pfctl_clear_src_nodes(int, int); @@ -124,6 +126,17 @@ int pfctl_load_ruleset(struct pfctl *, char *, int pfctl_load_rule(struct pfctl *, char *, struct pfctl_rule *, int); const char *pfctl_lookup_option(char *, const char * const *); void pfctl_reset(int, int); +int pfctl_walk_show(int, struct pfioc_ruleset *, void *); +int pfctl_walk_get(int, struct pfioc_ruleset *, void *); +int pfctl_walk_anchors(int, int, const char *, + int(*)(int, struct pfioc_ruleset *, void *), void *); +struct pfr_anchors * + pfctl_get_anchors(int, const char *, int); +int pfctl_recurse(int, int, const char *, + int(*)(int, int, struct pfr_anchoritem *)); +int pfctl_call_clearrules(int, int, struct pfr_anchoritem *); +int pfctl_call_cleartables(int, int, struct pfr_anchoritem *); +int pfctl_call_clearanchors(int, int, struct pfr_anchoritem *); static struct pfctl_anchor_global pf_anchors; struct pfctl_anchor pf_main_anchor; @@ -151,6 +164,7 @@ int dev = -1; struct pfctl_handle *pfh = NULL; static int first_title = 1; static int labels = 0; +static int exit_val = 0; #define INDENT(d, o) do { \ if (o) { \ @@ -269,6 +283,40 @@ usage(void) exit(1); } +void +pfctl_err(int opts, int eval, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + + if ((opts & PF_OPT_IGNFAIL) == 0) + verr(eval, fmt, ap); + else + vwarn(fmt, ap); + + va_end(ap); + + exit_val = eval; +} + +void +pfctl_errx(int opts, int eval, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + + if ((opts & PF_OPT_IGNFAIL) == 0) + verrx(eval, fmt, ap); + else + vwarnx(fmt, ap); + + va_end(ap); + + exit_val = eval; +} + /* * Cache protocol number to name translations. * @@ -361,7 +409,7 @@ pfctl_clear_stats(struct pfctl_handle *h, int opts) { int ret; if ((ret = pfctl_clear_status(h)) != 0) - errc(1, ret, "DIOCCLRSTATUS"); + pfctl_err(opts, 1, "DIOCCLRSTATUS"); if ((opts & PF_OPT_QUIET) == 0) fprintf(stderr, "pf: statistics cleared\n"); } @@ -469,16 +517,19 @@ pfctl_flush_eth_rules(int dev, int opts, char *anchorname) fprintf(stderr, "Ethernet rules cleared\n"); } -void +int pfctl_flush_rules(int dev, int opts, char *anchorname) { int ret; ret = pfctl_clear_rules(dev, anchorname); - if (ret != 0) - err(1, "pfctl_clear_rules"); - if ((opts & PF_OPT_QUIET) == 0) + if (ret != 0) { + pfctl_err(opts, 1, "%s", __func__); + return (1); + } else if ((opts & PF_OPT_QUIET) == 0) fprintf(stderr, "rules cleared\n"); + + return (0); } void @@ -515,7 +566,7 @@ void pfctl_clear_src_nodes(int dev, int opts) { if (ioctl(dev, DIOCCLRSRCNODES)) - err(1, "DIOCCLRSRCNODES"); + pfctl_err(opts, 1, "DIOCCLRSRCNODES"); if ((opts & PF_OPT_QUIET) == 0) fprintf(stderr, "source tracking entries cleared\n"); } @@ -530,13 +581,13 @@ pfctl_clear_iface_states(int dev, const char *iface, int opts) memset(&kill, 0, sizeof(kill)); if (iface != NULL && strlcpy(kill.ifname, iface, sizeof(kill.ifname)) >= sizeof(kill.ifname)) - errx(1, "invalid interface: %s", iface); + pfctl_errx(opts, 1, "invalid interface: %s", iface); if (opts & PF_OPT_KILLMATCH) kill.kill_match = true; if ((ret = pfctl_clear_states_h(pfh, &kill, &killed)) != 0) - errc(1, ret, "DIOCCLRSTATES"); + pfctl_err(opts, 1, "DIOCCLRSTATUS"); if ((opts & PF_OPT_QUIET) == 0) fprintf(stderr, "%d states cleared\n", killed); } @@ -687,7 +738,7 @@ pfctl_net_kill_states(int dev, const char *iface, int opts) memset(&last_dst, 0xff, sizeof(last_dst)); if (iface != NULL && strlcpy(kill.ifname, iface, sizeof(kill.ifname)) >= sizeof(kill.ifname)) - errx(1, "invalid interface: %s", iface); + pfctl_errx(opts, 1, "invalid interface: %s", iface); if (state_killers == 2 && (strcmp(state_kill[0], "nat") == 0)) { kill.nat = true; @@ -740,13 +791,13 @@ pfctl_net_kill_states(int dev, const char *iface, int opts) resp[1]->ai_addr); if ((ret = pfctl_kill_states_h(pfh, &kill, &newkilled)) != 0) - errc(1, ret, "DIOCKILLSTATES"); + pfctl_errx(opts, 1, "DIOCKILLSTATES"); killed += newkilled; } freeaddrinfo(res[1]); } else { if ((ret = pfctl_kill_states_h(pfh, &kill, &newkilled)) != 0) - errc(1, ret, "DIOCKILLSTATES"); + pfctl_errx(opts, 1, "DIOCKILLSTATES"); killed += newkilled; } } @@ -778,7 +829,7 @@ pfctl_gateway_kill_states(int dev, const char *iface, int opts) memset(&last_src, 0xff, sizeof(last_src)); if (iface != NULL && strlcpy(kill.ifname, iface, sizeof(kill.ifname)) >= sizeof(kill.ifname)) - errx(1, "invalid interface: %s", iface); + pfctl_errx(opts, 1, "invalid interface: %s", iface); if (opts & PF_OPT_KILLMATCH) kill.kill_match = true; @@ -799,7 +850,7 @@ pfctl_gateway_kill_states(int dev, const char *iface, int opts) copy_satopfaddr(&kill.rt_addr.addr.v.a.addr, resp->ai_addr); if (pfctl_kill_states_h(pfh, &kill, &newkilled)) - err(1, "DIOCKILLSTATES"); + pfctl_errx(opts, 1, "DIOCKILLSTATES"); killed += newkilled; } @@ -823,7 +874,7 @@ pfctl_label_kill_states(int dev, const char *iface, int opts) memset(&kill, 0, sizeof(kill)); if (iface != NULL && strlcpy(kill.ifname, iface, sizeof(kill.ifname)) >= sizeof(kill.ifname)) - errx(1, "invalid interface: %s", iface); + pfctl_errx(opts, 1, "invalid interface: %s", iface); if (opts & PF_OPT_KILLMATCH) kill.kill_match = true; @@ -833,7 +884,7 @@ pfctl_label_kill_states(int dev, const char *iface, int opts) errx(1, "label too long: %s", state_kill[1]); if ((ret = pfctl_kill_states_h(pfh, &kill, &killed)) != 0) - errc(1, ret, "DIOCKILLSTATES"); + pfctl_errx(opts, 1, "DIOCKILLSTATES"); if ((opts & PF_OPT_QUIET) == 0) fprintf(stderr, "killed %d states\n", killed); @@ -871,7 +922,7 @@ pfctl_id_kill_states(int dev, const char *iface, int opts) } if ((ret = pfctl_kill_states_h(pfh, &kill, &killed)) != 0) - errc(1, ret, "DIOCKILLSTATES"); + pfctl_errx(opts, 1, "DIOCKILLSTATES"); if ((opts & PF_OPT_QUIET) == 0) fprintf(stderr, "killed %d states\n", killed); @@ -895,7 +946,7 @@ pfctl_key_kill_states(int dev, const char *iface, int opts) if (iface != NULL && strlcpy(kill.ifname, iface, sizeof(kill.ifname)) >= sizeof(kill.ifname)) - errx(1, "invalid interface: %s", iface); + pfctl_errx(opts, 1, "invalid interface: %s", iface); s = strdup(state_kill[1]); if (!s) @@ -931,7 +982,7 @@ pfctl_key_kill_states(int dev, const char *iface, int opts) errx(1, "invalid host: %s", tokens[didx]); if ((ret = pfctl_kill_states_h(pfh, &kill, &killed)) != 0) - errc(1, ret, "DIOCKILLSTATES"); + pfctl_errx(opts, 1, "DIOCKILLSTATES"); if ((opts & PF_OPT_QUIET) == 0) fprintf(stderr, "killed %d states\n", killed); @@ -1289,17 +1340,12 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, u_int32_t mnr, nr; memset(&prs, 0, sizeof(prs)); - if ((ret = pfctl_get_rulesets(pfh, npath, &mnr)) != 0) { - if (ret == EINVAL) - fprintf(stderr, "Anchor '%s' " - "not found.\n", anchorname); - else - errc(1, ret, "DIOCGETRULESETS"); - } + if ((ret = pfctl_get_rulesets(pfh, npath, &mnr)) != 0) + errx(1, "%s", pf_strerror(ret)); for (nr = 0; nr < mnr; ++nr) { if ((ret = pfctl_get_ruleset(pfh, npath, nr, &prs)) != 0) - errc(1, ret, "DIOCGETRULESET"); + errx(1, "%s", pf_strerror(ret)); INDENT(depth, !(opts & PF_OPT_VERBOSE)); printf("anchor \"%s\" all {\n", prs.name); pfctl_show_rules(dev, npath, opts, @@ -1314,14 +1360,14 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, if (opts & PF_OPT_SHOWALL) { ret = pfctl_get_rules_info_h(pfh, &ri, PF_PASS, path); if (ret != 0) { - warnc(ret, "DIOCGETRULES"); + warnx("%s", pf_strerror(ret)); goto error; } header++; } ret = pfctl_get_rules_info_h(pfh, &ri, PF_SCRUB, path); if (ret != 0) { - warnc(ret, "DIOCGETRULES"); + warnx("%s", pf_strerror(ret)); goto error; } if (opts & PF_OPT_SHOWALL) { @@ -1514,12 +1560,12 @@ pfctl_show_nat(int dev, const char *path, int opts, char *anchorname, int depth, fprintf(stderr, "NAT anchor '%s' " "not found.\n", anchorname); else - errc(1, ret, "DIOCGETRULESETS"); + errx(1, "%s", pf_strerror(ret)); } for (nr = 0; nr < mnr; ++nr) { if ((ret = pfctl_get_ruleset(pfh, npath, nr, &prs)) != 0) - errc(1, ret, "DIOCGETRULESET"); + errx(1, "%s", pf_strerror(ret)); INDENT(depth, !(opts & PF_OPT_VERBOSE)); printf("nat-anchor \"%s\" all {\n", prs.name); pfctl_show_nat(dev, npath, opts, @@ -2038,8 +2084,8 @@ pfctl_load_ruleset(struct pfctl *pf, char *path, struct pfctl_ruleset *rs, if ((pf->opts & PF_OPT_NOACTION) == 0 && (error = pfctl_ruleset_trans(pf, path, rs->anchor, false))) { - printf("pfctl_load_rulesets: " - "pfctl_ruleset_trans %d\n", error); + printf("%s: " + "pfctl_ruleset_trans %d\n", __func__, error); goto error; } } else if (pf->opts & PF_OPT_VERBOSE) @@ -2805,7 +2851,7 @@ pfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how) if ((pf->opts & PF_OPT_NOACTION) == 0) { if (how == 0) { if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi)) - err(1, "DIOCCLRIFFLAG"); + pfctl_err(pf->opts, 1, "DIOCCLRIFFLAG"); } else { if (ioctl(pf->dev, DIOCSETIFFLAG, &pi)) err(1, "DIOCSETIFFLAG"); @@ -2864,43 +2910,178 @@ pfctl_test_altqsupport(int dev, int opts) } int -pfctl_show_anchors(int dev, int opts, char *anchorname) +pfctl_walk_show(int opts, struct pfioc_ruleset *pr, void *warg) +{ + if (pr->path[0]) { + if (pr->path[0] != '_' || (opts & PF_OPT_VERBOSE)) + printf(" %s/%s\n", pr->path, pr->name); + } else if (pr->name[0] != '_' || (opts & PF_OPT_VERBOSE)) + printf(" %s\n", pr->name); + + return (0); +} + +int +pfctl_walk_get(int opts, struct pfioc_ruleset *pr, void *warg) +{ + struct pfr_anchoritem *pfra; + struct pfr_anchors *anchors; + int e; + + anchors = (struct pfr_anchors *)warg; + + pfra = malloc(sizeof(*pfra)); + if (pfra == NULL) + err(1, "%s", __func__); + + if (pr->path[0]) + e = asprintf(&pfra->pfra_anchorname, "%s/%s", pr->path, + pr->name); + else + e = asprintf(&pfra->pfra_anchorname, "%s", pr->name); + + if (e == -1) + err(1, "%s", __func__); + + SLIST_INSERT_HEAD(anchors, pfra, pfra_sle); + + return (0); +} + +int +pfctl_walk_anchors(int dev, int opts, const char *anchor, + int(walkf)(int, struct pfioc_ruleset *, void *), void *warg) { struct pfioc_ruleset pr; u_int32_t mnr, nr; int ret; memset(&pr, 0, sizeof(pr)); - if ((ret = pfctl_get_rulesets(pfh, anchorname, &mnr)) != 0) { - if (ret == EINVAL) - fprintf(stderr, "Anchor '%s' not found.\n", - anchorname); - else - errc(1, ret, "DIOCGETRULESETS"); - return (-1); - } + if ((ret = pfctl_get_rulesets(pfh, anchor, &mnr)) != 0) + errx(1, "%s", pf_strerror(ret)); for (nr = 0; nr < mnr; ++nr) { char sub[MAXPATHLEN]; - if ((ret = pfctl_get_ruleset(pfh, anchorname, nr, &pr)) != 0) + if ((ret = pfctl_get_ruleset(pfh, anchor, nr, &pr)) != 0) errc(1, ret, "DIOCGETRULESET"); if (!strcmp(pr.name, PF_RESERVED_ANCHOR)) continue; sub[0] = '\0'; - if (pr.path[0]) { - strlcat(sub, pr.path, sizeof(sub)); - strlcat(sub, "/", sizeof(sub)); - } - strlcat(sub, pr.name, sizeof(sub)); - if (sub[0] != '_' || (opts & PF_OPT_VERBOSE)) - printf(" %s\n", sub); - if ((opts & PF_OPT_VERBOSE) && pfctl_show_anchors(dev, opts, sub)) + if (walkf(opts, &pr, warg)) + return (-1); + + if (pr.path[0]) + snprintf(sub, sizeof(sub), "%s/%s", pr.path, pr.name); + else + snprintf(sub, sizeof(sub), "%s", pr.name); + if (pfctl_walk_anchors(dev, opts, sub, walkf, warg)) return (-1); } return (0); } int +pfctl_show_anchors(int dev, int opts, char *anchor) +{ + return ( + pfctl_walk_anchors(dev, opts, anchor, pfctl_walk_show, NULL)); +} + +struct pfr_anchors * +pfctl_get_anchors(int dev, const char *anchor, int opts) +{ + struct pfioc_ruleset pr; + static struct pfr_anchors anchors; + char anchorbuf[PATH_MAX]; + char *n; + + SLIST_INIT(&anchors); + + memset(&pr, 0, sizeof(pr)); + if (*anchor != '\0') { + strlcpy(anchorbuf, anchor, sizeof(anchorbuf)); + n = dirname(anchorbuf); + if (n[0] != '.' && n[1] != '\0') + strlcpy(pr.path, n, sizeof(pr.path)); + strlcpy(anchorbuf, anchor, sizeof(anchorbuf)); + n = basename(anchorbuf); + if (n != NULL) + strlcpy(pr.name, n, sizeof(pr.name)); + } + + /* insert a root anchor first. */ + pfctl_walk_get(opts, &pr, &anchors); + + if (pfctl_walk_anchors(dev, opts, anchor, pfctl_walk_get, &anchors)) + errx(1, "%s failed to retrieve list of anchors, can't continue", + __func__); + + return (&anchors); +} + +int +pfctl_call_cleartables(int dev, int opts, struct pfr_anchoritem *pfra) +{ + /* + * PF_OPT_QUIET makes pfctl_clear_tables() to stop printing number of + * tables cleared for given anchor. + */ + opts |= PF_OPT_QUIET; + return ((pfctl_do_clear_tables(pfra->pfra_anchorname, opts) == -1) ? + 1 : 0); +} + +int +pfctl_call_clearrules(int dev, int opts, struct pfr_anchoritem *pfra) +{ + /* + * PF_OPT_QUIET makes pfctl_clear_rules() to stop printing a 'rules + * cleared' message for every anchor it deletes. + */ + opts |= PF_OPT_QUIET; + return (pfctl_flush_rules(dev, opts, pfra->pfra_anchorname)); +} + +int +pfctl_call_clearanchors(int dev, int opts, struct pfr_anchoritem *pfra) +{ + int rv = 0; + + rv |= pfctl_call_cleartables(dev, opts, pfra); + rv |= pfctl_call_clearrules(dev, opts, pfra); + + return (rv); +} + +int +pfctl_recurse(int dev, int opts, const char *anchorname, + int(*walkf)(int, int, struct pfr_anchoritem *)) +{ + int rv = 0; + struct pfr_anchors *anchors; + struct pfr_anchoritem *pfra, *pfra_save; + + anchors = pfctl_get_anchors(dev, anchorname, opts); + /* + * While traversing the list, pfctl_clear_*() must always return + * so that failures on one anchor do not prevent clearing others. + */ + opts |= PF_OPT_IGNFAIL; + printf("Removing:\n"); + SLIST_FOREACH_SAFE(pfra, anchors, pfra_sle, pfra_save) { + printf(" %s\n", + (*pfra->pfra_anchorname == '\0') ? "/" : + pfra->pfra_anchorname); + rv |= walkf(dev, opts, pfra); + SLIST_REMOVE(anchors, pfra, pfr_anchoritem, pfra_sle); + free(pfra->pfra_anchorname); + free(pfra); + } + + return (rv); +} + +int pfctl_show_eth_anchors(int dev, int opts, char *anchorname) { struct pfctl_eth_rulesets_info ri; @@ -2990,7 +3171,6 @@ pfctl_reset(int dev, int opts) int main(int argc, char *argv[]) { - int error = 0; int ch; int mode = O_RDONLY; int opts = 0; @@ -3218,7 +3398,7 @@ main(int argc, char *argv[]) if (opts & PF_OPT_DISABLE) if (pfctl_disable(dev, opts)) - error = 1; + exit_val = 1; if ((path = calloc(1, MAXPATHLEN)) == NULL) errx(1, "%s: calloc", __func__); @@ -3259,7 +3439,7 @@ main(int argc, char *argv[]) pfctl_show_status(dev, opts); break; case 'R': - error = pfctl_show_running(dev); + exit_val = pfctl_show_running(dev); break; case 't': pfctl_show_timeouts(dev, opts); @@ -3321,7 +3501,11 @@ main(int argc, char *argv[]) pfctl_flush_eth_rules(dev, opts, anchorname); break; case 'r': - pfctl_flush_rules(dev, opts, anchorname); + if (opts & PF_OPT_RECURSE) + pfctl_recurse(dev, opts, anchorname, + pfctl_call_clearrules); + else + pfctl_flush_rules(dev, opts, anchorname); break; case 'n': pfctl_flush_nat(dev, opts, anchorname); @@ -3347,7 +3531,13 @@ main(int argc, char *argv[]) pfctl_flush_eth_rules(dev, opts, anchorname); pfctl_flush_rules(dev, opts, anchorname); pfctl_flush_nat(dev, opts, anchorname); - pfctl_do_clear_tables(anchorname, opts); + if (opts & PF_OPT_RECURSE) + pfctl_recurse(dev, opts, anchorname, + pfctl_call_clearanchors); + else { + pfctl_do_clear_tables(anchorname, opts); + pfctl_flush_rules(dev, opts, anchorname); + } if (!*anchorname) { pfctl_clear_altq(dev, opts); pfctl_clear_iface_states(dev, ifaceopt, opts); @@ -3361,7 +3551,11 @@ main(int argc, char *argv[]) pfctl_clear_fingerprints(dev, opts); break; case 'T': - pfctl_do_clear_tables(anchorname, opts); + if ((opts & PF_OPT_RECURSE) == 0) + pfctl_do_clear_tables(anchorname, opts); + else + pfctl_recurse(dev, opts, anchorname, + pfctl_call_cleartables); break; case 'R': pfctl_reset(dev, opts); @@ -3385,7 +3579,7 @@ main(int argc, char *argv[]) pfctl_kill_src_nodes(dev, opts); if (tblcmdopt != NULL) { - error = pfctl_table(argc, argv, tableopt, + exit_val = pfctl_table(argc, argv, tableopt, tblcmdopt, rulesopt, anchorname, opts); rulesopt = NULL; } @@ -3411,17 +3605,17 @@ main(int argc, char *argv[]) if (rulesopt != NULL && !(opts & PF_OPT_MERGE) && !anchorname[0] && (loadopt & PFCTL_FLAG_OPTION)) if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE)) - error = 1; + exit_val = 1; if (rulesopt != NULL) { if (pfctl_rules(dev, rulesopt, opts, optimize, anchorname, NULL)) - error = 1; + exit_val = 1; } if (opts & PF_OPT_ENABLE) if (pfctl_enable(dev, opts)) - error = 1; + exit_val = 1; if (debugopt != NULL) { switch (*debugopt) { @@ -3440,5 +3634,19 @@ main(int argc, char *argv[]) } } - exit(error); + exit(exit_val); +} + +char * +pf_strerror(int errnum) +{ + switch (errnum) { + case ESRCH: + return "Table does not exist."; + case EINVAL: + case ENOENT: + return "Anchor does not exist."; + default: + return strerror(errnum); + } } diff --git a/sbin/pfctl/pfctl.h b/sbin/pfctl/pfctl.h index d8196c129187..afecc78086e0 100644 --- a/sbin/pfctl/pfctl.h +++ b/sbin/pfctl/pfctl.h @@ -55,6 +55,13 @@ struct pfr_buffer { (var) != NULL; \ (var) = pfr_buf_next((buf), (var))) +struct pfr_anchoritem { + SLIST_ENTRY(pfr_anchoritem) pfra_sle; + char *pfra_anchorname; +}; + +SLIST_HEAD(pfr_anchors, pfr_anchoritem); + int pfr_get_fd(void); int pfr_add_table(struct pfr_table *, int *, int); int pfr_del_table(struct pfr_table *, int *, int); @@ -76,12 +83,12 @@ void *pfr_buf_next(struct pfr_buffer *, const void *); int pfr_buf_grow(struct pfr_buffer *, int); int pfr_buf_load(struct pfr_buffer *, char *, int, int (*)(struct pfr_buffer *, char *, int, int), int); -char *pfr_strerror(int); +char *pf_strerror(int); int pfi_get_ifaces(const char *, struct pfi_kif *, int *); int pfi_clr_istats(const char *, int *, int); void pfctl_print_title(char *); -void pfctl_do_clear_tables(const char *, int); +int pfctl_do_clear_tables(const char *, int); void pfctl_show_tables(const char *, int); int pfctl_table(int, char *[], char *, const char *, char *, const char *, int); @@ -150,4 +157,7 @@ void expand_label(char *, size_t, struct pfctl_rule *); const char *pfctl_proto2name(int); +void pfctl_err(int, int, const char *, ...); +void pfctl_errx(int, int, const char *, ...); + #endif /* _PFCTL_H_ */ diff --git a/sbin/pfctl/pfctl_optimize.c b/sbin/pfctl/pfctl_optimize.c index b58bace326c2..1d2a60555f19 100644 --- a/sbin/pfctl/pfctl_optimize.c +++ b/sbin/pfctl/pfctl_optimize.c @@ -273,7 +273,10 @@ pfctl_optimize_ruleset(struct pfctl *pf, struct pfctl_ruleset *rs) struct pfctl_rule *r; struct pfctl_rulequeue *old_rules; - DEBUG("optimizing ruleset"); + if (TAILQ_EMPTY(rs->rules[PF_RULESET_FILTER].active.ptr)) + return (0); + + DEBUG("optimizing ruleset \"%s\"", rs->anchor->path); memset(&table_buffer, 0, sizeof(table_buffer)); skip_init(); TAILQ_INIT(&opt_queue); @@ -720,11 +723,7 @@ reorder_rules(struct pfctl *pf, struct superblock *block, int depth) * it based on a more optimal skipstep order. */ TAILQ_INIT(&head); - while ((por = TAILQ_FIRST(&block->sb_rules))) { - TAILQ_REMOVE(&block->sb_rules, por, por_entry); - TAILQ_INSERT_TAIL(&head, por, por_entry); - } - + TAILQ_CONCAT(&head, &block->sb_rules, por_entry); while (!TAILQ_EMPTY(&head)) { largest = 1; @@ -745,11 +744,7 @@ reorder_rules(struct pfctl *pf, struct superblock *block, int depth) * Nothing useful left. Leave remaining rules in order. */ DEBUG("(%d) no more commonality for skip steps", depth); - while ((por = TAILQ_FIRST(&head))) { - TAILQ_REMOVE(&head, por, por_entry); - TAILQ_INSERT_TAIL(&block->sb_rules, por, - por_entry); - } + TAILQ_CONCAT(&block->sb_rules, &head, por_entry); } else { /* * There is commonality. Extract those common rules @@ -860,10 +855,7 @@ block_feedback(struct pfctl *pf, struct superblock *block) */ TAILQ_INIT(&queue); - while ((por1 = TAILQ_FIRST(&block->sb_rules)) != NULL) { - TAILQ_REMOVE(&block->sb_rules, por1, por_entry); - TAILQ_INSERT_TAIL(&queue, por1, por_entry); - } + TAILQ_CONCAT(&queue, &block->sb_rules, por_entry); while ((por1 = TAILQ_FIRST(&queue)) != NULL) { TAILQ_REMOVE(&queue, por1, por_entry); @@ -900,13 +892,13 @@ load_feedback_profile(struct pfctl *pf, struct superblocks *superblocks) struct pf_opt_queue queue; struct pfctl_rules_info rules; struct pfctl_rule a, b, rule; - int nr, mnr; + int nr, mnr, ret; TAILQ_INIT(&queue); TAILQ_INIT(&prof_superblocks); - if (pfctl_get_rules_info_h(pf->h, &rules, PF_PASS, "")) { - warn("DIOCGETRULES"); + if ((ret = pfctl_get_rules_info_h(pf->h, &rules, PF_PASS, "")) != 0) { + warnx("%s", pf_strerror(ret)); return (1); } mnr = rules.nr; @@ -921,7 +913,7 @@ load_feedback_profile(struct pfctl *pf, struct superblocks *superblocks) if (pfctl_get_rule_h(pf->h, nr, rules.ticket, "", PF_PASS, &rule, anchor_call)) { - warn("DIOCGETRULENV"); + warnx("%s", pf_strerror(ret)); free(por); return (1); } @@ -1256,7 +1248,7 @@ add_opt_table(struct pfctl *pf, struct pf_opt_tbl **tbl, sa_family_t af, /* This is just a temporary table name */ snprintf((*tbl)->pt_name, sizeof((*tbl)->pt_name), "%s%d", - PF_OPT_TABLE_PREFIX, tablenum++); + PF_OPTIMIZER_TABLE_PFX, tablenum++); DEBUG("creating table <%s>", (*tbl)->pt_name); } @@ -1323,9 +1315,9 @@ pf_opt_create_table(struct pfctl *pf, struct pf_opt_tbl *tbl) /* Now we have to pick a table name that isn't used */ again: DEBUG("translating temporary table <%s> to <%s%x_%d>", tbl->pt_name, - PF_OPT_TABLE_PREFIX, table_identifier, tablenum); + PF_OPTIMIZER_TABLE_PFX, table_identifier, tablenum); snprintf(tbl->pt_name, sizeof(tbl->pt_name), "%s%x_%d", - PF_OPT_TABLE_PREFIX, table_identifier, tablenum); + PF_OPTIMIZER_TABLE_PFX, table_identifier, tablenum); PFRB_FOREACH(t, &table_buffer) { if (strcasecmp(t->pfrt_name, tbl->pt_name) == 0) { /* Collision. Try again */ diff --git a/sbin/pfctl/pfctl_osfp.c b/sbin/pfctl/pfctl_osfp.c index 3a94c2e8c81b..5770c8343a46 100644 --- a/sbin/pfctl/pfctl_osfp.c +++ b/sbin/pfctl/pfctl_osfp.c @@ -264,7 +264,7 @@ void pfctl_clear_fingerprints(int dev, int opts) { if (ioctl(dev, DIOCOSFPFLUSH)) - err(1, "DIOCOSFPFLUSH"); + pfctl_err(opts, 1, "DIOCOSFPFLUSH"); } /* flush pfctl's view of the fingerprints */ diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c index 26a213c3ffd9..f2eb75135609 100644 --- a/sbin/pfctl/pfctl_parser.c +++ b/sbin/pfctl/pfctl_parser.c @@ -68,7 +68,7 @@ void print_op (u_int8_t, const char *, const char *); void print_port (u_int8_t, u_int16_t, u_int16_t, const char *, int); -void print_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned); +void print_ugid (u_int8_t, id_t, id_t, const char *); void print_flags (uint16_t); void print_fromto(struct pf_rule_addr *, pf_osfp_t, struct pf_rule_addr *, sa_family_t, u_int8_t, int, int); @@ -364,14 +364,14 @@ print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, const char *proto, int numer } void -print_ugid(u_int8_t op, unsigned u1, unsigned u2, const char *t, unsigned umax) +print_ugid(u_int8_t op, id_t i1, id_t i2, const char *t) { char a1[11], a2[11]; - snprintf(a1, sizeof(a1), "%u", u1); - snprintf(a2, sizeof(a2), "%u", u2); + snprintf(a1, sizeof(a1), "%ju", (uintmax_t)i1); + snprintf(a2, sizeof(a2), "%ju", (uintmax_t)i2); printf(" %s", t); - if (u1 == umax && (op == PF_OP_EQ || op == PF_OP_NE)) + if (i1 == -1 && (op == PF_OP_EQ || op == PF_OP_NE)) print_op(op, "unknown", a2); else print_op(op, a1, a2); @@ -928,7 +928,7 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numer printf("%sall", count++ ? ", " : ""); if (r->log & PF_LOG_MATCHES) printf("%smatches", count++ ? ", " : ""); - if (r->log & PF_LOG_SOCKET_LOOKUP) + if (r->log & PF_LOG_USER) printf("%suser", count++ ? ", " : ""); if (r->logif) printf("%sto pflog%u", count++ ? ", " : "", @@ -977,11 +977,9 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numer printf(" %sreceived-on %s", r->rcvifnot ? "!" : "", r->rcv_ifname); if (r->uid.op) - print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user", - UID_MAX); + print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user"); if (r->gid.op) - print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group", - GID_MAX); + print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group"); if (r->flags || r->flagset) { printf(" flags "); print_flags(r->flags); @@ -1485,7 +1483,8 @@ ifa_load(void) err(1, "getifaddrs"); for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - if (!(ifa->ifa_addr->sa_family == AF_INET || + if (ifa->ifa_addr == NULL || + !(ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6 || ifa->ifa_addr->sa_family == AF_LINK)) continue; diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h index b91d37c791ae..7a3c0c2a523f 100644 --- a/sbin/pfctl/pfctl_parser.h +++ b/sbin/pfctl/pfctl_parser.h @@ -55,6 +55,7 @@ #define PF_OPT_RECURSE 0x04000 #define PF_OPT_KILLMATCH 0x08000 #define PF_OPT_NODNS 0x10000 +#define PF_OPT_IGNFAIL 0x20000 #define PF_NAT_PROXY_PORT_LOW 50001 #define PF_NAT_PROXY_PORT_HIGH 65535 @@ -262,7 +263,6 @@ struct pf_opt_tbl { struct node_tinithead pt_nodes; struct pfr_buffer *pt_buf; }; -#define PF_OPT_TABLE_PREFIX "__automatic_" /* optimizer pf_rule container */ struct pf_opt_rule { diff --git a/sbin/pfctl/pfctl_radix.c b/sbin/pfctl/pfctl_radix.c index 21191259adff..00e4207d377b 100644 --- a/sbin/pfctl/pfctl_radix.c +++ b/sbin/pfctl/pfctl_radix.c @@ -461,16 +461,3 @@ pfr_next_token(char buf[BUF_SIZE], FILE *fp) buf[i] = '\0'; return (1); } - -char * -pfr_strerror(int errnum) -{ - switch (errnum) { - case ESRCH: - return "Table does not exist"; - case ENOENT: - return "Anchor or Ruleset does not exist"; - default: - return strerror(errnum); - } -} diff --git a/sbin/pfctl/pfctl_table.c b/sbin/pfctl/pfctl_table.c index 0842b042df41..f583f5ef8e79 100644 --- a/sbin/pfctl/pfctl_table.c +++ b/sbin/pfctl/pfctl_table.c @@ -61,7 +61,6 @@ static int load_addr(struct pfr_buffer *, int, char *[], char *, int, int); static void print_addrx(struct pfr_addr *, struct pfr_addr *, int); static int nonzero_astats(struct pfr_astats *); static void print_astats(struct pfr_astats *, int); -static void radix_perror(void); static void xprintf(int, const char *, ...); static void print_iface(struct pfi_kif *, int); @@ -75,13 +74,14 @@ static const char *istats_text[2][2][2] = { { { "In6/Pass:", "In6/Block:" }, { "Out6/Pass:", "Out6/Block:" } } }; -#define RVTEST(fct) do { \ - if ((!(opts & PF_OPT_NOACTION) || \ - (opts & PF_OPT_DUMMYACTION)) && \ - (fct)) { \ - radix_perror(); \ - goto _error; \ - } \ +#define RVTEST(fct) do { \ + if ((!(opts & PF_OPT_NOACTION) || \ + (opts & PF_OPT_DUMMYACTION)) && \ + (fct)) { \ + if ((opts & PF_OPT_RECURSE) == 0) \ + warnx("%s", pf_strerror(errno)); \ + goto _error; \ + } \ } while (0) #define CREATE_TABLE do { \ @@ -92,7 +92,7 @@ static const char *istats_text[2][2][2] = { (opts & PF_OPT_DUMMYACTION)) && \ (pfr_add_table(&table, &nadd, flags)) && \ (errno != EPERM)) { \ - radix_perror(); \ + warnx("%s", pf_strerror(errno)); \ goto _error; \ } \ if (nadd) { \ @@ -103,11 +103,17 @@ static const char *istats_text[2][2][2] = { table.pfrt_flags &= ~PFR_TFLAG_PERSIST; \ } while(0) -void +int pfctl_do_clear_tables(const char *anchor, int opts) { - if (pfctl_table(0, NULL, NULL, "-F", NULL, anchor, opts)) - exit(1); + int rv; + + if ((rv = pfctl_table(0, NULL, NULL, "-F", NULL, anchor, opts)) == -1) { + if ((opts & PF_OPT_IGNFAIL) == 0) + exit(1); + } + + return (rv); } void @@ -552,13 +558,6 @@ print_astats(struct pfr_astats *as, int dns) (unsigned long long)as->pfras_bytes[dir][op]); } -void -radix_perror(void) -{ - extern char *__progname; - fprintf(stderr, "%s: %s.\n", __progname, pfr_strerror(errno)); -} - int pfctl_define_table(char *name, int flags, int addrs, const char *anchor, struct pfr_buffer *ab, u_int32_t ticket) @@ -640,10 +639,8 @@ pfctl_show_ifaces(const char *filter, int opts) for (;;) { pfr_buf_grow(&b, b.pfrb_size); b.pfrb_size = b.pfrb_msize; - if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size)) { - radix_perror(); - exit(1); - } + if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size)) + errx(1, "%s", pf_strerror(errno)); if (b.pfrb_size <= b.pfrb_msize) break; } diff --git a/sbin/pfctl/tests/files/pf0088.in b/sbin/pfctl/tests/files/pf0088.in index 4700b6916b7e..a85aa84a30bb 100644 --- a/sbin/pfctl/tests/files/pf0088.in +++ b/sbin/pfctl/tests/files/pf0088.in @@ -16,7 +16,7 @@ pass to 10.0.0.2 keep state block from 10.0.0.3 to 10.0.0.2 pass to 10.0.0.2 modulate state block from 10.0.0.3 to 10.0.0.2 -pass to 10.0.0.2 synproxy state +pass in to 10.0.0.2 synproxy state pass out proto tcp from 10.0.0.4 to 10.0.0.5 keep state diff --git a/sbin/pfctl/tests/files/pf0088.ok b/sbin/pfctl/tests/files/pf0088.ok index 47251a4503dd..801056a4ab46 100644 --- a/sbin/pfctl/tests/files/pf0088.ok +++ b/sbin/pfctl/tests/files/pf0088.ok @@ -11,7 +11,7 @@ pass inet from any to 10.0.0.2 flags S/SA keep state block drop inet from 10.0.0.3 to 10.0.0.2 pass inet from any to 10.0.0.2 flags S/SA modulate state block drop inet from 10.0.0.3 to 10.0.0.2 -pass inet from any to 10.0.0.2 flags S/SA synproxy state +pass in inet from any to 10.0.0.2 flags S/SA synproxy state pass out inet proto tcp from 10.0.0.4 to 10.0.0.5 flags S/SA keep state pass out inet proto tcp from 10.0.0.4 to 10.0.0.5 port = http flags S/SA keep state pass out all flags S/SA keep state diff --git a/sbin/pfctl/tests/files/pf1072.fail b/sbin/pfctl/tests/files/pf1072.fail new file mode 100644 index 000000000000..06ef5ae457e5 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1072.fail @@ -0,0 +1 @@ +invalid port range diff --git a/sbin/pfctl/tests/files/pf1072.in b/sbin/pfctl/tests/files/pf1072.in new file mode 100644 index 000000000000..e09e92388ce1 --- /dev/null +++ b/sbin/pfctl/tests/files/pf1072.in @@ -0,0 +1 @@ +pass in proto tcp from any port 500:100 to any diff --git a/sbin/pfctl/tests/macro.sh b/sbin/pfctl/tests/macro.sh index 9c48dbbc69f0..071c6cb4f426 100755 --- a/sbin/pfctl/tests/macro.sh +++ b/sbin/pfctl/tests/macro.sh @@ -3,6 +3,7 @@ atf_test_case "space" cleanup space_head() { atf_set descr "Test macros with spaces" + atf_set require.kmods "pf" } space_body() diff --git a/sbin/pfctl/tests/pfctl_test.c b/sbin/pfctl/tests/pfctl_test.c index dbdcaa4900ea..5f0aa7826bb4 100644 --- a/sbin/pfctl/tests/pfctl_test.c +++ b/sbin/pfctl/tests/pfctl_test.c @@ -65,24 +65,6 @@ * Copied from OpenBSD. */ -static bool -check_pf_module_available(void) -{ - int modid; - struct module_stat stat; - - if ((modid = modfind("pf")) < 0) { - warn("pf module not found"); - return false; - } - stat.version = sizeof(struct module_stat); - if (modstat(modid, &stat) < 0) { - warn("can't stat pf module id %d", modid); - return false; - } - return (true); -} - extern char **environ; static struct sbuf * @@ -185,9 +167,6 @@ run_pfctl_test(const char *input_path, const char *output_path, struct sbuf *expected_output; struct sbuf *real_output; - if (!check_pf_module_available()) - atf_tc_skip("pf(4) is not loaded"); - /* The test inputs need to be able to use relative includes. */ snprintf(input_files_path, sizeof(input_files_path), "%s/files", atf_tc_get_config_var(tc, "srcdir")); @@ -292,6 +271,7 @@ do_selfpf_test(const char *number, const atf_tc_t *tc) ATF_TC_HEAD(pf##number, tc) \ { \ atf_tc_set_md_var(tc, "descr", descr); \ + atf_tc_set_md_var(tc, "require.kmods", "pf"); \ } \ ATF_TC_BODY(pf##number, tc) \ { \ @@ -301,6 +281,7 @@ do_selfpf_test(const char *number, const atf_tc_t *tc) ATF_TC_HEAD(selfpf##number, tc) \ { \ atf_tc_set_md_var(tc, "descr", "Self " descr); \ + atf_tc_set_md_var(tc, "require.kmods", "pf"); \ } \ ATF_TC_BODY(selfpf##number, tc) \ { \ @@ -312,6 +293,7 @@ do_selfpf_test(const char *number, const atf_tc_t *tc) ATF_TC_HEAD(pf##number, tc) \ { \ atf_tc_set_md_var(tc, "descr", descr); \ + atf_tc_set_md_var(tc, "require.kmods", "pf"); \ } \ ATF_TC_BODY(pf##number, tc) \ { \ @@ -325,6 +307,7 @@ do_selfpf_test(const char *number, const atf_tc_t *tc) atf_tc_set_md_var(tc, "descr", descr); \ atf_tc_set_md_var(tc, "execenv", "jail"); \ atf_tc_set_md_var(tc, "execenv.jail.params", "vnet"); \ + atf_tc_set_md_var(tc, "require.kmods", "pf"); \ } \ ATF_TC_BODY(pf##number, tc) \ { \ diff --git a/sbin/pfctl/tests/pfctl_test_list.inc b/sbin/pfctl/tests/pfctl_test_list.inc index 51729bc9adad..3a68cc06ec74 100644 --- a/sbin/pfctl/tests/pfctl_test_list.inc +++ b/sbin/pfctl/tests/pfctl_test_list.inc @@ -180,3 +180,4 @@ PFCTL_TEST(1068, "max-pkt-rate") PFCTL_TEST(1069, "max-pkt-size") PFCTL_TEST_FAIL(1070, "include line number") PFCTL_TEST(1071, "mask length on (lo0)") +PFCTL_TEST_FAIL(1072, "Invalid port range") diff --git a/sbin/route/route_netlink.c b/sbin/route/route_netlink.c index 631c2860b547..ba22a2ec1e22 100644 --- a/sbin/route/route_netlink.c +++ b/sbin/route/route_netlink.c @@ -738,6 +738,7 @@ print_nlmsg(struct nl_helper *h, struct nlmsghdr *hdr, struct snl_msg_info *cinf print_nlmsg_generic(h, hdr, cinfo); } + fflush(stdout); snl_clear_lb(&h->ss_cmd); } diff --git a/sbin/savecore/savecore.8 b/sbin/savecore/savecore.8 index 53d2360719dd..1fb79c51f98d 100644 --- a/sbin/savecore/savecore.8 +++ b/sbin/savecore/savecore.8 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd April 4, 2022 +.Dd July 16, 2025 .Dt SAVECORE 8 .Os .Sh NAME @@ -69,7 +69,7 @@ Generate output via .Xr libxo 3 in a selection of different human and machine readable formats. See -.Xr xo_parse_args 3 +.Xr xo_options 7 for details on command line arguments. .It Fl C Check to see if a dump exists, @@ -193,7 +193,7 @@ is meant to be called near the end of the initialization file .Xr zstd 1 , .Xr getbootfile 3 , .Xr libxo 3 , -.Xr xo_parse_args 3 , +.Xr xo_options 7 , .Xr mem 4 , .Xr textdump 4 , .Xr tar 5 , |