代码拉取完成,页面将自动刷新
package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/http/httputil"
"net/url"
"os"
"os/exec"
"strconv"
"strings"
"sync"
"time"
"gitee.com/aurawing/surguard-go/device"
"github.com/labstack/echo"
"github.com/labstack/echo/middleware"
"github.com/shirou/gopsutil/v3/net"
"golang.org/x/net/http2"
"golang.org/x/net/http2/h2c"
)
type StatResp struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data map[string]interface{} `json:"data"`
}
var statSrv http.Server
var statWg sync.WaitGroup
var statInterfaceName string
var statGroupName string
var statDev *device.Device
func startStatServer(interfaceName, portStr string, logger *device.Logger, dev *device.Device) error {
statWg.Add(1)
statDev = dev
groupNameStr := os.Getenv(device.ENV_SG_GROUP_NAME)
if groupNameStr == "" {
statGroupName = device.DEFAULT_GROUP_NAME
} else {
statGroupName = groupNameStr
}
if strings.TrimSpace(interfaceName) == "" {
logger.Errorf("interface name is empty")
return errors.New("interface name is empty")
}
statInterfaceName = interfaceName
port := int64(device.DEFAULT_LISTEN_PORT)
if strings.TrimSpace(portStr) != "" {
var err error
port, err = strconv.ParseInt(strings.TrimSpace(portStr), 10, 64)
if err != nil {
logger.Errorf("parse stat server port failed %v", err)
return err
}
}
server := echo.New()
server.Use(middleware.Logger())
server.Use(middleware.Recover())
server.Use(middleware.GzipWithConfig(middleware.GzipConfig{
Level: 5,
}))
server.GET("/surguard/netstat", sgNetStat)
server.POST("/surguard/bypass", bypass)
server.POST("/surguard/disableBypass", disableBypass)
apiStatPort := port + 1
apiStatPortStr := os.Getenv("SG_STAT_PORT")
if apiStatPortStr != "" {
var err error
apiStatPort, err = strconv.ParseInt(strings.TrimSpace(apiStatPortStr), 10, 64)
if err != nil {
logger.Errorf("parse API stat server port failed %v", err)
return err
}
}
proxy := httputil.NewSingleHostReverseProxy(&url.URL{
Scheme: "http",
Host: fmt.Sprintf("localhost:%d", apiStatPort),
})
server.Any("/surwall/*", echo.WrapHandler(proxy))
h2s := &http2.Server{}
statSrv = http.Server{
Addr: fmt.Sprintf(":%d", port),
Handler: h2c.NewHandler(server, h2s),
//ReadTimeout: 30 * time.Second, // customize http.Server timeouts
}
go func() {
if err := statSrv.ListenAndServe(); err != http.ErrServerClosed {
logger.Errorf("stat server error: %v", err)
}
statWg.Done()
}()
return nil
}
func getNetStats(interfaceName string) (*net.IOCountersStat, error) {
netStats, err := net.IOCounters(true)
if err != nil {
return nil, err
}
for _, stats := range netStats {
if stats.Name == interfaceName {
return &stats, nil
}
}
return nil, fmt.Errorf("interface '%s' not found", interfaceName)
}
func sgNetStat(c echo.Context) error {
resp := new(StatResp)
stats, err := getNetStats(statInterfaceName)
if err != nil {
resp.Code = -1
resp.Msg = err.Error()
resp.Data = map[string]interface{}{}
} else {
resp.Code = 0
resp.Msg = "ok"
resp.Data = map[string]interface{}{
"InterfaceName": stats.Name,
"BytesSent": stats.BytesSent,
"BytesReceived": stats.BytesRecv,
"PacketsSent": stats.PacketsSent,
"PacketsReceived": stats.PacketsRecv,
"ErrorsSent": stats.Errout,
"ErrorsReceived": stats.Errin,
"DropsSent": stats.Dropout,
"DropReceived": stats.Dropin,
}
}
b, err := json.Marshal(resp)
if err != nil {
resp.Code = -2
resp.Msg = err.Error()
resp.Data = map[string]interface{}{}
}
return c.JSONBlob(http.StatusOK, b)
}
func bypass(c echo.Context) error {
resp := new(StatResp)
if !device.IfBindInterface() {
err := runCmd("ip", "route", "flush", "table", statGroupName)
if err != nil {
resp.Code = -3
resp.Msg = err.Error()
resp.Data = map[string]interface{}{}
}
} else {
statDev.IterPeerEndpoint(func(s string) {
runCmd("route", "delete", s)
})
}
b, err := json.Marshal(resp)
if err != nil {
resp.Code = -2
resp.Msg = err.Error()
resp.Data = map[string]interface{}{}
}
return c.JSONBlob(http.StatusOK, b)
}
func disableBypass(c echo.Context) error {
resp := new(StatResp)
if !device.IfBindInterface() {
err := runCmd("ip", "route", "add", "default", "dev", statInterfaceName, "table", statGroupName)
if err != nil {
resp.Code = -4
resp.Msg = err.Error()
resp.Data = map[string]interface{}{}
}
} else {
statDev.IterPeerEndpoint(func(s string) {
runCmd("route", "add", s, "mask", "255.255.255.255", "0.0.0.0", "IF", strconv.Itoa(device.GetDeviceIndex()))
})
}
b, err := json.Marshal(resp)
if err != nil {
resp.Code = -2
resp.Msg = err.Error()
resp.Data = map[string]interface{}{}
}
return c.JSONBlob(http.StatusOK, b)
}
func stopStatServer(logger *device.Logger) {
timeoutCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
defer statWg.Wait()
// 关闭 HTTP 服务器
if err := statSrv.Shutdown(timeoutCtx); err != nil {
logger.Errorf("Stat server shutdown error: %v", err)
}
}
func runCmd(args ...string) error {
cmd := exec.Command(args[0], args[1:]...)
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
cmd.Stdin = os.Stdin
err := cmd.Run()
return err
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。