當前位置:首頁 » 編程語言 » 原始套接字編程c語言
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

原始套接字編程c語言

發布時間: 2022-12-23 11:45:05

A. c語言中關於socket函數的例子

函數說明:socket()用來建立一個新的socket, 也就是向系統注冊, 通知系統建立一通信埠. 參數domain 指定使用何種的地址類型, 完整的定義在/usr/include/bits/socket.h 內, 底下是常見的協議:
PF_UNIX/PF_LOCAL/AF_UNIX/AF_LOCAL UNIX 進程通信協議
PF_INET?AF_INET Ipv4 網路協議
PF_INET6/AF_INET6 Ipv6 網路協議
PF_IPX/AF_IPX IPX-Novell 協議
PF_NETLINK/AF_NETLINK 核心用戶介面裝置
PF_X25/AF_X25 ITU-T X. 25/ISO-8208 協議
PF_AX25/AF_AX25 業余無線AX. 25 協議
PF_ATMPVC/AF_ATMPVC 存取原始 ATM PVCs
PF_APPLETALK/AF_APPLETALK appletalk (DDP)協議
PF_PACKET/AF_PACKET 初級封包介面

參數 type 有下列幾種數值:
1、SOCK_STREAM 提供雙向連續且可信賴的數據流, 即TCP. 支持 OOB 機制, 在所有數據傳送前必須使用connect()來建立連線狀態.
2、SOCK_DGRAM 使用不連續不可信賴的數據包連接
3、SOCK_SEQPACKET 提供連續可信賴的數據包連接
4、SOCK_RAW 提供原始網路協議存取
5、SOCK_RDM 提供可信賴的數據包連接
6、SOCK_PACKET 提供和網路驅動程序直接通信. protocol 用來指定socket 所使用的傳輸協議編號, 通常此參考不用管它, 設為0 即可.

返回值:成功則返回socket 處理代碼, 失敗返回-1.

錯誤代碼:
1、EPROTONOSUPPORT 參數domain 指定的類型不支持參數type 或protocol 指定的協議
2、ENFILE 核心內存不足, 無法建立新的socket 結構
3、EMFILE 進程文件表溢出, 無法再建立新的socket
4、EACCESS 許可權不足, 無法建立type 或protocol 指定的協議
5、ENOBUFS/ENOMEM 內存不足
6、EINVAL 參數domain/type/protocol 不合法

B. C語言random函數

s_addr是一個long型的變數,當然可以用random的返回值進行賦值。結構體如下:
typedef struct in_addr {
union {
struct {
u_char s_b1,s_b2,s_b3,s_b4;
} S_un_b;
struct {
u_short s_w1,s_w2;
} S_un_w;
u_long S_addr;////////////////////////////////////////這里
} S_un;
} in_addr;

IP地址本來就是一個32位整數,只不過為了方便記憶和查看,將8位作為一組,每組用10進制數字表示,並且用'.'隔開。比如:0.0.0.3,對應的32位二進制數為:0000000000.....111(前面有29個0),s_addr就是記錄這個二進制數的。

struct {u_char s_b1,s_b2,s_b3,s_b4;} S_un_b;
這個是用4個10進制數表示的IP地址,
s_un_b.s_b1=0
s_un_b.s_b2=0
s_un_b.s_b3=0
s_un_b.s_b4=3
就是IP地址"0.0.0.3"了,系統負責將它轉換為32位二進制數。

struct {u_short s_w1,s_w2;} S_un_w;
這個是指前16位作為一部分,後面16位作為一個部分。".0.0.0.3"前面16位作為一個部分值為0,後面的部分值為3,所以:
s_un_w.s_w1=0;
s_un_w.s_w2=3;

C. 進程間通信(IPC)——Unix域套接字 VS 網路套接字

進程間通信就是不同進程間進行數據交換的過程。因為進程間相互獨立,每個進程擁有獨立的地址空間、數據處理邏輯,操作系統保證了進程獨立運行的地址安全;但在復雜系統,單進程往往不能勝任業務需求,需要多進程的加入,多進程協作完成工作,這就離不開進程間通信這個話題了。

進程間通信有很多種方式,列舉如下:

而進程間通信按進程分布情況可以 單機內的進程間通信 多機間遠程調用的進程間通信 ,後者無需多講,在分布式等大型系統中是非常常見的,而進行通信的方式主要是上述方法中的網路IPC,有非常多的資料介紹相關內容,不在本文的討論范圍之內。

本文主要討論在 單機內進程間通信 中,Unix域套接字和TCP網路套接字的對比,後者屬於網路IPC。

套接字是一種應用程序介面,包括了一個用C語言寫成的應用程序開發庫,主要用於實現進程間通訊,在計算機網路通訊方面被廣泛使用。下面要討論的網路套接字和Unix套接字均屬於套接字。

在定義套接字類型的時候,網路套接字通常使用 AF_INET 進行定義;Unix域套接字則使用 AF_UNIX 進行定義。

套接字類型有三種,分別是流式套接字、數據報套接字和原始套接字。

