Skip to content

Commit a7c3330

Browse files
committed
incusd/firewall: Add basic rules on nftables
This aligns the behavior with OVN where the most basic connectivity for the purpose of obtaining IP addresses and DNS should be allowed. Closes #1919 Signed-off-by: Stéphane Graber <[email protected]>
1 parent d137a06 commit a7c3330

File tree

5 files changed

+70
-6
lines changed

5 files changed

+70
-6
lines changed

internal/server/device/nic_bridged.go

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,11 +1182,50 @@ func (d *nicBridged) setFilters() (err error) {
11821182
defer revert.Fail()
11831183
revert.Add(func() { d.removeFilters(config) })
11841184

1185-
IPv4Nets, IPv6Nets, err := allowedIPNets(config)
1185+
ipv4Nets, ipv6Nets, err := allowedIPNets(config)
11861186
if err != nil {
11871187
return err
11881188
}
11891189

1190+
var ipv4DNS []string
1191+
var ipv6DNS []string
1192+
1193+
if d.network != nil {
1194+
netConfig := d.network.Config()
1195+
1196+
ipv4DNS = []string{}
1197+
ipv6DNS = []string{}
1198+
1199+
// Pull directly configured DNS name servers (if any).
1200+
nsList := util.SplitNTrimSpace(netConfig["dns.nameservers"], ",", -1, false)
1201+
for _, ns := range nsList {
1202+
if ns == "" {
1203+
continue
1204+
}
1205+
1206+
nsIP := net.ParseIP(ns)
1207+
if nsIP == nil {
1208+
return fmt.Errorf("Invalid DNS nameserver")
1209+
}
1210+
1211+
if nsIP.To4() == nil {
1212+
ipv4DNS = append(ipv4DNS, ns)
1213+
} else {
1214+
ipv6DNS = append(ipv6DNS, ns)
1215+
}
1216+
}
1217+
1218+
// Add IPv4 router.
1219+
if netConfig["ipv4.address"] != "" && netConfig["ipv4.address"] != "none" {
1220+
ipv4DNS = append(ipv4DNS, strings.Split(netConfig["ipv4.address"], "/")[0])
1221+
}
1222+
1223+
// Add IPv6 router.
1224+
if netConfig["ipv6.address"] != "" && netConfig["ipv6.address"] != "none" {
1225+
ipv6DNS = append(ipv6DNS, strings.Split(netConfig["ipv6.address"], "/")[0])
1226+
}
1227+
}
1228+
11901229
var aclRules []firewallDrivers.ACLRule
11911230
var aclNames []string
11921231
if config["security.acls"] != "" {
@@ -1202,10 +1241,9 @@ func (d *nicBridged) setFilters() (err error) {
12021241
if err != nil {
12031242
return err
12041243
}
1205-
12061244
}
12071245

1208-
err = d.state.Firewall.InstanceSetupBridgeFilter(d.inst.Project().Name, d.inst.Name(), d.name, d.config["parent"], d.config["host_name"], d.config["hwaddr"], IPv4Nets, IPv6Nets, d.network != nil, util.IsTrue(config["security.mac_filtering"]), aclRules)
1246+
err = d.state.Firewall.InstanceSetupBridgeFilter(d.inst.Project().Name, d.inst.Name(), d.name, d.config["parent"], d.config["host_name"], d.config["hwaddr"], ipv4Nets, ipv6Nets, ipv4DNS, ipv6DNS, d.network != nil, util.IsTrue(config["security.mac_filtering"]), aclRules)
12091247
if err != nil {
12101248
return err
12111249
}

internal/server/firewall/drivers/drivers_nftables.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ func (d Nftables) instanceDeviceLabel(projectName, instanceName, deviceName stri
401401
}
402402

403403
// InstanceSetupBridgeFilter sets up the filter rules to apply bridged device IP filtering.
404-
func (d Nftables) InstanceSetupBridgeFilter(projectName string, instanceName string, deviceName string, parentName string, hostName string, hwAddr string, IPv4Nets []*net.IPNet, IPv6Nets []*net.IPNet, parentManaged bool, macFiltering bool, aclRules []ACLRule) error {
404+
func (d Nftables) InstanceSetupBridgeFilter(projectName string, instanceName string, deviceName string, parentName string, hostName string, hwAddr string, IPv4Nets []*net.IPNet, IPv6Nets []*net.IPNet, IPv4DNS []string, IPv6DNS []string, parentManaged bool, macFiltering bool, aclRules []ACLRule) error {
405405
deviceLabel := d.instanceDeviceLabel(projectName, instanceName, deviceName)
406406

407407
mac, err := net.ParseMAC(hwAddr)
@@ -480,6 +480,10 @@ func (d Nftables) InstanceSetupBridgeFilter(projectName string, instanceName str
480480
tplFields["aclOutAcceptRules"] = nftRules.outAcceptRules
481481
tplFields["aclOutDefaultRule"] = nftRules.defaultOutRule
482482

483+
// Required for basic connectivity
484+
tplFields["dnsIPv4"] = IPv4DNS
485+
tplFields["dnsIPv6"] = IPv6DNS
486+
483487
err = d.applyNftConfig(nftablesInstanceBridgeFilter, tplFields)
484488
if err != nil {
485489
return fmt.Errorf("Failed adding bridge filter rules for instance device %q (%s): %w", deviceLabel, tplFields["family"], err)

internal/server/firewall/drivers/drivers_nftables_templates.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,24 @@ chain in{{.chainSeparator}}{{.deviceLabel}} {
190190
{{ if or .aclInDropRules .aclInRejectRules .aclInAcceptRules .aclOutDropRules .aclOutAcceptRules .aclInDefaultRule }}
191191
ct state established,related accept
192192
193+
{{ if .dnsIPv4 }}
194+
{{ range .dnsIPv4 }}
195+
iifname "{{$.hostName}}" ip daddr "{{.}}" tcp dport 53 accept
196+
iifname "{{$.hostName}}" ip daddr "{{.}}" udp dport 53 accept
197+
{{ end }}
198+
{{ end }}
199+
200+
{{ if .dnsIPv6 }}
201+
{{ range .dnsIPv6 }}
202+
iifname "{{$.hostName}}" ip6 daddr "{{.}}" tcp dport 53 accept
203+
iifname "{{$.hostName}}" ip6 daddr "{{.}}" udp dport 53 accept
204+
{{ end }}
205+
{{ end }}
206+
207+
iifname "{{.hostName}}" ether type ip ip saddr 0.0.0.0 ip daddr 255.255.255.255 udp dport 67 accept
208+
iifname "{{.hostName}}" ether type ip6 ip6 saddr fe80::/10 ip6 daddr ff02::1:2 udp dport 547 accept
209+
iifname "{{.hostName}}" ether type ip6 ip6 saddr fe80::/10 ip6 daddr ff02::2 icmpv6 type 133 accept
210+
193211
iifname "{{.hostName}}" ether type arp accept
194212
iifname "{{.hostName}}" ip6 nexthdr ipv6-icmp icmpv6 type { nd-neighbor-solicit, nd-neighbor-advert } accept
195213
{{ end }}
@@ -323,6 +341,10 @@ chain out{{.chainSeparator}}{{.deviceLabel}} {
323341
oifname "{{.hostName}}" ether type arp accept
324342
oifname "{{.hostName}}" ip6 nexthdr ipv6-icmp icmpv6 type { nd-neighbor-solicit, nd-neighbor-advert } accept
325343
344+
oifname "{{.hostName}}" udp sport 67 udp dport 68 accept
345+
oifname "{{.hostName}}" ip6 saddr fe80::/10 udp sport 547 accept
346+
oifname "{{.hostName}}" ip6 saddr fe80::/10 icmpv6 type {1, 2, 3, 4, 128, 134, 135, 136, 143} accept
347+
326348
# Network ACLs
327349
{{ range .aclOutDropRules}}
328350
{{.}}

internal/server/firewall/drivers/drivers_xtables.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -811,7 +811,7 @@ func (d Xtables) instanceDeviceIPTablesComment(projectName string, instanceName
811811
// If the parent bridge is managed by Incus then parentManaged argument should be true so that the rules added can
812812
// use the iptablesChainACLFilterPrefix chain. If not they are added to the main filter chains directly (which only
813813
// works for unmanaged bridges because those don't support ACLs).
814-
func (d Xtables) InstanceSetupBridgeFilter(projectName string, instanceName string, deviceName string, parentName string, hostName string, hwAddr string, IPv4Nets []*net.IPNet, IPv6Nets []*net.IPNet, parentManaged bool, macFiltering bool, aclRules []ACLRule) error {
814+
func (d Xtables) InstanceSetupBridgeFilter(projectName string, instanceName string, deviceName string, parentName string, hostName string, hwAddr string, IPv4Nets []*net.IPNet, IPv6Nets []*net.IPNet, IPv4DNS []string, IPv6DNS []string, parentManaged bool, macFiltering bool, aclRules []ACLRule) error {
815815
if len(aclRules) > 0 {
816816
return fmt.Errorf("ACL rules not supported for xtables bridge filtering")
817817
}

internal/server/firewall/firewall_interface.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ type Firewall interface {
2727
NetworkApplyAddressSets(sets []drivers.AddressSet, nftTable string) error
2828
NetworkDeleteAddressSetsIfUnused(nftTable string) error
2929

30-
InstanceSetupBridgeFilter(projectName string, instanceName string, deviceName string, parentName string, hostName string, hwAddr string, IPv4Nets []*net.IPNet, IPv6Nets []*net.IPNet, parentManaged bool, macFiltering bool, aclRules []drivers.ACLRule) error
30+
InstanceSetupBridgeFilter(projectName string, instanceName string, deviceName string, parentName string, hostName string, hwAddr string, IPv4Nets []*net.IPNet, IPv6Nets []*net.IPNet, IPv4DNS []string, IPv6DNS []string, parentManaged bool, macFiltering bool, aclRules []drivers.ACLRule) error
3131
InstanceClearBridgeFilter(projectName string, instanceName string, deviceName string, parentName string, hostName string, hwAddr string, IPv4Nets []*net.IPNet, IPv6Nets []*net.IPNet) error
3232

3333
InstanceSetupProxyNAT(projectName string, instanceName string, deviceName string, forward *drivers.AddressForward) error

0 commit comments

Comments
 (0)