青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Xiao.Zhu C++

Xiao.Zhu C++

  C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
  29 隨筆 :: 14 文章 :: 17 評論 :: 0 Trackbacks
1.概要
  相信在IPv6的時代到來之前,NAT仍然是解決大多數人上網的主要途徑,而且它在企業內網Intranet中也扮演著十分重要的角色.
  NAT的全稱是Network Address Translator(網絡地址轉換),其主要作用是把內網IP地址轉換成為全球唯一的可定位的外部IP地址,從而使得局域網內的所有用戶可以通過一個或 者少數幾個IP地址與全球的Internet通信,不僅節約了IP地址,而且在一定程度上保護了內部網絡.
  由于工作需要,筆者希望編寫一個具有NAT功能的軟件,將同一個網段內把本機設為網關的擁有私有IP的主機發來的數據包轉發到外部網絡,并把響應信息返回給對應的主機.這個問題在不同的層次上做就有不同的解決方案,由于筆者也是網絡新手,走了不少彎路:
  首先,企圖在用戶層利用原始套接字(Raw Socket)來實現,但是系統擁有對未開放端口的自動復位功能,每當我們轉發一個數據包時,需要占用系統的一個端口,但是這點系統并不知道,它接收到對 于這個端口的回應信息時,會認為本端口不存在,并發送一個帶有復位標志的數據包請求對方斷開連接.這就阻攔了所有非本機請求的連接,所以這個方案首先被否 定了.
  隨后,不得不往系統下面走,準備在核心態實現.當然越簡單越好,于是筆者選擇了Filter-Hook驅動.Filter-Hook Driver, 事實上不是一種新的網絡驅動,它只是擴展了IP過濾驅動(IP Filter Driver)的功能,是一種內核模式驅動(Kernel Mode Driver). 在Filter-Hook Driver中我們提供回調函數(callback),然后使用IP Filter Driver注冊回調函數。這樣當數據包發送和接收時,IP Filter Driver會調用回調函數。可惜夢想再一次破滅,這個回調函數的返回值只有PF_FORWARD,PF_DROP,PF_PASS三種,并不能把修改后 的數據包主動發送出去.
  只有在向底層走了,NDIS應該是必經之路.而且經過兩次失敗,發現閉門造車是不可行的,偶然在網上搜索到了幾篇文章,聽說在NDIS的中間層驅動中可以實現NAT,新的探索之路就這樣開始了......

2.NAT簡介
  NAT(Network Address Translator)的出現并不是偶然的,一方面是由于IPv4的創造者們沒有想到,Internet以及TCP/IP發展如此迅速,在他們還們完全享 受TCP/IP的成功帶來的快感之前,32位的IP地址竟然不夠用了;另一方面我們必須保證某些特殊的主機在于局域網絡連接的同時,保持對外界直接曝光, 但是由需要與外界在受控的情況下通訊.下圖是一個典型的NAT示意.
    \ | /             .                     /
  +---------------+ WAN   .       +-----------------+/
  |Regional Router|----------------------|Stub Router w/NAT|---
  +---------------+       .       +-----------------+\
                    .               |     \
                    .               | LAN
                    .           ---------------
                Stub border

  下面舉一個具體的例子說明兩個處于內網的主機是如何通過NAT通信的
                          \ | /
                        +---------------+
                        |Regional Router|
                        +---------------+
                      WAN |       | WAN
                          |       |
            Stub A .............|....   ....|............ Stub B
                          |       |
              {s=198.76.29.7,^ |       | v{s=198.76.29.7,
              d=198.76.28.4}^ |       | v d=198.76.28.4}
              +-----------------+     +-----------------+
              |Stub Router w/NAT|     |Stub Router w/NAT|
              +-----------------+     +-----------------+
                  |                 |
                  | LAN           LAN |
              -------------         -------------
                      |           |
          {s=10.33.96.5, ^ |           | v{s=198.76.29.7,
          d=198.76.28.4}^ +--+         +--+ v d=10.81.13.22}
                    |--|         |--|
                    /____\       /____\
                  10.33.96.5     10.81.13.22

圖 中有兩個殘樁網絡A和B,現在假設A中的一臺主機10.33.96.5需要同B中的10.81.13.22通信,它必須把自己發送的數據報的目的地址設置 為B的一個外網地址198.76.28.4,并在NAT中把源地址轉換成A的外部地址198.76.29.7,才能使數據包順利抵達廣域網中的路由器,并 轉到B,在由B網的NAT把數據包發送給10.81.13.22.
  隨著NAT多年的發展,出現了很多不同風格,應用于不同場合的NAT.筆者實現的是傳統NAT中的一種特殊情況NAPT(Network Address Port Translation),它把所有內網的IP地址都轉換成同一個外部IP地址,并通過不同的端口來區分各個不同的內部主機.