流式套接字(SOCK_STREAM):流式套接字用於提供面向連接、可靠的數據傳輸服務。該服務將保證數據能夠實現無差錯、無重復發送,並按順序接收。流式套接字之所以能夠實現可靠的數據服務,原因在於其使用了傳輸控制協議,即TCP(The Transmission Control Protocol)協議。

數據報套接字(SOCK_DGRAM):數據報套接字提供了一種無連接的服務。該服務並不能保證數據傳輸的可靠性,數據有可能在傳輸過程中丟失或出現數據重復,且無法保證順序地接收到數據。數據報套接字使用UDP(User Datagram Protocol)協議進行數據的傳輸。由於數據報套接字不能保證數據傳輸的可靠性,對於有可能出現的數據丟失情況,需要在程序中做相應的處理。

原始套接字(SOCK_RAW):原始套接字(SOCKET_RAW)允許對較低層次的協議直接訪問,比如IP、 ICMP協議,它常用於檢驗新的協議實現,或者訪問現有服務中配置的新設備,因為RAW SOCKET可以自如地控制Windows下的多種協議,能夠對網路底層的傳輸機制進行控制,所以可以應用原始套接字來操縱網路層和傳輸層應用。比如,我們可以通過RAW SOCKET來接收發向本機的ICMP、IGMP協議包,或者接收TCP/IP棧不能夠處理的IP包,也可以用來發送一些自定包頭或自定協議的IP包。網路監聽技術很大程度上依賴於SOCKET_RAW。

原始套接字與標准套接字(標准套接字指的是前面介紹的流式套接字和數據報套接字)的區別在於:原始套接字可以讀寫內核沒有處理的IP數據包,而流式套接字只能讀取TCP協議的數據,數據報套接字只能讀取UDP協議的數據。因此,如果要訪問其他協議發送數據必須使用原始套接字。

網路通信中通常都是使用網路套接字進行通信,可用於單機進程間通信和多機進程間通信,網路套接字由五元組來標識:(源地址、源埠、目標地址、目標埠、通信協議),因而網路套接字在網路協議棧中屬於傳輸層之上的內容。所以,在使用網路套接字通信的時候,傳遞內容需要經過完整的網路協議棧四層模型中的(傳輸層-網路層-網路訪問層(數據鏈路層-物理層))。

回想在協議棧當中,對於報文的處理有哪些操作。

Unix域套接字只能用於在同一個計算機的進程間進行通信。雖然網路套接字也可以用於單機進程間的通信,但是使用Unix域套接字效率會更高,因為Unix域套接字僅僅進行數據復制,不會執行在網路協議棧中需要處理的添加、刪除報文頭、計算校驗和、計算報文順序等復雜操作,因而在單機的進程間通信中,更加推薦使用Unix域套接字。

關於套接字的使用,資料很多,不再介紹。

這里拿網路套接字和Unix域套接字出來比較的原因是,很多人在進行單機多進程開發時沒有注意到Unix域套接字的存在,而是使用了成本較高的網路套接字進行開發。Unix套接字在通信開銷方面是很小的,因而在單機通信中更加推薦使用Unix域套接字。

原文鏈接

