feat: add cmd route add and route delete for route management (#711)

This commit is contained in:
naison
2025-08-28 20:29:12 +08:00
committed by GitHub
parent cf473d85c9
commit 79fcc1b8f5
168 changed files with 30715 additions and 533 deletions

View File

@@ -0,0 +1,67 @@
package action
import (
"context"
"fmt"
"io"
"net"
"github.com/containernetworking/cni/pkg/types"
log "github.com/sirupsen/logrus"
"github.com/wencaiwulue/kubevpn/v2/pkg/daemon/rpc"
plog "github.com/wencaiwulue/kubevpn/v2/pkg/log"
"github.com/wencaiwulue/kubevpn/v2/pkg/tun"
)
func (svr *Server) Route(ctx context.Context, req *rpc.RouteRequest) (*rpc.RouteResponse, error) {
if !svr.IsSudo {
logger := plog.GetLoggerForClient(int32(log.InfoLevel), io.MultiWriter(svr.LogFile))
var index = -1
for i, connection := range svr.connections {
if connection.GetConnectionID() == svr.currentConnectionID {
index = i
break
}
}
if index == -1 {
logger.Infof("No connection found")
return nil, fmt.Errorf("no connection found")
}
tunName, err := svr.connections[index].GetTunDeviceName()
if err != nil {
return nil, err
}
_, ipNet, err := net.ParseCIDR(req.Cidr)
if err != nil {
return nil, err
}
client, err := svr.GetClient(true)
if err != nil {
return nil, err
}
return client.Route(ctx, &rpc.RouteRequest{
Cidr: ipNet.String(),
Type: req.Type,
Dev: tunName,
})
} else {
_, ipNet, err := net.ParseCIDR(req.Cidr)
if err != nil {
return nil, err
}
switch req.Type {
case rpc.RouteType_ROUTE_ADD:
err = tun.AddRoutes(req.Dev, types.Route{Dst: *ipNet})
case rpc.RouteType_ROUTE_DELETE:
err = tun.DeleteRoutes(req.Dev, types.Route{Dst: *ipNet})
}
if err != nil {
return nil, err
}
return &rpc.RouteResponse{
Message: "ok",
}, nil
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -16,6 +16,7 @@ service Daemon {
rpc SshStart (SshStartRequest) returns (SshStartResponse) {}
rpc SshStop (SshStopRequest) returns (SshStopResponse) {}
rpc Route (RouteRequest) returns (RouteResponse) {}
rpc Logs (stream LogRequest) returns (stream LogResponse) {}
rpc Upgrade (UpgradeRequest) returns (UpgradeResponse) {}
@@ -274,6 +275,21 @@ message SshStopResponse {
string ServerIP = 1;
}
message RouteRequest {
string cidr = 1;
RouteType type = 2;
string dev = 3;
}
enum RouteType {
ROUTE_ADD = 0;
ROUTE_DELETE = 1;
}
message RouteResponse {
string message = 1;
}
message SshConnectRequest {
string Stdin = 1;
SshJump SshJump = 2;

View File

@@ -29,6 +29,7 @@ const (
Daemon_ConnectionUse_FullMethodName = "/rpc.Daemon/ConnectionUse"
Daemon_SshStart_FullMethodName = "/rpc.Daemon/SshStart"
Daemon_SshStop_FullMethodName = "/rpc.Daemon/SshStop"
Daemon_Route_FullMethodName = "/rpc.Daemon/Route"
Daemon_Logs_FullMethodName = "/rpc.Daemon/Logs"
Daemon_Upgrade_FullMethodName = "/rpc.Daemon/Upgrade"
Daemon_Status_FullMethodName = "/rpc.Daemon/Status"
@@ -53,6 +54,7 @@ type DaemonClient interface {
ConnectionUse(ctx context.Context, in *ConnectionUseRequest, opts ...grpc.CallOption) (*ConnectionUseResponse, error)
SshStart(ctx context.Context, in *SshStartRequest, opts ...grpc.CallOption) (*SshStartResponse, error)
SshStop(ctx context.Context, in *SshStopRequest, opts ...grpc.CallOption) (*SshStopResponse, error)
Route(ctx context.Context, in *RouteRequest, opts ...grpc.CallOption) (*RouteResponse, error)
Logs(ctx context.Context, opts ...grpc.CallOption) (Daemon_LogsClient, error)
Upgrade(ctx context.Context, in *UpgradeRequest, opts ...grpc.CallOption) (*UpgradeResponse, error)
Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error)
@@ -293,6 +295,15 @@ func (c *daemonClient) SshStop(ctx context.Context, in *SshStopRequest, opts ...
return out, nil
}
func (c *daemonClient) Route(ctx context.Context, in *RouteRequest, opts ...grpc.CallOption) (*RouteResponse, error) {
out := new(RouteResponse)
err := c.cc.Invoke(ctx, Daemon_Route_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *daemonClient) Logs(ctx context.Context, opts ...grpc.CallOption) (Daemon_LogsClient, error) {
stream, err := c.cc.NewStream(ctx, &Daemon_ServiceDesc.Streams[6], Daemon_Logs_FullMethodName, opts...)
if err != nil {
@@ -467,6 +478,7 @@ type DaemonServer interface {
ConnectionUse(context.Context, *ConnectionUseRequest) (*ConnectionUseResponse, error)
SshStart(context.Context, *SshStartRequest) (*SshStartResponse, error)
SshStop(context.Context, *SshStopRequest) (*SshStopResponse, error)
Route(context.Context, *RouteRequest) (*RouteResponse, error)
Logs(Daemon_LogsServer) error
Upgrade(context.Context, *UpgradeRequest) (*UpgradeResponse, error)
Status(context.Context, *StatusRequest) (*StatusResponse, error)
@@ -512,6 +524,9 @@ func (UnimplementedDaemonServer) SshStart(context.Context, *SshStartRequest) (*S
func (UnimplementedDaemonServer) SshStop(context.Context, *SshStopRequest) (*SshStopResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method SshStop not implemented")
}
func (UnimplementedDaemonServer) Route(context.Context, *RouteRequest) (*RouteResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Route not implemented")
}
func (UnimplementedDaemonServer) Logs(Daemon_LogsServer) error {
return status.Errorf(codes.Unimplemented, "method Logs not implemented")
}
@@ -777,6 +792,24 @@ func _Daemon_SshStop_Handler(srv interface{}, ctx context.Context, dec func(inte
return interceptor(ctx, in, info, handler)
}
func _Daemon_Route_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RouteRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DaemonServer).Route(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Daemon_Route_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DaemonServer).Route(ctx, req.(*RouteRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Daemon_Logs_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(DaemonServer).Logs(&daemonLogsServer{stream})
}
@@ -976,6 +1009,10 @@ var Daemon_ServiceDesc = grpc.ServiceDesc{
MethodName: "SshStop",
Handler: _Daemon_SshStop_Handler,
},
{
MethodName: "Route",
Handler: _Daemon_Route_Handler,
},
{
MethodName: "Upgrade",
Handler: _Daemon_Upgrade_Handler,

13
pkg/tun/route.go Normal file
View File

@@ -0,0 +1,13 @@
package tun
import "github.com/containernetworking/cni/pkg/types"
// AddRoutes for outer called
func AddRoutes(tunName string, routes ...types.Route) error {
return addTunRoutes(tunName, routes...)
}
// DeleteRoutes ...
func DeleteRoutes(tunName string, routes ...types.Route) error {
return deleteTunRoutes(tunName, routes...)
}

View File

@@ -2,14 +2,74 @@ package tun
import (
"errors"
"fmt"
"net"
"net/netip"
"os"
"github.com/containernetworking/cni/pkg/types"
"golang.org/x/net/route"
"golang.org/x/sys/unix"
)
func addTunRoutes(ifName string, routes ...types.Route) error {
tunIfi, err := net.InterfaceByName(ifName)
if err != nil {
return err
}
gw := &route.LinkAddr{Index: tunIfi.Index}
var prefixList []netip.Prefix
for _, r := range routes {
if net.ParseIP(r.Dst.IP.String()) == nil {
continue
}
var prefix netip.Prefix
prefix, err = netip.ParsePrefix(r.Dst.String())
if err != nil {
return err
}
prefixList = append(prefixList, prefix)
}
if len(prefixList) == 0 {
return nil
}
err = addRoute(gw, prefixList...)
if err != nil {
return fmt.Errorf("failed to add dst %v via %s to route table: %v", prefixList, ifName, err)
}
return nil
}
func deleteTunRoutes(ifName string, routes ...types.Route) error {
tunIfi, err := net.InterfaceByName(ifName)
if err != nil {
return err
}
gw := &route.LinkAddr{Index: tunIfi.Index}
var prefixList []netip.Prefix
for _, r := range routes {
if net.ParseIP(r.Dst.IP.String()) == nil {
continue
}
var prefix netip.Prefix
prefix, err = netip.ParsePrefix(r.Dst.String())
if err != nil {
return err
}
prefixList = append(prefixList, prefix)
}
if len(prefixList) == 0 {
return nil
}
err = deleteRoute(gw, prefixList...)
if err != nil {
return fmt.Errorf("failed to add dst %v via %s to route table: %v", prefixList, ifName, err)
}
return nil
}
func addRoute(gw route.Addr, r ...netip.Prefix) error {
if len(r) == 0 {
return nil

49
pkg/tun/route_linux.go Normal file
View File

@@ -0,0 +1,49 @@
//go:build linux
package tun
import (
"errors"
"fmt"
"net"
"syscall"
"github.com/containernetworking/cni/pkg/types"
"github.com/docker/libcontainer/netlink"
netlink1 "github.com/vishvananda/netlink"
)
func addTunRoutes(ifName string, routes ...types.Route) error {
for _, route := range routes {
if net.ParseIP(route.Dst.IP.String()) == nil {
continue
}
// ip route add 192.168.1.123/32 dev utun0
err := netlink.AddRoute(route.Dst.String(), "", "", ifName)
if err != nil && !errors.Is(err, syscall.EEXIST) {
return fmt.Errorf("failed to add dst %v via %s to route table: %v", route.Dst.String(), ifName, err)
}
}
return nil
}
func deleteTunRoutes(ifName string, routes ...types.Route) error {
tunIfi, err := net.InterfaceByName(ifName)
if err != nil {
return err
}
for _, route := range routes {
if net.ParseIP(route.Dst.IP.String()) == nil {
continue
}
// ip route add 192.168.1.123/32 dev utun0
err = netlink1.RouteDel(&netlink1.Route{
Dst: &route.Dst,
LinkIndex: tunIfi.Index,
})
if err != nil && !errors.Is(err, syscall.EEXIST) {
return fmt.Errorf("failed to add dst %v via %s to route table: %v", route.Dst.String(), ifName, err)
}
}
return nil
}

90
pkg/tun/route_windows.go Normal file
View File

@@ -0,0 +1,90 @@
//go:build windows
package tun
import (
"net"
"net/netip"
"syscall"
"github.com/containernetworking/cni/pkg/types"
"github.com/pkg/errors"
"golang.org/x/sys/windows"
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
)
func addTunRoutes(tunName string, routes ...types.Route) error {
name, err2 := net.InterfaceByName(tunName)
if err2 != nil {
return err2
}
ifUID, err := winipcfg.LUIDFromIndex(uint32(name.Index))
if err != nil {
return err
}
for _, route := range routes {
if net.ParseIP(route.Dst.IP.String()) == nil {
continue
}
if route.GW == nil {
if route.Dst.IP.To4() != nil {
route.GW = net.IPv4zero
} else {
route.GW = net.IPv6zero
}
}
var prefix netip.Prefix
prefix, err = netip.ParsePrefix(route.Dst.String())
if err != nil {
return err
}
var addr netip.Addr
addr, err = netip.ParseAddr(route.GW.String())
if err != nil {
return err
}
err = ifUID.AddRoute(prefix, addr.Unmap(), 0)
if err != nil && !errors.Is(err, windows.ERROR_OBJECT_ALREADY_EXISTS) && !errors.Is(err, syscall.ERROR_NOT_FOUND) {
return err
}
}
return nil
}
func deleteTunRoutes(tunName string, routes ...types.Route) error {
name, err2 := net.InterfaceByName(tunName)
if err2 != nil {
return err2
}
ifUID, err := winipcfg.LUIDFromIndex(uint32(name.Index))
if err != nil {
return err
}
for _, route := range routes {
if net.ParseIP(route.Dst.IP.String()) == nil {
continue
}
if route.GW == nil {
if route.Dst.IP.To4() != nil {
route.GW = net.IPv4zero
} else {
route.GW = net.IPv6zero
}
}
var prefix netip.Prefix
prefix, err = netip.ParsePrefix(route.Dst.String())
if err != nil {
return err
}
var addr netip.Addr
addr, err = netip.ParseAddr(route.GW.String())
if err != nil {
return err
}
err = ifUID.DeleteRoute(prefix, addr.Unmap())
if err != nil && !errors.Is(err, syscall.ERROR_NOT_FOUND) {
return err
}
}
return nil
}

View File

@@ -131,8 +131,3 @@ func (c *tunConn) SetReadDeadline(time.Time) error {
func (c *tunConn) SetWriteDeadline(time.Time) error {
return &net.OpError{Op: "set", Net: "tun", Source: nil, Addr: nil, Err: errors.New("write deadline not supported")}
}
// AddRoutes for outer called
func AddRoutes(tunName string, routes ...types.Route) error {
return addTunRoutes(tunName, routes...)
}

View File

@@ -9,9 +9,7 @@ import (
"runtime"
"unsafe"
"github.com/containernetworking/cni/pkg/types"
pkgerr "github.com/pkg/errors"
"golang.org/x/net/route"
"golang.org/x/sys/unix"
"golang.zx2c4.com/wireguard/tun"
@@ -92,35 +90,6 @@ func createTun(cfg Config) (conn net.Conn, itf *net.Interface, err error) {
return
}
func addTunRoutes(ifName string, routes ...types.Route) error {
tunIfi, err := net.InterfaceByName(ifName)
if err != nil {
return err
}
gw := &route.LinkAddr{Index: tunIfi.Index}
var prefixList []netip.Prefix
for _, r := range routes {
if net.ParseIP(r.Dst.IP.String()) == nil {
continue
}
var prefix netip.Prefix
prefix, err = netip.ParsePrefix(r.Dst.String())
if err != nil {
return err
}
prefixList = append(prefixList, prefix)
}
if len(prefixList) == 0 {
return nil
}
err = addRoute(gw, prefixList...)
if err != nil {
return fmt.Errorf("failed to add dst %v via %s to route table: %v", prefixList, ifName, err)
}
return nil
}
// struct ifaliasreq
type inet4AliasReq struct {
name [unix.IFNAMSIZ]byte

View File

@@ -8,7 +8,6 @@ import (
"net"
"syscall"
"github.com/containernetworking/cni/pkg/types"
"github.com/docker/libcontainer/netlink"
"golang.zx2c4.com/wireguard/tun"
@@ -104,17 +103,3 @@ func createTun(cfg Config) (conn net.Conn, itf *net.Interface, err error) {
}
return
}
func addTunRoutes(ifName string, routes ...types.Route) error {
for _, route := range routes {
if net.ParseIP(route.Dst.IP.String()) == nil {
continue
}
// ip route add 192.168.1.123/32 dev utun0
err := netlink.AddRoute(route.Dst.String(), "", "", ifName)
if err != nil && !errors.Is(err, syscall.EEXIST) {
return fmt.Errorf("failed to add dst %v via %s to route table: %v", route.Dst.String(), ifName, err)
}
}
return nil
}

View File

@@ -11,7 +11,6 @@ import (
"syscall"
"time"
"github.com/containernetworking/cni/pkg/types"
"github.com/pkg/errors"
"golang.org/x/sys/windows"
wintun "golang.zx2c4.com/wintun"
@@ -125,44 +124,6 @@ func createTun(cfg Config) (conn net.Conn, itf *net.Interface, err error) {
return
}
func addTunRoutes(tunName string, routes ...types.Route) error {
name, err2 := net.InterfaceByName(tunName)
if err2 != nil {
return err2
}
ifUID, err := winipcfg.LUIDFromIndex(uint32(name.Index))
if err != nil {
return err
}
for _, route := range routes {
if net.ParseIP(route.Dst.IP.String()) == nil {
continue
}
if route.GW == nil {
if route.Dst.IP.To4() != nil {
route.GW = net.IPv4zero
} else {
route.GW = net.IPv6zero
}
}
var prefix netip.Prefix
prefix, err = netip.ParsePrefix(route.Dst.String())
if err != nil {
return err
}
var addr netip.Addr
addr, err = netip.ParseAddr(route.GW.String())
if err != nil {
return err
}
err = ifUID.AddRoute(prefix, addr.Unmap(), 0)
if err != nil && !errors.Is(err, windows.ERROR_OBJECT_ALREADY_EXISTS) && !errors.Is(err, syscall.ERROR_NOT_FOUND) {
return err
}
}
return nil
}
type winTunConn struct {
ifce wireguardtun.Device
addr net.Addr