proxyport/app/forward/forward.go

202 lines
3.3 KiB
Go

package forward
import (
"context"
"fmt"
"git.makemake.in/kzkzzzz/mycommon/mylog"
"proxyport/app/db"
"proxyport/app/model"
"sync"
)
type Protocol int
func (p Protocol) String() string {
switch p {
case 0:
return "TCP"
case 1:
return "UDP"
}
return "unknown"
}
const (
ProtocolTCP Protocol = 0
ProtocolUDP Protocol = 1
)
type IForward interface {
Forward() error
Stop()
}
var ListenerManager = &Manager{
lock: &sync.Mutex{},
}
type Info struct {
Id int
Name string
TargetAddr []string
LocalAddr string
LocalIp string
LocalPort int
Protocol Protocol
Status int
}
type activeForward struct {
forward IForward
info *Info
}
type forwardKey struct {
localAddr string
protocol Protocol
}
type Manager struct {
activeForwardMap map[forwardKey]*activeForward
lock *sync.Mutex
}
func (m *Manager) initForwardList() []*Info {
data := make([]*model.Forward, 0)
err := db.DB().Table("forward").Select("*").Find(&data).Error
if err != nil {
panic(err)
}
list := make([]*Info, 0)
for _, v := range data {
if v.Status == 0 {
continue
}
list = append(list, m.convertModel(v))
}
return list
}
func (m *Manager) convertModel(v *model.Forward) *Info {
info := &Info{
Id: v.Id,
Name: v.Name,
TargetAddr: v.TargetAddr,
LocalIp: v.LocalIp,
LocalPort: v.LocalPort,
Protocol: Protocol(v.Protocol),
Status: v.Status,
}
if v.LocalIp == "" {
info.LocalAddr = fmt.Sprintf("0.0.0.0:%d", v.LocalPort)
} else {
info.LocalAddr = fmt.Sprintf("%s:%d", v.LocalIp, v.LocalPort)
}
return info
}
func (m *Manager) Add(v *model.Forward) error {
m.lock.Lock()
defer m.lock.Unlock()
forwardInfo := m.convertModel(v)
key := forwardKey{
localAddr: forwardInfo.LocalAddr,
protocol: forwardInfo.Protocol,
}
_, ok := m.activeForwardMap[key]
if ok {
return fmt.Errorf("[%s] [%s] is exist", forwardInfo.Protocol, forwardInfo.LocalAddr)
}
tmp := &activeForward{
info: forwardInfo,
}
if Protocol(v.Protocol) == ProtocolUDP {
tmp.forward = NewUDP(forwardInfo)
} else {
tmp.forward = NewTCP(forwardInfo)
}
m.activeForwardMap[key] = tmp
err := tmp.forward.Forward()
if err != nil {
delete(m.activeForwardMap, key)
return err
}
return nil
}
func (m *Manager) Remove(v *model.Forward) {
m.lock.Lock()
defer m.lock.Unlock()
forwardInfo := m.convertModel(v)
key := forwardKey{
localAddr: forwardInfo.LocalAddr,
protocol: forwardInfo.Protocol,
}
fr, ok := m.activeForwardMap[key]
if !ok {
return
}
fr.forward.Stop()
delete(m.activeForwardMap, key)
}
func (m *Manager) Start(ctx context.Context) {
m.activeForwardMap = make(map[forwardKey]*activeForward)
list := m.initForwardList()
for _, v := range list {
key := forwardKey{
localAddr: v.LocalAddr,
protocol: v.Protocol,
}
switch v.Protocol {
case ProtocolTCP:
m.activeForwardMap[key] = &activeForward{
forward: NewTCP(v),
info: v,
}
case ProtocolUDP:
m.activeForwardMap[key] = &activeForward{
forward: NewUDP(v),
info: v,
}
}
}
for _, v := range m.activeForwardMap {
err := v.forward.Forward()
if err != nil {
mylog.Error(err)
}
}
select {
case <-ctx.Done():
m.Stop()
}
}
func (m *Manager) Stop() {
for _, v := range m.activeForwardMap {
v.forward.Stop()
}
}