D. 怎樣用C語言實現網路抓包

  1. 第一法則:站在巨人肩膀上 && 不要重復造輪子。

    對於這種復雜的過程,第一選擇是使用現成的,節約時間,提升效率。

    Wireshark(前稱Ethereal)是一個網路封包分析軟體。網路封包分析軟體的功能是擷取網路封包,並盡可能顯示出最為詳細的網路封包資料。Wireshark使用WinPCAP作為介面,直接與網卡進行數據報文交換。
    網路封包分析軟體的功能可想像成 "電工技師使用電表來量測電流、電壓、電阻" 的工作 - 只是將場景移植到網路上,並將電線替換成網路線。在過去,網路封包分析軟體是非常昂貴,或是專門屬於營利用的軟體。Ethereal的出現改變了這一切。在GNUGPL通用許可證的保障范圍底下,使用者可以以免費的代價取得軟體與其源代碼,並擁有針對其源代碼修改及客制化的權利。Ethereal是目前全世界最廣泛的網路封包分析軟體之一。

  2. 第二法則:學習 && 提升。

    如果是單純的學習知識,可以直接嘗試寫一些具有部分功能的程序,過程會有點艱難,但非常有意義。學習網路編程,需要了解 開放系統互連參考模型的的七層每一層的意義以及現實當中實現的四層的網路協議。然後就可以知道抓包的包位於模型當中的傳輸層協議,包括UDP和TCP的協議。進一步要學習每種協議的格式,表頭,數據包等等。一句話,冰凍三尺非一日之寒。

  3. Windows下的抓包及簡單的編程。

    Windows2000在TCP/IP協議組件上做了很多改進,功能也有增強。比如在協議棧上的調整,增大了默認窗口大小,以及高延遲鏈接新演算法。同時在安全性上,可應用IPSec加強安全性,比NT下有不少的改進。
    Microsoft TCP/IP 組件包含「核心協議」、「服務」及兩者之間的「介面」。傳輸驅動程序介面 (TDI) 與網路設備介面規范 (NDIS) 是公用的。 此外,還有許多用戶模型應用程序的更高級介面。最常用的介面是 Windows Sockets、遠程過程調用 (RPC) 和 NetBIOS。
    Windows Sockets 是一個編程介面,它是在加州大學伯克利分校開發的套接字介面的基礎上定義的。它包括了一組擴展件,以充分利用 Microsoft Windows 消息驅動的特點。規范的 1.1 版是在 1993 年 1 月發行的,2.2.0 版在 1996 年 5 月發行。Windows 2000 支持 Winsock 2.2 版。在Winsock2中,支持多個傳輸協議的原始套接字,重疊I/O模型、服務質量控制等。
    這里介紹Windows Sockets的一些關於原始套接字(Raw Socket)的編程。同Winsock1相比,最明顯的就是支持了Raw Socket套接字類型,通過原始套接字,我們可以更加自如地控制Windows下的多種協議,而且能夠對網路底層的傳輸機制進行控制。
    1、創建一個原始套接字,並設置IP頭選項。

    SOCKET sock;
    sock = socket(AF_INET,SOCK_RAW,IPPROTO_IP);
    或者:
    s = WSASoccket(AF_INET,SOCK_RAW,IPPROTO_IP,NULL,0,WSA_FLAG_OVERLAPPED);
    這里,我們設置了SOCK_RAW標志,表示我們聲明的是一個原始套接字類型。創建原始套接字後,IP頭就會包含在接收的數據中,如果我們設定 IP_HDRINCL 選項,那麼,就需要自己來構造IP頭。注意,如果設置IP_HDRINCL 選項,那麼必須具有 administrator許可權,要不就必須修改注冊表:
    HKEY_LOCAL_
    修改鍵:DisableRawSecurity(類型為DWORD),把值修改為 1。如果沒有,就添加。
    BOOL blnFlag=TRUE;
    setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&blnFlag, sizeof(blnFlag);
    對於原始套接字在接收數據報的時候,要注意這么幾點:
    a、如果接收的數據報中協議類型和定義的原始套接字匹配,那麼,接收的所有數據就拷貝到套接字中。
    b、如果綁定了本地地址,那麼只有接收數據IP頭中對應的遠端地址匹配,接收的數據就拷貝到套接字中。
    c、如果定義的是外部地址,比如使用connect(),那麼,只有接收數據IP頭中對應的源地址匹配,接收的數據就拷貝到套接字中。


    2、構造IP頭和TCP頭
    這里,提供IP頭和TCP頭的結構:
    // Standard TCP flags
    #define URG 0x20
    #define ACK 0x10
    #define PSH 0x08
    #define RST 0x04
    #define SYN 0x02
    #define FIN 0x01
    typedef struct _iphdr //定義IP首部
    {
    unsigned char h_lenver; //4位首部長度+4位IP版本號
    unsigned char tos; //8位服務類型TOS
    unsigned short total_len; //16位總長度(位元組)
    unsigned short ident; //16位標識
    unsigned short frag_and_flags; //3位標志位
    unsigned char ttl; //8位生存時間 TTL
    unsigned char proto; //8位協議 (TCP, UDP 或其他)
    unsigned short checksum; //16位IP首部校驗和
    unsigned int sourceIP; //32位源IP地址
    unsigned int destIP; //32位目的IP地址
    }IP_HEADER;

    typedef struct psd_hdr //定義TCP偽首部
    {
    unsigned long saddr; //源地址
    unsigned long daddr; //目的地址
    char mbz;
    char ptcl; //協議類型
    unsigned short tcpl; //TCP長度
    }PSD_HEADER;

    typedef struct _tcphdr //定義TCP首部
    {
    USHORT th_sport; //16位源埠
    USHORT th_dport; //16位目的埠
    unsigned int th_seq; //32位序列號
    unsigned int th_ack; //32位確認號
    unsigned char th_lenres; //4位首部長度/6位保留字
    unsigned char th_flag; //6位標志位
    USHORT th_win; //16位窗口大小
    USHORT th_sum; //16位校驗和
    USHORT th_urp; //16位緊急數據偏移量
    }TCP_HEADER;

    TCP偽首部並不是真正存在的,只是用於計算檢驗和。校驗和函數:

    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頭部的時候,就同時需要自己計算他們的檢驗和。

    3、發送原始套接字數據報

    填充這些頭部稍微麻煩點,發送就相對簡單多了。只需要使用sendto()就OK。

    sendto(sock, (char*)&tcpHeader, sizeof(tcpHeader), 0, (sockaddr*)&addr_in,sizeof(addr_in));

    下面是一個示常式序,可以作為SYN掃描的一部分。

    #include <stdio.h>
    #include <winsock2.h>
    #include <ws2tcpip.h>

    #define SOURCE_PORT 7234
    #define MAX_RECEIVEBYTE 255

    typedef struct ip_hdr //定義IP首部
    {
    unsigned char h_verlen; //4位首部長度,4位IP版本號
    unsigned char tos; //8位服務類型TOS
    unsigned short total_len; //16位總長度(位元組)
    unsigned short ident; //16位標識
    unsigned short frag_and_flags; //3位標志位
    unsigned char ttl; //8位生存時間 TTL
    unsigned char proto; //8位協議 (TCP, UDP 或其他)
    unsigned short checksum; //16位IP首部校驗和
    unsigned int sourceIP; //32位源IP地址
    unsigned int destIP; //32位目的IP地址
    }IPHEADER;

    typedef struct tsd_hdr //定義TCP偽首部
    {
    unsigned long saddr; //源地址
    unsigned long daddr; //目的地址
    char mbz;
    char ptcl; //協議類型
    unsigned short tcpl; //TCP長度
    }PSDHEADER;

    typedef struct tcp_hdr //定義TCP首部
    {
    USHORT th_sport; //16位源埠
    USHORT th_dport; //16位目的埠
    unsigned int th_seq; //32位序列號
    unsigned int th_ack; //32位確認號
    unsigned char th_lenres; //4位首部長度/6位保留字
    unsigned char th_flag; //6位標志位
    USHORT th_win; //16位窗口大小
    USHORT th_sum; //16位校驗和
    USHORT th_urp; //16位緊急數據偏移量
    }TCPHEADER;

    //CheckSum:計算校驗和的子函數
    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);
    }

    void useage()
    {
    printf("****************************************** ");
    printf("TCPPing ");
    printf(" Written by Refdom ");
    printf(" Email: [email protected] ");
    printf("Useage: TCPPing.exe Target_ip Target_port ");
    printf("******************************************* ");
    }

    int main(int argc, char* argv[])
    {
    WSADATA WSAData;
    SOCKET sock;
    SOCKADDR_IN addr_in;
    IPHEADER ipHeader;
    TCPHEADER tcpHeader;
    PSDHEADER psdHeader;

    char szSendBuf[60]={0};
    BOOL flag;
    int rect,nTimeOver;

    useage();

    if (argc!= 3)
    { return false; }

    if (WSAStartup(MAKEWORD(2,2), &WSAData)!=0)
    {
    printf("WSAStartup Error! ");
    return false;
    }

    if ((sock=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0,WSA_FLAG_OVERLAPPED))==INVALID_SOCKET)
    {
    printf("Socket Setup Error! ");
    return false;
    }
    flag=true;
    if (setsockopt(sock,IPPROTO_IP, IP_HDRINCL,(char *)&flag,sizeof(flag))==SOCKET_ERROR)
    {
    printf("setsockopt IP_HDRINCL error! ");
    return false;
    }

    nTimeOver=1000;
    if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTimeOver, sizeof(nTimeOver))==SOCKET_ERROR)
    {
    printf("setsockopt SO_SNDTIMEO error! ");
    return false;
    }
    addr_in.sin_family=AF_INET;
    addr_in.sin_port=htons(atoi(argv[2]));
    addr_in.sin_addr.S_un.S_addr=inet_addr(argv[1]);

    //
    //
    //填充IP首部
    ipHeader.h_verlen=(4<<4 | sizeof(ipHeader)/sizeof(unsigned long));
    // ipHeader.tos=0;
    ipHeader.total_len=htons(sizeof(ipHeader)+sizeof(tcpHeader));
    ipHeader.ident=1;
    ipHeader.frag_and_flags=0;
    ipHeader.ttl=128;
    ipHeader.proto=IPPROTO_TCP;
    ipHeader.checksum=0;
    ipHeader.sourceIP=inet_addr("本地地址");
    ipHeader.destIP=inet_addr(argv[1]);

    //填充TCP首部
    tcpHeader.th_dport=htons(atoi(argv[2]));
    tcpHeader.th_sport=htons(SOURCE_PORT); //源埠號
    tcpHeader.th_seq=htonl(0x12345678);
    tcpHeader.th_ack=0;
    tcpHeader.th_lenres=(sizeof(tcpHeader)/4<<4|0);
    tcpHeader.th_flag=2; //修改這里來實現不同的標志位探測,2是SYN,1是FIN,16是ACK探測 等等
    tcpHeader.th_win=htons(512);
    tcpHeader.th_urp=0;
    tcpHeader.th_sum=0;

    psdHeader.saddr=ipHeader.sourceIP;
    psdHeader.daddr=ipHeader.destIP;
    psdHeader.mbz=0;
    psdHeader.ptcl=IPPROTO_TCP;
    psdHeader.tcpl=htons(sizeof(tcpHeader));

    //計算校驗和
    memcpy(szSendBuf, &psdHeader, sizeof(psdHeader));
    memcpy(szSendBuf+sizeof(psdHeader), &tcpHeader, sizeof(tcpHeader));
    tcpHeader.th_sum=checksum((USHORT *)szSendBuf,sizeof(psdHeader)+sizeof(tcpHeader));

    memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));
    memcpy(szSendBuf+sizeof(ipHeader), &tcpHeader, sizeof(tcpHeader));
    memset(szSendBuf+sizeof(ipHeader)+sizeof(tcpHeader), 0, 4);
    ipHeader.checksum=checksum((USHORT *)szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader));

    memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));

    rect=sendto(sock, szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader),
    0, (struct sockaddr*)&addr_in, sizeof(addr_in));
    if (rect==SOCKET_ERROR)
    {
    printf("send error!:%d ",WSAGetLastError());
    return false;
    }
    else
    printf("send ok! ");

    closesocket(sock);
    WSACleanup();

    return 0;
    }

    4、接收數據
    和發送原始套接字數據相比,接收就比較麻煩了。因為在WIN我們不能用recv()來接收raw socket上的數據,這是因為,所有的IP包都是先遞交給系統核心,然後再傳輸到用戶程序,當發送一個raws socket包的時候(比如syn),核心並不知道,也沒有這個數據被發送或者連接建立的記錄,因此,當遠端主機回應的時候,系統核心就把這些包都全部丟掉,從而到不了應用程序上。所以,就不能簡單地使用接收函數來接收這些數據報。

    要達到接收數據的目的,就必須採用嗅探,接收所有通過的數據包,然後進行篩選,留下符合我們需要的。可以再定義一個原始套接字,用來完成接收數據的任務,需要設置SIO_RCVALL,表示接收所有的數據。

    SOCKET sniffersock;
    sniffsock = WSASocket(AF_INET, SOCK_RAW, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);

    DWORD lpvBuffer = 1;
    DWORD lpcbBytesReturned = 0 ;
    WSAIoctl(sniffersock, SIO_RCVALL, &lpvBuffer, sizeof(lpvBuffer), NULL, 0, & lpcbBytesReturned, NULL, NULL);

    創建一個用於接收數據的原始套接字,我們可以用接收函數來接收數據包了。然後在使用一個過濾函數達到篩選的目的,接收我們需要的數據包。

    如果在XP以上的操作系統,微軟封殺了Raw Soccket,只能用wincpap之類的開發包了。

