mirror of
https://github.com/kubenetworks/kubevpn.git
synced 2025-09-27 03:36:09 +08:00
187 lines
4.5 KiB
Go
187 lines
4.5 KiB
Go
package core
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net"
|
|
"time"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/wencaiwulue/kubevpn/v2/pkg/config"
|
|
plog "github.com/wencaiwulue/kubevpn/v2/pkg/log"
|
|
"github.com/wencaiwulue/kubevpn/v2/pkg/util"
|
|
)
|
|
|
|
func (h *tunHandler) HandleClient(ctx context.Context, tun net.Conn) {
|
|
defer tun.Close()
|
|
remoteAddr, err := net.ResolveUDPAddr("udp", h.node.Remote)
|
|
if err != nil {
|
|
plog.G(ctx).Errorf("[TUN-CLIENT] Failed to resolve udp addr %s: %v", h.node.Remote, err)
|
|
return
|
|
}
|
|
in := make(chan *DataElem, MaxSize)
|
|
out := make(chan *DataElem, MaxSize)
|
|
defer util.SafeClose(in)
|
|
defer util.SafeClose(out)
|
|
|
|
d := &ClientDevice{
|
|
tun: tun,
|
|
tunInbound: in,
|
|
tunOutbound: out,
|
|
chExit: h.chExit,
|
|
}
|
|
d.SetTunInboundHandler(func(tunInbound <-chan *DataElem, tunOutbound chan<- *DataElem) {
|
|
for ctx.Err() == nil {
|
|
packetConn, err := getRemotePacketConn(ctx, h.chain)
|
|
if err != nil {
|
|
plog.G(ctx).Debugf("[TUN-CLIENT] Failed to get remote conn from %s -> %s: %s", tun.LocalAddr(), remoteAddr, err)
|
|
time.Sleep(time.Millisecond * 200)
|
|
continue
|
|
}
|
|
err = transportTunClient(ctx, tunInbound, tunOutbound, packetConn, remoteAddr)
|
|
if err != nil {
|
|
plog.G(ctx).Debugf("[TUN-CLIENT] %s: %v", tun.LocalAddr(), err)
|
|
}
|
|
}
|
|
})
|
|
|
|
d.Start(ctx)
|
|
}
|
|
|
|
func getRemotePacketConn(ctx context.Context, chain *Chain) (packetConn net.PacketConn, err error) {
|
|
defer func() {
|
|
if err != nil && packetConn != nil {
|
|
_ = packetConn.Close()
|
|
}
|
|
}()
|
|
if !chain.IsEmpty() {
|
|
var cc net.Conn
|
|
cc, err = chain.DialContext(ctx)
|
|
if err != nil {
|
|
return
|
|
}
|
|
var ok bool
|
|
if packetConn, ok = cc.(net.PacketConn); !ok {
|
|
err = errors.New("not a packet connection")
|
|
return
|
|
}
|
|
} else {
|
|
var lc net.ListenConfig
|
|
packetConn, err = lc.ListenPacket(ctx, "udp", "")
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func transportTunClient(ctx context.Context, tunInbound <-chan *DataElem, tunOutbound chan<- *DataElem, packetConn net.PacketConn, remoteAddr net.Addr) error {
|
|
errChan := make(chan error, 2)
|
|
defer packetConn.Close()
|
|
|
|
go func() {
|
|
defer util.HandleCrash()
|
|
for e := range tunInbound {
|
|
if e.src.Equal(e.dst) {
|
|
util.SafeWrite(tunOutbound, e)
|
|
continue
|
|
}
|
|
_, err := packetConn.WriteTo(e.data[:e.length], remoteAddr)
|
|
config.LPool.Put(e.data[:])
|
|
if err != nil {
|
|
util.SafeWrite(errChan, errors.Wrap(err, fmt.Sprintf("failed to write packet to remote %s", remoteAddr)))
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
go func() {
|
|
defer util.HandleCrash()
|
|
for {
|
|
buf := config.LPool.Get().([]byte)[:]
|
|
n, _, err := packetConn.ReadFrom(buf[:])
|
|
if err != nil {
|
|
config.LPool.Put(buf[:])
|
|
util.SafeWrite(errChan, errors.Wrap(err, fmt.Sprintf("failed to read packet from remote %s", remoteAddr)))
|
|
return
|
|
}
|
|
util.SafeWrite(tunOutbound, &DataElem{data: buf[:], length: n})
|
|
}
|
|
}()
|
|
|
|
select {
|
|
case err := <-errChan:
|
|
return err
|
|
case <-ctx.Done():
|
|
return nil
|
|
}
|
|
}
|
|
|
|
type ClientDevice struct {
|
|
tun net.Conn
|
|
tunInbound chan *DataElem
|
|
tunOutbound chan *DataElem
|
|
// your main logic
|
|
tunInboundHandler func(tunInbound <-chan *DataElem, tunOutbound chan<- *DataElem)
|
|
chExit chan error
|
|
}
|
|
|
|
func (d *ClientDevice) Start(ctx context.Context) {
|
|
go d.tunInboundHandler(d.tunInbound, d.tunOutbound)
|
|
go heartbeats(ctx, d.tun)
|
|
go d.readFromTun()
|
|
go d.writeToTun()
|
|
|
|
select {
|
|
case err := <-d.chExit:
|
|
plog.G(ctx).Errorf("[TUN-CLIENT]: %v", err)
|
|
return
|
|
case <-ctx.Done():
|
|
return
|
|
}
|
|
}
|
|
|
|
func (d *ClientDevice) SetTunInboundHandler(handler func(tunInbound <-chan *DataElem, tunOutbound chan<- *DataElem)) {
|
|
d.tunInboundHandler = handler
|
|
}
|
|
|
|
func (d *ClientDevice) readFromTun() {
|
|
defer util.HandleCrash()
|
|
for {
|
|
buf := config.LPool.Get().([]byte)[:]
|
|
n, err := d.tun.Read(buf[:])
|
|
if err != nil {
|
|
util.SafeWrite(d.chExit, err)
|
|
config.LPool.Put(buf[:])
|
|
return
|
|
}
|
|
if n == 0 {
|
|
config.LPool.Put(buf[:])
|
|
continue
|
|
}
|
|
|
|
// Try to determine network protocol number, default zero.
|
|
var src, dst net.IP
|
|
src, dst, err = util.ParseIP(buf[:n])
|
|
if err != nil {
|
|
plog.G(context.Background()).Debugf("[TUN-GVISOR] Unknown packet: %v", err)
|
|
config.LPool.Put(buf[:])
|
|
continue
|
|
}
|
|
plog.G(context.Background()).Debugf("[TUN-RAW] SRC: %s, DST: %s, Length: %d", src.String(), dst, n)
|
|
util.SafeWrite(d.tunInbound, NewDataElem(buf[:], n, src, dst))
|
|
}
|
|
}
|
|
|
|
func (d *ClientDevice) writeToTun() {
|
|
defer util.HandleCrash()
|
|
for e := range d.tunOutbound {
|
|
_, err := d.tun.Write(e.data[:e.length])
|
|
config.LPool.Put(e.data[:])
|
|
if err != nil {
|
|
util.SafeWrite(d.chExit, err)
|
|
return
|
|
}
|
|
}
|
|
}
|