BSD Network Tools
Inspecting and configuring networking on FreeBSD, OpenBSD, and NetBSD with ifconfig, route, netstat, and pf.
BSD Network Tools
Inspecting and configuring networking on FreeBSD, OpenBSD, and NetBSD with ifconfig, route, netstat, and pf.
Overview
If you arrive from Linux, the muscle memory is wrong. On modern Linux the ip suite (iproute2) has displaced ifconfig, route, netstat, and arp, which are now legacy compatibility wrappers. On the BSDs the opposite is true: ifconfig, route, netstat, and arp are the primary, current, fully-supported tools. There is no ip command, no ss, and no tc. The classic BSD utilities never went away because they were never deprecated — they are actively developed and remain the canonical interface.
Three points trip up newcomers most:
- Interface names are driver-based, not
eth0/eth1. An Intel gigabit NIC isem0origb0, a Realtek isre0, a Broadcom isbge0. The number is the unit, not a slot. Runifconfig -lto discover them. - Configuration persists in plain
rc.conf-style files, not in a daemon's database. FreeBSD and NetBSD use/etc/rc.conf; OpenBSD uses per-interface/etc/hostname.iffiles. Runtime changes viaifconfigare lost on reboot unless written to these files. - The firewall is not netfilter. OpenBSD invented and ships pf; FreeBSD ships pf, ipfw, and legacy ipf; NetBSD's default is npf (its in-tree pf and ipf are deprecated and their use is discouraged — reach for npf).
flowchart TB
subgraph Linux["Linux (iproute2)"]
L1["ip addr / ip link"]
L2["ip route"]
L3["ss"]
L4["tc"]
L5["nftables"]
end
subgraph BSD["BSD (classic tools)"]
B1["ifconfig"]
B2["route / netstat -r"]
B3["sockstat / netstat -an"]
B4["dummynet / ALTQ"]
B5["pf / ipfw / npf"]
end
L1 -.maps to.-> B1
L2 -.maps to.-> B2
L3 -.maps to.-> B3
L4 -.maps to.-> B4
L5 -.maps to.-> B5
Per-OS defaults at a glance
| Capability | FreeBSD | OpenBSD | NetBSD |
|---|---|---|---|
| Persistent config | /etc/rc.conf |
/etc/hostname.if |
/etc/rc.conf + /etc/ifconfig.if |
| Default firewall | none enabled; pf, ipfw, ipf available | pf (always present) | npf (pf, ipf in-tree but deprecated) |
sockstat |
yes | no (use fstat/netstat) |
no (use fstat/netstat) |
| Traffic shaping | dummynet (ipfw), ALTQ (pf) | pf queueing (HFSC), ALTQ on older | ALTQ |
| Link aggregation | lagg |
trunk/aggr |
agr |
Linux to BSD Command Mapping
The single most useful table if you think in iproute2. The BSD column is the idiomatic equivalent, not a drop-in syntax match — the arguments differ.
| Task | Linux (iproute2) | BSD |
|---|---|---|
| Show/set addresses | ip addr |
ifconfig |
| Show/set link state | ip link |
ifconfig |
| Show routing table | ip route |
netstat -rn |
| Add/del routes | ip route add/del |
route add/delete |
| Neighbour (ARP) | ip neigh |
arp |
| Neighbour (IPv6 ND) | ip -6 neigh |
ndp |
| Socket statistics | ss |
sockstat (FreeBSD) / netstat -an |
| Interface counters | ip -s link |
netstat -i / netstat -ibdh |
| Traffic shaping | tc |
dummynet (ipfw) / pf queues / ALTQ |
| Link media/speed | ethtool |
ifconfig <if> media |
| Tunnels/VLANs/bridges | ip link add |
ifconfig <if> create |
| Firewall | nft / iptables |
pfctl / ipfw / npfctl |
A common mistake: there is no ip route show table-style multi-table routing on stock BSD. FreeBSD has setfib/multiple FIBs and OpenBSD has rdomains/rtables, but these are deliberate, separate features — not the everyday model.
ifconfig
ifconfig is the workhorse: it shows and configures addresses, link state, media, MTU, and creates virtual interfaces. It is not deprecated here.
Key Concepts
- A single
ifconfiginvocation can stack multiple operations: address family, address, netmask, and flags all on one line. - Secondary addresses are aliases. The first
inetis the primary; every additional address must use thealiaskeyword. This is the biggest divergence fromip addr add, which treats all addresses uniformly. - Netmask can be given as a dotted quad, a hex mask (
0xffffff00), or — on FreeBSD and NetBSD — CIDR via/24. OpenBSDifconfigalso accepts/24.
Showing Interfaces
# List interface names only (the "what are my NICs called" command)
ifconfig -l
# Show all interfaces, full detail
ifconfig
# Show one interface
ifconfig em0
# Show only up-and-running interfaces
ifconfig -u
# Show only interfaces of a given type/group (FreeBSD/OpenBSD groups)
ifconfig -g egress # OpenBSD: the interface with the default route
Addresses
# Set the primary IPv4 address (CIDR form, FreeBSD/NetBSD/OpenBSD)
ifconfig em0 inet 192.0.2.10/24
# Equivalent with explicit netmask
ifconfig em0 inet 192.0.2.10 netmask 255.255.255.0
# Add a SECONDARY address — must use 'alias'
ifconfig em0 inet 192.0.2.11/32 alias
# Remove a secondary address
ifconfig em0 inet 192.0.2.11 -alias
# IPv6 address
ifconfig em0 inet6 2001:db8::10 prefixlen 64
# Add a secondary IPv6 alias
ifconfig em0 inet6 2001:db8::11 prefixlen 64 alias
# Remove the primary IPv4 address entirely
ifconfig em0 inet 192.0.2.10 -alias # (removing primary uses -alias too)
Note: for the primary address you normally just overwrite it by setting a new one. The
alias/-aliasdistinction matters most when adding or removing extra addresses on an interface that already has one.
Link State, MTU, and MAC
# Bring an interface up / down
ifconfig em0 up
ifconfig em0 down
# Set MTU (jumbo frames example)
ifconfig em0 mtu 9000
# Override the MAC address (link-layer)
ifconfig em0 ether 02:00:00:aa:bb:cc # FreeBSD: 'ether' or 'lladdr'
ifconfig em0 lladdr 02:00:00:aa:bb:cc # OpenBSD/NetBSD: 'lladdr'
Media (the ethtool equivalent)
media/mediaopt set speed, duplex, and link options. This is where ethtool muscle memory goes.
# Show supported media types and current setting
ifconfig em0 media
# Force 1000baseT full duplex
ifconfig em0 media 1000baseT mediaopt full-duplex
# Force autoselect (let the PHY negotiate)
ifconfig em0 media autoselect
# Wireless: list options (FreeBSD wraps the NIC in a wlanN clone)
ifconfig wlan0 list scan
Cloned (Virtual) Interfaces
BSD creates virtual interfaces on demand with create. This is the ip link add analogue.
# Create and destroy
ifconfig vlan0 create
ifconfig vlan0 destroy
# tap (layer-2) and tun (layer-3) point-to-point devices
ifconfig tap0 create
ifconfig tun0 create
# bridge, lagg, gif (generic tunnel), gre
ifconfig bridge0 create
ifconfig lagg0 create
ifconfig gif0 create
Naming caveat: FreeBSD uses
laggfor aggregation andtap/tun; OpenBSD usestrunk/aggrfor aggregation, andtun/tapexist but tap istap. Verify the cloner name on the target OS withifconfig <name> create— an unknown cloner errors immediately.
VLANs
802.1Q VLAN interfaces are cloned and bound to a parent (the "vlandev").
# FreeBSD: create vlan10 on top of em0 with tag 10
ifconfig vlan0 create vlan 10 vlandev em0
ifconfig vlan0 inet 192.0.2.10/24 up
# FreeBSD also supports the descriptive name form
ifconfig em0.10 create # creates a vlan interface named em0.10, tag 10
# OpenBSD: same vlan/vlandev keywords
ifconfig vlan10 create
ifconfig vlan10 vlan 10 vlandev em0
ifconfig vlan10 inet 192.0.2.10/24 up
The
vlan/vlandevkeyword pair is consistent across FreeBSD, OpenBSD, and NetBSD. The auto-namedem0.10shorthand is a FreeBSD convenience — do not assume it on OpenBSD/NetBSD.
Bridges
A bridge joins interfaces at layer 2. Members are added with addm.
# Create the bridge
ifconfig bridge0 create
# Add member interfaces
ifconfig bridge0 addm em0 addm em1
# Bring it up
ifconfig bridge0 up
# Remove a member
ifconfig bridge0 deletem em1
# Inspect members and STP state
ifconfig bridge0
graph TB
subgraph bridge0
M1["em0 (addm)"]
M2["em1 (addm)"]
M3["tap0 (addm)"]
end
M1 --- SW["L2 forwarding"]
M2 --- SW
M3 --- SW
This is the standard pattern for bridging VMs/jails to a physical NIC (a tap per guest, all added to one bridge0).
Link Aggregation
The keyword and driver differ by OS — a frequent stumbling block.
# FreeBSD: lagg with LACP
ifconfig lagg0 create
ifconfig lagg0 laggproto lacp laggport em0 laggport em1
ifconfig lagg0 inet 192.0.2.10/24 up
# FreeBSD failover protocol (active/standby)
ifconfig lagg0 laggproto failover laggport em0 laggport em1
# OpenBSD: 'aggr' (the LACP/802.1AX driver) — members added with 'trunkport'
ifconfig aggr0 create
ifconfig aggr0 trunkport em0 trunkport em1
ifconfig aggr0 inet 192.0.2.10/24 up
# OpenBSD also has the older 'trunk' driver for non-LACP modes
# (failover, loadbalance, roundrobin, broadcast — NOT lacp):
ifconfig trunk0 create
ifconfig trunk0 trunkproto failover trunkport em0 trunkport em1
# NetBSD uses 'agr' (which does LACP)
Verify before relying on it: FreeBSD =
lagg/laggproto/laggport; OpenBSD splits the job —aggr(4)is the LACP/802.1AX driver, while the oldertrunk(4)does not implement LACP (onlyfailover,loadbalance,roundrobin,broadcast); NetBSD =agr(which does LACP). Both OpenBSD drivers add members withtrunkport. The protocol names are broadly shared but not identical across all three — check the man page on the box.
route
route manipulates the kernel routing table directly. The syntax is the classic BSD form and differs from ip route — there is no via/dev grammar.
Key Concepts
-netdeclares a network destination;-hosta single host. Omitting both letsrouteguess from the netmask.defaultis the keyword for the default route (Linux's0.0.0.0/0).- To view the table, the idiomatic command is
netstat -rn, notroute—routeis for changes and single lookups (route get).
Viewing and Looking Up
# Show the whole routing table, numeric (the everyday command)
netstat -rn
# Show IPv4 only / IPv6 only
netstat -rn -f inet
netstat -rn -f inet6
# Look up the route the kernel would use for a destination
route get 8.8.8.8
route -6 get 2001:4860:4860::8888
Adding and Deleting
# Add a default gateway
route add default 192.0.2.1
route -n add default 192.0.2.1 # -n: no DNS resolution on output
# Add a network route via a gateway
route add -net 10.0.0.0/8 192.0.2.254
# Add a host route
route add -host 10.1.2.3 192.0.2.254
# IPv6 default
route -6 add default 2001:db8::1
# Delete routes
route delete default
route delete -net 10.0.0.0/8
route delete -host 10.1.2.3
# Change an existing route's gateway
route change default 192.0.2.2
# Flush the entire routing table (careful — drops your default too)
route flush
FreeBSD note:
route add default 192.0.2.1works, but scripts often use the explicitroute add -net default 192.0.2.1. On OpenBSD the persistent default lives in/etc/mygate, not in a route command.
arp and ndp
arp manages the IPv4 neighbour cache; ndp is its IPv6 (Neighbour Discovery) counterpart. Together they cover what ip neigh does on Linux.
# --- arp (IPv4) ---
# Show the ARP cache, numeric
arp -an
# Show one host
arp 192.0.2.10
# Add a static (permanent) ARP entry
arp -s 192.0.2.10 00:11:22:33:44:55
# Delete an entry
arp -d 192.0.2.10
# Flush the whole ARP cache (FreeBSD)
arp -d -a
# --- ndp (IPv6 neighbour discovery) ---
# Show the neighbour cache
ndp -an
# Add a static neighbour entry
ndp -s 2001:db8::10 00:11:22:33:44:55
# Delete an entry
ndp -d 2001:db8::10
# Show default router list and prefix list (FreeBSD/NetBSD;
# OpenBSD ndp has no -r/-p — use route(8) / sysctl there)
ndp -r
ndp -p
netstat
On BSD, netstat is not legacy — it is the primary tool for routes, sockets, interface counters, and protocol statistics. Note that BSD netstat flags overlap with Linux's but the output and some flags differ (there is no -tulpn idiom; use the forms below).
Routing and Interfaces
# Routing table (numeric) — the canonical "show routes"
netstat -rn
# Per-interface statistics (packets, errors, collisions)
netstat -i
# Numeric, human-readable, with byte counters (FreeBSD)
netstat -ibdh
# Watch one interface live, updating every second (FreeBSD)
netstat -I em0 -w 1
Sockets
# All sockets, numeric (TCP + UDP + UNIX)
netstat -an
# Only Internet sockets (no UNIX domain)
netstat -an -f inet
netstat -an -f inet6
# Listening TCP sockets, numeric
netstat -an -p tcp | grep LISTEN
# FreeBSD: show the PID/program owning each socket
netstat -anv # -v adds extra columns; pair with sockstat for owners
Protocol and Buffer Statistics
# Per-protocol statistics (retransmits, resets, drops...)
netstat -s
netstat -sp tcp # just TCP
netstat -sp ip
# mbuf (network memory buffer) usage — BSD-specific, no Linux analogue
netstat -m
netstat -m (mbuf clusters) has no real Linux equivalent and is the first place to look when a BSD box reports out-of-memory under network load.
sockstat (FreeBSD)
sockstat is FreeBSD's answer to ss/lsof -i: it maps open sockets to the processes and users that own them. OpenBSD and NetBSD have no sockstat — use netstat -an plus fstat there.
# All open sockets with owning process and user
sockstat
# IPv4 + IPv6 listening sockets only (the "what's listening" command)
sockstat -4 -6 -l
# Only a specific protocol
sockstat -P tcp
# Filter by port
sockstat -p 443
# Connected (non-listening) sockets
sockstat -c
# OpenBSD / NetBSD equivalent — find what holds a socket:
fstat | grep internet
netstat -an -f inet
Firewalls
The BSDs ship different firewalls. Pick by OS and by what you already know. This section summarises; each firewall is a large topic in its own right.
flowchart LR
subgraph FreeBSD
F1["pf"]
F2["ipfw + dummynet"]
F3["ipf (legacy)"]
end
subgraph OpenBSD
O1["pf (only)"]
end
subgraph NetBSD
N1["npf (default)"]
N2["pf"]
N3["ipf"]
end
pf (FreeBSD, OpenBSD, NetBSD)
pf is OpenBSD's firewall and the most portable. Rules live in /etc/pf.conf; pfctl loads and inspects them. pf grammar diverged between OpenBSD and FreeBSD but has largely reconverged — OpenBSD modernised it (match, the nat-to/rdr-to translation rules, and the built-in queue system), and current FreeBSD pf accepts the same inline match … nat-to/rdr-to form, retaining the standalone nat/rdr statements only for backward compatibility. Write the modern nat-to/rdr-to syntax (as below) on both. The lasting divergence is queueing: FreeBSD still uses ALTQ (kernel-options-gated) where OpenBSD has the newer queue/HFSC system. Always check man pf.conf on the target.
# Enable / disable pf
pfctl -e # enable
pfctl -d # disable
# Load (and replace) the ruleset from a file
pfctl -f /etc/pf.conf
# Validate without loading
pfctl -nf /etc/pf.conf
# Show loaded rules / NAT rules / state table / info
pfctl -sr # show filter rules
pfctl -sn # show NAT rules
pfctl -ss # show the state table
pfctl -si # show status and counters
pfctl -sa # show everything
# Tables (named address lists)
pfctl -t bruteforce -T add 203.0.113.5
pfctl -t bruteforce -T show
pfctl -t bruteforce -T flush
# Anchors (sub-rulesets, e.g. for jails / dynamic rules)
pfctl -a myapp -sr
Minimal OpenBSD-style /etc/pf.conf:
# OpenBSD pf.conf — default-deny inbound, stateful
ext_if = "em0"
set skip on lo
block return # default block, send RST/ICMP
pass out quick # allow all outbound, keep state
pass in on $ext_if proto tcp to port { 22, 80, 443 }
# NAT for an internal network (OpenBSD modern syntax)
match out on $ext_if from 192.168.0.0/24 to any nat-to ($ext_if)
# Redirect (port forward) inbound 80 to an internal host
pass in on $ext_if proto tcp to port 80 rdr-to 192.168.0.10
Ordering: OpenBSD pf is last-matching-rule wins (use
quickto stop evaluation). This is the opposite of iptables' first-match. Forgetting this is the classic "my pass rule is overridden by a later block" bug.
ipfw (FreeBSD)
ipfw is FreeBSD-native, rule-numbered, and first-match-wins. It also drives dummynet for traffic shaping.
# Show the ruleset (with rule numbers)
ipfw list
ipfw -a list # with packet/byte counters
# Add rules (lower numbers evaluated first)
ipfw add 100 allow tcp from any to me 22
ipfw add 200 allow ip from any to any via lo0
ipfw add 65000 deny ip from any to any
# Delete a rule by number
ipfw delete 200
# Flush everything (default policy may then deny — keep console access!)
ipfw flush
# Show dynamic (stateful) rules
ipfw -d list
ipfw's implicit final rule is
deny ip from any to anyunless the kernel is built withIPFIREWALL_DEFAULT_TO_ACCEPTornet.inet.ip.fw.default_to_accept=1is set. Flushing the ruleset over SSH can therefore lock you out instantly.
ipf / IPFILTER (legacy, NetBSD)
ipf/ipnat is the older Darren Reed firewall, still present on FreeBSD and NetBSD. Configured via /etc/ipf.conf and /etc/ipnat.conf, managed with ipf, ipnat, and ipfstat. Treat it as legacy on FreeBSD; prefer pf or ipfw for new work.
npf (NetBSD default)
NetBSD's modern firewall is npf, configured in /etc/npf.conf and managed with npfctl.
npfctl validate /etc/npf.conf # check syntax
npfctl reload # load the ruleset
npfctl start # enable
npfctl show # show active config
npfctl stats # counters
Traffic Shaping
There is no tc. BSD shapes traffic through either dummynet (driven by ipfw) or queueing in pf.
dummynet via ipfw (FreeBSD)
dummynet attaches packets to pipes (bandwidth/delay/loss) or queues (weighted sharing).
# Define a pipe: 1 Mbit/s with 50 ms one-way delay
ipfw pipe 1 config bw 1Mbit/s delay 50ms
# Add packet loss and a queue limit
ipfw pipe 1 config bw 1Mbit/s delay 50ms plr 0.01 queue 50
# Send matching traffic into the pipe
ipfw add 100 pipe 1 ip from any to 192.0.2.0/24 out
# Weighted queues sharing a parent pipe
ipfw pipe 10 config bw 10Mbit/s
ipfw queue 1 config pipe 10 weight 100
ipfw queue 2 config pipe 10 weight 10
ipfw add 200 queue 1 tcp from any to any 443 out
ipfw add 210 queue 2 tcp from any to any out
# Inspect
ipfw pipe show
ipfw queue show
Queueing in pf
On FreeBSD, pf shaping uses ALTQ (kernel must have ALTQ compiled in). On OpenBSD, the newer queue syntax (HFSC under the hood) arrived in 5.5 and ALTQ was removed entirely in 5.6.
# OpenBSD modern pf queueing (HFSC) in /etc/pf.conf
queue rootq on em0 bandwidth 100M
queue ssh parent rootq bandwidth 10M
queue web parent rootq bandwidth 50M default
pass out on em0 proto tcp to port 22 set queue ssh
pass out on em0 proto tcp to port { 80, 443 } set queue web
# FreeBSD pf with ALTQ (older syntax; requires ALTQ kernel options)
altq on em0 cbq bandwidth 100Mb queue { ssh, web }
queue ssh bandwidth 10% priority 5
queue web bandwidth 50% cbq(default)
This is the sharpest pf divergence: ALTQ syntax (FreeBSD) and the
queuesyntax (OpenBSD ≥ 5.5, ALTQ removed in 5.6) are mutually incompatible. A pf.conf written for one will not load on the other. Confirm which your target supports.
Sysctl Networking Knobs
BSD sysctl uses the net.inet.* (IPv4) and net.inet6.* (IPv6) trees — not Linux's net.ipv4.* / net.ipv6.*. The tree layout is entirely different, so Linux tuning snippets do not translate verbatim.
# Turn the box into a router (enable IPv4 forwarding) — runtime
sysctl net.inet.ip.forwarding=1
# IPv6 forwarding
sysctl net.inet6.ip6.forwarding=1
# Inspect a subtree
sysctl net.inet.tcp # all TCP knobs
sysctl net.inet.ip.forwarding # one value
# Common FreeBSD tuning examples
sysctl net.inet.tcp.delayed_ack=0
sysctl net.inet.ip.fw.default_to_accept # ipfw default policy (read-only after boot)
sysctl net.inet.ip.redirect=0 # don't send ICMP redirects
| Purpose | BSD sysctl | Linux counterpart |
|---|---|---|
| IPv4 forwarding | net.inet.ip.forwarding |
net.ipv4.ip_forward |
| IPv6 forwarding | net.inet6.ip6.forwarding |
net.ipv6.conf.all.forwarding |
| Send ICMP redirects | net.inet.ip.redirect |
net.ipv4.conf.all.send_redirects |
| TCP keepalive | net.inet.tcp.keepidle (ms) |
net.ipv4.tcp_keepalive_time (s) |
Persist sysctls in
/etc/sysctl.conf(all three BSDs). For routing, the correct way to enable forwarding persistently on FreeBSD isgateway_enable="YES"in/etc/rc.conf(which sets the sysctl at boot), not editing the sysctl directly.
Persistence
Runtime ifconfig/route changes vanish on reboot. Each OS persists configuration differently — this is where Linux habits cause the most "it worked until I rebooted" surprises.
FreeBSD: /etc/rc.conf
# /etc/rc.conf
hostname="host.example.com"
# Static IPv4 on em0
ifconfig_em0="inet 192.0.2.10/24"
# Secondary address (alias) — note the _alias0 suffix, numbered
ifconfig_em0_alias0="inet 192.0.2.11/32"
# IPv6
ifconfig_em0_ipv6="inet6 2001:db8::10 prefixlen 64"
# DHCP instead of static
ifconfig_em0="DHCP"
# Default gateway
defaultrouter="192.0.2.1"
ipv6_defaultrouter="2001:db8::1"
# Act as a router (enables net.inet.ip.forwarding at boot)
gateway_enable="YES"
ipv6_gateway_enable="YES"
# Enable pf and point it at its config
pf_enable="YES"
pf_rules="/etc/pf.conf"
# Or enable ipfw instead
firewall_enable="YES"
firewall_script="/etc/ipfw.rules"
# Create a vlan / bridge at boot
cloned_interfaces="vlan0 bridge0"
ifconfig_vlan0="vlan 10 vlandev em0 inet 192.0.2.10/24"
Apply rc.conf network changes without rebooting:
service netif restart && service routing restart(FreeBSD). On a remote box, do this carefully — restarting netif drops the connection if you fat-finger the address.
OpenBSD: /etc/hostname.if + /etc/mygate
OpenBSD has one file per interface, named /etc/hostname.<ifname>. The default route lives in /etc/mygate.
# /etc/hostname.em0
inet 192.0.2.10 255.255.255.0
inet alias 192.0.2.11 255.255.255.255
inet6 2001:db8::10 64
# DHCP form (single line)
# dhcp
# /etc/mygate
192.0.2.1
2001:db8::1
# /etc/hostname.vlan10 — VLAN persisted on OpenBSD
inet 192.0.2.10 255.255.255.0
vlan 10 vlandev em0
Enable IP forwarding persistently on OpenBSD via /etc/sysctl.conf:
# /etc/sysctl.conf (OpenBSD)
net.inet.ip.forwarding=1
net.inet6.ip6.forwarding=1
pf is on by default on OpenBSD; its config is simply /etc/pf.conf. Apply changes with sh /etc/netstart em0 (re-reads the hostname.if file) or pfctl -f /etc/pf.conf for the firewall.
NetBSD: /etc/rc.conf + /etc/ifconfig.if
NetBSD blends both styles. Simple setups go in /etc/rc.conf; per-interface complexity goes in /etc/ifconfig.<ifname>.
# /etc/rc.conf (NetBSD)
ifconfig_wm0="inet 192.0.2.10 netmask 255.255.255.0"
defaultroute="192.0.2.1"
ip6mode="host"
# Enable the npf firewall
npf=YES
# Router mode: NetBSD has no rc.conf ip_forwarding knob.
# IPv4 forwarding is a sysctl (set it in /etc/sysctl.conf):
# net.inet.ip.forwarding=1
# IPv6 forwarding is driven by ip6mode:
ip6mode="router"
# /etc/ifconfig.wm0 (NetBSD) — alternative, one directive per line
inet 192.0.2.10/24
inet 192.0.2.11/32 alias
NetBSD's driver names differ again: Intel gigabit is often
wm0(notem0). Always checkifconfig -lon the actual machine rather than assuming.
Diagnostics
The classic diagnostic tools mostly originated on BSD, so they behave as expected — but a few names differ.
# Packet capture (tcpdump is BSD-native; see the tcpdump cheatsheet)
tcpdump -i em0 -nn host 192.0.2.10
# Trace the path to a host
traceroute 8.8.8.8
traceroute6 2001:4860:4860::8888
# Connectivity
ping 8.8.8.8
ping6 2001:4860:4860::8888 # FreeBSD also accepts 'ping -6'
# DNS lookups
host example.com # available on all three
dig example.com # FreeBSD (bind-tools), NetBSD
drill example.com # OpenBSD default (ldns; no dig in base)
# Live socket / connection state
sockstat -4 -6 -l # FreeBSD: what's listening
netstat -an -f inet # portable
# pf live state and counters
pfctl -ss # current state table
pfctl -si # status and rule counters
# Interface throughput, live
netstat -I em0 -w 1 # FreeBSD
systat -ifstat 1 # FreeBSD/OpenBSD curses interface stats
OpenBSD ships
drill(from ldns), notdig, in the base system — reaching fordigon a fresh OpenBSD box fails until you install bind-tools.hostis present everywhere.
Quick Reference
| Task | Command |
|---|---|
| List interface names | ifconfig -l |
| Show all interfaces | ifconfig |
| Set primary IPv4 | ifconfig em0 inet 192.0.2.10/24 |
| Add secondary IPv4 | ifconfig em0 inet 192.0.2.11/32 alias |
| Bring interface up/down | ifconfig em0 up / down |
| Set MTU | ifconfig em0 mtu 9000 |
| Force media | ifconfig em0 media 1000baseT mediaopt full-duplex |
| Create vlan | ifconfig vlan0 create vlan 10 vlandev em0 |
| Create bridge + add member | ifconfig bridge0 create ; ifconfig bridge0 addm em0 |
| Show routing table | netstat -rn |
| Add default route | route add default 192.0.2.1 |
| Add network route | route add -net 10.0.0.0/8 192.0.2.254 |
| Look up a route | route get 8.8.8.8 |
| Show ARP cache | arp -an |
| Static ARP entry | arp -s 192.0.2.10 00:11:22:33:44:55 |
| Show IPv6 neighbours | ndp -an |
| Interface counters | netstat -i (FreeBSD: netstat -ibdh) |
| Socket statistics | netstat -an / sockstat -4 -6 -l (FreeBSD) |
| Protocol stats | netstat -sp tcp |
| mbuf usage | netstat -m |
| Enable forwarding (runtime) | sysctl net.inet.ip.forwarding=1 |
| Load pf rules | pfctl -f /etc/pf.conf |
| Show pf state table | pfctl -ss |
| List ipfw rules | ipfw -a list |
| Shape with dummynet | ipfw pipe 1 config bw 1Mbit/s delay 50ms |
Common Issues and Solutions
| Issue | Cause | Solution |
|---|---|---|
| "Interface eth0 not found" | BSD names NICs by driver, not ethN |
Run ifconfig -l; expect em0, igb0, re0, bge0, wm0 (NetBSD) |
| Secondary IP silently doesn't stick | Adding a second address without alias overwrites the primary |
Use ifconfig em0 inet 192.0.2.11/32 alias |
| Config lost after reboot | Runtime ifconfig/route changes aren't persistent |
Write to /etc/rc.conf (FreeBSD/NetBSD) or /etc/hostname.if (OpenBSD) |
ip, ss, tc commands not found |
Those are Linux iproute2 tools | Use ifconfig, netstat/sockstat, dummynet/pf queues |
| pf installed but blocking nothing | pf loaded but not enabled | FreeBSD: pf_enable="YES" in rc.conf + pfctl -e; OpenBSD: pf is on by default |
| All forwarded traffic dropped | IP forwarding off by default | sysctl net.inet.ip.forwarding=1; persist via gateway_enable="YES" (FreeBSD) |
| pf pass rule ignored | OpenBSD pf is last-match-wins; a later block overrides |
Reorder rules or add quick to the pass rule |
Locked out after ipfw flush |
ipfw default is deny ip from any to any |
Keep console access; add an allow-SSH rule before flushing, or set default_to_accept |
dig not found (OpenBSD) |
OpenBSD base ships drill, not dig |
Use drill, or pkg_add bind-tools |
| pf queue config won't load | ALTQ (FreeBSD) vs queue syntax (OpenBSD ≥ 5.5; ALTQ removed in 5.6) are incompatible |
Use the syntax matching the OS; check man pf.conf |
lagg/trunk keyword rejected |
Aggregation driver differs per OS | FreeBSD lagg/laggport; OpenBSD aggr (LACP) or trunk (non-LACP), both via trunkport; NetBSD agr |
sockstat not found |
sockstat is FreeBSD-only | OpenBSD/NetBSD: use netstat -an + fstat |
Related Topics
The following topics complement this BSD networking cheatsheet:
- tcpdump/Wireshark — packet capture, BSD-native, for diagnosing the traffic these tools route
- iptables/nftables — the Linux firewall counterpart to pf/ipfw/npf
- Nginx/HAProxy — application-layer traffic handling on top of BSD networking
- WireGuard / IPsec — VPN tunnels configured via
ifconfig/gif/pf on BSD - DNS (BIND/Unbound) — name resolution, with Unbound shipping in OpenBSD/FreeBSD base
- ZFS/Jails — FreeBSD jails commonly bridge to the network via
bridge/epair/tap