E. 允許該應用創建網路套接字是什麼意思

應用許可權
1. 完全的網路訪問許可權
允許該應用創建網路套接字和使用自定義網路協議。瀏覽器和其他某些應用提供了向互聯網發送數據的途徑,因此應用無需該許可權即可向互聯網發送數據

2. 查看網路狀態
允許應用程序查看所有網路的狀態。例如存在和連接的網路

3. 查看WLAN狀態
允許程序訪問WLAN網路狀態信息

4. 讀取手機狀態和身份
允許應用訪問設備的電話功能。此許可權可讓應用確定本機號碼和設備ID、是否正處於通話狀態以及撥打的號碼

5. 寫入和讀取外部儲存
允許程序寫入和讀取您的外置儲存器許可權,例如:SD卡上讀取與存儲游戲數據

6. 後台運行
允許程序在手機屏幕關閉後後台進程仍然運行

7. 安裝其他應用
允許安裝未知來源的適配許可權

8. 讀取系統日誌文件
允許程序讀取底層系統日誌文件

9.控制震動
允許應用控制振動設備

10. 拍攝照片和視頻
允許訪問攝像頭進行拍照或錄制視頻

11. 錄音
允許該應用使用麥克風錄制音頻

12. 訪問精確位置(基於GPS和網路)
允許應用根據GPS或網路來源(例如基站和WLN網路)獲取您的位置信息。您的手機必須支持並開啟這些位置信息服務,應用才能使用這些服務,這可能會增加耗電量

