标签:
一、修正错误
之前在测试过程中,经常性的出现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