mirror of
https://github.com/luscis/openlan.git
synced 2025-10-06 17:17:00 +08:00
290 lines
6.8 KiB
Go
Executable File
290 lines
6.8 KiB
Go
Executable File
package config
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"path"
|
|
"regexp"
|
|
|
|
"github.com/luscis/openlan/pkg/libol"
|
|
)
|
|
|
|
type ShadowProxy struct {
|
|
Server string `json:"server,omitempty"`
|
|
Key string `json:"key,omitempty"`
|
|
Cipher string `json:"cipher,omitempty"`
|
|
Password string `json:"password,omitempty"`
|
|
Plugin string `json:"plugin,omitempty"`
|
|
PluginOpts string `json:"pluginOpts,omitempty"`
|
|
Protocol string `json:"protocol,omitempty"`
|
|
}
|
|
|
|
type ForwardSocks struct {
|
|
Server string `json:"server,omitempty"`
|
|
}
|
|
|
|
type HttpForward struct {
|
|
Protocol string `json:"protocol,omitempty" yaml:"protocol,omitempty"`
|
|
Server string `json:"server,omitempty" yaml:"server,omitempty"`
|
|
Insecure bool `json:"insecure,omitempty" yaml:"insecure,omitempty"`
|
|
Match []string `json:"match,omitempty" yaml:"match,omitempty"`
|
|
Secret string `json:"secret,omitempty" yaml:"secret,omitempty"`
|
|
Socks ForwardSocks `json:"socks,omitempty" yaml:"socks,omitempty"`
|
|
}
|
|
|
|
func (f *HttpForward) SocksAddr() string {
|
|
if f.Socks.Server != "" {
|
|
return f.Socks.Server
|
|
}
|
|
return f.Server
|
|
}
|
|
|
|
type HttpBackends []*HttpForward
|
|
|
|
func (h HttpBackends) isMatch(value string, rules []string) bool {
|
|
if len(rules) == 0 {
|
|
return true
|
|
}
|
|
|
|
for _, rule := range rules {
|
|
pattern := fmt.Sprintf(`(^|\.)%s(:\d+)?$`, regexp.QuoteMeta(rule))
|
|
re := regexp.MustCompile(pattern)
|
|
if re.MatchString(value) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (h HttpBackends) FindBackend(host string) *HttpForward {
|
|
for _, via := range h {
|
|
if via == nil {
|
|
continue
|
|
}
|
|
if via.Server == "" && via.Socks.Server == "" {
|
|
continue
|
|
}
|
|
if h.isMatch(host, via.Match) {
|
|
return via
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type FindBackend interface {
|
|
FindBackend(host string) *HttpForward
|
|
}
|
|
|
|
type SocksProxy struct {
|
|
Conf string `json:"-" yaml:"-"`
|
|
Listen string `json:"listen,omitempty" yaml:"listen,omitempty"`
|
|
Auth *Password `json:"auth,omitempty" yaml:"auth,omitempty"`
|
|
Backends HttpBackends `json:"backends,omitempty" yaml:"backends,omitempty"`
|
|
}
|
|
|
|
func (s *SocksProxy) Initialize() error {
|
|
libol.Info("SocksProxy.Initialize %s", s.Conf)
|
|
if err := s.Load(); err != nil {
|
|
libol.Error("SocksProxy.Initialize %s", err)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *SocksProxy) Load() error {
|
|
if s.Conf == "" || libol.FileExist(s.Conf) != nil {
|
|
return libol.NewErr("invalid configure file")
|
|
}
|
|
return libol.UnmarshalLoad(s, s.Conf)
|
|
}
|
|
|
|
type HttpSocks struct {
|
|
Listen string `json:"listen,omitempty"`
|
|
}
|
|
|
|
type HttpProxy struct {
|
|
Conf string `json:"-" yaml:"-"`
|
|
ConfDir string `json:"-" yaml:"-"`
|
|
Listen string `json:"listen,omitempty"`
|
|
Auth *Password `json:"auth,omitempty" yaml:"auth,omitempty"`
|
|
Cert *Cert `json:"cert,omitempty" yaml:"cert,omitempty"`
|
|
Password string `json:"password,omitempty" yaml:"password,omitempty"`
|
|
CaCert string `json:"cacert,omitempty" yaml:"cacert,omitempty"`
|
|
Backends HttpBackends `json:"backends,omitempty" yaml:"backends,omitempty"`
|
|
Socks *HttpSocks `json:"socks,omitempty" yaml:"socks,omitempty"`
|
|
SocksProxy *SocksProxy `json:"-" yaml:"-"`
|
|
}
|
|
|
|
func (h *HttpProxy) Initialize() error {
|
|
if h.ConfDir == "" {
|
|
h.ConfDir = path.Dir(os.Args[0])
|
|
}
|
|
libol.Info("HttpProxy.Initialize %s", h.Conf)
|
|
if err := h.Load(); err != nil {
|
|
libol.Error("HttpProxy.Initialize %s", err)
|
|
return err
|
|
}
|
|
h.Correct()
|
|
return nil
|
|
}
|
|
|
|
func (h *HttpProxy) Load() error {
|
|
if h.Conf == "" || libol.FileExist(h.Conf) != nil {
|
|
return libol.NewErr("invalid configure file")
|
|
}
|
|
return libol.UnmarshalLoad(h, h.Conf)
|
|
}
|
|
|
|
func (h *HttpProxy) Correct() {
|
|
if h.Cert != nil {
|
|
h.Cert.Correct()
|
|
}
|
|
if h.Password == "" {
|
|
h.Password = h.Listen + ".pass"
|
|
}
|
|
h.Password = path.Join(h.ConfDir, h.Password)
|
|
if h.CaCert == "" {
|
|
h.CaCert = "ca.crt"
|
|
}
|
|
h.CaCert = path.Join(h.ConfDir, h.CaCert)
|
|
if h.Socks != nil {
|
|
h.SocksProxy = &SocksProxy{
|
|
Listen: h.Socks.Listen,
|
|
}
|
|
}
|
|
}
|
|
|
|
func (h *HttpProxy) FindMatch(domain string, to *HttpForward) int {
|
|
for i, rule := range to.Match {
|
|
if rule == domain {
|
|
return i
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
func (h *HttpProxy) FindBackend(remote string) *HttpForward {
|
|
for _, to := range h.Backends {
|
|
if to.Server == remote {
|
|
return to
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (h *HttpProxy) AddMatch(domain, remote string) int {
|
|
to := h.FindBackend(remote)
|
|
if to == nil {
|
|
return -1
|
|
}
|
|
index := h.FindMatch(domain, to)
|
|
if index == -1 {
|
|
to.Match = append(to.Match, domain)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func (h *HttpProxy) DelMatch(domain, remote string) int {
|
|
to := h.FindBackend(remote)
|
|
if to == nil {
|
|
return -1
|
|
}
|
|
index := h.FindMatch(domain, to)
|
|
if index > -1 {
|
|
to.Match = append(to.Match[:index], to.Match[index+1:]...)
|
|
}
|
|
return index
|
|
}
|
|
|
|
func (h *HttpProxy) Save() {
|
|
if h.Conf == "" {
|
|
return
|
|
}
|
|
if err := libol.MarshalSave(&h, h.Conf, true); err != nil {
|
|
libol.Error("Proxy.Save %s %s", h.Conf, err)
|
|
}
|
|
}
|
|
|
|
type TcpProxy struct {
|
|
Conf string `json:"-" yaml:"-"`
|
|
Listen string `json:"listen,omitempty"`
|
|
Target []string `json:"target,omitempty"`
|
|
}
|
|
|
|
func (t *TcpProxy) Initialize() error {
|
|
libol.Info("TcpProxy.Initialize %s", t.Conf)
|
|
if err := t.Load(); err != nil {
|
|
libol.Error("TcpProxy.Initialize %s", err)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (t *TcpProxy) Load() error {
|
|
if t.Conf == "" || libol.FileExist(t.Conf) != nil {
|
|
return libol.NewErr("invalid configure file")
|
|
}
|
|
return libol.UnmarshalLoad(t, t.Conf)
|
|
}
|
|
|
|
type Proxy struct {
|
|
Conf string `json:"-" yaml:"-"`
|
|
ConfDir string `json:"-" yaml:"-"`
|
|
Log Log `json:"log"`
|
|
Socks []*SocksProxy `json:"socks,omitempty" yaml:"socks,omitempty"`
|
|
Http []*HttpProxy `json:"http,omitempty" yaml:"http,omitempty"`
|
|
Tcp []*TcpProxy `json:"tcp,omitempty" yaml:"tcp,omitempty"`
|
|
Shadow []*ShadowProxy `json:"shadow,omitempty" yaml:"shadow,omitempty"`
|
|
PProf string `json:"pprof,omitempty" yaml:"pprof,omitempty"`
|
|
}
|
|
|
|
func NewProxy() *Proxy {
|
|
p := &Proxy{}
|
|
p.Parse()
|
|
p.Initialize()
|
|
return p
|
|
}
|
|
|
|
func (p *Proxy) Parse() {
|
|
flag.StringVar(&p.Log.File, "log:file", "", "Configure log file")
|
|
flag.StringVar(&p.Conf, "conf", "", "The configure file")
|
|
flag.StringVar(&p.PProf, "prof", "", "Http listen for CPU prof")
|
|
flag.IntVar(&p.Log.Verbose, "log:level", 20, "Configure log level")
|
|
flag.Parse()
|
|
}
|
|
|
|
func (p *Proxy) Initialize() {
|
|
if p.Conf == "" {
|
|
p.Conf = path.Dir(os.Args[0]) + "/" + "proxy.json"
|
|
}
|
|
if p.ConfDir == "" {
|
|
p.ConfDir = path.Dir(p.Conf)
|
|
}
|
|
if err := p.Load(); err != nil {
|
|
libol.Error("Proxy.Initialize %s", err)
|
|
}
|
|
p.Correct()
|
|
libol.Debug("Proxy.Initialize %v", p)
|
|
}
|
|
|
|
func (p *Proxy) Correct() {
|
|
for _, h := range p.Http {
|
|
h.ConfDir = p.ConfDir
|
|
h.Correct()
|
|
}
|
|
p.Log.Correct()
|
|
}
|
|
|
|
func (p *Proxy) Load() error {
|
|
return libol.UnmarshalLoad(p, p.Conf)
|
|
}
|
|
|
|
func (p *Proxy) Save() {
|
|
if err := libol.MarshalSave(&p, p.Conf, true); err != nil {
|
|
libol.Error("Proxy.Save %s %s", p.Conf, err)
|
|
}
|
|
}
|