mirror of
https://github.com/cedar2025/hysteria.git
synced 2025-08-14 13:21:49 +00:00
feat: rework config handling code & add QR
This commit is contained in:
@@ -87,49 +87,50 @@ type serverConfigACME struct {
|
||||
Dir string `mapstructure:"dir"`
|
||||
}
|
||||
|
||||
// Config validates the fields and returns a ready-to-use Hysteria server config
|
||||
func (c *serverConfig) Config() (*server.Config, error) {
|
||||
hyConfig := &server.Config{}
|
||||
// Conn
|
||||
func (c *serverConfig) fillConn(hyConfig *server.Config) error {
|
||||
listenAddr := c.Listen
|
||||
if listenAddr == "" {
|
||||
listenAddr = ":443"
|
||||
}
|
||||
uAddr, err := net.ResolveUDPAddr("udp", listenAddr)
|
||||
if err != nil {
|
||||
return nil, configError{Field: "listen", Err: err}
|
||||
return configError{Field: "listen", Err: err}
|
||||
}
|
||||
conn, err := net.ListenUDP("udp", uAddr)
|
||||
if err != nil {
|
||||
return nil, configError{Field: "listen", Err: err}
|
||||
return configError{Field: "listen", Err: err}
|
||||
}
|
||||
switch strings.ToLower(c.Obfs.Type) {
|
||||
case "", "plain":
|
||||
hyConfig.Conn = conn
|
||||
return nil
|
||||
case "salamander":
|
||||
ob, err := obfs.NewSalamanderObfuscator([]byte(c.Obfs.Salamander.Password))
|
||||
if err != nil {
|
||||
return nil, configError{Field: "obfs.salamander.password", Err: err}
|
||||
return configError{Field: "obfs.salamander.password", Err: err}
|
||||
}
|
||||
hyConfig.Conn = obfs.WrapPacketConn(conn, ob)
|
||||
return nil
|
||||
default:
|
||||
return nil, configError{Field: "obfs.type", Err: errors.New("unsupported obfuscation type")}
|
||||
return configError{Field: "obfs.type", Err: errors.New("unsupported obfuscation type")}
|
||||
}
|
||||
// TLSConfig
|
||||
}
|
||||
|
||||
func (c *serverConfig) fillTLSConfig(hyConfig *server.Config) error {
|
||||
if c.TLS == nil && c.ACME == nil {
|
||||
return nil, configError{Field: "tls", Err: errors.New("must set either tls or acme")}
|
||||
return configError{Field: "tls", Err: errors.New("must set either tls or acme")}
|
||||
}
|
||||
if c.TLS != nil && c.ACME != nil {
|
||||
return nil, configError{Field: "tls", Err: errors.New("cannot set both tls and acme")}
|
||||
return configError{Field: "tls", Err: errors.New("cannot set both tls and acme")}
|
||||
}
|
||||
if c.TLS != nil {
|
||||
// Local TLS cert
|
||||
if c.TLS.Cert == "" || c.TLS.Key == "" {
|
||||
return nil, configError{Field: "tls", Err: errors.New("empty cert or key path")}
|
||||
return configError{Field: "tls", Err: errors.New("empty cert or key path")}
|
||||
}
|
||||
cert, err := tls.LoadX509KeyPair(c.TLS.Cert, c.TLS.Key)
|
||||
if err != nil {
|
||||
return nil, configError{Field: "tls", Err: err}
|
||||
return configError{Field: "tls", Err: err}
|
||||
}
|
||||
hyConfig.TLSConfig.Certificates = []tls.Certificate{cert}
|
||||
} else {
|
||||
@@ -160,7 +161,7 @@ func (c *serverConfig) Config() (*server.Config, error) {
|
||||
case "zerossl", "zero":
|
||||
cmIssuer.CA = certmagic.ZeroSSLProductionCA
|
||||
default:
|
||||
return nil, configError{Field: "acme.ca", Err: errors.New("unknown CA")}
|
||||
return configError{Field: "acme.ca", Err: errors.New("unknown CA")}
|
||||
}
|
||||
cmCfg.Issuers = []certmagic.Issuer{cmIssuer}
|
||||
cmCache := certmagic.NewCache(certmagic.CacheOptions{
|
||||
@@ -172,15 +173,18 @@ func (c *serverConfig) Config() (*server.Config, error) {
|
||||
cmCfg = certmagic.New(cmCache, *cmCfg)
|
||||
|
||||
if len(c.ACME.Domains) == 0 {
|
||||
return nil, configError{Field: "acme.domains", Err: errors.New("empty domains")}
|
||||
return configError{Field: "acme.domains", Err: errors.New("empty domains")}
|
||||
}
|
||||
err = cmCfg.ManageSync(context.Background(), c.ACME.Domains)
|
||||
err := cmCfg.ManageSync(context.Background(), c.ACME.Domains)
|
||||
if err != nil {
|
||||
return nil, configError{Field: "acme.domains", Err: err}
|
||||
return configError{Field: "acme.domains", Err: err}
|
||||
}
|
||||
hyConfig.TLSConfig.GetCertificate = cmCfg.GetCertificate
|
||||
}
|
||||
// QUICConfig
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *serverConfig) fillQUICConfig(hyConfig *server.Config) error {
|
||||
hyConfig.QUICConfig = server.QUICConfig{
|
||||
InitialStreamReceiveWindow: c.QUIC.InitStreamReceiveWindow,
|
||||
MaxStreamReceiveWindow: c.QUIC.MaxStreamReceiveWindow,
|
||||
@@ -190,52 +194,70 @@ func (c *serverConfig) Config() (*server.Config, error) {
|
||||
MaxIncomingStreams: c.QUIC.MaxIncomingStreams,
|
||||
DisablePathMTUDiscovery: c.QUIC.DisablePathMTUDiscovery,
|
||||
}
|
||||
// BandwidthConfig
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *serverConfig) fillBandwidthConfig(hyConfig *server.Config) error {
|
||||
var err error
|
||||
if c.Bandwidth.Up != "" {
|
||||
hyConfig.BandwidthConfig.MaxTx, err = convBandwidth(c.Bandwidth.Up)
|
||||
if err != nil {
|
||||
return nil, configError{Field: "bandwidth.up", Err: err}
|
||||
return configError{Field: "bandwidth.up", Err: err}
|
||||
}
|
||||
}
|
||||
if c.Bandwidth.Down != "" {
|
||||
hyConfig.BandwidthConfig.MaxRx, err = convBandwidth(c.Bandwidth.Down)
|
||||
if err != nil {
|
||||
return nil, configError{Field: "bandwidth.down", Err: err}
|
||||
return configError{Field: "bandwidth.down", Err: err}
|
||||
}
|
||||
}
|
||||
// DisableUDP
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *serverConfig) fillDisableUDP(hyConfig *server.Config) error {
|
||||
hyConfig.DisableUDP = c.DisableUDP
|
||||
// Authenticator
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *serverConfig) fillAuthenticator(hyConfig *server.Config) error {
|
||||
if c.Auth.Type == "" {
|
||||
return nil, configError{Field: "auth.type", Err: errors.New("empty auth type")}
|
||||
return configError{Field: "auth.type", Err: errors.New("empty auth type")}
|
||||
}
|
||||
switch strings.ToLower(c.Auth.Type) {
|
||||
case "password":
|
||||
if c.Auth.Password == "" {
|
||||
return nil, configError{Field: "auth.password", Err: errors.New("empty auth password")}
|
||||
return configError{Field: "auth.password", Err: errors.New("empty auth password")}
|
||||
}
|
||||
hyConfig.Authenticator = &auth.PasswordAuthenticator{Password: c.Auth.Password}
|
||||
return nil
|
||||
default:
|
||||
return nil, configError{Field: "auth.type", Err: errors.New("unsupported auth type")}
|
||||
return configError{Field: "auth.type", Err: errors.New("unsupported auth type")}
|
||||
}
|
||||
// EventLogger
|
||||
}
|
||||
|
||||
func (c *serverConfig) fillEventLogger(hyConfig *server.Config) error {
|
||||
hyConfig.EventLogger = &serverLogger{}
|
||||
// MasqHandler
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *serverConfig) fillMasqHandler(hyConfig *server.Config) error {
|
||||
switch strings.ToLower(c.Masquerade.Type) {
|
||||
case "", "404":
|
||||
hyConfig.MasqHandler = http.NotFoundHandler()
|
||||
return nil
|
||||
case "file":
|
||||
if c.Masquerade.File.Dir == "" {
|
||||
return nil, configError{Field: "masquerade.file.dir", Err: errors.New("empty file directory")}
|
||||
return configError{Field: "masquerade.file.dir", Err: errors.New("empty file directory")}
|
||||
}
|
||||
hyConfig.MasqHandler = http.FileServer(http.Dir(c.Masquerade.File.Dir))
|
||||
return nil
|
||||
case "proxy":
|
||||
if c.Masquerade.Proxy.URL == "" {
|
||||
return nil, configError{Field: "masquerade.proxy.url", Err: errors.New("empty proxy url")}
|
||||
return configError{Field: "masquerade.proxy.url", Err: errors.New("empty proxy url")}
|
||||
}
|
||||
u, err := url.Parse(c.Masquerade.Proxy.URL)
|
||||
if err != nil {
|
||||
return nil, configError{Field: "masquerade.proxy.url", Err: err}
|
||||
return configError{Field: "masquerade.proxy.url", Err: err}
|
||||
}
|
||||
hyConfig.MasqHandler = &httputil.ReverseProxy{
|
||||
Rewrite: func(r *httputil.ProxyRequest) {
|
||||
@@ -251,8 +273,29 @@ func (c *serverConfig) Config() (*server.Config, error) {
|
||||
w.WriteHeader(http.StatusBadGateway)
|
||||
},
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return nil, configError{Field: "masquerade.type", Err: errors.New("unsupported masquerade type")}
|
||||
return configError{Field: "masquerade.type", Err: errors.New("unsupported masquerade type")}
|
||||
}
|
||||
}
|
||||
|
||||
// Config validates the fields and returns a ready-to-use Hysteria server config
|
||||
func (c *serverConfig) Config() (*server.Config, error) {
|
||||
hyConfig := &server.Config{}
|
||||
fillers := []func(*server.Config) error{
|
||||
c.fillConn,
|
||||
c.fillTLSConfig,
|
||||
c.fillQUICConfig,
|
||||
c.fillBandwidthConfig,
|
||||
c.fillDisableUDP,
|
||||
c.fillAuthenticator,
|
||||
c.fillEventLogger,
|
||||
c.fillMasqHandler,
|
||||
}
|
||||
for _, f := range fillers {
|
||||
if err := f(hyConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return hyConfig, nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user