MagiTrickle/group.go

190 lines
3.6 KiB
Go
Raw Normal View History

2024-08-27 03:07:58 +03:00
package main
2024-08-30 04:30:33 +03:00
import (
"fmt"
2024-08-30 05:27:52 +03:00
"net"
2024-09-04 08:14:09 +03:00
"os"
2024-08-30 05:27:52 +03:00
"time"
2024-08-30 04:30:33 +03:00
"kvas2-go/models"
2024-09-04 10:59:52 +03:00
"github.com/rs/zerolog/log"
"github.com/vishvananda/netlink"
2024-09-05 03:53:10 +03:00
"github.com/vishvananda/netlink/nl"
2024-08-30 04:30:33 +03:00
)
2024-08-27 03:07:58 +03:00
2024-08-30 04:09:28 +03:00
type GroupOptions struct {
Enabled bool
ipRule *netlink.Rule
2024-09-04 10:59:52 +03:00
ipRoute *netlink.Route
2024-08-30 04:09:28 +03:00
}
2024-08-27 03:07:58 +03:00
type Group struct {
*models.Group
2024-08-30 04:40:46 +03:00
ipsetName string
options GroupOptions
2024-08-27 03:07:58 +03:00
}
2024-08-30 04:30:33 +03:00
2024-08-30 05:27:52 +03:00
func (g *Group) HandleIPv4(names []string, address net.IP, ttl time.Duration) error {
if !g.options.Enabled {
return nil
}
2024-09-04 08:14:09 +03:00
ttlSeconds := uint32(ttl.Seconds())
2024-08-30 05:27:52 +03:00
DomainSearch:
for _, domain := range g.Domains {
if !domain.IsEnabled() {
continue
}
for _, name := range names {
if domain.IsMatch(name) {
2024-09-04 08:14:09 +03:00
err := netlink.IpsetAdd(g.ipsetName, &netlink.IPSetEntry{
IP: address,
Timeout: &ttlSeconds,
Replace: true,
})
2024-08-30 05:27:52 +03:00
if err != nil {
2024-09-04 09:15:03 +03:00
return fmt.Errorf("failed to assign address: %w", err)
2024-08-30 05:27:52 +03:00
}
break DomainSearch
}
}
}
return nil
}
2024-08-30 04:30:33 +03:00
func (g *Group) Enable() error {
if g.options.Enabled {
return nil
}
var err error
2024-09-05 03:53:10 +03:00
markMap := make(map[uint32]struct{})
tableMap := map[int]struct{}{
0: {},
253: {},
254: {},
255: {},
}
var table int
var mark uint32
rules, err := netlink.RuleList(nl.FAMILY_ALL)
2024-08-30 04:30:33 +03:00
if err != nil {
2024-09-05 03:53:10 +03:00
return fmt.Errorf("error while getting rules: %w", err)
}
for _, rule := range rules {
markMap[rule.Mark] = struct{}{}
tableMap[rule.Table] = struct{}{}
}
routes, err := netlink.RouteListFiltered(nl.FAMILY_ALL, &netlink.Route{}, netlink.RT_FILTER_TABLE)
if err != nil {
return fmt.Errorf("error while getting routes: %w", err)
}
for _, route := range routes {
tableMap[route.Table] = struct{}{}
}
for {
if _, exists := tableMap[table]; exists {
table++
continue
}
break
2024-08-30 04:30:33 +03:00
}
2024-09-05 03:53:10 +03:00
for {
if _, exists := markMap[mark]; exists {
mark++
continue
}
break
}
rule := netlink.NewRule()
rule.Mark = mark
rule.Table = table
2024-08-30 04:30:33 +03:00
if err != nil {
return fmt.Errorf("error while getting free table: %w", err)
}
err = netlink.RuleAdd(rule)
2024-08-30 04:30:33 +03:00
if err != nil {
return fmt.Errorf("error while adding rule: %w", err)
2024-08-30 04:30:33 +03:00
}
g.options.ipRule = rule
2024-08-30 04:30:33 +03:00
2024-09-04 10:59:52 +03:00
iface, err := netlink.LinkByName(g.Interface)
if err != nil {
log.Warn().Str("interface", g.Interface).Msg("error while getting interface")
}
if iface != nil {
route := &netlink.Route{
LinkIndex: iface.Attrs().Index,
Table: rule.Table,
Dst: &net.IPNet{
IP: []byte{0, 0, 0, 0},
Mask: []byte{0, 0, 0, 0},
},
}
err = netlink.RouteAdd(route)
if err != nil {
return fmt.Errorf("error while adding route: %w", err)
}
g.options.ipRoute = route
}
2024-09-04 08:14:09 +03:00
defaultTimeout := uint32(300)
err = netlink.IpsetDestroy(g.ipsetName)
if err != nil && !os.IsNotExist(err) {
2024-08-30 04:40:46 +03:00
return fmt.Errorf("failed to destroy ipset: %w", err)
}
2024-09-04 08:14:09 +03:00
err = netlink.IpsetCreate(g.ipsetName, "hash:ip", netlink.IpsetCreateOptions{
Timeout: &defaultTimeout,
})
2024-08-30 04:40:46 +03:00
if err != nil {
return fmt.Errorf("failed to create ipset: %w", err)
}
2024-08-30 04:30:33 +03:00
g.options.Enabled = true
return nil
}
func (g *Group) Disable() error {
if !g.options.Enabled {
return nil
}
2024-09-04 10:59:52 +03:00
var err error
if g.options.ipRule != nil {
err = netlink.RuleDel(g.options.ipRule)
if err != nil {
return fmt.Errorf("error while deleting rule: %w", err)
}
g.options.ipRule = nil
}
if g.options.ipRoute != nil {
err = netlink.RouteDel(g.options.ipRoute)
if err != nil {
return fmt.Errorf("error while deleting route: %w", err)
}
g.options.ipRule = nil
2024-08-30 04:30:33 +03:00
}
2024-09-04 08:14:09 +03:00
err = netlink.IpsetDestroy(g.ipsetName)
if err != nil && !os.IsNotExist(err) {
2024-08-30 04:40:46 +03:00
return fmt.Errorf("failed to destroy ipset: %w", err)
}
2024-08-30 04:30:33 +03:00
g.options.Enabled = false
return nil
}