mirror of
https://github.com/kubenetworks/kubevpn.git
synced 2025-10-22 15:00:35 +08:00
feat: feat: optimize code and remove detect conflict interface
This commit is contained in:
3
go.mod
3
go.mod
@@ -12,7 +12,6 @@ require (
|
||||
github.com/milosgajdos/tenus v0.0.3
|
||||
github.com/moby/term v0.0.0-20221205130635-1aeaba878587
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/shadowsocks/go-shadowsocks2 v0.1.5
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8
|
||||
github.com/spf13/cobra v1.6.1
|
||||
@@ -88,13 +87,11 @@ require (
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||
github.com/rivo/uniseg v0.4.3 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/xlab/treeprint v1.1.0 // indirect
|
||||
go.starlark.net v0.0.0-20230112144946-fae38c8a6d89 // indirect
|
||||
golang.org/x/crypto v0.5.0 // indirect
|
||||
golang.org/x/mod v0.7.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/term v0.4.0 // indirect
|
||||
|
9
go.sum
9
go.sum
@@ -281,8 +281,6 @@ github.com/prometheus-community/pro-bing v0.1.0 h1:zjzLGhfNPP0bP1OlzGB+SJcguOViw
|
||||
github.com/prometheus-community/pro-bing v0.1.0/go.mod h1:BpWlHurD9flHtzq8wrh8QGWYz9ka9z9ZJAyOel8ej58=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw=
|
||||
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
@@ -293,8 +291,6 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
|
||||
github.com/schollz/progressbar/v3 v3.13.0 h1:9TeeWRcjW2qd05I8Kf9knPkW4vLM/hYoa6z9ABvxje8=
|
||||
github.com/schollz/progressbar/v3 v3.13.0/go.mod h1:ZBYnSuLAX2LU8P8UiKN/KgF2DY58AJC8yfVYLPC8Ly4=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/shadowsocks/go-shadowsocks2 v0.1.5 h1:PDSQv9y2S85Fl7VBeOMF9StzeXZyK1HakRm86CUbr28=
|
||||
github.com/shadowsocks/go-shadowsocks2 v0.1.5/go.mod h1:AGGpIoek4HRno4xzyFiAtLHkOpcoznZEkAccaI/rplM=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8=
|
||||
@@ -345,9 +341,6 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
|
||||
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -454,7 +447,6 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -486,7 +478,6 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg=
|
||||
|
@@ -3,10 +3,8 @@ package core
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"k8s.io/client-go/util/retry"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
@@ -18,34 +16,22 @@ type Server struct {
|
||||
func (s *Server) Serve(ctx context.Context) error {
|
||||
l := s.Listener
|
||||
defer l.Close()
|
||||
var tempDelay time.Duration
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
if err := retry.OnError(retry.DefaultBackoff, func(err error) bool { return err != nil }, l.Close); err != nil {
|
||||
log.Warnf("error while close listener, err: %v", err)
|
||||
}
|
||||
}()
|
||||
for ctx.Err() == nil {
|
||||
conn, e := l.Accept()
|
||||
if e != nil {
|
||||
if ne, ok := e.(net.Error); ok && ne.Timeout() {
|
||||
if tempDelay == 0 {
|
||||
tempDelay = 5 * time.Millisecond
|
||||
} else {
|
||||
tempDelay *= 2
|
||||
}
|
||||
if max := 1 * time.Second; tempDelay > max {
|
||||
tempDelay = max
|
||||
}
|
||||
log.Warnf("server: Accept error: %v; retrying in %v", e, tempDelay)
|
||||
time.Sleep(tempDelay)
|
||||
//go func() {
|
||||
// <-ctx.Done()
|
||||
// l.Close()
|
||||
//}()
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
default:
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
log.Warnf("server: accept error: %v", err)
|
||||
continue
|
||||
}
|
||||
return e
|
||||
go s.Handler.Handle(ctx, conn)
|
||||
}
|
||||
tempDelay = 0
|
||||
|
||||
go s.Handler.Handle(ctx, conn)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -7,8 +7,6 @@ import (
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/wencaiwulue/kubevpn/pkg/config"
|
||||
)
|
||||
|
||||
type fakeUDPTunnelConnector struct {
|
||||
@@ -33,19 +31,14 @@ func TCPHandler() Handler {
|
||||
|
||||
func (h *fakeUdpHandler) Handle(ctx context.Context, tcpConn net.Conn) {
|
||||
defer tcpConn.Close()
|
||||
if config.Debug {
|
||||
log.Debugf("[tcpserver] %s -> %s\n", tcpConn.RemoteAddr(), tcpConn.LocalAddr())
|
||||
}
|
||||
log.Debugf("[tcpserver] %s -> %s\n", tcpConn.RemoteAddr(), tcpConn.LocalAddr())
|
||||
// serve tunnel udp, tunnel <-> remote, handle tunnel udp request
|
||||
udpConn, err := net.DialUDP("udp", nil, Server8422)
|
||||
if err != nil {
|
||||
log.Debugf("[tcpserver] udp-tun %s -> %s : %s", tcpConn.RemoteAddr(), udpConn.LocalAddr(), err)
|
||||
log.Errorf("[tcpserver] udp-tun %s -> %s : %s", tcpConn.RemoteAddr(), udpConn.LocalAddr(), err)
|
||||
return
|
||||
}
|
||||
defer udpConn.Close()
|
||||
if config.Debug {
|
||||
log.Debugf("[tcpserver] udp-tun %s <- %s\n", tcpConn.RemoteAddr(), udpConn.LocalAddr())
|
||||
}
|
||||
log.Debugf("[tcpserver] udp-tun %s <-> %s", tcpConn.RemoteAddr(), udpConn.LocalAddr())
|
||||
_ = h.tunnelServerUDP(tcpConn, udpConn)
|
||||
log.Debugf("[tcpserver] udp-tun %s >-< %s", tcpConn.RemoteAddr(), udpConn.LocalAddr())
|
||||
@@ -73,9 +66,7 @@ func (h *fakeUdpHandler) tunnelServerUDP(tcpConn net.Conn, udpConn *net.UDPConn)
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
if config.Debug {
|
||||
log.Debugf("[tcpserver] udp-tun %s >>> %s length: %d", tcpConn.RemoteAddr(), Server8422, len(dgram.Data))
|
||||
}
|
||||
log.Debugf("[tcpserver] udp-tun %s >>> %s length: %d", tcpConn.RemoteAddr(), Server8422, len(dgram.Data))
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -98,9 +89,7 @@ func (h *fakeUdpHandler) tunnelServerUDP(tcpConn net.Conn, udpConn *net.UDPConn)
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
if config.Debug {
|
||||
log.Debugf("[tcpserver] udp-tun %s <<< %s length: %d", tcpConn.RemoteAddr(), dgram.Addr(), len(dgram.Data))
|
||||
}
|
||||
log.Debugf("[tcpserver] udp-tun %s <<< %s length: %d", tcpConn.RemoteAddr(), dgram.Addr(), len(dgram.Data))
|
||||
}
|
||||
}()
|
||||
return <-errChan
|
||||
@@ -141,17 +130,3 @@ func (c *fakeUDPTunnelConn) WriteTo(b []byte, _ net.Addr) (int, error) {
|
||||
func (c *fakeUDPTunnelConn) Close() error {
|
||||
return c.Conn.Close()
|
||||
}
|
||||
|
||||
func (c *fakeUDPTunnelConn) CloseWrite() error {
|
||||
if cc, ok := c.Conn.(interface{ CloseWrite() error }); ok {
|
||||
return cc.CloseWrite()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *fakeUDPTunnelConn) CloseRead() error {
|
||||
if cc, ok := c.Conn.(interface{ CloseRead() error }); ok {
|
||||
return cc.CloseRead()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -3,21 +3,17 @@ package core
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/shadowsocks/go-shadowsocks2/shadowaead"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/songgao/water/waterutil"
|
||||
"golang.org/x/net/ipv4"
|
||||
"golang.org/x/net/ipv6"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"github.com/wencaiwulue/kubevpn/pkg/config"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/songgao/water/waterutil"
|
||||
)
|
||||
|
||||
func ipToTunRouteKey(ip net.IP) string {
|
||||
return ip.To16().String()
|
||||
return ip.String()
|
||||
}
|
||||
|
||||
type tunHandler struct {
|
||||
@@ -37,71 +33,55 @@ func TunHandler(chain *Chain, node *Node) Handler {
|
||||
}
|
||||
}
|
||||
|
||||
func (h *tunHandler) Handle(ctx context.Context, conn net.Conn) {
|
||||
defer conn.Close()
|
||||
func (h *tunHandler) Handle(ctx context.Context, tun net.Conn) {
|
||||
defer tun.Close()
|
||||
var err error
|
||||
var raddr net.Addr
|
||||
var remoteAddr net.Addr
|
||||
if addr := h.node.Remote; addr != "" {
|
||||
raddr, err = net.ResolveUDPAddr("udp", addr)
|
||||
remoteAddr, err = net.ResolveUDPAddr("udp", addr)
|
||||
if err != nil {
|
||||
log.Debugf("[tun] %s: remote addr: %v", conn.LocalAddr(), err)
|
||||
log.Errorf("[tun] %s: remote addr: %v", tun.LocalAddr(), err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var tempDelay time.Duration
|
||||
for ctx.Err() == nil {
|
||||
for {
|
||||
err = func() error {
|
||||
var err error
|
||||
var pc net.PacketConn
|
||||
if raddr != nil && !h.chain.IsEmpty() {
|
||||
var packetConn net.PacketConn
|
||||
if remoteAddr != nil && !h.chain.IsEmpty() {
|
||||
cc, err := h.chain.DialContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var ok bool
|
||||
pc, ok = cc.(net.PacketConn)
|
||||
packetConn, ok = cc.(net.PacketConn)
|
||||
if !ok {
|
||||
err = errors.New("not a packet connection")
|
||||
log.Debugf("[tun] %s - %s: %s", conn.LocalAddr(), raddr, err)
|
||||
log.Errorf("[tun] %s - %s: %s", tun.LocalAddr(), remoteAddr, err)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
laddr, _ := net.ResolveUDPAddr("udp", h.node.Addr)
|
||||
pc, err = net.ListenUDP("udp", laddr)
|
||||
var lc net.ListenConfig
|
||||
packetConn, err = lc.ListenPacket(ctx, "udp", h.node.Addr)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return h.transportTun(ctx, conn, pc, raddr)
|
||||
return h.transportTun(ctx, tun, packetConn, remoteAddr)
|
||||
}()
|
||||
if err != nil {
|
||||
log.Debugf("[tun] %s: %v", conn.LocalAddr(), err)
|
||||
log.Debugf("[tun] %s: %v", tun.LocalAddr(), err)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-h.chExit:
|
||||
return
|
||||
case <-ctx.Done():
|
||||
h.chExit <- struct{}{}
|
||||
return
|
||||
default:
|
||||
log.Debugf("next loop, err: %v", err)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if tempDelay == 0 {
|
||||
tempDelay = 1000 * time.Millisecond
|
||||
} else {
|
||||
tempDelay *= 2
|
||||
}
|
||||
if max := 6 * time.Second; tempDelay > max {
|
||||
tempDelay = max
|
||||
}
|
||||
time.Sleep(tempDelay)
|
||||
continue
|
||||
}
|
||||
tempDelay = 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,24 +99,17 @@ func (h *tunHandler) findRouteFor(dst net.IP) net.Addr {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *tunHandler) transportTun(ctx context.Context, tun net.Conn, conn net.PacketConn, raddr net.Addr) error {
|
||||
func (h *tunHandler) transportTun(ctx context.Context, tun net.Conn, conn net.PacketConn, remoteAddr net.Addr) error {
|
||||
errChan := make(chan error, 2)
|
||||
defer func() {
|
||||
if c, ok := conn.(interface{ CloseRead() error }); ok {
|
||||
_ = c.CloseRead()
|
||||
}
|
||||
if c, ok := conn.(interface{ CloseWrite() error }); ok {
|
||||
_ = c.CloseWrite()
|
||||
}
|
||||
_ = conn.Close()
|
||||
}()
|
||||
defer conn.Close()
|
||||
go func() {
|
||||
b := SPool.Get().([]byte)
|
||||
defer SPool.Put(b)
|
||||
offset := 8
|
||||
|
||||
for ctx.Err() == nil {
|
||||
for {
|
||||
err := func() error {
|
||||
n, err := tun.Read(b[:])
|
||||
n, err := tun.Read(b[offset:])
|
||||
if err != nil {
|
||||
select {
|
||||
case h.chExit <- struct{}{}:
|
||||
@@ -146,8 +119,8 @@ func (h *tunHandler) transportTun(ctx context.Context, tun net.Conn, conn net.Pa
|
||||
}
|
||||
|
||||
// client side, deliver packet directly.
|
||||
if raddr != nil {
|
||||
_, err = conn.WriteTo(b[:n], raddr)
|
||||
if remoteAddr != nil {
|
||||
_, err = conn.WriteTo(b[:n], remoteAddr)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -155,25 +128,21 @@ func (h *tunHandler) transportTun(ctx context.Context, tun net.Conn, conn net.Pa
|
||||
if waterutil.IsIPv4(b[:n]) {
|
||||
header, err := ipv4.ParseHeader(b[:n])
|
||||
if err != nil {
|
||||
log.Debugf("[tun] %s: %v", tun.LocalAddr(), err)
|
||||
log.Errorf("[tun] %s: %v", tun.LocalAddr(), err)
|
||||
return nil
|
||||
}
|
||||
if config.Debug {
|
||||
log.Debugf("[tun] %s", header.String())
|
||||
}
|
||||
log.Debugf("[tun] %s", header.String())
|
||||
src, dst = header.Src, header.Dst
|
||||
} else if waterutil.IsIPv6(b[:n]) {
|
||||
header, err := ipv6.ParseHeader(b[:n])
|
||||
if err != nil {
|
||||
log.Debugf("[tun] %s: %v", tun.LocalAddr(), err)
|
||||
log.Errorf("[tun] %s: %v", tun.LocalAddr(), err)
|
||||
return nil
|
||||
}
|
||||
if config.Debug {
|
||||
log.Debugf("[tun] %s", header.String())
|
||||
}
|
||||
log.Debugf("[tun] %s", header.String())
|
||||
src, dst = header.Src, header.Dst
|
||||
} else {
|
||||
log.Debugf("[tun] unknown packet")
|
||||
log.Errorf("[tun] unknown packet")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -183,15 +152,16 @@ func (h *tunHandler) transportTun(ctx context.Context, tun net.Conn, conn net.Pa
|
||||
return nil
|
||||
}
|
||||
|
||||
if config.Debug {
|
||||
log.Debugf("[tun] find route: %s -> %s", dst, addr)
|
||||
}
|
||||
log.Debugf("[tun] find route: %s -> %s", dst, addr)
|
||||
_, err = conn.WriteTo(b[:n], addr)
|
||||
return err
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
select {
|
||||
case errChan <- err:
|
||||
default:
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -201,15 +171,15 @@ func (h *tunHandler) transportTun(ctx context.Context, tun net.Conn, conn net.Pa
|
||||
b := LPool.Get().([]byte)
|
||||
defer LPool.Put(b)
|
||||
|
||||
for ctx.Err() == nil {
|
||||
for {
|
||||
err := func() error {
|
||||
n, addr, err := conn.ReadFrom(b[:])
|
||||
if err != nil && err != shadowaead.ErrShortPacket {
|
||||
n, srcAddr, err := conn.ReadFrom(b[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// client side, deliver packet to tun device.
|
||||
if raddr != nil {
|
||||
if remoteAddr != nil {
|
||||
_, err = tun.Write(b[:n])
|
||||
return err
|
||||
}
|
||||
@@ -218,42 +188,36 @@ func (h *tunHandler) transportTun(ctx context.Context, tun net.Conn, conn net.Pa
|
||||
if waterutil.IsIPv4(b[:n]) {
|
||||
header, err := ipv4.ParseHeader(b[:n])
|
||||
if err != nil {
|
||||
log.Debugf("[tun] %s: %v", tun.LocalAddr(), err)
|
||||
log.Errorf("[tun] %s: %v", tun.LocalAddr(), err)
|
||||
return nil
|
||||
}
|
||||
if config.Debug {
|
||||
log.Debugf("[tun] %s", header.String())
|
||||
}
|
||||
log.Debugf("[tun] %s", header.String())
|
||||
src, dst = header.Src, header.Dst
|
||||
} else if waterutil.IsIPv6(b[:n]) {
|
||||
header, err := ipv6.ParseHeader(b[:n])
|
||||
if err != nil {
|
||||
log.Debugf("[tun] %s: %v", tun.LocalAddr(), err)
|
||||
log.Errorf("[tun] %s: %v", tun.LocalAddr(), err)
|
||||
return nil
|
||||
}
|
||||
if config.Debug {
|
||||
log.Debugf("[tun] %s", header.String())
|
||||
}
|
||||
log.Debugf("[tun] %s", header.String())
|
||||
src, dst = header.Src, header.Dst
|
||||
} else {
|
||||
log.Debugf("[tun] unknown packet")
|
||||
log.Errorf("[tun] unknown packet")
|
||||
return nil
|
||||
}
|
||||
|
||||
routeKey := ipToTunRouteKey(src)
|
||||
if actual, loaded := h.routes.LoadOrStore(routeKey, addr); loaded {
|
||||
if actual.(net.Addr).String() != addr.String() {
|
||||
log.Debugf("[tun] update route: %s -> %s (old %s)", src, addr, actual.(net.Addr))
|
||||
h.routes.Store(routeKey, addr)
|
||||
if actual, loaded := h.routes.LoadOrStore(routeKey, srcAddr); loaded {
|
||||
if actual.(net.Addr).String() != srcAddr.String() {
|
||||
log.Debugf("[tun] update route: %s -> %s (old %s)", src, srcAddr, actual.(net.Addr))
|
||||
h.routes.Store(routeKey, srcAddr)
|
||||
}
|
||||
} else {
|
||||
log.Debugf("[tun] new route: %s -> %s", src, addr)
|
||||
log.Debugf("[tun] new route: %s -> %s", src, srcAddr)
|
||||
}
|
||||
|
||||
if routeToAddr := h.findRouteFor(dst); routeToAddr != nil {
|
||||
if config.Debug {
|
||||
log.Debugf("[tun] find route: %s -> %s", dst, routeToAddr)
|
||||
}
|
||||
log.Debugf("[tun] find route: %s -> %s", dst, routeToAddr)
|
||||
_, err = conn.WriteTo(b[:n], routeToAddr)
|
||||
return err
|
||||
}
|
||||
@@ -269,7 +233,10 @@ func (h *tunHandler) transportTun(ctx context.Context, tun net.Conn, conn net.Pa
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
select {
|
||||
case errChan <- err:
|
||||
default:
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@@ -4,11 +4,11 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/types"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
@@ -30,7 +30,6 @@ import (
|
||||
"github.com/wencaiwulue/kubevpn/pkg/config"
|
||||
"github.com/wencaiwulue/kubevpn/pkg/core"
|
||||
"github.com/wencaiwulue/kubevpn/pkg/dns"
|
||||
"github.com/wencaiwulue/kubevpn/pkg/route"
|
||||
"github.com/wencaiwulue/kubevpn/pkg/tun"
|
||||
"github.com/wencaiwulue/kubevpn/pkg/util"
|
||||
)
|
||||
@@ -133,7 +132,6 @@ func (c *ConnectOptions) DoConnect() (err error) {
|
||||
c.deleteFirewallRule(ctx)
|
||||
c.setupDNS()
|
||||
log.Info("dns service ok")
|
||||
//c.detectConflictDevice()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -144,7 +142,7 @@ func (c *ConnectOptions) portForward(ctx context.Context, port string) error {
|
||||
podInterface := c.clientset.CoreV1().Pods(c.Namespace)
|
||||
go func() {
|
||||
var first = pointer.Bool(true)
|
||||
for ctx.Err() == nil {
|
||||
for {
|
||||
func() {
|
||||
podList, err := c.GetRunningPodList()
|
||||
if err != nil {
|
||||
@@ -261,7 +259,7 @@ func (c *ConnectOptions) startLocalTunServe(ctx context.Context, forwardAddress
|
||||
|
||||
// Listen all pod, add route if needed
|
||||
func (c *ConnectOptions) addRouteDynamic(ctx context.Context) {
|
||||
for ctx.Err() == nil {
|
||||
for {
|
||||
func() {
|
||||
w, err := c.clientset.CoreV1().Pods(v1.NamespaceAll).Watch(ctx, metav1.ListOptions{Watch: true, TimeoutSeconds: pointer.Int64(30)})
|
||||
if err != nil {
|
||||
@@ -299,7 +297,7 @@ func (c *ConnectOptions) addRouteDynamic(ctx context.Context) {
|
||||
return
|
||||
}
|
||||
}
|
||||
err := tun.AddRoutes(tun.IPRoute{Dest: &net.IPNet{IP: net.ParseIP(ip), Mask: net.CIDRMask(32, 32)}})
|
||||
err := tun.AddRoutes(types.Route{Dst: net.IPNet{IP: net.ParseIP(ip), Mask: net.CIDRMask(32, 32)}})
|
||||
if err != nil {
|
||||
log.Debugf("[route] add route failed, pod: %s, ip: %s,err: %v", name, ip, err)
|
||||
} else {
|
||||
@@ -323,16 +321,6 @@ func (c *ConnectOptions) deleteFirewallRule(ctx context.Context) {
|
||||
go util.Heartbeats(ctx)
|
||||
}
|
||||
|
||||
func (c *ConnectOptions) detectConflictDevice() {
|
||||
tunName := os.Getenv(config.EnvTunNameOrLUID)
|
||||
if len(tunName) == 0 {
|
||||
return
|
||||
}
|
||||
if err := route.DetectAndDisableConflictDevice(tunName); err != nil {
|
||||
log.Warnf("error occours while disable conflict devices, err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ConnectOptions) setupDNS() {
|
||||
const port = 53
|
||||
pod, err := c.GetRunningPodList()
|
||||
|
@@ -148,7 +148,6 @@ func TestPatchAnnotation(t *testing.T) {
|
||||
|
||||
func TestPing(t *testing.T) {
|
||||
ip := "10.233.98.197"
|
||||
ping, _ := Ping(ip)
|
||||
pinger, err := probing.NewPinger(ip)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -159,5 +158,5 @@ func TestPing(t *testing.T) {
|
||||
panic(err)
|
||||
}
|
||||
stats := pinger.Statistics() // get send/receive/duplicate/rtt stats
|
||||
fmt.Println(ping)
|
||||
fmt.Println(stats)
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/types"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/wencaiwulue/kubevpn/pkg/config"
|
||||
@@ -12,6 +13,10 @@ import (
|
||||
"github.com/wencaiwulue/kubevpn/pkg/tun"
|
||||
)
|
||||
|
||||
// Route example:
|
||||
// -L "tcp://:10800" -L "tun://:8422?net=223.254.0.100/16"
|
||||
// -L "tun:/10.233.24.133:8422?net=223.254.0.102/16&route=223.254.0.0/16"
|
||||
// -L "tun:/127.0.0.1:8422?net=223.254.0.102/16&route=223.254.0.0/16,10.233.0.0/16" -F "tcp://127.0.0.1:10800"
|
||||
type Route struct {
|
||||
ServeNodes []string // -L tun
|
||||
ChainNode string // -F tcp
|
||||
@@ -78,7 +83,7 @@ func (r *Route) GenerateServers() ([]core.Server, error) {
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
func parseIPRoutes(routeStringList string) (routes []tun.IPRoute) {
|
||||
func parseIPRoutes(routeStringList string) (routes []types.Route) {
|
||||
if len(routeStringList) == 0 {
|
||||
return
|
||||
}
|
||||
@@ -86,7 +91,7 @@ func parseIPRoutes(routeStringList string) (routes []tun.IPRoute) {
|
||||
routeList := strings.Split(routeStringList, ",")
|
||||
for _, route := range routeList {
|
||||
if _, ipNet, _ := net.ParseCIDR(strings.TrimSpace(route)); ipNet != nil {
|
||||
routes = append(routes, tun.IPRoute{Dest: ipNet})
|
||||
routes = append(routes, types.Route{Dst: *ipNet})
|
||||
}
|
||||
}
|
||||
return
|
||||
|
@@ -1,57 +0,0 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
// DetectAndDisableConflictDevice will detect conflict route table and try to disable device
|
||||
// 1, get route table
|
||||
// 2, detect conflict
|
||||
// 3, disable device
|
||||
func DetectAndDisableConflictDevice(origin string) error {
|
||||
routeTable, err := GetRouteTable()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conflict := detectConflictDevice(origin, routeTable)
|
||||
if len(conflict) != 0 {
|
||||
log.Infof("those device: %s will to be disabled because of route conflict with %s", strings.Join(conflict, ","), origin)
|
||||
}
|
||||
err = DisableDevice(conflict)
|
||||
return err
|
||||
}
|
||||
|
||||
func detectConflictDevice(origin string, routeTable map[string][]*net.IPNet) []string {
|
||||
var conflict = sets.NewString()
|
||||
vpnRoute := routeTable[origin]
|
||||
for k, originRoute := range routeTable {
|
||||
if k == origin {
|
||||
continue
|
||||
}
|
||||
out:
|
||||
for _, originNet := range originRoute {
|
||||
for _, vpnNet := range vpnRoute {
|
||||
// like 255.255.0.0/16 should not take effect
|
||||
if bytes.Equal(originNet.IP, originNet.Mask) || bytes.Equal(vpnNet.IP, vpnNet.Mask) {
|
||||
continue
|
||||
}
|
||||
if vpnNet.Contains(originNet.IP) || originNet.Contains(vpnNet.IP) {
|
||||
originMask, _ := originNet.Mask.Size()
|
||||
vpnMask, _ := vpnNet.Mask.Size()
|
||||
// means interface: k is more precisely, traffic will go to interface k because route table feature
|
||||
// mare precisely is preferred
|
||||
if originMask > vpnMask {
|
||||
conflict.Insert(k)
|
||||
break out
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return conflict.Delete(origin).List()
|
||||
}
|
@@ -1,156 +0,0 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/net/route"
|
||||
)
|
||||
|
||||
// netstat -anr | grep 10.61
|
||||
//10.61/16 utun4 USc utun4
|
||||
//10.61.10.251 10.176.32.40 UGHWIig utun2
|
||||
//10.61.64/18 10.61.64.1 UCS utun3
|
||||
//10.61.64.1 10.61.64.0 UH utun3
|
||||
func TestConflict(t *testing.T) {
|
||||
var mm = make(map[string][]*net.IPNet)
|
||||
_, ipNet, err := net.ParseCIDR("10.61.0.0/16")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, ipNet2, err := net.ParseCIDR("10.61.64.0/18")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, ipNet3, err := net.ParseCIDR("10.61.64.1/24")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
mm["utun4"] = []*net.IPNet{ipNet}
|
||||
mm["utun3"] = []*net.IPNet{ipNet2, ipNet3}
|
||||
|
||||
var origin = "utun4"
|
||||
conflict := detectConflictDevice(origin, mm)
|
||||
fmt.Println(conflict)
|
||||
}
|
||||
|
||||
func TestGetConflictDevice(t *testing.T) {
|
||||
err := DetectAndDisableConflictDevice("utun2")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
rib, err := route.FetchRIB(syscall.AF_INET, syscall.NET_RT_DUMP, 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
msgs, err := route.ParseRIB(syscall.NET_RT_DUMP, rib)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
nameToIndex := make(map[int]string)
|
||||
addrs, err := net.Interfaces()
|
||||
for _, addr := range addrs {
|
||||
nameToIndex[addr.Index] = addr.Name
|
||||
}
|
||||
|
||||
m := make(map[string][]route.Addr)
|
||||
for _, msg := range msgs {
|
||||
message := msg.(*route.RouteMessage)
|
||||
if name, found := nameToIndex[message.Index]; found {
|
||||
if v, ok := m[name]; ok {
|
||||
temp := removeEmptyElement(message)
|
||||
m[name] = append(v, temp...)
|
||||
} else {
|
||||
m[name] = removeEmptyElement(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println(m)
|
||||
}
|
||||
|
||||
func removeEmptyElement(message *route.RouteMessage) []route.Addr {
|
||||
var temp []route.Addr
|
||||
for _, addr := range message.Addrs {
|
||||
if addr != nil {
|
||||
temp = append(temp, addr)
|
||||
}
|
||||
}
|
||||
return temp
|
||||
}
|
||||
|
||||
func TestGetRouteTableByNetstat(t *testing.T) {
|
||||
ip := net.ParseIP("192.168.1.1")
|
||||
for i := range ip.To4() {
|
||||
fmt.Println(i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInteract(t *testing.T) {
|
||||
type data struct {
|
||||
ipNet1 *net.IPNet
|
||||
ipNet2 *net.IPNet
|
||||
result bool
|
||||
}
|
||||
var list = []data{{
|
||||
ipNet1: &net.IPNet{
|
||||
IP: net.ParseIP("192.168.1.1"),
|
||||
Mask: net.CIDRMask(24, 32),
|
||||
},
|
||||
ipNet2: &net.IPNet{
|
||||
IP: net.ParseIP("192.168.100.100"),
|
||||
Mask: net.CIDRMask(16, 32),
|
||||
},
|
||||
result: true,
|
||||
}, {
|
||||
ipNet1: &net.IPNet{
|
||||
IP: net.ParseIP("192.168.0.0"),
|
||||
Mask: net.CIDRMask(17, 32),
|
||||
},
|
||||
ipNet2: &net.IPNet{
|
||||
IP: net.ParseIP("192.168.0.0"),
|
||||
Mask: net.CIDRMask(16, 32),
|
||||
},
|
||||
result: true,
|
||||
}, {
|
||||
ipNet1: &net.IPNet{
|
||||
IP: net.ParseIP("191.168.0.0"),
|
||||
Mask: net.CIDRMask(17, 32),
|
||||
},
|
||||
ipNet2: &net.IPNet{
|
||||
IP: net.ParseIP("192.168.0.0"),
|
||||
Mask: net.CIDRMask(16, 32),
|
||||
},
|
||||
result: false,
|
||||
}, {
|
||||
ipNet1: &net.IPNet{
|
||||
IP: net.ParseIP("255.255.255.0"),
|
||||
Mask: net.CIDRMask(24, 32),
|
||||
},
|
||||
ipNet2: &net.IPNet{
|
||||
IP: net.ParseIP("255.255.0.0"),
|
||||
Mask: net.CIDRMask(16, 32),
|
||||
},
|
||||
result: true,
|
||||
}, {
|
||||
ipNet1: &net.IPNet{
|
||||
IP: net.ParseIP("255.255.255.255"),
|
||||
Mask: net.CIDRMask(32, 32),
|
||||
},
|
||||
ipNet2: &net.IPNet{
|
||||
IP: net.ParseIP("255.255.0.0"),
|
||||
Mask: net.CIDRMask(16, 32),
|
||||
},
|
||||
result: false,
|
||||
}}
|
||||
for _, d := range list {
|
||||
if b := d.ipNet1.Contains(d.ipNet2.IP) || d.ipNet2.Contains(d.ipNet1.IP); d.result != b {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,99 +0,0 @@
|
||||
//go:build !amd64 && !arm64 && !x86 && !386
|
||||
// +build !amd64,!arm64,!x86,!386
|
||||
|
||||
package route
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/net/route"
|
||||
)
|
||||
|
||||
// not contains route like 10.61.64/18 10.61.64.1 UCS utun3, todo how about pull a merge to golang sdk???
|
||||
// just contains 10.61.64, which mask is 0, 8, 16, 32, do not middle number
|
||||
func getRouteTableByFetchRIB() (map[string][]*net.IPNet, error) {
|
||||
rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_DUMP, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msgs, err := route.ParseRIB(syscall.NET_RT_DUMP, rib)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nameToIndex := make(map[int]string)
|
||||
addrs, err := net.Interfaces()
|
||||
for _, addr := range addrs {
|
||||
nameToIndex[addr.Index] = addr.Name
|
||||
}
|
||||
|
||||
m := make(map[string][]route.Addr)
|
||||
for _, msg := range msgs {
|
||||
message := msg.(*route.RouteMessage)
|
||||
if name, found := nameToIndex[message.Index]; found {
|
||||
if v, ok := m[name]; ok {
|
||||
temp := removeNilElement(message)
|
||||
m[name] = append(v, temp...)
|
||||
} else {
|
||||
m[name] = removeNilElement(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
var mm = make(map[string][]*net.IPNet)
|
||||
for k, v := range m {
|
||||
var temp []*net.IPNet
|
||||
for _, addr := range v {
|
||||
if a, ok := addr.(*route.Inet4Addr); ok {
|
||||
var ip = make(net.IP, net.IPv4len)
|
||||
copy(ip, a.IP[:])
|
||||
if one, _ := mask(ip).Size(); one == 0 {
|
||||
continue
|
||||
}
|
||||
temp = append(temp, &net.IPNet{IP: ip, Mask: mask(ip)})
|
||||
} else if a, ok := addr.(*route.Inet6Addr); ok {
|
||||
var ip = make(net.IP, net.IPv6len)
|
||||
copy(ip, a.IP[:])
|
||||
if one, _ := mask(ip).Size(); one == 0 {
|
||||
continue
|
||||
}
|
||||
temp = append(temp, &net.IPNet{IP: ip, Mask: mask(ip)})
|
||||
} else if _, ok := addr.(*route.LinkAddr); ok {
|
||||
//fmt.Println(a)
|
||||
// todo
|
||||
}
|
||||
}
|
||||
mm[k] = temp
|
||||
}
|
||||
return mm, nil
|
||||
}
|
||||
|
||||
func removeNilElement(message *route.RouteMessage) []route.Addr {
|
||||
var temp []route.Addr
|
||||
for _, addr := range message.Addrs {
|
||||
if addr != nil {
|
||||
temp = append(temp, addr)
|
||||
}
|
||||
}
|
||||
return temp
|
||||
}
|
||||
|
||||
// route.FetchRIB fetches a routing information base from the operating system.
|
||||
// In most cases, zero means a wildcard.
|
||||
func mask(ip []byte) net.IPMask {
|
||||
size := 0
|
||||
for i := len(ip) - 1; i >= 0; i-- {
|
||||
if ip[i] == 0 {
|
||||
size++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
// 0.0.0.0
|
||||
if size == len(ip) {
|
||||
return net.CIDRMask(len(ip)*8, len(ip)*8)
|
||||
}
|
||||
if size == 0 {
|
||||
return net.CIDRMask(0, len(ip)*8)
|
||||
}
|
||||
return net.CIDRMask((len(ip)-size)*8, len(ip)*8)
|
||||
}
|
@@ -1,264 +0,0 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package route
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// sudo ifconfig utun3 down
|
||||
func DisableDevice(conflict []string) error {
|
||||
for _, dev := range conflict {
|
||||
if err := exec.Command("sudo", "ifconfig", dev, "down").Run(); err != nil {
|
||||
log.Errorf("can not disable interface: %s, err: %v", dev, err)
|
||||
return err
|
||||
} else {
|
||||
// todo: optimize it
|
||||
//handler.RollbackFuncList = append(handler.RollbackFuncList, func() {
|
||||
// _ = exec.Command("sudo", "ifconfig", dev, "up").Run()
|
||||
//})
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetRouteTable() (map[string][]*net.IPNet, error) {
|
||||
output, err := exec.Command("netstat", "-anr").CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
split := strings.Split(string(output), "\n")
|
||||
routeTable := make(map[string][]*net.IPNet)
|
||||
for _, i := range split {
|
||||
fields := strings.Fields(i)
|
||||
if len(fields) >= 4 {
|
||||
cidr := fields[0]
|
||||
eth := fields[3]
|
||||
if _, ipNet, err := parseCIDR(cidr); err == nil {
|
||||
if v, ok := routeTable[eth]; ok {
|
||||
routeTable[eth] = append(v, ipNet)
|
||||
} else {
|
||||
routeTable[eth] = []*net.IPNet{ipNet}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return routeTable, nil
|
||||
}
|
||||
|
||||
const big = 0xFFFFFF
|
||||
|
||||
// Decimal to integer.
|
||||
// Returns number, characters consumed, success.
|
||||
func dtoi(s string) (n int, i int, ok bool) {
|
||||
n = 0
|
||||
for i = 0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
|
||||
n = n*10 + int(s[i]-'0')
|
||||
if n >= big {
|
||||
return big, i, false
|
||||
}
|
||||
}
|
||||
if i == 0 {
|
||||
return 0, 0, false
|
||||
}
|
||||
return n, i, true
|
||||
}
|
||||
|
||||
// Hexadecimal to integer.
|
||||
// Returns number, characters consumed, success.
|
||||
func xtoi(s string) (n int, i int, ok bool) {
|
||||
n = 0
|
||||
for i = 0; i < len(s); i++ {
|
||||
if '0' <= s[i] && s[i] <= '9' {
|
||||
n *= 16
|
||||
n += int(s[i] - '0')
|
||||
} else if 'a' <= s[i] && s[i] <= 'f' {
|
||||
n *= 16
|
||||
n += int(s[i]-'a') + 10
|
||||
} else if 'A' <= s[i] && s[i] <= 'F' {
|
||||
n *= 16
|
||||
n += int(s[i]-'A') + 10
|
||||
} else {
|
||||
break
|
||||
}
|
||||
if n >= big {
|
||||
return 0, i, false
|
||||
}
|
||||
}
|
||||
if i == 0 {
|
||||
return 0, i, false
|
||||
}
|
||||
return n, i, true
|
||||
}
|
||||
|
||||
func parseCIDR(s string) (net.IP, *net.IPNet, error) {
|
||||
indexByte6 := strings.Count(s, ":")
|
||||
indexByte4 := strings.Count(s, ".")
|
||||
if indexByte4 < 0 && indexByte6 < 0 {
|
||||
return nil, nil, &net.ParseError{Type: "CIDR address", Text: s}
|
||||
}
|
||||
|
||||
i := strings.IndexByte(s, '/')
|
||||
var addr, mask string
|
||||
if i < 0 {
|
||||
addr = s
|
||||
// ipv6
|
||||
if indexByte6 > 0 {
|
||||
mask = strconv.Itoa((indexByte6 + 1) * 8)
|
||||
} else {
|
||||
mask = strconv.Itoa((indexByte4 + 1) * 8)
|
||||
}
|
||||
} else {
|
||||
addr, mask = s[:i], s[i+1:]
|
||||
}
|
||||
iplen := net.IPv4len
|
||||
ip := parseIPv4(addr)
|
||||
if ip == nil {
|
||||
iplen = net.IPv6len
|
||||
ip = parseIPv6(addr)
|
||||
}
|
||||
n, i, ok := dtoi(mask)
|
||||
if ip == nil || !ok || i != len(mask) || n < 0 || n > 8*iplen {
|
||||
return nil, nil, &net.ParseError{Type: "CIDR address", Text: s}
|
||||
}
|
||||
m := net.CIDRMask(n, 8*iplen)
|
||||
return ip, &net.IPNet{IP: ip.Mask(m), Mask: m}, nil
|
||||
}
|
||||
|
||||
// Parse IPv4 address (d.d.d.d).
|
||||
func parseIPv4(s string) net.IP {
|
||||
var p [net.IPv4len]byte
|
||||
for i := 0; i < net.IPv4len; i++ {
|
||||
if len(s) == 0 {
|
||||
// Missing octets.
|
||||
continue
|
||||
}
|
||||
if i > 0 {
|
||||
if s[0] != '.' {
|
||||
return nil
|
||||
}
|
||||
s = s[1:]
|
||||
}
|
||||
n, c, ok := dtoi(s)
|
||||
if !ok || n > 0xFF {
|
||||
return nil
|
||||
}
|
||||
if c > 1 && s[0] == '0' {
|
||||
// Reject non-zero components with leading zeroes.
|
||||
return nil
|
||||
}
|
||||
s = s[c:]
|
||||
p[i] = byte(n)
|
||||
}
|
||||
if len(s) != 0 {
|
||||
return nil
|
||||
}
|
||||
return net.IPv4(p[0], p[1], p[2], p[3])
|
||||
}
|
||||
|
||||
func parseIPv6(s string) (ip net.IP) {
|
||||
ip = make(net.IP, net.IPv6len)
|
||||
ellipsis := -1 // position of ellipsis in ip
|
||||
|
||||
// Might have leading ellipsis
|
||||
if len(s) >= 2 && s[0] == ':' && s[1] == ':' {
|
||||
ellipsis = 0
|
||||
s = s[2:]
|
||||
// Might be only ellipsis
|
||||
if len(s) == 0 {
|
||||
return ip
|
||||
}
|
||||
}
|
||||
|
||||
// Loop, parsing hex numbers followed by colon.
|
||||
i := 0
|
||||
for i < net.IPv6len {
|
||||
// Hex number.
|
||||
n, c, ok := xtoi(s)
|
||||
if !ok || n > 0xFFFF {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
// If followed by dot, might be in trailing IPv4.
|
||||
if c < len(s) && s[c] == '.' {
|
||||
if ellipsis < 0 && i != net.IPv6len-net.IPv4len {
|
||||
// Not the right place.
|
||||
return nil
|
||||
}
|
||||
if i+net.IPv4len > net.IPv6len {
|
||||
// Not enough room.
|
||||
return nil
|
||||
}
|
||||
ip4 := parseIPv4(s)
|
||||
if ip4 == nil {
|
||||
return nil
|
||||
}
|
||||
ip[i] = ip4[12]
|
||||
ip[i+1] = ip4[13]
|
||||
ip[i+2] = ip4[14]
|
||||
ip[i+3] = ip4[15]
|
||||
s = ""
|
||||
i += net.IPv4len
|
||||
break
|
||||
}
|
||||
|
||||
// Save this 16-bit chunk.
|
||||
ip[i] = byte(n >> 8)
|
||||
ip[i+1] = byte(n)
|
||||
i += 2
|
||||
|
||||
// Stop at end of string.
|
||||
s = s[c:]
|
||||
if len(s) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
// Otherwise must be followed by colon and more.
|
||||
if s[0] != ':' || len(s) == 1 {
|
||||
return nil
|
||||
}
|
||||
s = s[1:]
|
||||
|
||||
// Look for ellipsis.
|
||||
if s[0] == ':' {
|
||||
if ellipsis >= 0 { // already have one
|
||||
return nil
|
||||
}
|
||||
ellipsis = i
|
||||
s = s[1:]
|
||||
if len(s) == 0 { // can be at end
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Must have used entire string.
|
||||
if len(s) != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If didn't parse enough, expand ellipsis.
|
||||
if i < net.IPv6len {
|
||||
if ellipsis < 0 {
|
||||
return nil
|
||||
}
|
||||
n := net.IPv6len - i
|
||||
for j := i - 1; j >= ellipsis; j-- {
|
||||
ip[j+n] = ip[j]
|
||||
}
|
||||
for j := ellipsis + n - 1; j >= ellipsis; j-- {
|
||||
ip[j] = 0
|
||||
}
|
||||
} else if ellipsis >= 0 {
|
||||
// Ellipsis must represent at least one 0 group.
|
||||
return nil
|
||||
}
|
||||
return ip
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
//go:build !windows && !darwin
|
||||
// +build !windows,!darwin
|
||||
|
||||
package route
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func GetRouteTable() (map[string][]*net.IPNet, error) {
|
||||
output, err := exec.Command("route", "-n").CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
split := strings.Split(string(output), "\n")
|
||||
routeTable := make(map[string][]*net.IPNet)
|
||||
for _, i := range split {
|
||||
fields := strings.Fields(i)
|
||||
if len(fields) >= 8 {
|
||||
dst := net.ParseIP(fields[0])
|
||||
mask := make(net.IPMask, net.IPv4len)
|
||||
copy(mask, net.ParseIP(fields[2]))
|
||||
eth := fields[7]
|
||||
if v, ok := routeTable[eth]; ok {
|
||||
routeTable[eth] = append(v, &net.IPNet{IP: dst, Mask: mask})
|
||||
} else {
|
||||
routeTable[eth] = []*net.IPNet{{IP: dst, Mask: mask}}
|
||||
}
|
||||
}
|
||||
}
|
||||
return routeTable, nil
|
||||
}
|
||||
|
||||
func DisableDevice(list []string) error {
|
||||
for _, dev := range list {
|
||||
if err := exec.Command("sudo", "ifconfig", dev, "down").Run(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
// todo: optimize code
|
||||
//rollbackFuncList = append(rollbackFuncList, func() {
|
||||
// _ = exec.Command("sudo", "ifconfig", dev, "up").Run()
|
||||
//})
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package route
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func GetRouteTable() (map[string][]*net.IPNet, error) {
|
||||
return make(map[string][]*net.IPNet), nil
|
||||
}
|
||||
|
||||
func DisableDevice(list []string) error {
|
||||
return nil
|
||||
}
|
@@ -6,6 +6,7 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/types"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/songgao/water"
|
||||
|
||||
@@ -17,7 +18,7 @@ type Config struct {
|
||||
Name string
|
||||
Addr string
|
||||
MTU int
|
||||
Routes []IPRoute
|
||||
Routes []types.Route
|
||||
Gateway string
|
||||
}
|
||||
|
||||
@@ -109,14 +110,8 @@ 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")}
|
||||
}
|
||||
|
||||
// IPRoute is an IP routing entry.
|
||||
type IPRoute struct {
|
||||
Dest *net.IPNet
|
||||
Gateway net.IP
|
||||
}
|
||||
|
||||
// AddRoutes for outer called
|
||||
func AddRoutes(routes ...IPRoute) error {
|
||||
func AddRoutes(routes ...types.Route) error {
|
||||
env := os.Getenv(config.EnvTunNameOrLUID)
|
||||
return addTunRoutes(env, routes...)
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@ import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/types"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/songgao/water"
|
||||
|
||||
@@ -61,16 +62,17 @@ func createTun(cfg Config) (conn net.Conn, itf *net.Interface, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func addTunRoutes(ifName string, routes ...IPRoute) error {
|
||||
func addTunRoutes(ifName string, routes ...types.Route) error {
|
||||
for _, route := range routes {
|
||||
if route.Dest == nil {
|
||||
if route.Dst.String() == "" {
|
||||
continue
|
||||
}
|
||||
cmd := fmt.Sprintf("route add -net %s -interface %s", route.Dest.String(), ifName)
|
||||
cmd := fmt.Sprintf("route add -net %s -interface %s", route.Dst.String(), ifName)
|
||||
log.Debugf("[tun] %s", cmd)
|
||||
args := strings.Split(cmd, " ")
|
||||
if er := exec.Command(args[0], args[1:]...).Run(); er != nil {
|
||||
return fmt.Errorf("%s: %v", cmd, er)
|
||||
err := exec.Command(args[0], args[1:]...).Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %v", cmd, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@@ -10,6 +10,7 @@ import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/types"
|
||||
"github.com/docker/libcontainer/netlink"
|
||||
"github.com/milosgajdos/tenus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -85,14 +86,14 @@ func createTun(cfg Config) (conn net.Conn, itf *net.Interface, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func addTunRoutes(ifName string, routes ...IPRoute) error {
|
||||
func addTunRoutes(ifName string, routes ...types.Route) error {
|
||||
for _, route := range routes {
|
||||
if route.Dest == nil {
|
||||
if route.Dst.String() == "" {
|
||||
continue
|
||||
}
|
||||
cmd := fmt.Sprintf("ip route add %s dev %s", route.Dest.String(), ifName)
|
||||
cmd := fmt.Sprintf("ip route add %s dev %s", route.Dst.String(), ifName)
|
||||
log.Debugf("[tun] %s", cmd)
|
||||
if err := netlink.AddRoute(route.Dest.String(), "", "", ifName); err != nil && !errors.Is(err, syscall.EEXIST) {
|
||||
if err := netlink.AddRoute(route.Dst.String(), "", "", ifName); err != nil && !errors.Is(err, syscall.EEXIST) {
|
||||
return fmt.Errorf("%s: %v", cmd, err)
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/types"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/songgao/water"
|
||||
|
||||
@@ -61,12 +62,12 @@ func createTun(cfg Config) (conn net.Conn, itf *net.Interface, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func addTunRoutes(ifName string, routes ...IPRoute) error {
|
||||
func addTunRoutes(ifName string, routes ...types.Route) error {
|
||||
for _, route := range routes {
|
||||
if route.Dest == nil {
|
||||
if route.Dst.String() == "" {
|
||||
continue
|
||||
}
|
||||
cmd := fmt.Sprintf("route add -net %s -interface %s", route.Dest.String(), ifName)
|
||||
cmd := fmt.Sprintf("route add -net %s -interface %s", route.Dst.String(), ifName)
|
||||
log.Debugf("[tun] %s", cmd)
|
||||
args := strings.Split(cmd, " ")
|
||||
if er := exec.Command(args[0], args[1:]...).Run(); er != nil {
|
||||
|
@@ -11,6 +11,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/types"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/windows"
|
||||
wireguardtun "golang.zx2c4.com/wireguard/tun"
|
||||
@@ -58,7 +59,7 @@ func createTun(cfg Config) (net.Conn, *net.Interface, error) {
|
||||
return &winTunConn{ifce: tunDevice, addr: &net.IPAddr{IP: ip}}, iface, nil
|
||||
}
|
||||
|
||||
func addTunRoutes(luid string, routes ...IPRoute) error {
|
||||
func addTunRoutes(luid string, routes ...types.Route) error {
|
||||
parseUint, err := strconv.ParseUint(luid, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -66,21 +67,21 @@ func addTunRoutes(luid string, routes ...IPRoute) error {
|
||||
ifName := winipcfg.LUID(parseUint)
|
||||
_ = ifName.FlushRoutes(windows.AF_INET)
|
||||
for _, route := range routes {
|
||||
if route.Dest == nil {
|
||||
if route.Dst.String() == "" {
|
||||
continue
|
||||
}
|
||||
var gw string
|
||||
if gw != "" {
|
||||
route.Gateway = net.ParseIP(gw)
|
||||
route.GW = net.ParseIP(gw)
|
||||
} else {
|
||||
route.Gateway = net.IPv4(0, 0, 0, 0)
|
||||
route.GW = net.IPv4(0, 0, 0, 0)
|
||||
}
|
||||
prefix, err := netip.ParsePrefix(route.Dest.String())
|
||||
prefix, err := netip.ParsePrefix(route.Dst.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var addr netip.Addr
|
||||
addr, err = netip.ParseAddr(route.Gateway.String())
|
||||
addr, err = netip.ParseAddr(route.GW.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
Reference in New Issue
Block a user