13. 訪問大致位置信息(基於網路進行定位)
允許應用根據網路來源(例如基站和 WLAN 網路)獲取您的位置信息。您的手機必須支持並開啟這些位置信息服務,此應用才能使用這些服務

F. Windows系統下能否通過原始套接字發送接受Arp數據包,如何操作(最好給個例子)

雖然Windows XP SP2已經不再支持原始TCP數據包的發送,但就其本身作為一項技術而言,掌握原始數據包的發送也是非常重要的。今天我們要討論的原始UDP數據包的構造,便是這項技術的應用。相信懂得了如何管理UDP頭,其他協議的封裝應該就不成問題了。在閱讀本文,你需要具備以下知識:熟悉C語言、Socket基礎知識和TCP/IP基礎知識。如果你已經掌握了上面的知識,那就讓我們行動吧。
數據包格式
在對數據包進行封裝之前,我們有必要了解一下數據報格式,圖1是IP頭格式。我們所學的知識絕大部分都是從資料書籍中來的,但資料畢竟是死的,當我們拿到圖 1所表示的格式時,似乎有點蒙——這個格式是什麼意思啊?怎麼看?我記得我初學的時候就老犯這種糊塗。下面具體說明一下。
javascript:dcs.images.doResizes(this,0,null);" src="/kf/UploadFiles_7205/201009/20100923105017273.jpg">
圖1

