P2p、install、log package

pull/121/head
刘河 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 package client
import ( import (
"bufio"
"github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/config" "github.com/cnlh/nps/lib/config"
"github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/conn"
"github.com/cnlh/nps/lib/crypt"
"github.com/cnlh/nps/lib/mux" "github.com/cnlh/nps/lib/mux"
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
"github.com/cnlh/nps/vender/github.com/xtaci/kcp" "github.com/cnlh/nps/vender/github.com/xtaci/kcp"
"net" "net"
"net/http"
"strconv"
"time" "time"
) )
@ -16,6 +20,7 @@ type TRPClient struct {
bridgeConnType string bridgeConnType string
proxyUrl string proxyUrl string
vKey string vKey string
p2pAddr map[string]string
tunnel *mux.Mux tunnel *mux.Mux
signal *conn.Conn signal *conn.Conn
ticker *time.Ticker ticker *time.Ticker
@ -26,6 +31,7 @@ type TRPClient struct {
func NewRPClient(svraddr string, vKey string, bridgeConnType string, proxyUrl string, cnf *config.Config) *TRPClient { func NewRPClient(svraddr string, vKey string, bridgeConnType string, proxyUrl string, cnf *config.Config) *TRPClient {
return &TRPClient{ return &TRPClient{
svrAddr: svraddr, svrAddr: svraddr,
p2pAddr: make(map[string]string, 0),
vKey: vKey, vKey: vKey,
bridgeConnType: bridgeConnType, bridgeConnType: bridgeConnType,
proxyUrl: proxyUrl, proxyUrl: proxyUrl,
@ -71,18 +77,30 @@ func (s *TRPClient) handleMain() {
logs.Warn(err) logs.Warn(err)
return return
} else if pwd, err := s.signal.GetShortLenContent(); err == nil { } 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() s.Close()
} }
func (s *TRPClient) newUdpConn(rAddr string, md5Password string) { func (s *TRPClient) newUdpConn(localAddr, rAddr string, md5Password string) {
var localConn net.PacketConn var localConn net.PacketConn
var err error var err error
var remoteAddress string 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) logs.Error(err)
return return
} }
@ -92,7 +110,6 @@ func (s *TRPClient) newUdpConn(rAddr string, md5Password string) {
return return
} }
logs.Trace("start local p2p udp listen, local address", localConn.LocalAddr().String()) logs.Trace("start local p2p udp listen, local address", localConn.LocalAddr().String())
//接收新的监听得到conn
for { for {
udpTunnel, err := l.AcceptKCP() udpTunnel, err := l.AcceptKCP()
if err != nil { if err != nil {
@ -104,14 +121,10 @@ func (s *TRPClient) newUdpConn(rAddr string, md5Password string) {
conn.SetUdpSession(udpTunnel) conn.SetUdpSession(udpTunnel)
logs.Trace("successful connection with client ,address %s", udpTunnel.RemoteAddr().String()) logs.Trace("successful connection with client ,address %s", udpTunnel.RemoteAddr().String())
//read link info from remote //read link info from remote
l := mux.NewMux(udpTunnel, s.bridgeConnType) conn.Accept(mux.NewMux(udpTunnel, s.bridgeConnType), func(c net.Conn) {
for { go s.handleChan(c)
connMux, err := l.Accept() })
if err != nil { break
continue
}
go s.handleChan(connMux)
}
} }
} }
} }
@ -144,7 +157,31 @@ func (s *TRPClient) handleChan(src net.Conn) {
} }
//host for target processing //host for target processing
lk.Host = common.FormatAddress(lk.Host) 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 { if targetConn, err := net.Dial(lk.ConnType, lk.Host); err != nil {
logs.Warn("connect to %s error %s", lk.Host, err.Error()) logs.Warn("connect to %s error %s", lk.Host, err.Error())
src.Close() src.Close()
@ -154,6 +191,7 @@ func (s *TRPClient) handleChan(src net.Conn) {
} }
} }
// Whether the monitor channel is closed
func (s *TRPClient) ping() { func (s *TRPClient) ping() {
s.ticker = time.NewTicker(time.Second * 5) s.ticker = time.NewTicker(time.Second * 5)
loop: loop:

View File

@ -4,17 +4,19 @@ import (
"encoding/base64" "encoding/base64"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt"
"github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/config" "github.com/cnlh/nps/lib/config"
"github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/conn"
"github.com/cnlh/nps/lib/crypt" "github.com/cnlh/nps/lib/crypt"
"github.com/cnlh/nps/lib/version" "github.com/cnlh/nps/lib/version"
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" "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/github.com/xtaci/kcp"
"github.com/cnlh/nps/vender/golang.org/x/net/proxy" "github.com/cnlh/nps/vender/golang.org/x/net/proxy"
"io/ioutil" "io/ioutil"
"log" "log"
"math"
"math/rand"
"net" "net"
"net/http" "net/http"
"net/http/httputil" "net/http/httputil"
@ -276,108 +278,137 @@ func basicAuth(username, password string) string {
return base64.StdEncoding.EncodeToString([]byte(auth)) return base64.StdEncoding.EncodeToString([]byte(auth))
} }
func handleP2PUdp(rAddr, md5Password, role string) (remoteAddress string, c net.PacketConn, err error) { func getRemoteAddressFromServer(rAddr string, localConn *net.UDPConn, md5Password, role string, add int) error {
tmpConn, err := common.GetLocalUdpAddr() rAddr, err := getNextAddr(rAddr, add)
if err != nil { if err != nil {
logs.Error(err) logs.Error(err)
return return err
} }
localConn, err := newUdpConnByAddr(tmpConn.LocalAddr().String()) addr, err := net.ResolveUDPAddr("udp", rAddr)
if err != nil { if err != nil {
logs.Error(err) return err
return
} }
localKcpConn, err := kcp.NewConn(rAddr, nil, 150, 3, localConn) if _, err := localConn.WriteTo(common.GetWriteStr(md5Password, role), addr); err != nil {
if err != nil { return err
logs.Error(err)
return
} }
conn.SetUdpSession(localKcpConn) return nil
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 {
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())
return
} }
func handleP2P(natType1, natType2 int, addr1, addr2 string, role string) (string, error) { func handleP2PUdp(localAddr, rAddr, md5Password, role string) (remoteAddress string, c net.PacketConn, err 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) localConn, err := newUdpConnByAddr(localAddr)
if err != nil {
return
}
err = getRemoteAddressFromServer(rAddr, localConn, md5Password, role, 0)
if err != nil {
logs.Error(err)
return
}
err = getRemoteAddressFromServer(rAddr, localConn, md5Password, role, 1)
if err != nil {
logs.Error(err)
return
}
err = getRemoteAddressFromServer(rAddr, localConn, md5Password, role, 2)
if err != nil {
logs.Error(err)
return
}
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
}
c, err = newUdpConnByAddr(localAddr)
return
}
func sendP2PTestMsg(localConn *net.UDPConn, remoteAddr1, remoteAddr2, remoteAddr3 string) (string, error) {
logs.Trace(remoteAddr3, remoteAddr2, remoteAddr1)
defer localConn.Close()
isClose := false
defer func() { isClose = true }()
interval, err := getAddrInterval(remoteAddr1, remoteAddr2, remoteAddr3)
if err != nil { if err != nil {
return "", err return "", err
} }
defer localConn.Close() 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) ticker := time.NewTicker(time.Millisecond * 500)
go func(ticker *time.Ticker) {
for { for {
select { select {
case <-ticker.C: 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 { if _, err := localConn.WriteTo([]byte(common.WORK_P2P_CONNECT), remoteUdpAddr); err != nil {
return 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) buf := make([]byte, 10)
for { for {
localConn.SetReadDeadline(time.Now().Add(time.Second * 30)) localConn.SetReadDeadline(time.Now().Add(time.Second * 10))
n, addr, err := localConn.ReadFromUDP(buf) n, addr, err := localConn.ReadFromUDP(buf)
localConn.SetReadDeadline(time.Time{}) localConn.SetReadDeadline(time.Time{})
if err != nil { if err != nil {
@ -397,7 +428,7 @@ func sendP2PTestMsg(remoteAddr string, localAddr string) (string, error) {
case common.WORK_P2P_CONNECT: case common.WORK_P2P_CONNECT:
go func() { go func() {
for i := 20; i > 0; i-- { 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 { if _, err = localConn.WriteTo([]byte(common.WORK_P2P_SUCCESS), addr); err != nil {
return return
} }
@ -407,9 +438,7 @@ func sendP2PTestMsg(remoteAddr string, localAddr string) (string, error) {
default: default:
continue continue
} }
ticker.Stop()
} }
ticker.Stop()
return "", errors.New("connect to the target failed, maybe the nat type is not support p2p") 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 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,11 +7,11 @@ import (
"github.com/cnlh/nps/lib/crypt" "github.com/cnlh/nps/lib/crypt"
"github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/lib/file"
"github.com/cnlh/nps/lib/mux" "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/astaxie/beego/logs"
"github.com/cnlh/nps/vender/github.com/xtaci/kcp" "github.com/cnlh/nps/vender/github.com/xtaci/kcp"
"net" "net"
"net/http" "net/http"
"sync"
) )
var ( var (
@ -19,10 +19,24 @@ var (
udpConn net.Conn udpConn net.Conn
muxSession *mux.Mux muxSession *mux.Mux
fileServer []*http.Server fileServer []*http.Server
lock sync.Mutex p2pNetBridge *p2pBridge
hasP2PTry bool
) )
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() { func CloseLocalServer() {
for _, v := range LocalServer { for _, v := range LocalServer {
v.Close() 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 { func StartLocalServer(l *config.LocalServer, config *config.CommonConfig) error {
tmpConn, err := common.GetLocalUdpAddr()
if err != nil {
return err
}
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, ""}) listener, err := net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), l.Port, ""})
if err != nil { if err != nil {
logs.Error("local listener startup failed port %d, error %s", l.Port, err.Error()) logs.Error("local listener startup failed port %d, error %s", l.Port, err.Error())
return err return err
} }
LocalServer = append(LocalServer, listener) LocalServer = append(LocalServer, listener)
logs.Info("successful start-up of local monitoring, port", l.Port) logs.Info("successful start-up of local tcp monitoring, port", l.Port)
conn.Accept(listener, func(c net.Conn) { conn.Accept(listener, func(c net.Conn) {
logs.Trace("new %s connection", l.Type)
if l.Type == "secret" { if l.Type == "secret" {
handleSecret(c, config, l) handleSecret(c, config, l)
} else { } else if l.Type == "p2p" {
handleP2PVisitor(c, config, l) handleP2PVisitor(c, config, l)
} }
}) })
}
return nil 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) { func handleP2PVisitor(localTcpConn net.Conn, config *config.CommonConfig, l *config.LocalServer) {
restart:
lock.Lock()
if udpConn == nil { 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") logs.Notice("new conn, P2P can not penetrate successfully, traffic will be transferred through the server")
handleSecret(localTcpConn, config, l) handleSecret(localTcpConn, config, l)
return
} else {
muxSession = mux.NewMux(udpConn, "kcp")
} }
}
lock.Unlock()
logs.Trace("start trying to connect with the server") 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 //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) 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) logs.Error(err)
return 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) remoteConn, err := NewConn(config.Tp, config.VKey, config.Server, common.WORK_P2P, config.ProxyUrl)
if err != nil { if err != nil {
logs.Error("Local connection server failed ", err.Error()) 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 localConn net.PacketConn
var remoteAddress string 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) logs.Error(err)
return return
} }
@ -143,4 +176,6 @@ func newUdpConn(config *config.CommonConfig, l *config.LocalServer) {
logs.Trace("successful create a connection with server", remoteAddress) logs.Trace("successful create a connection with server", remoteAddress)
conn.SetUdpSession(udpTunnel) conn.SetUdpSession(udpTunnel)
udpConn = udpTunnel udpConn = udpTunnel
muxSession = mux.NewMux(udpConn, "kcp")
p2pNetBridge = &p2pBridge{}
} }

View File

@ -60,7 +60,7 @@ func main() {
if *logType == "stdout" { if *logType == "stdout" {
logs.SetLogger(logs.AdapterConsole, `{"level":`+*logLevel+`,"color":true}`) logs.SetLogger(logs.AdapterConsole, `{"level":`+*logLevel+`,"color":true}`)
} else { } else {
logs.SetLogger(logs.AdapterFile, `{"level":`+*logLevel+`,"filename":"`+*logPath+`","daily":false,"color":true}`) logs.SetLogger(logs.AdapterFile, `{"level":`+*logLevel+`,"filename":"`+*logPath+`","daily":false,"maxlines":100000,"color":true}`)
} }
//p2p or secret command //p2p or secret command
if *password != "" { if *password != "" {

View File

@ -50,7 +50,7 @@ func main() {
if *logType == "stdout" { if *logType == "stdout" {
logs.SetLogger(logs.AdapterConsole, `{"level":`+level+`,"color":true}`) logs.SetLogger(logs.AdapterConsole, `{"level":`+level+`,"color":true}`)
} else { } else {
logs.SetLogger(logs.AdapterFile, `{"level":`+level+`,"filename":"`+beego.AppConfig.String("log_path")+`","daily":false,"color":true}`) logs.SetLogger(logs.AdapterFile, `{"level":`+level+`,"filename":"`+beego.AppConfig.String("log_path")+`","daily":false,"maxlines":100000,"color":true}`)
} }
task := &file.Tunnel{ task := &file.Tunnel{
Mode: "webServer", Mode: "webServer",

View File

@ -163,6 +163,13 @@ func TestUdpPort(port int) bool {
//Length prevents sticking //Length prevents sticking
//# Characters are used to separate data //# Characters are used to separate data
func BinaryWrite(raw *bytes.Buffer, v ...string) { func BinaryWrite(raw *bytes.Buffer, v ...string) {
b := GetWriteStr(v...)
binary.Write(raw, binary.LittleEndian, int32(len(b)))
binary.Write(raw, binary.LittleEndian, b)
}
// get seq str
func GetWriteStr(v ...string) []byte {
buffer := new(bytes.Buffer) buffer := new(bytes.Buffer)
var l int32 var l int32
for _, v := range v { for _, v := range v {
@ -170,8 +177,7 @@ func BinaryWrite(raw *bytes.Buffer, v ...string) {
binary.Write(buffer, binary.LittleEndian, []byte(v)) binary.Write(buffer, binary.LittleEndian, []byte(v))
binary.Write(buffer, binary.LittleEndian, []byte(CONN_DATA_SEQ)) binary.Write(buffer, binary.LittleEndian, []byte(CONN_DATA_SEQ))
} }
binary.Write(raw, binary.LittleEndian, l) return buffer.Bytes()
binary.Write(raw, binary.LittleEndian, buffer.Bytes())
} }
//inArray str interface //inArray str interface
@ -244,6 +250,19 @@ func GetIpByAddr(addr string) string {
return arr[0] return arr[0]
} }
//get port from the complete address
func GetPortByAddr(addr string) int {
arr := strings.Split(addr, ":")
if len(arr) < 2 {
return 0
}
p, err := strconv.Atoi(arr[1])
if err != nil {
return 0
}
return p
}
func CopyBuffer(dst io.Writer, src io.Reader) (written int64, err error) { func CopyBuffer(dst io.Writer, src io.Reader) (written int64, err error) {
buf := pool.GetBufPoolCopy() buf := pool.GetBufPoolCopy()
defer pool.PutBufPoolCopy(buf) defer pool.PutBufPoolCopy(buf)

View File

@ -13,6 +13,9 @@ import (
func InstallNps() { func InstallNps() {
path := common.GetInstallPath() path := common.GetInstallPath()
if common.FileExists(path) {
log.Fatalf("the path %s has exist, does not support install", path)
}
MkidrDirAll(path, "conf", "web/static", "web/views") MkidrDirAll(path, "conf", "web/static", "web/views")
//复制文件到对应目录 //复制文件到对应目录
if err := CopyDir(filepath.Join(common.GetAppPath(), "web", "views"), filepath.Join(path, "web", "views")); err != nil { if err := CopyDir(filepath.Join(common.GetAppPath(), "web", "views"), filepath.Join(path, "web", "views")); err != nil {

View File

@ -1,6 +1,6 @@
package version package version
const VERSION = "0.22.5" const VERSION = "0.23.0"
// Compulsory minimum version, Minimum downward compatibility to this version // Compulsory minimum version, Minimum downward compatibility to this version
func GetVersion() string { func GetVersion() string {

View File

@ -17,10 +17,14 @@ type Service interface {
Close() error Close() error
} }
type NetBridge interface {
SendLinkInfo(clientId int, link *conn.Link, t *file.Tunnel) (target net.Conn, err error)
}
//BaseServer struct //BaseServer struct
type BaseServer struct { type BaseServer struct {
id int id int
bridge *bridge.Bridge bridge NetBridge
task *file.Tunnel task *file.Tunnel
errorContent []byte errorContent []byte
sync.Mutex sync.Mutex

View File

@ -147,7 +147,7 @@ func (s *httpServer) httpHandle(c *conn.Conn, r *http.Request) {
logs.Warn(err.Error()) logs.Warn(err.Error())
break break
} }
lk = conn.NewLink(common.CONN_TCP, targetAddr, host.Client.Cnf.Crypt, host.Client.Cnf.Compress, r.RemoteAddr, host.Target.LocalProxy) lk = conn.NewLink("http", targetAddr, host.Client.Cnf.Crypt, host.Client.Cnf.Compress, r.RemoteAddr, host.Target.LocalProxy)
if target, err = s.bridge.SendLinkInfo(host.Client.Id, lk, nil); err != nil { if target, err = s.bridge.SendLinkInfo(host.Client.Id, lk, nil); err != nil {
logs.Notice("connect to target %s error %s", lk.Host, err) logs.Notice("connect to target %s error %s", lk.Host, err)
break break

View File

@ -1,7 +1,6 @@
package proxy package proxy
import ( import (
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/lib/cache" "github.com/cnlh/nps/lib/cache"
"github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/conn"
@ -22,7 +21,7 @@ type HttpsServer struct {
httpsListenerMap sync.Map httpsListenerMap sync.Map
} }
func NewHttpsServer(l net.Listener, bridge *bridge.Bridge, useCache bool, cacheLen int) *HttpsServer { func NewHttpsServer(l net.Listener, bridge NetBridge, useCache bool, cacheLen int) *HttpsServer {
https := &HttpsServer{listener: l} https := &HttpsServer{listener: l}
https.bridge = bridge https.bridge = bridge
https.useCache = useCache https.useCache = useCache

View File

@ -1,12 +1,11 @@
package proxy package proxy
import ( import (
"encoding/binary"
"github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/pool"
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
"net" "net"
"strconv" "strings"
"time" "time"
) )
@ -14,15 +13,12 @@ type P2PServer struct {
BaseServer BaseServer
p2pPort int p2pPort int
p2p map[string]*p2p p2p map[string]*p2p
listener *net.UDPConn
} }
type p2p struct { type p2p struct {
provider *conn.Conn visitorAddr *net.UDPAddr
visitor *conn.Conn providerAddr *net.UDPAddr
visitorAddr string
providerAddr string
providerNatType int32
visitorNatType int32
} }
func NewP2PServer(p2pPort int) *P2PServer { func NewP2PServer(p2pPort int) *P2PServer {
@ -33,62 +29,52 @@ func NewP2PServer(p2pPort int) *P2PServer {
} }
func (s *P2PServer) Start() error { func (s *P2PServer) Start() error {
return conn.NewKcpListenerAndProcess(":"+strconv.Itoa(s.p2pPort), func(c net.Conn) { logs.Info("start p2p server port", s.p2pPort)
s.p2pProcess(conn.NewConn(c)) var err error
}) s.listener, err = net.ListenUDP("udp", &net.UDPAddr{net.ParseIP("0.0.0.0"), s.p2pPort, ""})
if err != nil {
return err
}
for {
buf := pool.BufPoolUdp.Get().([]byte)
n, addr, err := s.listener.ReadFromUDP(buf)
if err != nil {
if strings.Contains(err.Error(), "use of closed network connection") {
break
}
continue
}
go s.handleP2P(addr, string(buf[:n]))
}
return nil
} }
func (s *P2PServer) p2pProcess(c *conn.Conn) { func (s *P2PServer) handleP2P(addr *net.UDPAddr, str string) {
var ( var (
f string
b []byte
err error
v *p2p v *p2p
ok bool ok bool
natType int32
) )
if b, err = c.GetShortContent(32); err != nil { arr := strings.Split(str, common.CONN_DATA_SEQ)
if len(arr) < 2 {
return return
} }
//get role if v, ok = s.p2p[arr[0]]; !ok {
if f, err = c.ReadFlag(); err != nil {
return
}
//get nat type
if err := binary.Read(c, binary.LittleEndian, &natType); err != nil {
return
}
if v, ok = s.p2p[string(b)]; !ok {
v = new(p2p) v = new(p2p)
s.p2p[string(b)] = v s.p2p[arr[0]] = v
} }
logs.Trace("new p2p connection ,role %s , password %s, nat type %s ,local address %s", f, string(b), strconv.Itoa(int(natType)), c.RemoteAddr().String()) logs.Trace("new p2p connection ,role %s , password %s ,local address %s", arr[1], arr[0], addr.String())
//存储 if arr[1] == common.WORK_P2P_VISITOR {
if f == common.WORK_P2P_VISITOR { v.visitorAddr = addr
v.visitorAddr = c.Conn.RemoteAddr().String()
v.visitorNatType = natType
v.visitor = c
for i := 20; i > 0; i-- { for i := 20; i > 0; i-- {
if v.provider != nil { if v.providerAddr != nil {
v.provider.WriteLenContent([]byte(v.visitorAddr)) s.listener.WriteTo([]byte(v.providerAddr.String()), v.visitorAddr)
binary.Write(v.provider, binary.LittleEndian, v.visitorNatType) s.listener.WriteTo([]byte(v.visitorAddr.String()), v.providerAddr)
break break
} }
time.Sleep(time.Second) time.Sleep(time.Second)
} }
v.provider = nil delete(s.p2p, arr[0])
} else { } else {
v.providerAddr = c.Conn.RemoteAddr().String() v.providerAddr = addr
v.providerNatType = natType
v.provider = c
for i := 20; i > 0; i-- {
if v.visitor != nil {
v.visitor.WriteLenContent([]byte(v.providerAddr))
binary.Write(v.visitor, binary.LittleEndian, v.providerNatType)
break
}
time.Sleep(time.Second)
}
v.visitor = nil
} }
} }

View File

@ -3,7 +3,6 @@ package proxy
import ( import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/conn"
"github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/lib/file"
@ -264,7 +263,7 @@ func (s *Sock5ModeServer) Start() error {
} }
//new //new
func NewSock5ModeServer(bridge *bridge.Bridge, task *file.Tunnel) *Sock5ModeServer { func NewSock5ModeServer(bridge NetBridge, task *file.Tunnel) *Sock5ModeServer {
s := new(Sock5ModeServer) s := new(Sock5ModeServer)
s.bridge = bridge s.bridge = bridge
s.task = task s.task = task

View File

@ -13,6 +13,7 @@ import (
"net/http" "net/http"
"path/filepath" "path/filepath"
"strconv" "strconv"
"syscall"
) )
type TunnelModeServer struct { type TunnelModeServer struct {
@ -22,7 +23,7 @@ type TunnelModeServer struct {
} }
//tcp|http|host //tcp|http|host
func NewTunnelModeServer(process process, bridge *bridge.Bridge, task *file.Tunnel) *TunnelModeServer { func NewTunnelModeServer(process process, bridge NetBridge, task *file.Tunnel) *TunnelModeServer {
s := new(TunnelModeServer) s := new(TunnelModeServer)
s.bridge = bridge s.bridge = bridge
s.process = process s.process = process
@ -114,3 +115,35 @@ func ProcessHttp(c *conn.Conn, s *TunnelModeServer) error {
} }
return s.DealClient(c, s.task.Client, addr, rb, common.CONN_TCP, nil, s.task.Flow, s.task.Target.LocalProxy) return s.DealClient(c, s.task.Client, addr, rb, common.CONN_TCP, nil, s.task.Flow, s.task.Target.LocalProxy)
} }
func HandleTrans(c *conn.Conn, s *TunnelModeServer) error {
if addr, err := getAddress(c.Conn); err != nil {
return err
} else {
return s.DealClient(c, s.task.Client, addr, nil, common.CONN_TCP, nil, s.task.Flow, s.task.Target.LocalProxy)
}
}
const SO_ORIGINAL_DST = 80
func getAddress(conn net.Conn) (string, error) {
sysrawconn, f := conn.(syscall.Conn)
if !f {
return "", nil
}
rawConn, err := sysrawconn.SyscallConn()
if err != nil {
return "", nil
}
var ip string
var port uint16
err = rawConn.Control(func(fd uintptr) {
addr, err := syscall.GetsockoptIPv6Mreq(int(fd), syscall.IPPROTO_IP, SO_ORIGINAL_DST)
if err != nil {
return
}
ip = net.IP(addr.Multiaddr[4:8]).String()
port = uint16(addr.Multiaddr[2])<<8 + uint16(addr.Multiaddr[3])
})
return ip + ":" + strconv.Itoa(int(port)), nil
}

View File

@ -90,8 +90,9 @@ func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string) {
} }
}() }()
if p, err := beego.AppConfig.Int("p2p_port"); err == nil { if p, err := beego.AppConfig.Int("p2p_port"); err == nil {
logs.Info("start p2p server port", p)
go proxy.NewP2PServer(p).Start() go proxy.NewP2PServer(p).Start()
go proxy.NewP2PServer(p + 1).Start()
go proxy.NewP2PServer(p + 2).Start()
} }
go DealBridgeTask() go DealBridgeTask()
go dealClientFlow() go dealClientFlow()
@ -125,6 +126,8 @@ func NewMode(Bridge *bridge.Bridge, c *file.Tunnel) proxy.Service {
service = proxy.NewSock5ModeServer(Bridge, c) service = proxy.NewSock5ModeServer(Bridge, c)
case "httpProxy": case "httpProxy":
service = proxy.NewTunnelModeServer(proxy.ProcessHttp, Bridge, c) service = proxy.NewTunnelModeServer(proxy.ProcessHttp, Bridge, c)
case "tcpTrans":
service = proxy.NewTunnelModeServer(proxy.HandleTrans, Bridge, c)
case "udp": case "udp":
service = proxy.NewUdpModeServer(Bridge, c) service = proxy.NewUdpModeServer(Bridge, c)
case "webServer": case "webServer":

View File

@ -70,7 +70,11 @@
+ '<b langtag="info-web-auth-username">basic</b>' + row.Client.Cnf.U + `&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp` + '<b langtag="info-web-auth-username">basic</b>' + row.Client.Cnf.U + `&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp`
+ '<b langtag="info-web-auth-password">basic</b>' + row.Client.Cnf.P + `&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp` + '<b langtag="info-web-auth-password">basic</b>' + row.Client.Cnf.P + `&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp`
if (row.Mode == "p2p") { if (row.Mode == "p2p") {
return tmp + "<br/><br>" + '<b langtag="info-command">访</b>' + "<code>./npc{{.win}} -server={{.ip}}:{{.p}} -vkey=" + row.Client.VerifyKey + " -type=" +{{.bridgeType}} +" -password=" + row.Password + " -target=" + row.Target.TargetStr + "</code>" return tmp + "<br/><br>"
+ '<b langtag="info-command">访(tcp)</b>' + "<code>./npc{{.win}} -server={{.ip}}:{{.p}} -vkey=" + row.Client.VerifyKey + " -type=" +{{.bridgeType}} +" -password=" + row.Password + " -target=" + row.Target.TargetStr + "</code>" + "<br/><br>"
+ '<b langtag="info-command">访(socks5)</b>' + "<code>./npc{{.win}} -server={{.ip}}:{{.p}} -vkey=" + row.Client.VerifyKey + " -type=" +{{.bridgeType}} +" -password=" + row.Password + " -local_type=p2ps" + "</code>" + "<br/><br>"
+ '<b langtag="info-command">访()</b>' + "<code>./npc{{.win}} -server={{.ip}}:{{.p}} -vkey=" + row.Client.VerifyKey + " -type=" +{{.bridgeType}} +" -password=" + row.Password + " -local_type=p2pt" + "</code>"
} }
if (row.Mode = "secret") { if (row.Mode = "secret") {
return tmp + "<br/><br>" + '<b langtag="info-command">访</b>' + "<code>./npc{{.win}} -server={{.ip}}:{{.p}} -vkey=" + row.Client.VerifyKey + " -type=" +{{.bridgeType}} +" -password=" + row.Password + " -local_type=secret" + "</code>" return tmp + "<br/><br>" + '<b langtag="info-command">访</b>' + "<code>./npc{{.win}} -server={{.ip}}:{{.p}} -vkey=" + row.Client.VerifyKey + " -type=" +{{.bridgeType}} +" -password=" + row.Password + " -local_type=secret" + "</code>"