原始套接字

发布时间:2017-2-20 16:33:48 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"原始套接字",主要涉及到原始套接字方面的内容,对于原始套接字感兴趣的同学可以参考一下。

一. 摘要   Raw Socket: 原始套接字   可以用它来发送和接收 IP 层以上的原始数据包, 如 ICMP, TCP, UDP...     int sockRaw = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);   这样我们就创建了一个 Raw Socket   Sniffer: 嗅探器   关于嗅探器的原理我想大多数人可能都知道   1. 把网卡置于混杂模式;   2. 捕获数据包;   3. 分析数据包.   但具体的实现知道的人恐怕就不是那么多了. 好, 现在让我们用 Raw Socket 的做一个自已的 Sniffer. 二. 把网卡置于混杂模式   在正常的情况下,一个网络接口应该只响应两种数据帧:   一种是与自己硬件地址相匹配的数据帧   一种是发向所有机器的广播数据帧   如果要网卡接收所有通过它的数据, 而不管是不是发给它的, 那么必须把网卡置于混杂模式. 也就是说让它的思维混乱, 不按正常的方式工作. 用 Raw Socket 实现代码如下:     setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*)&flag, sizeof(flag); //设置 IP 头操作选项     bind(sockRaw, (PSOCKADDR)&addrLocal, sizeof(addrLocal); //把 sockRaw 绑定到本地网卡上     ioctlsocket(sockRaw, SIO_RCVALL, &dwValue);       //让 sockRaw 接受所有的数据   flag 标志是用来设置 IP 头操作的, 也就是说要亲自处理 IP 头: bool flag = ture;   addrLocal 为本地地址: SOCKADDR_IN addrLocal;   dwValue 为输入输出参数, 为 1 时执行, 0 时取消: DWORD dwValue = 1;   没想到这么简单吧? 三. 捕获数据包   你的 sockRaw 现在已经在工作了, 可以在局域网内其它的电脑上用 Sniffer 检测工具检测一下, 看你的网卡是否处于混杂模式(比如 DigitalBrain 的 ARPKiller).   不能让他白白的浪费资源啊, 抓包!     recv(sockRaw, RecvBuf, BUFFER_SIZE, 0); //接受任意数据包   #define BUFFER_SIZE 65535   char RecvBuf[BUFFER_SIZE];   越来越发现 Sniffer 原来如此的简单了, 这么一个函数就已经完成抓取数据包的任务了. 四. 分析数据包   这回抓来的包和平常用 Socket 接受的包可就不是一回事儿了, 里面包含 IP, TCP 等原始信息. 要分析它首先得知道这些结构.   数据包的总体结构:   ----------------------------------------------   | ip header | tcp header(or x header) | data |   ----------------------------------------------   IP header structure:        4    8    16                    32 bit   |--------|--------|----------------|--------------------------------|   | Ver  | IHL  |Type of service |     Total length     |   |--------|--------|----------------|--------------------------------|   | Identification |   Flags   |     Fragment offset    |   |--------|--------|----------------|--------------------------------|   | Time to live  |  Protocol  |     Header checksum    |   |--------|--------|----------------|--------------------------------|   |             Source address              |   |--------|--------|----------------|--------------------------------|   |            Destination address             |   |--------|--------|----------------|--------------------------------|   |            Option + Padding              |   |--------|--------|----------------|--------------------------------|   |                Data                |   |--------|--------|----------------|--------------------------------|   TCP header structure:                   16                32 bit   |--------------------------------|--------------------------------|   |     Source port      |    Destination port    |   |--------------------------------|--------------------------------|   |             Sequence number             |   |--------------------------------|--------------------------------|   |           Acknowledgement number           |   |--------------------------------|--------------------------------|   | Offset | Resrvd |U|A|P|R|S|F|      Window       |   |--------------------------------|--------------------------------|   |      Checksum       |    Urgent pointer     |   |--------------------------------|--------------------------------|   |             Option + Padding            |   |--------------------------------|--------------------------------|   |               Data                |   |--------------------------------|--------------------------------| 五. 实现 Sniffer   OK!   现在都清楚了, 还等什么.   下面是我用 BCB6 写的一个 Simple Sniffer 的代码, 仅供参考.   (需要在工程文件里加入WS2_32.LIB这个文件) //*************************************************************************// //* CPP File: WMain.cpp //* Simple Sniffer by shadowstar //* http://shadowstar.126.com/ //*************************************************************************// #include <vcl.h> #pragma hdrstop #include <winsock2.h> #include <ws2tcpip.h> #include <mstcpip.h> #include <netmon.h> #include "WMain.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TMainForm *MainForm; //--------------------------------------------------------------------------- __fastcall TMainForm::TMainForm(TComponent* Owner)   : TForm(Owner) { WSADATA WSAData;   BOOL  flag  = true;   int   nTimeout = 1000;   char  LocalName[16];   struct hostent *pHost;   //检查 Winsock 版本号   if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)     throw Exception("WSAStartup error!");   //初始化 Raw Socket   if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == INVALID_SOCKET)     throw Exception("socket setup error!");   //设置IP头操作选项   if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*)&flag, sizeof(flag)) == SOCKET_ERROR)     throw Exception("setsockopt IP_HDRINCL error!");   //获取本机名   if (gethostname((char*)LocalName, sizeof(LocalName)-1) == SOCKET_ERROR)     throw Exception("gethostname error!");   //获取本地 IP 地址   if ((pHost = gethostbyname((char*)LocalName)) == NULL)     throw Exception("gethostbyname error!");   addr_in.sin_addr  = *(in_addr *)pHost->h_addr_list[0]; //IP   addr_in.sin_family = AF_INET;   addr_in.sin_port  = htons(57274);   //把 sock 绑定到本地地址上   if (bind(sock, (PSOCKADDR)&addr_in, sizeof(addr_in)) == SOCKET_ERROR)     throw Exception("bind error!");   iSortDirection = 1; } //--------------------------------------------------------------------------- __fastcall TMainForm::~TMainForm() {   WSACleanup(); } //--------------------------------------------------------------------------- void __fastcall TMainForm::btnCtrlClick(TObject *Sender) {   TListItem *Item;   DWORD dwValue;   int nIndex = 0;   if (btnCtrl->Caption == "&Start")   {     dwValue = 1;     //设置 SOCK_RAW 为SIO_RCVALL,以便接收所有的IP包     if (ioctlsocket(sock, SIO_RCVALL, &dwValue) != 0)       throw Exception("ioctlsocket SIO_RCVALL error!");     bStop = false;     btnCtrl->Caption = "&Stop";     lsvPacket->Items->Clear();   }   else   {     dwValue = 0;     bStop = true;     btnCtrl->Caption = "&Start";     //设置SOCK_RAW为SIO_RCVALL,停止接收     if (ioctlsocket(sock, SIO_RCVALL, &dwValue) != 0)       throw Exception("WSAIoctl SIO_RCVALL error!");   }   while (!bStop)   {     if (recv(sock, RecvBuf, BUFFER_SIZE, 0) > 0)     {       nIndex++;              ip = *(IP*)RecvBuf;       tcp = *(TCP*)(RecvBuf + (ip.HdrLen & IP_HDRLEN_MASK));       Item = lsvPacket->Items->Add();       Item->Caption = nIndex;       Item->SubItems->Add(GetProtocolTxt(ip.Protocol));       Item->SubItems->Add(inet_ntoa(*(in_addr*)&ip.SrcAddr));       Item->SubItems->Add(inet_ntoa(*(in_addr*)&ip.DstAddr));       Item->SubItems->Add(tcp.SrcPort);       Item->SubItems->Add(tcp.DstPort);       Item->SubItems->Add(ntohs(ip.TotalLen));     }     Application->ProcessMessages();   }   } //--------------------------------------------------------------------------- AnsiString __fastcall TMainForm::GetProtocolTxt(int Protocol) {   switch (Protocol)   {     case IPPROTO_ICMP :      //1        /* control message protocol */       return PROTOCOL_STRING_ICMP_TXT;     case IPPROTO_TCP :      //6        /* tcp */       return PROTOCOL_STRING_TCP_TXT;     case IPPROTO_UDP :      //17       /* user datagram protocol */       return PROTOCOL_STRING_UDP_TXT;     default :       return PROTOCOL_STRING_UNKNOWN_TXT;   } } //--------------------------------------------------------------------------- //*************************************************************************// //* Header File: WMain.h for WMain.cpp class TMainForm //*************************************************************************// //--------------------------------------------------------------------------- #ifndef WMainH #define WMainH //--------------------------------------------------------------------------- #define BUFFER_SIZE 65535 #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <ComCtrls.hpp> #include <ExtCtrls.hpp> #include <winsock2.h> #include "netmon.h" //--------------------------------------------------------------------------- class TMainForm : public TForm { __published: // IDE-managed Components   TPanel *Panel1;   TButton *btnCtrl;   TListView *lsvPacket;   TLabel *Label1;   void __fastcall btnCtrlClick(TObject *Sender);   void __fastcall lsvPacketColumnClick(TObject *Sender,      TListColumn *Column);   void __fastcall lsvPacketCompare(TObject *Sender, TListItem *Item1,      TListItem *Item2, int Data, int &Compare);   void __fastcall Label1Click(TObject *Sender); private: // User declarations   AnsiString __fastcall GetProtocolTxt(int Protocol); public: // User declarations   SOCKET   sock;   SOCKADDR_IN addr_in;   IP     ip;   TCP     tcp;   PSUHDR   psdHeader;   char    RecvBuf[BUFFER_SIZE];   bool    bStop;   int iSortDirection;   int iColumnToSort;      __fastcall TMainForm(TComponent* Owner);   __fastcall ~TMainForm(); }; //--------------------------------------------------------------------------- extern PACKAGE TMainForm *MainForm; //--------------------------------------------------------------------------- #endif   偷了个懒, IP, TCP 头及一些宏定义用了 netmon.h 的头, 这个文件在 BCB6 的 include 目录下可以找得到, 其中与本程序相关内容如下: //*************************************************************************// //* Header File: netmon.h //*************************************************************************// // // IP Packet Structure // typedef struct _IP {   union   {     BYTE  Version;     BYTE  HdrLen;   };   BYTE ServiceType;   WORD TotalLen;   WORD ID;   union   {     WORD  Flags;     WORD  FragOff;   };   BYTE TimeToLive;   BYTE Protocol;   WORD HdrChksum;   DWORD  SrcAddr;   DWORD  DstAddr;   BYTE Options[0]; } IP; typedef IP * LPIP; typedef IP UNALIGNED * ULPIP; // // TCP Packet Structure // typedef struct _TCP   {   WORD SrcPort;   WORD DstPort;   DWORD SeqNum;   DWORD AckNum;   BYTE DataOff;   BYTE Flags;   WORD Window;   WORD Chksum;   WORD UrgPtr;   } TCP; typedef TCP *LPTCP; typedef TCP UNALIGNED * ULPTCP; // upper protocols #define PROTOCOL_STRING_ICMP_TXT    "ICMP" #define PROTOCOL_STRING_TCP_TXT    "TCP" #define PROTOCOL_STRING_UDP_TXT    "UDP" #define PROTOCOL_STRING_SPX_TXT    "SPX" #define PROTOCOL_STRING_NCP_TXT    "NCP" #define PROTOCOL_STRING_UNKNOW_TXT   "UNKNOW"   这个文件也有人声称没有. //*************************************************************************// //* Header File: mstcpip.h //*************************************************************************// // Copyright (c) Microsoft Corporation. All rights reserved. #if _MSC_VER > 1000 #pragma once #endif /* Argument structure for SIO_KEEPALIVE_VALS */ struct tcp_keepalive {   u_long onoff;   u_long keepalivetime;   u_long keepaliveinterval; }; // New WSAIoctl Options #define SIO_RCVALL      _WSAIOW(IOC_VENDOR,1) #define SIO_RCVALL_MCAST   _WSAIOW(IOC_VENDOR,2) #define SIO_RCVALL_IGMPMCAST _WSAIOW(IOC_VENDOR,3) #define SIO_KEEPALIVE_VALS  _WSAIOW(IOC_VENDOR,4) #define SIO_ABSORB_RTRALERT  _WSAIOW(IOC_VENDOR,5) #define SIO_UCAST_IF     _WSAIOW(IOC_VENDOR,6) #define SIO_LIMIT_BROADCASTS _WSAIOW(IOC_VENDOR,7) #define SIO_INDEX_BIND    _WSAIOW(IOC_VENDOR,8) #define SIO_INDEX_MCASTIF   _WSAIOW(IOC_VENDOR,9) #define SIO_INDEX_ADD_MCAST  _WSAIOW(IOC_VENDOR,10) #define SIO_INDEX_DEL_MCAST  _WSAIOW(IOC_VENDOR,11) // Values for use with SIO_RCVALL* options #define RCVALL_OFF       0 #define RCVALL_ON       1 #define RCVALL_SOCKETLEVELONLY 2 六. 小结   优点: 实现简单, 不需要做驱动程序就可实现抓包.   缺点: 数据包头不含帧信息, 不能接收到与 IP 同层的其它数据包, 如 ARP, RARP...   这里提供的程序仅仅是一个 Sniffer 的例子, 没有对数据包进行进一步的分析. 写此文的目的在于熟悉Raw Socket 编程方法, 了解 TCP/IP 协议结构原理以及各协议之间的关系.  

上一篇:精彩对白:好想好想谈恋爱
下一篇:读书笔记《Programming in C++》之一

相关文章

关键词: 原始套接字

相关评论