mirror of
https://github.com/kubenetworks/kubevpn.git
synced 2025-12-24 11:51:13 +08:00
a udp tunnel over tcp
This commit is contained in:
@@ -65,17 +65,12 @@ func (c *Chain) DialContext(ctx context.Context, network, address string) (conn
|
||||
}
|
||||
|
||||
func (c *Chain) dial(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
route, err := c.selectRoute()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ipAddr := address
|
||||
if address != "" {
|
||||
ipAddr = c.resolve(address)
|
||||
}
|
||||
|
||||
if route.IsEmpty() {
|
||||
if c.IsEmpty() {
|
||||
switch network {
|
||||
case "udp", "udp4", "udp6":
|
||||
if address == "" {
|
||||
@@ -90,12 +85,12 @@ func (c *Chain) dial(ctx context.Context, network, address string) (net.Conn, er
|
||||
return d.DialContext(ctx, network, ipAddr)
|
||||
}
|
||||
|
||||
conn, err := route.getConn(ctx)
|
||||
conn, err := c.getConn(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cc, err := route.Node().Client.ConnectContext(ctx, conn, network, ipAddr)
|
||||
cc, err := c.Node().Client.ConnectContext(ctx, conn, network, ipAddr)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
@@ -122,12 +117,7 @@ func (c *Chain) Conn() (conn net.Conn, err error) {
|
||||
}
|
||||
|
||||
for i := 0; i < retries; i++ {
|
||||
var route *Chain
|
||||
route, err = c.selectRoute()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
conn, err = route.getConn(ctx)
|
||||
conn, err = c.getConn(ctx)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
@@ -150,15 +140,3 @@ func (c *Chain) getConn(_ context.Context) (conn net.Conn, err error) {
|
||||
conn = cc
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Chain) selectRoute() (route *Chain, err error) {
|
||||
if c.IsEmpty() {
|
||||
return newRoute(), nil
|
||||
}
|
||||
if c.isRoute {
|
||||
return c, nil
|
||||
}
|
||||
route = newRoute()
|
||||
route.SetNode(c.node)
|
||||
return
|
||||
}
|
||||
|
||||
227
core/socks.go
227
core/socks.go
@@ -3,7 +3,6 @@ package core
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/wencaiwulue/kubevpn/util"
|
||||
"net"
|
||||
@@ -14,136 +13,50 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type clientSelector struct {
|
||||
methods []uint8
|
||||
}
|
||||
|
||||
func (selector *clientSelector) Methods() []uint8 {
|
||||
if util.Debug {
|
||||
log.Debug("[socks5] methods:", selector.methods)
|
||||
}
|
||||
return selector.methods
|
||||
}
|
||||
|
||||
func (selector *clientSelector) AddMethod(methods ...uint8) {
|
||||
selector.methods = append(selector.methods, methods...)
|
||||
}
|
||||
|
||||
func (selector *clientSelector) Select(methods ...uint8) (method uint8) {
|
||||
return
|
||||
}
|
||||
|
||||
func (selector *clientSelector) OnSelected(method uint8, conn net.Conn) (net.Conn, error) {
|
||||
if util.Debug {
|
||||
log.Debug("[socks5] method selected:", method)
|
||||
}
|
||||
switch method {
|
||||
case gosocks5.MethodNoAuth:
|
||||
log.Debug("[socks5] client", "no auth")
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
type serverSelector struct {
|
||||
methods []uint8
|
||||
}
|
||||
|
||||
func (selector *serverSelector) Methods() []uint8 {
|
||||
return selector.methods
|
||||
}
|
||||
|
||||
func (selector *serverSelector) AddMethod(methods ...uint8) {
|
||||
selector.methods = append(selector.methods, methods...)
|
||||
}
|
||||
|
||||
func (selector *serverSelector) Select(methods ...uint8) (method uint8) {
|
||||
if util.Debug {
|
||||
log.Debugf("[socks5] %d %d %v", gosocks5.Ver5, len(methods), methods)
|
||||
}
|
||||
method = gosocks5.MethodNoAuth
|
||||
return
|
||||
}
|
||||
|
||||
func (selector *serverSelector) OnSelected(method uint8, conn net.Conn) (net.Conn, error) {
|
||||
if util.Debug {
|
||||
log.Debugf("[socks5] %d %d", gosocks5.Ver5, method)
|
||||
}
|
||||
switch method {
|
||||
case gosocks5.MethodNoAuth:
|
||||
log.Debugf("[socks5] server, no auth")
|
||||
return conn, nil
|
||||
case gosocks5.MethodNoAcceptable:
|
||||
return nil, gosocks5.ErrBadMethod
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
type socks5UDPTunConnector struct {
|
||||
type fakeUDPTunConnector struct {
|
||||
}
|
||||
|
||||
// SOCKS5UDPTunConnector creates a connector for SOCKS5 UDP-over-TCP relay.
|
||||
// It accepts an optional auth info for SOCKS5 Username/Password Authentication.
|
||||
func SOCKS5UDPTunConnector() Connector {
|
||||
return &socks5UDPTunConnector{}
|
||||
return &fakeUDPTunConnector{}
|
||||
}
|
||||
|
||||
func (c *socks5UDPTunConnector) ConnectContext(ctx context.Context, conn net.Conn, network, address string) (net.Conn, error) {
|
||||
func (c *fakeUDPTunConnector) ConnectContext(_ context.Context, conn net.Conn, network, address string) (net.Conn, error) {
|
||||
switch network {
|
||||
case "tcp", "tcp4", "tcp6":
|
||||
return nil, fmt.Errorf("%s unsupported", network)
|
||||
}
|
||||
conn.SetDeadline(time.Now().Add(util.ConnectTimeout))
|
||||
_ = conn.SetDeadline(time.Now().Add(util.ConnectTimeout))
|
||||
defer conn.SetDeadline(time.Time{})
|
||||
|
||||
targetAddr, _ := net.ResolveUDPAddr("udp", address)
|
||||
return newSocks5UDPTunnelConn(conn, nil, targetAddr)
|
||||
return newFakeUDPTunnelConnOverTcp(conn, targetAddr)
|
||||
}
|
||||
|
||||
type socks5Handler struct {
|
||||
selector *serverSelector
|
||||
type fakeUdpHandler struct {
|
||||
}
|
||||
|
||||
// SOCKS5Handler creates a server Handler for SOCKS5 proxy server.
|
||||
func SOCKS5Handler() Handler {
|
||||
h := &socks5Handler{}
|
||||
h := &fakeUdpHandler{}
|
||||
h.Init()
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *socks5Handler) Init(...HandlerOption) {
|
||||
h.selector = &serverSelector{}
|
||||
h.selector.AddMethod(
|
||||
gosocks5.MethodNoAuth,
|
||||
)
|
||||
func (h *fakeUdpHandler) Init(...HandlerOption) {
|
||||
}
|
||||
|
||||
func (h *socks5Handler) Handle(conn net.Conn) {
|
||||
func (h *fakeUdpHandler) Handle(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
|
||||
conn = gosocks5.ServerConn(conn, h.selector)
|
||||
req, err := gosocks5.ReadRequest(conn)
|
||||
if err != nil {
|
||||
log.Debugf("[socks5] %s -> %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||
return
|
||||
}
|
||||
|
||||
if util.Debug {
|
||||
log.Debugf("[socks5] %s -> %s\n%s", conn.RemoteAddr(), conn.LocalAddr(), req)
|
||||
}
|
||||
switch req.Cmd {
|
||||
case gosocks5.CmdUdp:
|
||||
h.handleUDPTunnel(conn, req)
|
||||
|
||||
default:
|
||||
log.Debugf("[socks5] %s - %s : Unrecognized request: %d", conn.RemoteAddr(), conn.LocalAddr(), req.Cmd)
|
||||
log.Debugf("[socks5] %s -> %s\n", conn.RemoteAddr(), conn.LocalAddr())
|
||||
}
|
||||
h.handleUDPTunnel(conn)
|
||||
}
|
||||
|
||||
func (h *socks5Handler) transportUDP(relay, peer net.PacketConn) (err error) {
|
||||
func (h *fakeUdpHandler) transportUDP(relay, peer net.PacketConn) (err error) {
|
||||
errc := make(chan error, 2)
|
||||
|
||||
var clientAddr net.Addr
|
||||
@@ -196,7 +109,7 @@ func (h *socks5Handler) transportUDP(relay, peer net.PacketConn) (err error) {
|
||||
}
|
||||
buf := bytes.Buffer{}
|
||||
dgram := gosocks5.NewUDPDatagram(gosocks5.NewUDPHeader(0, 0, toSocksAddr(raddr)), b[:n])
|
||||
dgram.Write(&buf)
|
||||
_ = dgram.Write(&buf)
|
||||
if _, err := relay.WriteTo(buf.Bytes(), clientAddr); err != nil {
|
||||
errc <- err
|
||||
return
|
||||
@@ -207,15 +120,10 @@ func (h *socks5Handler) transportUDP(relay, peer net.PacketConn) (err error) {
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case err = <-errc:
|
||||
//log.Println("w exit", err)
|
||||
}
|
||||
|
||||
return
|
||||
return <-errc
|
||||
}
|
||||
|
||||
func (h *socks5Handler) tunnelClientUDP(uc *net.UDPConn, cc net.Conn) (err error) {
|
||||
func (h *fakeUdpHandler) tunnelClientUDP(uc *net.UDPConn, cc net.Conn) (err error) {
|
||||
errc := make(chan error, 2)
|
||||
|
||||
var clientAddr *net.UDPAddr
|
||||
@@ -271,7 +179,7 @@ func (h *socks5Handler) tunnelClientUDP(uc *net.UDPConn, cc net.Conn) (err error
|
||||
dgram.Header.Rsv = 0
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
dgram.Write(&buf)
|
||||
_ = dgram.Write(&buf)
|
||||
if _, err := uc.WriteToUDP(buf.Bytes(), clientAddr); err != nil {
|
||||
errc <- err
|
||||
return
|
||||
@@ -282,42 +190,28 @@ func (h *socks5Handler) tunnelClientUDP(uc *net.UDPConn, cc net.Conn) (err error
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case err = <-errc:
|
||||
}
|
||||
|
||||
return
|
||||
return <-errc
|
||||
}
|
||||
|
||||
func (h *socks5Handler) handleUDPTunnel(conn net.Conn, req *gosocks5.Request) {
|
||||
func (h *fakeUdpHandler) handleUDPTunnel(conn net.Conn) {
|
||||
// serve tunnel udp, tunnel <-> remote, handle tunnel udp request
|
||||
addr := req.Addr.String()
|
||||
|
||||
bindAddr, _ := net.ResolveUDPAddr("udp", addr)
|
||||
bindAddr, _ := net.ResolveUDPAddr("udp", ":0")
|
||||
uc, err := net.ListenUDP("udp", bindAddr)
|
||||
if err != nil {
|
||||
log.Debugf("[socks5] udp-tun %s -> %s : %s", conn.RemoteAddr(), req.Addr, err)
|
||||
log.Debugf("[socks5] udp-tun %s -> %s : %s", conn.RemoteAddr(), bindAddr, err)
|
||||
return
|
||||
}
|
||||
defer uc.Close()
|
||||
|
||||
socksAddr := toSocksAddr(uc.LocalAddr())
|
||||
socksAddr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String())
|
||||
reply := gosocks5.NewReply(gosocks5.Succeeded, socksAddr)
|
||||
if err := reply.Write(conn); err != nil {
|
||||
log.Debugf("[socks5] udp-tun %s <- %s : %s", conn.RemoteAddr(), socksAddr, err)
|
||||
return
|
||||
}
|
||||
if util.Debug {
|
||||
log.Debugf("[socks5] udp-tun %s <- %s\n%s", conn.RemoteAddr(), socksAddr, reply)
|
||||
log.Debugf("[socks5] udp-tun %s <- %s\n", conn.RemoteAddr(), uc.LocalAddr())
|
||||
}
|
||||
log.Debugf("[socks5] udp-tun %s <-> %s", conn.RemoteAddr(), socksAddr)
|
||||
h.tunnelServerUDP(conn, uc)
|
||||
log.Debugf("[socks5] udp-tun %s >-< %s", conn.RemoteAddr(), socksAddr)
|
||||
log.Debugf("[socks5] udp-tun %s <-> %s", conn.RemoteAddr(), uc.LocalAddr())
|
||||
_ = h.tunnelServerUDP(conn, uc)
|
||||
log.Debugf("[socks5] udp-tun %s >-< %s", conn.RemoteAddr(), uc.LocalAddr())
|
||||
return
|
||||
}
|
||||
|
||||
func (h *socks5Handler) tunnelServerUDP(cc net.Conn, pc net.PacketConn) (err error) {
|
||||
func (h *fakeUdpHandler) tunnelServerUDP(cc net.Conn, pc net.PacketConn) (err error) {
|
||||
errc := make(chan error, 2)
|
||||
|
||||
go func() {
|
||||
@@ -333,8 +227,7 @@ func (h *socks5Handler) tunnelServerUDP(cc net.Conn, pc net.PacketConn) (err err
|
||||
}
|
||||
|
||||
// pipe from peer to tunnel
|
||||
dgram := gosocks5.NewUDPDatagram(
|
||||
gosocks5.NewUDPHeader(uint16(n), 0, toSocksAddr(addr)), b[:n])
|
||||
dgram := gosocks5.NewUDPDatagram(gosocks5.NewUDPHeader(uint16(n), 0, toSocksAddr(addr)), b[:n])
|
||||
if err := dgram.Write(cc); err != nil {
|
||||
log.Debugf("[socks5] udp-tun %s <- %s : %s", cc.RemoteAddr(), dgram.Header.Addr, err)
|
||||
errc <- err
|
||||
@@ -371,14 +264,9 @@ func (h *socks5Handler) tunnelServerUDP(cc net.Conn, pc net.PacketConn) (err err
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case err = <-errc:
|
||||
}
|
||||
|
||||
return
|
||||
return <-errc
|
||||
}
|
||||
|
||||
// TODO: support ipv6 and domain
|
||||
func toSocksAddr(addr net.Addr) *gosocks5.Addr {
|
||||
host := "0.0.0.0"
|
||||
port := 0
|
||||
@@ -394,71 +282,26 @@ func toSocksAddr(addr net.Addr) *gosocks5.Addr {
|
||||
}
|
||||
}
|
||||
|
||||
func socks5Handshake(conn net.Conn) (net.Conn, error) {
|
||||
cs := &clientSelector{}
|
||||
cs.AddMethod(
|
||||
gosocks5.MethodNoAuth,
|
||||
)
|
||||
|
||||
cc := gosocks5.ClientConn(conn, cs)
|
||||
if err := cc.Handleshake(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cc, nil
|
||||
}
|
||||
|
||||
// fake upd connect over tcp
|
||||
type socks5UDPTunnelConn struct {
|
||||
type fakeUDPTunnelConn struct {
|
||||
// tcp connection
|
||||
net.Conn
|
||||
targetAddr net.Addr
|
||||
}
|
||||
|
||||
func newSocks5UDPTunnelConn(conn net.Conn, serverAddr, targetAddr net.Addr) (net.Conn, error) {
|
||||
cc, err := socks5Handshake(conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := gosocks5.NewRequest(gosocks5.CmdUdp, toSocksAddr(serverAddr))
|
||||
if err := req.Write(cc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if util.Debug {
|
||||
log.Debug("[socks5] udp-tun", req)
|
||||
}
|
||||
|
||||
reply, err := gosocks5.ReadReply(cc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if util.Debug {
|
||||
log.Debug("[socks5] udp-tun", reply)
|
||||
}
|
||||
|
||||
if reply.Rep != gosocks5.Succeeded {
|
||||
return nil, errors.New("socks5 UDP tunnel failure")
|
||||
}
|
||||
|
||||
bindAddr, err := net.ResolveUDPAddr("udp", reply.Addr.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Debugf("[socks5] udp-tun associate on %s OK", bindAddr)
|
||||
|
||||
return &socks5UDPTunnelConn{
|
||||
Conn: cc,
|
||||
func newFakeUDPTunnelConnOverTcp(conn net.Conn, targetAddr net.Addr) (net.Conn, error) {
|
||||
return &fakeUDPTunnelConn{
|
||||
Conn: conn,
|
||||
targetAddr: targetAddr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *socks5UDPTunnelConn) Read(b []byte) (n int, err error) {
|
||||
func (c *fakeUDPTunnelConn) Read(b []byte) (n int, err error) {
|
||||
n, _, err = c.ReadFrom(b)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *socks5UDPTunnelConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
|
||||
func (c *fakeUDPTunnelConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
|
||||
dgram, err := gosocks5.ReadUDPDatagram(c.Conn)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -468,11 +311,11 @@ func (c *socks5UDPTunnelConn) ReadFrom(b []byte) (n int, addr net.Addr, err erro
|
||||
return
|
||||
}
|
||||
|
||||
func (c *socks5UDPTunnelConn) Write(b []byte) (n int, err error) {
|
||||
func (c *fakeUDPTunnelConn) Write(b []byte) (n int, err error) {
|
||||
return c.WriteTo(b, c.targetAddr)
|
||||
}
|
||||
|
||||
func (c *socks5UDPTunnelConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
|
||||
func (c *fakeUDPTunnelConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
|
||||
dgram := gosocks5.NewUDPDatagram(gosocks5.NewUDPHeader(uint16(len(b)), 0, toSocksAddr(addr)), b)
|
||||
if err = dgram.Write(c.Conn); err != nil {
|
||||
return
|
||||
|
||||
@@ -17,10 +17,8 @@ import (
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/client-go/util/homedir"
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
"net"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -28,10 +26,7 @@ import (
|
||||
|
||||
func TestCreateServer(t *testing.T) {
|
||||
clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
|
||||
&clientcmd.ClientConfigLoadingRules{
|
||||
ExplicitPath: clientcmd.RecommendedHomeFile,
|
||||
},
|
||||
nil,
|
||||
&clientcmd.ClientConfigLoadingRules{ExplicitPath: clientcmd.RecommendedHomeFile}, nil,
|
||||
)
|
||||
config, err := clientConfig.ClientConfig()
|
||||
if err != nil {
|
||||
@@ -66,10 +61,7 @@ func TestGetIp(t *testing.T) {
|
||||
|
||||
func TestGetIPFromDHCP(t *testing.T) {
|
||||
clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
|
||||
&clientcmd.ClientConfigLoadingRules{
|
||||
ExplicitPath: filepath.Join(homedir.HomeDir(), clientcmd.RecommendedHomeDir, clientcmd.RecommendedFileName),
|
||||
},
|
||||
nil,
|
||||
&clientcmd.ClientConfigLoadingRules{ExplicitPath: clientcmd.RecommendedHomeFile}, nil,
|
||||
)
|
||||
config, err := clientConfig.ClientConfig()
|
||||
if err != nil {
|
||||
@@ -80,13 +72,10 @@ func TestGetIPFromDHCP(t *testing.T) {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = InitDHCP(clientset, "test", nil)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
manager := NewDHCPManager(clientset, "test", nil)
|
||||
for i := 0; i < 10; i++ {
|
||||
ipNet, err := GetIpFromDHCP(clientset, "test")
|
||||
ipNet2, err := GetIpFromDHCP(clientset, "test")
|
||||
ipNet, err := manager.RentIPRandom()
|
||||
ipNet2, err := manager.RentIPRandom()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
continue
|
||||
@@ -94,8 +83,8 @@ func TestGetIPFromDHCP(t *testing.T) {
|
||||
fmt.Printf("%s->%s\n", ipNet.String(), ipNet2.String())
|
||||
}
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
err = ReleaseIpToDHCP(clientset, "test", ipNet)
|
||||
err = ReleaseIpToDHCP(clientset, "test", ipNet2)
|
||||
err = manager.ReleaseIpToDHCP(ipNet)
|
||||
err = manager.ReleaseIpToDHCP(ipNet2)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user