c語言用raw socket進行抓包


 

 https://www.cnblogs.com/MrYuan/p/5215923.html

https://blog.csdn.net/qq_41787205/article/details/86694417

本機端口查看

打開DOS窗口后,一般我們會先輸入“netstat”命令查看簡單的統計信息,其中冒號后面的是端口信息:

輸入“netstat -nao”命令時可以在最右列顯示PID進程序號,以便我們用命令直接結束程序:

輸入“netstat -nab”命令可以網絡連接、端口占用和程序運行的詳細信息

然后用任務管理器看對應的進程。

利用快捷鍵win+R鍵打開運行窗口。輸入cmd回車打開命令提示符窗口  
1:查看本機開放的端口,即已被占用的端口號。  命令:  netstat -an   
部分結果列表:  
Proto   Local Address           Foreign Address        State 

TCP    0.0.0.0:135                0.0.0.0:0                     LISTENING

TCP    0.0.0.0:3473              0.0.0.0:0                     LISTENING 

TCP    0.0.0.0:8009              0.0.0.0:0                     LISTENING   

Local Addresss 對應的這列,“:”后邊即為以開放的端口號。   

 

 

 

2:查看某個端口號是否被占用  netstat -ano|findstr  "3306" (注意雙引號前面有個空格)

 

 

 

可以看到,輸入端口號“3306”和"51016"都沒有返回任何值,說明這兩個端口沒有被占用,

而輸入端口號”52475“后看到,出現了2行返回結果,說明這個端口被占用了

  
3:查看進程號對應的進程名稱  tasklist|findstr ”9400“

 

 

 

注意:這里輸入的不是端口號,而是后面顯示的端口號對應的進程號

可以看到,輸入進程號9400后,顯示了該進程號對應的進程名,即360se.exe

   

4:結束進程  tskill 360se.exe

tskill 進程名/進程號

也可以直接在任務管理器中結束,打開任務管理器快捷鍵:ctrl+shift+ESC  命令:  

小知識:Netstat命令用法命令格式:

Netstat -a -e -n -o -s-an-a 表示顯示所有活動的TCP連接以及計算機監聽的TCP和UDP端口。

-e 表示顯示以太網發送和接收的字節數、數據包數等。

-n 表示只以數字形式顯示所有活動的TCP連接的地址和端口號。

-o 表示顯示活動的TCP連接並包括每個連接的進程ID(PID)。

-s 表示按協議顯示各種連接的統計信息,包括端口號。

-an 查看所有開放的端口

 

 

delete和析構函數間的關系及細節

https://blog.csdn.net/wk_bjut_edu_cn/article/details/79149540

https://blog.csdn.net/lzm18064126848/article/details/50392164

 

 

#include
#include
using namespace std;  
class shape 
{ 
public:
 char x;
    shape(char m) 
   {  

    x=m;
    cout << "構造"<<endl;
    cout <<x<<endl;
   } 
   ~shape() 
   {  
    cout << "析構"<<endl;

    cout<<x<<endl;
   } 
}; 
int main() 
{ 
    shape a('a'); 
    shape* b = new shape('b');
   delete b;

    system("pause");
    return 0; 
}

 

 

當有那句delete b時,運行結果如圖,delete和析構函數間的關系及細節也就是說delete b之后執行了shape的析構函數,而按了任意鍵之后,會立馬閃出一個析構a來,這說明程序執行完成后,即在a所在的作用域結束后,執行了shape的析構函數

而當沒有delete b時,運行結果如圖delete和析構函數間的關系及細節,這說明暫時沒有執行b的shape析構函數,按了任意鍵后,跟上面一樣,也只會閃出一個析構a來,沒有析構b

這說明,直接聲明的對象,比如shape a,即在棧上面的對象,所在作用域結束后,會自動執行析構函數,而new出來的在堆上的對象,不調用delete,即使它所在的作用域已經結束,也不會調用析構函數,根據另外一篇文章內所述,可能程序結束后,OS(操作系統)會回收其堆內占用的內存,這樣就不知道會干什么,會不會調用析構了。