在認識該格式之前,我們有必要了解一下什麼是「大尾」,什麼是「小尾」。「大尾」就是高位位元組排放在內存的低端,低位位元組排放在內存的高端。「小尾」反之。 Intel處理器大多數使用小尾位元組序,Motorola處理器大多數使用大尾(Big Endian)位元組序。既然不同的處理器處理的方式不一樣,那麼在網路交流數據的時候便應該使用同一套標准,不然肯定會發生錯誤的。TCP/IP各層協議將位元組序定義為大尾,因此TCP/IP協議中使用的位元組序通常稱之為網路位元組序,因而在填充數據包的時候一定要注意位元組順序,不然會出錯!還有,圖1的數據是從左至右位元組由低向高,這一點注意一下,初學者容易犯錯。
上面是一些需要注意的地方,下面再說一下各個欄位的含義。

1)版本號:標志版本;
2)分組長度(HLEN):報文頭部的字數(字長=32bits);
3)業務類型(Type of Service):分組的處理方式;
4)總長度(Total Length):分組頭部和數據的總長度(位元組數);
5)標識(Identification)、標記(Flags)、片偏移(Frag Offset):對分組進行分片,以便允許網上不同MTU時能進行傳送;
6)生存時間(TTL):規定分組在網上傳送的最長時間(秒),防止分組無休止地要求網路搜尋不存在的目的地址;
7)協議(Protocol):發送分組的上層協議號(TCP= 6,UDP=17);
8)校驗和(Header Checksum):分組頭校驗和;
9)源和目的IP地址(Source and Destination IP Address):標識網路終端設備的IP地址;
10)IP選項(IP Options):網路測試、調試、保密及其他;
11)數據(Data):上層協議數據。
根據上面的說明我們可以定義以下IP頭結構。

typedef struct _IPHeader // 20位元組的IP頭
{
UCHAR iphVerLen; // 版本號和頭長度(各佔4位)
UCHAR ipTOS; // 服務類型
USHORTipLength; // 封包總長度,即整個IP報的長度
USHORTipID; // 封包標識,惟一標識發送的每一個數據報
USHORTipFlags; // 標志
UCHAR ipTTL; // 生存時間,就是TTL
UCHAR ipProtocol // 協議,可能是TCP、UDP、ICMP等
USHORTipChecksum; // 校驗和
ULONG ipSource; // 源IP地址
ULONG ipDestination; // 目的IP地址
} IPHeader, *PIPHeader;

有了IP頭,下面就應該是UDP頭了,如圖2所示。下面說一下各個欄位的含義。
javascript:dcs.images.doResizes(this,0,null); border=0>
圖2

1)源埠(Source Port):呼叫端埠號;
2)目的埠(Destination Port):被叫端埠號;
3)報頭長度(HLEN):報文頭部的位元組數;
4)校驗和(Checksum):報頭和數據欄位的校驗和;
5)數據(Data):上層協議數據。

下面是定義的UDP頭結構。
typedef struct _UDPHeader
{
USHORT sourcePort; // 源埠號
USHORT destinationPort;// 目的埠號
USHORT len; // 封包長度
USHORT checksum; // 校驗和
} UDPHeader, *PUDPHeader;

上面我詳細介紹了IP頭和UDP頭的格式。在我們填充數據包的時候,應該清楚IP頭、UDP頭和傳輸數據的順序應該與如圖3一致。

圖3

編程 實現
下面我們來看看發送原始UDP封包的代碼是如何實現的。首先我們要有一個IP校驗碼,這有前人寫好的專門代碼,我們不必深究,拿來用就行,再此不貼出來,大家看雜志相關即可。下面是主程序的代碼,很簡單,大家慢慢體會,相信會有所收獲的。

int main()
{// 輸入參數信息
char szDestIp[] = "88.88.88.88";
// <<== 填寫目的IP地址
char szSourceIp[] = "127.0.0.1";
// <<== 填寫你自己的IP地址

USHORT nDestPort = 4567; //目的埠
USHORT nSourcePort = 8888;//源埠
char szMsg[] = "大家好,我是Hokkien!/r/n";
int nMsgLen = strlen(szMsg);

// 創建原始套節字
SOCKET sRaw = ::socket(AF_INET, SOCK_RAW, IPPROTO_UDP);

// 有效IP頭包含選項
BOOL bIncl = TRUE;
::setsockopt(sRaw, IPPROTO_IP, IP_HDRINCL, (char *)&bIncl, sizeof(bIncl));
char buff[1024] = { 0 };
// 填充IP頭
IPHeader *pIphdr = (IPHeader *)buff;
pIphdr->iphVerLen = (4<<4 | (sizeof(IPHeader)/sizeof(ULONG)));
//版本與長度
pIphdr->ipLength = ::htons(sizeof(IPHeader) + sizeof(UDPHeader) + nMsgLen);
//數據包長度
pIphdr->ipTTL = 128; //生存時間
pIphdr->ipProtocol = IPPROTO_UDP;//UDP
pIphdr->ipSource = ::inet_addr(szSourceIp); //源IP
pIphdr->ipDestination = ::inet_addr(szDestIp); //目的IP
pIphdr->ipChecksum = checksum((USHORT*)pIphdr, sizeof(IPHeader));
//校驗碼,這是必需的!
// 填充UDP頭
UDPHeader *pUdphdr = (UDPHeader *)&buff[sizeof(IPHeader)];
pUdphdr->sourcePort = htons(8888); //源埠
pUdphdr->destinationPort = htons(nDestPort);//目的埠
pUdphdr->len = htons(sizeof(UDPHeader) + nMsgLen);//報頭長度
pUdphdr->checksum = 0; //校驗和,不是必需的

char *pData = &buff[sizeof(IPHeader) + sizeof(UDPHeader)];
memcpy(pData, szMsg, nMsgLen);
//填充校驗和
(pIphdr, pUdphdr, pData, nMsgLen);
// 設置目的地址
SOCKADDR_IN destAddr = { 0 };
destAddr.sin_family = AF_INET;
destAddr.sin_port = htons(nDestPort);
destAddr.sin_addr.S_un.S_addr = ::inet_addr(szDestIp);
// 發送原始UDP封包
int nRet;
for(int i=0; i<5; i++)
{
nRet = ::sendto(sRaw, buff,
sizeof(IPHeader) + sizeof(UDPHeader) + nMsgLen, 0, (sockaddr*)&destAddr, sizeof(destAddr));
if(nRet == SOCKET_ERROR)
{
printf(" sendto() failed: %d /n", ::WSAGetLastError());
break;
}
else
{
printf(" sent %d bytes /n", nRet);
}
}

::closesocket(sRaw);

getchar();
return 0;
}

