package main import ( "bufio" "crypto/tls" "crypto/x509" "encoding/json" "errors" "fmt" "io/ioutil" "net/url" "os" "strings" "time" "github.com/ginuerzh/gost" ) var ( defaultCertFile = "cert.pem" defaultKeyFile = "key.pem" ) // Load the certificate from cert and key files, will use the default certificate if the provided info are invalid. func tlsConfig(certFile, keyFile string) (*tls.Config, error) { if certFile == "" { certFile = defaultCertFile } if keyFile == "" { keyFile = defaultKeyFile } cert, err := tls.LoadX509KeyPair(certFile, keyFile) if err != nil { return nil, err } return &tls.Config{Certificates: []tls.Certificate{cert}}, nil } func loadCA(caFile string) (cp *x509.CertPool, err error) { if caFile == "" { return } cp = x509.NewCertPool() data, err := ioutil.ReadFile(caFile) if err != nil { return nil, err } if !cp.AppendCertsFromPEM(data) { return nil, errors.New("AppendCertsFromPEM failed") } return } func loadConfigureFile(configureFile string) error { if configureFile == "" { return nil } content, err := ioutil.ReadFile(configureFile) if err != nil { return err } var cfg struct { route Routes []route } if err := json.Unmarshal(content, &cfg); err != nil { return err } if len(cfg.route.ServeNodes) > 0 { routes = append(routes, cfg.route) } for _, route := range cfg.Routes { if len(route.ServeNodes) > 0 { routes = append(routes, route) } } gost.Debug = cfg.Debug return nil } type stringList []string func (l *stringList) String() string { return fmt.Sprintf("%s", *l) } func (l *stringList) Set(value string) error { *l = append(*l, value) return nil } func parseKCPConfig(configFile string) (*gost.KCPConfig, error) { if configFile == "" { return nil, nil } file, err := os.Open(configFile) if err != nil { return nil, err } defer file.Close() config := &gost.KCPConfig{} if err = json.NewDecoder(file).Decode(config); err != nil { return nil, err } return config, nil } func parseUsers(authFile string) (users []*url.Userinfo, err error) { if authFile == "" { return } file, err := os.Open(authFile) if err != nil { return } scanner := bufio.NewScanner(file) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if line == "" || strings.HasPrefix(line, "#") { continue } s := strings.SplitN(line, " ", 2) if len(s) == 1 { users = append(users, url.User(strings.TrimSpace(s[0]))) } else if len(s) == 2 { users = append(users, url.UserPassword(strings.TrimSpace(s[0]), strings.TrimSpace(s[1]))) } } err = scanner.Err() return } func parseIP(s string, port string) (ips []string) { if s == "" { return } if port == "" { port = "8080" // default port } file, err := os.Open(s) if err != nil { ss := strings.Split(s, ",") for _, s := range ss { s = strings.TrimSpace(s) if s != "" { if !strings.Contains(s, ":") { s = s + ":" + port } ips = append(ips, s) } } return } scanner := bufio.NewScanner(file) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if line == "" || strings.HasPrefix(line, "#") { continue } if !strings.Contains(line, ":") { line = line + ":" + port } ips = append(ips, line) } return } func parseBypass(s string) *gost.Bypass { if s == "" { return nil } var matchers []gost.Matcher var reversed bool if strings.HasPrefix(s, "~") { reversed = true s = strings.TrimLeft(s, "~") } f, err := os.Open(s) if err != nil { for _, s := range strings.Split(s, ",") { s = strings.TrimSpace(s) if s == "" { continue } matchers = append(matchers, gost.NewMatcher(s)) } return gost.NewBypass(reversed, matchers...) } f.Close() bp := gost.NewBypass(reversed) go gost.PeriodReload(bp, s) return bp } func parseResolver(cfg string) gost.Resolver { if cfg == "" { return nil } timeout := 30 * time.Second ttl := 60 * time.Second var nss []gost.NameServer f, err := os.Open(cfg) if err != nil { for _, s := range strings.Split(cfg, ",") { s = strings.TrimSpace(s) if s == "" { continue } ss := strings.Split(s, "/") if len(ss) == 1 { nss = append(nss, gost.NameServer{ Addr: ss[0], }) } if len(ss) == 2 { nss = append(nss, gost.NameServer{ Addr: ss[0], Protocol: ss[1], }) } } return gost.NewResolver(timeout, ttl, nss...) } f.Close() resolver := gost.NewResolver(timeout, ttl) go gost.PeriodReload(resolver, cfg) return resolver }