update config

This commit is contained in:
ginuerzh
2022-01-03 23:45:49 +08:00
parent 14537d16ea
commit 566e930010
42 changed files with 412 additions and 521 deletions

View File

@ -7,10 +7,11 @@ import (
"strings" "strings"
"github.com/go-gost/gost/pkg/config" "github.com/go-gost/gost/pkg/config"
"github.com/go-gost/gost/pkg/registry"
) )
var ( var (
ErrInvalidService = errors.New("invalid service") ErrInvalidCmd = errors.New("invalid cmd")
ErrInvalidNode = errors.New("invalid node") ErrInvalidNode = errors.New("invalid node")
) )
@ -36,32 +37,36 @@ func buildConfigFromCmd(services, nodes stringList) (*config.Config, error) {
} }
for i, node := range nodes { for i, node := range nodes {
url, err := checkCmd(node) url, err := normCmd(node)
if err != nil { if err != nil {
return nil, err return nil, err
} }
nodeConfig, err := buildNodeConfig(url)
if err != nil {
return nil, err
}
nodeConfig.Name = "node-0"
chain.Hops = append(chain.Hops, &config.HopConfig{ chain.Hops = append(chain.Hops, &config.HopConfig{
Name: fmt.Sprintf("hop-%d", i), Name: fmt.Sprintf("hop-%d", i),
Nodes: []*config.NodeConfig{ Nodes: []*config.NodeConfig{nodeConfig},
{
Name: "node-0",
URL: url,
},
},
}) })
} }
for i, svc := range services { for i, svc := range services {
url, err := checkCmd(svc) url, err := normCmd(svc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
service := &config.ServiceConfig{
Name: fmt.Sprintf("service-%d", i), service, err := buildServiceConfig(url)
URL: url, if err != nil {
return nil, err
} }
service.Name = fmt.Sprintf("service-%d", i)
if chain != nil { if chain != nil {
service.Chain = chain.Name service.Handler.Chain = chain.Name
} }
cfg.Services = append(cfg.Services, service) cfg.Services = append(cfg.Services, service)
} }
@ -69,20 +74,140 @@ func buildConfigFromCmd(services, nodes stringList) (*config.Config, error) {
return cfg, nil return cfg, nil
} }
func checkCmd(s string) (string, error) { func buildServiceConfig(url *url.URL) (*config.ServiceConfig, error) {
var handler, listener string
schemes := strings.Split(url.Scheme, "+")
if len(schemes) == 1 {
handler = schemes[0]
listener = schemes[0]
}
if len(schemes) == 2 {
handler = schemes[0]
listener = schemes[1]
}
svc := &config.ServiceConfig{
Addr: url.Host,
}
if h := registry.GetHandler(handler); h == nil {
handler = "auto"
}
if ln := registry.GetListener(listener); ln == nil {
listener = "tcp"
if handler == "ssu" {
listener = "udp"
}
}
if remotes := strings.Trim(url.EscapedPath(), "/"); remotes != "" {
svc.Forwarder = &config.ForwarderConfig{
Targets: strings.Split(remotes, ","),
}
if handler != "relay" {
if listener == "tcp" || listener == "udp" ||
listener == "rtcp" || listener == "rudp" ||
listener == "tun" || listener == "tap" {
handler = listener
} else {
handler = "tcp"
}
}
}
md := make(map[string]interface{})
for k, v := range url.Query() {
if len(v) > 0 {
md[k] = v[0]
}
}
var auths []config.AuthConfig
if url.User != nil {
auth := config.AuthConfig{
Username: url.User.Username(),
}
auth.Password, _ = url.User.Password()
auths = append(auths, auth)
}
svc.Handler = &config.HandlerConfig{
Type: handler,
Auths: auths,
Metadata: md,
}
svc.Listener = &config.ListenerConfig{
Type: listener,
Metadata: md,
}
return svc, nil
}
func buildNodeConfig(url *url.URL) (*config.NodeConfig, error) {
var connector, dialer string
schemes := strings.Split(url.Scheme, "+")
if len(schemes) == 1 {
connector = schemes[0]
dialer = schemes[0]
}
if len(schemes) == 2 {
connector = schemes[0]
dialer = schemes[1]
}
node := &config.NodeConfig{
Addr: url.Host,
}
if c := registry.GetConnector(connector); c == nil {
connector = "http"
}
if d := registry.GetDialer(dialer); d == nil {
dialer = "tcp"
if connector == "ssu" {
dialer = "udp"
}
}
md := make(map[string]interface{})
for k, v := range url.Query() {
if len(v) > 0 {
md[k] = v[0]
}
}
md["serverName"] = url.Host
var auth *config.AuthConfig
if url.User != nil {
auth = &config.AuthConfig{
Username: url.User.Username(),
}
auth.Password, _ = url.User.Password()
}
node.Connector = &config.ConnectorConfig{
Type: connector,
Auth: auth,
Metadata: md,
}
node.Dialer = &config.DialerConfig{
Type: dialer,
Metadata: md,
}
return node, nil
}
func normCmd(s string) (*url.URL, error) {
s = strings.TrimSpace(s) s = strings.TrimSpace(s)
if s == "" { if s == "" {
return "", ErrInvalidService return nil, ErrInvalidCmd
} }
if !strings.Contains(s, "://") { if !strings.Contains(s, "://") {
s = "auto://" + s s = "auto://" + s
} }
u, err := url.Parse(s) return url.Parse(s)
if err != nil {
return "", err
}
return u.String(), nil
} }

View File