總結
需要注意的是,如果這段代碼在Windows XP SP2以前的操作系統上運行,可以使用假的源IP地址。但遺憾的是,Windows XP SP2中,則必須指定一個有效的IP地址,而且不是回環IP(即127.0.0.1)。Windows現在已經不支持原始TCP的發送了。這些種種限制,使得我們在XP上玩黑玩得很不自在!為了取消這種限制,我們可以開發自己的驅動,但開發驅動畢竟不是簡單之事,我等菜鳥哪來這等本事啊。不過可喜的是,已經有高人為我們開發了一套當今非常流行的網路開發包驅動Winpcap,完全可以取消上面的限制!對於這種方法,我們以後再討論,大家期待一下,呵呵

G. socket是什麼呀

套接字(Socket),就是對網路中不同主機上的應用進程之間進行雙向通信的端點的抽象。

一個套接字就是網路上進程通信的一端,提供了應用層進程利用網路協議交換數據的機制。從所處的地位來講,套接字上聯應用進程,下聯網路協議棧,是應用程序通過網路協議進行通信的介面,是應用程序與網路協議根進行交互的介面。

套接字是通信的基石,是支持TCP/IP協議的路通信的基本操作單元。

可以將套接字看作不同主機間的進程進行雙間通信的端點,它構成了單個主機內及整個網路間的編程界面。套接字存在於通信域中,通信域是為了處理一般的線程通過套接字通信而引進的一種抽象概念。

套接字通常和同一個域中的套接字交換數據(數據交換也可能穿越域的界限,但這時一定要執行某種解釋程序),各種進程使用這個相同的域互相之間用Internet協議簇來進行通信。

Socket(套接字)可以看成是兩個網路應用程序進行通信時,各自通信連接中的端點,這是一個邏輯上的概念。它是網路環境中進程間通信的API(應用程序編程介面),也是可以被命名和定址的通信端點,使用中的每一個套接字都有其類型和一個與之相連進程。

通信時其中一個網路應用程序將要傳輸的一段信息寫入它所在主機的 Socket中,該 Socket通過與網路介面卡(NIC)相連的傳輸介質將這段信息送到另外一台主機的 Socket中,使對方能夠接收到這段信息。

Socket是由IP地址和埠結合的,提供向應用層進程傳送數據包的機制。

類型

1、數據報套接字

無連接套接字,使用用戶數據報協議(UDP)。在數據報套接字上發送或接收的每個數據包都單獨定址和路由。數據報套接字不能保證順序和可靠性,因此從一台機器或進程發送到另一台機器或進程的多個數據包可能以任何順序到達或可能根本不到達。在數據報套接字上發送廣播可能需要特殊配置。

為了接收廣播數據包,數據報套接字不應該綁定到特定地址,盡管在某些實現中,當數據報套接字綁定到特定地址時也可能接收廣播數據包。

2、流套接字

面向連接的套接字,使用傳輸控制協議(TCP)、流控制傳輸協議(SCTP) 或數據報擁塞控制協議(DCCP)。流套接字提供了無記錄邊界的有序且獨特的無錯誤數據流,並具有用於創建和銷毀連接以及報告錯誤的明確定義的機制。

流套接字以帶外功能可靠地、有序地傳輸數據。在 Internet 上,流套接字通常使用 TCP 實現,以便應用程序可以使用 TCP/IP 協議在任何網路上運行。

3、原始套接字

允許直接發送和接收 IP 數據包,無需任何特定於協議的傳輸層格式。對於其他類型的套接字,根據選擇的傳輸層協議(例如 TCP、UDP)自動封裝有效載荷,並且套接字用戶不知道與有效載荷一起廣播的協議頭的存在。從原始套接字讀取時,通常包含標頭。

