using netlink instead exec in ip-helper
This commit is contained in:
		
							parent
							
								
									dd58154c07
								
							
						
					
					
						commit
						c335a7cce6
					
				
							
								
								
									
										2
									
								
								group.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								group.go
									
									
									
									
									
								
							| @ -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 { | ||||||
|  | |||||||
| @ -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) | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user