delete詳解:首先調用析構函數,完成類成員的釋放,比如類成員有vector也指向了堆上的內存,就需要在析構函數中同樣使用delete釋放這塊內存,或者說它自身處於一個容器當中,就需要在這個容器中erase它

然后再free掉整個對象的內存;

delete b過后,b仍然指向改內存,即地址不變,但指針可能為懸垂指針,訪問它可能帶來意想不到的結果,也可能正確訪問,不確定,所以建議delete后,把指針設置成NULL,后面也可根據指針是否為NULL判斷是否可用

 

 

 

 

inet_addr()將命令行中輸入的點分IP地址轉換為二進制表示的網絡字節序IP地址

 inet_ntoa()和上面那個相反

https://blog.csdn.net/bit666888/article/details/81746085

 

地址轉換函數:inet_ntoa() 和 inet_addr()
inet_ntoa():

函數原型:

char *inet_ntoa(struct in_addr);

 


參數:in_addr是一個結構體,用來表示一個32位的IPV4地址。

struct in_addr{
in_addr_t s_addr;
}

 



返回值:返回點分十進制的字符串在靜態內存中的指針。

點分十進制:

全稱為點分(點式)十進制表示法,是IPV4的IP地址標識方法。
IPV4中用4個字節表示一個IP地址,每個字節按照十進制表示為0~255。
點分十進制就是用4個從0~255的數字,來表示一個IP地址。
例如:192.168.1.246


頭文件:<arpa/inet.h>

別稱:IP地址轉換函數。

功能:將網絡字節序IP轉化成點分十進制IP

網絡字節序:網絡字節序是TCP/IP中規定好的一種數據表示格式,它與具體的CPU類型、操作系統等無關,從而可以保證數據在不同主機之間傳輸時能夠被正確解釋。網絡字節順序采用big endian(大端)排序方式。

inet_addr():

簡介:
inet_addr方法可以轉化字符串,主要用來將一個十進制的數轉化為二進制的數,用途多余IPV4的IP轉化。
函數原型:

in_addr_t inet_addr(const char* cp);

 


參數:字符串,一個點分十進制的IP地址。
返回值:
若字符串有效,則將字符串轉換為32位二進制網絡字節序的IPV4地址;否則,為INADDR_NONE
頭文件:<arpa/inet.h>
別稱:IP地址轉化函數。
功能:將一個點分十進制的IP轉換成一個長整數型(u_long類型)。

 

 

 https://www.cnblogs.com/crazyleeyang/articles/2446146.html

sockaddr與sockaddr_in及其使用

 

       編了有不少的socket相關的例子了,同時在現在的項目中常用到socket編程,今天突然發現對與socket編程中的地址使用還不是很熟練,於是綜合一下網上的資料,詳細探討下.首先要說明的是這里主要探討struct sockaddr 與struct sockaddr_in兩個結構體.在linux環境下,結構體struct sockaddr在/usr/include/linux/socket.h中定義,具體定義如下:

typedef unsigned short sa_family_t;
struct sockaddr
{
   sa_family_t  sa_family;       /* 地址族,一般都是“AF_xxx”的形式,通常用的是AF_INET,2個字節 */
    char   sa_data[14];           /* 14字節的協議地址,包含該socket的IP地址和端口等信息 */   
};

這是通用socket地址(共16字節).具體到internet環境下使用的socket的地址為sockaddr_in,二者長度一樣,都是16個字節.二者可以進行類型轉換.一般情況下,需要把sockaddr_in結構強制轉換成sockaddr再傳入系統調用函數中.

struct   sockaddr_in
{
    short int        sin_family;  /* 地址族,形如AF_xxx,通常用的是AF_INET,2字節 */   
    unsigned short int  sin_port;     /* 端口號(使用網絡字節順序)2字節 */   
    struct in_addr    sin_addr;     /* 存儲IP地址,4字節,就是32位的ip地址 */   
    unsigned char       sin_zero[8]; /* 總共8個字節,實際上沒有什么用,只是為了和struct sockaddr保持一樣的長度 */   
};

