前言
这部分的内容就不做过多的介绍,关于RFB协议的简介能从书上,网上或者其他博客了解到很多。相信大家更加感兴趣的还是RFB协议里面客户端与服务器连接过程。
现在就通过分析远程工具TigerVNC中RFB协议C++源码,了解其客户端与服务器的连接。
客户端源码主要分布在CConnection.cxx,CMsgReader.cxx,CMsgWriter.cxx
服务端源码主要分布在SConnection.cxx,SMsgReader.cxx,SMsgWriter.cxx
协议主要分为三个阶段,下面依次介绍:
第一阶段:版本号认证
客户端: 进入等待服务端发送支持的协议版本号过来的状态
void CConnection::initialiseProtocol()
{
state_ = RFBSTATE_PROTOCOL_VERSION;
}
服务端: 发送支持的版本号 cp.writeVersion(os),随后等待客户端发送客户端使用的版本号
void SConnection::initialiseProtocol()
{
cp.writeVersion(os);
state_ = RFBSTATE_PROTOCOL_VERSION;
}
客户端: 接收服务端支持版本号cp.readVersion(is, &done),然后发送客户端使用的版本给服务端cp.writeVersion(os)
vlog.debug("reading protocol version");
bool done;
if (!cp.readVersion(is, &done)) {
state_ = RFBSTATE_INVALID;
throw Exception("reading version failed: not an RFB server?");
}
if (!done) return;
vlog.info("Server supports RFB protocol version %d.%d",
cp.majorVersion, cp.minorVersion);
// The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
if (cp.beforeVersion(3,3)) {
vlog.error("Server gave unsupported RFB protocol version %d.%d",
cp.majorVersion, cp.minorVersion);
state_ = RFBSTATE_INVALID;
throw Exception("Server gave unsupported RFB protocol version %d.%d",
cp.majorVersion, cp.minorVersion);
} else if (useProtocol3_3 || cp.beforeVersion(3,7)) {
cp.setVersion(3,3);
} else if (cp.afterVersion(3,8)) {
cp.setVersion(3,8);
}
cp.writeVersion(os);
state_ = RFBSTATE_SECURITY_TYPES;
vlog.info("Using RFB protocol version %d.%d",
cp.majorVersion, cp.minorVersion);
服务端: 获取客户端使用的版本号cp.readVersion(is, &done),确认能否支持
vlog.debug("reading protocol version");
bool done;
if (!cp.readVersion(is, &done)) {
state_ = RFBSTATE_INVALID;
throw Exception("reading version failed: not an RFB client?");
}
if (!done) return;
vlog.info("Client needs protocol version %d.%d",
cp.majorVersion, cp.minorVersion);
if (cp.majorVersion != 3) {
// unknown protocol version
char msg[256];
sprintf(msg,"Error: client needs protocol version %d.%d, server has %d.%d",
cp.majorVersion, cp.minorVersion,
defaultMajorVersion, defaultMinorVersion);
throwConnFailedException(msg);
}
if (cp.minorVersion != 3 && cp.minorVersion != 7 && cp.minorVersion != 8) {
vlog.error("Client uses unofficial protocol version %d.%d",
cp.majorVersion,cp.minorVersion);
if (cp.minorVersion >= 8)
cp.minorVersion = 8;
else if (cp.minorVersion == 7)
cp.minorVersion = 7;
else
cp.minorVersion = 3;
vlog.error("Assuming compatibility with version %d.%d",
cp.majorVersion,cp.minorVersion);
}
versionReceived();
第二阶段:安全认证
服务端: 服务端确认能够支持客户端使用版本后,向客户端发送能支持的安全类型数量os->writeU8(secTypes.size())和种类os->writeU8(*i)
std::list<rdr::U8> secTypes;
std::list<rdr::U8>::iterator i;
secTypes = security->GetEnabledSecTypes();
// list supported security types for >=3.7 clients
if (secTypes.empty())
throwConnFailedException("No supported security types");
os->writeU8(secTypes.size());
for (i=secTypes.begin(); i!=secTypes.end(); i++)
os->writeU8(*i);
os->flush();
state_ = RFBSTATE_SECURITY_TYPE;
客户端: 获取服务端能够支持的安全类型数量 is->readU8()和种类 rdr::U8 serverSecType = is->readU8()
int nServerSecTypes = is->readU8();
if (nServerSecTypes == 0)
throwConnFailedException();
std::list<rdr::U8>::iterator j;
for (int i = 0; i < nServerSecTypes; i++) {
rdr::U8 serverSecType = is->readU8();
vlog.debug("Server offers security type %s(%d)",
secTypeName(serverSecType), serverSecType);
/*
* Use the first type sent by server which matches client's type.
* It means server's order specifies priority.
*/
if (secType == secTypeInvalid) {
for (j = secTypes.begin(); j != secTypes.end(); j++)
if (*j == serverSecType) {
secType = *j;
break;
}
}
}
客户端: 选择一个使用的安全类型发送给服务端 os->writeU8(secType)
// Inform the server of our decision
if (secType != secTypeInvalid) {
os->writeU8(secType);
os->flush();
vlog.info("Choosing security type %s(%d)",secTypeName(secType),secType);
}
服务端: 接收客户端选择的安全类型 is->readU8(),随后验证合理性processSecurityType(int secType) => processSecurityMsg() => queryConnection(const char* userName) => approveConnection(bool accept, const char* reason) 。成功调用os->writeU32(secResultOK),失败调用os->writeU32(secResultFailed)并传送错误说明os->writeString(reason)。随后服务端进入状态RFBSTATE_INITIALISATION,等待客户端传客户端初始化信息过来。
备注:其他远程工具如UltraVNC还有Challenge等过程,例如有一种为VNC安全认证,当用VNC认证的时候,协议数据采用明文发送,服务器发送一个16字节的随机数验证给客户端,客户端用DES对验证进行加密,用用户密码作为密钥回复给服务器16字节,这时服务器会返回安全结果给客户端。如果成功就进入初始化报文阶段。不成功就关闭连接。
void SConnection::processSecurityTypeMsg()
{
vlog.debug("processing security type message");
int secType = is->readU8();
processSecurityType(secType);
}
void SConnection::processSecurityType(int secType)
{
// Verify that the requested security type should be offered
std::list<rdr::U8> secTypes;
std::list<rdr::U8>::iterator i;
secTypes = security->GetEnabledSecTypes();
for (i=secTypes.begin(); i!=secTypes.end(); i++)
if (*i == secType) break;
if (i == secTypes.end())
throw Exception("Requested security type not available");
vlog.info("Client requests security type %s(%d)",
secTypeName(secType),secType);
try {
state_ = RFBSTATE_SECURITY;
ssecurity = security->GetSSecurity(secType);
} catch (rdr::Exception& e) {
throwConnFailedException(e.str());
}
processSecurityMsg();
}
void SConnection::processSecurityMsg()
{
vlog.debug("processing security message");
try {
bool done = ssecurity->processMsg(this);
if (done) {
state_ = RFBSTATE_QUERYING;
queryConnection(ssecurity->getUserName());
setAccessRights(ssecurity->getAccessRights());
}
} catch (AuthFailureException& e) {
vlog.error("AuthFailureException: %s", e.str());
os->writeU32(secResultFailed);
if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message
os->writeString(e.str());
os->flush();
throw;
}
}
void SConnection::queryConnection(const char* userName)
{
approveConnection(true);
}
void SConnection::approveConnection(bool accept, const char* reason)
{
if (state_ != RFBSTATE_QUERYING)
throw Exception("SConnection::approveConnection: invalid state");
if (!reason) reason = "Authentication failure";
if (!cp.beforeVersion(3,8) || ssecurity->getType() != secTypeNone) {
if (accept) {
os->writeU32(secResultOK);
} else {
os->writeU32(secResultFailed);
if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message
os->writeString(reason);
}
os->flush();
}
if (accept) {
state_ = RFBSTATE_INITIALISATION;
reader_ = new SMsgReader(this, is);
writer_ = new SMsgWriter(&cp, os);
authSuccess();
} else {
state_ = RFBSTATE_INVALID;
throw AuthFailureException(reason);
}
}
客户端: 获取服务端验证结果 is->readU32(),通过则继续调用 securityCompleted() 。失败则报出异常,获取错误说明 reason.buf = is->readString()
void CConnection::processSecurityResultMsg()
{
vlog.debug("processing security result message");
int result;
if (cp.beforeVersion(3,8) && csecurity->getType() == secTypeNone) {
result = secResultOK;
} else {
if (!is->checkNoWait(1)) return;
result = is->readU32();
}
switch (result) {
case secResultOK:
securityCompleted();
return;
case secResultFailed:
vlog.debug("auth failed");
break;
case secResultTooMany:
vlog.debug("auth failed - too many tries");
break;
default:
throw Exception("Unknown security result from server");
}
CharArray reason;
if (cp.beforeVersion(3,8))
reason.buf = strDup("Authentication failure");
else
reason.buf = is->readString();
state_ = RFBSTATE_INVALID;
throw AuthFailureException(reason.buf);
}
第三阶段:客户端和服务端互送初始化信息
客户端: 安全认证通过后,传送初始化信息给服务端 writer_->writeClientInit(shared),是否接受共享(shared),若不接受,则服务端只远程这一个客户端。同时进入状态RFBSTATE_INITIALISATION,等待服务端传初始化信息过来
void CConnection::securityCompleted()
{
state_ = RFBSTATE_INITIALISATION;
reader_ = new CMsgReader(this, is);
writer_ = new CMsgWriter(&cp, os);
vlog.debug("Authentication success!");
authSuccess();
writer_->writeClientInit(shared);
}
void CMsgWriter::writeClientInit(bool shared)
{
os->writeU8(shared);
endMsg();
}
服务端: 获取客户端初始化信息reader_->readClientInit() ,流程为processInitMsg() => readClientInit() => clientInit(bool shared)
void SConnection::processInitMsg()
{
vlog.debug("reading client initialisation");
reader_->readClientInit();
}
void SMsgReader::readClientInit()
{
bool shared = is->readU8();
handler->clientInit(shared);
}
void SConnection::clientInit(bool shared)
{
writer_->writeServerInit();
state_ = RFBSTATE_NORMAL;
}
服务端: 发送服务端初始化信息到客户端,然后进入RFBSTATE_NORMAL状态,可与客户端互发数据 reader_->readMsg();
void SConnection::clientInit(bool shared)
{
writer_->writeServerInit();
state_ = RFBSTATE_NORMAL;
}
void SMsgWriter::writeServerInit()
{
os->writeU16(cp->width);
os->writeU16(cp->height);
cp->pf().write(os);
os->writeString(cp->name());
endMsg();
}
客户端: 获取服务端初始化信息,processInitMsg() => readServerInit() => serverInit() ,然后进入RFBSTATE_NORMAL状态。连接完毕,可与服务端互发数据 reader_->readMsg();
void CConnection::processInitMsg()
{
vlog.debug("reading server initialisation");
reader_->readServerInit();
}
void CMsgReader::readServerInit()
{
int width = is->readU16();
int height = is->readU16();
handler->setDesktopSize(width, height);
PixelFormat pf;
pf.read(is);
handler->setPixelFormat(pf);
CharArray name(is->readString());
handler->setName(name.buf);
handler->serverInit();
}
void CConnection::serverInit()
{
state_ = RFBSTATE_NORMAL;
vlog.debug("initialisation done");
}