raw Software

A Mac can route traffic from a local Ethernet network through an upstream Wi-Fi connection without enabling the graphical Internet Sharing service. This is useful when the downstream network needs static addresses, a custom DHCP server, or firewall rules that remain under direct control.

The manual setup below provides IPv4 routing and NAT only. It does not start DHCP or DNS services. The examples use a Wi-Fi uplink and a wired downstream interface, but the same method works with other interface combinations.

Identify the Network Interfaces

Do not assume that Wi-Fi is always en0 or that USB Ethernet receives a particular number. macOS assigns interface names according to the hardware present on that Mac. List the hardware ports and inspect the current default route:

networksetup -listallhardwareports
route -n get default | grep 'interface:'

The remaining commands use this network plan:

Role Example
Internet-facing interface en0
Local-network interface en5
Local subnet 192.168.3.0/24
Mac router address 192.168.3.1

Replace both interface names before running the privileged commands. The upstream interface should already have working internet access.

Configure the Downstream Interface

Assign the router address to the local interface. A /24 network corresponds to the netmask 255.255.255.0:

sudo ifconfig en5 inet 192.168.3.1 netmask 255.255.255.0 up
ifconfig en5

This address is temporary and may be replaced by Network settings or after a restart. That is useful while testing because it does not permanently rewrite the network service. For a lasting address, configure the corresponding service under System Settings > Network.

Enable IPv4 Forwarding

Allow the kernel to forward IPv4 packets between interfaces:

sudo sysctl -w net.inet.ip.forwarding=1
sysctl net.inet.ip.forwarding

The value should be 1. It returns to the system default after a restart, so a manually managed router must reapply it during startup.

Create a Scoped PF Ruleset

macOS uses PF for packet filtering and network address translation. Its default configuration exposes wildcard anchors below com.apple/*. Loading a dedicated child anchor keeps these rules separate from rules installed by macOS services and avoids flushing the main ruleset.

Create /etc/pf.anchors/raw.internet-sharing with the actual interface names:

upstream = "en0"
downstream = "en5"
lan = "192.168.3.0/24"

nat on $upstream inet from $lan to any -> ($upstream)
pass in quick on $downstream inet from $lan to any keep state
pass out quick on $upstream inet from $lan to any keep state

The NAT rule rewrites packets from the private subnet to the current address of the upstream interface. The two pass rules admit forwarding only along the intended path. Existing installations with a stricter PF policy may need additional rules tailored to that policy.

Validate the file before loading it:

sudo pfctl -vnf /etc/pf.anchors/raw.internet-sharing

A syntax check produces no fatal error and does not alter the active rules. Load the rules into the child anchor, then enable PF using its reference-counted interface:

sudo pfctl -a com.apple/raw.internet-sharing -f /etc/pf.anchors/raw.internet-sharing
sudo pfctl -E

Keep the token printed by pfctl -E. It allows this setup to release its own PF reference later without disabling PF for another macOS service. Do not use pfctl -d as a routine setup step.

Inspect the loaded NAT and filter rules with:

sudo pfctl -a com.apple/raw.internet-sharing -sn
sudo pfctl -a com.apple/raw.internet-sharing -sr

Configure a Linux Client

A client needs an address in the same subnet, the Mac as its default gateway, and a DNS resolver. The following commands configure a temporary address on a Linux interface named eth0:

sudo ip addr replace 192.168.3.3/24 dev eth0
sudo ip link set eth0 up
sudo ip route replace default via 192.168.3.1

Current Raspberry Pi OS releases normally use NetworkManager. For a persistent profile, first find its connection name with nmcli connection show, then adapt this example:

sudo nmcli connection modify "Wired connection 1" \
	ipv4.method manual \
	ipv4.addresses 192.168.3.3/24 \
	ipv4.gateway 192.168.3.1 \
	ipv4.dns "1.1.1.1 9.9.9.9"
sudo nmcli connection up "Wired connection 1"

Older distributions may use a different network manager. Avoid editing /etc/network/interfaces unless that file is actually the active configuration source on the client.

Test Each Layer

Test local reachability, routed IP traffic, and DNS separately from the Linux client:

ping -c 3 192.168.3.1
ping -c 3 1.1.1.1
getent hosts raw.org

If the first test fails, check the cable, interface names, addresses, and subnet masks. If only the second test fails, inspect forwarding and PF. If the IP test works but the hostname lookup fails, correct the client's DNS configuration.

Packet counters and a short capture on the Mac can confirm whether traffic enters and leaves the expected interfaces:

sudo pfctl -a com.apple/raw.internet-sharing -vvs rules
sudo tcpdump -ni en5
sudo tcpdump -ni en0

Remove the Manual Setup

Flush only the dedicated anchor, release the token returned by pfctl -E, and disable forwarding:

sudo pfctl -a com.apple/raw.internet-sharing -F all
sudo pfctl -X TOKEN_FROM_PFCTL_E
sudo sysctl -w net.inet.ip.forwarding=0

Restore the downstream network service through System Settings or with networksetup -setdhcp and its exact service name. Do not disable PF globally: macOS services may still hold and depend on their own PF references.

Apple's graphical Internet Sharing feature manages its own addressing, DHCP, and PF state. Use either that feature or the manual ruleset, not both at the same time.