삽으로 네트웍을 파헤쳐 보자.. (그래도 보물따위는 나오지 않는다.) Study+more

근 2주간.. 네트웍인지 뭐시깽인지 때문에 맘고생 허리고생 한거 생각하면 이가 갈리지만.. 아직도 갈길이 구만리라..

4층 창문밖으로 던져버리지 못하는 내 자신을 매우 저주하며.. 글을 쓴다. 닝기리..- _-;

IPv4/v6 두개로 나뉘지만, v6는 우선 버린다. (모르니까..- _-.. )

IP v4는 'IP Header'라는 내용으로 검색하면 질릴정도로 나온다. 고로 생략... (뭣?!)

TCP는 버전이고 뭐고 없는듯.. 그림은 아래에.. (참, 패킷 `데이터`는 TCP헤더 뒤에 딸려온다)

마지막으로 Ethernet 프레임 이라는게 있다. 이놈은 비교할수 없을 정도로 간단하다.. (정말...)

앞에 Preamble은 뭔지 잘 모르겠고- _-; Type이 0x0800이면 뒤에 따라오는 Data가 IP Header타입 이라는 이야기다.
Data에는 IP Header와 TCP Header, 실제Data가 포함된다. 이는 최대 1500Byte까지 가능하다. (데이터만 이라면 최대 1500바이트보다 좀 더 작겠지?)

typedef struct _EthHdr
  {
   char        DestMAC[6];
   char        SrcMAC[6];
   USHORT      Type;                                  // 0x0800 => IP.
  }EthHdr, *PEthHdr;

typedef struct _IPHdr
  {
   union
     {
      UCHAR HdrLenVer;
      struct
        {
         UCHAR    IPHdrLen         : 4;               // Length, in 4-byte multiples.
         UCHAR    IPVer            : 4;               // IP version.
        };
     };
   UCHAR          TypeOfService;
   USHORT         TotalLength;                        // Size of IP datagram.
   USHORT         Identification;
   union
     {
      USHORT      FragmentationSummary;
      struct
        {
         USHORT   FragmentOffset1  : 5;
         USHORT   LastFragment     : 1;
         USHORT   CannotFragment   : 1;
         USHORT   padding          : 1;               // Reserved, must be zero.
         USHORT   FragmentOffset2  : 8;
        };
     };
   UCHAR          TTL;
   UCHAR          Protocol;
   USHORT         Checksum;
   ULONG          SourceAddress;
   ULONG          DestinationAddress;
  }IPHdr, *PIPHdr;

typedef struct _TCPHdr
  {
   USHORT         SrcPort;
   USHORT         DestPort;
   ULONG          SeqNbr;
   ULONG          AckNbr;
   union
     {
      UCHAR       OffsetReserved;         
      struct
        {
         UCHAR    Reserved         : 4;
         UCHAR    DataOffset       : 4;              
        };
     };
   union
     {
      UCHAR       Flags;
      struct
        {
         UCHAR    EndOfData        : 1;
         UCHAR    Synchronize      : 1;
         UCHAR    Reset            : 1;
         UCHAR    PushFunction     : 1;
         UCHAR    AckFdSignificant : 1;
         UCHAR    UrgentData       : 1;
        };
     };
   USHORT         Window;
   USHORT         Checksum;
   USHORT         UrgentPtr;
  }TCPHdr, *PTCPHdr;

한 바이트가 못되는 flag들은 비트필드(BitField)와 공용체(UNION)을 사용하여 처리하였다. (중간에 그림의 구조체와 순서가 틀린 부분을 발견할수도 있을것이다. 이는 코드를 짜고서 테스트해보니 LittleEndian때문인지, 순서가 맞지 않아서 임의로 수정한 것이다.)

시간이 별로 없으니 핵심만 말한다. 나는 현재 NDIS IM드라이버 작성중이다. (하나의 패킷 처리를 위해서 아래와 같이 진행한다)

NDIS에서 Send시에 Packet 처리할때, MDL로 헤더들이 연결되어 있기 때문에, 만약 내용을 수정하고자 한다면, 연결된 MDL들을 주욱 확인하며 수정해야 한다.

더불어 Checksum처리를 해야 하기때문에, 실제로는 하나의 버퍼를 만들어서 그 버퍼에 이더넷,IP/TCP헤더,데이터 를 모두 복사해서, 내용을 수정하고, Checksum을 다시 계산해서 박아줘야 한다.

그럼, Receive시에는 어떻게 동작하느냐? ... MDL이고 뭐고 다 필요없다. HeaderBuffer랑 LookAheadBuffer 까보면 된다. 둘다 동일한 메모리 공간을 가리키고 있다. 다만, LookAheadBuffer는 IP헤더 부터 시작하는 주소가 된다. 따라서 주소값으로 보면 HeaderBuffer가 조금 더 앞서 있을것이다. (약 14바이트 정도..?)

LookAheadBuffer를 IP/TCP헤더/데이터 로 나누고(단순히 포인터로 가리키면 OK!), 만약 어느것 하나라도 내용을 수정했다면, 역시나 Checksum을 다시 계산해서 박아줘야 한다.

....아놔. 일주일 넘게 한 삽질이 이렇게 몇줄 안되는 내용으로 축약되다니.. 뉀장- _-


덧글

  • mi 2011/08/10 13:38 # 삭제 답글

    2계층 데이타 링크계층의 Ethernet 프레임 에서 Preamble는 신호 동기화를 뜻합니다
    총 8옥텍중 7옥텟은 10101010 X 7 의 신호를 보내면서 라우터간의 신호를 동기화시키고
    마지막 1옥텟은 10101011 신호를 보내면서 프레임의 시작을 알리는 신호를 보냅니다
    참고로 Preamble는 2계층 헤더에 포함되지 않습니다
댓글 입력 영역