struct in_addr其實就是32位IP地址,下面是in_addr的結構:

struct in_addr 
{
    unsigned long s_addr;
};

還有另一種形式,如下:

struct in_addr
{
    union
    {
        struct{unsigned char s_b1,s_b2,s_b3,s_b4;} S_un_b;
        struct{unsigned short s_w1,s_w2;} S_un_w;
        unsigned long S_addr;//4字節,32位,按照網絡字節順序存儲IP地址
    } S_un;
};

  關於網絡字節順序:其實數據的順序是由cpu決定的,與操作系統無關,如 Intel x86結構下,short型數0x1234表示為34 12,int型數0x12345678表示為78 56 34 12(小端數據),如IBM power PC結構下,short型數0x1234表示為12 34,int型數0x12345678表示為12 34 56 78,則為大端數據.在網絡傳輸時需要做好轉換,網絡字節順序為大端字節順序.下面是一些用於轉換的函數.

htons:把unsigned short類型從主機序轉換到網絡序;

htonl:把unsigned long 類型從主機序轉換到網絡序;

ntohs:把unsigned short類型從網絡序轉換到主機序;

ntohl:把unsigned long 類型從網絡序轉換到主機序;

inet_aton(const char *string, struct in_addr*addr):將一個字符串IP地址轉換為一個32位的網絡序列IP地址

inet_addr:是將一個點分制的IP地址(如192.168.0.1)轉換為上述結構中需要的32位IP地址(0xC0A80001),即轉換成in_addr,inet_addr()返回的地址已經是網絡字節格式,所以無需再調用函數htonl();

inet_ntoa(struct in_addr):返回點分十進制的字符串在靜態內存中的指針,所以每次調用 inet_ntoa(),它就將覆蓋上次調用時所得的IP地址.

inet_pton(int af, const char *src, void *dst):函數將點分十進制的地址src轉換為in_addr的結構體,並復制在dst中.

const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt):轉換網絡二進制結構到點分十進制類型的地址

例子:

my_addr.sin_family = AF_INET;  /* 主機字節序 */
my_addr.sin_port   = htons(MYPORT);  /* short, 網絡字節序 */
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//還有如此的格式
my_addr.sin_addr.s_addr = inet_addr("192.168.0.1");

一般編程中並不直接針對sockaddr操作,而是使用sockaddr_in來進行操作.要做轉換的時候用:(struct sockaddr*)mysock_addr,填值的時候使用sockaddr_in結構,而作為函數的參數傳入的時候轉換成sockaddr結構就行了.

 

計算機網絡高級軟件編程技術P80頁

對於抓到的包進行端口過濾或者進行ip地址過濾。

端口號一般http協議是默認80端口,https協議是使用443端口,還有其他的上網查。

然后對於一個網站的ip地址,可以通過在cmd命令行用ping + 網址。比如csdn的使用ping blog.csdn.net可以得到csdn的ip地址。對於tcp頭還要在學習一下!!!!!!!!!!!!!!!!!!!

 

