diff --git a/bridge/bridge.go b/bridge/bridge.go index 51d5369..35a8d93 100755 --- a/bridge/bridge.go +++ b/bridge/bridge.go @@ -10,6 +10,7 @@ import ( "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/lib/mux" "github.com/cnlh/nps/lib/version" + "github.com/cnlh/nps/server/connection" "github.com/cnlh/nps/server/tool" "github.com/cnlh/nps/vender/github.com/astaxie/beego" "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" @@ -37,9 +38,7 @@ func NewClient(t, f *mux.Mux, s *conn.Conn) *Client { } type Bridge struct { - TunnelPort int //通信隧道端口 - tcpListener *net.TCPListener //server端监听 - kcpListener *kcp.Listener //server端监听 + TunnelPort int //通信隧道端口 Client map[int]*Client tunnelType string //bridge type kcp or tcp OpenTask chan *file.Tunnel @@ -68,15 +67,18 @@ func NewTunnel(tunnelPort int, tunnelType string, ipVerify bool, runList map[int func (s *Bridge) StartTunnel() error { go s.ping() - var err error + l, err := connection.GetBridgeListener(s.tunnelType) + if err != nil { + return err + } if s.tunnelType == "kcp" { - s.kcpListener, err = kcp.ListenWithOptions(":"+strconv.Itoa(s.TunnelPort), nil, 150, 3) - if err != nil { + listener, ok := l.(*kcp.Listener) + if !ok { return err } go func() { for { - c, err := s.kcpListener.AcceptKCP() + c, err := listener.AcceptKCP() conn.SetUdpSession(c) if err != nil { logs.Warn(err) @@ -86,13 +88,13 @@ func (s *Bridge) StartTunnel() error { } }() } else { - s.tcpListener, err = net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), s.TunnelPort, ""}) - if err != nil { + listener, ok := l.(net.Listener) + if !ok { return err } go func() { for { - c, err := s.tcpListener.Accept() + c, err := listener.Accept() if err != nil { logs.Warn(err) continue @@ -115,6 +117,11 @@ func (s *Bridge) verifySuccess(c *conn.Conn) { } func (s *Bridge) cliProcess(c *conn.Conn) { + //read test flag + if _, err := c.GetShortContent(3); err != nil { + logs.Info("The client %s connect error", c.Conn.RemoteAddr()) + return + } //version check if b, err := c.GetShortContent(32); err != nil || string(b) != crypt.Md5(version.GetVersion()) { logs.Info("The client %s version does not match", c.Conn.RemoteAddr()) @@ -126,7 +133,7 @@ func (s *Bridge) cliProcess(c *conn.Conn) { c.SetReadDeadline(5, s.tunnelType) var buf []byte var err error - //get vkey from client + //get vKey from client if buf, err = c.GetShortContent(32); err != nil { c.Close() return @@ -140,7 +147,6 @@ func (s *Bridge) cliProcess(c *conn.Conn) { } else { s.verifySuccess(c) } - //做一个判断 添加到对应的channel里面以供使用 if flag, err := c.ReadFlag(); err == nil { s.typeDeal(flag, c, id) } else { @@ -197,7 +203,7 @@ func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int) { var isPub bool client, err := file.GetCsvDb().GetClient(id); if err == nil { - if client.VerifyKey == beego.AppConfig.String("publicVkey") { + if client.VerifyKey == beego.AppConfig.String("public_vkey") { isPub = true } else { isPub = false @@ -237,7 +243,7 @@ func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int) { s.clientLock.Unlock() //向密钥对应的客户端发送与服务端udp建立连接信息,地址,密钥 v.signal.Write([]byte(common.NEW_UDP_CONN)) - svrAddr := beego.AppConfig.String("serverIp") + ":" + beego.AppConfig.String("p2pPort") + svrAddr := beego.AppConfig.String("p2p_ip") + ":" + beego.AppConfig.String("p2p_port") if err != nil { logs.Warn("get local udp addr error") return diff --git a/client/client.go b/client/client.go index 899813e..5a755b0 100755 --- a/client/client.go +++ b/client/client.go @@ -209,7 +209,7 @@ func (s *TRPClient) srcProcess(src net.Conn) { src.Close() } else { logs.Trace("new %s connection with the goal of %s, remote address:%s", lk.ConnType, lk.Host, lk.RemoteAddr) - conn.CopyWaitGroup(src, targetConn, lk.Crypt, lk.Compress, nil, nil) + conn.CopyWaitGroup(src, targetConn, lk.Crypt, lk.Compress, nil, nil, false) } } diff --git a/client/control.go b/client/control.go index 6881a5a..d4239d6 100644 --- a/client/control.go +++ b/client/control.go @@ -198,6 +198,10 @@ func NewConn(tp string, vkey string, server string, connType string, proxyUrl st return nil, err } c := conn.NewConn(connection) + if _, err := c.Write([]byte(common.CONN_TEST)); err != nil { + logs.Error(err) + os.Exit(0) + } if _, err := c.Write([]byte(crypt.Md5(version.GetVersion()))); err != nil { logs.Error(err) os.Exit(0) diff --git a/client/local.go b/client/local.go index 5864728..d4ab35d 100644 --- a/client/local.go +++ b/client/local.go @@ -79,7 +79,7 @@ func processSecret(localTcpConn net.Conn, config *config.CommonConfig, l *config logs.Error("Local connection server failed ", err.Error()) return } - conn.CopyWaitGroup(remoteConn, localTcpConn, false, false, nil, nil) + conn.CopyWaitGroup(remoteConn.Conn, localTcpConn, false, false, nil, nil, false) } func processP2P(localTcpConn net.Conn, config *config.CommonConfig, l *config.LocalServer) { @@ -100,7 +100,7 @@ func processP2P(localTcpConn net.Conn, config *config.CommonConfig, l *config.Lo logs.Error(err) return } - conn.CopyWaitGroup(nowConn, localTcpConn, config.Cnf.Crypt, config.Cnf.Compress, nil, nil) + conn.CopyWaitGroup(nowConn, localTcpConn, config.Cnf.Crypt, config.Cnf.Compress, nil, nil, false) } func newUdpConn(config *config.CommonConfig, l *config.LocalServer) { diff --git a/cmd/nps/nps.go b/cmd/nps/nps.go index a46b0e4..ebdfb26 100644 --- a/cmd/nps/nps.go +++ b/cmd/nps/nps.go @@ -7,6 +7,7 @@ import ( "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/lib/install" "github.com/cnlh/nps/server" + "github.com/cnlh/nps/server/connection" "github.com/cnlh/nps/server/test" "github.com/cnlh/nps/vender/github.com/astaxie/beego" "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" @@ -37,7 +38,7 @@ func main() { return } } - if level = beego.AppConfig.String("logLevel"); level == "" { + if level = beego.AppConfig.String("log_level"); level == "" { level = "7" } logs.Reset() @@ -51,10 +52,11 @@ func main() { task := &file.Tunnel{ Mode: "webServer", } - bridgePort, err := beego.AppConfig.Int("bridgePort") + bridgePort, err := beego.AppConfig.Int("bridge_port") if err != nil { logs.Error("Getting bridgePort error", err) os.Exit(0) } - server.StartNewServer(bridgePort, task, beego.AppConfig.String("bridgeType")) + connection.InitConnectionService() + server.StartNewServer(bridgePort, task, beego.AppConfig.String("bridge_type")) } diff --git a/conf/clients.csv b/conf/clients.csv index 806736c..74aeb20 100644 --- a/conf/clients.csv +++ b/conf/clients.csv @@ -1 +1,2 @@ -2,corjmrbhr33otit1,,true,,,0,false,0,0,0 +2,corjmrbhr33otit1,,true,,,1,false,0,0,0 +5,2dyy78gj7b9zw09l,,true,,,0,false,0,0,0 diff --git a/conf/hosts.csv b/conf/hosts.csv index 4bc8b3d..c56b455 100644 --- a/conf/hosts.csv +++ b/conf/hosts.csv @@ -1 +1 @@ -b.o.com,127.0.0.1:8080,2,,,111,/,3,0,0 +a.o.com,127.0.0.1:8082,2,,,111,/,3,5290945,30260,all diff --git a/conf/npc.conf b/conf/npc.conf index 2ae0602..ac61982 100644 --- a/conf/npc.conf +++ b/conf/npc.conf @@ -1,12 +1,11 @@ [common] -server=127.0.0.1:8284 +server=127.0.0.1:8024 tp=tcp vkey=123 auto_reconnection=true - [web] -host=a.o.com -target=127.0.0.1:8080 +host=b.o.com +target=127.0.0.1:8082 [tcp] mode=tcp target=8006-8010,8012 diff --git a/conf/nps.conf b/conf/nps.conf index e2f926d..1422445 100755 --- a/conf/nps.conf +++ b/conf/nps.conf @@ -1,61 +1,47 @@ appname = nps - -#Web Management Port -httpport = 8080 - #Boot mode(dev|pro) runmode = dev -#Web Management Password -password=123 - -username=admin - -##Communication Port between Client and Server -##If the data transfer mode is tcp, it is TCP port -##If the data transfer mode is kcp, it is UDP port -bridgePort=8284 - #Web API unauthenticated IP address -authKey=test +#auth_key=test +#auth_crypt_key =1234567812345678 -##web API get password -cryptKey = "1234567812345678" +#HTTP(S) proxy port, no startup if empty +http_proxy_port=80 +https_proxy_port=445 +#certFile absolute path +pem_path=conf/server.pem +#KeyFile absolute path +key_path=conf/server.key -##HTTP proxy port, no startup if empty -httpProxyPort=80 - -##HTTPS proxy port, no startup if empty -httpsProxyPort= - -##certFile absolute path -pemPath=/etc/nginx/certificate.crt - -##KeyFile absolute path -keyPath=/etc/nginx/private.key - -##Data transmission mode(kcp or tcp) -bridgeType=tcp +##bridge +bridge_type=tcp +bridge_port=8024 +bridge_ip=0.0.0.0 # Public password, which clients can use to connect to the server # After the connection, the server will be able to open relevant ports and parse related domain names according to its own configuration file. -publicVkey=123 +public_vkey=123 #Traffic data persistence interval(minute) #Ignorance means no persistence -#flowStoreInterval=1 +#flow_store_interval=1 -#log level -#LevelEmergency->0 LevelAlert->1 LevelCritical->2 LevelError->3 LevelWarning->4 -#LevelNotice->5 LevelInformational->6 LevelDebug->7 -#logLevel=7 +# log level LevelEmergency->0 LevelAlert->1 LevelCritical->2 LevelError->3 LevelWarning->4 LevelNotice->5 LevelInformational->6 LevelDebug->7 +#log_level=7 #Whether to restrict IP access, true or false or ignore -#ipLimit=true +#ip_limit=true -#must set when use p2p -#serverIp=127.0.0.1 +#p2p +#p2p_ip=127.0.0.1 +#p2p_port=6000 -#p2p udp port -#p2pPort=6000 +#web +web_host=c.o.com +web_username=admin +web_password=123 +web_port = 8080 +web_ip=0.0.0.0 +#allow_ports=9001-9009,10001,11000-12000 \ No newline at end of file diff --git a/conf/server.key b/conf/server.key new file mode 100644 index 0000000..570054a --- /dev/null +++ b/conf/server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA2MVLOHvgU8FCp6LgQrPfaWcGygrsRk7TL9hbT8MxbCRUSLV7 +Lbt3q5Knz8eTN4NWmwE6L5glOcH2x3Hnn+hPjbvgq35XBBIccAm0cYYKqoKkikeK +FZM0Gp/WhSrhJ4laTyQqyleIFKpwD9kHDiC/sxjGDhSFmHKhhAnsQIRm2tppFXX0 +aAMqJEm88jzk1BN2QtKjEAn1u8v1+QW1KP3WuzdXH4L7hhMll66/KIm6Hfs2FRHQ +pRUWqZeJY4q79NW5p5f+siGwOsGpxb/p11pM+0xnCH3UIFbm3zCTzP4sLvkfFGAe +yAHsAwmaP8dJxh40ej3NN8uNiNvt8nw2Vb/1LwIDAQABAoIBAD40x/RKoEKIyE8B +D6g0pB1EQo+CePFoN3SYewO1uR4WgtVmtxWVoa7r5BpdZGLe3uCWhpMX7z7W6bGs +f1LFQOckjkHIfMIfTGfecRjO5Yqu+Pbxtq+gUah+S/plJr3IzdC+SUVNvzBnBMeX +eU3Vmg2UQ2nQ+9GWu8D/c/vDwxx0X8oQ2G8QaxX0tUurlSMNA3M7xySwEvhx54fO +UrDF3Q4yF48eA4butxVLFWf3cnlY+nR8uYd2vKfmp689/8C6kkfoM9igB78e93sm +uDM2eRLm4kU5WLl301T42n6AF7w8J0MhLLVOIeLs4l5gZPa3uKvYFmuHQao7e/5R +U/jHKrECgYEA8alPXuxFSVOvdhIsSN//Frj9CdExVdYmaLkt/2LO4FMnOaWh1xh7 +5iCY1bJT8D9dhfbqRg3qW2oguZD8gu04R8fTRegQ89qmAIwsEYqVf9salR41lZU4 +Rc+5yc7O11WIe9Lzu+ONFBFkAh3UFMR4zVZ/JhKIG/P5Srm7SUdKW2cCgYEA5aHo +x2LR+yKhjkrBzHG3Qrfy1PtlYHjOpYYAKHQcBFuiG08W3CK/vkYl+mhv0uyhT7mn +q6NDqrpZPRnDlOoEqgRS1X/QWKN6Pgd4HNLIawvp0vK9jYXDPcAXFzVthXCIwFcn +3a3m4cHiuLdRNOHkydiHQyTOF6eEneN07TDvwvkCgYEApzOd1u9igPmFzQuF2GYi ++HXFnaU/nUQuDwcQ7EJRIKRn31raPxiRoQesty5LJU6yRp4wOYgnPliPi9Tk4TGA +XynC4/tMv2vorzhMxVY9Wdke602bhYNZC/RNd3O/aP2lEQdD3Bv04I2nxE8fDb9i +VbAjCRSJV83WDf2zt1+78sECgYEAzezjRiKdcZu9y0/I+WEk2cUCE/MaF2he0FsZ +uy1cjp/qAJltQ5452xUnK6cKWNlxU4CHF0mC/hC8xCldliZCZoEYE3PaUBLSJdwm +35o6tpxpZI3gZJCG5NJlIp/8BkVDrVC7ZHV17hAkFEf4n/bPaB8wNYtE8jt8luaK +TcarzGkCgYBn2alN0RLN2PHDurraFZB6GuCvh/arEjSCY3SDFQPF10CVjTDV7sx3 +eqJkwJ81syTmfJwZIceWbOFGgsuSx37UrQAVlHZSvzeqEg9dA5HqSoOACyidJI7j +RG2+HB+KpsIZjGgLrEM4i7VOpYUDRdaouIXngFq/t9HNT+MDck5/Lw== +-----END RSA PRIVATE KEY----- diff --git a/conf/server.pem b/conf/server.pem new file mode 100644 index 0000000..7908eca --- /dev/null +++ b/conf/server.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIJAPXRSiP0Fs7sMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTcxMTA3MDg1MzQ2WhcNMjcxMTA1MDg1MzQ2WjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA2MVLOHvgU8FCp6LgQrPfaWcGygrsRk7TL9hbT8MxbCRUSLV7Lbt3q5Kn +z8eTN4NWmwE6L5glOcH2x3Hnn+hPjbvgq35XBBIccAm0cYYKqoKkikeKFZM0Gp/W +hSrhJ4laTyQqyleIFKpwD9kHDiC/sxjGDhSFmHKhhAnsQIRm2tppFXX0aAMqJEm8 +8jzk1BN2QtKjEAn1u8v1+QW1KP3WuzdXH4L7hhMll66/KIm6Hfs2FRHQpRUWqZeJ +Y4q79NW5p5f+siGwOsGpxb/p11pM+0xnCH3UIFbm3zCTzP4sLvkfFGAeyAHsAwma +P8dJxh40ej3NN8uNiNvt8nw2Vb/1LwIDAQABo4GnMIGkMB0GA1UdDgQWBBQdPc0R +a8alY6Ab7voidkTGaH4PxzB1BgNVHSMEbjBsgBQdPc0Ra8alY6Ab7voidkTGaH4P +x6FJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV +BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAPXRSiP0Fs7sMAwGA1UdEwQF +MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAH1IZNkjuvt2nZPzXsuiVNyCE1vm346z +naE0Uzt3aseAN9m/iiB8mLz+ryvWc2aFMX5lTdsHdm2rqmqBCBXeRwTLf4OeHIju +ZQW6makWt6PxANEo6gbdPbQXbS420ssUhnR2irIH1SdI31iikVFPdiS0baRRE/gS ++440M1jOOOnKm0Qin92ejsshmji/0qaD2+6D5TNw4HmIZaFTBw+kfjxCL6trfeBn +4fT0RJ121V3G3+AtG5sWQ93B3pCg+jtD+fGKkNSLhphq84bD1Zv7l73QGOoylkEn +Sc0ajTLOXFBb83yRdlgV3Da95jH9rDZ4jSod48m+KemoZTDQw0vSwAU= +-----END CERTIFICATE----- diff --git a/conf/tasks.csv b/conf/tasks.csv index e69de29..a06ff67 100644 --- a/conf/tasks.csv +++ b/conf/tasks.csv @@ -0,0 +1,2 @@ +8025,socks5,,1,1,2,,0,0, +8026,httpProxy,,1,2,2,,0,0, diff --git a/lib/common/const.go b/lib/common/const.go index f06deb7..0014125 100644 --- a/lib/common/const.go +++ b/lib/common/const.go @@ -22,6 +22,7 @@ const ( NEW_HOST = "host" CONN_TCP = "tcp" CONN_UDP = "udp" + CONN_TEST = "TST" UnauthorizedBytes = `HTTP/1.1 401 Unauthorized Content-Type: text/plain; charset=utf-8 WWW-Authenticate: Basic realm="easyProxy" diff --git a/lib/conn/conn.go b/lib/conn/conn.go index 2f0e0ee..5f7f615 100755 --- a/lib/conn/conn.go +++ b/lib/conn/conn.go @@ -7,7 +7,9 @@ import ( "errors" "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/config" + "github.com/cnlh/nps/lib/crypt" "github.com/cnlh/nps/lib/file" + "github.com/cnlh/nps/lib/mux" "github.com/cnlh/nps/lib/pool" "github.com/cnlh/nps/lib/rate" "github.com/cnlh/nps/vender/github.com/xtaci/kcp" @@ -119,46 +121,31 @@ func (s *Conn) ReadFlag() (string, error) { //设置连接为长连接 func (s *Conn) SetAlive(tp string) { - if tp == "kcp" { - s.setKcpAlive() - } else { - s.setTcpAlive() + switch s.Conn.(type) { + case *kcp.UDPSession: + s.Conn.(*kcp.UDPSession).SetReadDeadline(time.Time{}) + case *net.TCPConn: + conn := s.Conn.(*net.TCPConn) + conn.SetReadDeadline(time.Time{}) + conn.SetKeepAlive(true) + conn.SetKeepAlivePeriod(time.Duration(2 * time.Second)) + case *mux.PortConn: + s.Conn.(*mux.PortConn).SetReadDeadline(time.Time{}) } } -//设置连接为长连接 -func (s *Conn) setTcpAlive() { - conn := s.Conn.(*net.TCPConn) - conn.SetReadDeadline(time.Time{}) - conn.SetKeepAlive(true) - conn.SetKeepAlivePeriod(time.Duration(2 * time.Second)) -} - -//设置连接为长连接 -func (s *Conn) setKcpAlive() { - conn := s.Conn.(*kcp.UDPSession) - conn.SetReadDeadline(time.Time{}) -} - //设置连接为长连接 func (s *Conn) SetReadDeadline(t time.Duration, tp string) { - if tp == "kcp" { - s.SetKcpReadDeadline(t) - } else { - s.SetTcpReadDeadline(t) + switch s.Conn.(type) { + case *kcp.UDPSession: + s.Conn.(*kcp.UDPSession).SetReadDeadline(time.Now().Add(time.Duration(t) * time.Second)) + case *net.TCPConn: + s.Conn.(*net.TCPConn).SetReadDeadline(time.Now().Add(time.Duration(t) * time.Second)) + case *mux.PortConn: + s.Conn.(*mux.PortConn).SetReadDeadline(time.Now().Add(time.Duration(t) * time.Second)) } } -//set read dead time -func (s *Conn) SetTcpReadDeadline(t time.Duration) { - s.Conn.(*net.TCPConn).SetReadDeadline(time.Now().Add(time.Duration(t) * time.Second)) -} - -//set read dead time -func (s *Conn) SetKcpReadDeadline(t time.Duration) { - s.Conn.(*kcp.UDPSession).SetReadDeadline(time.Now().Add(time.Duration(t) * time.Second)) -} - //send info for link func (s *Conn) SendLinkInfo(link *Link) (int, error) { raw := bytes.NewBuffer([]byte{}) @@ -402,19 +389,19 @@ func SetUdpSession(sess *kcp.UDPSession) { } //conn1 mux conn -func CopyWaitGroup(conn1, conn2 io.ReadWriteCloser, crypt bool, snappy bool, rate *rate.Rate, flow *file.Flow) { +func CopyWaitGroup(conn1, conn2 net.Conn, crypt bool, snappy bool, rate *rate.Rate, flow *file.Flow, isServer bool) { var in, out int64 var wg sync.WaitGroup - conn1 = GetConn(conn1, crypt, snappy, rate) + connHandle := GetConn(conn1, crypt, snappy, rate, isServer) go func(in *int64) { wg.Add(1) - *in, _ = common.CopyBuffer(conn1, conn2) - conn1.Close() + *in, _ = common.CopyBuffer(connHandle, conn2) + connHandle.Close() conn2.Close() wg.Done() }(&in) - out, _ = common.CopyBuffer(conn2, conn1) - conn1.Close() + out, _ = common.CopyBuffer(conn2, connHandle) + connHandle.Close() conn2.Close() wg.Wait() if flow != nil { @@ -423,11 +410,14 @@ func CopyWaitGroup(conn1, conn2 io.ReadWriteCloser, crypt bool, snappy bool, rat } //get crypt or snappy conn -func GetConn(conn io.ReadWriteCloser, crypt, snappy bool, rate *rate.Rate) (io.ReadWriteCloser) { - if crypt { - conn = NewCryptConn(conn, true, rate) +func GetConn(conn net.Conn, cpt, snappy bool, rate *rate.Rate, isServer bool) (io.ReadWriteCloser) { + if cpt { + if isServer { + return crypt.NewTlsServerConn(conn) + } + return crypt.NewTlsClientConn(conn) } else if snappy { - conn = NewSnappyConn(conn, crypt, rate) + return NewSnappyConn(conn, cpt, rate) } return conn } diff --git a/lib/conn/normal.go b/lib/conn/normal.go deleted file mode 100644 index e14e027..0000000 --- a/lib/conn/normal.go +++ /dev/null @@ -1,72 +0,0 @@ -package conn - -import ( - "github.com/cnlh/nps/lib/crypt" - "github.com/cnlh/nps/lib/pool" - "github.com/cnlh/nps/lib/rate" - "io" -) - -type CryptConn struct { - conn io.ReadWriteCloser - crypt bool - rate *rate.Rate -} - -func NewCryptConn(conn io.ReadWriteCloser, crypt bool, rate *rate.Rate) *CryptConn { - c := new(CryptConn) - c.conn = conn - c.crypt = crypt - c.rate = rate - return c -} - -//加密写 -func (s *CryptConn) Write(b []byte) (n int, err error) { - n = len(b) - if s.crypt { - if b, err = crypt.AesEncrypt(b, []byte(cryptKey)); err != nil { - return - } - } - if b, err = GetLenBytes(b); err != nil { - return - } - _, err = s.conn.Write(b) - if s.rate != nil { - s.rate.Get(int64(n)) - } - return -} - -//解密读 -func (s *CryptConn) Read(b []byte) (n int, err error) { - var lens int - var buf []byte - var rb []byte - if lens, err = GetLen(s.conn); err != nil || lens > len(b) || lens < 0 { - return - } - buf = pool.BufPool.Get().([]byte) - defer pool.BufPool.Put(buf) - if n, err = io.ReadFull(s.conn, buf[:lens]); err != nil { - return - } - if s.crypt { - if rb, err = crypt.AesDecrypt(buf[:lens], []byte(cryptKey)); err != nil { - return - } - } else { - rb = buf[:lens] - } - copy(b, rb) - n = len(rb) - if s.rate != nil { - s.rate.Get(int64(n)) - } - return -} - -func (s *CryptConn) Close() error { - return s.conn.Close() -} diff --git a/lib/crypt/tls.go b/lib/crypt/tls.go new file mode 100644 index 0000000..69c2280 --- /dev/null +++ b/lib/crypt/tls.go @@ -0,0 +1,28 @@ +package crypt + +import ( + "crypto/tls" + "github.com/cnlh/nps/vender/github.com/astaxie/beego" + "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" + "net" + "os" + "path/filepath" +) + +func NewTlsServerConn(conn net.Conn) net.Conn { + cert, err := tls.LoadX509KeyPair(filepath.Join(beego.AppPath, "conf", "server.pem"), filepath.Join(beego.AppPath, "conf", "server.key")) + if err != nil { + logs.Error(err) + os.Exit(0) + return nil + } + config := &tls.Config{Certificates: []tls.Certificate{cert}} + return tls.Server(conn, config) +} + +func NewTlsClientConn(conn net.Conn) net.Conn { + conf := &tls.Config{ + InsecureSkipVerify: true, + } + return tls.Client(conn, conf) +} diff --git a/lib/file/file.go b/lib/file/file.go index de822bf..9161433 100644 --- a/lib/file/file.go +++ b/lib/file/file.go @@ -225,6 +225,7 @@ func (s *Csv) StoreHostToCsv() { strconv.Itoa(host.Id), strconv.Itoa(int(host.Flow.ExportFlow)), strconv.Itoa(int(host.Flow.InletFlow)), + host.Scheme, } err1 := writer.Write(record) if err1 != nil { @@ -298,6 +299,11 @@ func (s *Csv) LoadHostFromCsv() { post.Flow = new(Flow) post.Flow.ExportFlow = int64(common.GetIntNoErrByStr(item[8])) post.Flow.InletFlow = int64(common.GetIntNoErrByStr(item[9])) + if len(item) > 10 { + post.Scheme = item[10] + } else { + post.Scheme = "all" + } hosts = append(hosts, post) if post.Id > s.HostIncreaseId { s.HostIncreaseId = post.Id @@ -319,7 +325,7 @@ func (s *Csv) DelHost(id int) error { func (s *Csv) IsHostExist(h *Host) bool { for _, v := range s.Hosts { - if v.Host == h.Host && h.Location == v.Location { + if v.Host == h.Host && h.Location == v.Location && (v.Scheme == "all" || v.Scheme == h.Scheme) { return true } } @@ -497,7 +503,7 @@ func (s *Csv) GetInfoByHost(host string, r *http.Request) (h *Host, err error) { if re, err = regexp.Compile(tmp); err != nil { return } - if len(re.FindAllString(host, -1)) > 0 { + if len(re.FindAllString(host, -1)) > 0 && (v.Scheme == "all" || v.Scheme == r.URL.Scheme) { //URL routing hosts = append(hosts, v) } diff --git a/lib/file/obj.go b/lib/file/obj.go index 7592b19..d6154bb 100644 --- a/lib/file/obj.go +++ b/lib/file/obj.go @@ -133,6 +133,7 @@ type Host struct { NowIndex int TargetArr []string NoStore bool + Scheme string //http https all sync.RWMutex } diff --git a/lib/mux/pconn.go b/lib/mux/pconn.go new file mode 100644 index 0000000..b351e7c --- /dev/null +++ b/lib/mux/pconn.go @@ -0,0 +1,63 @@ +package mux + +import ( + "net" + "time" +) + +type PortConn struct { + Conn net.Conn + rs []byte + start int +} + +func newPortConn(conn net.Conn, rs []byte) *PortConn { + return &PortConn{ + Conn: conn, + rs: rs, + } +} + +func (pConn *PortConn) Read(b []byte) (n int, err error) { + if len(b) < len(pConn.rs)-pConn.start { + defer func() { + pConn.start = pConn.start + len(b) + }() + return copy(b, pConn.rs), nil + } + if pConn.start < len(pConn.rs) { + defer func() { + pConn.start = len(pConn.rs) + }() + return copy(b, pConn.rs[pConn.start:]), nil + } + return pConn.Conn.Read(b) +} + +func (pConn *PortConn) Write(b []byte) (n int, err error) { + return pConn.Conn.Write(b) +} + +func (pConn *PortConn) Close() error { + return pConn.Conn.Close() +} + +func (pConn *PortConn) LocalAddr() net.Addr { + return pConn.Conn.LocalAddr() +} + +func (pConn *PortConn) RemoteAddr() net.Addr { + return pConn.Conn.RemoteAddr() +} + +func (pConn *PortConn) SetDeadline(t time.Time) error { + return pConn.Conn.SetDeadline(t) +} + +func (pConn *PortConn) SetReadDeadline(t time.Time) error { + return pConn.Conn.SetReadDeadline(t) +} + +func (pConn *PortConn) SetWriteDeadline(t time.Time) error { + return pConn.Conn.SetWriteDeadline(t) +} diff --git a/lib/mux/plistener.go b/lib/mux/plistener.go new file mode 100644 index 0000000..9bdaabc --- /dev/null +++ b/lib/mux/plistener.go @@ -0,0 +1,44 @@ +package mux + +import ( + "errors" + "net" +) + +type PortListener struct { + net.Listener + connCh chan *PortConn + addr net.Addr + isClose bool +} + +func NewPortListener(connCh chan *PortConn, addr net.Addr) *PortListener { + return &PortListener{ + connCh: connCh, + addr: addr, + } +} + +func (pListener *PortListener) Accept() (net.Conn, error) { + if pListener.isClose { + return nil, errors.New("the listener has closed") + } + conn := <-pListener.connCh + if conn != nil { + return conn, nil + } + return nil, errors.New("the listener has closed") +} + +func (pListener *PortListener) Close() error { + //close + if pListener.isClose { + return errors.New("the listener has closed") + } + pListener.isClose = true + return nil +} + +func (pListener *PortListener) Addr() net.Addr { + return pListener.addr +} diff --git a/lib/mux/pmux.go b/lib/mux/pmux.go new file mode 100644 index 0000000..ff4f5d4 --- /dev/null +++ b/lib/mux/pmux.go @@ -0,0 +1,163 @@ +// This module is used for port reuse +// Distinguish client, web manager , HTTP and HTTPS according to the difference of protocol +package mux + +import ( + "bufio" + "bytes" + "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" + "github.com/pkg/errors" + "io" + "net" + "strconv" + "strings" +) + +const ( + HTTP_GET = 716984 + HTTP_POST = 807983 + HTTP_HEAD = 726965 + HTTP_PUT = 808585 + HTTP_DELETE = 686976 + HTTP_CONNECT = 677978 + HTTP_OPTIONS = 798084 + HTTP_TRACE = 848265 + CLIENT = 848384 +) + +type PortMux struct { + net.Listener + port int + isClose bool + managerHost string + clientConn chan *PortConn + httpConn chan *PortConn + httpsConn chan *PortConn + managerConn chan *PortConn +} + +func NewPortMux(port int, managerHost string) *PortMux { + pMux := &PortMux{ + managerHost: managerHost, + port: port, + clientConn: make(chan *PortConn), + httpConn: make(chan *PortConn), + httpsConn: make(chan *PortConn), + managerConn: make(chan *PortConn), + } + pMux.Start() + return pMux +} + +func (pMux *PortMux) Start() error { + // Port multiplexing is based on TCP only + tcpAddr, err := net.ResolveTCPAddr("tcp", "0.0.0.0:"+strconv.Itoa(pMux.port)) + if err != nil { + return err + } + pMux.Listener, err = net.ListenTCP("tcp", tcpAddr) + if err != nil { + return err + } + go func() { + for { + conn, err := pMux.Listener.Accept() + if err != nil { + logs.Warn(err) + //close + pMux.Close() + } + go pMux.process(conn) + } + }() + return nil +} + +func (pMux *PortMux) process(conn net.Conn) { + // Recognition according to different signs + // read 3 byte + buf := make([]byte, 3) + if n, err := io.ReadFull(conn, buf); err != nil || n != 3 { + return + } + var ch chan *PortConn + var rs []byte + var buffer bytes.Buffer + switch bytesToNum(buf) { + case HTTP_CONNECT, HTTP_DELETE, HTTP_GET, HTTP_HEAD, HTTP_OPTIONS, HTTP_POST, HTTP_PUT, HTTP_TRACE: //http and manager + buffer.Reset() + r := bufio.NewReader(conn) + buffer.Write(buf) + for { + b, _, err := r.ReadLine() + if err != nil { + logs.Warn("read line error", err.Error()) + conn.Close() + break + } + buffer.Write(b) + buffer.Write([]byte("\r\n")) + if strings.Index(string(b), "Host:") == 0 || strings.Index(string(b), "host:") == 0 { + // Remove host and space effects + str := strings.Replace(string(b), "Host:", "", -1) + str = strings.Replace(str, "host:", "", -1) + str = strings.TrimSpace(str) + // Determine whether it is the same as the manager domain name + if str == pMux.managerHost { + ch = pMux.managerConn + } else { + ch = pMux.httpConn + } + b, _ := r.Peek(r.Buffered()) + buffer.Write(b) + rs = buffer.Bytes() + break + } + } + case CLIENT: // client connection + ch = pMux.clientConn + default: // https + ch = pMux.httpsConn + } + if len(rs) == 0 { + rs = buf + } + ch <- newPortConn(conn, rs) +} + +func (pMux *PortMux) Close() error { + if pMux.isClose { + return errors.New("the port mux has closed") + } + pMux.isClose = true + close(pMux.clientConn) + close(pMux.httpsConn) + close(pMux.httpConn) + close(pMux.managerConn) + return pMux.Listener.Close() +} + +func (pMux *PortMux) GetClientListener() net.Listener { + return NewPortListener(pMux.clientConn, pMux.Listener.Addr()) +} + +func (pMux *PortMux) GetHttpListener() net.Listener { + return NewPortListener(pMux.httpConn, pMux.Listener.Addr()) +} + +func (pMux *PortMux) GetHttpsListener() net.Listener { + return NewPortListener(pMux.httpsConn, pMux.Listener.Addr()) +} + +func (pMux *PortMux) GetManagerListener() net.Listener { + return NewPortListener(pMux.managerConn, pMux.Listener.Addr()) +} + +func bytesToNum(b []byte) int { + var str string + for i := 0; i < len(b); i++ { + str += strconv.Itoa(int(b[i])) + } + x, _ := strconv.Atoi(str) + return int(x) +} diff --git a/lib/mux/pmux_test.go b/lib/mux/pmux_test.go new file mode 100644 index 0000000..01a9b6c --- /dev/null +++ b/lib/mux/pmux_test.go @@ -0,0 +1,39 @@ +package mux + +import ( + "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" + "testing" + "time" +) + +func TestPortMux_Close(t *testing.T) { + logs.Reset() + logs.EnableFuncCallDepth(true) + logs.SetLogFuncCallDepth(3) + + pMux := NewPortMux(8888) + go func() { + if pMux.Start() != nil { + logs.Warn("Error") + } + }() + time.Sleep(time.Second * 3) + go func() { + l := pMux.GetHttpsAccept() + conn, err := l.Accept() + logs.Warn(conn, err) + }() + go func() { + l := pMux.GetHttpAccept() + conn, err := l.Accept() + logs.Warn(conn, err) + }() + go func() { + l := pMux.GetClientAccept() + conn, err := l.Accept() + logs.Warn(conn, err) + }() + l := pMux.GetManagerAccept() + conn, err := l.Accept() + logs.Warn(conn, err) +} diff --git a/lib/version/version.go b/lib/version/version.go index da2a957..af8a2b6 100644 --- a/lib/version/version.go +++ b/lib/version/version.go @@ -1,7 +1,8 @@ package version -const VERSION = "0.17.1" +const VERSION = "0.18.0" +// Compulsory minimum version, Minimum downward compatibility to this version func GetVersion() string { - return VERSION + return "0.18.0" } diff --git a/server/connection/connection.go b/server/connection/connection.go new file mode 100644 index 0000000..79c144d --- /dev/null +++ b/server/connection/connection.go @@ -0,0 +1,92 @@ +package connection + +import ( + "github.com/cnlh/nps/lib/mux" + "github.com/cnlh/nps/vender/github.com/astaxie/beego" + "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" + "github.com/cnlh/nps/vender/github.com/xtaci/kcp" + "net" + "os" + "strconv" +) + +var pMux *mux.PortMux +var bridgePort string +var httpsPort string +var httpPort string +var webPort string + +func InitConnectionService() { + bridgePort = beego.AppConfig.String("bridge_port") + httpsPort = beego.AppConfig.String("https_proxy_port") + httpPort = beego.AppConfig.String("http_proxy_port") + webPort = beego.AppConfig.String("web_port") + + if httpPort == bridgePort || httpsPort == bridgePort || webPort == bridgePort { + port, err := strconv.Atoi(bridgePort) + if err != nil { + logs.Error(err) + os.Exit(0) + } + pMux = mux.NewPortMux(port, beego.AppConfig.String("web_host")) + } +} + +func GetBridgeListener(tp string) (interface{}, error) { + logs.Info("server start, the bridge type is %s, the bridge port is %s", tp, bridgePort) + var p int + var err error + if p, err = strconv.Atoi(bridgePort); err != nil { + return nil, err + } + if pMux != nil { + return pMux.GetClientListener(), nil + } else if tp == "udp" { + if p, err = beego.AppConfig.Int("bridge_port"); err != nil { + logs.Error(err) + os.Exit(0) + } else { + return kcp.ListenWithOptions(":"+strconv.Itoa(p), nil, 150, 3) + } + } + return net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP(beego.AppConfig.String("bridge_ip")), p, ""}) +} + +func GetHttpListener() (net.Listener, error) { + if pMux != nil && httpPort == bridgePort { + logs.Info("start http listener, port is", bridgePort) + return pMux.GetHttpListener(), nil + } + logs.Info("start http listener, port is", httpPort) + return getTcpListener("", httpPort) +} + +func GetHttpsListener() (net.Listener, error) { + if pMux != nil && httpsPort == bridgePort { + logs.Info("start https listener, port is", bridgePort) + return pMux.GetHttpsListener(), nil + } + logs.Info("start https listener, port is", httpsPort) + return getTcpListener("", httpsPort) +} + +func GetWebManagerListener() (net.Listener, error) { + if pMux != nil && webPort == bridgePort { + logs.Info("Web management start, access port is", bridgePort) + return pMux.GetManagerListener(), nil + } + logs.Info("web management start, access port is", webPort) + return getTcpListener(beego.AppConfig.String("web_ip"), webPort) +} + +func getTcpListener(ip, p string) (net.Listener, error) { + port, err := strconv.Atoi(p) + if err != nil { + logs.Error(err) + os.Exit(0) + } + if ip == "" { + ip = "0.0.0.0" + } + return net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP(ip), port, ""}) +} diff --git a/server/proxy/base.go b/server/proxy/base.go index 4e58350..1eb5949 100644 --- a/server/proxy/base.go +++ b/server/proxy/base.go @@ -83,7 +83,7 @@ func (s *BaseServer) DealClient(c *conn.Conn, addr string, rb []byte, tp string) if rb != nil { target.Write(rb) } - conn.CopyWaitGroup(target, c, link.Crypt, link.Compress, s.task.Client.Rate, s.task.Client.Flow) + conn.CopyWaitGroup(target, c.Conn, link.Crypt, link.Compress, s.task.Client.Rate, s.task.Client.Flow, true) } s.task.Client.AddConn() diff --git a/server/proxy/http.go b/server/proxy/http.go index bf7a0ad..d6049ab 100644 --- a/server/proxy/http.go +++ b/server/proxy/http.go @@ -7,6 +7,7 @@ import ( "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/file" + "github.com/cnlh/nps/server/connection" "github.com/cnlh/nps/vender/github.com/astaxie/beego" "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" "io" @@ -21,18 +22,19 @@ import ( type httpServer struct { BaseServer - httpPort int //http端口 - httpsPort int //https监听端口 - pemPath string - keyPath string - stop chan bool + httpPort int //http端口 + httpsPort int //https监听端口 + pemPath string + keyPath string + stop chan bool + httpslistener net.Listener } func NewHttp(bridge *bridge.Bridge, c *file.Tunnel) *httpServer { - httpPort, _ := beego.AppConfig.Int("httpProxyPort") - httpsPort, _ := beego.AppConfig.Int("httpsProxyPort") - pemPath := beego.AppConfig.String("pemPath") - keyPath := beego.AppConfig.String("keyPath") + httpPort, _ := beego.AppConfig.Int("http_proxy_port") + httpsPort, _ := beego.AppConfig.Int("https_proxy_port") + pemPath := beego.AppConfig.String("pem_path") + keyPath := beego.AppConfig.String("key_path") return &httpServer{ BaseServer: BaseServer{ task: c, @@ -49,16 +51,20 @@ func NewHttp(bridge *bridge.Bridge, c *file.Tunnel) *httpServer { func (s *httpServer) Start() error { var err error - var http, https *http.Server + var httpSrv, httpsSrv *http.Server if s.errorContent, err = common.ReadAllFromFile(filepath.Join(common.GetRunPath(), "web", "static", "page", "error.html")); err != nil { s.errorContent = []byte("easyProxy 404") } if s.httpPort > 0 { - http = s.NewServer(s.httpPort) + httpSrv = s.NewServer(s.httpPort, "http") go func() { - logs.Info("Start http listener, port is", s.httpPort) - err := http.ListenAndServe() + l, err := connection.GetHttpListener() + if err != nil { + logs.Error(err) + os.Exit(0) + } + err = httpSrv.Serve(l) if err != nil { logs.Error(err) os.Exit(0) @@ -67,17 +73,21 @@ func (s *httpServer) Start() error { } if s.httpsPort > 0 { if !common.FileExists(s.pemPath) { - logs.Error("ssl certFile %s is not exist", s.pemPath) os.Exit(0) } if !common.FileExists(s.keyPath) { logs.Error("ssl keyFile %s exist", s.keyPath) os.Exit(0) } - https = s.NewServer(s.httpsPort) + httpsSrv = s.NewServer(s.httpsPort, "https") go func() { logs.Info("Start https listener, port is", s.httpsPort) - err := https.ListenAndServeTLS(s.pemPath, s.keyPath) + l, err := connection.GetHttpsListener() + if err != nil { + logs.Error(err) + os.Exit(0) + } + err = httpsSrv.ServeTLS(l, s.pemPath, s.keyPath) if err != nil { logs.Error(err) os.Exit(0) @@ -86,11 +96,11 @@ func (s *httpServer) Start() error { } select { case <-s.stop: - if http != nil { - http.Close() + if httpSrv != nil { + httpsSrv.Close() } - if https != nil { - https.Close() + if httpsSrv != nil { + httpsSrv.Close() } } return nil @@ -123,16 +133,17 @@ func (s *httpServer) process(c *conn.Conn, r *http.Request) { lastHost *file.Host err error connClient io.ReadWriteCloser + scheme = r.URL.Scheme ) if host, err = file.GetCsvDb().GetInfoByHost(r.Host, r); err != nil { - logs.Notice("the url %s %s can't be parsed!", r.Host, r.RequestURI) + logs.Notice("the url %s %s %s can't be parsed!", r.URL.Scheme, r.Host, r.RequestURI) goto end } else if !host.Client.GetConn() { //conn num limit logs.Notice("connections exceed the current client %d limit %d ,now connection num %d", host.Client.Id, host.Client.MaxConn, host.Client.NowConn) c.Close() return } else { - logs.Trace("new http(s) connection,clientId %d,host %s,url %s,remote address %s", host.Client.Id, r.Host, r.URL, r.RemoteAddr) + logs.Trace("new %s connection,clientId %d,host %s,url %s,remote address %s", r.URL.Scheme, host.Client.Id, r.Host, r.URL, r.RemoteAddr) lastHost = host } for { @@ -153,7 +164,7 @@ func (s *httpServer) process(c *conn.Conn, r *http.Request) { logs.Notice("connect to target %s error %s", lk.Host, err) break } - connClient = conn.GetConn(target, lk.Crypt, lk.Compress, host.Client.Rate) + connClient = conn.GetConn(target, lk.Crypt, lk.Compress, host.Client.Rate, true) isConn = false go func() { w, _ := common.CopyBuffer(c, connClient) @@ -163,10 +174,10 @@ func (s *httpServer) process(c *conn.Conn, r *http.Request) { }() } else { r, err = http.ReadRequest(bufio.NewReader(c)) + r.URL.Scheme = scheme if err != nil { break } - logs.Trace("New http(s) connection,clientId %d,host %s,url %s,remote address %s", host.Client.Id, r.Host, r.URL, r.RemoteAddr) //What happened ,Why one character less??? if r.Method == "ET" { r.Method = "GET" @@ -174,11 +185,12 @@ func (s *httpServer) process(c *conn.Conn, r *http.Request) { if r.Method == "OST" { r.Method = "POST" } - logs.Trace("new http(s) connection,clientId %d,host %s,url %s,remote address %s", host.Client.Id, r.Host, r.URL, r.RemoteAddr) - if host, err = file.GetCsvDb().GetInfoByHost(r.Host, r); err != nil { - logs.Notice("the url %s %s can't be parsed!", r.Host, r.RequestURI) + logs.Trace("new %s connection,clientId %d,host %s,url %s,remote address %s", r.URL.Scheme, host.Client.Id, r.Host, r.URL, r.RemoteAddr) + if hostTmp, err := file.GetCsvDb().GetInfoByHost(r.Host, r); err != nil { + logs.Notice("the url %s %s %s can't be parsed!", r.URL.Scheme, r.Host, r.RequestURI) break } else if host != lastHost { + host = hostTmp lastHost = host isConn = true host.Client.AddConn() @@ -192,6 +204,7 @@ func (s *httpServer) process(c *conn.Conn, r *http.Request) { break } host.Flow.Add(int64(len(b)), 0) + logs.Trace("http(s) request, method %s, host %s, url %s, remote address %s, target %s", r.Method, r.Host, r.RequestURI, r.RemoteAddr, host.Target) //write connClient.Write(b) } @@ -208,10 +221,11 @@ end: } } -func (s *httpServer) NewServer(port int) *http.Server { +func (s *httpServer) NewServer(port int, scheme string) *http.Server { return &http.Server{ Addr: ":" + strconv.Itoa(port), Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + r.URL.Scheme = scheme s.handleTunneling(w, r) }), // Disable HTTP/2. diff --git a/server/proxy/socks5.go b/server/proxy/socks5.go index 6100d72..3a2b0c2 100755 --- a/server/proxy/socks5.go +++ b/server/proxy/socks5.go @@ -144,12 +144,12 @@ func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8) { //s.DealClient(conn.NewConn(c), addr, nil, ltype) link := conn.NewLink(ltype, addr, s.task.Client.Cnf.Crypt, s.task.Client.Cnf.Compress, c.RemoteAddr().String()) - if target, err := s.bridge.SendLinkInfo(s.task.Client.Id, link, c.RemoteAddr().String(),s.task); err != nil { + if target, err := s.bridge.SendLinkInfo(s.task.Client.Id, link, c.RemoteAddr().String(), s.task); err != nil { c.Close() return } else { s.sendReply(c, succeeded) - conn.CopyWaitGroup(target, c, link.Crypt, link.Compress, s.task.Client.Rate, s.task.Client.Flow) + conn.CopyWaitGroup(target, c, link.Crypt, link.Compress, s.task.Client.Rate, s.task.Client.Flow, true) } s.task.Client.AddConn() diff --git a/server/proxy/tcp.go b/server/proxy/tcp.go index 32ee317..eeb4b55 100755 --- a/server/proxy/tcp.go +++ b/server/proxy/tcp.go @@ -6,10 +6,11 @@ import ( "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/file" + "github.com/cnlh/nps/server/connection" "github.com/cnlh/nps/vender/github.com/astaxie/beego" "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" "net" - "os" + "net/http" "path/filepath" "strings" ) @@ -72,20 +73,24 @@ type WebServer struct { //开始 func (s *WebServer) Start() error { - p, _ := beego.AppConfig.Int("httpport") + p, _ := beego.AppConfig.Int("web_port") if p == 0 { stop := make(chan struct{}) <-stop } - if !common.TestTcpPort(p) { - logs.Error("Web management port %d is occupied", p) - os.Exit(0) - } + //if !common.TestTcpPort(p) { + // // logs.Error("Web management port %d is occupied", p) + // // os.Exit(0) + // //} beego.BConfig.WebConfig.Session.SessionOn = true - logs.Info("Web management start, access port is", p) beego.SetStaticPath("/static", filepath.Join(common.GetRunPath(), "web", "static")) beego.SetViewsPath(filepath.Join(common.GetRunPath(), "web", "views")) - beego.Run() + if l, err := connection.GetWebManagerListener(); err == nil { + beego.InitBeforeHTTPRun() + http.Serve(l, beego.BeeApp.Handlers) + } else { + logs.Error(err) + } return errors.New("Web management startup failure") } diff --git a/server/server.go b/server/server.go index 76aa5f8..74284f0 100644 --- a/server/server.go +++ b/server/server.go @@ -34,7 +34,7 @@ func init() { //从csv文件中恢复任务 func InitFromCsv() { //Add a public password - if vkey := beego.AppConfig.String("publicVkey"); vkey != "" { + if vkey := beego.AppConfig.String("public_vkey"); vkey != "" { c := file.NewClient(vkey, true, true) file.GetCsvDb().NewClient(c) RunList[c.Id] = nil @@ -77,14 +77,12 @@ func DealBridgeTask() { //start a new server func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string) { - Bridge = bridge.NewTunnel(bridgePort, bridgeType, common.GetBoolByStr(beego.AppConfig.String("ipLimit")), RunList) + Bridge = bridge.NewTunnel(bridgePort, bridgeType, common.GetBoolByStr(beego.AppConfig.String("ip_limit")), RunList) if err := Bridge.StartTunnel(); err != nil { logs.Error("start server bridge error", err) os.Exit(0) - } else { - logs.Info("Server startup, the bridge type is %s, the bridge port is %d", bridgeType, bridgePort) } - if p, err := beego.AppConfig.Int("p2pPort"); err == nil { + if p, err := beego.AppConfig.Int("p2p_port"); err == nil { logs.Info("start p2p server port", p) go proxy.NewP2PServer(p).Start() } @@ -159,7 +157,7 @@ func AddTask(t *file.Tunnel) error { logs.Error("taskId %d start error port %d open failed", t.Id, t.Port) return errors.New("the port open error") } - if minute, err := beego.AppConfig.Int("flowStoreInterval"); err == nil && minute > 0 { + if minute, err := beego.AppConfig.Int("flow_store_interval"); err == nil && minute > 0 { go flowSession(time.Minute * time.Duration(minute)) } if svr := NewMode(Bridge, t); svr != nil { @@ -324,14 +322,14 @@ func GetDashboardData() map[string]interface{} { data["httpProxyCount"] = http data["secretCount"] = secret data["p2pCount"] = p2p - data["bridgeType"] = beego.AppConfig.String("bridgeType") - data["httpProxyPort"] = beego.AppConfig.String("httpProxyPort") - data["httpsProxyPort"] = beego.AppConfig.String("httpsProxyPort") - data["ipLimit"] = beego.AppConfig.String("ipLimit") - data["flowStoreInterval"] = beego.AppConfig.String("flowStoreInterval") - data["serverIp"] = beego.AppConfig.String("serverIp") - data["p2pPort"] = beego.AppConfig.String("p2pPort") - data["logLevel"] = beego.AppConfig.String("logLevel") + data["bridgeType"] = beego.AppConfig.String("bridge_type") + data["httpProxyPort"] = beego.AppConfig.String("http_proxy_port") + data["httpsProxyPort"] = beego.AppConfig.String("https_proxy_port") + data["ipLimit"] = beego.AppConfig.String("ip_limit") + data["flowStoreInterval"] = beego.AppConfig.String("flow_store_interval") + data["serverIp"] = beego.AppConfig.String("p2p_ip") + data["p2pPort"] = beego.AppConfig.String("p2p_port") + data["logLevel"] = beego.AppConfig.String("log_level") tcpCount := 0 for _, v := range file.GetCsvDb().Clients { tcpCount += v.NowConn diff --git a/server/test/test.go b/server/test/test.go index 9a43eae..c67fd8a 100644 --- a/server/test/test.go +++ b/server/test/test.go @@ -18,17 +18,17 @@ func TestServerConfig() { isInArr(&postTcpArr, v.Port, v.Remark, "tcp") } } - p, err := beego.AppConfig.Int("httpport") + p, err := beego.AppConfig.Int("web_port") if err != nil { log.Fatalln("Getting web management port error :", err) } else { isInArr(&postTcpArr, p, "Web Management port", "tcp") } - if p := beego.AppConfig.String("bridgePort"); p != "" { + if p := beego.AppConfig.String("bridge_port"); p != "" { if port, err := strconv.Atoi(p); err != nil { log.Fatalln("get Server and client communication portserror:", err) - } else if beego.AppConfig.String("bridgeType") == "kcp" { + } else if beego.AppConfig.String("bridge_type") == "kcp" { isInArr(&postUdpArr, port, "Server and client communication ports", "udp") } else { isInArr(&postTcpArr, port, "Server and client communication ports", "tcp") @@ -42,7 +42,7 @@ func TestServerConfig() { isInArr(&postTcpArr, port, "https port", "tcp") } } - if p := beego.AppConfig.String("httpsProxyPort"); p != "" { + if p := beego.AppConfig.String("https_proxy_port"); p != "" { if port, err := strconv.Atoi(p); err != nil { log.Fatalln("get https port error", err) } else { diff --git a/server/tool/utils.go b/server/tool/utils.go index 37b39a9..c95f41a 100644 --- a/server/tool/utils.go +++ b/server/tool/utils.go @@ -8,7 +8,7 @@ import ( var ports []int func init() { - p := beego.AppConfig.String("allowPorts") + p := beego.AppConfig.String("allow_ports") ports = common.GetPorts(p) } diff --git a/web/controllers/auth.go b/web/controllers/auth.go index a2c310c..d0305f3 100644 --- a/web/controllers/auth.go +++ b/web/controllers/auth.go @@ -15,11 +15,11 @@ func (s *AuthController) GetAuthKey() { s.Data["json"] = m s.ServeJSON() }() - if cryptKey := beego.AppConfig.String("cryptKey"); len(cryptKey) != 16 { + if cryptKey := beego.AppConfig.String("auth_crypt_key"); len(cryptKey) != 16 { m["status"] = 0 return } else { - b, err := crypt.AesEncrypt([]byte(beego.AppConfig.String("authKey")), []byte(cryptKey)) + b, err := crypt.AesEncrypt([]byte(beego.AppConfig.String("auth_key")), []byte(cryptKey)) if err != nil { m["status"] = 0 return diff --git a/web/controllers/base.go b/web/controllers/base.go index 636676a..91be786 100755 --- a/web/controllers/base.go +++ b/web/controllers/base.go @@ -50,6 +50,10 @@ func (s *BaseController) display(tpl ...string) { arr := strings.Split(common.GetHostByName(ip), ":") s.Data["ip"] = arr[0] } + s.Data["bridgeType"] = beego.AppConfig.String("bridge_type") + if common.IsWindows() { + s.Data["win"] = ".exe" + } s.Data["p"] = server.Bridge.TunnelPort s.Data["proxyPort"] = beego.AppConfig.String("hostPort") s.Layout = "public/layout.html" diff --git a/web/controllers/index.go b/web/controllers/index.go index 0176d77..81b9c56 100755 --- a/web/controllers/index.go +++ b/web/controllers/index.go @@ -239,6 +239,7 @@ func (s *IndexController) AddHost() { Remark: s.GetString("remark"), Location: s.GetString("location"), Flow: &file.Flow{}, + Scheme: s.GetString("scheme"), } var err error if h.Client, err = file.GetCsvDb().GetClient(s.GetIntNoErr("client_id")); err != nil { @@ -273,6 +274,7 @@ func (s *IndexController) EditHost() { h.Remark = s.GetString("remark") h.TargetArr = nil h.Location = s.GetString("location") + h.Scheme = s.GetString("scheme") file.GetCsvDb().UpdateHost(h) var err error if h.Client, err = file.GetCsvDb().GetClient(s.GetIntNoErr("client_id")); err != nil { diff --git a/web/controllers/login.go b/web/controllers/login.go index 19f6f06..e960ae6 100755 --- a/web/controllers/login.go +++ b/web/controllers/login.go @@ -12,7 +12,7 @@ func (self *LoginController) Index() { self.TplName = "login/index.html" } func (self *LoginController) Verify() { - if self.GetString("password") == beego.AppConfig.String("password") && self.GetString("username") == beego.AppConfig.String("username") { + if self.GetString("password") == beego.AppConfig.String("web_password") && self.GetString("username") == beego.AppConfig.String("web_username") { self.SetSession("auth", true) self.Data["json"] = map[string]interface{}{"status": 1, "msg": "login success"} self.ServeJSON() diff --git a/web/views/client/list.html b/web/views/client/list.html index 0594b5e..ac8282e 100755 --- a/web/views/client/list.html +++ b/web/views/client/list.html @@ -129,7 +129,7 @@ + 'compress: ' + row.Cnf.Compress + `       ` + 'username: ' + row.Cnf.U + `       ` + 'password: ' + row.Cnf.P + `       ` + "

" - + 'commond: ' + "./npc -server={{.ip}}:{{.p}} -vkey=" + row.VerifyKey + "" + + 'commond: ' + "./npc{{.win}} -server={{.ip}}:{{.p}} -vkey=" + row.VerifyKey + " -type=" +{{.bridgeType}} +"" }, //表格的列 columns: [ diff --git a/web/views/index/hadd.html b/web/views/index/hadd.html index bf9f30b..3dac746 100755 --- a/web/views/index/hadd.html +++ b/web/views/index/hadd.html @@ -16,6 +16,16 @@ +
+ +
+ +
+
diff --git a/web/views/index/hedit.html b/web/views/index/hedit.html index a1395ff..cfc2da1 100644 --- a/web/views/index/hedit.html +++ b/web/views/index/hedit.html @@ -1,4 +1,3 @@ -
@@ -9,13 +8,25 @@
- +
- + +
+
+
+ +
+
diff --git a/web/views/index/hlist.html b/web/views/index/hlist.html index ca862d3..eb54351 100755 --- a/web/views/index/hlist.html +++ b/web/views/index/hlist.html @@ -97,6 +97,12 @@ visible: true,//false表示不显示 sortable: true,//启用排序 }, + { + field: 'Scheme',//域值 + title: 'scheme',//标题 + visible: true,//false表示不显示 + sortable: true,//启用排序 + }, { field: 'Target',//域值 title: 'target',//标题