QTun【step 15 DHCP対応】

5980 ワード

一、誤りを修正する
以前はテスト中に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をサポートする
  • プロファイルのuse_を追加dhcpフィールドとluaインタフェース
  • を追加
  • sys_の変更login_msg_t構造
    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)拡張性が強く、サーバ側に新しいクライアント署名を追加した場合、サーバ側プログラムを再起動する必要がないことです.注意が必要なのは、個々のクライアントに異なる署名を構成することをお勧めします.このようなメリットは、各クライアントが独立してそれぞれの署名を持っており、より安全であることです.
  • server_の変更process_login関数1).まずクライアントからのバージョン番号をチェックする2).DHCPモードでない場合は、クライアントからのイントラネットIPが現在のセグメント内にあるかどうかをチェックする3).クライアントから送信署名が現在の署名ファイルにあるかどうかを確認する4).DHCPモードを有効にするかどうかによってserver_を呼び出すprocess_login_dhcp関数またはserver_process_login_no_dhcp関数は、前者が現在のセグメントに基づいて適切なIPアドレス通知クライアントを探し、後者が元の論理
  • である.
  • connect_の変更server関数1).サーバ側からのバージョン番号がローカルバージョン番号と同じかどうかを確認する2).サーバ側からのIPアドレスが0 3であるかをチェックする).サーバ側からのsignatureがローカルと同じかどうかを確認する4).サーバ側からのIPアドレスがローカルと同じかどうかをチェックし、サーバ側がDHCPモードである場合はサーバ側から与えられたIPを用いてバインド5).その他の初期化
  • を行う.
    三、より柔軟な署名検証
    古いバージョンと互換性があるためsys_login_msg_t構造のヘッダ3バイトはバージョン番号の定義として用いられる.また、柔軟性とセキュリティを向上させるため、qtunプログラムにはsignatureファイルのパスのみが保存され、チェックするたびに動的に読み出されます.
  • 定義script_signature_verifyとscript_load_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
    ", 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
    ", lua_tostring(lua, -1)); return 0; } str = lua_tostring(lua, -1); memcpy(signature, str, 31); return 1; }
  • 以上の2つの関数は最終的にqtunを呼び出す.luaのsignature_verifyとsignature_loadインタフェース
    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
    
  • connect_server関数では、loginメッセージを作成する前に署名を
    unsigned char signature[31] = {0};
    script_load_signature(qtun->lua, signature);
    msg = new_login_msg(qtun->localip, 0, 0, 1, 0, signature);
    
  • に読み出す.
  • server_process_login関数でscript_を呼び出すsignature_verifyクライアントから送信署名が署名ファイル
    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;
    }
    
  • に存在するかどうかを確認する.
  • connect_サーバ関数で、サーバがデータを返すときにscript_を呼び出すsignature_verifyインタフェースによるチェック
    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