3.中間層驅動NDIS Intermediate Drivers
  所謂中間層驅動是指位于微端口和協議之間的驅動,實際上它是微軟在網絡驅動中留出來的接口,便于用戶實現自己對數據包的處理.在協議驅動層看來,它就是微 端口;在微端口看來,它又是協議層驅動.因此,如果需要在此層實現自己對數據包的處理函數,不僅要在上邊緣注冊MiniportXxx Function,還要在下邊緣注冊ProtocolXxx Function.一般在這個層次做工作的同志都會學習并了解DDK的一個經典Sample:Passthru.如果對它不了解,可以去看看 Addylee前幾天的文章"基于PassThru的NDIS中間層驅動程序擴展",講得很清晰.

4.NAPT的具體實現
  程序整體框架依然是基于PaaThru的,具體要注意的問題有以下幾點:
4.1 轉發表的維護
typedef struct _PortNode
{
  USHORT inport;               //內網端口
  USHORT export;           //轉發端口
  USHORT report;           //遠程端口
  ULONG inip;           //內網IP
  ULONG reip;           //遠程IP
  struct _PortNode * next;         //鏈表指針
}PortNode;

PortNode * first = NULL;             //全局變量,轉發表的頭結點

NTSTATUS
DriverEntry(
  IN   PDRIVER_OBJECT     DriverObject,
  IN   PUNICODE_STRING     RegistryPath
  )
{
    ......
  Status = NdisAllocateMemory(&first,sizeof(PortNode), 0,HighestAcceptableMax);
  if(Status == NDIS_STATUS_SUCCESS)
  {
    NdisZeroMemory(first,sizeof(PortNode));
    //首結點的inip表示本主機地址
    first->inip = 本主機IP        
    //首結點的reip表示本主機所在的網絡地址
    first->reip = first->inip & 0x00ffffff;
  }
  ......
}

4.2 校驗和的計算
USHORT CheckSum(USHORT *buffer, int size)
{
  unsigned long cksum=0;
  while(size >1)
  {
    cksum += * buffer++;
    size -=sizeof(USHORT);
  }
  if(size)
  {
    cksum += *(UCHAR*)buffer;
  }
  cksum = (cksum >> 16) + (cksum & 0xffff);
  cksum += (cksum >>16);
  return (USHORT)(~cksum);
}
  IP TCP UDP三種包校驗和的計算方法是一致的,本文采用的方法是簡單地重新計算整個包的校驗和,在RFC1631中,作者提出了一種差量計算法以提高計算速度,并且給出了C語言版的源代碼.

