diff --git a/config.go b/config.go index 4fd2856..2402a94 100755 --- a/config.go +++ b/config.go @@ -21,7 +21,7 @@ func initConfig() (err error) { //define args tcpArgs := services.TCPArgs{} httpArgs := services.HTTPArgs{} - // tlsArgs := services.TLSArgs{} + tunnelArgs := services.TunnelArgs{} udpArgs := services.UDPArgs{} //build srvice args @@ -56,6 +56,9 @@ func initConfig() (err error) { udp := app.Command("udp", "proxy on udp mode") udpArgs.Timeout = udp.Flag("timeout", "tcp timeout milliseconds when connect to parent proxy").Short('t').Default("2000").Int() udpArgs.ParentType = udp.Flag("parent-type", "parent protocol type ").Short('T').Enum("tls", "tcp", "udp") + //########tunnel######### + tunnel := app.Command("tcp", "proxy on tunnel mode") + tunnelArgs.Timeout = tunnel.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int() kingpin.MustParse(app.Parse(os.Args[1:])) @@ -74,11 +77,13 @@ func initConfig() (err error) { os.Exit(0) } } + poster() //regist services and run service serviceName := kingpin.MustParse(app.Parse(os.Args[1:])) services.Regist("http", services.NewHTTP(), httpArgs) services.Regist("tcp", services.NewTCP(), tcpArgs) services.Regist("udp", services.NewUDP(), udpArgs) + services.Regist("tunnel", services.NewTunnel(), tunnelArgs) service, err = services.Run(serviceName) if err != nil { log.Fatalf("run service [%s] fail, ERR:%s", service, err) diff --git a/main.go b/main.go index 53a16be..1057e85 100644 --- a/main.go +++ b/main.go @@ -9,111 +9,8 @@ import ( "syscall" ) -const APP_VERSION = "2.2" +const APP_VERSION = "3.0" -// var ( -// checker Checker -// certBytes []byte -// keyBytes []byte -// outPool ConnPool -// basicAuth BasicAuth -// ) - -func init() { - - // return - // //Init - // err = Init() - // if err != nil { - // log.Fatalf("err : %s", err) - // } - // isLocalHTTP := cfg.GetBool("local-http") - // isTLS := cfg.GetBool("local-tls") || cfg.GetBool("parent-tls") - // isTCP := isLocalHTTP || isTLS || cfg.GetBool("local-tcp") || cfg.GetBool("parent-tcp") - - // //InitTCP - // if isTCP { - // err = InitTCP() - // } - // if err != nil { - // log.Fatalf("err : %s", err) - // } - // //InitTLS - // if isTLS { - // err = InitTLS() - // } - // if err != nil { - // log.Fatalf("err : %s", err) - // } - // //InitUDP - // if cfg.GetBool("local-udp") || cfg.GetBool("parent-udp") { - // err = InitUDP() - // } - // if err != nil { - // log.Fatalf("err : %s", err) - // } - // //InitLocal - // err = InitLocal() - // if err != nil { - // log.Fatalf("err : %s", err) - // } - // //InitLocalTCP - // if cfg.GetBool("local-tcp") || cfg.GetBool("local-tls") || isLocalHTTP { - // err = InitLocalTCP() - // } - // if err != nil { - // log.Fatalf("err : %s", err) - // } - // //InitLocalTLS - // if cfg.GetBool("local-tls") { - // err = InitLocalTLS() - // } - // if err != nil { - // log.Fatalf("err : %s", err) - // } - // //InitLocalHTTP - // if isLocalHTTP { - // err = InitLocalHTTP() - // } - // if err != nil { - // log.Fatalf("err : %s", err) - // } - // //InitLocalUDP - // if cfg.GetBool("local-udp") { - // err = InitLocalUDP() - // } - // if err != nil { - // log.Fatalf("err : %s", err) - // } - // //InitParent - // if cfg.GetString("parent") != "" { - // err = InitParent() - // if err != nil { - // log.Fatalf("err : %s", err) - // } - // //InitParentTCP - // if cfg.GetBool("parent-tcp") || cfg.GetBool("parent-tls") { - // err = InitParentTCP() - // } - // if err != nil { - // log.Fatalf("err : %s", err) - // } - // //InitParentTLS - // if cfg.GetBool("parent-tls") { - // err = InitParentTLS() - // } - // if err != nil { - // log.Fatalf("err : %s", err) - // } - // //InitParentUDP - // if cfg.GetBool("parent-udp") { - // err = InitParentUDP() - // } - // if err != nil { - // log.Fatalf("err : %s", err) - // } - // } -} func main() { err := initConfig() if err != nil { @@ -122,7 +19,6 @@ func main() { Clean(&service.S) } func Clean(s *services.Service) { - //block main() signalChan := make(chan os.Signal, 1) cleanupDone := make(chan bool) signal.Notify(signalChan, @@ -140,469 +36,3 @@ func Clean(s *services.Service) { }() <-cleanupDone } - -// func Init() (err error) { -// return -// } -// func InitTCP() (err error) { -// return -// } -// func InitTLS() (err error) { -// certBytes, err = ioutil.ReadFile(cfg.GetString("cert")) -// if err != nil { -// log.Printf("err : %s", err) -// return -// } -// keyBytes, err = ioutil.ReadFile(cfg.GetString("key")) -// if err != nil { -// log.Printf("err : %s", err) -// return -// } -// return -// } -// func InitUDP() (err error) { -// return -// } -// func InitLocal() (err error) { -// return -// } -// func InitLocalTCP() (err error) { -// return -// } -// func InitLocalTLS() (err error) { - -// return -// } -// func InitLocalHTTP() (err error) { -// err = InitBasicAuth() -// if err != nil { -// return -// } -// return -// } - -// func InitLocalUDP() (err error) { -// return -// } -// func InitParent() (err error) { -// initOutPool(cfg.GetBool("parent-tls"), certBytes, keyBytes, cfg.GetString("parent"), cfg.GetInt("tcp-timeout"), cfg.GetInt("pool-size"), cfg.GetInt("pool-size")*2) -// checker = NewChecker(cfg.GetInt("check-timeout"), int64(cfg.GetInt("check-interval")), cfg.GetString("blocked"), cfg.GetString("direct")) -// log.Printf("use parent proxy : %s, udp : %v, tcp : %v, tls: %v", cfg.GetString("parent"), cfg.GetBool("parent-udp"), cfg.GetBool("parent-tcp"), cfg.GetBool("parent-tls")) -// return -// } -// func InitParentTCP() (err error) { -// return -// } -// func InitParentTLS() (err error) { -// return -// } -// func InitParentUDP() (err error) { -// return -// } -// func main() { -// //catch panic error -// defer func() { -// e := recover() -// if e != nil { -// log.Printf("err : %s,\ntrace:%s", e, string(debug.Stack())) -// } -// }() -// return -// sc := NewServerChannel(cfg.GetString("ip"), cfg.GetInt("port")) -// if cfg.GetBool("local-tls") { -// LocalTLSServer(&sc) -// } else if cfg.GetBool("local-tcp") { -// LocalTCPServer(&sc) -// } else if cfg.GetBool("local-udp") { -// LocalUDPServer(&sc) -// } -// log.Printf("proxy on %s , udp: %v, tcp: %v, tls: %v ,http: %v", (*sc.Listener).Addr(), cfg.GetBool("local-udp"), cfg.GetBool("local-tcp"), cfg.GetBool("local-tls"), cfg.GetBool("local-http")) - -// clean() -// } - -// func CheckTCPDeocder(inConn *net.Conn) (useProxy bool, address string, req *HTTPRequest, err error) { -// if cfg.GetBool("local-http") { -// useProxy, req, err = HTTPProxyDecoder(inConn) -// if err != nil { -// return -// } -// address = req.Host -// } else { -// address = cfg.GetString("parent") -// } -// if address == "" { -// useProxy = false -// } else if cfg.GetBool("always") { -// useProxy = true -// } -// return -// } -// func LocalTCPServer(sc *ServerChannel) { -// (*sc).ListenTCP(func(inConn net.Conn) { -// userProxy, address, req, err := CheckTCPDeocder(&inConn) -// if err != nil { -// if err != io.EOF { -// log.Printf("tcp decode error , ERR:%s", err) -// } -// return -// } -// TCPOutBridge(&inConn, userProxy, address, req) -// }) -// } - -// func LocalTLSServer(sc *ServerChannel) { -// (*sc).ListenTls(certBytes, keyBytes, func(inConn net.Conn) { -// userProxy, address, req, err := CheckTCPDeocder(&inConn) -// if err != nil { -// if err != io.EOF { -// log.Printf("tls decode error , ERR:%s", err) -// } -// return -// } -// TCPOutBridge(&inConn, userProxy, address, req) -// }) -// } - -// func LocalUDPServer(sc *ServerChannel) { -// (*sc).ListenUDP(func(packet []byte, localAddr, srcAddr *net.UDPAddr) { - -// }) -// } - -// func TCPOutBridge(inConn *net.Conn, userProxy bool, address string, req *HTTPRequest) { -// var outConn net.Conn -// var _outConn interface{} -// var err error -// if userProxy { -// _outConn, err = outPool.Get() -// if err == nil { -// outConn = _outConn.(net.Conn) -// } -// } else { -// outConn, err = ConnectHost(address, cfg.GetInt("tcp-timeout")) -// } -// if err != nil { -// log.Printf("connect to %s , err:%s", address, err) -// closeConn(inConn) -// return -// } -// inAddr := (*inConn).RemoteAddr().String() -// outAddr := outConn.RemoteAddr().String() -// log.Printf("%s use proxy %v", address, userProxy) - -// if req != nil { -// if req.IsHTTPS() && !userProxy { -// req.HTTPSReply() -// } else { -// outConn.Write(req.headBuf) -// } -// } - -// IoBind(*inConn, outConn, func(err error) { -// log.Printf("conn %s - %s [%s] released", inAddr, outAddr, address) -// closeConn(inConn) -// closeConn(&outConn) -// }, func(n int, d bool) {}, 0) -// log.Printf("conn %s - %s [%s] connected", inAddr, outAddr, address) -// } -// func UDPOutBridge() { - -// } - -// func DoUDP() { -// if cfg.GetBool("local-udp") { - -// } else { - -// } -// } - -// //DoTCP contains tcp && http -// func DoTCP() { -// //define command line args -// proxyIsTls = cfg.GetBool("parent-tls") -// localIsTls = cfg.GetBool("local-tls") -// proxyAddr = cfg.GetString("parent") -// bindIP := cfg.GetString("ip") -// bindPort := cfg.GetInt("port") -// timeout := cfg.GetInt("check-timeout") -// connTimeout = cfg.GetInt("tcp-timeout") -// interval := cfg.GetInt("check-interval") -// certFile := cfg.GetString("cert") -// keyFile := cfg.GetString("key") -// blockedFile := cfg.GetString("blocked") -// directFile := cfg.GetString("direct") - -// isTCP = cfg.GetBool("tcp") -// poolInitSize := cfg.GetInt("pool-size") - -// //check args required -// if proxyIsTls && proxyAddr == "" { -// log.Fatalf("parent proxy address required") -// } - -// //check tls cert&key file -// if certFile == "" { -// certFile = "proxy.crt" -// } -// if keyFile == "" { -// keyFile = "proxy.key" -// } -// if proxyIsTls || localIsTls { -// certBytes, err = ioutil.ReadFile(certFile) -// if err != nil { -// log.Printf("err : %s", err) -// return -// } -// keyBytes, err = ioutil.ReadFile(keyFile) -// if err != nil { -// log.Printf("err : %s", err) -// return -// } -// } -// //init tls info string -// var proxyIsTlsStr string -// var localIsTlsStr string -// protocolStr := "tcp" -// if !isTCP { -// protocolStr = "http(s)" -// } -// if proxyIsTls { -// proxyIsTlsStr = "tls " -// } -// if localIsTls { -// localIsTlsStr = "tls " -// } -// //init checker and pool if needed -// if proxyAddr != "" { -// if !isTCP && !cfg.GetBool("always") { -// checker = NewChecker(timeout, int64(interval), blockedFile, directFile) -// } -// log.Printf("use %sparent %s proxy : %s", proxyIsTlsStr, protocolStr, proxyAddr) -// initOutPool(proxyIsTls, certBytes, keyBytes, proxyAddr, connTimeout, poolInitSize, poolInitSize*2) -// } else if isTCP { -// log.Printf("tcp proxy need parent") -// return -// } -// //init basic auth only in http mode -// if !isTCP { -// basicAuth = NewBasicAuth() -// if cfg.GetString("auth-file") != "" { -// httpAuthorization = true -// n, err := basicAuth.AddFromFile(cfg.GetString("auth-file")) -// if err != nil { -// log.Fatalf("auth-file:%s", err) -// } -// log.Printf("auth data added from file %d , total:%d", n, basicAuth.Total()) -// } -// if len(cfg.GetStringSlice("auth")) > 0 { -// httpAuthorization = true -// n := basicAuth.Add(cfg.GetStringSlice("auth")) -// log.Printf("auth data added %d, total:%d", n, basicAuth.Total()) -// } -// } - -// //listen -// sc := NewServerChannel(bindIP, bindPort) -// var err error -// if localIsTls { -// err = sc.ListenTls(certBytes, keyBytes, connHandler) -// } else { -// err = sc.ListenTCP(connHandler) -// } -// //listen fail -// if err != nil { -// log.Fatalf("ERR:%s", err) -// } else { -// log.Printf("%s %sproxy on %s", protocolStr, localIsTlsStr, (*sc.Listener).Addr()) -// } -// } -// func connHandler(inConn net.Conn) { -// defer func() { -// err := recover() -// if err != nil { -// log.Printf("connHandler crashed,err:%s\nstack:%s", err, string(debug.Stack())) -// closeConn(&inConn) -// } -// }() -// if isTCP { -// tcpHandler(&inConn) -// } else { -// httpHandler(&inConn) -// } -// } - -// func tcpHandler(inConn *net.Conn) { -// var outConn net.Conn -// var _outConn interface{} -// _outConn, err = outPool.Get() -// if err != nil { -// log.Printf("connect to %s , err:%s", proxyAddr, err) -// closeConn(inConn) -// return -// } -// outConn = _outConn.(net.Conn) -// inAddr := (*inConn).RemoteAddr().String() -// outAddr := outConn.RemoteAddr().String() -// IoBind((*inConn), outConn, func(err error) { -// log.Printf("conn %s - %s released", inAddr, outAddr) -// closeConn(inConn) -// closeConn(&outConn) -// }, func(n int, d bool) {}, 0) -// log.Printf("conn %s - %s connected", inAddr, outAddr) -// } -// func httpHandler(inConn *net.Conn) { -// var b [4096]byte -// var n int -// n, err = (*inConn).Read(b[:]) -// if err != nil { -// if err != io.EOF { -// log.Printf("read err:%s", err) -// } -// closeConn(inConn) -// return -// } -// var method, host, address string -// index := bytes.IndexByte(b[:], '\n') -// if index == -1 { -// log.Printf("data err:%s", string(b[:n])[:50]) -// closeConn(inConn) -// return -// } - -// fmt.Sscanf(string(b[:index]), "%s%s", &method, &host) -// if method == "" || host == "" { -// log.Printf("data err:%s", string(b[:n])[:50]) -// closeConn(inConn) -// return -// } -// isHTTPS := method == "CONNECT" - -// //http basic auth,only http -// if !isHTTPS { -// if httpAuthorization { -// //log.Printf("request :%s", string(b[:n])) -// authorization, err := getHeader("Authorization", b[:n]) -// if err != nil { -// fmt.Fprint(*inConn, "HTTP/1.1 401 Unauthorized\r\nWWW-Authenticate: Basic realm=\"\"\r\n\r\nUnauthorized") -// closeConn(inConn) -// return -// } -// //log.Printf("Authorization:%s", authorization) -// basic := strings.Fields(authorization) -// if len(basic) != 2 { -// log.Printf("authorization data error,ERR:%s", authorization) -// closeConn(inConn) -// return -// } -// user, err := base64.StdEncoding.DecodeString(basic[1]) -// if err != nil { -// log.Printf("authorization data parse error,ERR:%s", err) -// closeConn(inConn) -// return -// } -// authOk := basicAuth.Check(string(user)) -// //log.Printf("auth %s,%v", string(user), authOk) -// if !authOk { -// fmt.Fprint(*inConn, "HTTP/1.1 401 Unauthorized\r\n\r\nUnauthorized") -// closeConn(inConn) -// return -// } -// } -// } - -// var bytes []byte -// if isHTTPS { //https访问 -// // [dd:dafds:fsd:dasd:2.2.23.3] or 2.2.23.3 or [dd:dafds:fsd:dasd:2.2.23.3]:2323 or 2.2.23.3:1234 -// address = fixHost(host) -// if hostIsNoPort(host) { //host不带端口, 默认443 -// address = address + ":443" -// } -// } else { //http访问 -// hostPortURL, err := url.Parse(host) -// if err != nil { -// log.Printf("url.Parse %s ERR:%s", host, err) -// closeConn(inConn) -// return -// } -// _host := fixHost(hostPortURL.Host) -// address = _host -// if hostIsNoPort(_host) { //host不带端口, 默认80 -// address = _host + ":80" -// } -// if _host != hostPortURL.Host { -// bytes = []byte(strings.Replace(string(b[:n]), hostPortURL.Host, _host, 1)) -// host = strings.Replace(host, hostPortURL.Host, _host, 1) -// } -// } -// //get url , reslut host is the full url -// host, err = getURL(b[:n], host) -// // log.Printf("body:%s", string(b[:n])) -// // log.Printf("%s:%s", method, host) -// if err != nil { -// log.Printf("header data err:%s", err) -// closeConn(inConn) -// return -// } - -// useProxy := false -// if proxyAddr != "" { -// if cfg.GetBool("always") { -// useProxy = true -// } else { -// if isHTTPS { -// checker.Add(address, true, method, "", nil) -// } else { -// if bytes != nil { -// checker.Add(address, false, method, host, bytes) -// } else { -// checker.Add(address, false, method, host, b[:n]) -// } -// } -// useProxy, _, _ = checker.IsBlocked(address) -// } -// // var failN, successN uint -// // useProxy, failN, successN = checker.IsBlocked(address) -// //log.Printf("use proxy ? %s : %v ,fail:%d, success:%d", address, useProxy, failN, successN) -// //log.Printf("use proxy ? %s : %v", address, useProxy) -// } - -// var outConn net.Conn -// var _outConn interface{} -// if useProxy { -// _outConn, err = outPool.Get() -// if err == nil { -// outConn = _outConn.(net.Conn) -// } -// } else { -// outConn, err = ConnectHost(address, connTimeout) -// } -// if err != nil { -// log.Printf("connect to %s , err:%s", address, err) -// closeConn(inConn) -// return -// } -// inAddr := (*inConn).RemoteAddr().String() -// outAddr := outConn.RemoteAddr().String() - -// if isHTTPS { -// if useProxy { -// outConn.Write(b[:n]) -// } else { -// fmt.Fprint(*inConn, "HTTP/1.1 200 Connection established\r\n\r\n") -// } -// } else { -// if bytes != nil { -// outConn.Write(bytes) -// } else { -// outConn.Write(b[:n]) -// } -// } -// IoBind(*inConn, outConn, func(err error) { -// log.Printf("conn %s - %s [%s] released", inAddr, outAddr, address) -// closeConn(inConn) -// closeConn(&outConn) -// }, func(n int, d bool) {}, 0) -// log.Printf("conn %s - %s [%s] connected", inAddr, outAddr, address) -// } diff --git a/services/args.go b/services/args.go index 17ba89d..8352114 100644 --- a/services/args.go +++ b/services/args.go @@ -18,6 +18,10 @@ type Args struct { PoolSize *int CheckParentInterval *int } +type TunnelArgs struct { + Args + Timeout *int +} type TCPArgs struct { Args Timeout *int diff --git a/services/http.go b/services/http.go index 799bd66..a0d3e32 100644 --- a/services/http.go +++ b/services/http.go @@ -27,7 +27,9 @@ func NewHTTP() Service { } func (s *HTTP) InitService() { s.InitBasicAuth() - s.checker = utils.NewChecker(*s.cfg.HTTPTimeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct) + if *s.cfg.Parent != "" { + s.checker = utils.NewChecker(*s.cfg.HTTPTimeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct) + } } func (s *HTTP) StopService() { if s.outPool.Pool != nil { @@ -76,17 +78,18 @@ func (s *HTTP) callback(inConn net.Conn) { return } address := req.Host - if req.IsHTTPS() { - s.checker.Add(address, true, req.Method, "", nil) - } else { - s.checker.Add(address, false, req.Method, req.URL, req.HeadBuf) - } + useProxy := true if *s.cfg.Parent == "" { useProxy = false } else if *s.cfg.Always { useProxy = true } else { + if req.IsHTTPS() { + s.checker.Add(address, true, req.Method, "", nil) + } else { + s.checker.Add(address, false, req.Method, req.URL, req.HeadBuf) + } //var n, m uint useProxy, _, _ = s.checker.IsBlocked(req.Host) //log.Printf("blocked ? : %v, %s , fail:%d ,success:%d", useProxy, address, n, m) diff --git a/services/tunnel.go b/services/tunnel.go new file mode 100644 index 0000000..a92d5b0 --- /dev/null +++ b/services/tunnel.go @@ -0,0 +1,39 @@ +package services + +import "log" + +type Tunnel struct { + cfg TunnelArgs +} + +func NewTunnel() Service { + return &Tunnel{ + cfg: TunnelArgs{}, + } +} + +func (s *Tunnel) InitService() { + +} +func (s *Tunnel) Check() { + if *s.cfg.Parent != "" { + log.Printf("use tls parent %s", *s.cfg.Parent) + } else { + log.Fatalf("parent required") + } + if s.cfg.CertBytes == nil || s.cfg.KeyBytes == nil { + log.Fatalf("cert and key file required") + } +} +func (s *Tunnel) StopService() { + +} +func (s *Tunnel) Start(args interface{}) (err error) { + s.cfg = args.(TunnelArgs) + s.Check() + s.InitService() + return +} +func (s *Tunnel) Clean() { + s.StopService() +} diff --git a/services/udp.go b/services/udp.go index 2850f86..34b414c 100644 --- a/services/udp.go +++ b/services/udp.go @@ -101,7 +101,11 @@ func (s *UDP) GetConn(connKey string) (conn net.Conn, isNew bool, err error) { func (s *UDP) OutToTCP(packet []byte, localAddr, srcAddr *net.UDPAddr) (err error) { numLocal := crc32.ChecksumIEEE([]byte(localAddr.String())) numSrc := crc32.ChecksumIEEE([]byte(srcAddr.String())) - connKey := uint64((numLocal/10)*10 + numSrc%10) + mod := uint32(*s.cfg.PoolSize) + if mod == 0 { + mod = 10 + } + connKey := uint64((numLocal/10)*10 + numSrc%mod) conn, isNew, err := s.GetConn(fmt.Sprintf("%d", connKey)) if err != nil { log.Printf("upd get conn to %s parent %s fail, ERR:%s", *s.cfg.ParentType, *s.cfg.Parent, err)