init
This commit is contained in:
commit
203d986e08
17 changed files with 3312 additions and 0 deletions
52
api/auth/handlr.go
Normal file
52
api/auth/handlr.go
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"git.jasinco.work/wgcl/internal/federate"
|
||||
"git.jasinco.work/wgcl/internal/logger"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var Driver federate.AUTH = nil
|
||||
|
||||
type login struct {
|
||||
Username string `form:"username" json:"username" binding:"required"`
|
||||
Password string `form:"password" json:"password" binding:"required"`
|
||||
}
|
||||
|
||||
var ErrBadRequest = errors.New("Failed to parse request")
|
||||
var ErrNoDriver = errors.New("No Auth Driver")
|
||||
|
||||
func UserLogin(c *gin.Context) (*User, error) {
|
||||
var cred login
|
||||
if c.ShouldBind(&cred) != nil {
|
||||
return nil, ErrBadRequest
|
||||
}
|
||||
if Driver == nil {
|
||||
return nil, ErrNoDriver
|
||||
}
|
||||
|
||||
userdn, err := Driver.UserAuthenticate(cred.Username, cred.Password)
|
||||
if err == nil {
|
||||
var power uint16 = 0
|
||||
|
||||
if stat, err := Driver.UserAuthorizeWG(userdn); err == nil {
|
||||
if stat {
|
||||
power |= AuthorizeWG
|
||||
}
|
||||
} else {
|
||||
logger.Logger.Error(err.Error())
|
||||
}
|
||||
logger.Logger.Info("user authorize", zap.String("user", userdn), zap.Uint16("power", power))
|
||||
|
||||
u := &User{
|
||||
UserName: userdn,
|
||||
Authorized: power,
|
||||
}
|
||||
u.setupClaim()
|
||||
return u, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
88
api/auth/jwt.go
Normal file
88
api/auth/jwt.go
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.jasinco.work/wgcl/internal/logger"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var AuthorizeWG uint16 = 0x1
|
||||
var AuthorizeRevProxy uint16 = 0x2
|
||||
|
||||
var JWTKey = []byte("fecv")
|
||||
|
||||
type User struct {
|
||||
UserName string `json:"dn" binding:"required"`
|
||||
Authorized uint16 `json:"pwr" binding:"required"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
func (u *User) setupClaim() {
|
||||
u.ExpiresAt = jwt.NewNumericDate(time.Now().Add(24 * time.Hour))
|
||||
u.Issuer = "tethsues"
|
||||
u.Subject = "smb"
|
||||
u.ID = "1"
|
||||
u.Audience = nil
|
||||
}
|
||||
func AuthMiddleware() gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
|
||||
logger.Logger.Info("auth middleware first")
|
||||
var user *User = nil
|
||||
auth_head, auth_head_exist := ctx.Request.Header["Authorization"]
|
||||
// cookie,cookie_err := ctx.Request.Cookie("token")
|
||||
if auth_head_exist && strings.HasPrefix(auth_head[0], "Bearer ") {
|
||||
_token, err := jwt.ParseWithClaims(strings.TrimPrefix(auth_head[0], "Bearer "), &User{}, func(t *jwt.Token) (any, error) {
|
||||
return JWTKey, nil
|
||||
})
|
||||
if err != nil {
|
||||
ctx.Status(400)
|
||||
ctx.Abort()
|
||||
return
|
||||
}
|
||||
if _user, ok := _token.Claims.(*User); ok {
|
||||
user = _user
|
||||
}
|
||||
}
|
||||
if user != nil {
|
||||
logger.Logger.Info("auth middleware", zap.String("dn", user.UserName))
|
||||
ctx.Set("token", user)
|
||||
} else {
|
||||
ctx.Set("token", nil)
|
||||
ctx.Status(400)
|
||||
ctx.Abort()
|
||||
return
|
||||
}
|
||||
ctx.Next()
|
||||
|
||||
}
|
||||
}
|
||||
func IssueJWT(c *gin.Context) {
|
||||
cred, err := UserLogin(c)
|
||||
if errors.Is(err, ErrBadRequest) {
|
||||
c.Status(400)
|
||||
return
|
||||
} else if err != nil {
|
||||
logger.Logger.Warn(err.Error())
|
||||
c.Status(500)
|
||||
return
|
||||
}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, *cred)
|
||||
ss, err := token.SignedString(JWTKey)
|
||||
if err != nil {
|
||||
logger.Logger.Warn(err.Error())
|
||||
c.Status(500)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, gin.H{
|
||||
"token": ss,
|
||||
})
|
||||
|
||||
// c.SetCookie("credential", )
|
||||
}
|
||||
1
api/vpn/controller.go
Normal file
1
api/vpn/controller.go
Normal file
|
|
@ -0,0 +1 @@
|
|||
package vpn
|
||||
142
api/vpn/handler.go
Normal file
142
api/vpn/handler.go
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
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)
|
||||
}
|
||||
}
|
||||
52
cmd/main.go
Normal file
52
cmd/main.go
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.jasinco.work/wgcl/api/auth"
|
||||
"git.jasinco.work/wgcl/api/vpn"
|
||||
"git.jasinco.work/wgcl/internal/federate"
|
||||
"git.jasinco.work/wgcl/internal/logger"
|
||||
"github.com/fvbock/endless"
|
||||
|
||||
//"github.com/gin-contrib/pprof"
|
||||
ginzap "github.com/gin-contrib/zap"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
r := gin.Default()
|
||||
r.Use(ginzap.Ginzap(logger.Logger, time.RFC3339, true))
|
||||
// r.Use(ginzap.RecoveryWithZap(logger.Logger, true))
|
||||
defer logger.Flush()
|
||||
|
||||
l := federate.FedLDAP{
|
||||
Base_dn: "dc=example,dc=com",
|
||||
User_filter: "(&(objectClass=person)(uid=%s))",
|
||||
Group_wg_filter: "(&(dn=%s)(memberof=cn=wgopr,ou=groups,dc=example,dc=com))",
|
||||
}
|
||||
l.Init("ldap://localhost:3890")
|
||||
|
||||
if err := l.AuthBind("uid=admin,ou=people,dc=example,dc=com", "recrecrec"); err != nil {
|
||||
logger.Logger.Fatal(err.Error())
|
||||
}
|
||||
|
||||
auth.Driver = &l
|
||||
|
||||
vpn.StartWG()
|
||||
defer vpn.StopWG()
|
||||
// pprof.Register(r)
|
||||
r.POST("/api/auth", auth.IssueJWT)
|
||||
|
||||
{
|
||||
g := r.Group("/api", auth.AuthMiddleware())
|
||||
v := g.Group("/vpn")
|
||||
v.GET("/peers", vpn.GETPeers)
|
||||
v.POST("/peer", vpn.NewPeer)
|
||||
v.GET("/peer", vpn.SearchPeer)
|
||||
v.DELETE("/peer", vpn.DeletePeer)
|
||||
}
|
||||
|
||||
endless.ListenAndServe("0.0.0.0:8080", r)
|
||||
}
|
||||
55
go.mod
Normal file
55
go.mod
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
module git.jasinco.work/wgcl
|
||||
|
||||
go 1.25.4
|
||||
|
||||
require (
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||
github.com/appleboy/gin-jwt/v3 v3.2.0 // indirect
|
||||
github.com/bytedance/gopkg v0.1.3 // indirect
|
||||
github.com/bytedance/sonic v1.14.1 // indirect
|
||||
github.com/bytedance/sonic/loader v0.3.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
|
||||
github.com/gin-contrib/pprof v1.5.3 // indirect
|
||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||
github.com/gin-contrib/zap v1.1.5 // indirect
|
||||
github.com/gin-gonic/gin v1.11.0 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
|
||||
github.com/go-ldap/ldap/v3 v3.4.12 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.28.0 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/goccy/go-yaml v1.18.0 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/hashicorp/go-set/v3 v3.0.1 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/quic-go/quic-go v0.55.0 // indirect
|
||||
github.com/redis/rueidis v1.0.66 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.3.0 // indirect
|
||||
github.com/vishvananda/netlink v1.3.1 // indirect
|
||||
github.com/vishvananda/netns v0.0.5 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
go.uber.org/mock v0.6.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/arch v0.22.0 // indirect
|
||||
golang.org/x/crypto v0.43.0 // indirect
|
||||
golang.org/x/mod v0.29.0 // indirect
|
||||
golang.org/x/net v0.46.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
golang.org/x/tools v0.38.0 // indirect
|
||||
google.golang.org/protobuf v1.36.10 // indirect
|
||||
)
|
||||
147
go.sum
Normal file
147
go.sum
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||
github.com/appleboy/gin-jwt/v3 v3.2.0 h1:Ifa8Zsm2cZ93u/HIAhcTmftTK8rIaaoAoH77lcajWD0=
|
||||
github.com/appleboy/gin-jwt/v3 v3.2.0/go.mod h1:ANNEPdDkdOp6jXAbicMFX7N4mIIx70m9A3asDmXdbYo=
|
||||
github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=
|
||||
github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
|
||||
github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ=
|
||||
github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA=
|
||||
github.com/bytedance/sonic v1.14.1 h1:FBMC0zVz5XUmE4z9wF4Jey0An5FueFvOsTKKKtwIl7w=
|
||||
github.com/bytedance/sonic v1.14.1/go.mod h1:gi6uhQLMbTdeP0muCnrjHLeCUPyb70ujhnNlhOylAFc=
|
||||
github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA=
|
||||
github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
||||
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 h1:6VSn3hB5U5GeA6kQw4TwWIWbOhtvR2hmbBJnTOtqTWc=
|
||||
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6/go.mod h1:YxOVT5+yHzKvwhsiSIWmbAYM3Dr9AEEbER2dVayfBkg=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/gin-contrib/pprof v1.5.3 h1:Bj5SxJ3kQDVez/s/+f9+meedJIqLS+xlkIVDe/lcvgM=
|
||||
github.com/gin-contrib/pprof v1.5.3/go.mod h1:0+LQSZ4SLO0B6+2n6JBzaEygpTBxe/nI+YEYpfQQ6xY=
|
||||
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
||||
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
||||
github.com/gin-contrib/zap v1.1.5 h1:qKwhWb4DQgPriCl1AHLLob6hav/KUIctKXIjTmWIN3I=
|
||||
github.com/gin-contrib/zap v1.1.5/go.mod h1:lAchUtGz9M2K6xDr1rwtczyDrThmSx6c9F384T45iOE=
|
||||
github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
|
||||
github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
github.com/go-ldap/ldap/v3 v3.4.12 h1:1b81mv7MagXZ7+1r7cLTWmyuTqVqdwbtJSjC0DAp9s4=
|
||||
github.com/go-ldap/ldap/v3 v3.4.12/go.mod h1:+SPAGcTtOfmGsCb3h1RFiq4xpp4N636G75OEace8lNo=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
|
||||
github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
||||
github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688=
|
||||
github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
|
||||
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hashicorp/go-set/v3 v3.0.1 h1:ZwO15ZYmIrFYL9zSm2wBuwcRiHxVdp46m/XA/MUlM6I=
|
||||
github.com/hashicorp/go-set/v3 v3.0.1/go.mod h1:0oPQqhtitglZeT2ZiWnRIfUG6gJAHnn7LzrS7SbgNY4=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg=
|
||||
github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
|
||||
github.com/quic-go/quic-go v0.55.0 h1:zccPQIqYCXDt5NmcEabyYvOnomjs8Tlwl7tISjJh9Mk=
|
||||
github.com/quic-go/quic-go v0.55.0/go.mod h1:DR51ilwU1uE164KuWXhinFcKWGlEjzys2l8zUl5Ss1U=
|
||||
github.com/redis/rueidis v1.0.66 h1:7rvyrl0vL/cAEkE97+L5v3MJ3Vg8IKz+KIxUTfT+yJk=
|
||||
github.com/redis/rueidis v1.0.66/go.mod h1:Lkhr2QTgcoYBhxARU7kJRO8SyVlgUuEkcJO1Y8MCluA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA=
|
||||
github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
|
||||
github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0=
|
||||
github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4=
|
||||
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
|
||||
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
|
||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
|
||||
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c=
|
||||
golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
|
||||
golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI=
|
||||
golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
|
||||
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
|
||||
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
|
||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
|
||||
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
|
||||
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
||||
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
||||
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
13
internal/federate/if.go
Normal file
13
internal/federate/if.go
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
package federate
|
||||
|
||||
import "errors"
|
||||
|
||||
type AUTH interface {
|
||||
IsUser(name string) (string, error)
|
||||
UserAuthorizeWG(name string) (bool, error)
|
||||
// return IsUser check
|
||||
UserAuthenticate(name string, password string) (string, error)
|
||||
}
|
||||
|
||||
var ErrAUTHNoUser = errors.New("No user for auth")
|
||||
var ErrAUTHAuthenticateInvalidPassword = errors.New("Incorrect Password")
|
||||
80
internal/federate/ldap.go
Normal file
80
internal/federate/ldap.go
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
package federate
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.jasinco.work/wgcl/internal/logger"
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
)
|
||||
|
||||
type FedLDAP struct {
|
||||
Base_dn string
|
||||
User_filter string
|
||||
endpoint *ldap.Conn
|
||||
Group_wg_filter string
|
||||
auth_endpoint *ldap.Conn
|
||||
}
|
||||
|
||||
func (l *FedLDAP) Init(endpoint string) {
|
||||
var err error
|
||||
|
||||
l.endpoint, err = ldap.DialURL(endpoint)
|
||||
if err != nil {
|
||||
logger.Logger.Fatal(err.Error())
|
||||
}
|
||||
l.auth_endpoint, err = ldap.DialURL(endpoint)
|
||||
if err != nil {
|
||||
logger.Logger.Fatal(err.Error())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (l *FedLDAP) AuthBind(user string, pass string) error {
|
||||
return l.endpoint.Bind(user, pass)
|
||||
}
|
||||
|
||||
func (l *FedLDAP) IsUser(name string) (string, error) {
|
||||
req := ldap.NewSearchRequest(l.Base_dn, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,
|
||||
1, 0, false,
|
||||
fmt.Sprintf(l.User_filter, ldap.EscapeFilter(name)), []string{"dn"}, nil)
|
||||
resp, err := l.endpoint.Search(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(resp.Entries) != 1 {
|
||||
return "", ErrAUTHNoUser
|
||||
}
|
||||
return resp.Entries[0].DN, nil
|
||||
}
|
||||
func (l *FedLDAP) UserAuthorizeWG(user_dn string) (bool, error) {
|
||||
req := ldap.NewSearchRequest(l.Base_dn, ldap.ScopeBaseObject, ldap.NeverDerefAliases,
|
||||
1, 0, false,
|
||||
fmt.Sprintf(l.Group_wg_filter, user_dn), []string{"dn"}, nil)
|
||||
|
||||
resp, err := l.endpoint.Search(req)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return len(resp.Entries) > 0, nil
|
||||
}
|
||||
func (l *FedLDAP) UserAuthenticate(name string, password string) (string, error) {
|
||||
// find user
|
||||
userdn, err := l.IsUser(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
req := ldap.NewSimpleBindRequest(userdn, ldap.EscapeFilter(password), nil)
|
||||
_, err = l.auth_endpoint.SimpleBind(req)
|
||||
var ldaperr *ldap.Error
|
||||
if errors.As(err, &ldaperr) && ldaperr.ResultCode == ldap.LDAPResultInvalidCredentials {
|
||||
return "", ErrAUTHAuthenticateInvalidPassword
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return userdn, nil
|
||||
}
|
||||
23
internal/logger/lib.go
Normal file
23
internal/logger/lib.go
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
package logger
|
||||
|
||||
import "go.uber.org/zap"
|
||||
|
||||
var Logger *zap.Logger
|
||||
|
||||
func init() {
|
||||
Logger, _ = zap.NewProduction()
|
||||
// sugar := logger.Sugar()
|
||||
// sugar.Infow("failed to fetch URL",
|
||||
// // Structured context as loosely typed key-value pairs.
|
||||
// "url", url,
|
||||
// "attempt", 3,
|
||||
// "backoff", time.Second,
|
||||
// )
|
||||
// sugar.Infof("Failed to fetch URL: %s", url)
|
||||
|
||||
// Create a Gin router with default middleware (logger and recovery)
|
||||
}
|
||||
|
||||
func Flush() {
|
||||
Logger.Sync() // flushes buffer, if any
|
||||
}
|
||||
67
internal/wg/ip_pool.go
Normal file
67
internal/wg/ip_pool.go
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
package wg
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"net/netip"
|
||||
|
||||
"github.com/hashicorp/go-set/v3"
|
||||
)
|
||||
|
||||
type IPPool struct {
|
||||
scope netip.Prefix
|
||||
leasure *set.Set[netip.Addr]
|
||||
cache netip.Addr
|
||||
}
|
||||
|
||||
var ErrIPPoolExhausted = errors.New("IP Pool Exhausted")
|
||||
|
||||
// @param base_ip4: is used as the gateway address
|
||||
func IPPool_Init(base_ip4 netip.Addr, cidr uint8) *IPPool {
|
||||
scope := netip.PrefixFrom(base_ip4, int(cidr))
|
||||
pool := &IPPool{leasure: set.New[netip.Addr](1 << (32 - cidr)), scope: scope}
|
||||
pool.cache = pool.scope.Addr().Next()
|
||||
|
||||
//calculate broadcast address
|
||||
var wildcard uint32 = (1 << (32 - cidr)) - 1
|
||||
|
||||
wildcard_mask := [4]byte{}
|
||||
binary.BigEndian.PutUint32(wildcard_mask[:4], wildcard)
|
||||
broadcast := base_ip4.As4()
|
||||
broadcast[0] |= wildcard_mask[0]
|
||||
broadcast[1] |= wildcard_mask[1]
|
||||
broadcast[2] |= wildcard_mask[2]
|
||||
broadcast[3] |= wildcard_mask[3]
|
||||
|
||||
broadcast_addr := netip.AddrFrom4(broadcast)
|
||||
pool.Lease(broadcast_addr)
|
||||
//gateway
|
||||
pool.Lease(base_ip4)
|
||||
|
||||
return pool
|
||||
}
|
||||
func (p *IPPool) Next() (netip.Addr, error) {
|
||||
cyclic := false
|
||||
for ; ; p.cache = p.cache.Next() {
|
||||
if p.leasure.Contains(p.cache) && p.cache.IsValid() {
|
||||
continue
|
||||
} else {
|
||||
if p.cache.IsValid() && p.scope.Contains(p.cache) && !p.leasure.Contains(p.cache) {
|
||||
return p.cache, nil
|
||||
} else if !cyclic {
|
||||
p.cache = p.scope.Masked().Addr()
|
||||
cyclic = true
|
||||
|
||||
} else {
|
||||
return p.cache, ErrIPPoolExhausted
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *IPPool) Lease(addr netip.Addr) {
|
||||
p.leasure.Insert(addr)
|
||||
}
|
||||
func (p *IPPool) HasIP(addr netip.Addr) {
|
||||
p.leasure.Contains(addr)
|
||||
}
|
||||
273
internal/wg/wg.go
Normal file
273
internal/wg/wg.go
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
package wg
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -I./
|
||||
#include <wireguard.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdlib.h>
|
||||
enum wg_device_flags dev_cfg = WGDEVICE_HAS_PRIVATE_KEY|WGDEVICE_HAS_LISTEN_PORT;
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"math/bits"
|
||||
"net/netip"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"git.jasinco.work/wgcl/internal/logger"
|
||||
protovpn "git.jasinco.work/wgcl/proto/out"
|
||||
"github.com/vishvananda/netlink"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// TODO: inspect all api, complete error handling
|
||||
|
||||
type WGPeer struct {
|
||||
name string
|
||||
privkey string //base64 string
|
||||
peer C.wg_peer
|
||||
next *WGPeer
|
||||
}
|
||||
|
||||
type WG struct {
|
||||
dev *C.wg_device
|
||||
lock sync.RWMutex
|
||||
keep_alive bool
|
||||
peers *WGPeer
|
||||
peers_len int
|
||||
IP4Pool *IPPool
|
||||
}
|
||||
|
||||
var WGfailedadddev = errors.New("failed add wgdev")
|
||||
var WGfailedsetdev = errors.New("failed set wgdev")
|
||||
var WGfailedparseb64key = errors.New("failed parse base64 key")
|
||||
|
||||
func GetB64Key(key *C.wg_key) string {
|
||||
var psk_b64 C.wg_key_b64_string
|
||||
|
||||
psk_ptr := (*C.uint8_t)(unsafe.Pointer(&(*key)[0]))
|
||||
psk_b64_ptr := (*C.char)(unsafe.Pointer(&psk_b64[0]))
|
||||
C.wg_key_to_base64(psk_b64_ptr, psk_ptr)
|
||||
return C.GoString(psk_b64_ptr)
|
||||
}
|
||||
|
||||
func NewKey() string {
|
||||
var privkey C.wg_key
|
||||
|
||||
privkey_as_ptr := (*C.uint8_t)(unsafe.Pointer(&privkey[0]))
|
||||
C.wg_generate_private_key(privkey_as_ptr)
|
||||
return GetB64Key(&privkey)
|
||||
}
|
||||
|
||||
func NewPresharedKey() string {
|
||||
var psk C.wg_key
|
||||
psk_ptr := (*C.uint8_t)(unsafe.Pointer(&psk[0]))
|
||||
C.wg_generate_preshared_key(psk_ptr)
|
||||
return GetB64Key(&psk)
|
||||
}
|
||||
|
||||
// device name and receive base64 encoded keys
|
||||
func WG_init(name string, privkey string, listen uint16, ip4_pool *IPPool) (*WG, error) {
|
||||
var dev WG
|
||||
dev.dev = (*C.wg_device)(C.malloc(C.sizeof_wg_device))
|
||||
|
||||
// hence it only call once at startup, I'd rather not to free it explicitly
|
||||
C.wg_key_from_base64((*C.uint8_t)(unsafe.Pointer(&dev.dev.private_key[0])), C.CString(privkey))
|
||||
|
||||
// set device name
|
||||
ifname := C.CString(name)
|
||||
C.strncpy(&dev.dev.name[0], ifname, 16)
|
||||
|
||||
dev.dev.flags = C.dev_cfg
|
||||
dev.dev.first_peer = (*C.wg_peer)(C.NULL)
|
||||
dev.dev.last_peer = (*C.wg_peer)(C.NULL)
|
||||
dev.dev.listen_port = (C.uint16_t)(listen)
|
||||
if C.wg_add_device((*C.char)(unsafe.Pointer(&dev.dev.name[0]))) < 0 {
|
||||
return nil, WGfailedadddev
|
||||
}
|
||||
if C.wg_set_device(dev.dev) < 0 {
|
||||
return nil, WGfailedsetdev
|
||||
}
|
||||
if C.wg_get_device(&dev.dev, (*C.char)(unsafe.Pointer(&dev.dev.name[0]))) < 0 {
|
||||
return nil, WGfailedsetdev
|
||||
}
|
||||
dev.peers = nil
|
||||
dev.IP4Pool = ip4_pool
|
||||
|
||||
// setup interface
|
||||
var err error
|
||||
wg_if, err := netlink.LinkByIndex(int(dev.dev.ifindex))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nl_addr, err := netlink.ParseAddr(ip4_pool.scope.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = netlink.AddrAdd(wg_if, nl_addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = netlink.LinkSetUp(wg_if)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dev, nil
|
||||
}
|
||||
|
||||
func (wg *WG) SyncStatus() {
|
||||
wg.lock.Lock()
|
||||
defer wg.lock.Unlock()
|
||||
if C.wg_get_device(&wg.dev, (*C.char)(unsafe.Pointer(&wg.dev.name[0]))) < 0 {
|
||||
logger.Logger.Info("Failed to sync wg status")
|
||||
}
|
||||
}
|
||||
|
||||
func (wg *WG) Deinit() {
|
||||
C.wg_del_device((*C.char)(unsafe.Pointer(&wg.dev.name[0])))
|
||||
}
|
||||
|
||||
func (wg *WG) WriteTxStart() {
|
||||
wg.lock.Lock()
|
||||
}
|
||||
func (wg *WG) WriteTxEnd() {
|
||||
wg.lock.Unlock()
|
||||
}
|
||||
|
||||
func (wg *WG) AddPeer(peer *WGPeer) {
|
||||
peer.next = nil
|
||||
wg.peers_len += 1
|
||||
if wg.peers == nil {
|
||||
wg.peers = peer
|
||||
return
|
||||
}
|
||||
ptr := wg.peers
|
||||
for ptr.next != nil {
|
||||
ptr = ptr.next
|
||||
}
|
||||
ptr.next = peer
|
||||
}
|
||||
|
||||
func (wg *WG) RemovePeer(peer *WGPeer) {
|
||||
if wg.peers == peer {
|
||||
wg.peers = peer.next
|
||||
}
|
||||
for ptr := wg.peers; ptr != nil; ptr = ptr.next {
|
||||
if ptr.next == peer {
|
||||
ptr.next = peer.next
|
||||
break
|
||||
}
|
||||
}
|
||||
wg.peers_len -= 1
|
||||
}
|
||||
|
||||
func (wg *WG) Apply() error {
|
||||
|
||||
if wg.peers != nil {
|
||||
first_ptr := (*C.wg_peer)(unsafe.Pointer(&wg.peers.peer))
|
||||
wg.dev.first_peer = first_ptr
|
||||
} else {
|
||||
wg.dev.first_peer = nil
|
||||
wg.dev.last_peer = nil
|
||||
}
|
||||
|
||||
for ptr := wg.peers; ptr != nil; ptr = (*WGPeer)(ptr.next) {
|
||||
if ptr.next == nil {
|
||||
ptr.peer.next_peer = nil
|
||||
last_ptr := (*C.wg_peer)(unsafe.Pointer(&ptr.peer))
|
||||
wg.dev.last_peer = last_ptr
|
||||
break
|
||||
}
|
||||
ptr.peer.next_peer = &(*WGPeer)(ptr.next).peer
|
||||
}
|
||||
wgdev := (*C.wg_device)(unsafe.Pointer(wg.dev))
|
||||
if C.wg_set_device(wgdev) < 0 {
|
||||
return WGfailedsetdev
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (wg *WG) SearchPeerIP4(addr netip.Addr) *WGPeer {
|
||||
wg.lock.RLock()
|
||||
defer wg.lock.RUnlock()
|
||||
ip4_slice := addr.As4()
|
||||
for ptr := wg.peers; ptr != nil; ptr = ptr.next {
|
||||
if bytes.Equal(ip4_slice[:], ptr.peer.first_allowedip.anon0[:4]) {
|
||||
return ptr
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (wg *WG) SearchPeerPubkey(pubkey string) (*WGPeer, error) {
|
||||
wg.lock.RLock()
|
||||
defer wg.lock.RUnlock()
|
||||
pubkey_cstr := C.CString(pubkey)
|
||||
defer C.free(unsafe.Pointer(pubkey_cstr))
|
||||
var pubkey_bin C.wg_key
|
||||
if C.wg_key_from_base64((*C.uint8_t)(&pubkey_bin[0]), pubkey_cstr) < 0 {
|
||||
return nil, WGfailedparseb64key
|
||||
}
|
||||
for ptr := wg.peers; ptr != nil; ptr = ptr.next {
|
||||
if C.wg_key_equal(&pubkey_bin, &ptr.peer.public_key) == 0 {
|
||||
return ptr, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
func (w *WG) GetPeersJson() *protovpn.PeerResp {
|
||||
w.lock.RLock()
|
||||
defer w.lock.RUnlock()
|
||||
peers := make([]*protovpn.PeerStatus, w.peers_len)
|
||||
peers_ptr := 0
|
||||
for ptr := w.peers; ptr != nil; ptr = ptr.next {
|
||||
peers[peers_ptr] = ptr.ToPeerStatus()
|
||||
peers_ptr += 1
|
||||
}
|
||||
resp := protovpn.PeerResp_builder{Peers: peers}
|
||||
return resp.Build()
|
||||
}
|
||||
|
||||
func WGPeer_init(name string, privkey string, remote netip.Addr) *WGPeer {
|
||||
var peer WGPeer
|
||||
peer.name = name
|
||||
peer.privkey = privkey
|
||||
|
||||
var privkey_bin C.wg_key
|
||||
priv_cstr := C.CString(privkey)
|
||||
defer C.free(unsafe.Pointer(priv_cstr))
|
||||
C.wg_key_from_base64((*C.uint8_t)(unsafe.Pointer(&privkey_bin[0])), priv_cstr)
|
||||
C.wg_generate_public_key((*C.uint8_t)(unsafe.Pointer(&peer.peer.public_key[0])), (*C.uint8_t)(unsafe.Pointer(&privkey_bin[0])))
|
||||
peer.peer.flags = C.WGPEER_HAS_PUBLIC_KEY | C.WGPEER_REPLACE_ALLOWEDIPS
|
||||
|
||||
remote_ip_arr := remote.As4()
|
||||
remote_ip := binary.LittleEndian.Uint32(remote_ip_arr[:])
|
||||
remote_endpoint := C.wg_allowed_ip_new_ip4((C.in_addr_t)(remote_ip), 32)
|
||||
|
||||
peer.peer.first_allowedip = remote_endpoint
|
||||
peer.peer.last_allowedip = remote_endpoint
|
||||
|
||||
return &peer
|
||||
}
|
||||
|
||||
func WGPeer_free(peer *WGPeer) {
|
||||
C.free(unsafe.Pointer(peer.peer.first_allowedip))
|
||||
}
|
||||
func (p *WGPeer) Disable() {
|
||||
p.peer.flags |= C.WGPEER_REMOVE_ME
|
||||
}
|
||||
func (p *WGPeer) Enable() {
|
||||
p.peer.flags &= bits.Reverse32(C.WGPEER_REMOVE_ME)
|
||||
}
|
||||
func (p *WGPeer) ToPeerStatus() *protovpn.PeerStatus {
|
||||
ip4, _ := netip.AddrFromSlice(p.peer.first_allowedip.anon0[:4])
|
||||
return protovpn.PeerStatus_builder{
|
||||
Enabled: proto.Bool((p.peer.flags & C.WGPEER_REMOVE_ME) == 0),
|
||||
Pubkey: proto.String(GetB64Key(&p.peer.public_key)),
|
||||
Nick: proto.String(p.name),
|
||||
Ipv4: proto.String(ip4.String()),
|
||||
Beacon: proto.Int64(int64(p.peer.last_handshake_time.tv_sec)),
|
||||
}.Build()
|
||||
}
|
||||
1720
internal/wg/wireguard.c
Normal file
1720
internal/wg/wireguard.c
Normal file
File diff suppressed because it is too large
Load diff
115
internal/wg/wireguard.h
Normal file
115
internal/wg/wireguard.h
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
/*
|
||||
* Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef WIREGUARD_H
|
||||
#define WIREGUARD_H
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <time.h>
|
||||
|
||||
typedef uint8_t wg_key[32];
|
||||
typedef char wg_key_b64_string[((sizeof(wg_key) + 2) / 3) * 4 + 1];
|
||||
|
||||
/* Cross platform __kernel_timespec */
|
||||
struct timespec64 {
|
||||
int64_t tv_sec;
|
||||
int64_t tv_nsec;
|
||||
};
|
||||
|
||||
typedef struct wg_allowedip {
|
||||
uint16_t family;
|
||||
union {
|
||||
struct in_addr ip4;
|
||||
struct in6_addr ip6;
|
||||
};
|
||||
uint8_t cidr;
|
||||
struct wg_allowedip *next_allowedip;
|
||||
} wg_allowedip;
|
||||
|
||||
wg_allowedip *wg_allowed_ip_new_ip4(in_addr_t ip4, uint8_t cidr);
|
||||
|
||||
enum wg_peer_flags {
|
||||
WGPEER_REMOVE_ME = 1U << 0,
|
||||
WGPEER_REPLACE_ALLOWEDIPS = 1U << 1,
|
||||
WGPEER_HAS_PUBLIC_KEY = 1U << 2,
|
||||
WGPEER_HAS_PRESHARED_KEY = 1U << 3,
|
||||
WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL = 1U << 4
|
||||
};
|
||||
|
||||
typedef union wg_endpoint {
|
||||
struct sockaddr addr;
|
||||
struct sockaddr_in addr4;
|
||||
struct sockaddr_in6 addr6;
|
||||
} wg_endpoint;
|
||||
|
||||
typedef struct wg_peer {
|
||||
enum wg_peer_flags flags;
|
||||
|
||||
wg_key public_key;
|
||||
wg_key preshared_key;
|
||||
|
||||
wg_endpoint endpoint;
|
||||
|
||||
struct timespec64 last_handshake_time;
|
||||
uint64_t rx_bytes, tx_bytes;
|
||||
uint16_t persistent_keepalive_interval;
|
||||
|
||||
struct wg_allowedip *first_allowedip, *last_allowedip;
|
||||
struct wg_peer *next_peer;
|
||||
} wg_peer;
|
||||
|
||||
enum wg_device_flags {
|
||||
WGDEVICE_REPLACE_PEERS = 1U << 0,
|
||||
WGDEVICE_HAS_PRIVATE_KEY = 1U << 1,
|
||||
WGDEVICE_HAS_PUBLIC_KEY = 1U << 2,
|
||||
WGDEVICE_HAS_LISTEN_PORT = 1U << 3,
|
||||
WGDEVICE_HAS_FWMARK = 1U << 4
|
||||
};
|
||||
|
||||
typedef struct wg_device {
|
||||
char name[IFNAMSIZ];
|
||||
uint32_t ifindex;
|
||||
|
||||
enum wg_device_flags flags;
|
||||
|
||||
wg_key public_key;
|
||||
wg_key private_key;
|
||||
|
||||
uint32_t fwmark;
|
||||
uint16_t listen_port;
|
||||
|
||||
struct wg_peer *first_peer, *last_peer;
|
||||
} wg_device;
|
||||
|
||||
#define wg_for_each_device_name(__names, __name, __len) \
|
||||
for ((__name) = (__names), (__len) = 0; ((__len) = strlen(__name)); \
|
||||
(__name) += (__len) + 1)
|
||||
#define wg_for_each_peer(__dev, __peer) \
|
||||
for ((__peer) = (__dev)->first_peer; (__peer); (__peer) = (__peer)->next_peer)
|
||||
#define wg_for_each_allowedip(__peer, __allowedip) \
|
||||
for ((__allowedip) = (__peer)->first_allowedip; (__allowedip); \
|
||||
(__allowedip) = (__allowedip)->next_allowedip)
|
||||
|
||||
int wg_set_device(wg_device *dev);
|
||||
int wg_get_device(wg_device **dev, const char *device_name);
|
||||
int wg_add_device(const char *device_name);
|
||||
int wg_del_device(const char *device_name);
|
||||
void wg_free_device(wg_device *dev);
|
||||
char *wg_list_device_names(void); /* first\0second\0third\0forth\0last\0\0 */
|
||||
void wg_key_to_base64(wg_key_b64_string base64, const wg_key key);
|
||||
int wg_key_from_base64(wg_key key, const wg_key_b64_string base64);
|
||||
bool wg_key_is_zero(const wg_key key);
|
||||
void wg_generate_public_key(wg_key public_key, const wg_key private_key);
|
||||
void wg_generate_private_key(wg_key private_key);
|
||||
void wg_generate_preshared_key(wg_key preshared_key);
|
||||
int wg_key_equal(wg_key *k1, wg_key *k2);
|
||||
|
||||
#endif
|
||||
13
justfile
Normal file
13
justfile
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
genproto:
|
||||
protoc --proto_path=proto --go_out=proto/out --go_opt=paths=source_relative vpn.proto
|
||||
build:
|
||||
go build -o srv ./cmd/main.go
|
||||
run: build clif
|
||||
sudo ./srv
|
||||
clif:
|
||||
sudo ip link delete wg0 || echo "no wg0"
|
||||
fzuser:
|
||||
#!/usr/bin/env bash
|
||||
cred=$(curlie POST localhost:8080/api/auth username=gggg password=gggggggg | jq -r ".token")
|
||||
echo "bearer ${cred}"
|
||||
curlie POST localhost:8080/api/vpn/peer "Authorization:Bearer $cred" name="test"
|
||||
452
proto/out/vpn.pb.go
Normal file
452
proto/out/vpn.pb.go
Normal file
|
|
@ -0,0 +1,452 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.10
|
||||
// protoc v6.33.0
|
||||
// source: vpn.proto
|
||||
|
||||
package out
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type PeerStatus struct {
|
||||
state protoimpl.MessageState `protogen:"opaque.v1"`
|
||||
xxx_hidden_Pubkey *string `protobuf:"bytes,1,opt,name=pubkey"`
|
||||
xxx_hidden_Ipv4 *string `protobuf:"bytes,2,opt,name=ipv4"`
|
||||
xxx_hidden_Enabled bool `protobuf:"varint,3,opt,name=enabled"`
|
||||
xxx_hidden_Nick *string `protobuf:"bytes,4,opt,name=nick"`
|
||||
xxx_hidden_Beacon int64 `protobuf:"varint,5,opt,name=beacon"`
|
||||
XXX_raceDetectHookData protoimpl.RaceDetectHookData
|
||||
XXX_presence [1]uint32
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *PeerStatus) Reset() {
|
||||
*x = PeerStatus{}
|
||||
mi := &file_vpn_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *PeerStatus) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*PeerStatus) ProtoMessage() {}
|
||||
|
||||
func (x *PeerStatus) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_vpn_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
func (x *PeerStatus) GetPubkey() string {
|
||||
if x != nil {
|
||||
if x.xxx_hidden_Pubkey != nil {
|
||||
return *x.xxx_hidden_Pubkey
|
||||
}
|
||||
return ""
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PeerStatus) GetIpv4() string {
|
||||
if x != nil {
|
||||
if x.xxx_hidden_Ipv4 != nil {
|
||||
return *x.xxx_hidden_Ipv4
|
||||
}
|
||||
return ""
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PeerStatus) GetEnabled() bool {
|
||||
if x != nil {
|
||||
return x.xxx_hidden_Enabled
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *PeerStatus) GetNick() string {
|
||||
if x != nil {
|
||||
if x.xxx_hidden_Nick != nil {
|
||||
return *x.xxx_hidden_Nick
|
||||
}
|
||||
return ""
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PeerStatus) GetBeacon() int64 {
|
||||
if x != nil {
|
||||
return x.xxx_hidden_Beacon
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *PeerStatus) SetPubkey(v string) {
|
||||
x.xxx_hidden_Pubkey = &v
|
||||
protoimpl.X.SetPresent(&(x.XXX_presence[0]), 0, 5)
|
||||
}
|
||||
|
||||
func (x *PeerStatus) SetIpv4(v string) {
|
||||
x.xxx_hidden_Ipv4 = &v
|
||||
protoimpl.X.SetPresent(&(x.XXX_presence[0]), 1, 5)
|
||||
}
|
||||
|
||||
func (x *PeerStatus) SetEnabled(v bool) {
|
||||
x.xxx_hidden_Enabled = v
|
||||
protoimpl.X.SetPresent(&(x.XXX_presence[0]), 2, 5)
|
||||
}
|
||||
|
||||
func (x *PeerStatus) SetNick(v string) {
|
||||
x.xxx_hidden_Nick = &v
|
||||
protoimpl.X.SetPresent(&(x.XXX_presence[0]), 3, 5)
|
||||
}
|
||||
|
||||
func (x *PeerStatus) SetBeacon(v int64) {
|
||||
x.xxx_hidden_Beacon = v
|
||||
protoimpl.X.SetPresent(&(x.XXX_presence[0]), 4, 5)
|
||||
}
|
||||
|
||||
func (x *PeerStatus) HasPubkey() bool {
|
||||
if x == nil {
|
||||
return false
|
||||
}
|
||||
return protoimpl.X.Present(&(x.XXX_presence[0]), 0)
|
||||
}
|
||||
|
||||
func (x *PeerStatus) HasIpv4() bool {
|
||||
if x == nil {
|
||||
return false
|
||||
}
|
||||
return protoimpl.X.Present(&(x.XXX_presence[0]), 1)
|
||||
}
|
||||
|
||||
func (x *PeerStatus) HasEnabled() bool {
|
||||
if x == nil {
|
||||
return false
|
||||
}
|
||||
return protoimpl.X.Present(&(x.XXX_presence[0]), 2)
|
||||
}
|
||||
|
||||
func (x *PeerStatus) HasNick() bool {
|
||||
if x == nil {
|
||||
return false
|
||||
}
|
||||
return protoimpl.X.Present(&(x.XXX_presence[0]), 3)
|
||||
}
|
||||
|
||||
func (x *PeerStatus) HasBeacon() bool {
|
||||
if x == nil {
|
||||
return false
|
||||
}
|
||||
return protoimpl.X.Present(&(x.XXX_presence[0]), 4)
|
||||
}
|
||||
|
||||
func (x *PeerStatus) ClearPubkey() {
|
||||
protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 0)
|
||||
x.xxx_hidden_Pubkey = nil
|
||||
}
|
||||
|
||||
func (x *PeerStatus) ClearIpv4() {
|
||||
protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 1)
|
||||
x.xxx_hidden_Ipv4 = nil
|
||||
}
|
||||
|
||||
func (x *PeerStatus) ClearEnabled() {
|
||||
protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 2)
|
||||
x.xxx_hidden_Enabled = false
|
||||
}
|
||||
|
||||
func (x *PeerStatus) ClearNick() {
|
||||
protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 3)
|
||||
x.xxx_hidden_Nick = nil
|
||||
}
|
||||
|
||||
func (x *PeerStatus) ClearBeacon() {
|
||||
protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 4)
|
||||
x.xxx_hidden_Beacon = 0
|
||||
}
|
||||
|
||||
type PeerStatus_builder struct {
|
||||
_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
|
||||
|
||||
Pubkey *string
|
||||
Ipv4 *string
|
||||
Enabled *bool
|
||||
Nick *string
|
||||
Beacon *int64
|
||||
}
|
||||
|
||||
func (b0 PeerStatus_builder) Build() *PeerStatus {
|
||||
m0 := &PeerStatus{}
|
||||
b, x := &b0, m0
|
||||
_, _ = b, x
|
||||
if b.Pubkey != nil {
|
||||
protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 0, 5)
|
||||
x.xxx_hidden_Pubkey = b.Pubkey
|
||||
}
|
||||
if b.Ipv4 != nil {
|
||||
protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 1, 5)
|
||||
x.xxx_hidden_Ipv4 = b.Ipv4
|
||||
}
|
||||
if b.Enabled != nil {
|
||||
protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 2, 5)
|
||||
x.xxx_hidden_Enabled = *b.Enabled
|
||||
}
|
||||
if b.Nick != nil {
|
||||
protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 3, 5)
|
||||
x.xxx_hidden_Nick = b.Nick
|
||||
}
|
||||
if b.Beacon != nil {
|
||||
protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 4, 5)
|
||||
x.xxx_hidden_Beacon = *b.Beacon
|
||||
}
|
||||
return m0
|
||||
}
|
||||
|
||||
type PeerResp struct {
|
||||
state protoimpl.MessageState `protogen:"opaque.v1"`
|
||||
xxx_hidden_Peers *[]*PeerStatus `protobuf:"bytes,1,rep,name=peers"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *PeerResp) Reset() {
|
||||
*x = PeerResp{}
|
||||
mi := &file_vpn_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *PeerResp) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*PeerResp) ProtoMessage() {}
|
||||
|
||||
func (x *PeerResp) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_vpn_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
func (x *PeerResp) GetPeers() []*PeerStatus {
|
||||
if x != nil {
|
||||
if x.xxx_hidden_Peers != nil {
|
||||
return *x.xxx_hidden_Peers
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *PeerResp) SetPeers(v []*PeerStatus) {
|
||||
x.xxx_hidden_Peers = &v
|
||||
}
|
||||
|
||||
type PeerResp_builder struct {
|
||||
_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
|
||||
|
||||
Peers []*PeerStatus
|
||||
}
|
||||
|
||||
func (b0 PeerResp_builder) Build() *PeerResp {
|
||||
m0 := &PeerResp{}
|
||||
b, x := &b0, m0
|
||||
_, _ = b, x
|
||||
x.xxx_hidden_Peers = &b.Peers
|
||||
return m0
|
||||
}
|
||||
|
||||
type PeerReq struct {
|
||||
state protoimpl.MessageState `protogen:"opaque.v1"`
|
||||
xxx_hidden_Name *string `protobuf:"bytes,1,req,name=name"`
|
||||
xxx_hidden_Ip4 *string `protobuf:"bytes,2,opt,name=ip4"`
|
||||
XXX_raceDetectHookData protoimpl.RaceDetectHookData
|
||||
XXX_presence [1]uint32
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *PeerReq) Reset() {
|
||||
*x = PeerReq{}
|
||||
mi := &file_vpn_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *PeerReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*PeerReq) ProtoMessage() {}
|
||||
|
||||
func (x *PeerReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_vpn_proto_msgTypes[2]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
func (x *PeerReq) GetName() string {
|
||||
if x != nil {
|
||||
if x.xxx_hidden_Name != nil {
|
||||
return *x.xxx_hidden_Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PeerReq) GetIp4() string {
|
||||
if x != nil {
|
||||
if x.xxx_hidden_Ip4 != nil {
|
||||
return *x.xxx_hidden_Ip4
|
||||
}
|
||||
return ""
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PeerReq) SetName(v string) {
|
||||
x.xxx_hidden_Name = &v
|
||||
protoimpl.X.SetPresent(&(x.XXX_presence[0]), 0, 2)
|
||||
}
|
||||
|
||||
func (x *PeerReq) SetIp4(v string) {
|
||||
x.xxx_hidden_Ip4 = &v
|
||||
protoimpl.X.SetPresent(&(x.XXX_presence[0]), 1, 2)
|
||||
}
|
||||
|
||||
func (x *PeerReq) HasName() bool {
|
||||
if x == nil {
|
||||
return false
|
||||
}
|
||||
return protoimpl.X.Present(&(x.XXX_presence[0]), 0)
|
||||
}
|
||||
|
||||
func (x *PeerReq) HasIp4() bool {
|
||||
if x == nil {
|
||||
return false
|
||||
}
|
||||
return protoimpl.X.Present(&(x.XXX_presence[0]), 1)
|
||||
}
|
||||
|
||||
func (x *PeerReq) ClearName() {
|
||||
protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 0)
|
||||
x.xxx_hidden_Name = nil
|
||||
}
|
||||
|
||||
func (x *PeerReq) ClearIp4() {
|
||||
protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 1)
|
||||
x.xxx_hidden_Ip4 = nil
|
||||
}
|
||||
|
||||
type PeerReq_builder struct {
|
||||
_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
|
||||
|
||||
Name *string
|
||||
Ip4 *string
|
||||
}
|
||||
|
||||
func (b0 PeerReq_builder) Build() *PeerReq {
|
||||
m0 := &PeerReq{}
|
||||
b, x := &b0, m0
|
||||
_, _ = b, x
|
||||
if b.Name != nil {
|
||||
protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 0, 2)
|
||||
x.xxx_hidden_Name = b.Name
|
||||
}
|
||||
if b.Ip4 != nil {
|
||||
protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 1, 2)
|
||||
x.xxx_hidden_Ip4 = b.Ip4
|
||||
}
|
||||
return m0
|
||||
}
|
||||
|
||||
var File_vpn_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_vpn_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\tvpn.proto\x12\bprotovpn\"~\n" +
|
||||
"\n" +
|
||||
"PeerStatus\x12\x16\n" +
|
||||
"\x06pubkey\x18\x01 \x01(\tR\x06pubkey\x12\x12\n" +
|
||||
"\x04ipv4\x18\x02 \x01(\tR\x04ipv4\x12\x18\n" +
|
||||
"\aenabled\x18\x03 \x01(\bR\aenabled\x12\x12\n" +
|
||||
"\x04nick\x18\x04 \x01(\tR\x04nick\x12\x16\n" +
|
||||
"\x06beacon\x18\x05 \x01(\x03R\x06beacon\"6\n" +
|
||||
"\bPeerResp\x12*\n" +
|
||||
"\x05peers\x18\x01 \x03(\v2\x14.protovpn.PeerStatusR\x05peers\"=\n" +
|
||||
"\aPeerReq\x12\x19\n" +
|
||||
"\x04name\x18\x01 \x01(\tB\x05\xaa\x01\x02\b\x03R\x04name\x12\x17\n" +
|
||||
"\x03ip4\x18\x02 \x01(\tB\x05\xaa\x01\x02\b\x01R\x03ip4B!Z\x1fgit.jasinco.work/wgcl/proto/outb\beditionsp\xe9\a"
|
||||
|
||||
var file_vpn_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||
var file_vpn_proto_goTypes = []any{
|
||||
(*PeerStatus)(nil), // 0: protovpn.PeerStatus
|
||||
(*PeerResp)(nil), // 1: protovpn.PeerResp
|
||||
(*PeerReq)(nil), // 2: protovpn.PeerReq
|
||||
}
|
||||
var file_vpn_proto_depIdxs = []int32{
|
||||
0, // 0: protovpn.PeerResp.peers:type_name -> protovpn.PeerStatus
|
||||
1, // [1:1] is the sub-list for method output_type
|
||||
1, // [1:1] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_vpn_proto_init() }
|
||||
func file_vpn_proto_init() {
|
||||
if File_vpn_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_vpn_proto_rawDesc), len(file_vpn_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 3,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_vpn_proto_goTypes,
|
||||
DependencyIndexes: file_vpn_proto_depIdxs,
|
||||
MessageInfos: file_vpn_proto_msgTypes,
|
||||
}.Build()
|
||||
File_vpn_proto = out.File
|
||||
file_vpn_proto_goTypes = nil
|
||||
file_vpn_proto_depIdxs = nil
|
||||
}
|
||||
19
proto/vpn.proto
Normal file
19
proto/vpn.proto
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
edition = "2024";
|
||||
package protovpn;
|
||||
option go_package = "git.jasinco.work/wgcl/proto/out";
|
||||
|
||||
message PeerStatus {
|
||||
string pubkey = 1;
|
||||
string ipv4 = 2;
|
||||
bool enabled = 3;
|
||||
string nick = 4;
|
||||
int64 beacon = 5;
|
||||
}
|
||||
|
||||
message PeerResp {
|
||||
repeated PeerStatus peers = 1;
|
||||
}
|
||||
message PeerReq {
|
||||
string name = 1 [features.field_presence = LEGACY_REQUIRED];
|
||||
string ip4 = 2 [features.field_presence = EXPLICIT];
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue