mirror of
https://github.com/nadoo/glider.git
synced 2026-07-17 17:30:11 +08:00
131 lines
3.0 KiB
Go
131 lines
3.0 KiB
Go
//go:build linux
|
|
|
|
package netset
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/netip"
|
|
"syscall"
|
|
|
|
libnetset "github.com/nadoo/netset"
|
|
)
|
|
|
|
type linuxBackend struct {
|
|
ipset *libnetset.IPSet
|
|
nftsets []*libnetset.NFTSet
|
|
}
|
|
|
|
func newBackend() (backend, error) {
|
|
return &linuxBackend{}, nil
|
|
}
|
|
|
|
func (b *linuxBackend) IPSetPair(name string) (*setPair, error) {
|
|
if b.ipset == nil {
|
|
client, err := libnetset.NewIPSet()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
b.ipset = client
|
|
}
|
|
|
|
if err := ensureIPSet(b.ipset, name); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := ensureIPSet(b.ipset, name+"6", libnetset.OptIPv6()); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &setPair{
|
|
label: "ipset " + name,
|
|
ipv4: ipSetTarget{client: b.ipset, name: name},
|
|
ipv6: ipSetTarget{client: b.ipset, name: name + "6"},
|
|
}, nil
|
|
}
|
|
|
|
func ensureIPSet(client *libnetset.IPSet, name string, opts ...libnetset.Option) error {
|
|
if err := client.Create(name, opts...); err != nil && !errors.Is(err, syscall.EEXIST) {
|
|
return fmt.Errorf("create %q: %w", name, err)
|
|
}
|
|
if err := client.Flush(name); err != nil {
|
|
return fmt.Errorf("flush %q: %w", name, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (b *linuxBackend) NFTSetPair(config nftSetConfig) (*setPair, error) {
|
|
ipv4, err := b.newNFTSet(config, config.name, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ipv6, err := b.newNFTSet(config, config.name+"6", true)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &setPair{
|
|
label: "nftset " + config.key(),
|
|
ipv4: nftSetTarget{set: ipv4},
|
|
ipv6: nftSetTarget{set: ipv6},
|
|
}, nil
|
|
}
|
|
|
|
func (b *linuxBackend) newNFTSet(config nftSetConfig, name string, ipv6 bool) (*libnetset.NFTSet, error) {
|
|
opts := []libnetset.Option{libnetset.OptFamily(config.family), libnetset.OptInterval()}
|
|
if ipv6 {
|
|
opts = append(opts, libnetset.OptIPv6())
|
|
}
|
|
|
|
set, err := libnetset.NewNFTSet(config.table, name, opts...)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("open %s/%s/%s: %w", config.familyName, config.table, name, err)
|
|
}
|
|
b.nftsets = append(b.nftsets, set)
|
|
|
|
if err := set.Create(); err != nil && !errors.Is(err, syscall.EEXIST) {
|
|
return nil, fmt.Errorf("create %s/%s/%s: %w", config.familyName, config.table, name, err)
|
|
}
|
|
if err := set.Flush(); err != nil {
|
|
return nil, fmt.Errorf("flush %s/%s/%s: %w", config.familyName, config.table, name, err)
|
|
}
|
|
return set, nil
|
|
}
|
|
|
|
func (b *linuxBackend) Close() error {
|
|
var errs []error
|
|
if b.ipset != nil {
|
|
errs = append(errs, b.ipset.Close())
|
|
b.ipset = nil
|
|
}
|
|
for _, set := range b.nftsets {
|
|
errs = append(errs, set.Close())
|
|
}
|
|
b.nftsets = nil
|
|
return errors.Join(errs...)
|
|
}
|
|
|
|
type ipSetTarget struct {
|
|
client *libnetset.IPSet
|
|
name string
|
|
}
|
|
|
|
func (s ipSetTarget) AddAddr(ip netip.Addr) error {
|
|
return s.client.AddAddr(s.name, ip)
|
|
}
|
|
|
|
func (s ipSetTarget) AddPrefix(prefix netip.Prefix) error {
|
|
return s.client.AddPrefix(s.name, prefix)
|
|
}
|
|
|
|
type nftSetTarget struct {
|
|
set *libnetset.NFTSet
|
|
}
|
|
|
|
func (s nftSetTarget) AddAddr(ip netip.Addr) error {
|
|
return s.set.AddAddr(ip)
|
|
}
|
|
|
|
func (s nftSetTarget) AddPrefix(prefix netip.Prefix) error {
|
|
return s.set.AddPrefix(prefix)
|
|
}
|