mirror of
https://github.com/qdm12/gluetun.git
synced 2026-08-11 14:52:56 +02:00
human review!
This commit is contained in:
@@ -10,6 +10,22 @@ import (
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
|
||||
// cidrMask returns the binary mask for a CIDR prefix length.
|
||||
//
|
||||
//nolint:mnd
|
||||
func cidrMask(bits, addrLen int) []byte {
|
||||
result := make([]byte, addrLen)
|
||||
fullBytes := bits / 8
|
||||
remainingBits := bits % 8
|
||||
for i := range fullBytes {
|
||||
result[i] = 0xff
|
||||
}
|
||||
if remainingBits > 0 {
|
||||
result[fullBytes] = byte((0xff << (8 - remainingBits)) & 0xff)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (f *Firewall) AcceptIpv6MulticastOutput(_ context.Context, intf string) error {
|
||||
f.mutex.Lock()
|
||||
defer f.mutex.Unlock()
|
||||
@@ -35,17 +51,17 @@ func (f *Firewall) AcceptIpv6MulticastOutput(_ context.Context, intf string) err
|
||||
mask := []byte{
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
|
||||
} //nolint:mnd
|
||||
}
|
||||
addr := []byte{
|
||||
0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00,
|
||||
} //nolint:mnd
|
||||
}
|
||||
|
||||
exprs = append(exprs,
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 24, // IPv6 Destination Address offset //nolint:mnd
|
||||
Offset: 24, //nolint:mnd // IPv6 Destination Address offset
|
||||
Len: 16, //nolint:mnd
|
||||
},
|
||||
&expr.Bitwise{
|
||||
@@ -53,7 +69,7 @@ func (f *Firewall) AcceptIpv6MulticastOutput(_ context.Context, intf string) err
|
||||
DestRegister: 1,
|
||||
Len: 16, //nolint:mnd
|
||||
Mask: mask,
|
||||
Xor: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //nolint:mnd
|
||||
Xor: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
@@ -79,8 +95,9 @@ func (f *Firewall) AcceptIpv6MulticastOutput(_ context.Context, intf string) err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Firewall) AcceptOutputTrafficToVPN(_ context.Context, defaultInterface string,
|
||||
connection models.Connection, remove bool) error {
|
||||
func (f *Firewall) AcceptOutputTrafficToVPN(_ context.Context, defaultInterface string,
|
||||
connection models.Connection, remove bool,
|
||||
) error {
|
||||
f.mutex.Lock()
|
||||
defer f.mutex.Unlock()
|
||||
|
||||
@@ -109,8 +126,8 @@ func (f *Firewall) AcceptOutputTrafficToVPN(_ context.Context, defaultInterface
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 16, // IPv4 destination address offset
|
||||
Len: 4, //nolint:mnd
|
||||
Offset: 16, //nolint:mnd // IPv4 destination address offset
|
||||
Len: 4, //nolint:mnd
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
@@ -123,7 +140,7 @@ func (f *Firewall) AcceptOutputTrafficToVPN(_ context.Context, defaultInterface
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 24, // IPv6 destination address offset
|
||||
Offset: 24, //nolint:mnd// IPv6 destination address offset
|
||||
Len: 16, //nolint:mnd
|
||||
},
|
||||
&expr.Cmp{
|
||||
@@ -136,21 +153,17 @@ func (f *Firewall) AcceptOutputTrafficToVPN(_ context.Context, defaultInterface
|
||||
|
||||
// Protocol (tcp or udp)
|
||||
var protocolByte uint8
|
||||
if connection.Protocol == "tcp" || connection.Protocol == "tcp-client" {
|
||||
switch connection.Protocol {
|
||||
case "tcp", "tcp-client":
|
||||
protocolByte = 6 // TCP
|
||||
} else if connection.Protocol == "udp" {
|
||||
case "udp":
|
||||
protocolByte = 17 // UDP
|
||||
} else {
|
||||
default:
|
||||
return fmt.Errorf("unsupported protocol: %s", connection.Protocol)
|
||||
}
|
||||
|
||||
exprs = append(exprs,
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseTransportHeader,
|
||||
Offset: 3, // Protocol byte offset in IP header
|
||||
Len: 1,
|
||||
},
|
||||
&expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
@@ -159,130 +172,12 @@ func (f *Firewall) AcceptOutputTrafficToVPN(_ context.Context, defaultInterface
|
||||
)
|
||||
|
||||
// Destination port
|
||||
portBytes := []byte{byte(connection.Port >> 8), byte(connection.Port)} //nolint:mnd
|
||||
portBytes := []byte{byte(connection.Port >> 8), byte(connection.Port)} //nolint:mnd,gosec
|
||||
exprs = append(exprs,
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseTransportHeader,
|
||||
Offset: 2, // destination port offset
|
||||
Len: 2, //nolint:mnd
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: portBytes,
|
||||
},
|
||||
&expr.Verdict{Kind: expr.VerdictAccept},
|
||||
)
|
||||
|
||||
rule := &nftables.Rule{
|
||||
Table: table,
|
||||
Chain: outputChain,
|
||||
Exprs: exprs,
|
||||
}
|
||||
|
||||
if !remove {
|
||||
conn.AddRule(rule)
|
||||
f.rules = append(f.rules, rule)
|
||||
} else {
|
||||
err = f.deleteRule(conn, rule)
|
||||
if err != nil {
|
||||
return fmt.Errorf("deleting rule: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
err = conn.Flush()
|
||||
if err != nil {
|
||||
if !remove {
|
||||
f.rules = f.rules[:len(f.rules)-1]
|
||||
}
|
||||
return fmt.Errorf("flushing: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Firewall) AcceptOutput(_ context.Context, protocol, intf string, ip netip.Addr, port uint16, remove bool) error {
|
||||
f.mutex.Lock()
|
||||
defer f.mutex.Unlock()
|
||||
|
||||
conn, err := nftables.New()
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating nftables connection: %w", err)
|
||||
}
|
||||
|
||||
table, _, _, outputChain := setupFilterWithBaseChains(conn)
|
||||
|
||||
const maxExprsLen = 7
|
||||
exprs := make([]expr.Any, 0, maxExprsLen)
|
||||
|
||||
if intf != "" && intf != "*" {
|
||||
exprs = append(exprs,
|
||||
&expr.Meta{Key: expr.MetaKeyOIFNAME, Register: 1},
|
||||
&expr.Cmp{Op: expr.CmpOpEq, Register: 1, Data: []byte(intf + "\x00")},
|
||||
)
|
||||
}
|
||||
|
||||
if ip.Is4() {
|
||||
exprs = append(exprs,
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 16, //nolint:mnd
|
||||
Len: 4, //nolint:mnd
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: ip.AsSlice(),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
exprs = append(exprs,
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 24, //nolint:mnd
|
||||
Len: 16, //nolint:mnd
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: ip.AsSlice(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
var protocolByte uint8
|
||||
switch protocol {
|
||||
case "tcp":
|
||||
protocolByte = 6 //nolint:mnd
|
||||
case "udp":
|
||||
protocolByte = 17 //nolint:mnd
|
||||
default:
|
||||
return fmt.Errorf("unsupported protocol: %s", protocol)
|
||||
}
|
||||
|
||||
exprs = append(exprs,
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseTransportHeader,
|
||||
Offset: 3, //nolint:mnd
|
||||
Len: 1,
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: []byte{protocolByte},
|
||||
},
|
||||
)
|
||||
|
||||
portBytes := []byte{byte(port >> 8), byte(port)} //nolint:mnd
|
||||
exprs = append(exprs,
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseTransportHeader,
|
||||
Offset: 2, //nolint:mnd
|
||||
Offset: 2, //nolint:mnd// destination port offset
|
||||
Len: 2, //nolint:mnd
|
||||
},
|
||||
&expr.Cmp{
|
||||
@@ -349,7 +244,7 @@ func (f *Firewall) AcceptOutputFromIPPortToIPPort(_ context.Context, protocol, i
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 12, //nolint:mnd
|
||||
Len: 4, //nolint:mnd
|
||||
Len: 4, //nolint:mnd
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
@@ -362,7 +257,7 @@ func (f *Firewall) AcceptOutputFromIPPortToIPPort(_ context.Context, protocol, i
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 8, //nolint:mnd
|
||||
Offset: 8, //nolint:mnd
|
||||
Len: 16, //nolint:mnd
|
||||
},
|
||||
&expr.Cmp{
|
||||
@@ -379,7 +274,7 @@ func (f *Firewall) AcceptOutputFromIPPortToIPPort(_ context.Context, protocol, i
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 16, //nolint:mnd
|
||||
Len: 4, //nolint:mnd
|
||||
Len: 4, //nolint:mnd
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
@@ -410,16 +305,11 @@ func (f *Firewall) AcceptOutputFromIPPortToIPPort(_ context.Context, protocol, i
|
||||
case "udp":
|
||||
protocolByte = 17 //nolint:mnd
|
||||
default:
|
||||
return fmt.Errorf("unsupported protocol: %s", protocol)
|
||||
return fmt.Errorf("unsupported protocol: %s", protocol) //nolint:err113
|
||||
}
|
||||
|
||||
exprs = append(exprs,
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseTransportHeader,
|
||||
Offset: 3, //nolint:mnd
|
||||
Len: 1,
|
||||
},
|
||||
&expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
@@ -427,7 +317,7 @@ func (f *Firewall) AcceptOutputFromIPPortToIPPort(_ context.Context, protocol, i
|
||||
},
|
||||
)
|
||||
|
||||
sourcePortBytes := []byte{byte(source.Port() >> 8), byte(source.Port())} //nolint:mnd
|
||||
sourcePortBytes := []byte{byte(source.Port() >> 8), byte(source.Port())} //nolint:mnd
|
||||
destinationPortBytes := []byte{byte(destination.Port() >> 8), byte(destination.Port())} //nolint:mnd
|
||||
exprs = append(exprs,
|
||||
&expr.Payload{
|
||||
@@ -511,7 +401,7 @@ func (f *Firewall) AcceptOutputFromIPToSubnet(_ context.Context, intf string, as
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 12, //nolint:mnd
|
||||
Len: 4, //nolint:mnd
|
||||
Len: 4, //nolint:mnd
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
@@ -524,7 +414,7 @@ func (f *Firewall) AcceptOutputFromIPToSubnet(_ context.Context, intf string, as
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 8, //nolint:mnd
|
||||
Offset: 8, //nolint:mnd
|
||||
Len: 16, //nolint:mnd
|
||||
},
|
||||
&expr.Cmp{
|
||||
@@ -536,22 +426,31 @@ func (f *Firewall) AcceptOutputFromIPToSubnet(_ context.Context, intf string, as
|
||||
}
|
||||
|
||||
if subnet.Addr().Is4() {
|
||||
mask := cidrMask(subnet.Bits(), 4) //nolint:mnd
|
||||
networkAddr := subnet.Masked().Addr().AsSlice()
|
||||
exprs = append(exprs,
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 16, //nolint:mnd
|
||||
Len: 4, //nolint:mnd
|
||||
Len: 4, //nolint:mnd
|
||||
},
|
||||
&expr.Bitwise{
|
||||
SourceRegister: 1,
|
||||
DestRegister: 1,
|
||||
Len: 4, //nolint:mnd
|
||||
Mask: subnet.Masked().Addr().AsSlice(),
|
||||
Mask: mask,
|
||||
Xor: []byte{0, 0, 0, 0}, //nolint:mnd
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: networkAddr,
|
||||
},
|
||||
)
|
||||
} else {
|
||||
mask := cidrMask(subnet.Bits(), 16) //nolint:mnd
|
||||
networkAddr := subnet.Masked().Addr().AsSlice()
|
||||
exprs = append(exprs,
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
@@ -563,9 +462,14 @@ func (f *Firewall) AcceptOutputFromIPToSubnet(_ context.Context, intf string, as
|
||||
SourceRegister: 1,
|
||||
DestRegister: 1,
|
||||
Len: 16, //nolint:mnd
|
||||
Mask: subnet.Masked().Addr().AsSlice(),
|
||||
Mask: mask,
|
||||
Xor: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //nolint:mnd
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: networkAddr,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user