func (n *d5sman) authenticate(conn *Conn, session *Session) error { var err error setRTimeout(conn) hashSRand, err := ReadFullByLen(1, conn) if err != nil { // client aborted if IsClosedError(err) { return ABORTED_ERROR.Apply(err) } else { return exception.Spawn(&err, "srand: read connection") } } myHashSRand := hash256(n.sRand) if !bytes.Equal(hashSRand, myHashSRand) { // MITM ? return INCONSISTENT_HASH } // client identity setRTimeout(conn) idBuf, err := ReadFullByLen(1, conn) if err != nil { return exception.Spawn(&err, "auth: read connection") } user, passwd, err := n.deserializeIdentity(idBuf) if err != nil { return err } if log.V(log.LV_LOGIN) { log.Infoln("Login request:", user) } pass, err := n.AuthSys.Authenticate(user, passwd) if !pass { // authSys denied log.Warningf("Auth %s:%s failed: %v\n", user, passwd, err) // reply failed msg conn.Write([]byte{1, 0}) return VALIDATION_FAILED } session.indentifySession(user, conn) w := newMsgWriter() w.WriteL1Msg([]byte{AUTH_PASS}) w.WriteL2Msg(n.tunParams.serialize()) // send tokens num := maxInt(GENERATE_TOKEN_NUM, n.Parallels+2) tokens := n.sessionMgr.createTokens(session, num) w.WriteL2Msg(tokens[1:]) // skip index=0 setWTimeout(conn) err = w.WriteTo(conn) return exception.Spawn(&err, "setting: write connection") }
// new connection func (n *d5sman) fullHandshake(conn *Conn) (session *Session, err error) { defer func() { if exception.Catch(recover(), &err) { if t, y := err.(*exception.Exception); y && t.Origin == ABORTED_ERROR { log.Warningf("Handshake aborted by client from=%s", n.clientAddr) } else { log.Warningf("Handshake error=%v from=%s", err, n.clientAddr) } } }() var cf *CipherFactory n.isNewSession = true cf, err = n.finishDHExchange(conn) if err != nil { return } session = n.NewSession(cf) err = n.authenticate(conn, session) return }
func (p *multiplexer) connectToDest(frm *frame, key string, tun *Conn) { defer func() { p.wg.Done() ex.Catch(recover(), nil) }() var ( dstConn net.Conn err error target = string(frm.data) denied = false ) if p.filter != nil { denied = p.filter.Filter(target) } if !denied { dstConn, err = dialer.Dial("tcp", target) } if err != nil || denied { p.router.removePreRegistered(key) if denied { frm.action = FRAME_ACTION_OPEN_DENIED log.Warningf("Denied request [%s] for %s\n", target, key) } else { frm.action = FRAME_ACTION_OPEN_N log.Warningf("Cannot connect to [%s] for %s error: %s\n", target, key, err) } frameWriteHead(tun, frm) } else { edge := p.router.register(key, target, tun, dstConn, false) // write edge if log.V(log.LV_SVR_OPEN) { log.Infoln("OPEN", target, "for", key) } dstConn.SetReadDeadline(ZERO_TIME) frm.action = FRAME_ACTION_OPEN_Y if frameWriteHead(tun, frm) == nil { p.relay(edge, tun, frm.sid) // read edge } else { // send open_y failed SafeClose(tun) } } }
func (t *Session) tokensHandle(args []byte) { var cmd = args[0] switch cmd { case FRAME_ACTION_TOKEN_REQUEST: tokens := t.mgr.createTokens(t, GENERATE_TOKEN_NUM) if tokens != nil { tokens[0] = FRAME_ACTION_TOKEN_REPLY t.mux.bestSend(tokens, "replyTokens") } default: log.Warningf("Unrecognized command=%x packet=[% x]\n", cmd, args) } }
func sendFrame(frm *frame) bool { dst := frm.conn.conn if log.V(log.LV_DAT_FRM) { log.Infoln("SEND queue", frm) } dst.SetWriteDeadline(time.Now().Add(GENERAL_SO_TIMEOUT)) nw, ew := dst.Write(frm.data) if nw == int(frm.length) && ew == nil { return false } // an error occured if log.V(log.LV_WARN_EDGE) { log.Warningf("Write edge (%s) error (%v) %s\n", frm.conn.dest, ew, frm) } return true }
func compareVersion(buf []byte) error { // compare version with remote myVer := VERSION rVer := binary.BigEndian.Uint32(buf) if rVer > myVer { rVerStr := fmt.Sprintf("%d.%d.%04d", rVer>>24, (rVer>>16)&0xFF, rVer&0xFFFF) myVer >>= 16 rVer >>= 16 if myVer == rVer { log.Warningf("Caution !!! Please upgrade to new version, remote is v%s\n", rVerStr) } else { return INCOMPATIBLE_VERSION.Apply(rVerStr) } } return nil }
func (c *Client) saveTokens(data []byte) { var tokens []byte switch data[0] { case FRAME_ACTION_TOKEN_REQUEST: log.Warningf("Unexpected token request") return case FRAME_ACTION_TOKEN_REPLY: tokens = data[1:] } c.lock.Lock() c.token = append(c.token, tokens...) c.lock.Unlock() // wakeup waiting c.pendingTK.notifyAll() if log.V(log.LV_TOKEN) { log.Infof("Received tokens=%d pool=%d\n", len(tokens)/TKSZ, len(c.token)/TKSZ) } }
// frame writer func frameWriteBuffer(tun *Conn, origin []byte) (err error) { // default timeout is 10s err = tun.SetWriteDeadline(time.Now().Add(WRITE_TUN_TIMEOUT)) if err == nil { var nw int buf := frameTransform(origin) nw, err = tun.Write(buf) if nw != len(buf) || err != nil { idleLastR := time.Now().UnixNano() - tun.priority.last if IsTimeout(err) && idleLastR < int64(WRITE_TUN_TIMEOUT) { err = nil } else { log.Warningf("Write tun (%s) error (%v) buf.len=%d\n", tun.identifier, err, len(buf)) SafeClose(tun) } } } return }
// external conn lifecycle func (n *d5sman) Connect(conn *Conn, tcPool []uint64) (session *Session, err error) { var ( nr int buf = make([]byte, DPH_P2) ) setRTimeout(conn) nr, err = conn.Read(buf) if nr == len(buf) { nr = 0 // reset nr ok, stype, len2 := verifyDbcHello(buf, n.sharedKey, tcPool) if ok { if len2 > 0 { setRTimeout(conn) nr, err = io.ReadFull(conn, buf[:len2]) n.dbcHello = buf[:len2] } else { n.dbcHello = buf } if nr == int(len2) && err == nil { switch stype { case TYPE_NEW: return n.fullHandshake(conn) case TYPE_RES: return n.resumeSession(conn) } } } } // then may be a prober // threats OR overlarge time error // We could use this log to block threats origin by external tools such as fail2ban. log.Warningf("Unrecognized Request from=%s len=%d\n", n.clientAddr, nr) return nil, nvl(err, UNRECOGNIZED_REQ).(error) }
// 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() } }