Add MAC address include/exclude filtering for nftables auto-redirect
Support filtering traffic by source MAC address in the prerouting chain, using ether addr payload matching with set lookups for multiple addresses.
This commit is contained in:
parent
30e535973b
commit
f8e7794cc2
2 changed files with 146 additions and 0 deletions
|
|
@ -3,6 +3,7 @@
|
||||||
package tun
|
package tun
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
_ "unsafe"
|
_ "unsafe"
|
||||||
|
|
||||||
|
|
@ -376,6 +377,149 @@ func (r *autoRedirect) nftablesCreateExcludeRules(nft *nftables.Conn, table *nft
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(r.tunOptions.IncludeMACAddress) > 0 {
|
||||||
|
nft.AddRule(&nftables.Rule{
|
||||||
|
Table: table,
|
||||||
|
Chain: chain,
|
||||||
|
Exprs: []expr.Any{
|
||||||
|
&expr.Meta{Key: expr.MetaKeyIIFTYPE, Register: 1},
|
||||||
|
&expr.Cmp{
|
||||||
|
Op: expr.CmpOpNeq,
|
||||||
|
Register: 1,
|
||||||
|
Data: binaryutil.NativeEndian.PutUint16(unix.ARPHRD_ETHER),
|
||||||
|
},
|
||||||
|
&expr.Counter{},
|
||||||
|
&expr.Verdict{
|
||||||
|
Kind: expr.VerdictReturn,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if len(r.tunOptions.IncludeMACAddress) > 1 {
|
||||||
|
includeMACSet := &nftables.Set{
|
||||||
|
Table: table,
|
||||||
|
Anonymous: true,
|
||||||
|
Constant: true,
|
||||||
|
KeyType: nftables.TypeEtherAddr,
|
||||||
|
}
|
||||||
|
err := nft.AddSet(includeMACSet, common.Map(r.tunOptions.IncludeMACAddress, func(it net.HardwareAddr) nftables.SetElement {
|
||||||
|
return nftables.SetElement{
|
||||||
|
Key: []byte(it),
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
nft.AddRule(&nftables.Rule{
|
||||||
|
Table: table,
|
||||||
|
Chain: chain,
|
||||||
|
Exprs: []expr.Any{
|
||||||
|
&expr.Payload{
|
||||||
|
OperationType: expr.PayloadLoad,
|
||||||
|
DestRegister: 1,
|
||||||
|
Base: expr.PayloadBaseLLHeader,
|
||||||
|
Offset: 6,
|
||||||
|
Len: 6,
|
||||||
|
},
|
||||||
|
&expr.Lookup{
|
||||||
|
SourceRegister: 1,
|
||||||
|
SetID: includeMACSet.ID,
|
||||||
|
SetName: includeMACSet.Name,
|
||||||
|
Invert: true,
|
||||||
|
},
|
||||||
|
&expr.Counter{},
|
||||||
|
&expr.Verdict{
|
||||||
|
Kind: expr.VerdictReturn,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
nft.AddRule(&nftables.Rule{
|
||||||
|
Table: table,
|
||||||
|
Chain: chain,
|
||||||
|
Exprs: []expr.Any{
|
||||||
|
&expr.Payload{
|
||||||
|
OperationType: expr.PayloadLoad,
|
||||||
|
DestRegister: 1,
|
||||||
|
Base: expr.PayloadBaseLLHeader,
|
||||||
|
Offset: 6,
|
||||||
|
Len: 6,
|
||||||
|
},
|
||||||
|
&expr.Cmp{
|
||||||
|
Op: expr.CmpOpNeq,
|
||||||
|
Register: 1,
|
||||||
|
Data: []byte(r.tunOptions.IncludeMACAddress[0]),
|
||||||
|
},
|
||||||
|
&expr.Counter{},
|
||||||
|
&expr.Verdict{
|
||||||
|
Kind: expr.VerdictReturn,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(r.tunOptions.ExcludeMACAddress) > 0 {
|
||||||
|
if len(r.tunOptions.ExcludeMACAddress) > 1 {
|
||||||
|
excludeMACSet := &nftables.Set{
|
||||||
|
Table: table,
|
||||||
|
Anonymous: true,
|
||||||
|
Constant: true,
|
||||||
|
KeyType: nftables.TypeEtherAddr,
|
||||||
|
}
|
||||||
|
err := nft.AddSet(excludeMACSet, common.Map(r.tunOptions.ExcludeMACAddress, func(it net.HardwareAddr) nftables.SetElement {
|
||||||
|
return nftables.SetElement{
|
||||||
|
Key: []byte(it),
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
nft.AddRule(&nftables.Rule{
|
||||||
|
Table: table,
|
||||||
|
Chain: chain,
|
||||||
|
Exprs: []expr.Any{
|
||||||
|
&expr.Payload{
|
||||||
|
OperationType: expr.PayloadLoad,
|
||||||
|
DestRegister: 1,
|
||||||
|
Base: expr.PayloadBaseLLHeader,
|
||||||
|
Offset: 6,
|
||||||
|
Len: 6,
|
||||||
|
},
|
||||||
|
&expr.Lookup{
|
||||||
|
SourceRegister: 1,
|
||||||
|
SetID: excludeMACSet.ID,
|
||||||
|
SetName: excludeMACSet.Name,
|
||||||
|
},
|
||||||
|
&expr.Counter{},
|
||||||
|
&expr.Verdict{
|
||||||
|
Kind: expr.VerdictReturn,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
nft.AddRule(&nftables.Rule{
|
||||||
|
Table: table,
|
||||||
|
Chain: chain,
|
||||||
|
Exprs: []expr.Any{
|
||||||
|
&expr.Payload{
|
||||||
|
OperationType: expr.PayloadLoad,
|
||||||
|
DestRegister: 1,
|
||||||
|
Base: expr.PayloadBaseLLHeader,
|
||||||
|
Offset: 6,
|
||||||
|
Len: 6,
|
||||||
|
},
|
||||||
|
&expr.Cmp{
|
||||||
|
Op: expr.CmpOpEq,
|
||||||
|
Register: 1,
|
||||||
|
Data: []byte(r.tunOptions.ExcludeMACAddress[0]),
|
||||||
|
},
|
||||||
|
&expr.Counter{},
|
||||||
|
&expr.Verdict{
|
||||||
|
Kind: expr.VerdictReturn,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if len(r.tunOptions.IncludeUID) > 0 {
|
if len(r.tunOptions.IncludeUID) > 0 {
|
||||||
if len(r.tunOptions.IncludeUID) > 1 || r.tunOptions.IncludeUID[0].Start != r.tunOptions.IncludeUID[0].End {
|
if len(r.tunOptions.IncludeUID) > 1 || r.tunOptions.IncludeUID[0].Start != r.tunOptions.IncludeUID[0].End {
|
||||||
|
|
|
||||||
2
tun.go
2
tun.go
|
|
@ -102,6 +102,8 @@ type Options struct {
|
||||||
IncludeAndroidUser []int
|
IncludeAndroidUser []int
|
||||||
IncludePackage []string
|
IncludePackage []string
|
||||||
ExcludePackage []string
|
ExcludePackage []string
|
||||||
|
IncludeMACAddress []net.HardwareAddr
|
||||||
|
ExcludeMACAddress []net.HardwareAddr
|
||||||
InterfaceFinder control.InterfaceFinder
|
InterfaceFinder control.InterfaceFinder
|
||||||
InterfaceMonitor DefaultInterfaceMonitor
|
InterfaceMonitor DefaultInterfaceMonitor
|
||||||
FileDescriptor int
|
FileDescriptor int
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue