239 lines
7.4 KiB
Go
239 lines
7.4 KiB
Go
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 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)) {
|
|
go func() {
|
|
atClient := NewClient()
|
|
atServer := NewServer()
|
|
tunnel := NewTunnel()
|
|
cluster := NewCluster()
|
|
traffic := NewTraffic()
|
|
user := NewUser()
|
|
online := NewOnline()
|
|
clusterApi := NewClusterAPI()
|
|
//intra api router
|
|
routerIntra := httprouter.New()
|
|
//client
|
|
routerIntra.POST("/client/add", timeoutFactory(atClient.Add))
|
|
routerIntra.POST("/client/update", timeoutFactory(atClient.Update))
|
|
routerIntra.GET("/client/delete", timeoutFactory(atClient.Delete))
|
|
routerIntra.GET("/client/list", timeoutFactory(atClient.List))
|
|
routerIntra.GET("/client/getClientById", timeoutFactory(atClient.GetClientByClientId))
|
|
//server
|
|
routerIntra.POST("/server/add", timeoutFactory(atServer.Add))
|
|
routerIntra.POST("/server/update", timeoutFactory(atServer.Update))
|
|
routerIntra.GET("/server/delete", timeoutFactory(atServer.Delete))
|
|
routerIntra.GET("/server/list", timeoutFactory(atServer.List))
|
|
routerIntra.GET("/server/getServerById", timeoutFactory(atServer.GetServerByServerId))
|
|
//tunnel
|
|
routerIntra.POST("/tunnel/add", timeoutFactory(tunnel.Add))
|
|
routerIntra.POST("/tunnel/update", timeoutFactory(tunnel.Update))
|
|
routerIntra.GET("/tunnel/delete", timeoutFactory(tunnel.Delete))
|
|
routerIntra.GET("/tunnel/list", timeoutFactory(tunnel.List))
|
|
routerIntra.GET("/tunnel/getTunnelByTunnelId", timeoutFactory(tunnel.GetTunnelByTunnelId))
|
|
routerIntra.GET("/tunnel/getTunnelsByClientId", timeoutFactory(tunnel.GetTunnelsByClientId))
|
|
routerIntra.GET("/tunnel/getTunnelsByServerId", timeoutFactory(tunnel.GetTunnelsByServerId))
|
|
routerIntra.GET("/tunnel/open", timeoutFactory(tunnel.TunnelOpen))
|
|
routerIntra.GET("/tunnel/close", timeoutFactory(tunnel.TunnelClose))
|
|
//user
|
|
routerIntra.GET("/user/getUserByName", timeoutFactory(user.GetUserByName))
|
|
routerIntra.GET("/user/getUserByEmail", timeoutFactory(user.GetUserByEmail))
|
|
routerIntra.GET("/user/getUserById", timeoutFactory(user.GetUserByUserId))
|
|
routerIntra.POST("/user/create", timeoutFactory(user.Create))
|
|
routerIntra.POST("/user/update", timeoutFactory(user.Update))
|
|
routerIntra.GET("/user/getRolesByUserId", timeoutFactory(user.GetRolesByUserId))
|
|
routerIntra.GET("/user/cluster", timeoutFactory(user.Cluster))
|
|
//online
|
|
routerIntra.GET("/online/getServerByClusterId", timeoutFactory(online.GetServerByClusterId))
|
|
routerIntra.GET("/online/getClientByClusterId", timeoutFactory(online.GetClientByClusterId))
|
|
|
|
//###########cluster api############
|
|
//cs登录认证
|
|
routerIntra.GET("/cs/auth", timeoutFactory(clusterApi.Auth))
|
|
//cs上线下线上报
|
|
routerIntra.GET("/cs/status", timeoutFactory(clusterApi.Status))
|
|
//流量上报
|
|
routerIntra.POST("/user/traffic", timeoutFactory(traffic.Traffic))
|
|
//cluster机器上报
|
|
routerIntra.POST("/cluster/report", timeoutFactory(cluster.Report))
|
|
|
|
//#######外网api######
|
|
//extra api router
|
|
routerExtra := httprouter.New()
|
|
routerExtra.GET("/cluster/get", timeoutFactory(clusterApi.Cluster))
|
|
|
|
//intra api
|
|
for _, ip := range cfg.GetStringSlice("port.ip-intra") {
|
|
go func(ip string) {
|
|
pool := x509.NewCertPool()
|
|
pool.AppendCertsFromPEM(utils.GetRootCert())
|
|
s := &http.Server{
|
|
Addr: fmt.Sprintf("%s:%d", ip, cfg.GetInt("port.intra")),
|
|
Handler: routerIntra,
|
|
TLSConfig: &tls.Config{
|
|
ClientCAs: pool,
|
|
ClientAuth: tls.RequireAndVerifyClientCert,
|
|
ServerName: "anytunnel-client",
|
|
},
|
|
}
|
|
log.Infof("listening on [%s] for http intra api", (*s).Addr)
|
|
if err := ListenAndServeTLS(s, utils.GetServerCert(), utils.GetServerKey()); err != nil {
|
|
log.Errorf("ListenAndServeTLS err:%s", err)
|
|
}
|
|
}(ip)
|
|
}
|
|
//extra api
|
|
for _, ip := range cfg.GetStringSlice("port.ip-extra") {
|
|
go func(ip string) {
|
|
pool := x509.NewCertPool()
|
|
pool.AppendCertsFromPEM(utils.GetRootCert())
|
|
s := &http.Server{
|
|
Addr: fmt.Sprintf("%s:%d", ip, cfg.GetInt("port.extra")),
|
|
Handler: routerExtra,
|
|
TLSConfig: &tls.Config{
|
|
ClientCAs: pool,
|
|
ClientAuth: tls.RequireAndVerifyClientCert,
|
|
ServerName: "anytunnel-client",
|
|
},
|
|
ReadTimeout: time.Millisecond * 3000,
|
|
}
|
|
log.Infof("listening on [%s] for http extra 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
|
|
}
|