macOS Network Tools
Inspecting and configuring networking on macOS with networksetup, scutil, ifconfig, pfctl, and the unified diagnostics tools.
macOS Network Tools
Inspecting and configuring networking on macOS with networksetup, scutil, ifconfig, pfctl, and the unified diagnostics tools.
Overview
macOS networking is two layers stacked on top of one another:
- A BSD core inherited from FreeBSD —
ifconfig,route,netstat,arp,ndp, and thepfpacket filter. These behave broadly as they do on FreeBSD. - Apple's System Configuration framework — a daemon (
configd) backed by a key/value "dynamic store", plus the user-facing CLIsnetworksetupandscutil. This is what the GUI in System Settings drives, and it is the source of truth for persistent configuration.
The headline trap for anyone arriving from Linux or generic BSD: the BSD tools are for inspection, not durable configuration. ifconfig/route changes apply to the running kernel but are not persistent and configd will revert them — sometimes within seconds, certainly across a link flap, DHCP renewal, or reboot. For changes that stick, use networksetup, scutil, or the GUI.
graph TB
subgraph Apple["Apple System Configuration layer (source of truth)"]
GUI[System Settings GUI]
NS[networksetup]
SC[scutil]
CONFIGD[configd<br/>dynamic store]
GUI --> CONFIGD
NS --> CONFIGD
SC --> CONFIGD
end
subgraph BSD["BSD core (runtime state, not persistent)"]
IFCONFIG[ifconfig]
ROUTE[route]
PF[pf / pfctl]
end
CONFIGD -->|applies + enforces| BSD
BSD -.->|inspect only| You[You]
Interface naming
macOS does not use predictable eth0/ens33-style names. Names are assigned by the kernel in probe order and vary by hardware:
| Interface | Typical role |
|---|---|
en0 |
First Ethernet or Wi-Fi — not guaranteed to be Ethernet |
en1, en2, … |
Further Ethernet/Wi-Fi/Thunderbolt/USB adapters |
lo0 |
Loopback |
bridge0 |
Bridge (Internet Sharing, virtualisation) |
utun0, utun1, … |
Tunnels — VPNs, Tailscale, WireGuard, Back to My Mac |
awdl0 |
Apple Wireless Direct Link (AirDrop, AirPlay, Continuity) |
llw0 |
Low-latency WLAN (Apple peer-to-peer) |
gif0, stf0 |
Generic/6-to-4 tunnel pseudo-interfaces |
anpi0, ap1 |
Apple-internal management/AP interfaces on some Macs |
On a laptop en0 is usually Wi-Fi; on a Mac with built-in Ethernet en0 is usually Ethernet and Wi-Fi lands on en1. Never hard-code the mapping — resolve it with networksetup -listallhardwareports (see below).
Services vs interfaces
A crucial Apple-specific distinction:
- A hardware port / interface is the BSD device (
en0). - A Network Service is a named configuration layered on top of a port — "Wi-Fi", "Ethernet", "USB 10/100/1000 LAN", "Thunderbolt Bridge". A service carries the IP config, DNS, proxies, and service order (priority). Multiple services can map to the same port, and services live inside a Location (a named set of services you can switch between).
networksetup operates on services (by their human-readable name), whereas ifconfig/route operate on interfaces. This is why networksetup -setdnsservers "Wi-Fi" … works but there is no networksetup command that takes en0 directly for DNS — you map the port to a service name first.
The Big Gotcha: runtime vs persistent
flowchart TD
A[You run ifconfig en0 192.0.2.10] --> B[Kernel accepts it immediately]
B --> C{configd reconciliation event<br/>DHCP renew / link flap / reboot}
C --> D[configd reapplies the<br/>service config from the dynamic store]
D --> E[Your manual change is gone]
F[You run networksetup -setmanual Wi-Fi ...] --> G[Written to dynamic store]
G --> H[configd applies AND re-applies it]
H --> I[Change persists]
Rules of thumb:
- Inspect with
ifconfig,netstat,route get,arp,ndp— these are accurate snapshots of live kernel state. - Configure with
networksetup,scutil, or the GUI — these write to the dynamic store thatconfigdenforces. - A manual
ifconfig/routechange is a temporary override. It is genuinely useful for testing (e.g. add a throwaway route to verify reachability) but treat it as ephemeral. - Many operations need
sudo(anything that mutates config) and some need to be in theadmingroup. - SIP (System Integrity Protection) protects system daemons and many
/Systempaths; you cannot replaceconfigd,mDNSResponder, or the firewall binaries, and some diagnostic tools (e.g.wdutil) gate output behindsudo. SIP does not stop normal config vianetworksetup/scutil. /etc/resolv.confis generated by the system and is incomplete — editing it does essentially nothing useful (see DNS section).
networksetup
The primary Apple CLI for persistent configuration. Lives at /usr/sbin/networksetup. Most read operations work unprivileged; writes need sudo. Run networksetup -help for the full (long) list — option names are verbose and case-sensitive, and service names with spaces must be quoted.
Discovery
# List network services in priority order (the service-order list)
networksetup -listallnetworkservices
# An asterisk (*) prefix marks a DISABLED service.
# Map services to hardware ports and BSD device names — the canonical
# way to find out which en* is Wi-Fi vs Ethernet on THIS machine
networksetup -listallhardwareports
# Show the device name for a given port
networksetup -listallhardwareports | grep -A2 "Wi-Fi"
# Full info for a service (IP, mask, router, MAC)
networksetup -getinfo "Wi-Fi"
# Hardware (MAC) address for a port
networksetup -getmacaddress "Wi-Fi"
networksetup -getmacaddress en0
IPv4 configuration
# Switch a service to DHCP
sudo networksetup -setdhcp "Wi-Fi"
# Set a static (manual) IPv4 config: service IP mask router
sudo networksetup -setmanual "Ethernet" 192.0.2.50 255.255.255.0 192.0.2.1
# DHCP but with a manual address handed back to you (BOOTP)
sudo networksetup -setbootp "Ethernet"
# Set/clear a DHCP client ID
sudo networksetup -setdhcp "Wi-Fi" MyClientID
# Read back the current IPv4 method and addressing
networksetup -getinfo "Ethernet"
DNS and search domains
DNS set here is per-service and is what configd publishes to the resolver. This is the correct, persistent way to set DNS — not editing /etc/resolv.conf.
# Show DNS servers for a service
networksetup -getdnsservers "Wi-Fi"
# Prints "There aren't any DNS Servers set on Wi-Fi." when the service
# inherits DNS from DHCP — that is normal, not an error.
# Set DNS servers (replaces the list; space-separated)
sudo networksetup -setdnsservers "Wi-Fi" 1.1.1.1 9.9.9.9
# Revert to DHCP-provided DNS — the literal word "Empty" clears the override
sudo networksetup -setdnsservers "Wi-Fi" Empty
# Search domains
networksetup -getsearchdomains "Wi-Fi"
sudo networksetup -setsearchdomains "Wi-Fi" example.com internal.example.com
sudo networksetup -setsearchdomains "Wi-Fi" Empty
Wi-Fi (AirPort) control
The Wi-Fi port name is usually en0 or en1 — confirm with -listallhardwareports. These commands take the device name, not the service name. The en0 below is illustrative: it holds on most laptops, but on desktops and a Mac mini with built-in Ethernet en0 is Ethernet and Wi-Fi is typically en1, so substitute the device your own -listallhardwareports reports.
# Power the radio on/off
sudo networksetup -setairportpower en0 off
sudo networksetup -setairportpower en0 on
# Current power state
networksetup -getairportpower en0
# Join a network (prompts add it to the keychain/preferred list)
sudo networksetup -setairportnetwork en0 "MySSID" "wifi-password"
# Currently associated SSID
networksetup -getairportnetwork en0
# Preferred networks (the remembered list, in join-priority order)
networksetup -listpreferredwirelessnetworks en0
sudo networksetup -addpreferredwirelessnetworkatindex en0 "MySSID" 0 WPA2 "password"
sudo networksetup -removepreferredwirelessnetwork en0 "MySSID"
sudo networksetup -removeallpreferredwirelessnetworks en0
Service order and IPv6
# Reorder services — first service is preferred for the default route.
# Pass the service names in the desired priority order.
sudo networksetup -ordernetworkservices "Ethernet" "Wi-Fi" "Thunderbolt Bridge"
# Enable/disable a whole service
sudo networksetup -setnetworkserviceenabled "Wi-Fi" off
# IPv6: automatic (default), link-local only, manual, or fully off
networksetup -getinfo "Wi-Fi" # shows IPv6 method
sudo networksetup -setv6automatic "Wi-Fi"
sudo networksetup -setv6linklocal "Wi-Fi"
sudo networksetup -setv6off "Wi-Fi" # disable IPv6 on the service
sudo networksetup -setv6manual "Wi-Fi" 2001:db8::10 64 2001:db8::1
Proxies (briefly)
# Web proxy (HTTP)
sudo networksetup -setwebproxy "Wi-Fi" proxy.example.com 8080
networksetup -getwebproxy "Wi-Fi"
# Auto-proxy (PAC) URL
sudo networksetup -setautoproxyurl "Wi-Fi" "http://proxy.example.com/proxy.pac"
# Turn a proxy off without forgetting its settings
sudo networksetup -setwebproxystate "Wi-Fi" off
scutil
scutil is the System Configuration utility — a thin CLI over the dynamic store plus a set of high-level query subcommands. Use it to read the effective resolver and reachability state and to manage the three host names.
High-level queries
# Network information / reachability: which interfaces have a usable
# default route, in priority order, for IPv4 and IPv6
scutil --nwi
# The effective resolver configuration — THE authoritative view of DNS
# on macOS. Shows scoped and multicast resolvers, not just one list.
scutil --dns
# Effective proxy configuration (resolved from service + PAC)
scutil --proxy
scutil --dns is the one to internalise. macOS DNS is scoped/split: different resolvers apply to different interfaces and different domains. The output is grouped into "resolver #1, #2, …", each with nameserver[], an optional domain/search, and an if_index/flags showing which interface it is bound to. A VPN's utun resolver and your Wi-Fi resolver coexist; a query for corp.internal may go to the VPN resolver while everything else goes to Wi-Fi. /etc/resolv.conf only ever reflects the primary resolver and omits all the scoped ones — which is why a tool that reads resolv.conf (or dig with no scoping) can disagree with what apps actually resolve.
Browsing the dynamic store
scutil with no arguments drops into an interactive session over the key/value store. Keys are path-like (State:/… for live state, Setup:/… for configured intent).
scutil
> list # list all keys
> list State:/Network/.* # keys matching a regex
> show State:/Network/Global/IPv4 # primary service, router, interface
> show State:/Network/Global/DNS # effective global DNS
> show State:/Network/Interface/en0/IPv4
> show Setup:/Network/Service/<id>/DNS # configured (persistent) intent
> quit
One-liners without entering the REPL:
# Primary interface + router in one shot
echo 'show State:/Network/Global/IPv4' | scutil
# Watch a key for changes (notification on update)
scutil -n # then 'open', 'n.add <key>', 'n.watch'
The three host names
macOS has three distinct name fields. Confusing them is a common cause of "why is my hostname wrong" tickets.
| Name | scutil key | What it is | Example |
|---|---|---|---|
| ComputerName | ComputerName |
Friendly UI name (Sharing pane, AirDrop). May contain spaces/Unicode. | Mike's MacBook Pro |
| HostName | HostName |
The "real" DNS/Unix hostname. Often unset, in which case it falls back to reverse-DNS or LocalHostName. |
mbp.example.com |
| LocalHostName | LocalHostName |
The Bonjour/mDNS name, advertised as <name>.local. ASCII, no spaces. |
Mikes-MacBook-Pro |
# Read
scutil --get ComputerName
scutil --get HostName # errors "HostName: not set" if unset — normal
scutil --get LocalHostName
# Set (needs sudo)
sudo scutil --set ComputerName "Mike's MacBook Pro"
sudo scutil --set HostName mbp.example.com
sudo scutil --set LocalHostName Mikes-MacBook-Pro
hostname (the BSD command) reflects HostName if set, otherwise a transient value; setting it with sudo hostname foo is not persistent — use scutil --set HostName.
DNS on macOS
The system resolver is mDNSResponder (the discoveryd experiment of 10.10 was reverted; mDNSResponder has been the resolver since and remains so through current macOS). It handles unicast DNS, multicast DNS (Bonjour), caching, and the per-interface/per-domain scoping described above.
flowchart LR
APP[App] -->|getaddrinfo| MDNS[mDNSResponder]
MDNS -->|scoped lookup| WIFI[Wi-Fi resolver]
MDNS -->|scoped lookup| VPN[utun / VPN resolver]
MDNS -->|.local| MCAST[Multicast DNS]
DIG[dig / host / nslookup] -.->|bypass scoping,<br/>talk to a server directly| WIFI
Querying the way apps see it
dig, host, and nslookup talk to a DNS server directly and do not honour macOS scoping or the search/resolver split. To reproduce what an application actually gets, query through the system resolver:
# Resolve via the system resolver (respects scoping, search domains, /etc/hosts)
dscacheutil -q host -a name example.com
# Bonjour / mDNS browsing and resolution
dns-sd -B _http._tcp # browse for HTTP services on the LAN
dns-sd -B _ssh._tcp local # browse SSH services
dns-sd -L "My Mac" _ssh._tcp # look up a specific instance
dns-sd -G v4v6 host.local # resolve a .local name to addresses
dns-sd -q example.com # unicast query through the resolver
# dig/host still useful for authoritative debugging (which server, raw records)
dig @1.1.1.1 example.com A +short
Rule: if dig succeeds but the app cannot resolve (or vice versa), trust dscacheutil/dns-sd for "what the app sees" and scutil --dns to explain why (wrong scoped resolver, missing search domain, VPN ordering).
Flushing the DNS cache
The current incantation (macOS 10.10.4+ and all modern releases) is both halves together:
sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder
dscacheutil -flushcache flushes the Directory Service cache; the killall -HUP mDNSResponder is what actually flushes the resolver/mDNS cache. Run both.
BSD inspection tools
These work as on FreeBSD and are the right tools for looking. Config changes made with them do not persist (see The Big Gotcha).
# Interface state, addresses, flags, media
ifconfig # all interfaces
ifconfig en0 # one interface
ifconfig -a # include down interfaces
# Routing table (numeric) and the active default route
netstat -rn
netstat -rn -f inet # IPv4 only
netstat -rn -f inet6 # IPv6 only
route -n get default # the resolved default route + its interface
route get 8.8.8.8 # which route/interface a given dst would use
# ARP / NDP neighbour tables
arp -a # IPv4 neighbour (ARP) cache
arp -d 192.0.2.1 # delete an entry (sudo)
ndp -an # IPv6 neighbour cache (the IPv6 'arp')
ndp -rn # IPv6 default routers
# Sockets / connections (no 'ss' on macOS — see below)
netstat -an # all sockets, numeric
netstat -an -p tcp # TCP only
netstat -i # per-interface packet counts / errors / drops
netstat -s # protocol statistics
route get/route -n get default is the single most useful idiom for "which interface and gateway will traffic to X actually use" — it accounts for scoped routes, VPNs, and service order.
No
sscommand. macOS ships noiproute2, so there is nossand noipcommand. Usenetstat,lsof -i,nettop, orarp/ndp/routeinstead. (Some people installiproute2macvia Homebrew for muscle-memoryip, but it only wraps a subset.)
Sockets and listening ports
The ss -tlnp idiom from Linux has no direct equivalent. The macOS way is lsof (or netstat -an for a raw socket list).
# Everything with an open network socket, numeric, no DNS/port name lookups
sudo lsof -i -P -n
# The "what is listening, and which process" idiom (the macOS ss replacement)
sudo lsof -nP -iTCP -sTCP:LISTEN
# Who is using a specific port
sudo lsof -nP -iTCP:443
sudo lsof -nP -i :8080
# UDP sockets
sudo lsof -nP -iUDP
# Live per-process network bandwidth (interactive; q to quit)
nettop
nettop -P # per-process aggregate
nettop -m tcp # TCP only
# GUI equivalent: Activity Monitor → Network tab (per-process throughput),
# and the 'Open Files and Ports' inspector for a process.
Run lsof under sudo to see other users' and system sockets; without it you only see your own.
pf firewall vs the Application Firewall
macOS ships two distinct firewalls. Confusing them is why "my pf rules don't seem to do anything" tickets exist.
| pf (packet filter) | Application Firewall (ALF) | |
|---|---|---|
| Layer | Packet/port (network) | Per-application (socket) |
| Origin | OpenBSD pf, via FreeBSD | Apple's own (socketfilterfw) |
| Controlled by | pfctl, /etc/pf.conf |
System Settings → Network → Firewall, or socketfilterfw |
| Default state | Disabled out of the box | User-toggled; off by default |
| Use case | NAT, port filtering, scripted rules, Internet Sharing | "Allow/block incoming connections to this app" |
The GUI firewall in System Settings drives the ALF, not pf. pf is enabled and configured separately on the command line.
pf (pfctl)
# Enable / disable the packet filter
sudo pfctl -e # enable
sudo pfctl -d # disable
# Load a ruleset
sudo pfctl -f /etc/pf.conf
# Show loaded rules / state / info
sudo pfctl -sr # show rules
sudo pfctl -s rules # (same)
sudo pfctl -si # show info / status (incl. whether Enabled)
sudo pfctl -ss # show state table
sudo pfctl -sn # show NAT rules
# Anchors (named sub-rulesets)
sudo pfctl -s Anchors # list anchors
sudo pfctl -a com.apple/250.ApplicationFirewall -sr
Config lives in /etc/pf.conf (the main file, which anchors in others) and /etc/pf.anchors/. Apple uses anchors heavily — Internet Sharing installs NAT rules into a pf anchor (com.apple.internet-sharing), and macOS keeps the base pf.conf minimal so your edits don't fight Apple's. For persistent custom rules across reboots, the robust approach is your own anchor plus a LaunchDaemon that runs pfctl -e -f, since the default pf.conf is not guaranteed to load your additions on boot.
Application Firewall (socketfilterfw)
The ALF binary is /usr/libexec/ApplicationFirewall/socketfilterfw.
ALF=/usr/libexec/ApplicationFirewall/socketfilterfw
# Global state
sudo "$ALF" --getglobalstate
sudo "$ALF" --setglobalstate on
# Stealth mode (don't respond to probes like ICMP/closed-port)
sudo "$ALF" --getstealthmode
sudo "$ALF" --setstealthmode on
# Block all incoming except essential services
sudo "$ALF" --setblockall on
# Per-app rules
sudo "$ALF" --add /Applications/Some.app
sudo "$ALF" --setallowsigned on
sudo "$ALF" --listapps
Wi-Fi diagnostics
The
airportCLI is gone. The old workhorse —/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport— was deprecated and neutered in macOS Sonoma 14.4: it stopped returning RSSI/channel/scan data and printed only a deprecation notice ("WARNING: The airport command line tool is deprecated…"). In later releases the binary has been removed outright — it is absent on macOS 15 (Sequoia) and macOS 26, so the path above no longer exists. Do not rely on it. Use the replacements below.
# Current Apple-blessed Wi-Fi diagnostics dump (RSSI, channel, PHY, BSSID,
# security, tx rate, country code). Needs sudo for the full detail.
sudo wdutil info
# Wi-Fi hardware + current association via system_profiler (no sudo;
# verbose but reliable for SSID, channel, PHY mode, RSSI, noise)
system_profiler SPAirPortDataType
# Currently associated SSID (works without the airport tool)
networksetup -getairportnetwork en0 # confirm the device with -listallhardwareports
# Radio power
networksetup -getairportpower en0
For scanning nearby networks, there is no fully-supported CLI replacement post-Sonoma; the Wireless Diagnostics app (hold Option, click the Wi-Fi menu → "Open Wireless Diagnostics", then Window → Scan) is Apple's intended path. wdutil info and system_profiler SPAirPortDataType cover the current association details that airport -I used to give.
Diagnostics and captures
Most of the familiar tools are present and BSD-flavoured.
# Reachability
ping example.com
ping -c 4 example.com
ping6 2001:db8::1 # or: ping -6
# Path / latency per hop
traceroute example.com
traceroute6 example.com
# (no mtr by default — install via Homebrew if wanted)
# Packet capture is built in (BSD tcpdump). See the tcpdump/Wireshark sheet.
sudo tcpdump -i en0 -nn 'port 443'
sudo tcpdump -i utun3 -nn # capture on a VPN/Tailscale tunnel
# Apple's built-in network quality / responsiveness test (macOS 12+).
# Measures throughput AND latency-under-load (RPM, "responsiveness").
networkQuality
networkQuality -v # verbose, separate up/down
networkQuality -s # sequential (down then up) rather than parallel
# Direct DNS debugging (bypasses macOS scoping — see DNS section)
dig example.com +short
host example.com
Reminder: dig/host/nslookup query a server directly and bypass macOS resolver scoping. For "what the app sees", use dscacheutil -q host -a name <host> and dns-sd.
VPN, utun, and Tailscale
VPN and mesh-VPN tunnels surface as utun* interfaces. Tailscale (utunN), WireGuard, and the built-in IKEv2/IPsec client all allocate one.
# List tunnel interfaces and their addresses
ifconfig | grep -A4 utun
# Which interface/route a destination resolves to — does it go down the tunnel?
route -n get default
route get 100.64.0.1 # a Tailscale CGNAT address, say
# Is the VPN's DNS resolver scoped in? (look for a utun if_index)
scutil --dns | grep -A6 utun
# Capture on the tunnel
sudo tcpdump -i utun3 -nn
The two questions a utun interface usually raises — "is my traffic actually going through it?" and "is split DNS pointing the right names at it?" — are answered by route -n get default / route get <dst> and scutil --dns respectively, not by ifconfig alone.
Quick Reference
Tool mapping (Linux → macOS)
| Task | Linux | macOS |
|---|---|---|
| Show interfaces/addresses | ip addr |
ifconfig |
| Show routes | ip route |
netstat -rn, route -n get default |
| Add a (temporary) route | ip route add |
route add (not persistent) |
| Listening sockets | ss -tlnp |
sudo lsof -nP -iTCP -sTCP:LISTEN |
| All sockets | ss -an |
netstat -an |
| Neighbour cache (ARP) | ip neigh |
arp -a, ndp -an (v6) |
| Set static IP (persistent) | nmcli / netplan |
networksetup -setmanual |
| Set DNS (persistent) | nmcli / resolvectl |
networksetup -setdnsservers |
| Effective resolver view | resolvectl status |
scutil --dns |
| Flush DNS cache | resolvectl flush-caches |
dscacheutil -flushcache; killall -HUP mDNSResponder |
| Per-process bandwidth | nethogs |
nettop |
| Firewall | nft/iptables |
pfctl (packet) / socketfilterfw (per-app) |
Most-used commands
| Command | Purpose |
|---|---|
networksetup -listallhardwareports |
Map en* → Wi-Fi/Ethernet on this Mac |
networksetup -getinfo "Wi-Fi" |
IP/mask/router/MAC for a service |
sudo networksetup -setmanual "Ethernet" IP MASK ROUTER |
Persistent static IP |
sudo networksetup -setdnsservers "Wi-Fi" 1.1.1.1 |
Persistent DNS |
scutil --nwi |
Reachability / primary interfaces |
scutil --dns |
The authoritative (scoped) resolver view |
scutil --get LocalHostName |
The .local Bonjour name |
dscacheutil -q host -a name HOST |
Resolve as the app would (scoped) |
sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder |
Flush DNS cache |
route -n get default |
Resolve the active default route/interface |
sudo lsof -nP -iTCP -sTCP:LISTEN |
What is listening (no ss) |
nettop |
Live per-process bandwidth |
sudo pfctl -si / -sr |
pf status / rules |
sudo wdutil info |
Current Wi-Fi RSSI/channel/PHY |
networkQuality |
Throughput + responsiveness test |
Common Issues and Solutions
| Issue | Cause | Solution |
|---|---|---|
ifconfig/route change reverted after a few seconds or a reboot |
configd re-applies the service config from the dynamic store; manual BSD changes are runtime-only |
Make the change persistent with networksetup/scutil (or the GUI). Use ifconfig/route only for throwaway tests. |
dig resolves but the app/browser can't (or resolves differently) |
macOS DNS is scoped/split; dig bypasses scoping and talks to a server directly |
Inspect with scutil --dns, reproduce the app's view with dscacheutil -q host -a name HOST and dns-sd. Check VPN/utun resolver ordering and search domains. |
Editing /etc/resolv.conf has no effect |
It is generated and only reflects the primary resolver | Set DNS via sudo networksetup -setdnsservers "<service>" …; verify with scutil --dns. |
| Stale DNS after a server/zone change | mDNSResponder cache |
sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder (run both halves). |
airport command prints a deprecation warning / no data, or the binary is missing entirely |
Neutered in macOS Sonoma 14.4; removed outright in macOS 15 (Sequoia)+ | Use sudo wdutil info and system_profiler SPAirPortDataType; use Wireless Diagnostics for scans. |
ss: command not found |
No iproute2 on macOS |
Use sudo lsof -nP -iTCP -sTCP:LISTEN, netstat -an, or nettop. |
| pf rules "don't apply" | pf is disabled by default, or you're editing the wrong firewall | sudo pfctl -si to check Enabled; sudo pfctl -e -f /etc/pf.conf. Remember the GUI firewall is the ALF (socketfilterfw), not pf. |
| GUI firewall on but ports still open | The ALF is per-app, not per-port; it doesn't block outbound or non-app listeners the way pf does | Use pf for packet/port filtering; use the ALF for "allow/block this app's incoming connections". |
| Can't set a static IP that survives reboot | Used ifconfig/route |
sudo networksetup -setmanual "<service>" IP MASK ROUTER, or System Settings → Network → service → Details → TCP/IP → Manually. |
Wrong interface assumed (en0 isn't Ethernet) |
Interface names are probe-order, not role-based | Resolve with networksetup -listallhardwareports; never hard-code en0 = Ethernet. |
sudo hostname foo doesn't persist |
BSD hostname sets a transient value |
sudo scutil --set HostName foo (and consider ComputerName/LocalHostName). |
| VPN up but traffic not using it | Routing/service-order or scoped DNS mismatch | route -n get default and route get <dst> for routing; scutil --dns for which resolver a name uses. |
Permission denied / empty lsof output |
Need elevated privileges to see other users' sockets | Run with sudo. |
Related Topics
- tcpdump/Wireshark — packet capture on
en*/utun*interfaces (built-intcpdump) - Tailscale / WireGuard — the
utuntunnels you'll be inspecting withroute getandscutil --dns - DNS fundamentals — scoped resolvers, search domains, and what
scutil --dnsis actually showing - pf firewall — deeper
pfctl/anchor configuration shared with FreeBSD/OpenBSD - Linux network tools (
ip/ss/nmcli) — the counterpart sheet this one maps against - Bonjour / mDNS / zeroconf —
dns-sd, service discovery, and.localnaming