#include<winsock2.h>
#include<iphlpapi.h>
#include <Ws2tcpip.h>
#include<iostream>
#include<conio.h>
#include <time.h>
#define IO_RCVALL _WSAIOW(IOC_VENDOR, 1)
#define BUFFER_SIZE 65535
using namespace std;
typedef pair<int, BYTE> pii;
char localName[256];//本地機器名
DWORD dwBufferLen[10];//獲取主機名
DWORD dwBufferInLen = 1;//指向主機信息的指針
DWORD dwBytesReturned = 0;//通過主機名獲取本地IP地址
char buffer[BUFFER_SIZE];
class CIPNode{
public:
    ULONG m_dwSourIpAddr;//源IP地址
    ULONG m_dwDestIpAddr;//目的IP地址
    BYTE m_chProtocol;//IP包的協議類型
    ULONG m_dwCounter;//數據包的數量
    CIPNode *pNext;//指向下一類IP節點
    CIPNode (ULONG dwSourIp, ULONG dwDestIp, BYTE chPro) {
        m_dwSourIpAddr = dwSourIp;
        m_dwDestIpAddr = dwDestIp;
        m_chProtocol = chPro;
        m_dwCounter = 1;//初始化數據包個數為1
    }
    void addCount() {//增加數據包的數量
        m_dwCounter++;
    }
    ULONG getCount() {//取得數據包的數量
        return m_dwSourIpAddr;
    }
    ULONG getSourIpAddr() {//取得源IP地址
        return m_dwSourIpAddr;
    }
    ULONG getDestIpAddr() {//取得目的IP地址
        return m_dwDestIpAddr;
    }
    BYTE getProtocol() {//取得協議類型
        return m_chProtocol;
    }
};
string getProtocol(BYTE Protocol) //獲取協議字段共8位
{
    switch(Protocol) //以下為協議號說明:
    {
        case 1:
        return "ICMP"; //Internet控制報文協議
        case 2:
        return "IGMP"; //Internet組管理協議
        case 4:
        return "IP in IP"; //移動IP數據封裝和隧道
        case 6:
        return "TCP"; //傳輸控制協議
        case 8:
        return "EGP"; //外部網關協議
        case 17:
        return "UDP"; //用戶數據報文協議
        case 41:
        return "IPv6";
        case 46:
        return "RSVP"; //資源預留協議
        case 89:
        return "OSPF"; //Open Shortest Path First 開發式最短路徑優先
        default:
        return "UNKNOW";
    }
}

class CNodeList {
private:
    CIPNode *pHead;//鏈表頭
    CIPNode *pTail;//鏈表尾
public:
    CNodeList() {//構造函數
        pHead = pTail = NULL;
    }
    //析構函數,完成類成員的釋放。
    ~CNodeList() {
        //刪除鏈表中的所有節點
        if(pHead != NULL) {
            CIPNode *pTemp = pHead;
            pHead = pHead -> pNext;
            delete pTemp;
            pTemp = NULL;
        }
    }
    //把新捕獲的IP數據包加入鏈表。
    void addNode(ULONG dwSourIp, ULONG dwDestIp, BYTE chPro) {
        if(pHead == NULL) {//鏈表為空
            pTail = new CIPNode(dwSourIp, dwDestIp, chPro);
            pHead = pTail;
            pTail -> pNext = NULL;
        }
        else {//鏈表不為空
            CIPNode *pTemp;
            for(pTemp = pHead; pTemp; pTemp = pTemp -> pNext) {
                //如果鏈表中已存在該類型的IP包,則數據包的個數加1.
                if(pTemp -> getSourIpAddr() == dwSourIp
                   && pTemp -> getDestIpAddr() == dwDestIp
                   && pTemp -> getProtocol() == chPro)
                {
                    pTemp -> addCount();
                    break;
                }
            }
            //如果鏈表中不存在該類型的IP包,則創建新的節點加入鏈表。
            if(pTemp == NULL) {
                pTail -> pNext = new CIPNode(dwSourIp, dwDestIp, chPro);
                pTail = pTail -> pNext;
                pTail -> pNext = NULL;
            }
        }
    }
    void print() {
        CIPNode *pTemp;
        for(pTemp = pHead; pTemp; pTemp = pTemp -> pNext) {
            printf("源主機 :%s\n", inet_ntoa(*(in_addr*) (&pTemp -> m_dwSourIpAddr)) );
            printf("目的主機:%s\n", inet_ntoa(*(in_addr*) (&pTemp -> m_dwDestIpAddr)) );
            cout << getProtocol(pTemp -> m_chProtocol) << endl;
        }
        printf("OVER\n");
    }
};