4.3 對收到的數據包的過濾和轉發
INT
PtReceivePacket(
  IN   NDIS_HANDLE         ProtocolBindingContext,
  IN   PNDIS_PACKET     Packet
  )
{
  ......

 
  PUCHAR     pPacketContent;
    PUCHAR     pBuf;
    UINT       BufLength;
    MDL       * pNext;
    UINT       i,j;
  BOOLEAN     transflag = FALSE;
  PNDIS_BUFFER MyBuffer;
  PIP_Header   pIPHeader;
 
  ......

  NdisDprAllocatePacket(&Status,
                  &MyPacket,
                  pAdapt->RecvPacketPoolHandle);

  if(Status == NDIS_STATUS_SUCCESS)
  {
    //add by thinking 06.6.3
    //把數據包內容從Packet拷貝到pPacketContent
    Status= NdisAllocateMemory( &pPacketContent, 2000, 0,HighestAcceptableMax);
    if (Status!=NDIS_STATUS_SUCCESS )   return Status;
    NdisZeroMemory (pPacketContent, 2000);
    NdisQueryBufferSafe(Packet->Private.Head, &pBuf, &BufLength, 32 );
    NdisMoveMemory(pPacketContent, pBuf, BufLength);
    i = BufLength;
    pNext = Packet->Private.Head;
    for(;;)
    {
        if(pNext == Packet->Private.Tail)
          break;
        pNext = pNext->Next;
        if(pNext == NULL)
          break;
        NdisQueryBufferSafe(pNext,&pBuf,&BufLength,32);
        NdisMoveMemory(pPacketContent+i,pBuf,BufLength);
        i+=BufLength;
    }
    if(pPacketContent[12] == 8 && pPacketContent[13] == 0 ) //is ip packet
    {
        ULONG netip;
        pIPHeader = (PIP_Header)(pPacketContent+14);
        netip = pIPHeader->ipSource & 0x00ffffff;
        //對收到的數據包進行過濾,只轉發需要轉發的包
        if(pIPHeader->ipDestination == first->inip && netip != first->reip)
        //如果目的地址是本主機,并且源IP不是本網段地址,則轉發給內網主機
        {
          DbgPrint("\nTransInPacket...\n");
          for(j=0;j<=i;j++)
            DbgPrint("%x ",pPacketContent[j]);
          //修改發給內網的數據包頭
          transflag = TransIn(pPacketContent);
        }
        else if(pIPHeader->ipDestination != 0xffffffff &&
          (pIPHeader->ipDestination & 0x00ffffff) != first->reip &&
          netip == first->reip)
        //如果目的地址不是廣播地址,而且是外網地址,源地址是內網IP,則轉發給外網
        {
          DbgPrint("\nTransOutPacket...\n");
          for(j=0;j<=i;j++)
            DbgPrint("%x ",pPacketContent[j]);
          //修改發給外網的數據包頭
          transflag = TransOut(pPacketContent);
        }
    }

    if(!transflag)
    {
          //按照原來的方式往上提交  
          ......
    }
    else
    {
        //轉發的一段關鍵代碼
        NdisAllocateBuffer(&Status,&MyBuffer,pAdapt->SendPacketPoolHandle,pPacketContent,i);
        NdisChainBufferAtFront(MyPacket, MyBuffer);
        Resvd =(PRSVD)(MyPacket->ProtocolReserved);
        Resvd->OriginalPkt = MyPacket;
          MyPacket->Private.Head->Next = NULL;
        MyPacket->Private.Tail = NULL;
        NdisSetPacketFlags(MyPacket, NDIS_FLAGS_DONT_LOOPBACK);
        NdisReturnPackets(&Packet, 1);
        NdisSend(&Status,pAdapt->BindingHandle,MyPacket);
        if(Status != NDIS_STATUS_PENDING)
        {
          NdisUnchainBufferAtFront(MyPacket ,&MyBuffer); //從MyPacket中解除buffer
          NdisQueryBufferSafe(MyBuffer, &pPacketContent, &BufLength,32 );
          if(pPacketContent != NULL)
            NdisFreeMemory(pPacketContent,BufLength, 0);
          NdisFreeBuffer(MyBuffer);
        }
        return 0;
    }
  ......
}

4.4 數據包頭的修改
  根據具體情況修改數據包的IP包頭,TCP包頭,或者UDP包頭,并且在修改的同時繼續維護轉發表,下面只給出TransIn的代碼,TransOut與其原理相同.
BOOLEAN TransIn(PUCHAR pPacketContent)
{
  PortNode * inmap;
  PIP_Header pIPHeader = (PIP_Header)(pPacketContent+14);
  USHORT iphdrlen = (pIPHeader->iphVerLen & 0x0f) * sizeof(ULONG);
  UCHAR checkbuff[2000] = {0};

  if(pIPHeader->ipProtocol == 6)
  {
    PTCP_Header pTCPHeader;
    USHORT tcphdrlen;
    pTCPHeader = (PTCP_Header)(pPacketContent+14 + iphdrlen);
    //tcphdrlen = ((pTCPHeader->dataoffset & 0xf0) >> 4) * sizeof(ULONG);
    tcphdrlen = htons(pIPHeader->ipLength) - iphdrlen;
    inmap = InMapping(pIPHeader->ipSource,pTCPHeader->sourcePort,
        pTCPHeader->destinationPort);
    if(inmap == NULL)
        return FALSE;

    //修改目的地址和目的端口,校驗和
    pIPHeader->ipDestination = inmap->inip;
    pTCPHeader->destinationPort = inmap->inport;
    pIPHeader->ipChecksum = 0;
    pTCPHeader->checksum = 0;

    //填充TCP偽首部
    psdhdr.saddr = pIPHeader->ipSource;
    psdhdr.daddr = pIPHeader->ipDestination;
    psdhdr.len = htons(tcphdrlen);
    psdhdr.mbz = 0;
    psdhdr.proto = 6;

    //計算TCP首部校驗和
    NdisMoveMemory(checkbuff,&psdhdr,sizeof(psdhdr));
    NdisMoveMemory(checkbuff+sizeof(psdhdr),pTCPHeader,tcphdrlen);
    pTCPHeader->checksum = CheckSum((USHORT *)checkbuff,sizeof(psdhdr)+tcphdrlen);

    //計算IP首部校驗和
    pIPHeader->ipChecksum = CheckSum((USHORT *)pIPHeader,iphdrlen);

    return TRUE;
  }
  else if(pIPHeader->ipProtocol == 17)
  {
    PUDP_Header pUDPHeader;
    USHORT udplen;
    pUDPHeader = (PUDP_Header)(pPacketContent+14 + iphdrlen);
    udplen = htons(pUDPHeader->len);
    inmap = InMapping(pIPHeader->ipSource,pUDPHeader->sourcePort,
        pUDPHeader->destinationPort);
    if(inmap == NULL)
        return FALSE;

    //修改目的地址和目的端口,校驗和
    pIPHeader->ipDestination = inmap->inip;
    pUDPHeader->destinationPort = inmap->inport;
    pIPHeader->ipChecksum = 0;
    pUDPHeader->checksum = 0;

    //填充UDP偽首部
    psdhdr.saddr = pIPHeader->ipSource;
    psdhdr.daddr = pIPHeader->ipDestination;
    psdhdr.len = pUDPHeader->len;
    psdhdr.mbz = 0;
    psdhdr.proto = 17;

    //計算UDP校驗和,包括所有UDP數據
    NdisMoveMemory(checkbuff,&psdhdr,sizeof(psdhdr));
    NdisMoveMemory(checkbuff+sizeof(psdhdr),pUDPHeader,udplen);
    pUDPHeader->checksum = CheckSum((USHORT *)checkbuff,sizeof(psdhdr)+udplen);

    //計算IP首部校驗和
    pIPHeader->ipChecksum = CheckSum((USHORT *)pIPHeader,iphdrlen);

    return TRUE;
  }
  else
    return FALSE;
}

5.小結
  本文簡單介紹了傳統NAT在中間層驅動中的實現,很多地方都可以進行改進.例如:校驗和的計算可以采用差量計算法以減少計算延遲;轉發表的維護可以采用樹 型結構(而不是本文中的鏈表)以減少轉發表的查找時間;定時對轉發表進行清理,釋放長時間不用的端口,以節約系統資源;構建ARP機制,并動態維護相關主 機的MAC地址;通過共享內存或者修改驅動對象的DispatchTable與用戶層進行通信,從而動態調整驅動功能.
posted on 2007-05-06 18:05 Xiao.Zhu 閱讀(330) 評論(0)  編輯 收藏 引用

只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲亚洲精品在线观看 | 午夜一级在线看亚洲| 亚洲午夜av| 日韩视频在线一区| 亚洲精品乱码久久久久久蜜桃麻豆 | 久久久久久91香蕉国产| 99精品久久久| 91久久精品国产91性色| 国产精品久久久久影院色老大 | 亚洲剧情一区二区| 夜夜嗨av一区二区三区四区| 一区二区三区在线观看视频 | 99在线精品视频在线观看| 亚洲国产mv| 久久精品水蜜桃av综合天堂| 美女久久网站| 欧美大成色www永久网站婷| 久久国产精品久久国产精品| 国语自产偷拍精品视频偷| 韩日精品视频| 一区二区国产在线观看| 欧美成人激情在线| 久久国内精品视频| 亚洲国产另类精品专区| 亚洲一区二区三区777| 免费不卡欧美自拍视频| 国产日韩欧美不卡| 亚洲韩日在线| 久久中文精品| 亚洲美女诱惑| 欧美成人中文字幕在线| 国产无遮挡一区二区三区毛片日本| 尤物在线精品| 久久经典综合| 欧美福利一区二区三区| 久久人人爽爽爽人久久久| 久久综合伊人77777尤物| 亚洲电影免费观看高清| 欧美美女日韩| 99国产一区| 99精品免费网| 欧美在线首页| 国产在线播放一区二区三区| 亚洲一区二区三区免费在线观看 | 久久国产精品高清| 国产精品超碰97尤物18| 一区二区冒白浆视频| 亚洲在线电影| 洋洋av久久久久久久一区| 亚洲成人资源| 免费黄网站欧美| 国产精品99久久久久久久vr| 亚洲网站视频| 国产一级久久| 欧美丰满少妇xxxbbb| 欧美日韩国产综合在线| 亚洲欧美国产毛片在线| 欧美在线视频免费播放| 亚洲欧美日韩爽爽影院| 欧美日韩免费网站| 久久午夜色播影院免费高清| 欧美一区二区在线播放| 亚洲精品一区二区三| 亚洲免费一在线| 亚洲精品视频免费| 欧美在线你懂的| 韩国成人理伦片免费播放| 欧美国产日韩一区二区在线观看| 久久看片网站| 欧美精品亚洲二区| 免费视频一区二区三区在线观看| 欧美区亚洲区| 一本色道综合亚洲| 欧美一区二区三区免费观看视频| 亚洲欧美中文字幕| 亚洲一区二区在线播放| 久久这里只精品最新地址| 久久夜色精品亚洲噜噜国产mv| 国产精品qvod| 日韩网站在线看片你懂的| 一区二区三区高清在线| 久久国产日韩| 亚洲大胆av| 一区二区三区精品久久久| 欧美揉bbbbb揉bbbbb| 亚洲一区免费网站| 欧美在线视频全部完| 国产一区二区久久久| 亚洲欧美中文日韩v在线观看| 久久久午夜视频| 亚洲一区二区三区影院| 亚洲国产一区二区三区青草影视 | 亚洲福利在线视频| 久久久精品日韩欧美| 亚洲少妇诱惑| 亚洲香蕉网站| 国产酒店精品激情| 亚洲激情不卡| 亚洲精品影院在线观看| 亚洲精品乱码久久久久久黑人 | 欧美亚洲成人网| 久久免费国产精品| 最近中文字幕mv在线一区二区三区四区| 久久综合色婷婷| 亚洲在线观看免费| 亚洲一级特黄| 亚洲日本在线观看| 久久九九免费| 欧美一区三区三区高中清蜜桃| 欧美中文日韩| 日韩视频二区| 国产亚洲欧美日韩美女| 久久久久在线观看| 亚洲精选视频免费看| 久久久久久久尹人综合网亚洲| 亚洲国产精品成人综合色在线婷婷| 欧美日韩免费看| 欧美日韩午夜在线| 欧美成人网在线| 亚洲国产高清高潮精品美女| 美脚丝袜一区二区三区在线观看| 欲香欲色天天天综合和网| 国产精品va在线播放我和闺蜜| 久久综合中文字幕| 性欧美videos另类喷潮| 亚洲国产毛片完整版| 欧美国产91| 免费在线观看精品| 久久精品综合| 欧美一区二区三区在线看| 亚洲欧美日韩天堂| 亚洲一区二区精品在线| 亚洲一区二区免费在线| 亚洲视频免费在线观看| 亚洲欧美国内爽妇网| 亚洲欧美日韩国产另类专区| 激情综合色综合久久综合| 国产精品夜色7777狼人| 国产日韩综合一区二区性色av| 欧美日韩中文字幕在线视频| 国产精品对白刺激久久久| 欧美四级剧情无删版影片| 日韩视频免费观看高清完整版| 亚洲国产影院| 欧美在线视频a| 西西人体一区二区| 久久精品一区四区| 一个色综合导航| 亚洲一级片在线观看| 欧美va天堂va视频va在线| 久久夜色精品国产欧美乱| 亚洲国产成人91精品| 一卡二卡3卡四卡高清精品视频| 午夜精品亚洲| 欧美视频一区二区三区…| 欧美电影在线观看完整版| 国产精品系列在线| 亚洲视频大全| 91久久国产自产拍夜夜嗨| 午夜精品影院在线观看| 欧美特黄一级大片| 一区二区在线免费观看| 亚洲一区二区高清视频| 亚洲国产岛国毛片在线| 91久久中文| 亚洲精品久久久久久久久久久久久 | 欧美日韩国语| 亚洲久久一区| 亚洲人体影院| 久久香蕉精品| 国产精品高清在线观看| 亚洲尤物精选| 久久国产精品电影| 狠狠色丁香婷婷综合久久片| 日韩一区二区高清| 99精品99| 伊大人香蕉综合8在线视| 欧美极品在线观看| 日韩小视频在线观看| 一区二区日韩免费看| 国产欧美另类| 亚洲电影在线看| 国产亚洲免费的视频看| 欧美高清在线视频| 欧美四级在线观看| 午夜精品久久久久久久99樱桃| 久久精品综合一区| 99国产精品久久久久久久| 午夜日韩av| 在线一区日本视频| 久久se精品一区精品二区| 一本一本久久a久久精品综合麻豆 一本一本久久a久久精品牛牛影视 | 久久久亚洲欧洲日产国码αv| 精品91在线| 亚洲欧洲日本一区二区三区| 一区二区三区久久网| 亚洲精品少妇30p| 久久久噜噜噜久久| 久久精品九九| 欧美精品一二三|