@ -3,9 +3,11 @@ package main
import ( import (
"io" "io"
"net" "net"
"net/url"
"os" "os"
"strings" "strings"
"github.com/go-gost/gost/pkg/auth"
"github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/bypass"
"github.com/go-gost/gost/pkg/chain" "github.com/go-gost/gost/pkg/chain"
"github.com/go-gost/gost/pkg/config" "github.com/go-gost/gost/pkg/config"
@ -54,12 +56,14 @@ func buildService(cfg *config.Config) (services []*service.Service) {
} }
for _, svc := range cfg.Services { for _, svc := range cfg.Services {
if svc.Listener == nil || svc.Handler == nil {
continue
}
serviceLogger := log.WithFields(map[string]interface{}{ serviceLogger := log.WithFields(map[string]interface{}{
"kind": "service", "kind": "service",
"service": svc.Name, "service": svc.Name,
"listener": svc.Listener.Type, "listener": svc.Listener.Type,
"handler": svc.Handler.Type, "handler": svc.Handler.Type,
"chain": svc.Chain,
}) })
listenerLogger := serviceLogger.WithFields(map[string]interface{}{ listenerLogger := serviceLogger.WithFields(map[string]interface{}{
@ -67,11 +71,12 @@ func buildService(cfg *config.Config) (services []*service.Service) {
}) })
ln := registry.GetListener(svc.Listener.Type)( ln := registry.GetListener(svc.Listener.Type)(
listener.AddrOption(svc.Addr), listener.AddrOption(svc.Addr),
listener.AuthenticatorOption(authFromConfig(svc.Listener.Auths...)),
listener.LoggerOption(listenerLogger), listener.LoggerOption(listenerLogger),
) )
if chainable, ok := ln.(chain.Chainable); ok { if chainable, ok := ln.(chain.Chainable); ok {
chainable.WithChain(chains[svc.Chain]) chainable.WithChain(chains[svc.Listener.Chain])
} }
if svc.Listener.Metadata == nil { if svc.Listener.Metadata == nil {
@ -86,12 +91,13 @@ func buildService(cfg *config.Config) (services []*service.Service) {
}) })
h := registry.GetHandler(svc.Handler.Type)( h := registry.GetHandler(svc.Handler.Type)(
handler.BypassOption(bypasses[svc.Bypass]),
handler.LoggerOption(handlerLogger), handler.LoggerOption(handlerLogger),
handler.BypassOption(bypasses[svc.Handler.Bypass]),
handler.AuthenticatorOption(authFromConfig(svc.Handler.Auths...)),
handler.RouterOption(&chain.Router{ handler.RouterOption(&chain.Router{
Chain: chains[svc.Chain], Chain: chains[svc.Handler.Chain],
Resolver: resolvers[svc.Resolver], Resolver: resolvers[svc.Handler.Resolver],
Hosts: hosts[svc.Hosts], Hosts: hosts[svc.Handler.Hosts],
Logger: handlerLogger, Logger: handlerLogger,
}), }),
) )
@ -134,14 +140,27 @@ func chainFromConfig(cfg *config.ChainConfig) *chain.Chain {
for _, hop := range cfg.Hops { for _, hop := range cfg.Hops {
group := &chain.NodeGroup{} group := &chain.NodeGroup{}
for _, v := range hop.Nodes { for _, v := range hop.Nodes {
connectorLogger := chainLogger.WithFields(map[string]interface{}{ nodeLogger := chainLogger.WithFields(map[string]interface{}{
"kind": "connector", "kind": "node",
"connector": v.Connector.Type, "connector": v.Connector.Type,
"dialer": v.Dialer.Type, "dialer": v.Dialer.Type,
"hop": hop.Name, "hop": hop.Name,
"node": v.Name, "node": v.Name,
}) })
connectorLogger := nodeLogger.WithFields(map[string]interface{}{
"kind": "connector",
})
var connectorUser *url.Userinfo
if auth := v.Connector.Auth; auth != nil && auth.Username != "" {
if auth.Password == "" {
connectorUser = url.User(auth.Username)
} else {
connectorUser = url.UserPassword(auth.Username, auth.Password)
}
}
cr := registry.GetConnector(v.Connector.Type)( cr := registry.GetConnector(v.Connector.Type)(
connector.UserOption(connectorUser),
connector.LoggerOption(connectorLogger), connector.LoggerOption(connectorLogger),
) )
@ -152,14 +171,20 @@ func chainFromConfig(cfg *config.ChainConfig) *chain.Chain {
connectorLogger.Fatal("init: ", err) connectorLogger.Fatal("init: ", err)
} }
dialerLogger := chainLogger.WithFields(map[string]interface{}{ dialerLogger := nodeLogger.WithFields(map[string]interface{}{
"kind": "dialer", "kind": "dialer",
"connector": v.Connector.Type,
"dialer": v.Dialer.Type,
"hop": hop.Name,
"node": v.Name,
}) })
var dialerUser *url.Userinfo
if auth := v.Dialer.Auth; auth != nil && auth.Username != "" {
if auth.Password == "" {
dialerUser = url.User(auth.Username)
} else {
dialerUser = url.UserPassword(auth.Username, auth.Password)
}
}
d := registry.GetDialer(v.Dialer.Type)( d := registry.GetDialer(v.Dialer.Type)(
dialer.UserOption(dialerUser),
dialer.LoggerOption(dialerLogger), dialer.LoggerOption(dialerLogger),
) )
@ -305,3 +330,18 @@ func hostsFromConfig(cfg *config.HostsConfig) hostspkg.HostMapper {
} }
return hosts return hosts
} }
func authFromConfig(cfgs ...config.AuthConfig) auth.Authenticator {
auths := make(map[string]string)
for _, cfg := range cfgs {
if cfg.Username == "" {
continue
}
auths[cfg.Username] = cfg.Password
}
if len(auths) > 0 {
return auth.NewMapAuthenticator(auths)
}
return nil
}

View File

@ -63,8 +63,6 @@ func main() {
log.Fatal(err) log.Fatal(err)
} }
normConfig(cfg)
log = logFromConfig(cfg.Log) log = logFromConfig(cfg.Log)
if outputCfgFile != "" { if outputCfgFile != "" {

View File

@ -1,139 +0,0 @@
package main
import (
"net/url"
"strings"
"github.com/go-gost/gost/pkg/config"
"github.com/go-gost/gost/pkg/registry"
)
// normConfig normalizes the config.
func normConfig(cfg *config.Config) {
for _, svc := range cfg.Services {
normService(svc)
}
for _, chain := range cfg.Chains {
normChain(chain)
}
}
func normService(svc *config.ServiceConfig) {
if svc.URL == "" {
return
}
u, _ := url.Parse(svc.URL)
var handler, listener string
schemes := strings.Split(u.Scheme, "+")
if len(schemes) == 1 {
handler = schemes[0]
listener = schemes[0]
}
if len(schemes) == 2 {
handler = schemes[0]
listener = schemes[1]
}
md := make(map[string]interface{})
for k, v := range u.Query() {
if len(v) > 0 {
md[k] = v[0]
}
}
if u.User != nil {
md["users"] = []interface{}{u.User.String()}
}
svc.Addr = u.Host
if h := registry.GetHandler(handler); h == nil {
handler = "auto"
}
if ln := registry.GetListener(listener); ln == nil {
listener = "tcp"
if handler == "ssu" {
listener = "udp"
}
}
if remotes := strings.Trim(u.EscapedPath(), "/"); remotes != "" {
svc.Forwarder = &config.ForwarderConfig{
Targets: strings.Split(remotes, ","),
}
if handler != "relay" {
if listener == "tcp" || listener == "udp" ||
listener == "rtcp" || listener == "rudp" ||
listener == "tun" || listener == "tap" {
handler = listener
} else {
handler = "tcp"
}
}
}
svc.Handler = &config.HandlerConfig{
Type: handler,
Metadata: md,
}
svc.Listener = &config.ListenerConfig{
Type: listener,
Metadata: md,
}
}
func normChain(chain *config.ChainConfig) {
for _, hop := range chain.Hops {
for _, node := range hop.Nodes {
if node.URL == "" {
continue
}
u, _ := url.Parse(node.URL)
var connector, dialer string
schemes := strings.Split(u.Scheme, "+")
if len(schemes) == 1 {
connector = schemes[0]
dialer = schemes[0]
}
if len(schemes) == 2 {
connector = schemes[0]
dialer = schemes[1]
}
md := make(map[string]interface{})
for k, v := range u.Query() {
if len(v) > 0 {
md[k] = v[0]
}
}
if u.User != nil {
md["user"] = u.User.String()
}
md["serverName"] = u.Host
node.Addr = u.Host
if c := registry.GetConnector(connector); c == nil {
connector = "http"
}
if d := registry.GetDialer(dialer); d == nil {
dialer = "tcp"
if connector == "ssu" {
dialer = "udp"
}
}
node.Connector = &config.ConnectorConfig{
Type: connector,
Metadata: md,
}
node.Dialer = &config.DialerConfig{
Type: dialer,
Metadata: md,
}
}
}
}

View File

@ -7,13 +7,12 @@ services:
- name: http+tcp - name: http+tcp
url: "http://gost:gost@:8000" url: "http://gost:gost@:8000"
addr: ":28000" addr: ":28000"
chain: chain01
# bypass: bypass01
handler: handler:
type: http type: http
chain: chain01
# bypass: bypass01
metadata: metadata:
proxyAgent: "gost/3.0" proxyAgent: "gost/3.0"
retry: 3
auths: auths:
- user1:pass1 - user1:pass1
- user2:pass2 - user2:pass2
@ -26,10 +25,10 @@ services:
- name: ss - name: ss
url: "ss://chacha20:gost@:8000" url: "ss://chacha20:gost@:8000"
addr: ":28338" addr: ":28338"
# chain: chain01
# bypass: bypass01
handler: handler:
type: ss type: ss
# chain: chain01
# bypass: bypass01
metadata: metadata:
method: chacha20-ietf method: chacha20-ietf
password: gost password: gost
@ -43,10 +42,10 @@ services:
- name: socks5 - name: socks5
url: "socks5://gost:gost@:1080" url: "socks5://gost:gost@:1080"
addr: ":21080" addr: ":21080"
# chain: chain-ss
# bypass: bypass01
handler: handler:
type: socks5 type: socks5
# chain: chain-ss
# bypass: bypass01
metadata: metadata:
auths: auths:
- gost:gost - gost:gost
@ -112,7 +111,6 @@ services:
- name: rtcp - name: rtcp
addr: ":28100" addr: ":28100"
# chain: chain-socks5
forwarder: forwarder:
targets: targets:
- 192.168.8.8:80 - 192.168.8.8:80
@ -122,6 +120,7 @@ services:
readTimeout: 5s readTimeout: 5s
listener: listener:
type: rtcp type: rtcp
# chain: chain-socks5
metadata: metadata:
keepAlive: 15s keepAlive: 15s
mux: true mux: true
@ -318,21 +317,6 @@ hosts:
- bar - bar
- baz - baz
probeResistance:
- name: pr-code404
type: code
value: 404
knock: www.example.com
- name: pr-web
type: web
value: http://example.com/page.html
- name: pr-host
type: host
value: example.com:80
- name: pr-file
type: file
value: /path/to/file
profiling: profiling:
addr: ":6060" addr: ":6060"
enabled: true enabled: true

View File

@ -6,22 +6,22 @@ type Authenticator interface {
} }
// LocalAuthenticator is an Authenticator that authenticates client by local key-value pairs. // LocalAuthenticator is an Authenticator that authenticates client by local key-value pairs.
type LocalAuthenticator struct { type MapAuthenticator struct {
kvs map[string]string kvs map[string]string
} }
// NewLocalAuthenticator creates an Authenticator that authenticates client by local infos. // NewMapAuthenticator creates an Authenticator that authenticates client by local infos.
func NewLocalAuthenticator(kvs map[string]string) *LocalAuthenticator { func NewMapAuthenticator(kvs map[string]string) *MapAuthenticator {
if kvs == nil { if kvs == nil {
kvs = make(map[string]string) kvs = make(map[string]string)
} }
return &LocalAuthenticator{ return &MapAuthenticator{
kvs: kvs, kvs: kvs,
} }
} }
// Authenticate checks the validity of the provided user-password pair. // Authenticate checks the validity of the provided user-password pair.
func (au *LocalAuthenticator) Authenticate(user, password string) bool { func (au *MapAuthenticator) Authenticate(user, password string) bool {
if au == nil { if au == nil {
return true return true
} }
@ -33,8 +33,3 @@ func (au *LocalAuthenticator) Authenticate(user, password string) bool {
v, ok := au.kvs[user] v, ok := au.kvs[user]
return ok && (v == "" || password == v) return ok && (v == "" || password == v)
} }
// Add adds a key-value pair to the Authenticator.
func (au *LocalAuthenticator) Add(k, v string) {
au.kvs[k] = v
}

View File

@ -36,6 +36,11 @@ type TLSConfig struct {
CA string CA string
} }
type AuthConfig struct {
Username string
Password string
}
type SelectorConfig struct { type SelectorConfig struct {
Strategy string Strategy string
MaxFails int MaxFails int
@ -76,11 +81,18 @@ type HostsConfig struct {
type ListenerConfig struct { type ListenerConfig struct {
Type string Type string
Chain string `yaml:",omitempty"`
Auths []AuthConfig `yaml:",omitempty"`
Metadata map[string]interface{} `yaml:",omitempty"` Metadata map[string]interface{} `yaml:",omitempty"`
} }
type HandlerConfig struct { type HandlerConfig struct {
Type string Type string
Chain string `yaml:",omitempty"`
Bypass string `yaml:",omitempty"`
Resolver string `yaml:",omitempty"`
Hosts string `yaml:",omitempty"`
Auths []AuthConfig `yaml:",omitempty"`
Metadata map[string]interface{} `yaml:",omitempty"` Metadata map[string]interface{} `yaml:",omitempty"`
} }
@ -91,24 +103,21 @@ type ForwarderConfig struct {
type DialerConfig struct { type DialerConfig struct {
Type string Type string
Auth *AuthConfig `yaml:",omitempty"`
Metadata map[string]interface{} `yaml:",omitempty"` Metadata map[string]interface{} `yaml:",omitempty"`
} }
type ConnectorConfig struct { type ConnectorConfig struct {
Type string Type string
Auth *AuthConfig `yaml:",omitempty"`
Metadata map[string]interface{} `yaml:",omitempty"` Metadata map[string]interface{} `yaml:",omitempty"`
} }
type ServiceConfig struct { type ServiceConfig struct {
Name string Name string
URL string `yaml:",omitempty"`
Addr string `yaml:",omitempty"` Addr string `yaml:",omitempty"`
Chain string `yaml:",omitempty"`
Bypass string `yaml:",omitempty"`
Resolver string `yaml:",omitempty"`
Hosts string `yaml:",omitempty"`
Listener *ListenerConfig `yaml:",omitempty"`
Handler *HandlerConfig `yaml:",omitempty"` Handler *HandlerConfig `yaml:",omitempty"`
Listener *ListenerConfig `yaml:",omitempty"`
Forwarder *ForwarderConfig `yaml:",omitempty"` Forwarder *ForwarderConfig `yaml:",omitempty"`
} }
@ -126,7 +135,6 @@ type HopConfig struct {
type NodeConfig struct { type NodeConfig struct {
Name string Name string
URL string `yaml:",omitempty"`
Addr string `yaml:",omitempty"` Addr string `yaml:",omitempty"`
Dialer *DialerConfig `yaml:",omitempty"` Dialer *DialerConfig `yaml:",omitempty"`
Connector *ConnectorConfig `yaml:",omitempty"` Connector *ConnectorConfig `yaml:",omitempty"`
@ -134,14 +142,14 @@ type NodeConfig struct {
} }
type Config struct { type Config struct {
Log *LogConfig `yaml:",omitempty"` Services []*ServiceConfig
Profiling *ProfilingConfig `yaml:",omitempty"` Chains []*ChainConfig `yaml:",omitempty"`
TLS *TLSConfig `yaml:",omitempty"`
Bypasses []*BypassConfig `yaml:",omitempty"` Bypasses []*BypassConfig `yaml:",omitempty"`
Resolvers []*ResolverConfig `yaml:",omitempty"` Resolvers []*ResolverConfig `yaml:",omitempty"`
Hosts []*HostsConfig `yaml:",omitempty"` Hosts []*HostsConfig `yaml:",omitempty"`
Chains []*ChainConfig `yaml:",omitempty"` TLS *TLSConfig `yaml:",omitempty"`
Services []*ServiceConfig Log *LogConfig `yaml:",omitempty"`
Profiling *ProfilingConfig `yaml:",omitempty"`
} }
func (c *Config) Load() error { func (c *Config) Load() error {

View File

@ -23,6 +23,7 @@ func init() {
} }
type httpConnector struct { type httpConnector struct {
user *url.Userinfo
md metadata md metadata
logger logger.Logger logger logger.Logger
} }
@ -34,6 +35,7 @@ func NewConnector(opts ...connector.Option) connector.Connector {
} }
return &httpConnector{ return &httpConnector{
user: options.User,
logger: options.Logger, logger: options.Logger,
} }
} }
@ -65,7 +67,7 @@ func (c *httpConnector) Connect(ctx context.Context, conn net.Conn, network, add
} }
req.Header.Set("Proxy-Connection", "keep-alive") req.Header.Set("Proxy-Connection", "keep-alive")
if user := c.md.User; user != nil { if user := c.user; user != nil {
u := user.Username() u := user.Username()
p, _ := user.Password() p, _ := user.Password()
req.Header.Set("Proxy-Authorization", req.Header.Set("Proxy-Authorization",

View File

@ -2,8 +2,6 @@ package http
import ( import (
"net/http" "net/http"
"net/url"
"strings"
"time" "time"
mdata "github.com/go-gost/gost/pkg/metadata" mdata "github.com/go-gost/gost/pkg/metadata"
@ -11,7 +9,6 @@ import (
type metadata struct { type metadata struct {
connectTimeout time.Duration connectTimeout time.Duration
User *url.Userinfo
header http.Header header http.Header
} }
@ -24,15 +21,6 @@ func (c *httpConnector) parseMetadata(md mdata.Metadata) (err error) {
c.md.connectTimeout = mdata.GetDuration(md, connectTimeout) c.md.connectTimeout = mdata.GetDuration(md, connectTimeout)
if v := mdata.GetString(md, user); v != "" {
ss := strings.SplitN(v, ":", 2)
if len(ss) == 1 {
c.md.User = url.User(ss[0])
} else {
c.md.User = url.UserPassword(ss[0], ss[1])
}
}
if mm := mdata.GetStringMapString(md, header); len(mm) > 0 { if mm := mdata.GetStringMapString(md, header); len(mm) > 0 {
hd := http.Header{} hd := http.Header{}
for k, v := range mm { for k, v := range mm {

View File

@ -24,6 +24,7 @@ func init() {
} }
type http2Connector struct { type http2Connector struct {
user *url.Userinfo
md metadata md metadata
logger logger.Logger logger logger.Logger
} }
@ -35,6 +36,7 @@ func NewConnector(opts ...connector.Option) connector.Connector {
} }
return &http2Connector{ return &http2Connector{
user: options.User,
logger: options.Logger, logger: options.Logger,
} }
} }
@ -74,7 +76,7 @@ func (c *http2Connector) Connect(ctx context.Context, conn net.Conn, network, ad
req.Header.Set("User-Agent", c.md.UserAgent) req.Header.Set("User-Agent", c.md.UserAgent)
} }
if user := c.md.User; user != nil { if user := c.user; user != nil {
u := user.Username() u := user.Username()
p, _ := user.Password() p, _ := user.Password()
req.Header.Set("Proxy-Authorization", req.Header.Set("Proxy-Authorization",

View File

@ -1,8 +1,6 @@
package http2 package http2
import ( import (
"net/url"
"strings"
"time" "time"
mdata "github.com/go-gost/gost/pkg/metadata" mdata "github.com/go-gost/gost/pkg/metadata"
@ -15,14 +13,12 @@ const (
type metadata struct { type metadata struct {
connectTimeout time.Duration connectTimeout time.Duration
UserAgent string UserAgent string
User *url.Userinfo
} }
func (c *http2Connector) parseMetadata(md mdata.Metadata) (err error) { func (c *http2Connector) parseMetadata(md mdata.Metadata) (err error) {
const ( const (
connectTimeout = "timeout" connectTimeout = "timeout"
userAgent = "userAgent" userAgent = "userAgent"
user = "user"
) )
c.md.connectTimeout = mdata.GetDuration(md, connectTimeout) c.md.connectTimeout = mdata.GetDuration(md, connectTimeout)
@ -31,14 +27,5 @@ func (c *http2Connector) parseMetadata(md mdata.Metadata) (err error) {
c.md.UserAgent = defaultUserAgent c.md.UserAgent = defaultUserAgent
} }
if v := mdata.GetString(md, user); v != "" {
ss := strings.SplitN(v, ":", 2)
if len(ss) == 1 {
c.md.User = url.User(ss[0])
} else {
c.md.User = url.UserPassword(ss[0], ss[1])
}
}
return return
} }

View File

@ -1,17 +1,25 @@
package connector package connector
import ( import (
"net/url"
"time" "time"
"github.com/go-gost/gost/pkg/logger" "github.com/go-gost/gost/pkg/logger"
) )
type Options struct { type Options struct {
User *url.Userinfo
Logger logger.Logger Logger logger.Logger
} }
type Option func(opts *Options) type Option func(opts *Options)
func UserOption(user *url.Userinfo) Option {
return func(opts *Options) {
opts.User = user
}
}
func LoggerOption(logger logger.Logger) Option { func LoggerOption(logger logger.Logger) Option {
return func(opts *Options) { return func(opts *Options) {
opts.Logger = logger opts.Logger = logger

View File

@ -79,10 +79,10 @@ func (c *relayConnector) bind(conn net.Conn, cmd uint8, network, address string)
Flags: cmd, Flags: cmd,
} }
if c.md.user != nil { if c.user != nil {
pwd, _ := c.md.user.Password() pwd, _ := c.user.Password()
req.Features = append(req.Features, &relay.UserAuthFeature{ req.Features = append(req.Features, &relay.UserAuthFeature{
Username: c.md.user.Username(), Username: c.user.Username(),
Password: pwd, Password: pwd,
}) })
} }

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"net" "net"
"net/url"
"time" "time"
"github.com/go-gost/gost/pkg/common/util/socks" "github.com/go-gost/gost/pkg/common/util/socks"
@ -19,6 +20,7 @@ func init() {
} }
type relayConnector struct { type relayConnector struct {
user *url.Userinfo
logger logger.Logger logger logger.Logger
md metadata md metadata
} }
@ -30,6 +32,7 @@ func NewConnector(opts ...connector.Option) connector.Connector {
} }
return &relayConnector{ return &relayConnector{
user: options.User,
logger: options.Logger, logger: options.Logger,
} }
} }
@ -71,10 +74,10 @@ func (c *relayConnector) Connect(ctx context.Context, conn net.Conn, network, ad
} }
} }
if c.md.user != nil { if c.user != nil {
pwd, _ := c.md.user.Password() pwd, _ := c.user.Password()
req.Features = append(req.Features, &relay.UserAuthFeature{ req.Features = append(req.Features, &relay.UserAuthFeature{
Username: c.md.user.Username(), Username: c.user.Username(),
Password: pwd, Password: pwd,
}) })
} }

View File

@ -1,8 +1,6 @@
package relay package relay
import ( import (
"net/url"
"strings"
"time" "time"
mdata "github.com/go-gost/gost/pkg/metadata" mdata "github.com/go-gost/gost/pkg/metadata"
@ -10,25 +8,15 @@ import (
type metadata struct { type metadata struct {
connectTimeout time.Duration connectTimeout time.Duration
user *url.Userinfo
noDelay bool noDelay bool
} }
func (c *relayConnector) parseMetadata(md mdata.Metadata) (err error) { func (c *relayConnector) parseMetadata(md mdata.Metadata) (err error) {
const ( const (
user = "user"
connectTimeout = "connectTimeout" connectTimeout = "connectTimeout"
noDelay = "nodelay" noDelay = "nodelay"
) )
if v := mdata.GetString(md, user); v != "" {
ss := strings.SplitN(v, ":", 2)
if len(ss) == 1 {
c.md.user = url.User(ss[0])
} else {
c.md.user = url.UserPassword(ss[0], ss[1])
}
}
c.md.connectTimeout = mdata.GetDuration(md, connectTimeout) c.md.connectTimeout = mdata.GetDuration(md, connectTimeout)
c.md.noDelay = mdata.GetBool(md, noDelay) c.md.noDelay = mdata.GetBool(md, noDelay)

View File

@ -5,6 +5,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"net" "net"
"net/url"
"strconv" "strconv"
"time" "time"
@ -21,6 +22,7 @@ func init() {
} }
type socks4Connector struct { type socks4Connector struct {
user *url.Userinfo
md metadata md metadata
logger logger.Logger logger logger.Logger
} }
@ -32,6 +34,7 @@ func NewConnector(opts ...connector.Option) connector.Connector {
} }
return &socks4Connector{ return &socks4Connector{
user: options.User,
logger: options.Logger, logger: options.Logger,
} }
} }
@ -96,7 +99,11 @@ func (c *socks4Connector) Connect(ctx context.Context, conn net.Conn, network, a
defer conn.SetDeadline(time.Time{}) defer conn.SetDeadline(time.Time{})
} }
req := gosocks4.NewRequest(gosocks4.CmdConnect, addr, nil) var userid []byte
if c.user != nil && c.user.Username() != "" {
userid = []byte(c.user.Username())
}
req := gosocks4.NewRequest(gosocks4.CmdConnect, addr, userid)
if err := req.Write(conn); err != nil { if err := req.Write(conn); err != nil {
c.logger.Error(err) c.logger.Error(err)
return nil, err return nil, err

View File

@ -1,7 +1,6 @@
package v4 package v4
import ( import (
"net/url"
"time" "time"
mdata "github.com/go-gost/gost/pkg/metadata" mdata "github.com/go-gost/gost/pkg/metadata"
@ -9,20 +8,15 @@ import (
type metadata struct { type metadata struct {
connectTimeout time.Duration connectTimeout time.Duration
User *url.Userinfo
disable4a bool disable4a bool
} }
func (c *socks4Connector) parseMetadata(md mdata.Metadata) (err error) { func (c *socks4Connector) parseMetadata(md mdata.Metadata) (err error) {
const ( const (
connectTimeout = "timeout" connectTimeout = "timeout"
user = "user"
disable4a = "disable4a" disable4a = "disable4a"
) )
if v := mdata.GetString(md, user); v != "" {
c.md.User = url.User(v)
}
c.md.connectTimeout = mdata.GetDuration(md, connectTimeout) c.md.connectTimeout = mdata.GetDuration(md, connectTimeout)
c.md.disable4a = mdata.GetBool(md, disable4a) c.md.disable4a = mdata.GetBool(md, disable4a)

View File

@ -6,6 +6,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"net" "net"
"net/url"
"time" "time"
"github.com/go-gost/gosocks5" "github.com/go-gost/gosocks5"
@ -23,6 +24,7 @@ func init() {
type socks5Connector struct { type socks5Connector struct {
selector gosocks5.Selector selector gosocks5.Selector
user *url.Userinfo
logger logger.Logger logger logger.Logger
md metadata md metadata
} }
@ -34,6 +36,7 @@ func NewConnector(opts ...connector.Option) connector.Connector {
} }
return &socks5Connector{ return &socks5Connector{
user: options.User,
logger: options.Logger, logger: options.Logger,
} }
} }
@ -49,7 +52,7 @@ func (c *socks5Connector) Init(md md.Metadata) (err error) {
gosocks5.MethodUserPass, gosocks5.MethodUserPass,
}, },
logger: c.logger, logger: c.logger,
User: c.md.User, User: c.user,
TLSConfig: c.md.tlsConfig, TLSConfig: c.md.tlsConfig,
} }
if !c.md.noTLS { if !c.md.noTLS {

View File

@ -2,8 +2,6 @@ package v5
import ( import (
"crypto/tls" "crypto/tls"
"net/url"
"strings"
"time" "time"
mdata "github.com/go-gost/gost/pkg/metadata" mdata "github.com/go-gost/gost/pkg/metadata"
@ -11,7 +9,6 @@ import (
type metadata struct { type metadata struct {
connectTimeout time.Duration connectTimeout time.Duration
User *url.Userinfo
tlsConfig *tls.Config tlsConfig *tls.Config
noTLS bool noTLS bool
} }
@ -19,19 +16,9 @@ type metadata struct {
func (c *socks5Connector) parseMetadata(md mdata.Metadata) (err error) { func (c *socks5Connector) parseMetadata(md mdata.Metadata) (err error) {
const ( const (
connectTimeout = "timeout" connectTimeout = "timeout"
user = "user"
noTLS = "notls" noTLS = "notls"
) )
if v := mdata.GetString(md, user); v != "" {
ss := strings.SplitN(v, ":", 2)
if len(ss) == 1 {
c.md.User = url.User(ss[0])
} else {
c.md.User = url.UserPassword(ss[0], ss[1])
}
}
c.md.connectTimeout = mdata.GetDuration(md, connectTimeout) c.md.connectTimeout = mdata.GetDuration(md, connectTimeout)
c.md.noTLS = mdata.GetBool(md, noTLS) c.md.noTLS = mdata.GetBool(md, noTLS)

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"net" "net"
"net/url"
"time" "time"
"github.com/go-gost/gosocks5" "github.com/go-gost/gosocks5"
@ -13,6 +14,7 @@ import (
"github.com/go-gost/gost/pkg/logger" "github.com/go-gost/gost/pkg/logger"
md "github.com/go-gost/gost/pkg/metadata" md "github.com/go-gost/gost/pkg/metadata"
"github.com/go-gost/gost/pkg/registry" "github.com/go-gost/gost/pkg/registry"
"github.com/shadowsocks/go-shadowsocks2/core"
) )
func init() { func init() {
@ -20,6 +22,8 @@ func init() {
} }
type ssConnector struct { type ssConnector struct {
user *url.Userinfo
cipher core.Cipher
md metadata md metadata
logger logger.Logger logger logger.Logger
} }
@ -31,12 +35,23 @@ func NewConnector(opts ...connector.Option) connector.Connector {
} }
return &ssConnector{ return &ssConnector{
user: options.User,
logger: options.Logger, logger: options.Logger,
} }
} }
func (c *ssConnector) Init(md md.Metadata) (err error) { func (c *ssConnector) Init(md md.Metadata) (err error) {
return c.parseMetadata(md) if err = c.parseMetadata(md); err != nil {
return
}
if c.user != nil {
method := c.user.Username()
password, _ := c.user.Password()
c.cipher, err = ss.ShadowCipher(method, password, c.md.key)
}
return
} }
func (c *ssConnector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) { func (c *ssConnector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
@ -80,8 +95,8 @@ func (c *ssConnector) Connect(ctx context.Context, conn net.Conn, network, addre
defer conn.SetDeadline(time.Time{}) defer conn.SetDeadline(time.Time{})
} }
if c.md.cipher != nil { if c.cipher != nil {
conn = c.md.cipher.StreamConn(conn) conn = c.cipher.StreamConn(conn)
} }
var sc net.Conn var sc net.Conn

View File

@ -1,42 +1,25 @@
package ss package ss
import ( import (
"strings"
"time" "time"
"github.com/go-gost/gost/pkg/common/util/ss"
mdata "github.com/go-gost/gost/pkg/metadata" mdata "github.com/go-gost/gost/pkg/metadata"
"github.com/shadowsocks/go-shadowsocks2/core"
) )
type metadata struct { type metadata struct {
cipher core.Cipher key string
connectTimeout time.Duration connectTimeout time.Duration
noDelay bool noDelay bool
} }
func (c *ssConnector) parseMetadata(md mdata.Metadata) (err error) { func (c *ssConnector) parseMetadata(md mdata.Metadata) (err error) {
const ( const (
user = "user"
key = "key" key = "key"
connectTimeout = "timeout" connectTimeout = "timeout"
noDelay = "nodelay" noDelay = "nodelay"
) )
var method, password string c.md.key = mdata.GetString(md, key)
if v := mdata.GetString(md, user); v != "" {
ss := strings.SplitN(v, ":", 2)
if len(ss) == 1 {
method = ss[0]
} else {
method, password = ss[0], ss[1]
}
}
c.md.cipher, err = ss.ShadowCipher(method, password, mdata.GetString(md, key))
if err != nil {
return
}
c.md.connectTimeout = mdata.GetDuration(md, connectTimeout) c.md.connectTimeout = mdata.GetDuration(md, connectTimeout)
c.md.noDelay = mdata.GetBool(md, noDelay) c.md.noDelay = mdata.GetBool(md, noDelay)

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"net" "net"
"net/url"
"time" "time"
"github.com/go-gost/gost/pkg/common/util/socks" "github.com/go-gost/gost/pkg/common/util/socks"
@ -12,6 +13,7 @@ import (
"github.com/go-gost/gost/pkg/logger" "github.com/go-gost/gost/pkg/logger"
md "github.com/go-gost/gost/pkg/metadata" md "github.com/go-gost/gost/pkg/metadata"
"github.com/go-gost/gost/pkg/registry" "github.com/go-gost/gost/pkg/registry"
"github.com/shadowsocks/go-shadowsocks2/core"
) )
func init() { func init() {
@ -19,6 +21,8 @@ func init() {
} }
type ssuConnector struct { type ssuConnector struct {
user *url.Userinfo
cipher core.Cipher
md metadata md metadata
logger logger.Logger logger logger.Logger
} }
@ -30,12 +34,23 @@ func NewConnector(opts ...connector.Option) connector.Connector {
} }
return &ssuConnector{ return &ssuConnector{
user: options.User,
logger: options.Logger, logger: options.Logger,
} }
} }
func (c *ssuConnector) Init(md md.Metadata) (err error) { func (c *ssuConnector) Init(md md.Metadata) (err error) {
return c.parseMetadata(md) if err = c.parseMetadata(md); err != nil {
return
}
if c.user != nil {
method := c.user.Username()
password, _ := c.user.Password()
c.cipher, err = ss.ShadowCipher(method, password, c.md.key)
}
return
} }
func (c *ssuConnector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) { func (c *ssuConnector) Connect(ctx context.Context, conn net.Conn, network, address string, opts ...connector.ConnectOption) (net.Conn, error) {
@ -67,16 +82,16 @@ func (c *ssuConnector) Connect(ctx context.Context, conn net.Conn, network, addr
pc, ok := conn.(net.PacketConn) pc, ok := conn.(net.PacketConn)
if ok { if ok {
if c.md.cipher != nil { if c.cipher != nil {
pc = c.md.cipher.PacketConn(pc) pc = c.cipher.PacketConn(pc)
} }
// standard UDP relay // standard UDP relay
return ss.UDPClientConn(pc, conn.RemoteAddr(), taddr, c.md.bufferSize), nil return ss.UDPClientConn(pc, conn.RemoteAddr(), taddr, c.md.bufferSize), nil
} }
if c.md.cipher != nil { if c.cipher != nil {
conn = ss.ShadowConn(c.md.cipher.StreamConn(conn), nil) conn = ss.ShadowConn(c.cipher.StreamConn(conn), nil)
} }
// UDP over TCP // UDP over TCP

View File

@ -2,42 +2,25 @@ package ss
import ( import (
"math" "math"
"strings"
"time" "time"
"github.com/go-gost/gost/pkg/common/util/ss"
mdata "github.com/go-gost/gost/pkg/metadata" mdata "github.com/go-gost/gost/pkg/metadata"
"github.com/shadowsocks/go-shadowsocks2/core"
) )
type metadata struct { type metadata struct {
cipher core.Cipher key string
connectTimeout time.Duration connectTimeout time.Duration
bufferSize int bufferSize int
} }
func (c *ssuConnector) parseMetadata(md mdata.Metadata) (err error) { func (c *ssuConnector) parseMetadata(md mdata.Metadata) (err error) {
const ( const (
user = "user"
key = "key" key = "key"
connectTimeout = "timeout" connectTimeout = "timeout"
bufferSize = "bufferSize" // udp buffer size bufferSize = "bufferSize" // udp buffer size
) )
var method, password string c.md.key = mdata.GetString(md, key)
if v := mdata.GetString(md, user); v != "" {
ss := strings.SplitN(v, ":", 2)
if len(ss) == 1 {
method = ss[0]
} else {
method, password = ss[0], ss[1]
}
}
c.md.cipher, err = ss.ShadowCipher(method, password, mdata.GetString(md, key))
if err != nil {
return
}
c.md.connectTimeout = mdata.GetDuration(md, connectTimeout) c.md.connectTimeout = mdata.GetDuration(md, connectTimeout)
if bs := mdata.GetInt(md, bufferSize); bs > 0 { if bs := mdata.GetInt(md, bufferSize); bs > 0 {

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"errors" "errors"
"net" "net"
"net/url"
"sync" "sync"
"time" "time"
@ -20,6 +21,7 @@ func init() {
} }
type forwardDialer struct { type forwardDialer struct {
user *url.Userinfo
sessions map[string]*sshSession sessions map[string]*sshSession
sessionMutex sync.Mutex sessionMutex sync.Mutex
logger logger.Logger logger logger.Logger
@ -33,6 +35,7 @@ func NewDialer(opts ...dialer.Option) dialer.Dialer {
} }
return &forwardDialer{ return &forwardDialer{
user: options.User,
sessions: make(map[string]*sshSession), sessions: make(map[string]*sshSession),
logger: options.Logger, logger: options.Logger,
} }
@ -161,9 +164,9 @@ func (d *forwardDialer) initSession(ctx context.Context, addr string, conn net.C
// Timeout: timeout, // Timeout: timeout,
HostKeyCallback: ssh.InsecureIgnoreHostKey(), HostKeyCallback: ssh.InsecureIgnoreHostKey(),
} }
if d.md.user != nil { if d.user != nil {
config.User = d.md.user.Username() config.User = d.user.Username()
if password, _ := d.md.user.Password(); password != "" { if password, _ := d.user.Password(); password != "" {
config.Auth = []ssh.AuthMethod{ config.Auth = []ssh.AuthMethod{
ssh.Password(password), ssh.Password(password),
} }

View File

@ -2,8 +2,6 @@ package ssh
import ( import (
"io/ioutil" "io/ioutil"
"net/url"
"strings"
"time" "time"
mdata "github.com/go-gost/gost/pkg/metadata" mdata "github.com/go-gost/gost/pkg/metadata"
@ -12,27 +10,16 @@ import (
type metadata struct { type metadata struct {
handshakeTimeout time.Duration handshakeTimeout time.Duration
user *url.Userinfo
signer ssh.Signer signer ssh.Signer
} }
func (d *forwardDialer) parseMetadata(md mdata.Metadata) (err error) { func (d *forwardDialer) parseMetadata(md mdata.Metadata) (err error) {
const ( const (
handshakeTimeout = "handshakeTimeout" handshakeTimeout = "handshakeTimeout"
user = "user"
privateKeyFile = "privateKeyFile" privateKeyFile = "privateKeyFile"
passphrase = "passphrase" passphrase = "passphrase"
) )
if v := mdata.GetString(md, user); v != "" {
ss := strings.SplitN(v, ":", 2)
if len(ss) == 1 {
d.md.user = url.User(ss[0])
} else {
d.md.user = url.UserPassword(ss[0], ss[1])
}
}
if key := mdata.GetString(md, privateKeyFile); key != "" { if key := mdata.GetString(md, privateKeyFile); key != "" {
data, err := ioutil.ReadFile(key) data, err := ioutil.ReadFile(key)
if err != nil { if err != nil {

View File

@ -3,16 +3,24 @@ package dialer
import ( import (
"context" "context"
"net" "net"
"net/url"
"github.com/go-gost/gost/pkg/logger" "github.com/go-gost/gost/pkg/logger"
) )
type Options struct { type Options struct {
User *url.Userinfo
Logger logger.Logger Logger logger.Logger
} }
type Option func(opts *Options) type Option func(opts *Options)
func UserOption(user *url.Userinfo) Option {
return func(opts *Options) {
opts.User = user
}
}
func LoggerOption(logger logger.Logger) Option { func LoggerOption(logger logger.Logger) Option {
return func(opts *Options) { return func(opts *Options) {
opts.Logger = logger opts.Logger = logger

View File

@ -8,6 +8,7 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/go-gost/gost/pkg/auth"
"github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/bypass"
"github.com/go-gost/gost/pkg/chain" "github.com/go-gost/gost/pkg/chain"
"github.com/go-gost/gost/pkg/handler" "github.com/go-gost/gost/pkg/handler"
@ -34,6 +35,7 @@ type forwardHandler struct {
bypass bypass.Bypass bypass bypass.Bypass
config *ssh.ServerConfig config *ssh.ServerConfig
router *chain.Router router *chain.Router
authenticator auth.Authenticator
logger logger.Logger logger logger.Logger
md metadata md metadata
} }
@ -57,13 +59,13 @@ func (h *forwardHandler) Init(md md.Metadata) (err error) {
} }
config := &ssh.ServerConfig{ config := &ssh.ServerConfig{
PasswordCallback: ssh_util.PasswordCallback(h.md.authenticator), PasswordCallback: ssh_util.PasswordCallback(h.authenticator),
PublicKeyCallback: ssh_util.PublicKeyCallback(h.md.authorizedKeys), PublicKeyCallback: ssh_util.PublicKeyCallback(h.md.authorizedKeys),
} }
config.AddHostKey(h.md.signer) config.AddHostKey(h.md.signer)
if h.md.authenticator == nil && len(h.md.authorizedKeys) == 0 { if h.authenticator == nil && len(h.md.authorizedKeys) == 0 {
config.NoClientAuth = true config.NoClientAuth = true
} }

View File

@ -2,9 +2,7 @@ package ssh
import ( import (
"io/ioutil" "io/ioutil"
"strings"
"github.com/go-gost/gost/pkg/auth"
tls_util "github.com/go-gost/gost/pkg/common/util/tls" tls_util "github.com/go-gost/gost/pkg/common/util/tls"
ssh_util "github.com/go-gost/gost/pkg/internal/util/ssh" ssh_util "github.com/go-gost/gost/pkg/internal/util/ssh"
mdata "github.com/go-gost/gost/pkg/metadata" mdata "github.com/go-gost/gost/pkg/metadata"
@ -12,32 +10,17 @@ import (
) )
type metadata struct { type metadata struct {
authenticator auth.Authenticator
signer ssh.Signer signer ssh.Signer
authorizedKeys map[string]bool authorizedKeys map[string]bool
} }
func (h *forwardHandler) parseMetadata(md mdata.Metadata) (err error) { func (h *forwardHandler) parseMetadata(md mdata.Metadata) (err error) {
const ( const (
users = "users"
authorizedKeys = "authorizedKeys" authorizedKeys = "authorizedKeys"
privateKeyFile = "privateKeyFile" privateKeyFile = "privateKeyFile"
passphrase = "passphrase" passphrase = "passphrase"
) )
if auths := mdata.GetStrings(md, users); len(auths) > 0 {
authenticator := auth.NewLocalAuthenticator(nil)
for _, auth := range auths {
ss := strings.SplitN(auth, ":", 2)
if len(ss) == 1 {
authenticator.Add(ss[0], "")
} else {
authenticator.Add(ss[0], ss[1])
}
}
h.md.authenticator = authenticator
}
if key := mdata.GetString(md, privateKeyFile); key != "" { if key := mdata.GetString(md, privateKeyFile); key != "" {
data, err := ioutil.ReadFile(key) data, err := ioutil.ReadFile(key)
if err != nil { if err != nil {

View File

@ -16,6 +16,7 @@ import (
"time" "time"
"github.com/asaskevich/govalidator" "github.com/asaskevich/govalidator"
"github.com/go-gost/gost/pkg/auth"
"github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/bypass"
"github.com/go-gost/gost/pkg/chain" "github.com/go-gost/gost/pkg/chain"
"github.com/go-gost/gost/pkg/handler" "github.com/go-gost/gost/pkg/handler"
@ -31,6 +32,7 @@ func init() {
type httpHandler struct { type httpHandler struct {
bypass bypass.Bypass bypass bypass.Bypass
router *chain.Router router *chain.Router
authenticator auth.Authenticator
logger logger.Logger logger logger.Logger
md metadata md metadata
} }
@ -260,7 +262,7 @@ func (h *httpHandler) basicProxyAuth(proxyAuth string) (username, password strin
func (h *httpHandler) authenticate(conn net.Conn, req *http.Request, resp *http.Response) (ok bool) { func (h *httpHandler) authenticate(conn net.Conn, req *http.Request, resp *http.Response) (ok bool) {
u, p, _ := h.basicProxyAuth(req.Header.Get("Proxy-Authorization")) u, p, _ := h.basicProxyAuth(req.Header.Get("Proxy-Authorization"))
if h.md.authenticator == nil || h.md.authenticator.Authenticate(u, p) { if h.authenticator == nil || h.authenticator.Authenticate(u, p) {
return true return true
} }

View File

@ -4,12 +4,10 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/go-gost/gost/pkg/auth"
mdata "github.com/go-gost/gost/pkg/metadata" mdata "github.com/go-gost/gost/pkg/metadata"
) )
type metadata struct { type metadata struct {
authenticator auth.Authenticator
probeResist *probeResist probeResist *probeResist
sni bool sni bool
enableUDP bool enableUDP bool
@ -19,26 +17,12 @@ type metadata struct {
func (h *httpHandler) parseMetadata(md mdata.Metadata) error { func (h *httpHandler) parseMetadata(md mdata.Metadata) error {
const ( const (
header = "header" header = "header"
users = "users"
probeResistKey = "probeResist" probeResistKey = "probeResist"
knock = "knock" knock = "knock"
sni = "sni" sni = "sni"
enableUDP = "udp" enableUDP = "udp"
) )
if auths := mdata.GetStrings(md, users); len(auths) > 0 {
authenticator := auth.NewLocalAuthenticator(nil)
for _, auth := range auths {
ss := strings.SplitN(auth, ":", 2)
if len(ss) == 1 {
authenticator.Add(ss[0], "")
} else {
authenticator.Add(ss[0], ss[1])
}
}
h.md.authenticator = authenticator
}
if m := mdata.GetStringMapString(md, header); len(m) > 0 { if m := mdata.GetStringMapString(md, header); len(m) > 0 {
hd := http.Header{} hd := http.Header{}
for k, v := range m { for k, v := range m {

View File

@ -15,6 +15,7 @@ import (
"time" "time"
"github.com/asaskevich/govalidator" "github.com/asaskevich/govalidator"
"github.com/go-gost/gost/pkg/auth"
"github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/bypass"
"github.com/go-gost/gost/pkg/chain" "github.com/go-gost/gost/pkg/chain"
"github.com/go-gost/gost/pkg/handler" "github.com/go-gost/gost/pkg/handler"
@ -31,6 +32,7 @@ func init() {
type http2Handler struct { type http2Handler struct {
bypass bypass.Bypass bypass bypass.Bypass
router *chain.Router router *chain.Router
authenticator auth.Authenticator
logger logger.Logger logger logger.Logger
md metadata md metadata
} }
@ -392,7 +394,7 @@ func (h *http2Handler) basicProxyAuth(proxyAuth string) (username, password stri
func (h *http2Handler) authenticate(conn net.Conn, req *http.Request, resp *http.Response) (ok bool) { func (h *http2Handler) authenticate(conn net.Conn, req *http.Request, resp *http.Response) (ok bool) {
u, p, _ := h.basicProxyAuth(req.Header.Get("Proxy-Authorization")) u, p, _ := h.basicProxyAuth(req.Header.Get("Proxy-Authorization"))
if h.md.authenticator == nil || h.md.authenticator.Authenticate(u, p) { if h.authenticator == nil || h.authenticator.Authenticate(u, p) {
return true return true
} }

View File

@ -3,12 +3,10 @@ package http2
import ( import (
"strings" "strings"
"github.com/go-gost/gost/pkg/auth"
mdata "github.com/go-gost/gost/pkg/metadata" mdata "github.com/go-gost/gost/pkg/metadata"
) )
type metadata struct { type metadata struct {
authenticator auth.Authenticator
proxyAgent string proxyAgent string
probeResist *probeResist probeResist *probeResist
sni bool sni bool
@ -18,7 +16,6 @@ type metadata struct {
func (h *http2Handler) parseMetadata(md mdata.Metadata) error { func (h *http2Handler) parseMetadata(md mdata.Metadata) error {
const ( const (
proxyAgent = "proxyAgent" proxyAgent = "proxyAgent"
users = "users"
probeResistKey = "probeResist" probeResistKey = "probeResist"
knock = "knock" knock = "knock"
sni = "sni" sni = "sni"
@ -27,19 +24,6 @@ func (h *http2Handler) parseMetadata(md mdata.Metadata) error {
h.md.proxyAgent = mdata.GetString(md, proxyAgent) h.md.proxyAgent = mdata.GetString(md, proxyAgent)
if auths := mdata.GetStrings(md, users); len(auths) > 0 {
authenticator := auth.NewLocalAuthenticator(nil)
for _, auth := range auths {
ss := strings.SplitN(auth, ":", 2)
if len(ss) == 1 {
authenticator.Add(ss[0], "")
} else {
authenticator.Add(ss[0], ss[1])
}
}
h.md.authenticator = authenticator
}
if v := mdata.GetString(md, probeResistKey); v != "" { if v := mdata.GetString(md, probeResistKey); v != "" {
if ss := strings.SplitN(v, ":", 2); len(ss) == 2 { if ss := strings.SplitN(v, ":", 2); len(ss) == 2 {
h.md.probeResist = &probeResist{ h.md.probeResist = &probeResist{

View File

@ -1,6 +1,7 @@
package handler package handler
import ( import (
"github.com/go-gost/gost/pkg/auth"
"github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/bypass"
"github.com/go-gost/gost/pkg/chain" "github.com/go-gost/gost/pkg/chain"
"github.com/go-gost/gost/pkg/logger" "github.com/go-gost/gost/pkg/logger"
@ -11,6 +12,7 @@ type Options struct {
Router *chain.Router Router *chain.Router
Bypass bypass.Bypass Bypass bypass.Bypass
Resolver resolver.Resolver Resolver resolver.Resolver
Authenticator auth.Authenticator
Logger logger.Logger Logger logger.Logger
} }
@ -28,6 +30,12 @@ func BypassOption(bypass bypass.Bypass) Option {
} }
} }
func AuthenticatorOption(auth auth.Authenticator) Option {
return func(opts *Options) {
opts.Authenticator = auth
}
}
func LoggerOption(logger logger.Logger) Option { func LoggerOption(logger logger.Logger) Option {
return func(opts *Options) { return func(opts *Options) {
opts.Logger = logger opts.Logger = logger

View File

@ -6,6 +6,7 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/go-gost/gost/pkg/auth"
"github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/bypass"
"github.com/go-gost/gost/pkg/chain" "github.com/go-gost/gost/pkg/chain"
"github.com/go-gost/gost/pkg/handler" "github.com/go-gost/gost/pkg/handler"
@ -23,6 +24,7 @@ type relayHandler struct {
group *chain.NodeGroup group *chain.NodeGroup
bypass bypass.Bypass bypass bypass.Bypass
router *chain.Router router *chain.Router
authenticator auth.Authenticator
logger logger.Logger logger logger.Logger
md metadata md metadata
} }
@ -107,7 +109,7 @@ func (h *relayHandler) Handle(ctx context.Context, conn net.Conn) {
Version: relay.Version1, Version: relay.Version1,
Status: relay.StatusOK, Status: relay.StatusOK,
} }
if h.md.authenticator != nil && !h.md.authenticator.Authenticate(user, pass) { if h.authenticator != nil && !h.authenticator.Authenticate(user, pass) {
resp.Status = relay.StatusUnauthorized resp.Status = relay.StatusUnauthorized
resp.WriteTo(conn) resp.WriteTo(conn)
h.logger.Error("unauthorized") h.logger.Error("unauthorized")

View File

@ -2,15 +2,12 @@ package relay
import ( import (
"math" "math"
"strings"
"time" "time"
"github.com/go-gost/gost/pkg/auth"
mdata "github.com/go-gost/gost/pkg/metadata" mdata "github.com/go-gost/gost/pkg/metadata"
) )
type metadata struct { type metadata struct {
authenticator auth.Authenticator
readTimeout time.Duration readTimeout time.Duration
enableBind bool enableBind bool
udpBufferSize int udpBufferSize int
@ -19,26 +16,12 @@ type metadata struct {
func (h *relayHandler) parseMetadata(md mdata.Metadata) (err error) { func (h *relayHandler) parseMetadata(md mdata.Metadata) (err error) {
const ( const (
users = "users"
readTimeout = "readTimeout" readTimeout = "readTimeout"
enableBind = "bind" enableBind = "bind"
udpBufferSize = "udpBufferSize" udpBufferSize = "udpBufferSize"
noDelay = "nodelay" noDelay = "nodelay"
) )
if auths := mdata.GetStrings(md, users); len(auths) > 0 {
authenticator := auth.NewLocalAuthenticator(nil)
for _, auth := range auths {
ss := strings.SplitN(auth, ":", 2)
if len(ss) == 1 {
authenticator.Add(ss[0], "")
} else {
authenticator.Add(ss[0], ss[1])
}
}
h.md.authenticator = authenticator
}
h.md.readTimeout = mdata.GetDuration(md, readTimeout) h.md.readTimeout = mdata.GetDuration(md, readTimeout)
h.md.enableBind = mdata.GetBool(md, enableBind) h.md.enableBind = mdata.GetBool(md, enableBind)
h.md.noDelay = mdata.GetBool(md, noDelay) h.md.noDelay = mdata.GetBool(md, noDelay)

View File

@ -6,6 +6,7 @@ import (
"time" "time"
"github.com/go-gost/gosocks4" "github.com/go-gost/gosocks4"
"github.com/go-gost/gost/pkg/auth"
"github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/bypass"
"github.com/go-gost/gost/pkg/chain" "github.com/go-gost/gost/pkg/chain"
"github.com/go-gost/gost/pkg/handler" "github.com/go-gost/gost/pkg/handler"
@ -22,6 +23,7 @@ func init() {
type socks4Handler struct { type socks4Handler struct {
bypass bypass.Bypass bypass bypass.Bypass
router *chain.Router router *chain.Router
authenticator auth.Authenticator
logger logger.Logger logger logger.Logger
md metadata md metadata
} }
@ -77,8 +79,8 @@ func (h *socks4Handler) Handle(ctx context.Context, conn net.Conn) {
conn.SetReadDeadline(time.Time{}) conn.SetReadDeadline(time.Time{})
if h.md.authenticator != nil && if h.authenticator != nil &&
!h.md.authenticator.Authenticate(string(req.Userid), "") { !h.authenticator.Authenticate(string(req.Userid), "") {
resp := gosocks4.NewReply(gosocks4.RejectedUserid, nil) resp := gosocks4.NewReply(gosocks4.RejectedUserid, nil)
resp.Write(conn) resp.Write(conn)
h.logger.Debug(resp) h.logger.Debug(resp)

View File

@ -3,31 +3,18 @@ package v4
import ( import (
"time" "time"
"github.com/go-gost/gost/pkg/auth"
mdata "github.com/go-gost/gost/pkg/metadata" mdata "github.com/go-gost/gost/pkg/metadata"
) )
type metadata struct { type metadata struct {
authenticator auth.Authenticator
readTimeout time.Duration readTimeout time.Duration
} }
func (h *socks4Handler) parseMetadata(md mdata.Metadata) (err error) { func (h *socks4Handler) parseMetadata(md mdata.Metadata) (err error) {
const ( const (
users = "users"
readTimeout = "readTimeout" readTimeout = "readTimeout"
) )
if auths := mdata.GetStrings(md, users); len(auths) > 0 {
authenticator := auth.NewLocalAuthenticator(nil)
for _, auth := range auths {
if auth != "" {
authenticator.Add(auth, "")
}
}
h.md.authenticator = authenticator
}
h.md.readTimeout = mdata.GetDuration(md, readTimeout) h.md.readTimeout = mdata.GetDuration(md, readTimeout)
return return
} }

View File

@ -6,6 +6,7 @@ import (
"time" "time"
"github.com/go-gost/gosocks5" "github.com/go-gost/gosocks5"
"github.com/go-gost/gost/pkg/auth"
"github.com/go-gost/gost/pkg/bypass" "github.com/go-gost/gost/pkg/bypass"
"github.com/go-gost/gost/pkg/chain" "github.com/go-gost/gost/pkg/chain"
"github.com/go-gost/gost/pkg/common/util/socks" "github.com/go-gost/gost/pkg/common/util/socks"
@ -24,6 +25,7 @@ type socks5Handler struct {
selector gosocks5.Selector selector gosocks5.Selector
bypass bypass.Bypass bypass bypass.Bypass
router *chain.Router router *chain.Router
authenticator auth.Authenticator
logger logger.Logger logger logger.Logger
md metadata md metadata
} }
@ -47,7 +49,7 @@ func (h *socks5Handler) Init(md md.Metadata) (err error) {
} }
h.selector = &serverSelector{ h.selector = &serverSelector{
Authenticator: h.md.authenticator, Authenticator: h.authenticator,
TLSConfig: h.md.tlsConfig, TLSConfig: h.md.tlsConfig,
logger: h.logger, logger: h.logger,
noTLS: h.md.noTLS, noTLS: h.md.noTLS,

View File

@ -3,17 +3,14 @@ package v5
import ( import (
"crypto/tls" "crypto/tls"
"math" "math"
"strings"
"time" "time"
"github.com/go-gost/gost/pkg/auth"
tls_util "github.com/go-gost/gost/pkg/common/util/tls" tls_util "github.com/go-gost/gost/pkg/common/util/tls"
mdata "github.com/go-gost/gost/pkg/metadata" mdata "github.com/go-gost/gost/pkg/metadata"
) )
type metadata struct { type metadata struct {
tlsConfig *tls.Config tlsConfig *tls.Config
authenticator auth.Authenticator
timeout time.Duration timeout time.Duration
readTimeout time.Duration readTimeout time.Duration
noTLS bool noTLS bool
@ -28,7 +25,6 @@ func (h *socks5Handler) parseMetadata(md mdata.Metadata) (err error) {
certFile = "certFile" certFile = "certFile"
keyFile = "keyFile" keyFile = "keyFile"
caFile = "caFile" caFile = "caFile"
users = "users"
readTimeout = "readTimeout" readTimeout = "readTimeout"
timeout = "timeout" timeout = "timeout"
noTLS = "notls" noTLS = "notls"
@ -47,19 +43,6 @@ func (h *socks5Handler) parseMetadata(md mdata.Metadata) (err error) {
return return
} }
if auths := mdata.GetStrings(md, users); len(auths) > 0 {
authenticator := auth.NewLocalAuthenticator(nil)
for _, auth := range auths {
ss := strings.SplitN(auth, ":", 2)
if len(ss) == 1 {
authenticator.Add(ss[0], "")
} else {
authenticator.Add(ss[0], ss[1])
}
}
h.md.authenticator = authenticator
}
h.md.readTimeout = mdata.GetDuration(md, readTimeout) h.md.readTimeout = mdata.GetDuration(md, readTimeout)
h.md.timeout = mdata.GetDuration(md, timeout) h.md.timeout = mdata.GetDuration(md, timeout)
h.md.noTLS = mdata.GetBool(md, noTLS) h.md.noTLS = mdata.GetBool(md, noTLS)

View File

@ -1,11 +1,13 @@
package listener package listener
import ( import (
"github.com/go-gost/gost/pkg/auth"
"github.com/go-gost/gost/pkg/logger" "github.com/go-gost/gost/pkg/logger"
) )
type Options struct { type Options struct {
Addr string Addr string
Authenticator auth.Authenticator
Logger logger.Logger Logger logger.Logger
} }
@ -17,6 +19,12 @@ func AddrOption(addr string) Option {
} }
} }
func AuthenticatorOption(auth auth.Authenticator) Option {
return func(opts *Options) {
opts.Authenticator = auth
}
}
func LoggerOption(logger logger.Logger) Option { func LoggerOption(logger logger.Logger) Option {
return func(opts *Options) { return func(opts *Options) {
opts.Logger = logger opts.Logger = logger

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"net" "net"
"github.com/go-gost/gost/pkg/auth"
ssh_util "github.com/go-gost/gost/pkg/internal/util/ssh" ssh_util "github.com/go-gost/gost/pkg/internal/util/ssh"
"github.com/go-gost/gost/pkg/listener" "github.com/go-gost/gost/pkg/listener"
"github.com/go-gost/gost/pkg/logger" "github.com/go-gost/gost/pkg/logger"
@ -20,6 +21,7 @@ type sshListener struct {
addr string addr string
net.Listener net.Listener
config *ssh.ServerConfig config *ssh.ServerConfig
authenticator auth.Authenticator
cqueue chan net.Conn cqueue chan net.Conn
errChan chan error errChan chan error
logger logger.Logger logger logger.Logger
@ -50,13 +52,13 @@ func (l *sshListener) Init(md md.Metadata) (err error) {
l.Listener = ln l.Listener = ln
config := &ssh.ServerConfig{ config := &ssh.ServerConfig{
PasswordCallback: ssh_util.PasswordCallback(l.md.authenticator), PasswordCallback: ssh_util.PasswordCallback(l.authenticator),
PublicKeyCallback: ssh_util.PublicKeyCallback(l.md.authorizedKeys), PublicKeyCallback: ssh_util.PublicKeyCallback(l.md.authorizedKeys),
} }
config.AddHostKey(l.md.signer) config.AddHostKey(l.md.signer)
if l.md.authenticator == nil && len(l.md.authorizedKeys) == 0 { if l.authenticator == nil && len(l.md.authorizedKeys) == 0 {
config.NoClientAuth = true config.NoClientAuth = true
} }

View File

@ -2,9 +2,7 @@ package ssh
import ( import (
"io/ioutil" "io/ioutil"
"strings"
"github.com/go-gost/gost/pkg/auth"
tls_util "github.com/go-gost/gost/pkg/common/util/tls" tls_util "github.com/go-gost/gost/pkg/common/util/tls"
ssh_util "github.com/go-gost/gost/pkg/internal/util/ssh" ssh_util "github.com/go-gost/gost/pkg/internal/util/ssh"
mdata "github.com/go-gost/gost/pkg/metadata" mdata "github.com/go-gost/gost/pkg/metadata"
@ -16,7 +14,6 @@ const (
) )
type metadata struct { type metadata struct {
authenticator auth.Authenticator
signer ssh.Signer signer ssh.Signer
authorizedKeys map[string]bool authorizedKeys map[string]bool
backlog int backlog int
@ -24,26 +21,12 @@ type metadata struct {
func (l *sshListener) parseMetadata(md mdata.Metadata) (err error) { func (l *sshListener) parseMetadata(md mdata.Metadata) (err error) {
const ( const (
users = "users"
authorizedKeys = "authorizedKeys" authorizedKeys = "authorizedKeys"
privateKeyFile = "privateKeyFile" privateKeyFile = "privateKeyFile"
passphrase = "passphrase" passphrase = "passphrase"
backlog = "backlog" backlog = "backlog"
) )
if auths := mdata.GetStrings(md, users); len(auths) > 0 {
authenticator := auth.NewLocalAuthenticator(nil)
for _, auth := range auths {
ss := strings.SplitN(auth, ":", 2)
if len(ss) == 1 {
authenticator.Add(ss[0], "")
} else {
authenticator.Add(ss[0], ss[1])
}
}
l.md.authenticator = authenticator
}
if key := mdata.GetString(md, privateKeyFile); key != "" { if key := mdata.GetString(md, privateKeyFile); key != "" {
data, err := ioutil.ReadFile(key) data, err := ioutil.ReadFile(key)
if err != nil { if err != nil {