init
This commit is contained in:
@@ -0,0 +1,421 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
utils "anytunnel/at-common"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/snail007/mini-logger"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
var (
|
||||
apiTimeout = time.Second * 30
|
||||
)
|
||||
|
||||
func apiTrafficCount(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
d, err := trafficCounter.AllDataJSON()
|
||||
if err != nil {
|
||||
jsonError(w, err, nil)
|
||||
return
|
||||
}
|
||||
fmt.Fprint(w, `{"code":1,"message":"","data":`+string(d)+`}`)
|
||||
}
|
||||
func apiTrafficCountTunnel(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
_TunnelID := ps.ByName("TunnelID")
|
||||
TunnelID, err := strconv.ParseUint(_TunnelID, 10, 64)
|
||||
if err != nil {
|
||||
jsonError(w, err, nil)
|
||||
return
|
||||
}
|
||||
_, err = poolTunnel.Get(TunnelID)
|
||||
if err != nil {
|
||||
jsonError(w, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
d, err := trafficCounter.TunnelDataJSON(TunnelID)
|
||||
if err != nil {
|
||||
jsonError(w, err, nil)
|
||||
return
|
||||
}
|
||||
fmt.Fprint(w, `{"code":1,"message":"","data":`+string(d)+`}`)
|
||||
}
|
||||
func apiServerStatus(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
ServerToken := ps.ByName("ServerToken")
|
||||
_, err := poolServerControlChannel.Get(ServerToken)
|
||||
if err != nil {
|
||||
jsonError(w, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
jsonSuccess(w, "", nil)
|
||||
}
|
||||
func apiClientStatus(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
ClientToken := ps.ByName("ClientToken")
|
||||
_, err := poolClientControlChannel.Get(ClientToken)
|
||||
if err != nil {
|
||||
jsonError(w, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
jsonSuccess(w, "", nil)
|
||||
}
|
||||
func apiServerOffline(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
ServerToken := ps.ByName("ServerToken")
|
||||
c, err := poolServerControlChannel.Get(ServerToken)
|
||||
if err != nil {
|
||||
jsonError(w, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
err = (*c.ServerMessageChannel.Conn).Close()
|
||||
if err != nil {
|
||||
jsonError(w, err, nil)
|
||||
return
|
||||
}
|
||||
//server offline should be delete data file associate it
|
||||
dataRecovery.DeleteServer(ServerToken)
|
||||
jsonSuccess(w, "", nil)
|
||||
}
|
||||
func apiClientOffline(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
ClientToken := ps.ByName("ClientToken")
|
||||
c, err := poolClientControlChannel.Get(ClientToken)
|
||||
if err != nil {
|
||||
jsonError(w, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
err = (*c.ClientMessageChannel.Conn).Close()
|
||||
if err != nil {
|
||||
jsonError(w, err, nil)
|
||||
return
|
||||
}
|
||||
jsonSuccess(w, "", nil)
|
||||
}
|
||||
func apiPortStatus(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
_TunnelID := ps.ByName("TunnelID")
|
||||
TunnelID, err := strconv.ParseUint(_TunnelID, 10, 64)
|
||||
if err != nil {
|
||||
jsonError(w, err, nil)
|
||||
return
|
||||
}
|
||||
clusterTunnel, err := poolTunnel.Get(TunnelID)
|
||||
if err != nil {
|
||||
jsonError(w, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
cmd := utils.MsgServerStatusPort{
|
||||
Msg: utils.Msg{MsgType: utils.MSG_SERVER_STATUS_PORT},
|
||||
TunnelID: TunnelID,
|
||||
Protocol: clusterTunnel.Protocol,
|
||||
}
|
||||
c, err := poolServerControlChannel.Get(clusterTunnel.ServerToken)
|
||||
if err != nil {
|
||||
jsonError(w, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
err = c.ServerMessageChannel.Write(cmd)
|
||||
if err != nil {
|
||||
jsonError(w, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
var resp utils.MsgResponse
|
||||
err = c.ServerMessageChannel.ReadTimeout(&resp, 5000)
|
||||
if err != nil {
|
||||
jsonError(w, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
if !resp.IsSuccess() {
|
||||
jsonError(w, resp.Message, nil)
|
||||
return
|
||||
}
|
||||
jsonSuccess(w, resp.Message, nil)
|
||||
}
|
||||
func apiPortClose(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
_TunnelID := ps.ByName("TunnelID")
|
||||
TunnelID, err := strconv.ParseUint(_TunnelID, 10, 64)
|
||||
if err != nil {
|
||||
jsonError(w, err, nil)
|
||||
return
|
||||
}
|
||||
clusterTunnel, err := poolTunnel.Get(TunnelID)
|
||||
if err != nil {
|
||||
jsonError(w, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
cmd := utils.MsgServerClosePort{
|
||||
Msg: utils.Msg{MsgType: utils.MSG_SERVER_CLOSE_PORT},
|
||||
TunnelID: TunnelID,
|
||||
Protocol: clusterTunnel.Protocol,
|
||||
}
|
||||
c, err := poolServerControlChannel.Get(clusterTunnel.ServerToken)
|
||||
if err != nil {
|
||||
jsonError(w, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
err = c.ServerMessageChannel.Write(cmd)
|
||||
if err != nil {
|
||||
jsonError(w, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
var resp utils.MsgResponse
|
||||
err = c.ServerMessageChannel.ReadTimeout(&resp, 5000)
|
||||
if err != nil {
|
||||
jsonError(w, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
if !resp.IsSuccess() {
|
||||
jsonError(w, resp.Message, nil)
|
||||
return
|
||||
}
|
||||
trafficCounter.DeleteTunnel(TunnelID)
|
||||
poolTunnel.Delete(TunnelID)
|
||||
err = dataRecovery.Delete(clusterTunnel.ServerToken, clusterTunnel.TunnelID)
|
||||
if err != nil {
|
||||
jsonError(w, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
jsonSuccess(w, "success", nil)
|
||||
}
|
||||
func apiPortOpen(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
_TunnelID := ps.ByName("TunnelID")
|
||||
ServerToken := ps.ByName("ServerToken")
|
||||
ServerBindIP := ps.ByName("ServerBindIP")
|
||||
_ServerListenPort := ps.ByName("ServerListenPort")
|
||||
ClientToken := ps.ByName("ClientToken")
|
||||
ClientLocalHost := ps.ByName("ClientLocalHost")
|
||||
_ClientLocalPort := ps.ByName("ClientLocalPort")
|
||||
_Protocol := ps.ByName("Protocol")
|
||||
_BytesPerSec := ps.ByName("BytesPerSec")
|
||||
TunnelID, err := strconv.ParseUint(_TunnelID, 10, 64)
|
||||
if err != nil {
|
||||
jsonError(w, err, nil)
|
||||
return
|
||||
}
|
||||
ServerListenPort, err := strconv.Atoi(_ServerListenPort)
|
||||
if err != nil {
|
||||
jsonError(w, err, nil)
|
||||
return
|
||||
}
|
||||
ClientLocalPort, err := strconv.Atoi(_ClientLocalPort)
|
||||
if err != nil {
|
||||
jsonError(w, err, nil)
|
||||
return
|
||||
}
|
||||
Protocol, err := strconv.Atoi(_Protocol)
|
||||
if err != nil {
|
||||
jsonError(w, err, nil)
|
||||
return
|
||||
}
|
||||
if Protocol != 1 && Protocol != 2 {
|
||||
jsonError(w, "protocol error", nil)
|
||||
return
|
||||
}
|
||||
BytesPerSec, err := strconv.Atoi(_BytesPerSec)
|
||||
if err != nil {
|
||||
jsonError(w, err, nil)
|
||||
return
|
||||
}
|
||||
if BytesPerSec < 0 {
|
||||
jsonError(w, "BytesPerSec error", nil)
|
||||
return
|
||||
}
|
||||
clusterTunnel, err := poolTunnel.Get(TunnelID)
|
||||
if err == nil {
|
||||
jsonError(w, "tunnel already opened , please close first", nil)
|
||||
return
|
||||
}
|
||||
clusterTunnel = ClusterTunnel{}
|
||||
clusterTunnel.TunnelID = TunnelID
|
||||
clusterTunnel.ServerToken = ServerToken
|
||||
clusterTunnel.ServerBindIP = ServerBindIP
|
||||
clusterTunnel.ServerListenPort = ServerListenPort
|
||||
clusterTunnel.ClientToken = ClientToken
|
||||
clusterTunnel.ClientLocalHost = ClientLocalHost
|
||||
clusterTunnel.ClientLocalPort = ClientLocalPort
|
||||
clusterTunnel.Protocol = Protocol
|
||||
clusterTunnel.BytesPerSec = float64(BytesPerSec)
|
||||
poolTunnel.Set(clusterTunnel)
|
||||
cmd := utils.MsgServerOpenPort{
|
||||
Msg: utils.Msg{MsgType: utils.MSG_SERVER_OPEN_PORT},
|
||||
TunnelID: TunnelID,
|
||||
BindIP: ServerBindIP,
|
||||
BindPort: ServerListenPort,
|
||||
Protocol: Protocol,
|
||||
}
|
||||
c, err := poolServerControlChannel.Get(ServerToken)
|
||||
if err != nil {
|
||||
jsonError(w, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
err = c.ServerMessageChannel.Write(cmd)
|
||||
if err != nil {
|
||||
jsonError(w, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
var resp utils.MsgResponse
|
||||
err = c.ServerMessageChannel.ReadTimeout(&resp, 5000)
|
||||
if err != nil {
|
||||
jsonError(w, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
if !resp.IsSuccess() {
|
||||
jsonError(w, resp.Message, nil)
|
||||
return
|
||||
}
|
||||
trafficCounter.InitTunnel(TunnelID)
|
||||
serverTunnelPool.AddTunnel(ServerToken, TunnelID)
|
||||
err = dataRecovery.Store(clusterTunnel)
|
||||
if err != nil {
|
||||
jsonError(w, resp.Message, nil)
|
||||
return
|
||||
}
|
||||
jsonSuccess(w, "success", nil)
|
||||
//log.Infof("open port cmd:%s", cmd)
|
||||
|
||||
}
|
||||
func jsonSuccess(w http.ResponseWriter, message, data interface{}) {
|
||||
jsonEcho(w, 1, message, data)
|
||||
}
|
||||
func jsonError(w http.ResponseWriter, message, data interface{}) {
|
||||
jsonEcho(w, 0, message, data)
|
||||
}
|
||||
func jsonEcho(w http.ResponseWriter, code int, message, data interface{}) {
|
||||
type JSONObj struct {
|
||||
Code int `json:"code"`
|
||||
Message interface{} `json:"message"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
jsonObj := JSONObj{
|
||||
Code: code,
|
||||
Message: message,
|
||||
Data: data,
|
||||
}
|
||||
d, err := json.Marshal(jsonObj)
|
||||
if err != nil {
|
||||
jsonObj.Code = 0
|
||||
jsonObj.Message = err.Error()
|
||||
d, _ = json.Marshal(jsonObj)
|
||||
fmt.Fprint(w, string(d))
|
||||
return
|
||||
}
|
||||
fmt.Fprint(w, string(d))
|
||||
}
|
||||
func initHttp(fn func(err error)) {
|
||||
router := httprouter.New()
|
||||
router.GET("/port/open/:TunnelID/:ServerToken/:ServerBindIP/:ServerListenPort/:ClientToken/:ClientLocalHost/:ClientLocalPort/:Protocol/:BytesPerSec", timeoutFactory(apiPortOpen))
|
||||
router.GET("/port/close/:TunnelID", timeoutFactory(apiPortClose))
|
||||
router.GET("/port/status/:TunnelID", timeoutFactory(apiPortStatus))
|
||||
router.GET("/server/offline/:ServerToken", timeoutFactory(apiServerOffline))
|
||||
router.GET("/server/status/:ServerToken", timeoutFactory(apiServerStatus))
|
||||
router.GET("/client/offline/:ClientToken", timeoutFactory(apiClientOffline))
|
||||
router.GET("/client/status/:ClientToken", timeoutFactory(apiClientStatus))
|
||||
router.GET("/traffic/count", timeoutFactory(apiTrafficCount))
|
||||
router.GET("/traffic/count/:TunnelID", timeoutFactory(apiTrafficCountTunnel))
|
||||
pool := x509.NewCertPool()
|
||||
pool.AppendCertsFromPEM(utils.GetRootCert())
|
||||
|
||||
for _, ip := range cfg.GetStringSlice("port.ip-api") {
|
||||
go func(ip string) {
|
||||
s := &http.Server{
|
||||
Addr: fmt.Sprintf("%s:%d", ip, cfg.GetInt("port.api")),
|
||||
Handler: router,
|
||||
TLSConfig: &tls.Config{
|
||||
ClientCAs: pool,
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
ServerName: "anytunnel-client",
|
||||
},
|
||||
ReadTimeout: time.Millisecond * 3000,
|
||||
}
|
||||
log.Infof("listening on [%s] for http api", (*s).Addr)
|
||||
if err := ListenAndServeTLS(s, utils.GetServerCert(), utils.GetServerKey()); err != nil {
|
||||
log.Errorf("ListenAndServeTLS err:%s", err)
|
||||
}
|
||||
}(ip)
|
||||
}
|
||||
}
|
||||
func timeoutFactory(fn func(w http.ResponseWriter, r *http.Request, ps httprouter.Params)) (handle func(w http.ResponseWriter, r *http.Request, ps httprouter.Params)) {
|
||||
|
||||
handle = func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
chn := make(chan bool, 1)
|
||||
go func() {
|
||||
fn(w, r, ps)
|
||||
chn <- true
|
||||
}()
|
||||
select {
|
||||
case <-chn:
|
||||
case <-time.After(apiTimeout):
|
||||
fmt.Fprint(w, "timeout")
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
func access(ctx *fasthttp.RequestCtx) {
|
||||
post := ""
|
||||
if cfg.GetBool("log.post") {
|
||||
post = string(ctx.Request.Body())
|
||||
}
|
||||
fields := logger.Fields{
|
||||
"code": strconv.Itoa(ctx.Response.StatusCode()),
|
||||
"uri": string(ctx.RequestURI()),
|
||||
"remoteAddr": strings.Split(ctx.RemoteAddr().String(), ":")[0],
|
||||
"method": string(ctx.Method()),
|
||||
"host": string(ctx.Request.Host()),
|
||||
"referer": string(ctx.Request.Header.Referer()),
|
||||
"userAgent": string(ctx.Request.Header.UserAgent()),
|
||||
"response": string(ctx.Response.Body()),
|
||||
"post": post,
|
||||
}
|
||||
accessLog.With(fields).Info("")
|
||||
}
|
||||
func ListenAndServeTLS(srv *http.Server, certPEMBlock, keyPEMBlock []byte) error {
|
||||
addr := srv.Addr
|
||||
if addr == "" {
|
||||
addr = ":https"
|
||||
}
|
||||
config := &tls.Config{}
|
||||
if srv.TLSConfig != nil {
|
||||
*config = *srv.TLSConfig
|
||||
}
|
||||
if config.NextProtos == nil {
|
||||
config.NextProtos = []string{"http/1.1"}
|
||||
}
|
||||
|
||||
var err error
|
||||
config.Certificates = make([]tls.Certificate, 1)
|
||||
config.Certificates[0], err = tls.X509KeyPair(certPEMBlock, keyPEMBlock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ln, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tlsListener := tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, config)
|
||||
return srv.Serve(tlsListener)
|
||||
}
|
||||
|
||||
// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
|
||||
// connections. It's used by ListenAndServe and ListenAndServeTLS so
|
||||
// dead TCP connections (e.g. closing laptop mid-download) eventually
|
||||
// go away.
|
||||
type tcpKeepAliveListener struct {
|
||||
*net.TCPListener
|
||||
}
|
||||
|
||||
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
|
||||
tc, err := ln.AcceptTCP()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tc.SetReadDeadline(time.Now().Add(time.Millisecond * 300))
|
||||
return tc, nil
|
||||
}
|
||||
Reference in New Issue
Block a user