P2p、install、log package

This commit is contained in:
刘河
2019-04-21 23:03:58 +08:00
parent 45521d5680
commit f6c596f318
16 changed files with 418 additions and 203 deletions

View File

@@ -1,13 +1,17 @@
package client
import (
"bufio"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/config"
"github.com/cnlh/nps/lib/conn"
"github.com/cnlh/nps/lib/crypt"
"github.com/cnlh/nps/lib/mux"
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
"github.com/cnlh/nps/vender/github.com/xtaci/kcp"
"net"
"net/http"
"strconv"
"time"
)
@@ -16,6 +20,7 @@ type TRPClient struct {
bridgeConnType string
proxyUrl string
vKey string
p2pAddr map[string]string
tunnel *mux.Mux
signal *conn.Conn
ticker *time.Ticker
@@ -26,6 +31,7 @@ type TRPClient struct {
func NewRPClient(svraddr string, vKey string, bridgeConnType string, proxyUrl string, cnf *config.Config) *TRPClient {
return &TRPClient{
svrAddr: svraddr,
p2pAddr: make(map[string]string, 0),
vKey: vKey,
bridgeConnType: bridgeConnType,
proxyUrl: proxyUrl,
@@ -71,18 +77,30 @@ func (s *TRPClient) handleMain() {
logs.Warn(err)
return
} else if pwd, err := s.signal.GetShortLenContent(); err == nil {
go s.newUdpConn(string(lAddr), string(pwd))
var localAddr string
//The local port remains unchanged for a certain period of time
if v, ok := s.p2pAddr[crypt.Md5(string(pwd)+strconv.Itoa(int(time.Now().Unix()/100)))]; !ok {
tmpConn, err := common.GetLocalUdpAddr()
if err != nil {
logs.Error(err)
return
}
localAddr = tmpConn.LocalAddr().String()
} else {
localAddr = v
}
go s.newUdpConn(localAddr, string(lAddr), string(pwd))
}
}
}
s.Close()
}
func (s *TRPClient) newUdpConn(rAddr string, md5Password string) {
func (s *TRPClient) newUdpConn(localAddr, rAddr string, md5Password string) {
var localConn net.PacketConn
var err error
var remoteAddress string
if remoteAddress, localConn, err = handleP2PUdp(rAddr, md5Password, common.WORK_P2P_PROVIDER); err != nil {
if remoteAddress, localConn, err = handleP2PUdp(localAddr, rAddr, md5Password, common.WORK_P2P_PROVIDER); err != nil {
logs.Error(err)
return
}
@@ -92,7 +110,6 @@ func (s *TRPClient) newUdpConn(rAddr string, md5Password string) {
return
}
logs.Trace("start local p2p udp listen, local address", localConn.LocalAddr().String())
//接收新的监听得到conn
for {
udpTunnel, err := l.AcceptKCP()
if err != nil {
@@ -104,14 +121,10 @@ func (s *TRPClient) newUdpConn(rAddr string, md5Password string) {
conn.SetUdpSession(udpTunnel)
logs.Trace("successful connection with client ,address %s", udpTunnel.RemoteAddr().String())
//read link info from remote
l := mux.NewMux(udpTunnel, s.bridgeConnType)
for {
connMux, err := l.Accept()
if err != nil {
continue
}
go s.handleChan(connMux)
}
conn.Accept(mux.NewMux(udpTunnel, s.bridgeConnType), func(c net.Conn) {
go s.handleChan(c)
})
break
}
}
}
@@ -144,7 +157,31 @@ func (s *TRPClient) handleChan(src net.Conn) {
}
//host for target processing
lk.Host = common.FormatAddress(lk.Host)
//connect to target
//if Conn type is http, read the request and log
if lk.ConnType == "http" {
if targetConn, err := net.Dial(common.CONN_TCP, lk.Host); err != nil {
logs.Warn("connect to %s error %s", lk.Host, err.Error())
src.Close()
} else {
go func() {
common.CopyBuffer(src, targetConn)
src.Close()
targetConn.Close()
}()
for {
if r, err := http.ReadRequest(bufio.NewReader(src)); err != nil {
src.Close()
targetConn.Close()
break
} else {
logs.Trace("http request, method %s, host %s, url %s, remote address %s", r.Method, r.Host, r.URL.Path, r.RemoteAddr)
r.Write(targetConn)
}
}
}
return
}
//connect to target if conn type is tcp or udp
if targetConn, err := net.Dial(lk.ConnType, lk.Host); err != nil {
logs.Warn("connect to %s error %s", lk.Host, err.Error())
src.Close()
@@ -154,6 +191,7 @@ func (s *TRPClient) handleChan(src net.Conn) {
}
}
// Whether the monitor channel is closed
func (s *TRPClient) ping() {
s.ticker = time.NewTicker(time.Second * 5)
loop:

View File

@@ -4,17 +4,19 @@ import (
"encoding/base64"
"encoding/binary"
"errors"
"fmt"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/config"
"github.com/cnlh/nps/lib/conn"
"github.com/cnlh/nps/lib/crypt"
"github.com/cnlh/nps/lib/version"
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
"github.com/cnlh/nps/vender/github.com/ccding/go-stun/stun"
"github.com/cnlh/nps/vender/github.com/xtaci/kcp"
"github.com/cnlh/nps/vender/golang.org/x/net/proxy"
"io/ioutil"
"log"
"math"
"math/rand"
"net"
"net/http"
"net/http/httputil"
@@ -276,108 +278,137 @@ func basicAuth(username, password string) string {
return base64.StdEncoding.EncodeToString([]byte(auth))
}
func handleP2PUdp(rAddr, md5Password, role string) (remoteAddress string, c net.PacketConn, err error) {
tmpConn, err := common.GetLocalUdpAddr()
func getRemoteAddressFromServer(rAddr string, localConn *net.UDPConn, md5Password, role string, add int) error {
rAddr, err := getNextAddr(rAddr, add)
if err != nil {
logs.Error(err)
return err
}
addr, err := net.ResolveUDPAddr("udp", rAddr)
if err != nil {
return err
}
if _, err := localConn.WriteTo(common.GetWriteStr(md5Password, role), addr); err != nil {
return err
}
return nil
}
func handleP2PUdp(localAddr, rAddr, md5Password, role string) (remoteAddress string, c net.PacketConn, err error) {
localConn, err := newUdpConnByAddr(localAddr)
if err != nil {
return
}
err = getRemoteAddressFromServer(rAddr, localConn, md5Password, role, 0)
if err != nil {
logs.Error(err)
return
}
localConn, err := newUdpConnByAddr(tmpConn.LocalAddr().String())
err = getRemoteAddressFromServer(rAddr, localConn, md5Password, role, 1)
if err != nil {
logs.Error(err)
return
}
localKcpConn, err := kcp.NewConn(rAddr, nil, 150, 3, localConn)
err = getRemoteAddressFromServer(rAddr, localConn, md5Password, role, 2)
if err != nil {
logs.Error(err)
return
}
conn.SetUdpSession(localKcpConn)
localToolConn := conn.NewConn(localKcpConn)
//get local nat type
//localNatType, host, err := stun.NewClient().Discover()
//if err != nil || host == nil {
// err = errors.New("get nat type error")
// return
//}
localNatType := stun.NATRestricted
//write password
if _, err = localToolConn.Write([]byte(md5Password)); err != nil {
var remoteAddr1, remoteAddr2, remoteAddr3 string
for {
buf := make([]byte, 1024)
if n, addr, er := localConn.ReadFromUDP(buf); er != nil {
err = er
return
} else {
rAddr2, _ := getNextAddr(rAddr, 1)
rAddr3, _ := getNextAddr(rAddr, 2)
switch addr.String() {
case rAddr:
remoteAddr1 = string(buf[:n])
case rAddr2:
remoteAddr2 = string(buf[:n])
case rAddr3:
remoteAddr3 = string(buf[:n])
}
}
if remoteAddr1 != "" && remoteAddr2 != "" && remoteAddr3 != "" {
break
}
}
if remoteAddress, err = sendP2PTestMsg(localConn, remoteAddr1, remoteAddr2, remoteAddr3); err != nil {
return
}
//write role
if _, err = localToolConn.Write([]byte(role)); err != nil {
return
}
if err = binary.Write(localToolConn, binary.LittleEndian, int32(localNatType)); err != nil {
return
}
//get another type address and nat type from server
var remoteAddr []byte
var remoteNatType int32
if remoteAddr, err = localToolConn.GetShortLenContent(); err != nil {
return
}
if err = binary.Read(localToolConn, binary.LittleEndian, &remoteNatType); err != nil {
return
}
localConn.Close()
//logs.Trace("remote nat type %d,local nat type %s", remoteNatType, localNatType)
if remoteAddress, err = sendP2PTestMsg(string(remoteAddr), tmpConn.LocalAddr().String()); err != nil {
return
}
c, err = newUdpConnByAddr(tmpConn.LocalAddr().String())
c, err = newUdpConnByAddr(localAddr)
return
}
func handleP2P(natType1, natType2 int, addr1, addr2 string, role string) (string, error) {
switch natType1 {
case int(stun.NATFull):
return sendP2PTestMsg(addr2, addr1)
case int(stun.NATRestricted):
switch natType2 {
case int(stun.NATFull), int(stun.NATRestricted), int(stun.NATPortRestricted), int(stun.NATSymetric):
return sendP2PTestMsg(addr2, addr1)
}
case int(stun.NATPortRestricted):
switch natType2 {
case int(stun.NATFull), int(stun.NATRestricted), int(stun.NATPortRestricted):
return sendP2PTestMsg(addr2, addr1)
}
case int(stun.NATSymetric):
switch natType2 {
case int(stun.NATFull), int(stun.NATRestricted):
return sendP2PTestMsg(addr2, addr1)
}
}
return "", errors.New("not support p2p")
}
func sendP2PTestMsg(remoteAddr string, localAddr string) (string, error) {
remoteUdpAddr, err := net.ResolveUDPAddr("udp", remoteAddr)
if err != nil {
return "", err
}
localConn, err := newUdpConnByAddr(localAddr)
if err != nil {
return "", err
}
func sendP2PTestMsg(localConn *net.UDPConn, remoteAddr1, remoteAddr2, remoteAddr3 string) (string, error) {
logs.Trace(remoteAddr3, remoteAddr2, remoteAddr1)
defer localConn.Close()
ticker := time.NewTicker(time.Millisecond * 500)
go func(ticker *time.Ticker) {
isClose := false
defer func() { isClose = true }()
interval, err := getAddrInterval(remoteAddr1, remoteAddr2, remoteAddr3)
if err != nil {
return "", err
}
go func() {
addr, err := getNextAddr(remoteAddr3, interval)
if err != nil {
return
}
remoteUdpAddr, err := net.ResolveUDPAddr("udp", addr)
if err != nil {
return
}
logs.Trace("try send test packet to target %s", addr)
ticker := time.NewTicker(time.Millisecond * 500)
for {
select {
case <-ticker.C:
logs.Trace("try send test packet to target %s", remoteAddr)
if isClose {
return
}
if _, err := localConn.WriteTo([]byte(common.WORK_P2P_CONNECT), remoteUdpAddr); err != nil {
return
}
}
}
}(ticker)
}()
if interval != 0 {
ip := common.GetIpByAddr(remoteAddr2)
go func() {
ports := getRandomPortArr(common.GetPortByAddr(remoteAddr3), common.GetPortByAddr(remoteAddr3)+interval*50)
for i := 0; i <= 50; i ++ {
go func(port int) {
trueAddress := ip + ":" + strconv.Itoa(port)
logs.Trace("try send test packet to target %s", trueAddress)
remoteUdpAddr, err := net.ResolveUDPAddr("udp", trueAddress)
if err != nil {
return
}
ticker := time.NewTicker(time.Second * 2)
for {
select {
case <-ticker.C:
if isClose {
return
}
if _, err := localConn.WriteTo([]byte(common.WORK_P2P_CONNECT), remoteUdpAddr); err != nil {
return
}
}
}
}(ports[i])
time.Sleep(time.Millisecond * 10)
}
}()
}
buf := make([]byte, 10)
for {
localConn.SetReadDeadline(time.Now().Add(time.Second * 30))
localConn.SetReadDeadline(time.Now().Add(time.Second * 10))
n, addr, err := localConn.ReadFromUDP(buf)
localConn.SetReadDeadline(time.Time{})
if err != nil {
@@ -397,7 +428,7 @@ func sendP2PTestMsg(remoteAddr string, localAddr string) (string, error) {
case common.WORK_P2P_CONNECT:
go func() {
for i := 20; i > 0; i-- {
logs.Trace("try send receive success packet to target %s", remoteAddr)
logs.Trace("try send receive success packet to target %s", addr.String())
if _, err = localConn.WriteTo([]byte(common.WORK_P2P_SUCCESS), addr); err != nil {
return
}
@@ -407,9 +438,7 @@ func sendP2PTestMsg(remoteAddr string, localAddr string) (string, error) {
default:
continue
}
ticker.Stop()
}
ticker.Stop()
return "", errors.New("connect to the target failed, maybe the nat type is not support p2p")
}
@@ -424,3 +453,66 @@ func newUdpConnByAddr(addr string) (*net.UDPConn, error) {
}
return udpConn, nil
}
func getNextAddr(addr string, n int) (string, error) {
arr := strings.Split(addr, ":")
if len(arr) != 2 {
return "", errors.New(fmt.Sprintf("the format of %s incorrect", addr))
}
if p, err := strconv.Atoi(arr[1]); err != nil {
return "", err
} else {
return arr[0] + ":" + strconv.Itoa(p+n), nil
}
}
func getAddrInterval(addr1, addr2, addr3 string) (int, error) {
arr1 := strings.Split(addr1, ":")
if len(arr1) != 2 {
return 0, errors.New(fmt.Sprintf("the format of %s incorrect", addr1))
}
arr2 := strings.Split(addr2, ":")
if len(arr2) != 2 {
return 0, errors.New(fmt.Sprintf("the format of %s incorrect", addr2))
}
arr3 := strings.Split(addr3, ":")
if len(arr3) != 2 {
return 0, errors.New(fmt.Sprintf("the format of %s incorrect", addr3))
}
p1, err := strconv.Atoi(arr1[1])
if err != nil {
return 0, err
}
p2, err := strconv.Atoi(arr2[1])
if err != nil {
return 0, err
}
p3, err := strconv.Atoi(arr3[1])
if err != nil {
return 0, err
}
interVal := int(math.Floor(math.Min(math.Abs(float64(p3-p2)), math.Abs(float64(p2-p1)))))
if p3-p1 < 0 {
return -interVal, nil
}
return interVal, nil
}
func getRandomPortArr(min, max int) []int {
if min > max {
min, max = max, min
}
addrAddr := make([]int, max-min+1)
for i := min; i <= max; i++ {
addrAddr[max-i] = i
}
rand.Seed(time.Now().UnixNano())
var r, temp int
for i := max - min; i > 0; i-- {
r = rand.Int() % i
temp = addrAddr[i]
addrAddr[i] = addrAddr[r]
addrAddr[r] = temp
}
return addrAddr
}

View File

@@ -7,22 +7,36 @@ import (
"github.com/cnlh/nps/lib/crypt"
"github.com/cnlh/nps/lib/file"
"github.com/cnlh/nps/lib/mux"
"github.com/cnlh/nps/server/proxy"
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
"github.com/cnlh/nps/vender/github.com/xtaci/kcp"
"net"
"net/http"
"sync"
)
var (
LocalServer []*net.TCPListener
udpConn net.Conn
muxSession *mux.Mux
fileServer []*http.Server
lock sync.Mutex
hasP2PTry bool
LocalServer []*net.TCPListener
udpConn net.Conn
muxSession *mux.Mux
fileServer []*http.Server
p2pNetBridge *p2pBridge
)
type p2pBridge struct {
}
func (p2pBridge *p2pBridge) SendLinkInfo(clientId int, link *conn.Link, t *file.Tunnel) (target net.Conn, err error) {
nowConn, err := muxSession.NewConn()
if err != nil {
udpConn = nil
return nil, err
}
if _, err := conn.NewConn(nowConn).SendInfo(link, ""); err != nil {
return nil, err
}
return nowConn, nil
}
func CloseLocalServer() {
for _, v := range LocalServer {
v.Close()
@@ -48,20 +62,58 @@ func startLocalFileServer(config *config.CommonConfig, t *file.Tunnel, vkey stri
}
func StartLocalServer(l *config.LocalServer, config *config.CommonConfig) error {
listener, err := net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), l.Port, ""})
tmpConn, err := common.GetLocalUdpAddr()
if err != nil {
logs.Error("local listener startup failed port %d, error %s", l.Port, err.Error())
return err
}
LocalServer = append(LocalServer, listener)
logs.Info("successful start-up of local monitoring, port", l.Port)
conn.Accept(listener, func(c net.Conn) {
if l.Type == "secret" {
handleSecret(c, config, l)
} else {
handleP2PVisitor(c, config, l)
for i := 0; i < 10; i++ {
logs.Notice("try to connect to the server", i+1)
newUdpConn(tmpConn.LocalAddr().String(), config, l)
if udpConn != nil {
break
}
})
}
task := &file.Tunnel{
Port: l.Port,
ServerIp: "0.0.0.0",
Status: true,
Client: &file.Client{
Cnf: &file.Config{
U: "",
P: "",
Compress: config.Client.Cnf.Compress,
},
Status: true,
RateLimit: 0,
Flow: &file.Flow{},
},
Flow: &file.Flow{},
Target: &file.Target{},
}
switch l.Type {
case "p2ps":
logs.Info("successful start-up of local socks5 monitoring, port", l.Port)
return proxy.NewSock5ModeServer(p2pNetBridge, task).Start()
case "p2pt":
logs.Info("successful start-up of local tcp trans monitoring, port", l.Port)
return proxy.NewTunnelModeServer(proxy.HandleTrans, p2pNetBridge, task).Start()
case "p2p", "secret":
listener, err := net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), l.Port, ""})
if err != nil {
logs.Error("local listener startup failed port %d, error %s", l.Port, err.Error())
return err
}
LocalServer = append(LocalServer, listener)
logs.Info("successful start-up of local tcp monitoring, port", l.Port)
conn.Accept(listener, func(c net.Conn) {
logs.Trace("new %s connection", l.Type)
if l.Type == "secret" {
handleSecret(c, config, l)
} else if l.Type == "p2p" {
handleP2PVisitor(c, config, l)
}
})
}
return nil
}
@@ -79,41 +131,22 @@ func handleSecret(localTcpConn net.Conn, config *config.CommonConfig, l *config.
}
func handleP2PVisitor(localTcpConn net.Conn, config *config.CommonConfig, l *config.LocalServer) {
restart:
lock.Lock()
if udpConn == nil {
if !hasP2PTry {
hasP2PTry = true
newUdpConn(config, l)
}
if udpConn == nil {
lock.Unlock()
logs.Notice("new conn, P2P can not penetrate successfully, traffic will be transferred through the server")
handleSecret(localTcpConn, config, l)
return
} else {
muxSession = mux.NewMux(udpConn, "kcp")
}
logs.Notice("new conn, P2P can not penetrate successfully, traffic will be transferred through the server")
handleSecret(localTcpConn, config, l)
}
lock.Unlock()
logs.Trace("start trying to connect with the server")
nowConn, err := muxSession.NewConn()
if err != nil {
udpConn = nil
logs.Error(err, "reconnect......")
goto restart
return
}
//TODO just support compress now because there is not tls file in client packages
link := conn.NewLink(common.CONN_TCP, l.Target, false, config.Client.Cnf.Compress, localTcpConn.LocalAddr().String(), false)
if _, err := conn.NewConn(nowConn).SendInfo(link, ""); err != nil {
if target, err := p2pNetBridge.SendLinkInfo(0, link, nil); err != nil {
logs.Error(err)
return
} else {
conn.CopyWaitGroup(target, localTcpConn, false, config.Client.Cnf.Compress, nil, nil, false, nil)
}
conn.CopyWaitGroup(nowConn, localTcpConn, false, config.Client.Cnf.Compress, nil, nil, false, nil)
}
func newUdpConn(config *config.CommonConfig, l *config.LocalServer) {
func newUdpConn(localAddr string, config *config.CommonConfig, l *config.LocalServer) {
remoteConn, err := NewConn(config.Tp, config.VKey, config.Server, common.WORK_P2P, config.ProxyUrl)
if err != nil {
logs.Error("Local connection server failed ", err.Error())
@@ -131,7 +164,7 @@ func newUdpConn(config *config.CommonConfig, l *config.LocalServer) {
}
var localConn net.PacketConn
var remoteAddress string
if remoteAddress, localConn, err = handleP2PUdp(string(rAddr), crypt.Md5(l.Password), common.WORK_P2P_VISITOR); err != nil {
if remoteAddress, localConn, err = handleP2PUdp(localAddr, string(rAddr), crypt.Md5(l.Password), common.WORK_P2P_VISITOR); err != nil {
logs.Error(err)
return
}
@@ -143,4 +176,6 @@ func newUdpConn(config *config.CommonConfig, l *config.LocalServer) {
logs.Trace("successful create a connection with server", remoteAddress)
conn.SetUdpSession(udpTunnel)
udpConn = udpTunnel
muxSession = mux.NewMux(udpConn, "kcp")
p2pNetBridge = &p2pBridge{}
}