标签:
一、修正错误
之前在测试过程中,经常性的出现Invalid msg错误,导致连接被重置。经过调查,发现原来是数据分片时最后一个分片的长度计算有误导致。下面我们来分析一下这个错误的代码:
int check_msg(client_t* client, msg_t* msg)
{
size_t msg_data_len;
if (msg->zone.clip)
{
if (msg->zone.last) msg_data_len = msg_data_length(msg) % client->max_length;
else msg_data_len = client->max_length;
}
else msg_data_len = msg_data_length(msg);
if (checksum(msg, sizeof(msg_t) + msg_data_len))
{
SYSLOG(LOG_ERR, "Invalid msg");
return 0;
}
return 1;
}
由上面的代码可以看出,当到来的数据包为最后一个分片时,根据代码中的运算方法直接与对端的max_length取模,此时如果最后一个分片的长度正好能被max_length整除时。所计算出的长度就是错的,应此会平凡的遇到Invalid msg错误。与该错误类似的问题已全部修正,已修正的函数有:
network.c: process_clip_msg和check_msg函数 msg_group.c: parse_msg_group函数 server.c: tcp_process函数 client.c: client_process函数
二、支持DHCP
typedef struct
{
unsigned short major_version;
unsigned char minor_version : 4;
unsigned char revision_version : 4;
unsigned int ip;
unsigned int gateway;
unsigned char mask;
unsigned short internal_mtu;
unsigned char signature[31];
unsigned char dhcp;
} sys_login_msg_t;
将头3个字节修改为版本号的定义,在末尾增加31字节的signature和1字节的dhcp标志位,使用31字节作为signature的长度的意义在于与下一字节的dhcp标志位组合后使整个结构对齐到46字节。由于该校验工作只发生在连接建立后,因此出于安全和拓展因素考虑,在配置文件中只记录签名文件的路径,在每次进行校验时由lua脚本动态读出并做校验。这样做的好处是:(1) 安全,文件内容永远不记录在内存中 (2) 拓展性强,当服务器端添加新的客户端签名时无需重启服务器端程序。 需要注意的是:建议为每个单独的客户端配置不同的签名,这样做的好处是,每个客户端都独立持有各自的签名,更加安全。三、更灵活的签名校验
为了兼容老版本,因此将sys_login_msg_t结构的头3字节用作版本号的定义。同时为了增强灵活性和安全性,在qtun程序中仅保存signature文件的路径,每次做校验时都动态的将其读出。
int script_signature_verify(lua_State* lua, const unsigned char signature[31]) {
lua_getglobal(lua, "signature_verify");
lua_pushlstring(lua, (char*)signature, 31);
if (lua_pcall(lua, 1, 1, 0) != 0) {
SYSLOG(LOG_ERR, "%s\n", lua_tostring(lua, -1));
return 0;
}
return lua_toboolean(lua, -1);
}
int script_load_signature(lua_State* lua, unsigned char signature[31]) {
const char* str;
lua_getglobal(lua, "signature_load");
if (lua_pcall(lua, 0, 1, 0) != 0) {
SYSLOG(LOG_ERR, "%s\n", lua_tostring(lua, -1));
return 0;
}
str = lua_tostring(lua, -1);
memcpy(signature, str, 31);
return 1;
}
function signature_load()
local file = io.open(qtun.conf.signature_file)
local ret = ‘‘
assert(file)
if qtun.state.is_server then
ret = file:read(‘*a‘)
else
ret = file:read(31)
end
file:close()
return ret
end
function signature_verify(signature)
if qtun.state.is_server then
local file = io.open(qtun.conf.signature_file)
assert(file)
while true do
local line = file:read()
if line == nil then break end
if line == signature then return true end
end
file:close()
return false
else
return signature == signature_load()
end
end
unsigned char signature[31] = {0};
script_load_signature(qtun->lua, signature);
msg = new_login_msg(qtun->localip, 0, 0, 1, 0, signature);
if (!script_signature_verify(qtun->lua, login->signature)) { // 签名检查失败
msg_t* new_msg;
unsigned char signature[sizeof(login->signature)];
memset(signature, 0, sizeof(signature));
SYSLOG(LOG_ERR, "unknown signature");
pool_room_free(&qtun->pool, room_id);
data = NULL;
new_msg = new_login_msg(0, 0, 0, 0, 0, signature);
if (new_msg) {
write_c(client, new_msg, sizeof(msg_t) + msg_data_length(new_msg));
pool_room_free(&qtun->pool, MSG_ROOM_IDX);
}
close_client(for_del, idx);
goto end;
}
if (!script_signature_verify(qtun->lua, login->signature)) {
SYSLOG(LOG_ERR, "invalid signature");
pool_room_free(&qtun->pool, room_id);
goto end;
}
四、完整代码
完整代码可到step15中查看
版本号:1.0.0
日期:2015-05-20
Jump The Great Firewall【step15 支持DHCP】
标签:
原文地址:http://www.cnblogs.com/lwch/p/4519258.html