netbirdio/netbird · error
add jump to MSS clamp chain: %w
Error message
add jump to MSS clamp chain: %w
What it means
addMSSClampingRules() inserts `-j NETBIRD-RT-MSSCLAMP` at position 1 of the mangle FORWARD chain so forwarded TCP SYNs get clamped to the interface MTU. A failure here is only logged by createContainers() (log.Errorf), not propagated, so the agent starts but forwarded TCP over the overlay may suffer fragmentation/blackholes on links with smaller MTUs.
Source
Thrown at client/firewall/iptables/router_linux.go:575
r.rules["static-nat-return"] = rule2
return nil
}
// addMSSClampingRules adds MSS clamping rules to prevent fragmentation for forwarded traffic.
func (r *router) addMSSClampingRules() error {
overhead := uint16(ipv4TCPHeaderSize)
if r.v6 {
overhead = ipv6TCPHeaderSize
}
mss := r.mtu - overhead
// Add jump rule from FORWARD chain in mangle table to our custom chain
jumpRule := []string{
"-j", chainRTMSSCLAMP,
}
if err := r.iptablesClient.Insert(tableMangle, chainFORWARD, 1, jumpRule...); err != nil {
return fmt.Errorf("add jump to MSS clamp chain: %w", err)
}
r.rules[jumpMSSClamp] = jumpRule
ruleOut := []string{
"-o", r.wgIface.Name(),
"-p", "tcp",
"--tcp-flags", "SYN,RST", "SYN",
"-j", "TCPMSS",
"--set-mss", fmt.Sprintf("%d", mss),
}
if err := r.iptablesClient.Append(tableMangle, chainRTMSSCLAMP, ruleOut...); err != nil {
return fmt.Errorf("add outbound MSS clamp rule: %w", err)
}
r.rules["mss-clamp-out"] = ruleOut
return nil
}
View on GitHub (pinned to 93e97f4bf1)
Solutions
- Grep the agent log for 'failed to add MSS clamping rules' after `netbird up` (the error is not returned to the CLI)
- Run `sudo iptables -t mangle -I FORWARD 1 -j NETBIRD-RT-MSSCLAMP` to see the real error
- `modprobe iptable_mangle`
- Reduce churn on the FORWARD chain (stop firewalld rewrites) or restart the agent after firewall changes
- Verify afterwards: `sudo iptables -t mangle -S FORWARD | head` should show the NETBIRD-RT-MSSCLAMP jump
Example fix
// before
if err := r.iptablesClient.Insert(tableMangle, chainFORWARD, 1, jumpRule...); err != nil {
return fmt.Errorf("add jump to MSS clamp chain: %w", err)
}
// after: tolerate an identical jump inserted by a previous run
exists, _ := r.iptablesClient.Exists(tableMangle, chainFORWARD, jumpRule...)
if !exists {
if err := r.iptablesClient.Insert(tableMangle, chainFORWARD, 1, jumpRule...); err != nil {
return fmt.Errorf("add jump to MSS clamp chain: %w", err)
}
}
r.rules[jumpMSSClamp] = jumpRule Defensive patterns
Strategy: validation
Validate before calling
func forwardChainProgrammable(ipt *iptables.IPTables) bool {
probe := []string{"-j", "RETURN"}
if err := ipt.Insert("mangle", "FORWARD", 1, probe...); err != nil {
return false
}
_ = ipt.DeleteIfExists("mangle", "FORWARD", probe...)
return true
} Try / catch
This failure is log-only by design; catch it at the ops layer by grepping for 'failed to add MSS clamping rules' and re-running addMSSClampingRules on the next reconciliation instead of crashing.
Prevention
- modprobe iptable_mangle on routed peers
- Prevent firewalld/ufw from wholesale-replacing FORWARD
- Verify `iptables -t mangle -S FORWARD` contains the NETBIRD-RT-MSSCLAMP jump after first start
When it happens
Trigger: `iptables -t mangle -I FORWARD 1 -j NETBIRD-RT-MSSCLAMP` failing when iptable_mangle is not loaded, CAP_NET_ADMIN is missing, another tool rewrote FORWARD concurrently making the insert race, or the xtables lock is held.
Common situations: Stripped container hosts without the mangle table; hosts running firewalld that replaces the FORWARD chain wholesale; MTU-sensitive links (PPP, tunnels) where clamping mattered and silent failure shows as stalled TCP handshakes for routed traffic.
Related errors
- add mangle prerouting rule: %w
- add mangle postrouting rule: %w
- remove mangle prerouting rule: %w
- remove mangle postrouting rule: %w
- add outbound MSS clamp rule: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/f3ccb8c29545df1f.
Report an issue: GitHub.