Skip to content

Commit

Permalink
feat: make firewalls unique to potential each of potential multiple m…
Browse files Browse the repository at this point in the history
…eshes
  • Loading branch information
tinyzimmer committed Aug 3, 2023
1 parent 8c9d7e3 commit 93237d0
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 26 deletions.
7 changes: 0 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
Expand Down Expand Up @@ -110,7 +109,6 @@ github.com/go-ldap/ldap/v3 v3.4.5/go.mod h1:bMGIq3AGbytbaMwf8wdv5Phdxz0FWHTIYMSz
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw=
github.com/go-ping/ping v1.1.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
Expand Down Expand Up @@ -257,7 +255,6 @@ github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
Expand Down Expand Up @@ -322,7 +319,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
Expand Down Expand Up @@ -512,8 +508,6 @@ github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYp
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/webmeshproj/api v0.2.2-0.20230803165352-8e06d34c8122 h1:zAv/S0u42C0jyl4HLF0d1/HBzdogvxAQQYCbYDXHObQ=
github.com/webmeshproj/api v0.2.2-0.20230803165352-8e06d34c8122/go.mod h1:ymJL82yEGc/xw880DAb65pBJShkBqkKOl3sCOBq7NVk=
github.com/webmeshproj/api v0.2.2-0.20230803221209-46d26bee6d1a h1:SIJnXO5h2JHJVpyZWOGlkJkyQ11bK2ZQBYVqOHmhdaI=
github.com/webmeshproj/api v0.2.2-0.20230803221209-46d26bee6d1a/go.mod h1:ymJL82yEGc/xw880DAb65pBJShkBqkKOl3sCOBq7NVk=
github.com/webmeshproj/raft-badger v0.0.0-20230728220038-2f75bbd4d5ed h1:ebSdqO+ryXs1OLIwND1w5LZPtIpUUd5srVz0wjmIyEY=
Expand Down Expand Up @@ -811,7 +805,6 @@ honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=
nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k=
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
pault.ag/go/modprobe v0.1.2 h1:bblunaPhqpTxGDJ5TVFW/4gheohBPleF2dIV6j6sWkI=
Expand Down
4 changes: 4 additions & 0 deletions pkg/net/system/firewall/firewall.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ const (

// Options are options for configuring a firewall.
type Options struct {
// ID is used to uniquely identify the firewall. It can be empty,
// in which case it is assumed only a single mesh connection will
// be using the firewall.
ID string
// DefaultPolicy is the default policy for the firewall.
DefaultPolicy Policy
// WireguardPort is the port to allow for wireguard traffic.
Expand Down
23 changes: 18 additions & 5 deletions pkg/net/system/firewall/firewall_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ const anchorFile = "/etc/pf.anchors/com.webmesh"

func newFirewall(opts *Options) (Firewall, error) {
// Make sure we can touch the anchor file
err := os.WriteFile(anchorFile, []byte{}, 0644)
afile := anchorFile
if opts.ID != "" {
afile = fmt.Sprintf("%s.%s", anchorFile, opts.ID)
}
err := os.WriteFile(afile, []byte{}, 0644)
if err != nil {
return nil, fmt.Errorf("touch anchor file: %w", err)
}
Expand All @@ -39,20 +43,25 @@ func newFirewall(opts *Options) (Firewall, error) {
if strings.Contains(string(out), "pf already enabled") {
return &pfctlFirewall{
enabledAtStart: true,
anchorFile: afile,
}, nil
}
return nil, fmt.Errorf("enable pfctl: %w", err)
}
return &pfctlFirewall{enabledAtStart: false}, nil
return &pfctlFirewall{
enabledAtStart: false,
anchorFile: afile,
}, nil
}

type pfctlFirewall struct {
enabledAtStart bool
anchorFile string
}

// AddWireguardForwarding should configure the firewall to allow forwarding traffic on the wireguard interface.
func (pf *pfctlFirewall) AddWireguardForwarding(ctx context.Context, ifaceName string) error {
f, err := os.OpenFile(anchorFile, os.O_APPEND|os.O_WRONLY, 0644)
f, err := os.OpenFile(pf.anchorFile, os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return fmt.Errorf("open anchor file: %w", err)
}
Expand All @@ -68,7 +77,7 @@ func (pf *pfctlFirewall) AddWireguardForwarding(ctx context.Context, ifaceName s

// AddMasquerade should configure the firewall to masquerade outbound traffic on the wireguard interface.
func (pf *pfctlFirewall) AddMasquerade(ctx context.Context, ifaceName string) error {
f, err := os.OpenFile(anchorFile, os.O_APPEND|os.O_WRONLY, 0644)
f, err := os.OpenFile(pf.anchorFile, os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return fmt.Errorf("open anchor file: %w", err)
}
Expand All @@ -85,7 +94,7 @@ func (pf *pfctlFirewall) AddMasquerade(ctx context.Context, ifaceName string) er
// Clear should clear any changes made to the firewall.
func (pf *pfctlFirewall) Clear(ctx context.Context) error {
// Clear the anchor file
err := os.WriteFile(anchorFile, []byte{}, 0644)
err := os.WriteFile(pf.anchorFile, []byte{}, 0644)
if err != nil {
return fmt.Errorf("clear anchor file: %w", err)
}
Expand All @@ -100,6 +109,10 @@ func (pf *pfctlFirewall) Close(ctx context.Context) error {
if err != nil {
return fmt.Errorf("clear: %w", err)
}
err = os.Remove(pf.anchorFile)
if err != nil {
return fmt.Errorf("remove anchor file: %w", err)
}
// If we started with pf disabled, re-disable it
if !pf.enabledAtStart {
return util.Exec(ctx, "pfctl", "-d")
Expand Down
24 changes: 19 additions & 5 deletions pkg/net/system/firewall/firewall_freebsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ const anchorFile = "/etc/pf.anchors/com.webmesh"

func newFirewall(opts *Options) (Firewall, error) {
// Make sure we can touch the anchor file
err := os.WriteFile(anchorFile, []byte{}, 0644)
afile := anchorFile
if opts.ID != "" {
afile = fmt.Sprintf("%s.%s", anchorFile, opts.ID)
}
err := os.WriteFile(afile, []byte{}, 0644)
if err != nil {
return nil, fmt.Errorf("touch anchor file: %w", err)
}
Expand All @@ -39,20 +43,25 @@ func newFirewall(opts *Options) (Firewall, error) {
if strings.Contains(string(out), "pf already enabled") {
return &pfctlFirewall{
enabledAtStart: true,
anchorFile: afile,
}, nil
}
return nil, fmt.Errorf("enable pfctl: %w", err)
}
return &pfctlFirewall{enabledAtStart: false}, nil
return &pfctlFirewall{
enabledAtStart: false,
anchorFile: afile,
}, nil
}

type pfctlFirewall struct {
enabledAtStart bool
anchorFile string
}

// AddWireguardForwarding should configure the firewall to allow forwarding traffic on the wireguard interface.
func (pf *pfctlFirewall) AddWireguardForwarding(ctx context.Context, ifaceName string) error {
f, err := os.OpenFile(anchorFile, os.O_APPEND|os.O_WRONLY, 0644)
f, err := os.OpenFile(pf.anchorFile, os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return fmt.Errorf("open anchor file: %w", err)
}
Expand All @@ -68,7 +77,7 @@ func (pf *pfctlFirewall) AddWireguardForwarding(ctx context.Context, ifaceName s

// AddMasquerade should configure the firewall to masquerade outbound traffic on the wireguard interface.
func (pf *pfctlFirewall) AddMasquerade(ctx context.Context, ifaceName string) error {
f, err := os.OpenFile(anchorFile, os.O_APPEND|os.O_WRONLY, 0644)
f, err := os.OpenFile(pf.anchorFile, os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return fmt.Errorf("open anchor file: %w", err)
}
Expand All @@ -85,7 +94,7 @@ func (pf *pfctlFirewall) AddMasquerade(ctx context.Context, ifaceName string) er
// Clear should clear any changes made to the firewall.
func (pf *pfctlFirewall) Clear(ctx context.Context) error {
// Clear the anchor file
err := os.WriteFile(anchorFile, []byte{}, 0644)
err := os.WriteFile(pf.anchorFile, []byte{}, 0644)
if err != nil {
return fmt.Errorf("clear anchor file: %w", err)
}
Expand All @@ -100,6 +109,11 @@ func (pf *pfctlFirewall) Close(ctx context.Context) error {
if err != nil {
return fmt.Errorf("clear: %w", err)
}
// Delete the anchor file
err = os.Remove(pf.anchorFile)
if err != nil {
return fmt.Errorf("remove anchor file: %w", err)
}
// If we started with pf disabled, re-disable it
if !pf.enabledAtStart {
return util.Exec(ctx, "pfctl", "-d")
Expand Down
8 changes: 8 additions & 0 deletions pkg/net/system/firewall/firewall_iptables_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ import (
"golang.org/x/exp/slog"
)

// newIPTablesFirewall returns a new iptables firewall manager. This firewall manager
// is technically not safe for use with multiple interfaces. The Close method may restore
// rules from another interface. But documentation should push people to use nftables instead.
// This is just a fallback.
func newIPTablesFirewall(_ *Options) (Firewall, error) {
fw := &iptablesFirewall{
log: slog.Default().With(slog.String("component", "iptables-firewall")),
Expand Down Expand Up @@ -62,6 +66,10 @@ func (fw *iptablesFirewall) Clear(ctx context.Context) error {
}
// Restore initial rules
for _, rule := range fw.initialRules {
if strings.HasPrefix(rule, "#") {
// Comment, skip
continue
}
err = fw.exec(ctx, strings.Fields(rule)...)
if err != nil {
return err
Expand Down
23 changes: 16 additions & 7 deletions pkg/net/system/firewall/firewall_nftables_init_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ const (
inetForwardChain = "forward"
)

func (fw *firewall) initialize() error {
func (fw *firewall) initialize(opts *Options) error {
var err error
for _, f := range []func() error{
fw.initTables,
func() error { return fw.initTables(opts) },
fw.initChains,
fw.initInputChain,
} {
Expand All @@ -56,9 +56,18 @@ func (fw *firewall) initialize() error {
return fw.conn.Flush()
}

func (fw *firewall) initTables() error {
func (fw *firewall) initTables(opts *Options) error {
filterTable := inetFilterTable
natTable := inetNatTable
rawTable := inetRawTable
if opts.ID != "" {
filterTable = fmt.Sprintf("%s_%s", inetFilterTable, opts.ID)
natTable = fmt.Sprintf("%s_%s", inetNatTable, opts.ID)
rawTable = fmt.Sprintf("%s_%s", inetRawTable, opts.ID)
}
tablesNames := []string{filterTable, natTable, rawTable}
fw.ti = nftableslib.InitNFTables(fw.conn).Tables()
for _, table := range []string{inetFilterTable, inetNatTable, inetRawTable} {
for _, table := range tablesNames {
_, err := fw.ti.Table(table, nftables.TableFamilyINet)
if err == nil {
// Table exists, flush it
Expand All @@ -70,15 +79,15 @@ func (fw *firewall) initTables() error {
return fmt.Errorf("failed to create table: %w", err)
}
}
filterchains, err := fw.ti.Table(inetFilterTable, nftables.TableFamilyINet)
filterchains, err := fw.ti.Table(filterTable, nftables.TableFamilyINet)
if err != nil {
return fmt.Errorf("failed to load filter table: %w", err)
}
natchains, err := fw.ti.Table(inetNatTable, nftables.TableFamilyINet)
natchains, err := fw.ti.Table(natTable, nftables.TableFamilyINet)
if err != nil {
return fmt.Errorf("failed to load NAT table: %w", err)
}
rawchains, err := fw.ti.Table(inetRawTable, nftables.TableFamilyINet)
rawchains, err := fw.ti.Table(rawTable, nftables.TableFamilyINet)
if err != nil {
return fmt.Errorf("failed to load raw table: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/net/system/firewall/firewall_nftables_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func newFirewall(opts *Options) (Firewall, error) {
conn: conn,
dnats: make(map[uint64][]byte),
}
err := fw.initialize()
err := fw.initialize(opts)
if err != nil {
if strings.Contains(err.Error(), "not supported") || strings.Contains(err.Error(), "no such file") {
// Try to fallback to iptables
Expand Down
8 changes: 7 additions & 1 deletion pkg/net/system/firewall/firewall_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,14 @@ func (wf *winFirewall) AddWireguardForwarding(ctx context.Context, ifaceName str

// AddMasquerade should configure the firewall to masquerade outbound traffic on the wireguard interface.
func (wf *winFirewall) AddMasquerade(ctx context.Context, ifaceName string) error {
err := util.Exec(ctx, "netsh", "advfirewall", "firewall", "add", "rule",
iface, err := net.InterfaceByName(ifaceName)
if err != nil {
return err
}
index := iface.Index
err = util.Exec(ctx, "netsh", "advfirewall", "firewall", "add", "rule",
`name="WireGuard Masquerade"`, "dir=out", "action=allow",
fmt.Sprintf("interface=%d", index),
)
if err != nil {
return err
Expand Down

0 comments on commit 93237d0

Please sign in to comment.