func (nego *d5SNegotiation) verifyThenDHExchange(conn net.Conn, credBuf []byte) (key []byte, err error) { userIdentity, err := RSADecrypt(credBuf, nego.RSAKeys.priv) ThrowErr(err) clientIdentity := string(userIdentity) if log.V(2) { log.Infoln("Auth clientIdentity:", clientIdentity) } allow, ex := nego.AuthSys.Authenticate(userIdentity) cDHPub, err := ReadFullByLen(2, conn) if !allow { log.Warningf("Auth %s failed: %v\n", clientIdentity, ex) conn.Write([]byte{0, 1, 0xff}) return nil, ex } nego.clientIdentity = clientIdentity key = takeSharedKey(nego.dhKeys, cDHPub) // if log.V(5) { // dumpHex("Sharedkey", key) // } buf := new(bytes.Buffer) buf.Write(nego.dhKeys.pubLen) buf.Write(nego.dhKeys.pub) _, err = buf.WriteTo(conn) return }
func (nego *d5SNegotiation) negotiate(hconn *hashedConn) (session *Session, err error) { setSoTimeout(hconn) nego.clientAddr = hconn.RemoteAddr().String() var ( nr int buf = make([]byte, DMLEN1) ) nr, err = hconn.Read(buf) ThrowErr(err) if nr == DMLEN2 { if d5SumValid(buf[TKSZ-2], buf[TKSZ]) && d5SumValid(buf[TKSZ-1], buf[TKSZ+1]) { return nego.transSession(hconn, buf) } } if nr == DMLEN1 && d5SumValid(buf[0xd5], buf[0xff]) { var ( skey []byte cf *CipherFactory ) skey, err = nego.verifyThenDHExchange(hconn, buf[256:]) ThrowErr(err) cf = NewCipherFactory(nego.Algo, skey) hconn.cipher = cf.NewCipher(nil) session = NewSession(hconn.Conn, cf, nego.clientIdentity) err = nego.respondTestWithToken(hconn, session) return } log.Warningf("Unrecognized Request from=%s len=%d\n", hconn.RemoteAddr(), nr) return nil, NEGOTIATION_FAILED }
func (c *Client) commandHandler(cmd byte, args []byte) { switch cmd { case TOKEN_REPLY: c.putTokens(args) default: log.Warningf("Unrecognized command=%x packet=[% x]\n", cmd, args) } }
func (t *Session) commandHandler(cmd byte, args []byte) { switch cmd { case TOKEN_REQUEST: tokens := t.svr.sessionMgr.createTokens(t, GENERATE_TOKEN_NUM) t.sigTun.postCommand(TOKEN_REPLY, tokens) default: log.Warningf("Unrecognized command=%x packet=[% x]\n", cmd, args) } }
func (t *Session) onSTDisconnected() { tid := t.tun.identifier SafeClose(t.tun) atomic.AddInt32(&t.svr.stCnt, -1) log.Warningf("Client(%s)-ST was disconnected\n", tid) i := t.svr.sessionMgr.clearTokens(t) if log.V(4) { log.Infof("Clear tokens %d of %s\n", i, tid) } }
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) tokens[0] = FRAME_ACTION_TOKEN_REPLY t.mux.bestSend(tokens, "replyTokens") default: log.Warningf("Unrecognized command=%x packet=[% x]\n", cmd, args) } }
func tunWrite2(tun *Conn, frm *frame) (err error) { err = tun.SetWriteDeadline(time.Now().Add(GENERAL_SO_TIMEOUT * 2)) if err != nil { return } var nr, nw int nr = int(frm.length) + FRAME_HEADER_LEN nw, err = tun.Write(frm.toNewBuffer()) if nr != nw || err != nil { log.Warningf("Write tun(%s) error(%v) when sending %s\n", tun.sign(), err, frm) SafeClose(tun) return } return nil }
func tunWrite1(tun *Conn, buf []byte) (err error) { err = tun.SetWriteDeadline(time.Now().Add(GENERAL_SO_TIMEOUT * 2)) if err != nil { return } var nr, nw int nr = len(buf) nw, err = tun.Write(buf) if nr != nw || err != nil { log.Warningf("Write tun(%s) error(%v) when sending buf.len=%d\n", tun.sign(), err, nr) SafeClose(tun) return } return nil }
func sendFrame(frm *frame) (werr bool) { dst := frm.conn.conn if log.V(5) { 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 } werr = true // an error occured log.Warningf("Write edge(%s) error(%v). %s\n", frm.conn.dest, ew, frm) return }
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() defer c.lock.Unlock() c.token = append(c.token, tokens...) atomic.CompareAndSwapInt32(&c.State, CLT_PENDING, CLT_WORKING) c.pendingTK.notifyAll() if log.V(3) { log.Infof("Recv tokens=%d pool=%d\n", len(tokens)/TKSZ, len(c.token)/TKSZ) } }
func (nego *d5CNegotiation) validateAndGetTokens(sconn *hashedConn, t *tunParams) (err error) { buf, err := ReadFullByLen(2, sconn) ThrowErr(err) tVer := VERSION oVer := binary.BigEndian.Uint32(buf) if oVer > tVer { oVerStr := fmt.Sprintf("%d.%d.%04d", oVer>>24, (oVer>>16)&0xFF, oVer&0xFFFF) tVer >>= 16 oVer >>= 16 if tVer == oVer { log.Warningf("Caution !!! Please upgrade to new version, remote is v%s\n", oVerStr) } else { return INCOMPATIBLE_VERSION.Apply(oVerStr) } } ofs := 4 t.stInterval = int(binary.BigEndian.Uint16(buf[ofs:])) ofs += 2 t.dtInterval = int(binary.BigEndian.Uint16(buf[ofs:])) ofs += 2 t.tunQty = int(buf[ofs]) t.token = buf[TUN_PARAMS_LEN:] if log.V(2) { n := len(buf) - TUN_PARAMS_LEN log.Infof("Got tokens length=%d\n", n/TKSZ) } rHash := sconn.RHashSum() wHash := sconn.WHashSum() _, err = sconn.Write(rHash) ThrowErr(err) oHash := make([]byte, TKSZ) _, err = sconn.Read(oHash) if !bytes.Equal(wHash, oHash) { log.Errorln("Server hash/r is inconsistence with the client/w") log.Errorf("rHash: [% x] wHash: [% x]\n", rHash, wHash) log.Errorf("oHash: [% x]\n", oHash) return INCONSISTENT_HASH } return }
func (nego *d5SNegotiation) negotiate(hConn *hashedConn) (session *Session, err error) { setSoTimeout(hConn) nego.clientAddr = hConn.RemoteAddr().String() var ( nr int buf = make([]byte, DMLEN1) ) nr, err = hConn.Read(buf) if err != nil { return nil, err } if nr == DMLEN2 && d5SumValid(buf[TKSZ-2], buf[TKSZ]) && d5SumValid(buf[TKSZ-1], buf[TKSZ+1]) { return nego.dataSession(hConn, buf) } if nr == DMLEN1 && d5SumValid(buf[0xd5], buf[0xff]) { return nego.handshakeSession(hConn, buf) } log.Warningf("Unrecognized Request from=%s len=%d\n", nego.clientAddr, nr) return nil, NEGOTIATION_FAILED }