nps/bridge/bridge.go

485 lines
12 KiB
Go
Raw Normal View History

2019-01-09 12:33:00 +00:00
package bridge
import (
2019-02-12 19:54:00 +00:00
"encoding/binary"
2019-01-09 12:33:00 +00:00
"errors"
2019-02-16 12:43:26 +00:00
"fmt"
2019-02-12 19:54:00 +00:00
"github.com/cnlh/nps/lib/common"
2019-02-09 09:07:47 +00:00
"github.com/cnlh/nps/lib/conn"
2019-02-12 19:54:00 +00:00
"github.com/cnlh/nps/lib/crypt"
2019-02-09 09:07:47 +00:00
"github.com/cnlh/nps/lib/file"
"github.com/cnlh/nps/lib/mux"
2019-02-23 15:29:48 +00:00
"github.com/cnlh/nps/lib/version"
2019-02-12 19:54:00 +00:00
"github.com/cnlh/nps/server/tool"
2019-02-26 14:40:28 +00:00
"github.com/cnlh/nps/vender/github.com/astaxie/beego"
2019-02-23 15:29:48 +00:00
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
2019-02-16 12:43:26 +00:00
"github.com/cnlh/nps/vender/github.com/xtaci/kcp"
2019-01-09 12:33:00 +00:00
"net"
2019-02-09 09:07:47 +00:00
"strconv"
2019-01-09 12:33:00 +00:00
"sync"
"time"
)
type Client struct {
2019-03-02 09:43:21 +00:00
tunnel *mux.Mux
signal *conn.Conn
file *mux.Mux
retryTime int // it will be add 1 when ping not ok until to 3 will close the client
sync.RWMutex
2019-01-09 12:33:00 +00:00
}
2019-03-02 09:43:21 +00:00
func NewClient(t, f *mux.Mux, s *conn.Conn) *Client {
2019-02-09 09:07:47 +00:00
return &Client{
signal: s,
tunnel: t,
2019-03-02 09:43:21 +00:00
file: f,
2019-02-09 09:07:47 +00:00
}
}
2019-01-26 09:27:28 +00:00
type Bridge struct {
2019-02-16 12:43:26 +00:00
TunnelPort int //通信隧道端口
tcpListener *net.TCPListener //server端监听
kcpListener *kcp.Listener //server端监听
Client map[int]*Client
tunnelType string //bridge type kcp or tcp
OpenTask chan *file.Tunnel
CloseClient chan int
2019-02-23 15:29:48 +00:00
SecretChan chan *conn.Secret
2019-02-16 12:43:26 +00:00
clientLock sync.RWMutex
Register map[string]time.Time
registerLock sync.RWMutex
ipVerify bool
2019-02-16 15:18:58 +00:00
runList map[int]interface{}
2019-01-09 12:33:00 +00:00
}
2019-02-16 15:18:58 +00:00
func NewTunnel(tunnelPort int, tunnelType string, ipVerify bool, runList map[int]interface{}) *Bridge {
2019-01-26 09:27:28 +00:00
t := new(Bridge)
2019-01-09 12:33:00 +00:00
t.TunnelPort = tunnelPort
t.Client = make(map[int]*Client)
2019-02-09 09:07:47 +00:00
t.tunnelType = tunnelType
2019-02-12 19:54:00 +00:00
t.OpenTask = make(chan *file.Tunnel)
t.CloseClient = make(chan int)
2019-02-16 12:43:26 +00:00
t.Register = make(map[string]time.Time)
t.ipVerify = ipVerify
2019-02-16 15:18:58 +00:00
t.runList = runList
2019-02-23 15:29:48 +00:00
t.SecretChan = make(chan *conn.Secret)
2019-01-09 12:33:00 +00:00
return t
}
2019-01-26 09:27:28 +00:00
func (s *Bridge) StartTunnel() error {
2019-03-02 09:43:21 +00:00
go s.ping()
2019-01-09 12:33:00 +00:00
var err error
2019-02-09 09:07:47 +00:00
if s.tunnelType == "kcp" {
s.kcpListener, err = kcp.ListenWithOptions(":"+strconv.Itoa(s.TunnelPort), nil, 150, 3)
if err != nil {
return err
}
go func() {
for {
c, err := s.kcpListener.AcceptKCP()
conn.SetUdpSession(c)
if err != nil {
2019-02-23 15:29:48 +00:00
logs.Warn(err)
2019-02-09 09:07:47 +00:00
continue
}
go s.cliProcess(conn.NewConn(c))
}
}()
} else {
s.tcpListener, err = net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), s.TunnelPort, ""})
2019-01-09 12:33:00 +00:00
if err != nil {
2019-02-09 09:07:47 +00:00
return err
2019-01-09 12:33:00 +00:00
}
2019-02-09 09:07:47 +00:00
go func() {
for {
c, err := s.tcpListener.Accept()
if err != nil {
2019-02-23 15:29:48 +00:00
logs.Warn(err)
2019-02-09 09:07:47 +00:00
continue
}
go s.cliProcess(conn.NewConn(c))
}
}()
2019-01-09 12:33:00 +00:00
}
2019-02-09 09:07:47 +00:00
return nil
2019-01-09 12:33:00 +00:00
}
//验证失败返回错误验证flag并且关闭连接
2019-02-09 09:07:47 +00:00
func (s *Bridge) verifyError(c *conn.Conn) {
c.Write([]byte(common.VERIFY_EER))
2019-01-09 12:33:00 +00:00
c.Conn.Close()
}
2019-02-12 19:54:00 +00:00
func (s *Bridge) verifySuccess(c *conn.Conn) {
c.Write([]byte(common.VERIFY_SUCCESS))
}
2019-02-09 09:07:47 +00:00
func (s *Bridge) cliProcess(c *conn.Conn) {
//version check
if b, err := c.GetShortContent(32); err != nil || string(b) != crypt.Md5(version.GetVersion()) {
2019-02-23 15:29:48 +00:00
logs.Info("The client %s version does not match", c.Conn.RemoteAddr())
c.Close()
return
}
2019-03-02 09:43:21 +00:00
//write server version to client
2019-02-24 05:17:43 +00:00
c.Write([]byte(crypt.Md5(version.GetVersion())))
2019-02-09 09:07:47 +00:00
c.SetReadDeadline(5, s.tunnelType)
2019-01-28 06:45:55 +00:00
var buf []byte
var err error
2019-03-02 09:43:21 +00:00
//get vkey from client
if buf, err = c.GetShortContent(32); err != nil {
2019-01-28 06:45:55 +00:00
c.Close()
return
2019-01-09 12:33:00 +00:00
}
2019-03-02 09:43:21 +00:00
//verify
2019-02-09 09:07:47 +00:00
id, err := file.GetCsvDb().GetIdByVerifyKey(string(buf), c.Conn.RemoteAddr().String())
if err != nil {
2019-02-23 15:29:48 +00:00
logs.Info("Current client connection validation error, close this client:", c.Conn.RemoteAddr())
2019-01-09 12:33:00 +00:00
s.verifyError(c)
2019-01-28 06:45:55 +00:00
return
2019-02-12 19:54:00 +00:00
} else {
s.verifySuccess(c)
2019-01-09 12:33:00 +00:00
}
//做一个判断 添加到对应的channel里面以供使用
2019-01-28 06:45:55 +00:00
if flag, err := c.ReadFlag(); err == nil {
s.typeDeal(flag, c, id)
2019-02-12 19:54:00 +00:00
} else {
2019-02-23 15:29:48 +00:00
logs.Warn(err, flag)
2019-01-28 06:45:55 +00:00
}
return
}
func (s *Bridge) DelClient(id int, isOther bool) {
2019-02-17 11:36:48 +00:00
s.clientLock.Lock()
defer s.clientLock.Unlock()
if v, ok := s.Client[id]; ok {
if c, err := file.GetCsvDb().GetClient(id); err == nil && c.NoStore {
s.CloseClient <- c.Id
}
2019-03-02 09:43:21 +00:00
if v.signal != nil {
v.signal.Close()
}
2019-02-17 11:36:48 +00:00
delete(s.Client, id)
}
}
2019-01-09 12:33:00 +00:00
//use different
2019-02-09 09:07:47 +00:00
func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int) {
2019-01-09 12:33:00 +00:00
switch typeVal {
2019-02-09 09:07:47 +00:00
case common.WORK_MAIN:
//the vKey connect by another ,close the client of before
s.clientLock.Lock()
2019-02-09 09:07:47 +00:00
if v, ok := s.Client[id]; ok {
s.clientLock.Unlock()
2019-02-09 09:07:47 +00:00
if v.signal != nil {
v.signal.WriteClose()
}
v.Lock()
v.signal = c
v.Unlock()
} else {
2019-03-02 09:43:21 +00:00
s.Client[id] = NewClient(nil, nil, c)
s.clientLock.Unlock()
}
2019-02-23 15:29:48 +00:00
logs.Info("clientId %d connection succeeded, address:%s ", id, c.Conn.RemoteAddr())
2019-02-09 09:07:47 +00:00
case common.WORK_CHAN:
s.clientLock.Lock()
if v, ok := s.Client[id]; ok {
s.clientLock.Unlock()
2019-02-09 09:07:47 +00:00
v.Lock()
v.tunnel = mux.NewMux(c.Conn)
2019-02-09 09:07:47 +00:00
v.Unlock()
} else {
2019-03-02 09:43:21 +00:00
s.Client[id] = NewClient(mux.NewMux(c.Conn), nil, nil)
s.clientLock.Unlock()
}
2019-02-12 19:54:00 +00:00
case common.WORK_CONFIG:
2019-03-02 09:43:21 +00:00
var isPub bool
client, err := file.GetCsvDb().GetClient(id);
if err == nil {
if client.VerifyKey == beego.AppConfig.String("publicVkey") {
isPub = true
} else {
isPub = false
}
}
binary.Write(c, binary.LittleEndian, isPub)
go s.getConfig(c, isPub, client)
2019-02-16 12:43:26 +00:00
case common.WORK_REGISTER:
go s.register(c)
2019-02-26 14:40:28 +00:00
case common.WORK_SECRET:
if b, err := c.GetShortContent(32); err == nil {
2019-02-23 15:29:48 +00:00
s.SecretChan <- conn.NewSecret(string(b), c)
}
2019-03-02 09:43:21 +00:00
case common.WORK_FILE:
s.clientLock.Lock()
if v, ok := s.Client[id]; ok {
s.clientLock.Unlock()
v.Lock()
v.file = mux.NewMux(c.Conn)
v.Unlock()
} else {
s.Client[id] = NewClient(nil, mux.NewMux(c.Conn), nil)
s.clientLock.Unlock()
}
2019-02-26 14:40:28 +00:00
case common.WORK_P2P:
//read md5 secret
if b, err := c.GetShortContent(32); err != nil {
2019-02-26 14:40:28 +00:00
return
} else if t := file.GetCsvDb().GetTaskByMd5Password(string(b)); t == nil {
return
} else {
s.clientLock.Lock()
if v, ok := s.Client[t.Client.Id]; !ok {
s.clientLock.Unlock()
return
} else {
s.clientLock.Unlock()
//向密钥对应的客户端发送与服务端udp建立连接信息地址密钥
v.signal.Write([]byte(common.NEW_UDP_CONN))
2019-02-26 14:40:28 +00:00
svrAddr := beego.AppConfig.String("serverIp") + ":" + beego.AppConfig.String("p2pPort")
if err != nil {
logs.Warn("get local udp addr error")
return
}
v.signal.WriteLenContent([]byte(svrAddr))
v.signal.WriteLenContent(b)
2019-02-26 14:40:28 +00:00
//向该请求者发送建立连接请求,服务器地址
c.WriteLenContent([]byte(svrAddr))
}
}
2019-01-09 12:33:00 +00:00
}
2019-02-09 09:07:47 +00:00
c.SetAlive(s.tunnelType)
2019-01-28 06:45:55 +00:00
return
2019-01-09 12:33:00 +00:00
}
//register ip
2019-02-16 12:43:26 +00:00
func (s *Bridge) register(c *conn.Conn) {
var hour int32
if err := binary.Read(c, binary.LittleEndian, &hour); err == nil {
s.registerLock.Lock()
s.Register[common.GetIpByAddr(c.Conn.RemoteAddr().String())] = time.Now().Add(time.Hour * time.Duration(hour))
s.registerLock.Unlock()
}
}
2019-03-02 09:43:21 +00:00
func (s *Bridge) SendLinkInfo(clientId int, link *conn.Link, linkAddr string, t *file.Tunnel) (target net.Conn, err error) {
s.clientLock.Lock()
if v, ok := s.Client[clientId]; ok {
s.clientLock.Unlock()
2019-03-02 09:43:21 +00:00
//If ip is restricted to do ip verification
2019-02-16 12:43:26 +00:00
if s.ipVerify {
s.registerLock.Lock()
ip := common.GetIpByAddr(linkAddr)
if v, ok := s.Register[ip]; !ok {
s.registerLock.Unlock()
return nil, errors.New(fmt.Sprintf("The ip %s is not in the validation list", ip))
} else {
if !v.After(time.Now()) {
return nil, errors.New(fmt.Sprintf("The validity of the ip %s has expired", ip))
}
}
s.registerLock.Unlock()
}
2019-03-02 09:43:21 +00:00
var tunnel *mux.Mux
if t != nil && t.Mode == "file" {
tunnel = v.file
} else {
tunnel = v.tunnel
}
if tunnel == nil {
err = errors.New("the client connect error")
return
}
2019-02-17 11:36:48 +00:00
2019-03-02 09:43:21 +00:00
if target, err = tunnel.NewConn(); err != nil {
return
}
if t != nil && t.Mode == "file" {
return
}
if _, err = conn.NewConn(target).SendLinkInfo(link); err != nil {
2019-03-02 09:43:21 +00:00
logs.Info("new connect error ,the target %s refuse to connect", link.Host)
return
}
} else {
s.clientLock.Unlock()
2019-02-23 15:29:48 +00:00
err = errors.New(fmt.Sprintf("the client %d is not connect", clientId))
2019-01-09 12:33:00 +00:00
}
return
2019-01-09 12:33:00 +00:00
}
2019-03-02 09:43:21 +00:00
func (s *Bridge) ping() {
ticker := time.NewTicker(time.Second * 5)
for {
select {
case <-ticker.C:
s.clientLock.Lock()
arr := make([]int, 0)
for k, v := range s.Client {
2019-03-02 12:12:58 +00:00
if v.tunnel == nil || v.signal == nil {
2019-03-02 09:43:21 +00:00
v.retryTime += 1
if v.retryTime >= 3 {
arr = append(arr, k)
}
continue
}
if v.tunnel.IsClose {
arr = append(arr, k)
}
}
s.clientLock.Unlock()
for _, v := range arr {
logs.Info("the client %d closed", v)
s.DelClient(v, false)
}
}
}
}
//get config and add task from client config
2019-03-02 09:43:21 +00:00
func (s *Bridge) getConfig(c *conn.Conn, isPub bool, client *file.Client) {
2019-02-12 19:54:00 +00:00
var fail bool
2019-02-23 15:29:48 +00:00
2019-02-12 19:54:00 +00:00
for {
flag, err := c.ReadFlag()
if err != nil {
break
}
switch flag {
case common.WORK_STATUS:
if b, err := c.GetShortContent(32); err != nil {
2019-02-12 19:54:00 +00:00
break
} else {
var str string
id, err := file.GetCsvDb().GetClientIdByVkey(string(b))
if err != nil {
break
}
for _, v := range file.GetCsvDb().Hosts {
if v.Client.Id == id {
str += v.Remark + common.CONN_DATA_SEQ
}
}
for _, v := range file.GetCsvDb().Tasks {
2019-02-16 15:18:58 +00:00
if _, ok := s.runList[v.Id]; ok && v.Client.Id == id {
2019-02-12 19:54:00 +00:00
str += v.Remark + common.CONN_DATA_SEQ
}
}
binary.Write(c, binary.LittleEndian, int32(len([]byte(str))))
binary.Write(c, binary.LittleEndian, []byte(str))
}
case common.NEW_CONF:
2019-02-23 15:29:48 +00:00
var err error
if client, err = c.GetConfigInfo(); err != nil {
2019-02-12 19:54:00 +00:00
fail = true
c.WriteAddFail()
break
} else {
2019-02-24 05:17:43 +00:00
if err = file.GetCsvDb().NewClient(client); err != nil {
fail = true
c.WriteAddFail()
break
}
2019-02-12 19:54:00 +00:00
c.WriteAddOk()
2019-02-24 05:17:43 +00:00
c.Write([]byte(client.VerifyKey))
2019-03-02 12:12:58 +00:00
s.clientLock.Lock()
s.Client[client.Id] = NewClient(nil, nil, nil)
s.clientLock.Unlock()
2019-02-12 19:54:00 +00:00
}
case common.NEW_HOST:
2019-03-02 09:43:21 +00:00
h, err := c.GetHostInfo()
if err != nil {
2019-02-12 19:54:00 +00:00
fail = true
c.WriteAddFail()
2019-02-23 15:29:48 +00:00
break
2019-03-02 09:43:21 +00:00
}
h.Client = client
if h.Location == "" {
h.Location = "/"
}
if !client.HasHost(h) {
if file.GetCsvDb().IsHostExist(h) {
fail = true
c.WriteAddFail()
break
} else {
file.GetCsvDb().NewHost(h)
c.WriteAddOk()
}
2019-02-12 19:54:00 +00:00
} else {
c.WriteAddOk()
}
case common.NEW_TASK:
if t, err := c.GetTaskInfo(); err != nil {
fail = true
c.WriteAddFail()
break
} else {
2019-02-15 14:59:28 +00:00
ports := common.GetPorts(t.Ports)
targets := common.GetPorts(t.Target)
if len(ports) > 1 && (t.Mode == "tcp" || t.Mode == "udp") && (len(ports) != len(targets)) {
2019-02-12 19:54:00 +00:00
fail = true
c.WriteAddFail()
2019-02-15 14:59:28 +00:00
break
} else if t.Mode == "secret" {
2019-02-23 15:29:48 +00:00
ports = append(ports, 0)
}
if len(ports) == 0 {
fail = true
c.WriteAddFail()
break
2019-02-15 14:59:28 +00:00
}
for i := 0; i < len(ports); i++ {
tl := new(file.Tunnel)
tl.Mode = t.Mode
tl.Port = ports[i]
if len(ports) == 1 {
tl.Target = t.Target
2019-02-16 15:18:58 +00:00
tl.Remark = t.Remark
2019-02-15 14:59:28 +00:00
} else {
2019-02-16 15:18:58 +00:00
tl.Remark = t.Remark + "_" + strconv.Itoa(tl.Port)
if t.TargetAddr != "" {
tl.Target = t.TargetAddr + ":" + strconv.Itoa(targets[i])
} else {
tl.Target = strconv.Itoa(targets[i])
}
2019-02-15 14:59:28 +00:00
}
tl.Id = file.GetCsvDb().GetTaskId()
tl.Status = true
tl.Flow = new(file.Flow)
tl.NoStore = true
tl.Client = client
2019-02-23 15:29:48 +00:00
tl.Password = t.Password
2019-03-02 09:43:21 +00:00
tl.LocalPath = t.LocalPath
tl.StripPre = t.StripPre
if !client.HasTunnel(tl) {
if err := file.GetCsvDb().NewTask(tl); err != nil {
logs.Notice("Add task error ", err.Error())
fail = true
c.WriteAddFail()
break
}
if b := tool.TestServerPort(tl.Port, tl.Mode); !b && t.Mode != "secret" && t.Mode != "p2p" {
fail = true
c.WriteAddFail()
break
} else {
s.OpenTask <- tl
}
2019-02-15 14:59:28 +00:00
}
c.WriteAddOk()
2019-02-12 19:54:00 +00:00
}
}
2019-01-09 12:33:00 +00:00
}
}
2019-02-12 19:54:00 +00:00
if fail && client != nil {
2019-03-02 09:43:21 +00:00
s.DelClient(client.Id, false)
2019-02-12 19:54:00 +00:00
}
c.Close()
2019-01-09 12:33:00 +00:00
}