2017-08-23 16:35:39 +08:00
package main
import (
"fmt"
"os"
2017-08-25 20:32:51 +08:00
"path"
2017-08-23 16:35:39 +08:00
"github.com/nadoo/conflag"
2018-08-11 11:46:10 +08:00
2018-08-12 22:07:19 +08:00
"github.com/nadoo/glider/dns"
2022-01-08 15:05:55 +08:00
"github.com/nadoo/glider/pkg/log"
2021-07-24 23:45:53 +08:00
"github.com/nadoo/glider/proxy"
2018-08-12 22:24:49 +08:00
"github.com/nadoo/glider/rule"
2017-08-23 16:35:39 +08:00
)
var flag = conflag . New ( )
2020-10-03 20:51:27 +08:00
// Config is global config struct.
2020-09-26 23:34:26 +08:00
type Config struct {
2021-07-24 23:45:53 +08:00
Verbose bool
LogFlags int
TCPBufSize int
UDPBufSize int
2018-08-10 19:03:30 +08:00
2020-09-27 19:50:21 +08:00
Listens [ ] string
2018-08-10 19:03:30 +08:00
2020-11-20 18:11:25 +08:00
Forwards [ ] string
Strategy rule . Strategy
2018-08-10 19:03:30 +08:00
2020-09-27 19:50:21 +08:00
RuleFiles [ ] string
RulesDir string
2017-08-23 16:35:39 +08:00
2018-08-12 22:07:19 +08:00
DNS string
DNSConfig dns . Config
2017-08-23 16:35:39 +08:00
2018-08-12 22:24:49 +08:00
rules [ ] * rule . Config
2020-09-27 19:50:21 +08:00
Services [ ] string
2017-08-23 16:35:39 +08:00
}
2020-09-26 23:34:26 +08:00
func parseConfig ( ) * Config {
conf := & Config { }
2019-10-21 21:03:19 +08:00
flag . SetOutput ( os . Stdout )
2022-02-16 23:37:25 +08:00
scheme := flag . String ( "scheme" , "" , "show help message of proxy scheme, use 'all' to see all schemes" )
example := flag . Bool ( "example" , false , "show usage examples" )
2022-02-15 21:34:55 +08:00
2017-08-23 16:35:39 +08:00
flag . BoolVar ( & conf . Verbose , "verbose" , false , "verbose mode" )
2022-02-15 21:34:55 +08:00
flag . IntVar ( & conf . LogFlags , "logflags" , 19 , "do not change it if you do not know what it is, ref: https://pkg.go.dev/log#pkg-constants" )
2021-07-24 23:45:53 +08:00
flag . IntVar ( & conf . TCPBufSize , "tcpbufsize" , 32768 , "tcp buffer size in Bytes" )
flag . IntVar ( & conf . UDPBufSize , "udpbufsize" , 2048 , "udp buffer size in Bytes" )
2022-02-15 21:34:55 +08:00
flag . StringSliceUniqVar ( & conf . Listens , "listen" , nil , "listen url, see the URL section below" )
flag . StringSliceVar ( & conf . Forwards , "forward" , nil , "forward url, see the URL section below" )
flag . StringVar ( & conf . Strategy . Strategy , "strategy" , "rr" , ` rr : Round Robin mode
ha : High Availability mode
lha : Latency based High Availability mode
dh : Destination Hashing mode ` )
flag . StringVar ( & conf . Strategy . Check , "check" , "http://www.msftconnecttest.com/connecttest.txt#expect=200" ,
` check = tcp [ : //HOST:PORT]: tcp port connect check
check = http : //HOST[:PORT][/URI][#expect=REGEX_MATCH_IN_RESP_LINE]
check = https : //HOST[:PORT][/URI][#expect=REGEX_MATCH_IN_RESP_LINE]
check = file : //SCRIPT_PATH: run a check script, healthy when exitcode=0, env vars: FORWARDER_ADDR,FORWARDER_URL
check = disable : disable health check ` )
2020-11-20 18:11:25 +08:00
flag . IntVar ( & conf . Strategy . CheckInterval , "checkinterval" , 30 , "fowarder check interval(seconds)" )
flag . IntVar ( & conf . Strategy . CheckTimeout , "checktimeout" , 10 , "fowarder check timeout(seconds)" )
flag . IntVar ( & conf . Strategy . CheckTolerance , "checktolerance" , 0 , "fowarder check tolerance(ms), switch only when new_latency < old_latency - tolerance, only used in lha mode" )
2022-02-20 21:37:36 +08:00
flag . IntVar ( & conf . Strategy . CheckLatencySamples , "checklatencysamples" , 10 , "use the average latency of the latest N checks" )
2020-11-20 18:11:25 +08:00
flag . BoolVar ( & conf . Strategy . CheckDisabledOnly , "checkdisabledonly" , false , "check disabled fowarders only" )
flag . IntVar ( & conf . Strategy . MaxFailures , "maxfailures" , 3 , "max failures to change forwarder status to disabled" )
flag . IntVar ( & conf . Strategy . DialTimeout , "dialtimeout" , 3 , "dial timeout(seconds)" )
flag . IntVar ( & conf . Strategy . RelayTimeout , "relaytimeout" , 0 , "relay timeout(seconds)" )
flag . StringVar ( & conf . Strategy . IntFace , "interface" , "" , "source ip or source interface" )
2018-08-10 19:03:30 +08:00
2020-09-27 19:50:21 +08:00
flag . StringSliceUniqVar ( & conf . RuleFiles , "rulefile" , nil , "rule file path" )
2017-09-04 23:32:12 +08:00
flag . StringVar ( & conf . RulesDir , "rules-dir" , "" , "rule file folder" )
2017-08-23 16:35:39 +08:00
2020-10-08 18:48:23 +08:00
// dns configs
2018-11-28 23:28:32 +08:00
flag . StringVar ( & conf . DNS , "dns" , "" , "local dns server listen address" )
flag . StringSliceUniqVar ( & conf . DNSConfig . Servers , "dnsserver" , [ ] string { "8.8.8.8:53" } , "remote dns server address" )
2018-08-27 00:01:09 +08:00
flag . BoolVar ( & conf . DNSConfig . AlwaysTCP , "dnsalwaystcp" , false , "always use tcp to query upstream dns servers no matter there is a forwarder or not" )
2018-08-12 22:07:19 +08:00
flag . IntVar ( & conf . DNSConfig . Timeout , "dnstimeout" , 3 , "timeout value used in multiple dnsservers switch(seconds)" )
flag . IntVar ( & conf . DNSConfig . MaxTTL , "dnsmaxttl" , 1800 , "maximum TTL value for entries in the CACHE(seconds)" )
flag . IntVar ( & conf . DNSConfig . MinTTL , "dnsminttl" , 0 , "minimum TTL value for entries in the CACHE(seconds)" )
2022-02-15 21:34:55 +08:00
flag . IntVar ( & conf . DNSConfig . CacheSize , "dnscachesize" , 4096 , "max number of dns response in CACHE" )
2021-05-30 12:18:05 +08:00
flag . BoolVar ( & conf . DNSConfig . CacheLog , "dnscachelog" , false , "show query log of dns cache" )
2022-01-20 21:59:40 +08:00
flag . BoolVar ( & conf . DNSConfig . NoAAAA , "dnsnoaaaa" , false , "disable AAAA query" )
2018-08-12 22:07:19 +08:00
flag . StringSliceUniqVar ( & conf . DNSConfig . Records , "dnsrecord" , nil , "custom dns record, format: domain/ip" )
2017-08-23 16:35:39 +08:00
2020-10-08 18:48:23 +08:00
// service configs
2020-10-01 22:38:34 +08:00
flag . StringSliceUniqVar ( & conf . Services , "service" , nil , "run specified services, format: SERVICE_NAME[,SERVICE_CONFIG]" )
2020-09-27 19:50:21 +08:00
2017-08-23 16:35:39 +08:00
flag . Usage = usage
err := flag . Parse ( )
if err != nil {
2019-03-01 00:59:55 +08:00
// flag.Usage()
2017-08-23 16:35:39 +08:00
fmt . Fprintf ( os . Stderr , "ERROR: %s\n" , err )
os . Exit ( - 1 )
}
2022-02-15 21:34:55 +08:00
if * scheme != "" {
2022-02-16 23:37:25 +08:00
fmt . Fprintf ( flag . Output ( ) , proxy . Usage ( * scheme ) )
os . Exit ( 0 )
}
if * example {
fmt . Fprintf ( flag . Output ( ) , examples )
2022-02-15 21:34:55 +08:00
os . Exit ( 0 )
}
2022-01-28 23:35:29 +08:00
// setup logger
log . Set ( conf . Verbose , conf . LogFlags )
2020-09-26 23:34:26 +08:00
2020-09-27 19:50:21 +08:00
if len ( conf . Listens ) == 0 && conf . DNS == "" && len ( conf . Services ) == 0 {
2019-03-01 00:59:55 +08:00
// flag.Usage()
2017-08-23 16:35:39 +08:00
fmt . Fprintf ( os . Stderr , "ERROR: listen url must be specified.\n" )
os . Exit ( - 1 )
}
2021-07-24 23:45:53 +08:00
// tcpbufsize
if conf . TCPBufSize > 0 {
proxy . TCPBufSize = conf . TCPBufSize
}
// udpbufsize
if conf . UDPBufSize > 0 {
proxy . UDPBufSize = conf . UDPBufSize
}
2017-08-23 16:35:39 +08:00
// rulefiles
2020-09-27 19:50:21 +08:00
for _ , ruleFile := range conf . RuleFiles {
2018-08-30 07:36:46 +08:00
if ! path . IsAbs ( ruleFile ) {
ruleFile = path . Join ( flag . ConfDir ( ) , ruleFile )
}
2018-09-17 19:16:17 +08:00
2018-08-12 22:24:49 +08:00
rule , err := rule . NewConfFromFile ( ruleFile )
2017-08-23 16:35:39 +08:00
if err != nil {
log . Fatal ( err )
}
conf . rules = append ( conf . rules , rule )
}
2017-09-04 23:32:12 +08:00
if conf . RulesDir != "" {
2018-07-29 23:44:23 +08:00
if ! path . IsAbs ( conf . RulesDir ) {
conf . RulesDir = path . Join ( flag . ConfDir ( ) , conf . RulesDir )
}
2017-08-25 20:32:51 +08:00
2018-09-17 19:16:17 +08:00
ruleFolderFiles , _ := rule . ListDir ( conf . RulesDir , ".rule" )
2017-09-04 23:32:12 +08:00
for _ , ruleFile := range ruleFolderFiles {
2018-08-12 22:24:49 +08:00
rule , err := rule . NewConfFromFile ( ruleFile )
2017-09-04 23:32:12 +08:00
if err != nil {
log . Fatal ( err )
}
conf . rules = append ( conf . rules , rule )
}
2017-08-23 16:35:39 +08:00
}
2017-09-04 23:32:12 +08:00
2020-09-26 23:34:26 +08:00
return conf
2017-08-23 16:35:39 +08:00
}
func usage ( ) {
2022-02-16 23:37:25 +08:00
fmt . Fprint ( flag . Output ( ) , usage1 )
flag . PrintDefaults ( )
fmt . Fprintf ( flag . Output ( ) , usage2 , proxy . ServerSchemes ( ) , proxy . DialerSchemes ( ) , version )
}
2019-10-21 21:03:19 +08:00
2022-02-16 23:37:25 +08:00
var usage1 = `
2022-02-15 21:34:55 +08:00
Usage : glider [ - listen URL ] ... [ - forward URL ] ... [ OPTION ] ...
2022-02-16 00:25:14 +08:00
2022-02-15 21:34:55 +08:00
e . g . glider - config / etc / glider / glider . conf
glider - listen : 8443 - forward socks5 : //serverA:1080 -forward socks5://serverB:1080 -verbose
2022-02-16 23:37:25 +08:00
OPTION :
`
2022-02-15 21:34:55 +08:00
2022-02-16 23:37:25 +08:00
var usage2 = `
2022-02-15 21:34:55 +08:00
URL :
proxy : SCHEME : //[USER:PASS@][HOST]:PORT
2022-02-16 00:25:14 +08:00
chain : proxy , proxy [ , proxy ] ...
2022-02-15 21:34:55 +08:00
e . g . - listen socks5 : //:1080
- listen tls : //:443?cert=crtFilePath&key=keyFilePath,http:// (protocol chain)
e . g . - forward socks5 : //server:1080
- forward tls : //server.com:443,http:// (protocol chain)
- forward socks5 : //serverA:1080,socks5://serverB:1080 (proxy chain)
2022-02-16 23:37:25 +08:00
SCHEME :
listen : % s
forward : % s
2022-02-15 21:34:55 +08:00
2022-02-16 23:37:25 +08:00
Note : use ' glider - scheme all ' or ' glider - scheme SCHEME ' to see help info for the scheme .
2022-02-15 21:34:55 +08:00
--
Forwarder Options : FORWARD_URL # OPTIONS
priority : the priority of that forwarder , the larger the higher , default : 0
interface : the local interface or ip address used to connect remote server .
e . g . - forward socks5 : //server:1080#priority=100
- forward socks5 : //server:1080#interface=eth0
- forward socks5 : //server:1080#priority=100&interface=192.168.1.99
Services :
dhcpd : service = dhcpd , INTERFACE , START_IP , END_IP , LEASE_MINUTES [ , MAC = IP , MAC = IP ... ]
e . g . service = dhcpd , eth1 , 192.168 .1 .100 , 192.168 .1 .199 , 720
2022-02-16 23:37:25 +08:00
--
Help :
glider - help
glider - scheme all
glider - example
2022-02-15 21:34:55 +08:00
2022-02-16 23:37:25 +08:00
see README . md and glider . conf . example for more details .
--
glider % s , https : //github.com/nadoo/glider
`
var examples = `
Examples :
glider - config glider . conf
- run glider with specified config file .
glider - listen : 8443 - verbose
- listen on : 8443 , serve as http / socks5 proxy on the same port , in verbose mode .
glider - listen : 8443 - forward direct : //#interface=eth0 -forward direct://#interface=eth1
- listen on 8443 and forward requests via interface eth0 and eth1 in round robin mode .
glider - listen tls : //:443?cert=crtFilePath&key=keyFilePath,http:// -verbose
- listen on : 443 as a https ( http over tls ) proxy server .
glider - listen http : //:8080 -forward socks5://serverA:1080,socks5://serverB:1080
- listen on : 8080 as a http proxy server , forward all requests via forward chain .
glider - listen : 8443 - forward socks5 : //serverA:1080 -forward socks5://serverB:1080#priority=10 -forward socks5://serverC:1080#priority=10
- serverA will only be used when serverB and serverC are not available .
glider - listen tcp : //:80 -forward tcp://serverA:80
- tcp tunnel : listen on : 80 and forward all requests to serverA : 80.
glider - listen udp : //:53 -forward socks5://serverA:1080,udp://8.8.8.8:53
- listen on : 53 and forward all udp requests to 8.8 .8 .8 : 53 via remote socks5 server .
glider - verbose - listen - dns = : 53 - dnsserver = 8.8 .8 .8 : 53 - forward socks5 : //serverA:1080 -dnsrecord=www.example.com/1.2.3.4
- listen on : 53 as dns server , forward to 8.8 .8 .8 : 53 via socks5 server .
`