從原始套接字傳輸數據包時,自動添加標頭是可選的。

大多數套接字應用程序編程介面(API),例如基於Berkeley 套接字的那些,支持原始套接字。Windows XP於 2001 年發布,在Winsock介面中實現了原始套接字支持,但三年後,微軟出於安全考慮限制了 Winsock 的原始套接字支持。

原始套接字用於與安全相關的應用程序,如Nmap。原始套接字的一個用例是在用戶空間中實現新的傳輸層協議。

原始套接字通常在網路設備中可用,用於路由協議,例如Internet 組管理協議(IGMP) 和開放最短路徑優先(OSPF),以及用於Internet 控制消息協議(ICMP) 等事情,由ping 實用程序。

以上內容參考網路-套接字

H. jolt2.c程序輸入什麼可以運行

這個, 應該是一個IP碎片攻擊的linux c源碼.
struct pkt是要發送的攻擊包:
IP報頭+ICMP包或UDP包+數據
當不指定埠的時候用ICMP包攻擊。
icmplen,udplen,iplen,分別是各種報頭的長度, spf_sck是攻擊使用的socket,它在main函數里被初始化為RAW類型的原始套接字,IP報頭也在待定義之列。
useage函數列印出程序如何使用的信息。
host_to_ip函數把主機名轉換為ip地址
quit函數退出程序
do_frags函數進行碎片攻擊,
參數是一個套接字,源地址,目的地址及埠號。
這個程序可以偽造攻擊的源地址(但是程序里卻沒有把偽造地址賦值給src_addr)
ip報頭關鍵的部分在於把pkt.ip.frag_off設置為8190, 所以 整個包的長度是8190*8+29=65549, 超過65535了,被攻擊的主機在重組ip碎片的時候,buffer就會溢出。為什麼有ip碎片? 因為鏈路層有個叫MTU的包大小限制,不知道的話可以查相關資料。
udp報頭的設置部分把目的埠設置為用戶輸入埠和1235的按位或運算的值。包的數據就一個字元a
icmp報頭的設置部分把包的類型設定為icmp echo request.

I. 了解物聯網知識需要學習哪些知識

課程名稱

使用教材

備注

物聯網產業與技術導論

《物聯網:技術、應用、標准與商業模式》,電子工業出版社,等教材。

在學完高等數學,物理,化學,通信原理,數字電路,計算機原理,程序設計原理等課程後開設本課程,全面了解物聯網之RFID、M2M、感測網、兩化融合等技術與應用。

C語言程序設計

《C語言程序設計》,清華大學出版社,等教材。

物聯網涉及底層編程,C語言為必修課,同時需要了解OSGi,OPC,Silverlight等技術標准

Java程序設計

《Java語言程序設計教程》,機械工業出版社,等教材。

物聯網應用層,伺服器端集成技術,開放Java技術也是必修課,同時需要了解Eclipse,SWT, Flash, HTML5,SaaS等技術

無線感測網路概論

《無線感測器網路理論、技術與實現》,國防工業出版社,《短距離無線通訊入門與實戰》北京航空航天大學出版社,等教材。

學習各種無線RF通訊技術與標准,Zigbee, 藍牙,WiFi,GPRS,CDMA,3G, 4G, 5G,Mote等等

TCP/IP網路與協議

《TCP/IP網路與協議》,清華大學出版社,等教材。

TCP/IP以及OSI網路分層協議標準是所有有線和無線網路協議的基礎,Socket編程技術也是基礎技能,為必修課

嵌入式系統
《嵌入式系統技術教程》,人民郵電出版社等教材。

嵌入式系統是物聯網感知層和通訊層重要技術,了解TinyOS等,為必修課

感測器技術概論

《感測器技術》,中國計量出版社,等教材。

物聯網專業學生需要對感測器技術與發展,尤其是在應用中如何選用有所了解,但不一定需要了解感測器的設計與生產,對相關的材料科學,生物技術等有深入了解

RFID技術概論

《射頻識別(RFID)技術原理與應用》,機械工業出版社,等教材。

RFID作為物聯網主要技術之一,需要了解,它本身(與智能卡技術融合)可以是一個細分專業或行業,也可以是研究生專業選題方向。

工業信息化及現場匯流排技術

《現場匯流排技術及應用教程》,機械工業出版社,等教材。

工業信息化也是物聯網主要應用領域,需要了解,它本身也可以是一個細分專業或行業,也可作為研究生專業選題方向。

M2M技術概論

《M2M: The Wireless Revolution》,TSTC Publishing,等教材。

本書是美國「Texas State Techinical College」推出的M2M專業教材,在美國首次提出了M2M專業教學大綱,M2M也是物聯網主要領域,需要了解,建議直接用英文授課。

物聯網軟體、標准、與中間件技術

《中間件技術原理與應用》,清華大學出版社,《物聯網:技術、應用、標准與商業模式》,電子工業出版社,等教材。

物聯網產業發展的關鍵在於應用,軟體是靈魂,中間件是產業化的基石,需要學習和了解,尤其是對畢業後有志於走向工業和企業界的學生。