zoukankan      html  css  js  c++  java
  • Linux 原始套接字抓包实例

        学习网络编程,调试各种连接和数据很麻烦,也有很多现成工具可以使用,不过还是喜欢再造个轮子来自己玩玩.

    header.h 定义了IP和TCP包头格式:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <net/if.h>
    
    /*
        定义TCP和IP的包头格式
    */
    
    
    /* IP header */
    struct ip {
            u_char  ip_vhl;                 /* version << 4 | header length >> 2 */
            u_char  ip_tos;                 /* type of service */
            u_short ip_len;                 /* total length */
            u_short ip_id;                  /* identification */
            u_short ip_off;                 /* fragment offset field */
            #define IP_RF 0x8000            /* reserved fragment flag */
            #define IP_DF 0x4000            /* dont fragment flag */
            #define IP_MF 0x2000            /* more fragments flag */
            #define IP_OFFMASK 0x1fff       /* mask for fragmenting bits */
            u_char  ip_ttl;                 /* time to live */
            u_char  ip_p;                   /* protocol */
            u_short ip_sum;                 /* checksum */
            struct  in_addr ip_src,ip_dst;  /* source and dest address */
    };
    #define IP_HL(ip)               (((ip)->ip_vhl) & 0x0f)
    #define IP_V(ip)                (((ip)->ip_vhl) >> 4)
    
    /* TCP header */
    typedef u_int tcp_seq;
    
    struct tcp {
            u_short th_sport;               /* source port */
            u_short th_dport;               /* destination port */
            tcp_seq th_seq;                 /* sequence number */
            tcp_seq th_ack;                 /* acknowledgement number */
            u_char  th_offx2;               /* data offset, rsvd */
    #define TH_OFF(th)      (((th)->th_offx2 & 0xf0) >> 4)
            u_char  th_flags;
            #define TH_FIN  0x01
            #define TH_SYN  0x02
            #define TH_RST  0x04
            #define TH_PUSH 0x08
            #define TH_ACK  0x10
            #define TH_URG  0x20
            #define TH_ECE  0x40
            #define TH_CWR  0x80
            #define TH_FLAGS        (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
            u_short th_win;                 /* window */
            u_short th_sum;                 /* checksum */
            u_short th_urp;                 /* urgent pointer */
    };

    main.c定义了主要功能:

    #include "header.h"
    #include <string.h>
    #include <sys/ioctl.h>
    
    int Open_Raw_Socket(void);
    int Set_Promisc(char *interface, int sock);
    void dump(const unsigned char*data_buffer, const unsigned int length);
    
    int main() {
        int sock;
        sock = Open_Raw_Socket();
        printf("raw socket is %d
    ", sock);
    
        char buffer[65535];
        
        int bytes_recieved;
        size_t fromlen;
        struct  sockaddr_in from;
        
        struct ip *ip;
        struct tcp *tcp;
        
        // 设置网卡eth0为混杂模式
        Set_Promisc("eth0", sock);
        // 输出TCP/IP报头的长度
        printf("IP header is %d 
    ", sizeof(struct ip));
        printf("TCP header is %d 
    ", sizeof(struct tcp));
        
        while (1) {
            fromlen = sizeof(from);
            bytes_recieved = recvfrom(sock, buffer, sizeof(buffer),
                    0, (struct sockaddr*)&from, &fromlen);
            
            printf("
    Bytes recieved: %5d
    ", bytes_recieved);
            printf("Source address: %s
    ", inet_ntoa(from.sin_addr));
            
            ip = (struct ip*)buffer;
            if (ip->ip_p == 6) {
                printf("Dest address is: %s
    ", inet_ntoa(ip->ip_dst));
                printf("IP header Length is :%d
    ", ip->ip_len);
                printf("Protocol: %d
    ", ip->ip_p);
                printf("Type of Server: %d
    ", ip->ip_tos);
                printf("Time to live is : %d
    ",ip->ip_ttl);
                printf("Check Sum is : %d
    ", ip->ip_sum);
                tcp = (struct tcp*)(buffer + 20);        // IP数据包和TCP数据包有20个字节的距离
                printf("Dest port is: %d
    ", ntohs(tcp->th_dport));
                printf("Source port is: %d
    ", ntohs(tcp->th_sport));
                printf("Seq number is : %d
    ", tcp->th_seq);
                printf("Ack number is : %d
    ", tcp->th_ack);
                printf("Flags is %d
    ", tcp->th_flags);
                
                dump((const unsigned char*)buffer, bytes_recieved);
                
            }
        }
        return 0;
        
    }
    
    
    // 建立一个原始socket句柄
    int Open_Raw_Socket(void) {
        int sock;
        if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
            perror("raw socket error
    ");
            exit(1);
        }
        return sock;
    }
    
    // 设置eth0为混杂模式
    
    int Set_Promisc(char *interface, int sock) {
        struct ifreq ifr;
        
        strncpy(ifr.ifr_name, interface, strnlen(interface, sizeof(interface)) + 1);
        if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) {
            perror("set promisc error one if
    ");
            exit(2);
        }
        
        printf("The interface is %s
    ", interface);
        printf("Retrieved flags from interface is ok
    ");
        
        ifr.ifr_flags |= IFF_PROMISC;
        
        if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) {
            perror("Can not set PROMISC flag:");
            exit(-1);
        }
        
        printf("Set Promisc ok
    ");
        
        return 0;
        
        
    }
    
    // 输出buffer内容
    void dump(const unsigned char*data_buffer, const unsigned int length) {
    
        unsigned char byte;
        unsigned int i, j;
        
        for (i = 0; i < length; i++) {
            byte = data_buffer[i];
            printf("%02x ", data_buffer[i]);
            if ((i % 16 == 15) || (i == length -1)) {
                for (j = 0; j < 15 -(i % 16); j++) {
                    printf("   ");
                }
                printf("|");
                for (j = (i - (i % 16)); j <= i; j++) {
                    byte = data_buffer[j];
                    if (byte > 31 && byte < 127)
                        printf("%c", byte);
                    else
                        printf(".");
                }
                printf("
    ");
            }
        }
        
    }

    使用时,需要root权限,在Ubuntu下需要sudo一下,使用实例, 利用了twsited的echo服务:

    raw socket

    可以用于调试简单的本机socket编程。

  • 相关阅读:
    超棒的监控工具 DataDog Splunk 日志易
    API 接口设计 原则
    程序员 架构师 成长 设计 原则
    OAM 继续演进:阿里云携手微软与 Crossplane 社区发布 OAM Kubernetes 标准实现与核心依赖库
    首席架构师 码农总结 互联网整体解决方案
    《不抱怨的世界2》 读后感
    适合开发者的最佳Linux发行版
    大数据 消息 日志
    CRM 线索来源 获客方式
    微服务开发过程中需要注意的若干事项_逍遥子曰
  • 原文地址:https://www.cnblogs.com/jaw-crusher/p/3516029.html
Copyright © 2011-2022 走看看