mirror of
https://github.com/cedar2025/hysteria.git
synced 2025-06-09 05:59:54 +00:00
Merge pull request #211 from HyNetwork/wip-more-auth
feat: multi-password & cmd auth
This commit is contained in:
commit
1430c81f90
30
cmd/auth/cmd.go
Normal file
30
cmd/auth/cmd.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"net"
|
||||||
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CmdAuthProvider struct {
|
||||||
|
Cmd string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *CmdAuthProvider) Auth(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string) {
|
||||||
|
cmd := exec.Command(p.Cmd, addr.String(), string(auth), strconv.Itoa(int(sSend)), strconv.Itoa(int(sRecv)))
|
||||||
|
out, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
if _, ok := err.(*exec.ExitError); ok {
|
||||||
|
return false, strings.TrimSpace(string(out))
|
||||||
|
} else {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"error": err,
|
||||||
|
}).Error("Failed to execute auth command")
|
||||||
|
return false, "internal error"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true, strings.TrimSpace(string(out))
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ package auth
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -33,24 +34,39 @@ func (p *HTTPAuthProvider) Auth(addr net.Addr, auth []byte, sSend uint64, sRecv
|
|||||||
Recv: sRecv,
|
Recv: sRecv,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, "Internal error"
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"error": err,
|
||||||
|
}).Error("Failed to marshal auth request")
|
||||||
|
return false, "internal error"
|
||||||
}
|
}
|
||||||
resp, err := p.Client.Post(p.URL, "application/json", bytes.NewBuffer(jbs))
|
resp, err := p.Client.Post(p.URL, "application/json", bytes.NewBuffer(jbs))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, "Internal error"
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"error": err,
|
||||||
|
}).Error("Failed to send auth request")
|
||||||
|
return false, "internal error"
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
return false, "Auth endpoint error"
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"code": resp.StatusCode,
|
||||||
|
}).Error("Invalid status code from auth server")
|
||||||
|
return false, "internal error"
|
||||||
}
|
}
|
||||||
data, err := ioutil.ReadAll(resp.Body)
|
data, err := ioutil.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, "Auth endpoint error"
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"error": err,
|
||||||
|
}).Error("Failed to read auth response")
|
||||||
|
return false, "internal error"
|
||||||
}
|
}
|
||||||
var ar authResp
|
var ar authResp
|
||||||
err = json.Unmarshal(data, &ar)
|
err = json.Unmarshal(data, &ar)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, "Auth endpoint error"
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"error": err,
|
||||||
|
}).Error("Failed to unmarshal auth response")
|
||||||
|
return false, "internal error"
|
||||||
}
|
}
|
||||||
return ar.OK, ar.Msg
|
return ar.OK, ar.Msg
|
||||||
}
|
}
|
@ -131,7 +131,7 @@ func initApp(c *cli.Context) error {
|
|||||||
"version", "url",
|
"version", "url",
|
||||||
"config", "file", "mode",
|
"config", "file", "mode",
|
||||||
"addr", "src", "dst", "session", "action",
|
"addr", "src", "dst", "session", "action",
|
||||||
"msg", "error",
|
"code", "msg", "error",
|
||||||
},
|
},
|
||||||
TimestampFormat: c.String("log-timestamp"),
|
TimestampFormat: c.String("log-timestamp"),
|
||||||
})
|
})
|
||||||
|
@ -2,14 +2,15 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
"github.com/lucas-clemente/quic-go"
|
"github.com/lucas-clemente/quic-go"
|
||||||
"github.com/lucas-clemente/quic-go/congestion"
|
"github.com/lucas-clemente/quic-go/congestion"
|
||||||
"github.com/oschwald/geoip2-golang"
|
"github.com/oschwald/geoip2-golang"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/tobyxdd/hysteria/cmd/auth"
|
||||||
"github.com/tobyxdd/hysteria/pkg/acl"
|
"github.com/tobyxdd/hysteria/pkg/acl"
|
||||||
"github.com/tobyxdd/hysteria/pkg/auth"
|
|
||||||
hyCongestion "github.com/tobyxdd/hysteria/pkg/congestion"
|
hyCongestion "github.com/tobyxdd/hysteria/pkg/congestion"
|
||||||
"github.com/tobyxdd/hysteria/pkg/core"
|
"github.com/tobyxdd/hysteria/pkg/core"
|
||||||
"github.com/tobyxdd/hysteria/pkg/obfs"
|
"github.com/tobyxdd/hysteria/pkg/obfs"
|
||||||
@ -84,7 +85,7 @@ func server(config *serverConfig) {
|
|||||||
quicConfig.MaxIncomingStreams = DefaultMaxIncomingStreams
|
quicConfig.MaxIncomingStreams = DefaultMaxIncomingStreams
|
||||||
}
|
}
|
||||||
// Auth
|
// Auth
|
||||||
var authFunc func(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string)
|
var authFunc core.ConnectFunc
|
||||||
var err error
|
var err error
|
||||||
switch authMode := config.Auth.Mode; authMode {
|
switch authMode := config.Auth.Mode; authMode {
|
||||||
case "", "none":
|
case "", "none":
|
||||||
@ -95,39 +96,24 @@ func server(config *serverConfig) {
|
|||||||
authFunc = func(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string) {
|
authFunc = func(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string) {
|
||||||
return true, "Welcome"
|
return true, "Welcome"
|
||||||
}
|
}
|
||||||
case "password":
|
case "password", "passwords":
|
||||||
logrus.Info("Password authentication enabled")
|
authFunc, err = passwordAuthFunc(config.Auth.Config)
|
||||||
var pwdConfig map[string]string
|
if err != nil {
|
||||||
err = json5.Unmarshal(config.Auth.Config, &pwdConfig)
|
|
||||||
if err != nil || len(pwdConfig["password"]) == 0 {
|
|
||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
"error": err,
|
"error": err,
|
||||||
}).Fatal("Invalid password authentication config")
|
}).Fatal("Failed to enable password authentication")
|
||||||
}
|
} else {
|
||||||
pwd := pwdConfig["password"]
|
logrus.Info("Password authentication enabled")
|
||||||
authFunc = func(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string) {
|
|
||||||
if string(auth) == pwd {
|
|
||||||
return true, "Welcome"
|
|
||||||
} else {
|
|
||||||
return false, "Wrong password"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case "external":
|
case "external":
|
||||||
logrus.Info("External authentication enabled")
|
authFunc, err = externalAuthFunc(config.Auth.Config)
|
||||||
var extConfig map[string]string
|
if err != nil {
|
||||||
err = json5.Unmarshal(config.Auth.Config, &extConfig)
|
|
||||||
if err != nil || len(extConfig["http"]) == 0 {
|
|
||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
"error": err,
|
"error": err,
|
||||||
}).Fatal("Invalid external authentication config")
|
}).Fatal("Failed to enable external authentication")
|
||||||
|
} else {
|
||||||
|
logrus.Info("External authentication enabled")
|
||||||
}
|
}
|
||||||
provider := &auth.HTTPAuthProvider{
|
|
||||||
Client: &http.Client{
|
|
||||||
Timeout: 10 * time.Second,
|
|
||||||
},
|
|
||||||
URL: extConfig["http"],
|
|
||||||
}
|
|
||||||
authFunc = provider.Auth
|
|
||||||
default:
|
default:
|
||||||
logrus.WithField("mode", config.Auth.Mode).Fatal("Unsupported authentication mode")
|
logrus.WithField("mode", config.Auth.Mode).Fatal("Unsupported authentication mode")
|
||||||
}
|
}
|
||||||
@ -199,6 +185,54 @@ func server(config *serverConfig) {
|
|||||||
logrus.WithField("error", err).Fatal("Server shutdown")
|
logrus.WithField("error", err).Fatal("Server shutdown")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func passwordAuthFunc(rawMsg json5.RawMessage) (core.ConnectFunc, error) {
|
||||||
|
var pwds []string
|
||||||
|
err := json5.Unmarshal(rawMsg, &pwds)
|
||||||
|
if err != nil {
|
||||||
|
// not a string list, legacy format?
|
||||||
|
var pwdConfig map[string]string
|
||||||
|
err = json5.Unmarshal(rawMsg, &pwdConfig)
|
||||||
|
if err != nil || len(pwdConfig["password"]) == 0 {
|
||||||
|
// still no, invalid config
|
||||||
|
return nil, errors.New("invalid config")
|
||||||
|
}
|
||||||
|
// yes it is
|
||||||
|
pwds = []string{pwdConfig["password"]}
|
||||||
|
}
|
||||||
|
return func(addr net.Addr, auth []byte, sSend uint64, sRecv uint64) (bool, string) {
|
||||||
|
for _, pwd := range pwds {
|
||||||
|
if string(auth) == pwd {
|
||||||
|
return true, "Welcome"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, "Wrong password"
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func externalAuthFunc(rawMsg json5.RawMessage) (core.ConnectFunc, error) {
|
||||||
|
var extConfig map[string]string
|
||||||
|
err := json5.Unmarshal(rawMsg, &extConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("invalid config")
|
||||||
|
}
|
||||||
|
if len(extConfig["http"]) != 0 {
|
||||||
|
hp := &auth.HTTPAuthProvider{
|
||||||
|
Client: &http.Client{
|
||||||
|
Timeout: 10 * time.Second,
|
||||||
|
},
|
||||||
|
URL: extConfig["http"],
|
||||||
|
}
|
||||||
|
return hp.Auth, nil
|
||||||
|
} else if len(extConfig["cmd"]) != 0 {
|
||||||
|
cp := &auth.CmdAuthProvider{
|
||||||
|
Cmd: extConfig["cmd"],
|
||||||
|
}
|
||||||
|
return cp.Auth, nil
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("invalid config")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func disconnectFunc(addr net.Addr, auth []byte, err error) {
|
func disconnectFunc(addr net.Addr, auth []byte, err error) {
|
||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
"src": addr,
|
"src": addr,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user