struct IPHEADER {//20-60
    BYTE Version_HeaderLength;//版本(4位)+首部長度(4位)
    BYTE TypeOfService;//服務類型。計算機網絡高級編程技術P76
    USHORT TotalLength;//總長度
    USHORT Identification;//標識
    USHORT Flags_FragmentOffset;//標志(3位)+分片偏移(13位)
    BYTE TimeToLive;//生存時間
    BYTE Protocol;//協議
    USHORT HeaderChecksum;//首部校驗和
    ULONG SourceAddress;//源ip地址
    ULONG DestAddress;//目的ip地址
//    BYTE Options//選項
};
//20-60
struct Tcphead{
    USHORT SourcePort;//源端口號
    USHORT DestPort;//目的端口號
    ULONG dwSeq;//序號
    ULONG dwAck;//確認序號
    BYTE Length;
    USHORT flag;
    USHORT Window;
    USHORT CheckSum;
    USHORT Urgent;
//    ULONG Options;
};


struct Udphead{
    USHORT SourcePort;
    USHORT DestPort;
    USHORT Length;
    USHORT CheckSum;
};

int cnt;
pii printip(IPHEADER *iphead) {
//        cout << "第 "<<cnt++<<" 個IP數據包信息:" << endl;
//        cout << "協議版本:" <<(iphead -> Version_HeaderLength >> 4) << endl;
//        cout << "首部長度:" << ((iphead -> Version_HeaderLength & 0x0F) << 2) << endl;//單位為4字節,所以乘四。
//        cout << "優先級:Priority: " << ((iphead -> TypeOfService) >> 5) << ",服務類型:Service: "
//        << (( (iphead -> TypeOfService) >> 1) & 0x0f) << endl;
//        cout << "IP包總長度:" << ntohs(iphead -> TotalLength) << endl; //網絡字節序轉為主機字節序
//        cout << "標識:" << ntohs(iphead -> Identification) << endl;//網絡字節序轉成主機字節序
//        cout << "標志位:" << "DF=" << ((iphead -> Flags_FragmentOffset >> 14) & 0x01);
//        cout << ",MF=" << ((iphead -> Flags_FragmentOffset >> 13) & 0x01) << endl;
//        //共3位,最高位為0;DF禁止分片標識。DF=0,可以分片;DF=1,不能分片。MF:分片標識。
//        //MF=0,表示接的是最后一個分片;MF=1,不是最后一個分片。
//        cout << "片偏移:" << (iphead -> Flags_FragmentOffset & 0x1fff) << endl;//得到后13位
//        cout << "生存周期:" << (int)iphead -> TimeToLive << endl;
//        cout << "協議類型:" << getProtocol(iphead -> Protocol) << endl;
//        cout << "首部校驗和:" << ntohs(iphead -> HeaderChecksum) << endl;
//        cout << "源地址:" << inet_ntoa(*(in_addr*)(&iphead -> SourceAddress) ) << endl;
//        cout << "目的地址:" << inet_ntoa(*(in_addr*) (&iphead -> DestAddress) ) << endl;
//        cout << "==============================================================" << endl << endl;
        return make_pair((iphead -> Version_HeaderLength & 0x0F) << 2, iphead -> Protocol);
}

