using netlink instead exec in ip-helper

This commit is contained in:
Vladimir Avtsenov 2024-09-04 09:50:56 +03:00
parent dd58154c07
commit c335a7cce6
2 changed files with 17 additions and 98 deletions

View File

@ -16,7 +16,7 @@ import (
type GroupOptions struct { type GroupOptions struct {
Enabled bool Enabled bool
FWMark uint32 FWMark uint32
Table uint16 Table int
} }
type Group struct { type Group struct {

View File

@ -1,16 +1,14 @@
package ipHelper package ipHelper
import ( import (
"bufio"
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"os"
"os/exec" "os/exec"
"regexp"
"slices" "slices"
"strconv"
"strings" "github.com/vishvananda/netlink"
"github.com/vishvananda/netlink/nl"
) )
var ( var (
@ -32,23 +30,13 @@ func ExecIp(args ...string) ([]byte, error) {
func GetUsedFwMarks() ([]uint32, error) { func GetUsedFwMarks() ([]uint32, error) {
markMap := make(map[uint32]struct{}) markMap := make(map[uint32]struct{})
out, err := ExecIp("rule", "show") rules, err := netlink.RuleList(nl.FAMILY_ALL)
if err != nil { if err != nil {
return nil, fmt.Errorf("error while getting rules: %w", err) return nil, fmt.Errorf("error while getting rules: %w", err)
} }
re := regexp.MustCompile(`fwmark\s+0x([0-9a-fA-F]+)`) for _, rule := range rules {
for _, line := range strings.Split(string(out), "\n") { markMap[rule.Mark] = struct{}{}
match := re.FindStringSubmatch(line)
if len(match) < 2 {
continue
}
hexStr := match[1]
hexValue, err := strconv.ParseInt(hexStr, 16, 64)
if err == nil {
markMap[uint32(hexValue)] = struct{}{}
}
} }
marks := make([]uint32, len(markMap)) marks := make([]uint32, len(markMap))
@ -77,102 +65,33 @@ func GetUnusedFwMark(startFrom uint32) (uint32, error) {
return fwmark, nil return fwmark, nil
} }
func GetTableAliases() (map[string]uint16, error) { func GetUsedTables() ([]int, error) {
tables := map[string]uint16{ tableMap := map[int]struct{}{
"unspec": 0,
"default": 253,
"main": 254,
"local": 255,
}
file, err := os.Open("/opt/etc/iproute2/rt_tables")
if err != nil {
if os.IsNotExist(err) {
return tables, nil
}
return nil, err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "#") || len(strings.TrimSpace(line)) == 0 {
continue
}
parts := strings.Fields(line)
if len(parts) >= 2 {
tableID, err := strconv.Atoi(parts[0])
if err == nil {
tables[parts[1]] = uint16(tableID)
}
}
}
if err := scanner.Err(); err != nil {
return nil, err
}
return tables, nil
}
func GetUsedTables() ([]uint16, error) {
tableMap := map[uint16]struct{}{
0: {}, 0: {},
253: {}, 253: {},
254: {}, 254: {},
255: {}, 255: {},
} }
tableAliases, err := GetTableAliases() routes, err := netlink.RouteListFiltered(nl.FAMILY_ALL, &netlink.Route{}, netlink.RT_FILTER_TABLE)
if err != nil {
return nil, fmt.Errorf("error while getting table aliases: %w", err)
}
out, err := ExecIp("route", "show", "table", "all")
if err != nil { if err != nil {
return nil, fmt.Errorf("error while getting routes: %w", err) return nil, fmt.Errorf("error while getting routes: %w", err)
} }
for _, line := range strings.Split(string(out), "\n") { for _, route := range routes {
if strings.Contains(line, "table") { tableMap[route.Table] = struct{}{}
parts := strings.Fields(line)
for i, part := range parts {
if part == "table" && i+1 < len(parts) {
tableNum, ok := tableAliases[parts[i+1]]
if !ok {
tableNumInt, _ := strconv.Atoi(parts[i+1])
tableNum = uint16(tableNumInt)
}
tableMap[tableNum] = struct{}{}
}
}
}
} }
out, err = ExecIp("rule", "show") rules, err := netlink.RuleList(nl.FAMILY_ALL)
if err != nil { if err != nil {
return nil, fmt.Errorf("error while getting rules: %w", err) return nil, fmt.Errorf("error while getting rules: %w", err)
} }
for _, line := range strings.Split(string(out), "\n") { for _, rule := range rules {
if strings.Contains(line, "lookup") { tableMap[rule.Table] = struct{}{}
parts := strings.Fields(line)
for i, part := range parts {
if part == "lookup" && i+1 < len(parts) {
tableNum, ok := tableAliases[parts[i+1]]
if !ok {
tableNumInt, _ := strconv.Atoi(parts[i+1])
tableNum = uint16(tableNumInt)
}
tableMap[tableNum] = struct{}{}
}
}
}
} }
tables := make([]uint16, len(tableMap)) tables := make([]int, len(tableMap))
counter := 0 counter := 0
for table, _ := range tableMap { for table, _ := range tableMap {
tables[counter] = table tables[counter] = table
@ -182,7 +101,7 @@ func GetUsedTables() ([]uint16, error) {
return tables, nil return tables, nil
} }
func GetUnusedTable(startFrom uint16) (uint16, error) { func GetUnusedTable(startFrom int) (int, error) {
usedTables, err := GetUsedTables() usedTables, err := GetUsedTables()
if err != nil { if err != nil {
return 0, fmt.Errorf("error while getting used tables: %w", err) return 0, fmt.Errorf("error while getting used tables: %w", err)