func (c *Client) ClientServe(conn net.Conn) { var done bool defer func() { ex.Catch(recover(), nil) if !done { SafeClose(conn) } }() reqNum := atomic.AddInt32(&c.reqCnt, 1) pbConn := NewPushbackInputStream(conn) proto, err := detectProtocol(pbConn) if err != nil { // chrome will make some advance connections and then aborted // cause a EOF if err != io.EOF && err != io.ErrUnexpectedEOF { log.Warningln(err) } return } switch proto { case PROT_SOCKS5: s5 := socks5Handler{pbConn} if s5.handshake() { if literalTarget, ok := s5.readRequest(); ok { c.mux.HandleRequest("SOCKS5", conn, literalTarget) done = true } } case PROT_HTTP: proto, target, err := httpProxyHandshake(pbConn) if err != nil { log.Warningln(err) break } switch proto { case PROT_HTTP: // plain http c.mux.HandleRequest("HTTP", pbConn, target) case PROT_HTTP_T: // http tunnel c.mux.HandleRequest("HTTP/T", conn, target) case PROT_LOCAL: // target is requestUri c.localServlet(conn, target) } done = true default: log.Warningln("Unrecognized request from", conn.RemoteAddr()) time.Sleep(REST_INTERVAL) } // client setSeed at every 32 req if reqNum&0x1f == 0x1f { myRand.setSeed(0) } }
func (c *Client) getToken() ([]byte, error) { c.lock.Lock() var tlen = len(c.token) / TKSZ if tlen <= TOKENS_FLOOR { // TODO may request many times c.asyncRequestTokens() } for len(c.token) < TKSZ { // release lock for waiting of pendingTK() c.lock.Unlock() log.Warningln("Waiting for token. Maybe the requests are coming too fast.") if !c.pendingTK.await(RETRY_INTERVAL * 2) { // acquire() cancelled by clearAll() return nil, ERR_REQ_TK_TIMEOUT } if atomic.LoadInt32(&c.state) < CLT_WORKING { return nil, ERR_REQ_TK_ABORTED } // recover lock status c.lock.Lock() } var token = c.token[:TKSZ] c.token = c.token[TKSZ:] // finally release c.lock.Unlock() return token, nil }
func (c *Client) localServlet(conn net.Conn, reqUri string) { initTplOnce.Do(lazyInitTemplate) defer conn.Close() switch reqUri { case "/wpad.dat": if c.connInfo.pacFile != NULL { // has pac setting pacFile, info, err := openReadOnlyFile(c.connInfo.pacFile) if err != nil { log.Errorln("Read PAC file", err) goto error404 } defer pacFile.Close() entity := respEntity{ contentType: "application/x-ns-proxy-autoconfig", contentLength: int(info.Size()), stream: pacFile, } writeHttpResponse(conn, 200, &entity) return } case "/": writeHttpResponse(conn, 200, c.renderPage("main")) return } error404: // other local request or pacFile not specified log.Warningln("Unrecognized Request", reqUri) // respond 404 writeHttpResponse(conn, 404, c.renderPage("404")) }
// step3-4 func (s socks5Handler) readRequest() (string, bool) { var ( buf = make([]byte, 262) // 4+(1+255)+2 host string ofs int ver, cmd, atyp byte ) var msg = []byte{5, 0, 0, 1, 0, 0, 0, 0, 0, 0} setRTimeout(s.conn) _, err := s.conn.Read(buf) if err != nil { exception.Spawn(&err, "socks: read request") goto errLogging } ver, cmd, atyp = buf[0], buf[1], buf[3] if ver != S5_VER || cmd != 1 { exception.Spawn(&err, "socks: invalid request") goto errHandler } buf = buf[4:] switch atyp { case IPV4: host = net.IP(buf[:net.IPv4len]).String() ofs = net.IPv4len case IPV6: host = "[" + net.IP(buf[:net.IPv6len]).String() + "]" ofs = net.IPv6len case DOMAIN: dlen := int(buf[0]) ofs = dlen + 1 host = string(buf[1:ofs]) // literal IPv6 if strings.Count(host, ":") >= 2 && !strings.HasPrefix(host, "[") { host = "[" + host + "]" } default: exception.Spawn(&err, "socks: invalid request") goto errHandler } // accept _, err = s.conn.Write(msg) if err != nil { exception.Spawn(&err, "socks: write response") goto errLogging } host += ":" + strconv.Itoa(int(binary.BigEndian.Uint16(buf[ofs:]))) return host, true errHandler: msg[1] = 0x1 // general SOCKS server failure setWTimeout(s.conn) s.conn.Write(msg) errLogging: log.Warningln(err) return NULL, false }
func (n *d5cman) Connect(p *tunParams) (conn *Conn, err error) { var rawConn net.Conn defer func() { n.dbcHello, n.sRand = nil, nil if exception.Catch(recover(), &err) { SafeClose(rawConn) if t, y := err.(*exception.Exception); y { // must terminate switch t.Origin { case ERR_TIME_ERROR: line := string(bytes.Repeat([]byte{'+'}, 30)) log.Warningln(line) log.Warningln("Maybe your clock is inaccurate, or your client credential is invalid.") log.Warningln(line) os.Exit(2) case INCOMPATIBLE_VERSION: log.Warningln(err) os.Exit(3) } } } }() rawConn, err = net.DialTimeout("tcp", n.sAddr, GENERAL_SO_TIMEOUT) n.dhKey, _ = crypto.NewDHKey(DH_METHOD) if err != nil { return } conn = NewConn(rawConn, nullCipherKit) if err = n.requestDHExchange(conn); err != nil { return } var cf *CipherFactory cf, err = n.finishDHExchange(conn) if err != nil { return } if err = n.validate(conn); err != nil { return } if err = n.authThenFinishSetting(conn, p); err != nil { return } p.cipherFactory = cf conn.SetId(n.provider, false) return }
func (p *multiplexer) bestSend(data []byte, action_desc string) bool { var buf = make([]byte, FRAME_HEADER_LEN+len(data)) pack(buf, FRAME_ACTION_TOKENS, 0, data) for i := 1; i <= 3; i++ { if atomic.LoadInt32(&p.status) < 0 /* MUX_CLOSED */ || p.pool == nil { log.Warningln("Abandon sending data of", action_desc) break } tun := p.pool.Select() if tun != nil { if frameWriteBuffer(tun, buf) == nil { return true } } else { time.Sleep(time.Millisecond * 200 * time.Duration(i)) } } log.Warningln("failed to send data of", action_desc) return false }
func (p *multiplexer) HandleRequest(prot string, client net.Conn, target string) { if tun := p.pool.Select(); tun != nil { sid := next_sid() if log.V(log.LV_REQ) { log.Infof("%s->[%s] from=%s sid=%d\n", prot, target, ipAddr(client.RemoteAddr()), sid) } key := sessionKey(tun, sid) edge := p.router.register(key, target, tun, client, true) // write edge p.relay(edge, tun, sid) // read edge } else { log.Warningln(ERR_TUN_NA) time.Sleep(time.Second) SafeClose(client) } }
// step1-2 func (s socks5Handler) handshake() bool { var buf = make([]byte, 2) var n, nmethods int var ver byte setRTimeout(s.conn) _, err := io.ReadFull(s.conn, buf) if err != nil { exception.Spawn(&err, "socks: read header") goto errLogging } ver, nmethods = buf[0], int(buf[1]) if ver != S5_VER || nmethods < 1 { err = INVALID_SOCKS5_HEADER exception.Spawn(&err, "socks: read header [% x]", buf[:2]) goto errHandler } buf = make([]byte, nmethods+1) // consider method non-00 setRTimeout(s.conn) n, err = io.ReadAtLeast(s.conn, buf, nmethods) if err != nil || n != nmethods { err = INVALID_SOCKS5_HEADER exception.Spawn(&err, "socks: read header [% x]", buf) goto errHandler } // accept buf = []byte{5, 0} setWTimeout(s.conn) _, err = s.conn.Write(buf) if err == nil { return true } else { err = exception.Spawn(&err, "socks: write response") goto errLogging } errHandler: // handshake error feedback // NO ACCEPTABLE METHODS buf = []byte{5, 0xff} setWTimeout(s.conn) s.conn.Write(buf) errLogging: log.Warningln(err) return false }
// quick resume session func (n *d5sman) resumeSession(conn *Conn) (session *Session, err error) { token := make([]byte, TKSZ) setRTimeout(conn) // just read once nr, err := conn.Read(token) if nr == len(token) && err == nil { // check token ok if session := n.sessionMgr.take(token); session != nil { // reuse cipherFactory to init cipher conn.SetupCipher(session.cipherFactory, token) // identify connection conn.SetId(session.uid, true) return session, nil } } log.Warningln("Incorrect token from", n.clientAddr, nvl(err, NULL)) return nil, VALIDATION_FAILED }
// TODO notify peer to slow down when queue increased too fast func (p *multiplexer) Listen(tun *Conn, handler event_handler, interval int) error { tun.priority = &TSPriority{0, 1e9} p.pool.Push(tun) defer p.onTunDisconnected(tun, handler) tun.SetSockOpt(1, 0, 1) var ( header = make([]byte, FRAME_HEADER_LEN) idle = NewIdler(interval, p.isClient) router = p.router nr int er error frm *frame key string ) if !p.isClient { // server first ping client // make client aware of using a valid token. idle.ping(tun) } for { idle.newRound(tun) nr, er = io.ReadFull(tun, header) if nr == FRAME_HEADER_LEN { frm, er = parse_frame(header) if er == nil && len(frm.data) > 0 { // read All and discard tail random nr, er = io.ReadFull(tun, frm.data) frm.data = frm.data[:frm.length] } } if er != nil { // shutdown if atomic.LoadInt32(&p.status) < 0 { time.Sleep(time.Second) return nil } switch idle.consumeError(er) { case ERR_NEW_PING: if er = idle.ping(tun); er == nil { continue } case ERR_PING_TIMEOUT: er = ex.New("Peer was unresponsive then close") } // abandon this connection return er } // prefix tun.identifier key = sessionKey(tun, frm.sid) switch frm.action { case FRAME_ACTION_CLOSE_W: if edge, _ := router.getRegistered(key); edge != nil { edge.bitwiseCompareAndSet(TCP_CLOSE_W) edge.deliver(frm) } case FRAME_ACTION_CLOSE_R: if edge, _ := router.getRegistered(key); edge != nil { edge.bitwiseCompareAndSet(TCP_CLOSE_R) closeR(edge.conn) } case FRAME_ACTION_DATA: edge, pre := router.getRegistered(key) if edge != nil { edge.deliver(frm) } else if pre { router.preDeliver(key, frm) } else { if log.V(log.LV_WARN) { log.Warningln("Peer sent data to an unexisted socket.", key, frm) } // trigger sending close to notice peer. pack(header, FRAME_ACTION_CLOSE_R, frm.sid, nil) if er = frameWriteBuffer(tun, header); er != nil { return er } } case FRAME_ACTION_OPEN: router.preRegister(key) p.wg.Add(1) go p.connectToDest(frm, key, tun) case FRAME_ACTION_OPEN_N, FRAME_ACTION_OPEN_Y, FRAME_ACTION_OPEN_DENIED: edge, _ := router.getRegistered(key) if edge != nil { if log.V(log.LV_ACT_FRM) { log.Infoln(p.role, "received OPEN_x", frm) } edge.ready <- frm.action close(edge.ready) } else { if log.V(log.LV_WARN) { log.Warningln("Peer sent OPEN_x to an unexisted socket.", key, frm) } } case FRAME_ACTION_PING: if er = idle.pong(tun); er == nil { atomic.AddInt32(&p.pingCnt, 1) } else { // reply pong failed return er } case FRAME_ACTION_PONG: if idle.verify() { if p.isClient && idle.lastPing > 0 { sRtt, devRtt := idle.updateRtt() atomic.StoreInt32(&p.sRtt, sRtt) if DEBUG { log.Infof("sRtt=%d devRtt=%d", sRtt, devRtt) if devRtt+(sRtt>>2) > sRtt { // restart ??? log.Warningf("Network jitter sRtt=%d devRtt=%d", sRtt, devRtt) } } } } else { log.Warningln("Incorrect action_pong received") } case FRAME_ACTION_TOKENS: handler(evt_tokens, frm.data) default: // impossible return fmt.Errorf("Unrecognized %s", frm) } tun.Update() } }