wgcl/api/vpn/handler.go
2025-11-20 11:47:00 +08:00

142 lines
2.7 KiB
Go

package vpn
import (
"context"
"io"
"net/netip"
"time"
"git.jasinco.work/wgcl/internal/logger"
"git.jasinco.work/wgcl/internal/wg"
protovpn "git.jasinco.work/wgcl/proto/out"
"github.com/gin-gonic/gin"
"google.golang.org/protobuf/encoding/protojson"
)
var wgctrl *wg.WG
var sync_cancel context.CancelFunc
func SyncWGStat(ctx context.Context) {
for {
select {
case <-ctx.Done():
return
default:
wgctrl.SyncStatus()
logger.Logger.Info("sync wg status")
time.Sleep(5 * time.Second)
}
}
}
func StartWG() {
var err error
baseip4 := netip.AddrFrom4([4]byte{172, 16, 0, 1})
pool := wg.IPPool_Init(baseip4, 26)
wgctrl, err = wg.WG_init("wg0", wg.NewKey(), 51823, pool)
if err != nil {
logger.Logger.Warn(err.Error())
logger.Logger.Fatal("Failed init wgctrl")
}
ctx, cancel := context.WithCancel(context.Background())
sync_cancel = cancel
go SyncWGStat(ctx)
}
func StopWG() {
logger.Logger.Info("Stopping WG")
sync_cancel()
wgctrl.Deinit()
}
func GETPeers(c *gin.Context) {
resp := wgctrl.GetPeersJson()
resp_json, err := protojson.Marshal(resp)
if err != nil {
c.Status(500)
return
}
c.Data(200, "application/json", resp_json)
}
func NewPeer(c *gin.Context) {
req := &protovpn.PeerReq{}
req_json, err := io.ReadAll(c.Request.Body)
if err != nil {
c.Status(400)
return
}
if protojson.Unmarshal(req_json, req) != nil {
c.Status(400)
return
}
wgctrl.WriteTxStart()
defer wgctrl.WriteTxEnd()
var ip4 *netip.Addr
if req.HasIp4() {
_ip4, err := netip.ParseAddr(req.GetIp4())
ip4 = &_ip4
if err != nil {
c.Status(400)
return
}
} else {
_ip4, err := wgctrl.IP4Pool.Next()
if err != nil {
logger.Logger.Warn("ip pool exhausted")
c.Status(500)
return
}
ip4 = &_ip4
}
peer := wg.WGPeer_init(req.GetName(), wg.NewKey(), *ip4)
wgctrl.AddPeer(peer)
wgctrl.IP4Pool.Lease(*ip4)
wgctrl.Apply()
c.Status(200)
}
func SearchPeer(c *gin.Context) {
if pubkey := c.Query("pubkey"); len(pubkey) > 0 {
p, err := wgctrl.SearchPeerPubkey(pubkey)
if p == nil {
if err != nil {
logger.Logger.Warn(err.Error())
}
c.Status(400)
return
}
b, err := protojson.Marshal(p.ToPeerStatus())
if err != nil {
logger.Logger.Warn(err.Error())
}
c.Data(200, "application/json", b)
} else {
c.Status(400)
}
}
func DeletePeer(c *gin.Context) {
if pubkey := c.Query("pubkey"); len(pubkey) > 0 {
p, err := wgctrl.SearchPeerPubkey(pubkey)
if p == nil {
if err != nil {
logger.Logger.Warn(err.Error())
}
c.Status(400)
return
}
wgctrl.WriteTxStart()
defer wgctrl.WriteTxEnd()
p.Disable()
if err = wgctrl.Apply(); err != nil {
logger.Logger.Warn("Can't apply disable peer")
}
wgctrl.RemovePeer(p)
c.Status(200)
} else {
c.Status(400)
}
}