diff --git a/README.md b/README.md index bd47525..0742ac3 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,8 @@ Listen (local proxy server): - TCP tunnel - UDP tunnel - UDP over TCP tunnel +- TLS, use it together with above proxy protocols(tcp) +- Unix domain socket, use it together with above proxy protocols(tcp) Forward (local proxy client/upstream proxy server): @@ -36,6 +38,7 @@ Forward (local proxy client/upstream proxy server): - VMess proxy(tcp) - TLS, use it together with above proxy protocols(tcp) - Websocket, use it together with above proxy protocols(tcp) +- Unix domain socket, use it together with above proxy protocols(tcp) DNS Forwarding Server (udp2tcp): @@ -135,8 +138,6 @@ glider v0.6.9 usage: forward url, format: SCHEME://[USER|METHOD:PASSWORD@][HOST]:PORT?PARAMS[,SCHEME://[USER|METHOD:PASSWORD@][HOST]:PORT?PARAMS] -interface string source ip or source interface - -ipset string - ipset name -listen value listen url, format: SCHEME://[USER|METHOD:PASSWORD@][HOST]:PORT?PARAMS -maxfailures int @@ -262,7 +263,7 @@ Examples: glider -listen socks5://:1080 -verbose -listen on :1080 as a socks5 proxy server, in verbose mode. - glider -listen =tls://:443?cert=crtFilePath&key=keyFilePath,http:// -verbose + glider -listen tls://:443?cert=crtFilePath&key=keyFilePath,http:// -verbose -listen on :443 as a https proxy server. glider -listen http://:8080 -forward socks5://127.0.0.1:1080 diff --git a/conf.go b/conf.go index c323ef7..68630e5 100644 --- a/conf.go +++ b/conf.go @@ -29,8 +29,6 @@ var conf struct { DNS string DNSConfig dns.Config - IPSet string - rules []*rule.Config } @@ -57,8 +55,6 @@ func confInit() { flag.IntVar(&conf.DNSConfig.MinTTL, "dnsminttl", 0, "minimum TTL value for entries in the CACHE(seconds)") flag.StringSliceUniqVar(&conf.DNSConfig.Records, "dnsrecord", nil, "custom dns record, format: domain/ip") - flag.StringVar(&conf.IPSet, "ipset", "", "ipset name") - flag.Usage = usage err := flag.Parse() if err != nil { @@ -240,7 +236,7 @@ func usage() { fmt.Fprintf(os.Stderr, " "+app+" -listen socks5://:1080 -verbose\n") fmt.Fprintf(os.Stderr, " -listen on :1080 as a socks5 proxy server, in verbose mode.\n") fmt.Fprintf(os.Stderr, "\n") - fmt.Fprintf(os.Stderr, " "+app+" -listen =tls://:443?cert=crtFilePath&key=keyFilePath,http:// -verbose\n") + fmt.Fprintf(os.Stderr, " "+app+" -listen tls://:443?cert=crtFilePath&key=keyFilePath,http:// -verbose\n") fmt.Fprintf(os.Stderr, " -listen on :443 as a https proxy server.\n") fmt.Fprintf(os.Stderr, "\n") fmt.Fprintf(os.Stderr, " "+app+" -listen http://:8080 -forward socks5://127.0.0.1:1080\n") diff --git a/config/examples/9.transparent_proxy_without_dnsmasq/glider.conf b/config/examples/9.transparent_proxy_without_dnsmasq/glider.conf index b78826c..47e14ea 100644 --- a/config/examples/9.transparent_proxy_without_dnsmasq/glider.conf +++ b/config/examples/9.transparent_proxy_without_dnsmasq/glider.conf @@ -9,8 +9,5 @@ listen=redir://:1081 dns=:53 dnsserver=8.8.8.8:53 -# as a ipset manager -ipset=glider - # parse all *.rule files in rules.d folder rules-dir=rules.d diff --git a/config/examples/9.transparent_proxy_without_dnsmasq/rules.d/home.rule b/config/examples/9.transparent_proxy_without_dnsmasq/rules.d/home.rule index 956afbb..0660982 100644 --- a/config/examples/9.transparent_proxy_without_dnsmasq/rules.d/home.rule +++ b/config/examples/9.transparent_proxy_without_dnsmasq/rules.d/home.rule @@ -13,6 +13,8 @@ strategy=rr checkwebsite=www.apple.com checkduration=30 +# as a ipset manager +ipset=glider # matches 192.168.0.0/16 cidr=192.168.0.0/16 diff --git a/config/examples/9.transparent_proxy_without_dnsmasq/rules.d/office.rule b/config/examples/9.transparent_proxy_without_dnsmasq/rules.d/office.rule index 634e88e..1f91f9f 100644 --- a/config/examples/9.transparent_proxy_without_dnsmasq/rules.d/office.rule +++ b/config/examples/9.transparent_proxy_without_dnsmasq/rules.d/office.rule @@ -15,6 +15,9 @@ checkduration=30 # specify a different dns server(if need) dnsserver=208.67.222.222:53 +# as a ipset manager +ipset=glider + # specify destinations include=office.list diff --git a/config/glider.conf.example b/config/glider.conf.example index 23a2050..55752b9 100644 --- a/config/glider.conf.example +++ b/config/glider.conf.example @@ -107,6 +107,9 @@ listen=socks5://:1080 # forward=tls://1.1.1.1:443,ws://,vmess://5a146038-0b56-4e95-b1dc-5c6f5a32cd98@?alterID=2 # forward=tls://1.1.1.1:443,ws://@/path,vmess://5a146038-0b56-4e95-b1dc-5c6f5a32cd98@?alterID=2 +# socks5 over unix domain socket +# forward=unix:///tmp/glider.socket,socks5:// + # FORWARDER CHAIN # --------------- # We can setup a forward chain using 1 forward option, @@ -167,15 +170,6 @@ dnsminttl=0 dnsrecord=www.example.com/1.2.3.4 dnsrecord=www.example.com/2606:2800:220:1:248:1893:25c8:1946 - -# IPSET MANAGEMENT -# ---------------- -# Create and mange ipset on linux based on destinations in rule files -# - add ip/cidrs in rule files on startup -# - add resolved ips for domains in rule files by dns forwarding server -# Usually used in transparent proxy mode on linux -ipset=glider - # INTERFACE SPECIFIC # ------------------ # Specify the outbound ip/interface. diff --git a/config/rules.d/office.rule.example b/config/rules.d/office.rule.example index fabf3bb..4147d83 100644 --- a/config/rules.d/office.rule.example +++ b/config/rules.d/office.rule.example @@ -20,9 +20,13 @@ checkduration=30 # DNS SERVER for domains in this rule file dnsserver=208.67.222.222:53 -# IPSET -# specify a ipset for destinations in this rule file -#ipset=office +# IPSET MANAGEMENT +# ---------------- +# Create and mange ipset on linux based on destinations in rule files +# - add ip/cidrs in rule files on startup +# - add resolved ips for domains in rule files by dns forwarding server +# Usually used in transparent proxy mode on linux +ipset=glider # DESTINATIONS # ------------ diff --git a/dns/server.go b/dns/server.go index 0531e11..cceff27 100644 --- a/dns/server.go +++ b/dns/server.go @@ -91,17 +91,17 @@ func (s *Server) ListenAndServeTCP(wg *sync.WaitGroup) { l, err := net.Listen("tcp", s.addr) wg.Done() if err != nil { - log.F("[dns]-tcp error: %v", err) + log.F("[dns-tcp] error: %v", err) return } defer l.Close() - log.F("[dns]-tcp listening TCP on %s", s.addr) + log.F("[dns-tcp] listening TCP on %s", s.addr) for { c, err := l.Accept() if err != nil { - log.F("[dns]-tcp error: failed to accept: %v", err) + log.F("[dns-tcp] error: failed to accept: %v", err) continue } go s.ServeTCP(c) @@ -116,14 +116,14 @@ func (s *Server) ServeTCP(c net.Conn) { var reqLen uint16 if err := binary.Read(c, binary.BigEndian, &reqLen); err != nil { - log.F("[dns]-tcp failed to get request length: %v", err) + log.F("[dns-tcp] failed to get request length: %v", err) return } reqBytes := make([]byte, reqLen+2) _, err := io.ReadFull(c, reqBytes[2:]) if err != nil { - log.F("[dns]-tcp error in read reqBytes %s", err) + log.F("[dns-tcp] error in read reqBytes %s", err) return } @@ -131,12 +131,12 @@ func (s *Server) ServeTCP(c net.Conn) { respBytes, err := s.Exchange(reqBytes, c.RemoteAddr().String(), true) if err != nil { - log.F("[dns]-tcp error in exchange: %s", err) + log.F("[dns-tcp] error in exchange: %s", err) return } if err := binary.Write(c, binary.BigEndian, respBytes); err != nil { - log.F("[dns]-tcp error in local write respBytes: %s", err) + log.F("[dns-tcp] error in local write respBytes: %s", err) return } } diff --git a/ipset/ipset_linux.go b/ipset/ipset_linux.go index b19d6c0..e3a1573 100644 --- a/ipset/ipset_linux.go +++ b/ipset/ipset_linux.go @@ -73,12 +73,11 @@ type Manager struct { fd int lsa syscall.SockaddrNetlink - mainSet string domainSet sync.Map } // NewManager returns a Manager -func NewManager(mainSet string, rules []*rule.Config) (*Manager, error) { +func NewManager(rules []*rule.Config) (*Manager, error) { fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_NETFILTER) if err != nil { log.F("%s", err) @@ -95,37 +94,28 @@ func NewManager(mainSet string, rules []*rule.Config) (*Manager, error) { return nil, err } - m := &Manager{fd: fd, lsa: lsa, mainSet: mainSet} - CreateSet(fd, lsa, mainSet) + m := &Manager{fd: fd, lsa: lsa} + // create ipset for _, r := range rules { - set := r.IPSet - - if set != "" && set != m.mainSet { - CreateSet(fd, lsa, set) - } else { - set = m.mainSet + if r.IPSet != "" { + CreateSet(fd, lsa, r.IPSet) } + } - // if dialer is Direct, do not insert to ipset, in order to avoid iptables redirect loop - if len(r.Forward) == 0 { - continue + // init ipset + for _, r := range rules { + if r.IPSet != "" { + for _, domain := range r.Domain { + m.domainSet.Store(domain, r.IPSet) + } + for _, ip := range r.IP { + AddToSet(fd, lsa, r.IPSet, ip) + } + for _, cidr := range r.CIDR { + AddToSet(fd, lsa, r.IPSet, cidr) + } } - - for _, domain := range r.Domain { - m.domainSet.Store(domain, set) - } - - for _, ip := range r.IP { - AddToSet(fd, lsa, mainSet, ip) - AddToSet(fd, lsa, r.IPSet, ip) - } - - for _, cidr := range r.CIDR { - AddToSet(fd, lsa, mainSet, cidr) - AddToSet(fd, lsa, r.IPSet, cidr) - } - } return m, nil @@ -141,14 +131,11 @@ func (m *Manager) AddDomainIP(domain, ip string) error { // find in domainMap if ipset, ok := m.domainSet.Load(domain); ok { - AddToSet(m.fd, m.lsa, m.mainSet, ip) - if ipset.(string) != m.mainSet { - AddToSet(m.fd, m.lsa, ipset.(string), ip) - } + AddToSet(m.fd, m.lsa, ipset.(string), ip) } } - } + return nil } diff --git a/ipset/ipset_other.go b/ipset/ipset_other.go index ab9be65..91445ad 100644 --- a/ipset/ipset_other.go +++ b/ipset/ipset_other.go @@ -12,7 +12,7 @@ import ( type Manager struct{} // NewManager returns a Manager -func NewManager(mainSet string, rules []*rule.Config) (*Manager, error) { +func NewManager(rules []*rule.Config) (*Manager, error) { return nil, errors.New("ipset not supported on this os") } diff --git a/main.go b/main.go index 8634a86..b288d79 100644 --- a/main.go +++ b/main.go @@ -44,7 +44,7 @@ func main() { dialer := rule.NewDialer(conf.rules, strategy.NewDialer(conf.Forward, &conf.StrategyConfig)) // ipset manager - ipsetM, _ := ipset.NewManager(conf.IPSet, conf.rules) + ipsetM, _ := ipset.NewManager(conf.rules) // check and setup dns server if conf.DNS != "" { diff --git a/proxy/socks5/socks5.go b/proxy/socks5/socks5.go index f3e8573..224196b 100644 --- a/proxy/socks5/socks5.go +++ b/proxy/socks5/socks5.go @@ -232,7 +232,7 @@ func (s *SOCKS5) Dial(network, addr string) (net.Conn, error) { c, err := s.dialer.Dial(network, s.addr) if err != nil { - log.F("dial to %s error: %s", s.addr, err) + log.F("[socks5]: dial to %s error: %s", s.addr, err) return nil, err } diff --git a/proxy/tls/tls.go b/proxy/tls/tls.go index 7e1a4b8..6a8fcdc 100644 --- a/proxy/tls/tls.go +++ b/proxy/tls/tls.go @@ -33,7 +33,7 @@ func init() { proxy.RegisterServer("tls", NewTLSServer) } -// NewTLS returns a tls proxy +// NewTLS returns a tls proxy struct func NewTLS(s string, dialer proxy.Dialer) (*TLS, error) { u, err := url.Parse(s) if err != nil { @@ -69,7 +69,7 @@ func NewTLS(s string, dialer proxy.Dialer) (*TLS, error) { return p, nil } -// NewTLSDialer returns a tls proxy dialer. +// NewTLSDialer returns a tls proxy dialer func NewTLSDialer(s string, dialer proxy.Dialer) (proxy.Dialer, error) { p, err := NewTLS(s, dialer) if err != nil { @@ -104,7 +104,7 @@ func NewTLSServer(s string, dialer proxy.Dialer) (proxy.Server, error) { cert, err := stdtls.LoadX509KeyPair(p.certFile, p.keyFile) if err != nil { - log.F("[tls] unabled load cert: %s, key %s", p.certFile, p.keyFile) + log.F("[tls] unable to load cert: %s, key %s", p.certFile, p.keyFile) return nil, err } @@ -144,8 +144,11 @@ func (s *TLS) ListenAndServe() { } } -// Serve . +// Serve serves requests func (s *TLS) Serve(c net.Conn) { + // we know the internal server will close the connection after serve + // defer c.Close() + if s.server != nil { cc := stdtls.Server(c, s.tlsConfig) s.server.Serve(cc) diff --git a/proxy/unix/unix.go b/proxy/unix/unix.go index 0395da1..0a43e62 100644 --- a/proxy/unix/unix.go +++ b/proxy/unix/unix.go @@ -93,7 +93,8 @@ func (s *Unix) ListenAndServe() { // Serve serves requests func (s *Unix) Serve(c net.Conn) { - defer c.Close() + // we know the internal server will close the connection after serve + // defer c.Close() if s.server != nil { s.server.Serve(c)