int main() {
    clock_t start = clock();
    WSADATA wsData;
    WSAStartup(MAKEWORD(2, 2), &wsData);
    SOCKET sock;
    sock = WSASocket(AF_INET, SOCK_RAW, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);
    gethostname(localName, 256);
    HOSTENT *pHost;
    pHost = gethostbyname(localName);
    sockaddr_in addr_in;
    addr_in.sin_family = AF_INET;//設定地址類型
    addr_in.sin_port = htons(8000);//設定一個端口。不能是已固定的端口
    for(DWORD i = 0; pHost -> h_addr_list[i]; i++) {
        printf ("IP address %lu:%s\n", i + 1, inet_ntoa (*(struct in_addr*)pHost->h_addr_list[i]));
    }
    int ind;
    scanf("%d", &ind);
    addr_in.sin_addr = *(in_addr *) pHost->h_addr_list[ind];//設置IP地址
    bind(sock, (sockaddr *) &addr_in, sizeof(addr_in));//把原始套接字綁定到本機地址上
    //設置混雜模式
    WSAIoctl(sock, IO_RCVALL, &dwBufferInLen, sizeof(dwBufferInLen), dwBufferLen, sizeof(dwBufferLen), &dwBytesReturned, NULL, NULL);
//    ULONG bioarg = 0;
//    ioctlsocket(sock, FIONBIO, &bioarg);
    CNodeList IpList;
    while(1) {
        int nPackSize = recv(sock, buffer, BUFFER_SIZE, 0);
        if(nPackSize > 0) {
            IPHEADER *pIpHdr;
            //通過指針把緩沖區中的內容強制轉換為IPHEADER數據結構。
            pIpHdr = (IPHEADER *) buffer;
            pii x = printip(pIpHdr);
            int xx;
            in_addr csdn;
            csdn.S_un.S_addr = inet_addr("202.202.32.35");
            if(x.second == 6) {
                Tcphead *pTcphdr;
                pTcphdr=(struct Tcphead*)(buffer+(x.first));
                printf("%d\n", (((pTcphdr -> Length) & 0xF0)>>4) * 4);
                printf("源端口%d, 目的端口%d\n", ntohs(pTcphdr -> SourcePort), ntohs(pTcphdr -> DestPort));
                if( (pTcphdr -> SourcePort) == ntohs(80) && (pIpHdr -> SourceAddress) == csdn.S_un.S_addr) {
                    printf("%s\n", inet_ntoa(*(in_addr*) (&pIpHdr -> SourceAddress) ));
                    printf("出去%s\n", buffer + (x.first) + (((pTcphdr -> Length) & 0xF0)>>4) * 4);
                    scanf("%d", &xx);
                }
                if( (pTcphdr -> DestPort) == ntohs(80) && (pIpHdr -> DestAddress) == csdn.S_un.S_addr) {
                    printf("%s\n", inet_ntoa(*(in_addr*) (&pIpHdr -> DestAddress) ));
                    printf("進來%s\n", buffer + (x.first) + (((pTcphdr -> Length) & 0xF0)>>4) * 4);
                    scanf("%d", &xx);
                }
            }
//            else if(x.second == 17) {
//                Udphead *pUdphdr;
//                pUdphdr=(struct Udphead*)(buffer+(x.first*4));
//                printf("源端口%d, 目的端口%d\n", pUdphdr -> SourcePort, pUdphdr -> DestPort);
//                if(pUdphdr -> SourcePort == 80) {
//
//                }
//            }
//            TCPPORT *tcpPort;
//            printf("%d\n", x);
//            tcpPort = (TCPPORT *) (buffer + x);
//            printf("源端口%u 目的端口%u\n", tcpPort -> SourcePort, tcpPort -> DestPort);
            //判斷IP包的源IP地址或目的IP地址是否為本地主機的IP地址。
            if(pIpHdr -> SourceAddress == addr_in.sin_addr.S_un.S_addr ||
               pIpHdr -> DestAddress == addr_in.sin_addr.S_un.S_addr)
            {
                IpList.addNode(pIpHdr -> SourceAddress, pIpHdr -> DestAddress, pIpHdr -> Protocol);
            }
//            printf("繼續yes/no\n");
//            char ch[4];
//            scanf("%s", ch);
//            if(ch[0] == 'y') continue;
//            else break;
        }
//        if(clock() - start >= 2000) break;
    }
    IpList.print();
    closesocket(sock);
    WSACleanup();
    return 0;
}

 

 

 

 

http://blog.chinaunix.net/uid-26729093-id-3444880.html?_t=t

https://blog.csdn.net/weixin_34198762/article/details/86037650


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM