github.com/geph-official/geph2@v0.22.6-0.20210211030601-f527cb59b0df/cmd/geph-client/listeners.go (about) 1 package main 2 3 import ( 4 "io/ioutil" 5 "net" 6 "net/http" 7 "time" 8 9 log "github.com/sirupsen/logrus" 10 11 "github.com/elazarl/goproxy" 12 "github.com/geph-official/geph2/cmd/geph-client/chinalist" 13 "github.com/geph-official/geph2/libs/cwl" 14 "github.com/geph-official/geph2/libs/tinysocks" 15 "golang.org/x/time/rate" 16 ) 17 18 func listenStats() { 19 log.Infoln("STATS on", statsAddr) 20 // spin up stats server 21 statsMux := http.NewServeMux() 22 statsServ := &http.Server{ 23 Addr: statsAddr, 24 Handler: statsMux, 25 ReadTimeout: time.Minute, 26 WriteTimeout: time.Minute, 27 } 28 statsMux.HandleFunc("/proxy.pac", handleProxyPac) 29 statsMux.HandleFunc("/kill", handleKill) 30 statsMux.HandleFunc("/", handleStats) 31 statsMux.HandleFunc("/logs", handleLogs) 32 statsMux.HandleFunc("/debugpack", handleDebugPack) 33 statsMux.HandleFunc("/stacktrace", handleStacktrace) 34 err := statsServ.ListenAndServe() 35 if err != nil { 36 panic(err) 37 } 38 } 39 40 func listenHTTP() { 41 log.Infoln("HTTP on", httpAddr) 42 // HTTP proxy 43 srv := goproxy.NewProxyHttpServer() 44 srv.Tr = &http.Transport{ 45 Dial: func(n, d string) (net.Conn, error) { 46 conn, err := dialTun(d) 47 if err != nil { 48 return nil, err 49 } 50 conn.(*net.TCPConn).SetKeepAlive(false) 51 conn.(*net.TCPConn).SetWriteBuffer(16384) 52 return conn, nil 53 }, 54 IdleConnTimeout: time.Second * 60, 55 Proxy: nil, 56 } 57 blankLogger := log.New() 58 blankLogger.SetOutput(ioutil.Discard) 59 srv.Logger = blankLogger 60 proxServ := &http.Server{ 61 Addr: httpAddr, 62 Handler: srv, 63 ReadTimeout: time.Minute * 5, 64 IdleTimeout: time.Minute * 5, 65 } 66 err := proxServ.ListenAndServe() 67 if err != nil { 68 panic(err.Error()) 69 } 70 } 71 72 func listenSocks() { 73 listener, err := net.Listen("tcp", socksAddr) 74 if err != nil { 75 panic(err) 76 } 77 semaphore := make(chan bool, 512) 78 downLimit := rate.NewLimiter(rate.Inf, 10000000) 79 upLimit := rate.NewLimiter(rate.Inf, 1000*1000) 80 useStats(func(sc *stats) { 81 if sc.Tier == "free" { 82 upLimit = rate.NewLimiter(100*1000, 1000*1000) 83 } 84 }) 85 log.Infoln("SOCKS5 on", socksAddr) 86 for { 87 cl, err := listener.Accept() 88 if err != nil { 89 panic(err) 90 } 91 go func() { 92 defer cl.Close() 93 cl.(*net.TCPConn).SetKeepAlive(false) 94 select { 95 case semaphore <- true: 96 defer func() { 97 <-semaphore 98 }() 99 default: 100 return 101 } 102 cmd, rmAddrProt, err := tinysocks.ReadRequest(cl) 103 if err != nil { 104 log.Debugln("Bad SOCKS5 request:", err) 105 return 106 } 107 if cmd != tinysocks.CmdConnect { 108 log.Debugln("Unsupported command:", cmd) 109 tinysocks.CompleteRequestTCP(7, cl) 110 return 111 } 112 rmAddr := rmAddrProt.String() 113 host, port, err := net.SplitHostPort(rmAddr) 114 if realName := fakeIPToName(host); realName != "" { 115 rmAddr = net.JoinHostPort(realName, port) 116 host = realName 117 } 118 var remote net.Conn 119 var ok bool 120 if bypassHost(host) { 121 remote, err = net.Dial("tcp", rmAddr) 122 if err != nil { 123 log.Printf("[%v] failed to bypass %v", len(semaphore), remote) 124 tinysocks.CompleteRequestTCP(5, cl) 125 return 126 } 127 log.Debugf("[%v] BYPASSED %v", len(semaphore), rmAddr) 128 remote.(*net.TCPConn).SetKeepAlive(false) // app responsibility 129 } else { 130 start := time.Now() 131 var key interface{} 132 remote, key, ok = sWrap.DialCmd("proxy", rmAddr) 133 if !ok { 134 return 135 } 136 defer remote.Close() 137 incrCounter(key) 138 defer decrCounter(key) 139 ping := time.Since(start) 140 log.Debugf("[%v] opened %v in %vms through %v", len(semaphore), rmAddr, ping.Milliseconds(), remote.RemoteAddr()) 141 useStats(func(sc *stats) { 142 pmil := ping.Milliseconds() 143 if time.Since(sc.PingTime).Seconds() > 30 || uint64(pmil) < sc.MinPing { 144 sc.MinPing = uint64(pmil) 145 sc.PingTime = time.Now() 146 } 147 }) 148 if !ok { 149 tinysocks.CompleteRequestTCP(5, cl) 150 return 151 } 152 } 153 tinysocks.CompleteRequestTCP(0, cl) 154 go func() { 155 defer remote.Close() 156 defer cl.Close() 157 cwl.CopyWithLimit(remote, cl, upLimit, func(n int) { 158 useStats(func(sc *stats) { 159 sc.UpBytes += uint64(n) 160 }) 161 }, time.Hour) 162 }() 163 cwl.CopyWithLimit(cl, remote, 164 downLimit, func(n int) { 165 useStats(func(sc *stats) { 166 sc.DownBytes += uint64(n) 167 }) 168 }, time.Hour) 169 }() 170 } 171 } 172 173 // TODO bypass local domains 174 func bypassHost(str string) bool { 175 return bypassChinese && chinalist.IsChinese(str) 176 }