A found tunnel carries its MTU to the mesh #28

Merged
jschoubben merged 1 commits from feat/a-taken-tunnel-carries-its-mtu into main 2026-09-26 20:40:09 +00:00
4 changed files with 37 additions and 1 deletions
Showing only changes of commit 8e2a1e762d - Show all commits
+1 -1
View File
@@ -910,7 +910,7 @@ func rekeyOnto(mine identity.Identity, found tunnel.Found) (identity.Identity, l
// carried is a found tunnel as it is presented to the mesh: everything but its private key. // carried is a found tunnel as it is presented to the mesh: everything but its private key.
func carried(t tunnel.Found) *link.Tunnel { func carried(t tunnel.Found) *link.Tunnel {
out := &link.Tunnel{Interface: t.Interface, Unit: t.Unit, Config: t.Config, Port: t.Port, out := &link.Tunnel{Interface: t.Interface, Unit: t.Unit, Config: t.Config, Port: t.Port,
Address: t.Address, Range: t.Range, PublicKey: t.PublicKey} Address: t.Address, Range: t.Range, MTU: t.MTU, PublicKey: t.PublicKey}
for _, p := range t.Peers { for _, p := range t.Peers {
out.Peers = append(out.Peers, link.TunnelPeer{PublicKey: p.PublicKey, Address: p.Address}) out.Peers = append(out.Peers, link.TunnelPeer{PublicKey: p.PublicKey, Address: p.Address})
} }
+1
View File
@@ -68,6 +68,7 @@ type Tunnel struct {
Port int `json:"port"` Port int `json:"port"`
Address string `json:"address"` Address string `json:"address"`
Range string `json:"range"` Range string `json:"range"`
MTU int `json:"mtu,omitempty"`
PublicKey string `json:"public_key"` PublicKey string `json:"public_key"`
Peers []TunnelPeer `json:"peers,omitempty"` Peers []TunnelPeer `json:"peers,omitempty"`
} }
+11
View File
@@ -44,6 +44,11 @@ type Found struct {
Port int `json:"port"` Port int `json:"port"`
Address string `json:"address"` Address string `json:"address"`
Range string `json:"range"` Range string `json:"range"`
// MTU is the interface's, when the found config set one. Kept because a tuned tunnel (a path
// that needs 1380, say) breaks silently if the mesh's interface comes up at the 1420 default:
// no ping fails, but TLS handshakes stall and transfers hang (novox/hq: a taken tunnel carries
// its MTU). Zero when the config named none, and the mesh sets no MTU line then.
MTU int `json:"mtu,omitempty"`
// PublicKey is what every peer knows this tunnel by — derived here from the private key, so // PublicKey is what every peer knows this tunnel by — derived here from the private key, so
// it is the key the file actually holds and not a comment beside it. // it is the key the file actually holds and not a comment beside it.
PublicKey string `json:"public_key"` PublicKey string `json:"public_key"`
@@ -209,6 +214,12 @@ func Parse(raw []byte) (Found, error) {
return Found{}, fmt.Errorf("ListenPort %q is not a port", value) return Found{}, fmt.Errorf("ListenPort %q is not a port", value)
} }
f.Port = port f.Port = port
case "mtu":
mtu, err := strconv.Atoi(value)
if err != nil || mtu < 576 || mtu > 65535 {
return Found{}, fmt.Errorf("MTU %q is not a plausible MTU", value)
}
f.MTU = mtu
case "address": case "address":
// The first address is the interface's; a second family would be a second // The first address is the interface's; a second family would be a second
// tunnel's worth of addressing, which this does not carry. // tunnel's worth of addressing, which this does not carry.
+24
View File
@@ -170,3 +170,27 @@ func TestNoneUpIsAnOrdinaryAnswerAndSeveralIsAQuestion(t *testing.T) {
t.Errorf("naming a tunnel that is not up was not refused: %v", err) t.Errorf("naming a tunnel that is not up was not refused: %v", err)
} }
} }
func TestAFoundTunnelReadsItsMTU(t *testing.T) {
// A tuned path sets MTU in [Interface]; the mesh must carry it or the tunnel regresses to the
// default silently (novox/hq: a taken tunnel carries its MTU).
private, public := aKey(t)
withMTU := "# tuned\n[Interface]\nPrivateKey = " + private +
"\nListenPort = 51820\nAddress = 10.10.0.3/24\nMTU = 1380\n" +
"[Peer]\nPublicKey = " + public + "\nAllowedIPs = 10.10.0.1/32\n"
f, err := Parse([]byte(withMTU))
if err != nil {
t.Fatal(err)
}
if f.MTU != 1380 {
t.Fatalf("MTU 1380 was not read; got %d", f.MTU)
}
// And a config with none leaves MTU zero, so the mesh writes no MTU line.
f2, err := Parse([]byte(aConfig(private, public)))
if err != nil {
t.Fatal(err)
}
if f2.MTU != 0 {
t.Fatalf("a config with no MTU must leave it zero; got %d", f2.MTU)
}
}