mirror of
https://github.com/yusing/godoxy.git
synced 2025-05-20 12:42:34 +02:00
tcp/udp fix
This commit is contained in:
parent
cbe23d2ed1
commit
351bf84559
8 changed files with 152 additions and 179 deletions
26
Dockerfile
26
Dockerfile
|
@ -1,20 +1,30 @@
|
||||||
FROM golang:1.22.1 as builder
|
FROM alpine:latest AS codemirror
|
||||||
|
RUN apk add --no-cache unzip wget make
|
||||||
|
COPY Makefile .
|
||||||
|
RUN make setup-codemirror
|
||||||
|
|
||||||
COPY go.mod /app/go.mod
|
FROM golang:1.22.1-alpine as builder
|
||||||
COPY src/ /app/src
|
COPY src/ /src
|
||||||
COPY Makefile /app
|
COPY go.mod go.sum /src/go-proxy
|
||||||
WORKDIR /app
|
WORKDIR /src/go-proxy
|
||||||
RUN make get
|
RUN --mount=type=cache,target="/go/pkg/mod" \
|
||||||
RUN make build
|
go mod download
|
||||||
|
|
||||||
|
ENV GOCACHE=/root/.cache/go-build
|
||||||
|
RUN --mount=type=cache,target="/go/pkg/mod" \
|
||||||
|
--mount=type=cache,target="/root/.cache/go-build" \
|
||||||
|
CGO_ENABLED=0 GOOS=linux go build -pgo=auto -o go-proxy
|
||||||
|
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
|
|
||||||
LABEL maintainer="yusing@6uo.me"
|
LABEL maintainer="yusing@6uo.me"
|
||||||
|
|
||||||
RUN apk add --no-cache tzdata
|
RUN apk add --no-cache tzdata
|
||||||
COPY --from=builder /app/bin/go-proxy /app/
|
RUN mkdir -p /app/templates
|
||||||
|
COPY --from=codemirror templates/codemirror/ /app/templates/codemirror
|
||||||
COPY templates/ /app/templates
|
COPY templates/ /app/templates
|
||||||
COPY schema/ /app/schema
|
COPY schema/ /app/schema
|
||||||
|
COPY --from=builder /src/go-proxy /app/
|
||||||
|
|
||||||
RUN chmod +x /app/go-proxy
|
RUN chmod +x /app/go-proxy
|
||||||
ENV DOCKER_HOST unix:///var/run/docker.sock
|
ENV DOCKER_HOST unix:///var/run/docker.sock
|
||||||
|
|
3
Makefile
3
Makefile
|
@ -11,6 +11,7 @@ setup-codemirror:
|
||||||
wget https://codemirror.net/5/codemirror.zip
|
wget https://codemirror.net/5/codemirror.zip
|
||||||
unzip codemirror.zip
|
unzip codemirror.zip
|
||||||
rm codemirror.zip
|
rm codemirror.zip
|
||||||
|
mkdir -p templates
|
||||||
mv codemirror-* templates/codemirror
|
mv codemirror-* templates/codemirror
|
||||||
|
|
||||||
build:
|
build:
|
||||||
|
@ -35,6 +36,6 @@ udp-server:
|
||||||
-p 9999:9999/udp \
|
-p 9999:9999/udp \
|
||||||
--label proxy.test-udp.scheme=udp \
|
--label proxy.test-udp.scheme=udp \
|
||||||
--label proxy.test-udp.port=20003:9999 \
|
--label proxy.test-udp.port=20003:9999 \
|
||||||
--network data_default \
|
--network host \
|
||||||
--name test-udp \
|
--name test-udp \
|
||||||
$$(docker build -q -f udp-test-server.Dockerfile .)
|
$$(docker build -q -f udp-test-server.Dockerfile .)
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import "os"
|
|
||||||
|
|
||||||
type Reader interface {
|
|
||||||
Read() ([]byte, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type FileReader struct {
|
|
||||||
Path string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *FileReader) Read() ([]byte, error) {
|
|
||||||
return os.ReadFile(r.Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ByteReader struct {
|
|
||||||
Data []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ByteReader) Read() ([]byte, error) {
|
|
||||||
return r.Data, nil
|
|
||||||
}
|
|
|
@ -2,13 +2,37 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"sync"
|
"os"
|
||||||
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Reader interface {
|
||||||
|
Read() ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileReader struct {
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *FileReader) Read() ([]byte, error) {
|
||||||
|
return os.ReadFile(r.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ByteReader struct {
|
||||||
|
Data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ByteReader) Read() ([]byte, error) {
|
||||||
|
return r.Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
type ReadCloser struct {
|
type ReadCloser struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
r io.ReadCloser
|
r io.ReadCloser
|
||||||
|
closed atomic.Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ReadCloser) Read(p []byte) (int, error) {
|
func (r *ReadCloser) Read(p []byte) (int, error) {
|
||||||
|
@ -21,13 +45,16 @@ func (r *ReadCloser) Read(p []byte) (int, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ReadCloser) Close() error {
|
func (r *ReadCloser) Close() error {
|
||||||
|
if r.closed.Load() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
r.closed.Store(true)
|
||||||
return r.r.Close()
|
return r.r.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
type Pipe struct {
|
type Pipe struct {
|
||||||
r ReadCloser
|
r ReadCloser
|
||||||
w io.WriteCloser
|
w io.WriteCloser
|
||||||
wg sync.WaitGroup
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
}
|
}
|
||||||
|
@ -35,32 +62,24 @@ type Pipe struct {
|
||||||
func NewPipe(ctx context.Context, r io.ReadCloser, w io.WriteCloser) *Pipe {
|
func NewPipe(ctx context.Context, r io.ReadCloser, w io.WriteCloser) *Pipe {
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
return &Pipe{
|
return &Pipe{
|
||||||
r: ReadCloser{ctx, r},
|
r: ReadCloser{ctx: ctx, r: r},
|
||||||
w: w,
|
w: w,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pipe) Start() {
|
func (p *Pipe) Start() error {
|
||||||
p.wg.Add(1)
|
return Copy(p.ctx, p.w, &p.r)
|
||||||
go func() {
|
|
||||||
Copy(p.ctx, p.w, &p.r)
|
|
||||||
p.wg.Done()
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pipe) Stop() {
|
func (p *Pipe) Stop() error {
|
||||||
p.cancel()
|
p.cancel()
|
||||||
p.wg.Wait()
|
return errors.Join(fmt.Errorf("read: %w", p.r.Close()), fmt.Errorf("write: %w", p.w.Close()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pipe) Close() (error, error) {
|
func (p *Pipe) Write(b []byte) (int, error) {
|
||||||
return p.r.Close(), p.w.Close()
|
return p.w.Write(b)
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Pipe) Wait() {
|
|
||||||
p.wg.Wait()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type BidirectionalPipe struct {
|
type BidirectionalPipe struct {
|
||||||
|
@ -75,26 +94,34 @@ func NewBidirectionalPipe(ctx context.Context, rw1 io.ReadWriteCloser, rw2 io.Re
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BidirectionalPipe) Start() {
|
func NewBidirectionalPipeIntermediate(ctx context.Context, listener io.ReadCloser, client io.ReadWriteCloser, target io.ReadWriteCloser) *BidirectionalPipe {
|
||||||
p.pSrcDst.Start()
|
return &BidirectionalPipe{
|
||||||
p.pDstSrc.Start()
|
pSrcDst: *NewPipe(ctx, listener, client),
|
||||||
|
pDstSrc: *NewPipe(ctx, client, target),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BidirectionalPipe) Stop() {
|
func (p *BidirectionalPipe) Start() error {
|
||||||
p.pSrcDst.Stop()
|
errCh := make(chan error, 2)
|
||||||
p.pDstSrc.Stop()
|
go func() {
|
||||||
|
errCh <- p.pSrcDst.Start()
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
errCh <- p.pDstSrc.Start()
|
||||||
|
}()
|
||||||
|
for err := range errCh {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *BidirectionalPipe) Close() (error, error) {
|
func (p *BidirectionalPipe) Stop() error {
|
||||||
return p.pSrcDst.Close()
|
return errors.Join(p.pSrcDst.Stop(), p.pDstSrc.Stop())
|
||||||
}
|
|
||||||
|
|
||||||
func (p *BidirectionalPipe) Wait() {
|
|
||||||
p.pSrcDst.Wait()
|
|
||||||
p.pDstSrc.Wait()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Copy(ctx context.Context, dst io.WriteCloser, src io.ReadCloser) error {
|
func Copy(ctx context.Context, dst io.WriteCloser, src io.ReadCloser) error {
|
||||||
_, err := io.Copy(dst, &ReadCloser{ctx, src})
|
_, err := io.Copy(dst, &ReadCloser{ctx: ctx, r: src})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@ func NewRoute(cfg *ProxyConfig) (Route, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, NewNestedErrorFrom(err).Subject(cfg.Alias)
|
return nil, NewNestedErrorFrom(err).Subject(cfg.Alias)
|
||||||
}
|
}
|
||||||
streamRoutes.Set(id, route)
|
|
||||||
return route, nil
|
return route, nil
|
||||||
} else {
|
} else {
|
||||||
httpRoutes.Ensure(cfg.Alias)
|
httpRoutes.Ensure(cfg.Alias)
|
||||||
|
|
|
@ -143,6 +143,7 @@ func (route *StreamRouteBase) Start() {
|
||||||
route.l.Errorf("failed to setup: %v", err)
|
route.l.Errorf("failed to setup: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
streamRoutes.Set(route.id, route)
|
||||||
route.started = true
|
route.started = true
|
||||||
route.wg.Add(2)
|
route.wg.Add(2)
|
||||||
go route.grAcceptConnections()
|
go route.grAcceptConnections()
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -14,12 +15,15 @@ type Pipes []*BidirectionalPipe
|
||||||
type TCPRoute struct {
|
type TCPRoute struct {
|
||||||
*StreamRouteBase
|
*StreamRouteBase
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
|
pipe Pipes
|
||||||
|
mu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTCPRoute(base *StreamRouteBase) StreamImpl {
|
func NewTCPRoute(base *StreamRouteBase) StreamImpl {
|
||||||
return &TCPRoute{
|
return &TCPRoute{
|
||||||
StreamRouteBase: base,
|
StreamRouteBase: base,
|
||||||
listener: nil,
|
listener: nil,
|
||||||
|
pipe: make(Pipes, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +44,6 @@ func (route *TCPRoute) Handle(c interface{}) error {
|
||||||
clientConn := c.(net.Conn)
|
clientConn := c.(net.Conn)
|
||||||
|
|
||||||
defer clientConn.Close()
|
defer clientConn.Close()
|
||||||
defer route.wg.Done()
|
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), tcpDialTimeout)
|
ctx, cancel := context.WithTimeout(context.Background(), tcpDialTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
@ -58,11 +61,12 @@ func (route *TCPRoute) Handle(c interface{}) error {
|
||||||
<-route.stopCh
|
<-route.stopCh
|
||||||
pipeCancel()
|
pipeCancel()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
route.mu.Lock()
|
||||||
pipe := NewBidirectionalPipe(pipeCtx, clientConn, serverConn)
|
pipe := NewBidirectionalPipe(pipeCtx, clientConn, serverConn)
|
||||||
pipe.Start()
|
route.pipe = append(route.pipe, pipe)
|
||||||
pipe.Wait()
|
route.mu.Unlock()
|
||||||
pipe.Close()
|
return pipe.Start()
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (route *TCPRoute) CloseListeners() {
|
func (route *TCPRoute) CloseListeners() {
|
||||||
|
@ -71,4 +75,9 @@ func (route *TCPRoute) CloseListeners() {
|
||||||
}
|
}
|
||||||
route.listener.Close()
|
route.listener.Close()
|
||||||
route.listener = nil
|
route.listener = nil
|
||||||
|
for _, pipe := range route.pipe {
|
||||||
|
if err := pipe.Stop(); err != nil {
|
||||||
|
route.l.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,52 +1,55 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type UDPRoute struct {
|
type UDPRoute struct {
|
||||||
*StreamRouteBase
|
*StreamRouteBase
|
||||||
|
|
||||||
connMap map[net.Addr]net.Conn
|
connMap UDPConnMap
|
||||||
connMapMutex sync.Mutex
|
connMapMutex sync.Mutex
|
||||||
|
|
||||||
listeningConn *net.UDPConn
|
listeningConn *net.UDPConn
|
||||||
targetConn *net.UDPConn
|
targetAddr *net.UDPAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
type UDPConn struct {
|
type UDPConn struct {
|
||||||
remoteAddr net.Addr
|
src *net.UDPConn
|
||||||
buffer []byte
|
dst *net.UDPConn
|
||||||
bytesReceived []byte
|
*BidirectionalPipe
|
||||||
nReceived int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UDPConnMap map[net.Addr]*UDPConn
|
||||||
|
|
||||||
func NewUDPRoute(base *StreamRouteBase) StreamImpl {
|
func NewUDPRoute(base *StreamRouteBase) StreamImpl {
|
||||||
return &UDPRoute{
|
return &UDPRoute{
|
||||||
StreamRouteBase: base,
|
StreamRouteBase: base,
|
||||||
connMap: make(map[net.Addr]net.Conn),
|
connMap: make(UDPConnMap),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (route *UDPRoute) Setup() error {
|
func (route *UDPRoute) Setup() error {
|
||||||
source, err := net.ListenPacket(route.ListeningScheme, fmt.Sprintf(":%v", route.ListeningPort))
|
laddr, err := net.ResolveUDPAddr(route.ListeningScheme, fmt.Sprintf(":%v", route.ListeningPort))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
source, err := net.ListenUDP(route.ListeningScheme, laddr)
|
||||||
target, err := net.Dial(route.TargetScheme, fmt.Sprintf("%s:%v", route.TargetHost, route.TargetPort))
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
raddr, err := net.ResolveUDPAddr(route.TargetScheme, fmt.Sprintf("%s:%v", route.TargetHost, route.TargetPort))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
source.Close()
|
source.Close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
route.listeningConn = source.(*net.UDPConn)
|
route.listeningConn = source
|
||||||
route.targetConn = target.(*net.UDPConn)
|
route.targetAddr = raddr
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,71 +67,39 @@ func (route *UDPRoute) Accept() (interface{}, error) {
|
||||||
return nil, io.ErrShortBuffer
|
return nil, io.ErrShortBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
conn := &UDPConn{
|
conn, ok := route.connMap[srcAddr]
|
||||||
remoteAddr: srcAddr,
|
|
||||||
buffer: buffer,
|
|
||||||
bytesReceived: buffer[:nRead],
|
|
||||||
nReceived: nRead,
|
|
||||||
}
|
|
||||||
return conn, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (route *UDPRoute) Handle(c interface{}) error {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
conn := c.(*UDPConn)
|
|
||||||
srcConn, ok := route.connMap[conn.remoteAddr]
|
|
||||||
if !ok {
|
if !ok {
|
||||||
route.connMapMutex.Lock()
|
route.connMapMutex.Lock()
|
||||||
srcConn, err = net.DialUDP("udp", nil, conn.remoteAddr.(*net.UDPAddr))
|
srcConn, err := net.DialUDP("udp", nil, srcAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
route.connMap[conn.remoteAddr] = srcConn
|
dstConn, err := net.DialUDP("udp", nil, route.targetAddr)
|
||||||
|
if err != nil {
|
||||||
|
srcConn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pipeCtx, pipeCancel := context.WithCancel(context.Background())
|
||||||
|
go func() {
|
||||||
|
<-route.stopCh
|
||||||
|
pipeCancel()
|
||||||
|
}()
|
||||||
|
conn = &UDPConn{
|
||||||
|
srcConn,
|
||||||
|
dstConn,
|
||||||
|
NewBidirectionalPipe(pipeCtx, sourceRWCloser{in, dstConn}, sourceRWCloser{in, srcConn}),
|
||||||
|
}
|
||||||
|
route.connMap[srcAddr] = conn
|
||||||
route.connMapMutex.Unlock()
|
route.connMapMutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
var forwarder func(*UDPConn, net.Conn) error
|
_, err = conn.dst.Write(buffer[:nRead])
|
||||||
|
return conn, err
|
||||||
|
}
|
||||||
|
|
||||||
if logLevel == logrus.DebugLevel {
|
func (route *UDPRoute) Handle(c interface{}) error {
|
||||||
forwarder = route.forwardReceivedDebug
|
return c.(*UDPConn).Start()
|
||||||
} else {
|
|
||||||
forwarder = route.forwardReceivedReal
|
|
||||||
}
|
|
||||||
|
|
||||||
// initiate connection to target
|
|
||||||
err = forwarder(conn, route.targetConn)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-route.stopCh:
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
// receive from target
|
|
||||||
conn, err = route.readFrom(route.targetConn, conn.buffer)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// forward to source
|
|
||||||
err = forwarder(conn, srcConn)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// read from source
|
|
||||||
conn, err = route.readFrom(srcConn, conn.buffer)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// forward to target
|
|
||||||
err = forwarder(conn, route.targetConn)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (route *UDPRoute) CloseListeners() {
|
func (route *UDPRoute) CloseListeners() {
|
||||||
|
@ -136,50 +107,28 @@ func (route *UDPRoute) CloseListeners() {
|
||||||
route.listeningConn.Close()
|
route.listeningConn.Close()
|
||||||
route.listeningConn = nil
|
route.listeningConn = nil
|
||||||
}
|
}
|
||||||
if route.targetConn != nil {
|
|
||||||
route.targetConn.Close()
|
|
||||||
route.targetConn = nil
|
|
||||||
}
|
|
||||||
for _, conn := range route.connMap {
|
for _, conn := range route.connMap {
|
||||||
conn.(*net.UDPConn).Close() // TODO: change on non udp target
|
if err := conn.dst.Close(); err != nil {
|
||||||
|
route.l.Error(err)
|
||||||
}
|
}
|
||||||
route.connMap = make(map[net.Addr]net.Conn)
|
}
|
||||||
|
route.connMap = make(UDPConnMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (route *UDPRoute) readFrom(src net.Conn, buffer []byte) (*UDPConn, error) {
|
type sourceRWCloser struct {
|
||||||
nRead, err := src.Read(buffer)
|
server *net.UDPConn
|
||||||
|
target *net.UDPConn
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if nRead == 0 {
|
|
||||||
return nil, io.ErrShortBuffer
|
|
||||||
}
|
|
||||||
|
|
||||||
return &UDPConn{
|
|
||||||
remoteAddr: src.RemoteAddr(),
|
|
||||||
buffer: buffer,
|
|
||||||
bytesReceived: buffer[:nRead],
|
|
||||||
nReceived: nRead,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (route *UDPRoute) forwardReceivedReal(receivedConn *UDPConn, dest net.Conn) error {
|
func (w sourceRWCloser) Read(p []byte) (int, error) {
|
||||||
nWritten, err := dest.Write(receivedConn.bytesReceived)
|
n, _, err := w.target.ReadFrom(p)
|
||||||
|
return n, err
|
||||||
if nWritten != receivedConn.nReceived {
|
|
||||||
err = io.ErrShortWrite
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (route *UDPRoute) forwardReceivedDebug(receivedConn *UDPConn, dest net.Conn) error {
|
func (w sourceRWCloser) Write(p []byte) (int, error) {
|
||||||
route.l.WithField("size", receivedConn.nReceived).Debugf(
|
return w.server.WriteToUDP(p, w.target.RemoteAddr().(*net.UDPAddr)) // TODO: support non udp
|
||||||
"forwarding from %s to %s",
|
}
|
||||||
receivedConn.remoteAddr.String(),
|
|
||||||
dest.RemoteAddr().String(),
|
func (w sourceRWCloser) Close() error {
|
||||||
)
|
return w.target.Close()
|
||||||
return route.forwardReceivedReal(receivedConn, dest)
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue