Skip to content

Commit 251790f

Browse files
authored
Merge pull request #655 from stgraber/main
Allow running in restricted MAC environments
2 parents 84c3656 + e7c29dc commit 251790f

5 files changed

Lines changed: 78 additions & 2 deletions

File tree

incus-osd/api/system_network.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ type SystemNetworkInterface struct {
4646
Routes []SystemNetworkRoute `json:"routes,omitempty" yaml:"routes,omitempty"`
4747
Hwaddr string `json:"hwaddr" yaml:"hwaddr"`
4848
Roles []string `json:"roles,omitempty" yaml:"roles,omitempty"`
49-
LLDP bool `json:"lldp" yaml:"lldp"`
49+
LLDP bool `json:"lldp,omitempty" yaml:"lldp,omitempty"`
50+
StrictHwaddr bool `json:"strict_hwaddr,omitempty" yaml:"strict_hwaddr,omitempty"`
5051
}
5152

5253
// SystemNetworkBond contains information about a network bond.
@@ -61,7 +62,7 @@ type SystemNetworkBond struct {
6162
Hwaddr string `json:"hwaddr,omitempty" yaml:"hwaddr,omitempty"`
6263
Members []string `json:"members,omitempty" yaml:"members,omitempty"`
6364
Roles []string `json:"roles,omitempty" yaml:"roles,omitempty"`
64-
LLDP bool `json:"lldp" yaml:"lldp"`
65+
LLDP bool `json:"lldp,omitempty" yaml:"lldp,omitempty"`
6566
}
6667

6768
// SystemNetworkVLAN contains information about a network vlan.

incus-osd/cmd/incus-osd/main.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/lxc/incus-os/incus-osd/internal/applications"
2222
"github.com/lxc/incus-os/incus-osd/internal/install"
2323
"github.com/lxc/incus-os/incus-osd/internal/keyring"
24+
"github.com/lxc/incus-os/incus-osd/internal/nftables"
2425
"github.com/lxc/incus-os/incus-osd/internal/providers"
2526
"github.com/lxc/incus-os/incus-osd/internal/recovery"
2627
"github.com/lxc/incus-os/incus-osd/internal/rest"
@@ -359,6 +360,11 @@ func startup(ctx context.Context, s *state.State, t *tui.TUI) error { //nolint:r
359360
// Perform network configuration.
360361
slog.InfoContext(ctx, "Bringing up the network")
361362

363+
err = nftables.ApplyHwaddrFilters(ctx, s.System.Network.Config)
364+
if err != nil {
365+
return err
366+
}
367+
362368
err = systemd.ApplyNetworkConfiguration(ctx, s, s.System.Network.Config, 30*time.Second, s.OS.SuccessfulBoot, providers.Refresh, delayInitialUpdateCheck)
363369
if err != nil {
364370
return err

incus-osd/internal/nftables/doc.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Package nftables offers functions to manage the nftables firewall.
2+
package nftables

incus-osd/internal/nftables/nft.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package nftables
2+
3+
import (
4+
"context"
5+
"strings"
6+
7+
"github.com/lxc/incus/v6/shared/subprocess"
8+
9+
"github.com/lxc/incus-os/incus-osd/api"
10+
)
11+
12+
// SetupChains creates the initial system-wide chains.
13+
func SetupChains(ctx context.Context) error {
14+
// Ensure we have a bridge table.
15+
_, err := subprocess.RunCommandContext(ctx, "nft", "add", "table", "bridge", "incus-osd")
16+
if err != nil {
17+
return err
18+
}
19+
20+
// Ensure we have a MAC filtering chain.
21+
_, err = subprocess.RunCommandContext(ctx, "nft", "add", "chain", "bridge", "incus-osd", "mac-filters", "{ type filter hook output priority 0 ; policy accept ; }")
22+
if err != nil {
23+
return err
24+
}
25+
26+
return nil
27+
}
28+
29+
// ApplyHwaddrFilters ensures that all interfaces with the StrictHwaddr flag set get a suitable MAC filter in place.
30+
func ApplyHwaddrFilters(ctx context.Context, networkCfg *api.SystemNetworkConfig) error {
31+
// Make sure we have the expected chains.
32+
err := SetupChains(ctx)
33+
if err != nil {
34+
return err
35+
}
36+
37+
// Empty the chain.
38+
_, err = subprocess.RunCommandContext(ctx, "nft", "flush", "chain", "bridge", "incus-osd", "mac-filters")
39+
if err != nil {
40+
return err
41+
}
42+
43+
// Apply the filters.
44+
for _, iface := range networkCfg.Interfaces {
45+
if !iface.StrictHwaddr {
46+
continue
47+
}
48+
49+
underlyingDevice := "_p" + strings.ToLower(strings.ReplaceAll(iface.Hwaddr, ":", ""))
50+
51+
_, err = subprocess.RunCommandContext(ctx, "nft", "add", "rule", "bridge", "incus-osd", "mac-filters", "oif", underlyingDevice, "ether", "saddr", "!=", iface.Hwaddr, "drop")
52+
if err != nil {
53+
return err
54+
}
55+
}
56+
57+
return nil
58+
}

incus-osd/internal/rest/api_system_network.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"time"
99

1010
"github.com/lxc/incus-os/incus-osd/api"
11+
"github.com/lxc/incus-os/incus-osd/internal/nftables"
1112
"github.com/lxc/incus-os/incus-osd/internal/providers"
1213
"github.com/lxc/incus-os/incus-osd/internal/rest/response"
1314
"github.com/lxc/incus-os/incus-osd/internal/seed"
@@ -124,6 +125,14 @@ func (s *Server) apiSystemNetwork(w http.ResponseWriter, r *http.Request) {
124125

125126
slog.InfoContext(r.Context(), "Applying new network configuration")
126127

128+
err = nftables.ApplyHwaddrFilters(r.Context(), newConfig.Config)
129+
if err != nil {
130+
slog.ErrorContext(r.Context(), "Failed to update network configuration: "+err.Error())
131+
_ = response.InternalError(err).Render(w)
132+
133+
return
134+
}
135+
127136
err = systemd.ApplyNetworkConfiguration(r.Context(), s.state, newConfig.Config, 30*time.Second, false, providers.Refresh, false)
128137
if err != nil {
129138
slog.ErrorContext(r.Context(), "Failed to update network configuration: "+err.Error())

0 commit comments

Comments
 (0)