mirror of https://github.com/k3s-io/k3s
164 lines
4.0 KiB
Go
164 lines
4.0 KiB
Go
package netroute
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"net"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
|
|
ps "github.com/benmoss/go-powershell"
|
|
psbe "github.com/benmoss/go-powershell/backend"
|
|
|
|
"fmt"
|
|
"math/big"
|
|
)
|
|
|
|
// Interface is an injectable interface for running MSFT_NetRoute commands. Implementations must be goroutine-safe.
|
|
type Interface interface {
|
|
// Get all net routes on the host
|
|
GetNetRoutesAll() ([]Route, error)
|
|
|
|
// Get net routes by link and destination subnet
|
|
GetNetRoutes(linkIndex int, destinationSubnet *net.IPNet) ([]Route, error)
|
|
|
|
// Create a new route
|
|
NewNetRoute(linkIndex int, destinationSubnet *net.IPNet, gatewayAddress net.IP) error
|
|
|
|
// Remove an existing route
|
|
RemoveNetRoute(linkIndex int, destinationSubnet *net.IPNet, gatewayAddress net.IP) error
|
|
|
|
// exit the shell
|
|
Exit()
|
|
}
|
|
|
|
type Route struct {
|
|
LinkIndex int
|
|
DestinationSubnet *net.IPNet
|
|
GatewayAddress net.IP
|
|
RouteMetric int
|
|
IfMetric int
|
|
}
|
|
|
|
type shell struct {
|
|
shellInstance ps.Shell
|
|
}
|
|
|
|
func New() Interface {
|
|
|
|
s, _ := ps.New(&psbe.Local{})
|
|
|
|
runner := &shell{
|
|
shellInstance: s,
|
|
}
|
|
|
|
return runner
|
|
}
|
|
|
|
func (shell *shell) Exit() {
|
|
shell.shellInstance.Exit()
|
|
shell.shellInstance = nil
|
|
}
|
|
|
|
func (shell *shell) GetNetRoutesAll() ([]Route, error) {
|
|
getRouteCmdLine := "get-netroute -erroraction Ignore"
|
|
stdout, err := shell.runScript(getRouteCmdLine)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return parseRoutesList(stdout), nil
|
|
}
|
|
func (shell *shell) GetNetRoutes(linkIndex int, destinationSubnet *net.IPNet) ([]Route, error) {
|
|
getRouteCmdLine := fmt.Sprintf("get-netroute -InterfaceIndex %v -DestinationPrefix %v -erroraction Ignore", linkIndex, destinationSubnet.String())
|
|
stdout, err := shell.runScript(getRouteCmdLine)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return parseRoutesList(stdout), nil
|
|
}
|
|
|
|
func (shell *shell) RemoveNetRoute(linkIndex int, destinationSubnet *net.IPNet, gatewayAddress net.IP) error {
|
|
removeRouteCmdLine := fmt.Sprintf("remove-netroute -InterfaceIndex %v -DestinationPrefix %v -NextHop %v -Verbose -Confirm:$false", linkIndex, destinationSubnet.String(), gatewayAddress.String())
|
|
_, err := shell.runScript(removeRouteCmdLine)
|
|
|
|
return err
|
|
}
|
|
|
|
func (shell *shell) NewNetRoute(linkIndex int, destinationSubnet *net.IPNet, gatewayAddress net.IP) error {
|
|
newRouteCmdLine := fmt.Sprintf("new-netroute -InterfaceIndex %v -DestinationPrefix %v -NextHop %v -Verbose", linkIndex, destinationSubnet.String(), gatewayAddress.String())
|
|
_, err := shell.runScript(newRouteCmdLine)
|
|
|
|
return err
|
|
}
|
|
|
|
func parseRoutesList(stdout string) []Route {
|
|
internalWhitespaceRegEx := regexp.MustCompile(`[\s\p{Zs}]{2,}`)
|
|
scanner := bufio.NewScanner(strings.NewReader(stdout))
|
|
var routes []Route
|
|
for scanner.Scan() {
|
|
line := internalWhitespaceRegEx.ReplaceAllString(scanner.Text(), "|")
|
|
if strings.HasPrefix(line, "ifIndex") || strings.HasPrefix(line, "----") {
|
|
continue
|
|
}
|
|
|
|
parts := strings.Split(line, "|")
|
|
if len(parts) != 5 {
|
|
continue
|
|
}
|
|
|
|
linkIndex, err := strconv.Atoi(parts[0])
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
gatewayAddress := net.ParseIP(parts[2])
|
|
if gatewayAddress == nil {
|
|
continue
|
|
}
|
|
|
|
_, destinationSubnet, err := net.ParseCIDR(parts[1])
|
|
if err != nil {
|
|
continue
|
|
}
|
|
route := Route{
|
|
DestinationSubnet: destinationSubnet,
|
|
GatewayAddress: gatewayAddress,
|
|
LinkIndex: linkIndex,
|
|
}
|
|
|
|
routes = append(routes, route)
|
|
}
|
|
|
|
return routes
|
|
}
|
|
|
|
func (r *Route) Equal(route Route) bool {
|
|
if r.DestinationSubnet.IP.Equal(route.DestinationSubnet.IP) && r.GatewayAddress.Equal(route.GatewayAddress) && bytes.Equal(r.DestinationSubnet.Mask, route.DestinationSubnet.Mask) {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (shell *shell) runScript(cmdLine string) (string, error) {
|
|
|
|
stdout, _, err := shell.shellInstance.Execute(cmdLine)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return stdout, nil
|
|
}
|
|
|
|
func IpToInt(ip net.IP) *big.Int {
|
|
if v := ip.To4(); v != nil {
|
|
return big.NewInt(0).SetBytes(v)
|
|
}
|
|
return big.NewInt(0).SetBytes(ip.To16())
|
|
}
|
|
|
|
func IntToIP(i *big.Int) net.IP {
|
|
return net.IP(i.Bytes())
|
|
}
|