mirror of
https://github.com/kubenetworks/kubevpn.git
synced 2025-09-26 19:31:17 +08:00
feat: add cmd route add and route delete for route management (#711)
This commit is contained in:
67
pkg/daemon/action/route.go
Normal file
67
pkg/daemon/action/route.go
Normal 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
@@ -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;
|
||||
|
@@ -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
13
pkg/tun/route.go
Normal 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...)
|
||||
}
|
@@ -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
49
pkg/tun/route_linux.go
Normal 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
90
pkg/tun/route_windows.go
Normal 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
|
||||
}
|
@@ -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...)
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user