Skip to content

Commit

Permalink
server: changes to auth API
Browse files Browse the repository at this point in the history
  • Loading branch information
vyloy committed Aug 21, 2023
1 parent cdff566 commit aacecd6
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 42 deletions.
124 changes: 91 additions & 33 deletions server/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,43 +320,101 @@ func (c *conn) handleTunnel(remoteIP string, r bool) (handled, reload bool, cli
return
}

// 验证 id secret
u, err := c.server.authUser(idStr, secretStr)
if err != nil {
// 使用局部锁而不是全局锁可以明显提高并发性能,但少数情况下会降低限制效果
c.server.reconnectRWMutex.Lock()
reconnectTimes := c.server.reconnect[remoteIP]
reconnectTimes++
c.server.reconnect[remoteIP] = reconnectTimes
c.server.reconnectRWMutex.Unlock()
var options options
var u user
if c.server.authUser != nil {
// 验证 id secret
u, err = c.server.authUser(idStr, secretStr)
if err != nil {
// 使用局部锁而不是全局锁可以明显提高并发性能,但少数情况下会降低限制效果
c.server.reconnectRWMutex.Lock()
reconnectTimes := c.server.reconnect[remoteIP]
reconnectTimes++
c.server.reconnect[remoteIP] = reconnectTimes
c.server.reconnectRWMutex.Unlock()

// ReconnectDuration 为 0 表示不进行限制解除
if c.server.config.ReconnectDuration > 0 && reconnectTimes > c.server.config.ReconnectTimes {
time.AfterFunc(c.server.config.ReconnectDuration, func() {
c.server.reconnectRWMutex.Lock()
c.server.reconnect[remoteIP] = 0
c.server.reconnectRWMutex.Unlock()
c.Logger.Debug().Msgf("release blocked IP: '%v'", remoteIP)
})
}

// ReconnectDuration 为 0 表示不进行限制解除
if c.server.config.ReconnectDuration > 0 && reconnectTimes > c.server.config.ReconnectTimes {
time.AfterFunc(c.server.config.ReconnectDuration, func() {
c.server.reconnectRWMutex.Lock()
c.server.reconnect[remoteIP] = 0
c.server.reconnectRWMutex.Unlock()
c.Logger.Debug().Msgf("release blocked IP: '%v'", remoteIP)
})
e := c.SendErrorSignalInvalidIDAndSecret()
c.Logger.Info().Err(err).AnErr("respErr", e).Msg("invalid id and secret")
return
}

e := c.SendErrorSignalInvalidIDAndSecret()
c.Logger.Info().Err(err).AnErr("respErr", e).Msg("invalid id and secret")
return
}
options, err = c.parseOptions(reader, idStr, u)
if err != nil {
c.Logger.Info().Err(err).Msg("failed to parse options")
return
}
if len(u.Host.Prefixes) > 0 {
for id := range options.ids {
if _, ok := u.Host.Prefixes[id]; !ok {
c.Logger.Info().Err(err).
AnErr("sendSignalError", c.SendErrorSignalHostRegexMismatch()).
Msg("invalid host prefixes")
return
}
}
}
} else {
u = user{
TCPs: c.server.config.TCPs,
Speed: c.server.config.Speed,
Connections: c.server.config.Connections,
Host: c.server.config.Host,
}
options, err = c.parseOptions(reader, idStr, u)
if err != nil {
c.Logger.Info().Err(err).Msg("failed to parse options")
return
}
prefixes := make([]string, 0, len(options.ids))
for s := range options.ids {
prefixes = append(prefixes, s)
}
u, err = c.server.authUserWithAPI(idStr, secretStr, prefixes)
if err != nil {
// 使用局部锁而不是全局锁可以明显提高并发性能,但少数情况下会降低限制效果
c.server.reconnectRWMutex.Lock()
reconnectTimes := c.server.reconnect[remoteIP]
reconnectTimes++
c.server.reconnect[remoteIP] = reconnectTimes
c.server.reconnectRWMutex.Unlock()

options, err := c.parseOptions(reader, idStr, u)
if err != nil {
c.Logger.Info().Err(err).Msg("failed to parse options")
return
}
if len(u.Host.Prefixes) > 0 {
for id := range options.ids {
if _, ok := u.Host.Prefixes[id]; !ok {
c.Logger.Info().Err(err).
AnErr("sendSignalError", c.SendErrorSignalHostRegexMismatch()).
Msg("invalid host prefixes")
return
// ReconnectDuration 为 0 表示不进行限制解除
if c.server.config.ReconnectDuration > 0 && reconnectTimes > c.server.config.ReconnectTimes {
time.AfterFunc(c.server.config.ReconnectDuration, func() {
c.server.reconnectRWMutex.Lock()
c.server.reconnect[remoteIP] = 0
c.server.reconnectRWMutex.Unlock()
c.Logger.Debug().Msgf("release blocked IP: '%v'", remoteIP)
})
}

e := c.SendErrorSignalInvalidIDAndSecret()
c.Logger.Info().Err(err).AnErr("respErr", e).Msg("invalid id and secret")
return
}
if len(u.Host.Prefixes) > 0 {
for id := range options.ids {
if _, ok := u.Host.Prefixes[id]; !ok {
c.Logger.Info().Str("id", idStr).Str("prefix", id).Msg("prefix not exists on platform")
delete(options.ids, id)
}
}
} else {
for id := range options.ids {
if id != idStr {
c.Logger.Info().Str("id", idStr).Str("prefix", id).Msg("prefix not exists on platform")
delete(options.ids, id)
}
}
}
}
Expand Down
30 changes: 21 additions & 9 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package server
import (
"bytes"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"io"
Expand Down Expand Up @@ -231,7 +232,7 @@ func (s *Server) Start() (err error) {
}

if len(s.config.AuthAPI) > 0 {
s.authUser = s.authUserWithAPI
s.authUser = nil
s.removeClient = s.removeClientOnly
} else if s.users.empty() {
s.Logger.Warn().Msg("working on -allowAnyClient mode, because no user is configured")
Expand Down Expand Up @@ -429,13 +430,24 @@ func (s *Server) startAPIServer() (err error) {
return nil
}

func (s *Server) authWithAPI(id string, secret string) (hostPrefixes map[string]struct{}, ok bool, err error) {
type authParam struct {
NetworkClientId string `json:"networkClientId"`
NetworkSecretKey string `json:"networkSecretKey"`
AppletTokens []string `json:"appletTokens"`
}

func (s *Server) authWithAPI(id string, secret string, prefixes []string) (hostPrefixes map[string]struct{}, ok bool, err error) {
var bs bytes.Buffer
_, _ = bs.WriteString(`{"networkClientId": "`)
_, _ = bs.WriteString(id)
_, _ = bs.WriteString(`", "networkSecretKey": "`)
_, _ = bs.WriteString(secret)
_, _ = bs.WriteString(`"}`)
encoder := json.NewEncoder(&bs)
p := &authParam{
NetworkClientId: id,
NetworkSecretKey: secret,
AppletTokens: prefixes,
}
err = encoder.Encode(p)
if err != nil {
return
}
req, err := http.NewRequest("POST", s.config.AuthAPI, &bs)
if err != nil {
return
Expand Down Expand Up @@ -660,12 +672,12 @@ func (s *Server) authUserWithConfig(id string, secret string) (u user, err error
return
}

func (s *Server) authUserWithAPI(id string, secret string) (u user, err error) {
func (s *Server) authUserWithAPI(id string, secret string, prefixes []string) (u user, err error) {
if len(id) < 1 || len(secret) < 1 {
err = ErrInvalidUser
return
}
hostPrefixes, ok, err := s.authWithAPI(id, secret)
hostPrefixes, ok, err := s.authWithAPI(id, secret, prefixes)
if err != nil {
return
}
Expand Down

0 comments on commit aacecd6

Please sign in to comment.