예제 #1
0
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)
	}
}
예제 #2
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
}
예제 #3
0
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"))
}
예제 #4
0
// 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
}
예제 #5
0
파일: d5.go 프로젝트: noscripter/deblocus
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
}
예제 #6
0
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
}
예제 #7
0
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)
	}
}
예제 #8
0
// 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
}
예제 #9
0
파일: d5.go 프로젝트: noscripter/deblocus
// 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
}
예제 #10
0
// 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()
	}
}