溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

使用uIP將TUN網(wǎng)卡適配到TAP網(wǎng)卡-tun2tap

發(fā)布時間:2020-07-17 07:21:58 來源:網(wǎng)絡(luò) 閱讀:1892 作者:dog250 欄目:移動開發(fā)

想玩虛擬網(wǎng)卡一定要玩TUN/TAP(以下簡稱TAP),想玩TAP一定要知道uIP。uIP是一個用戶態(tài)實現(xiàn)的一個超級輕量級的麻雀雖小五臟俱全的TCP/IP協(xié)議棧,相比lwIP要好用好玩得多,具體怎么個意思,還是請教它的大帥哥作者吧。本文要說的只是它的一個應(yīng)用,既如何將TUN模式的虛擬網(wǎng)卡適配成TAP模式的虛擬網(wǎng)卡,這個需求確實是需要的。
      到底什么時候需要把TUN模式的虛擬網(wǎng)卡裝bi成一個TAP模式的虛擬網(wǎng)卡呢?在你想這么做的時候!我個人認為TAP模式的虛擬網(wǎng)卡特別適合做服務(wù)端,它可以任意橋接物理網(wǎng)段和虛擬網(wǎng)段,但是有些平臺真的就是不支持TAP模式虛擬網(wǎng)卡,比如說Android系統(tǒng),我一直都想知道為什么,但是得到就是一句sorry!作為一個開源的平臺,我逐漸發(fā)現(xiàn)它不是那么的Free,任何平臺都沒有Linux那樣任你隨便蹂躪。Android限制API的使用,沒有root,那么怎么在有限的API接口范圍內(nèi)達到效果呢?如果說Open×××的服務(wù)端使用的一直都是TAP模式的虛擬網(wǎng)卡,難道還要專門為Android單獨啟動一個TUN模式的服務(wù)嗎?作為一個偏執(zhí)的人,我絕不這么做!那么我會想方設(shè)法把Android的TUN網(wǎng)卡適配到TAP模式。
      TUN和TAP的區(qū)別是什么?無非就是少了一個以太網(wǎng)鏈路層,內(nèi)核驅(qū)動層面不給實現(xiàn),那么我自己在用戶態(tài)實現(xiàn)行不?大家都知道,從TUN網(wǎng)卡對應(yīng)的字符設(shè)備讀取出來的東西以及寫入的東西就是一個IP數(shù)據(jù)報,那么很簡單,我只需要實現(xiàn)以下三點即可:
1.將數(shù)據(jù)從TUN字符設(shè)備讀出來后封裝一個以太頭;
2.將數(shù)據(jù)寫入TUN字符設(shè)備前去除其以太頭。
3.實現(xiàn)一個ARP邏輯,應(yīng)付ARP請求以及為了封裝目標MAC地址而主動發(fā)送ARP請求。

很簡單是吧。但是要是真的寫起代碼來,還真的要費些時間和精力。
      我早就承認我不是一個真正的程序員,然而我是獵手,我希望用現(xiàn)成的東西幫我完成以上這一切,能重用的東西為何不重用呢,做到這一點需要的是積累,如果你不知道有uIP這么一個東西,那么可能你現(xiàn)在真的需要自己寫代碼了。上周買了一本書,講述iOS以及Mac OS X內(nèi)核編程的,原因是我的蘋果電腦已經(jīng)成了垃圾玩具了,心想能像對待Linux內(nèi)核那樣蹂躪Mac OS內(nèi)核,可是并不是那么回事,知識和能力需要積累,并不是想當然的,雖然操作系統(tǒng)原理都那回事,然而當你動手的時候,就會發(fā)現(xiàn)并非如此!
     還好,我自認對TAP虛擬網(wǎng)卡還算比較熟悉,因此我相信自己可以做到這件TUN適配到TAP的事情,由于自己比較懶,所有使用了uIP,如果不用uIP的話,憑著自己對以太幀結(jié)構(gòu)以及ARP協(xié)議的理解,也是可以完成代碼的,這個代碼的關(guān)鍵并不是什么高深的算法或者深刻的理論知識,而是對協(xié)議格式的理解以及簡單地掌握C語言內(nèi)存操作的技巧,僅此而已。如果你還對uIP不熟悉,那就就花10分鐘時間瀏覽一下,它是超級簡單的,它把TAP網(wǎng)卡當成網(wǎng)線,在用戶態(tài)實現(xiàn)了一個完整的TCP/IP協(xié)議棧。既然uIP在用戶態(tài)實現(xiàn)了一個完整的協(xié)議棧,那么它肯定也實現(xiàn)了ARP邏輯以及以太幀的封裝邏輯,而這正是TUN適配到TAP的時候所要用到的。
      那么該怎么辦?很簡單,修改uIP的代碼便是,在給出具體的修改之前,首先說一下除了使用了uIP之外,還使用了simpletun,玩TAP虛擬網(wǎng)卡的如果一頭扎進Open×××那就錯了,應(yīng)該先玩下simpletun,就一個C文件,直接gcc編譯即可。我使用simpletun作為服務(wù)端:
simpletun -s -p 12345 -a -i zz0
我之所以使用zz0作為虛擬網(wǎng)卡的名字是因為這樣在ifconfig的時候它會在最后,配置它的時候不用再拖動滾動條了。很顯然,服務(wù)端使用的是TAP模式,那么客戶端我準備使用修改后的uIP,由于標準的uIP使用的是TAP,于是我把它修改成TUN模式,只需要將tapdev_init中的IFF_TAP改為IFF_TUN即可。修改了虛擬網(wǎng)卡模式之后,剩下的就是重寫讀寫邏輯了,之所以說是重寫而不是修改是因為重寫比修改更容易,uIP的好處在于其定義了很多好用的接口而不是它實現(xiàn)的現(xiàn)成邏輯,使用這些接口或者稍加改動的接口來實現(xiàn)一個新的邏輯或許更加容易。

      和標準的uIP不同的是,tun2tap版本的uIP并不從虛擬網(wǎng)卡讀取以太幀,而是從網(wǎng)絡(luò)套接字讀取以太幀,虛擬網(wǎng)卡只是tun2tap版本uIP的“上層”,這一點是和標準的uIP的unix/main.c邏輯完全相反的。以下就是新版的main邏輯代碼:


int main(int argc, char **argv)
{
    .......
    // 設(shè)置本端的IP地址以及MAC,正常邏輯應(yīng)該在獲取虛擬IP地址以后再設(shè)置
    uip_ipaddr(ipaddr, 1,2,3,5);
    uip_sethostaddr(ipaddr);
    uip_ipaddr(ipaddr, 1,2,3,4);
    uip_setdraddr(ipaddr);
    uip_ipaddr(ipaddr, 255,255,255,0);
    uip_setnetmask(ipaddr);
    ... // 設(shè)置MAC地址
        // 初始化和simpletun連接的套接字
    net_init();
        while(1) {
                char raw_tun[UIP_BUFSIZE];
                memset(uip_buf, 0, sizeof(uip_buf));
        // 從套接字讀取數(shù)據(jù),要么為ARP,要么為IP
                uip_len = net_read();
                if(uip_len > 0) {
            // 如果是IP的話,摘掉以太頭送往TUN網(wǎng)卡
                        if(BUF->type == htons(UIP_ETHTYPE_IP)) {
                                char *buf2tun = BUF;
                                buf2tun += sizeof(struct uip_eth_hdr);
                // 送往TUN虛擬網(wǎng)卡
                                tapdev_send(buf2tun, uip_len-sizeof(struct uip_eth_hdr));
            // 如果是ARP的話,回復ARP請求或者...
                        } else if(BUF->type == htons(UIP_ETHTYPE_ARP)) {
                // 處理ARP
                                uip_arp_arpin();
                                if(uip_len > 0) {
                    // 回復ARP
                                        net_send();
                                }
                        }
                } else if(timer_expired(&periodic_timer)) {
                        timer_reset(&periodic_timer);
                        for(i = 0; i < UIP_CONNS; i++) {
                                uip_periodic(i);
                                if(uip_len > 0) {
                                        uip_arp_out();
                                        net_send();
                                }
                        }
                        if(timer_expired(&arp_timer)) {
                                timer_reset(&arp_timer);
                                uip_arp_timer();
                        }
                }
        // 繼續(xù)處理TAP網(wǎng)卡讀出的數(shù)據(jù),封裝上以太幀頭
                memset(uip_buf, 0, sizeof(uip_buf));
                uip_len = tapdev_read(raw_tun,
                                        UIP_BUFSIZE);
                if(uip_len > 0) {
                        memcpy(uip_buf+sizeof(struct uip_eth_hdr),
                                        raw_tun,
                                        uip_len);
            // 要么請求ARP,要么直接發(fā)送數(shù)據(jù)
                        uip_arp_out();
                        net_send();
                }
        }
        return 0;
}

以上代碼基本就完成了TUN到TAP的適配,如此一來,Open×××的服務(wù)端就可以一直使用TAP模式,即便某些平臺的Open×××必須使用TUN模式,也可以采用以上的方式實現(xiàn)一個用戶態(tài)的以太層,在用戶態(tài)封裝/解封裝以太幀。這樣可以大大降低服務(wù)端的復雜性。
      起初,我希望能直接在網(wǎng)上找到TUN適配到TAP的現(xiàn)成代碼,于是我搜索“TUN TAP 轉(zhuǎn)化”,“TUN TAP 適配”均無結(jié)果,換英文搜還是未果,于是按照老外的常用命名邏輯搜索“tun2tap”,“tap2tun”也依然沒找到什么,反而獲取了幾個reset...因此我寫下此文,還是老想法,希望如果有人想做類似事情的時候,能幫上點什么,起碼不像我一樣一無所獲,互聯(lián)網(wǎng)上應(yīng)該應(yīng)有盡有才對。


向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI