mirror of
https://github.com/yusing/godoxy.git
synced 2026-03-21 08:39:03 +01:00
183 lines
3.8 KiB
Go
Executable File
183 lines
3.8 KiB
Go
Executable File
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type StreamRoute interface {
|
|
Route
|
|
ListeningUrl() string
|
|
TargetUrl() string
|
|
Logger() logrus.FieldLogger
|
|
|
|
closeListeners()
|
|
closeChannel()
|
|
unmarkPort()
|
|
wait()
|
|
}
|
|
|
|
type StreamRouteBase struct {
|
|
Alias string // to show in panel
|
|
Type string
|
|
ListeningScheme string
|
|
ListeningPort int
|
|
TargetScheme string
|
|
TargetHost string
|
|
TargetPort int
|
|
|
|
id string
|
|
wg sync.WaitGroup
|
|
stopChann chan struct{}
|
|
l logrus.FieldLogger
|
|
}
|
|
|
|
func newStreamRouteBase(config *ProxyConfig) (*StreamRouteBase, error) {
|
|
var streamType string = StreamType_TCP
|
|
var srcPort string
|
|
var dstPort string
|
|
var srcScheme string
|
|
var dstScheme string
|
|
|
|
port_split := strings.Split(config.Port, ":")
|
|
if len(port_split) != 2 {
|
|
cfgl.Warnf("Invalid port %s, assuming it is target port", config.Port)
|
|
srcPort = "0"
|
|
dstPort = config.Port
|
|
} else {
|
|
srcPort = port_split[0]
|
|
dstPort = port_split[1]
|
|
}
|
|
|
|
if port, hasName := NamePortMap[dstPort]; hasName {
|
|
dstPort = port
|
|
}
|
|
|
|
srcPortInt, err := strconv.Atoi(srcPort)
|
|
if err != nil {
|
|
return nil, fmt.Errorf(
|
|
"invalid stream source port %s, ignoring", srcPort,
|
|
)
|
|
}
|
|
|
|
utils.markPortInUse(srcPortInt)
|
|
|
|
dstPortInt, err := strconv.Atoi(dstPort)
|
|
if err != nil {
|
|
return nil, fmt.Errorf(
|
|
"invalid stream target port %s, ignoring", dstPort,
|
|
)
|
|
}
|
|
|
|
scheme_split := strings.Split(config.Scheme, ":")
|
|
|
|
if len(scheme_split) == 2 {
|
|
srcScheme = scheme_split[0]
|
|
dstScheme = scheme_split[1]
|
|
} else {
|
|
srcScheme = config.Scheme
|
|
dstScheme = config.Scheme
|
|
}
|
|
|
|
return &StreamRouteBase{
|
|
Alias: config.Alias,
|
|
Type: streamType,
|
|
ListeningScheme: srcScheme,
|
|
ListeningPort: srcPortInt,
|
|
TargetScheme: dstScheme,
|
|
TargetHost: config.Host,
|
|
TargetPort: dstPortInt,
|
|
|
|
id: config.GetID(),
|
|
wg: sync.WaitGroup{},
|
|
stopChann: make(chan struct{}),
|
|
l: srlog.WithFields(logrus.Fields{
|
|
"alias": config.Alias,
|
|
"src": fmt.Sprintf("%s://:%d", srcScheme, srcPortInt),
|
|
"dst": fmt.Sprintf("%s://%s:%d", dstScheme, config.Host, dstPortInt),
|
|
}),
|
|
}, nil
|
|
}
|
|
|
|
func NewStreamRoute(config *ProxyConfig) (StreamRoute, error) {
|
|
switch config.Scheme {
|
|
case StreamType_TCP:
|
|
return NewTCPRoute(config)
|
|
case StreamType_UDP:
|
|
return NewUDPRoute(config)
|
|
default:
|
|
return nil, errors.New("unknown stream type")
|
|
}
|
|
}
|
|
|
|
func (route *StreamRouteBase) ListeningUrl() string {
|
|
return fmt.Sprintf("%s:%v", route.ListeningScheme, route.ListeningPort)
|
|
}
|
|
|
|
func (route *StreamRouteBase) TargetUrl() string {
|
|
return fmt.Sprintf("%s://%s:%v", route.TargetScheme, route.TargetHost, route.TargetPort)
|
|
}
|
|
|
|
func (route *StreamRouteBase) Logger() logrus.FieldLogger {
|
|
return route.l
|
|
}
|
|
|
|
func (route *StreamRouteBase) SetupListen() {
|
|
if route.ListeningPort == 0 {
|
|
freePort, err := utils.findUseFreePort(20000)
|
|
if err != nil {
|
|
route.l.Error(err)
|
|
return
|
|
}
|
|
route.ListeningPort = freePort
|
|
route.l.Info("Assigned free port ", route.ListeningPort)
|
|
}
|
|
route.l.Info("Listening on ", route.ListeningUrl())
|
|
}
|
|
|
|
func (route *StreamRouteBase) RemoveFromRoutes() {
|
|
streamRoutes.Delete(route.id)
|
|
}
|
|
|
|
func (route *StreamRouteBase) wait() {
|
|
route.wg.Wait()
|
|
}
|
|
|
|
func (route *StreamRouteBase) closeChannel() {
|
|
close(route.stopChann)
|
|
}
|
|
|
|
func (route *StreamRouteBase) unmarkPort() {
|
|
utils.unmarkPortInUse(route.ListeningPort)
|
|
}
|
|
|
|
func stopListening(route StreamRoute) {
|
|
l := route.Logger()
|
|
l.Debug("Stopping listening")
|
|
route.closeChannel()
|
|
route.closeListeners()
|
|
|
|
done := make(chan struct{})
|
|
|
|
go func() {
|
|
route.wait()
|
|
close(done)
|
|
route.unmarkPort()
|
|
}()
|
|
|
|
select {
|
|
case <-done:
|
|
l.Info("Stopped listening")
|
|
return
|
|
case <-time.After(StreamStopListenTimeout):
|
|
l.Error("timed out waiting for connections")
|
|
return
|
|
}
|
|
}
|