一个简单的sniffer抓包程序

来源:互联网 发布:用友软件破解版 编辑:程序博客网 时间:2024/05/01 19:31
#include "unp.h"#include <linux/if_ether.h>/* Ethernet header are are always exactly 14 bytes */#define SIZE_ETHERNET14/* Ethernet address are 6 bytes */#define ETHER_ADDR_LEN6#define LINE_WIDTH16/*+---------+---------+---------------------------------------------------+| Version | Header  | Type of Service |           Total Length          ||         |  Length |                 |                                 || (4bit)  | (4bit)  |   (8bit)        |             (16bit)             |+---------+---------+-----------------+--------+------------------------+|           Identification            |  Flag  |     Fragment Offset    ||                                     |        |                        ||               (16bit)               | (3bit) |        (13bit)         |+-------------------+-----------------+--------+------------------------+|   Time to Live    |    Protocol     |         Header Checksum         ||                   |                 |                                 ||      (8bit)       |     (8bit)      |            (16bit)              |+-------------------+-----------------+---------------------------------+|                              Source IP Address                        ||                                                                       ||                                  (32bit)                              |------------------------------------------------------------------------+|                           Destination IP Address                      ||                                                                       ||                                  (32bit)                              |+-----------------------------------------------------------------------+|                                 Options                               ||                                                                       ||                                  (32bit)                              |+-----------------------------------------------------------------------+|                                  Data                                 ||                                                                       ||                                  ...                                  |+-----------------------------------------------------------------------+*/struct sniff_ip {u_charip_vhl;/* version &0xf0 >> 4 | header len &0x0f*/    unsigned char   ip_tos;/* type of service*/    unsigned short  ip_len;/* total length */    unsigned short  ip_id;/* Identification */    unsigned short  ip_off;/* flag offset field */#define  IP_REF0x800/* reserved flagment flag */#define  IP_DF0x400/* dont fragment flag */#define  IP_MF0x200/* more fragment flag */#define  IP_OFFMASK0x1fff/* mask for fragment bits */    unsigned char   ip_ttl;/* time to live */    unsigned char   ip_protocol;/* protocol */    unsigned short  ip_cksum;/* checksum */    struct in_addr  ip_src;/* source address */    struct in_addrip_dst;/* destination address */};#define IP_HL(ip)((ip->ip_vhl) & 0x0f)#define IP_V(ip)(((ip->ip_vhl) & 0xf0) >> 4)/*Ehernet II帧结构:帧头:6个字节的目的MAC地址和6字节的源MAC地址。2字节的类型字段,表示封装在数据中的数据类型。数据:46-1500字节的数据字段。帧尾 :4字节的帧效验序列。+-------+--------------+----------------------------------------+------+| D-MAC | S-MAC | TYPE |                    DATA                | CRC  || 6B    |  6B   | 2B   |                                        |  4B  |+-------+--------------+----------------------------------------+------+ */struct sniff_ethernet {u_charether_dhost[ETHER_ADDR_LEN];/* destination host address */u_charether_shost[ETHER_ADDR_LEN];/* source host address */u_short ether_type;/* IP? ARP? RARP? etc */};/*  TCP 格式 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                               |                               ||       Source Port             |        Destination Port       ||                               |                               |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                                                               ||                        Sequence Number                        ||                                                               |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                                                               ||                    Acknowledgment NUmber                      ||                                                               |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+| Data |            |U|A|P|R|S|F|                               ||offset|  Reserved  |R|C|S|S|Y|I|        Window                 ||      |            |G|K|H|T|N|N|                               |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                               |                               ||       Checksum                |          Urgent Pointer       ||                               |                               |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                                               |               ||                  Options                      |   Padding     ||                                               |               |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                                                               ||                             Data                              ||                                                               |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/typedef u_int tcp_seq;struct sniff_tcp {u_shortth_sport;/* source port */u_short th_dport;/* destination port */tcp_seqth_seq;/* sequence number */tcp_seq th_ack;/* acknowledgment number */u_char  th_offx2;/* data offset, reserved , 因为保留位全为0,被拆成两部分*/#define TH_OFF(th) (((th->th_offx2) & 0xf0) >> 4) u_charth_flags;/* flags */#define TH_FIN0x01 #define TH_SYN0x02 #define TH_RST0x04 #define TH_PUSH0x08 #define TH_ACK0x10 #define TH_URG  0x20#define TH_ECE0x40#define TH_CWR0x80#define TH_FLAGS(TH_FIN | TH_SYN | TH_RST | TH_ACK | TH_URG | TH_ECE | TH_CWR) u_shortth_win;/* window */u_short th_sum;/* checksum */u_short th_urp;/* urgent pointer */};/* * 打印一行(16个字节): offset hex ascii * * 00000   47 45 54 20 2f 20 48 54  54 50 2f 31 2e 31 0d 0a   GET / HTTP/1.1.. */voidprint_hex_ascii_line(const u_char *payload,  ssize_t len, ssize_t offset) {ssize_ti;intgap;const u_char*ch;/* offset */printf("%05d\t", offset);/* hex */ch = payload;for (i = 0; i < len; ++i) {printf("%02x ", *ch++);if (i == LINE_WIDTH / 2 - 1) printf("%2c ", ' ');}if (len < LINE_WIDTH / 2) printf("%2x ", ' ');/* 不够8个字节时打印空格 */if (len < LINE_WIDTH) {gap = LINE_WIDTH - len;while(gap-- > 0) printf("%2c ", ' ');}printf("\t");/* ascii */ch = payload;for (i = 0; i < len; ++i) {if (isprint(*ch))printf("%c", *ch);elseprintf("%c", '.');++ch;}printf("\n");}/* * 打印有效载荷(避免打印二进制) */voidprint_payload(const u_char *payload, ssize_t len) {ssize_tlen_rem = len;ssize_tline_len;ssize_toffset= 0;const u_char*ptr = payload;if (len_rem == 0) {return;}/* 只有一行 */if (len <= LINE_WIDTH) {print_hex_ascii_line(ptr, len, offset);return;}/* data跨越多行 */for ( ; ; ) {printf("len_rem: %d offset : %d\n", len_rem, offset);if (len_rem <= LINE_WIDTH) {print_hex_ascii_line(ptr, len_rem, offset);break;}print_hex_ascii_line(ptr, LINE_WIDTH, offset);len_rem -= LINE_WIDTH;ptr += LINE_WIDTH;offset += LINE_WIDTH;}}voidgot_packet(const u_char *packet) {static int count= 1;/* packet counter *//* 声明指向分组的指针 */struct sniff_ethernet*ethernet;struct sniff_tcp*tcp;struct sniff_ip*ip;const u_char*p, *payload;ssize_t size_ip;ssize_t size_tcp;ssize_t size_payload;/* 有效载荷 */printf("\nPacket number %d:\n", count++);printf("\t源主机\t\t\t目标主机\n");ethernet = (struct sniff_ethernet *)packet;p = ethernet->ether_shost;printf("\t%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",p[6] & 0xff, p[7] & 0xff,p[8] & 0xff, p[9] & 0xff,p[10] & 0xff, p[11] & 0xff);p = ethernet->ether_dhost;printf("\t%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",p[0] & 0xff, p[1] & 0xff,p[2] & 0xff, p[3] & 0xff, p[4] & 0xff, p[5] & 0xff);ip = (struct sniff_ip *)(packet + SIZE_ETHERNET);size_ip = IP_HL(ip) * 4;if (size_ip < 20) {printf(" Invalid IP header length: %zu\n", size_ip);return;}printf("\tFrom:%s", inet_ntoa(ip->ip_src));printf("\tTo:%s\n", inet_ntoa(ip->ip_dst));switch(ip->ip_protocol) {case IPPROTO_TCP:printf("\tProtocl: TCP\n");break;case IPPROTO_UDP:printf("\tProtocl: UDP\n");return;case IPPROTO_ICMP:printf("\tProtocl: ICMP\n");return;case IPPROTO_IP:printf("\tProtocl: IP\n");return;case IPPROTO_RAW:printf("\tProtocl: RAW\n");return;default:printf("\tProtocl: Unknown\n");return;}/* * 只处理tcp *//* 定义和计算tcp head偏移 */tcp = (struct sniff_tcp *)(packet + SIZE_ETHERNET + size_ip);size_tcp = TH_OFF(tcp) * 4;if (size_tcp < 20) {printf("\tInvalid TCP header length:%zu bytes\n", size_tcp);return;}printf("\t源端口: %d\t\t目标端口:%d\n", tcp->th_sport, tcp->th_dport);/* 定义/计算有效载荷段偏移 */payload = (u_char *)(packet + SIZE_ETHERNET + size_ip + size_tcp); /* 计算tcp 载荷大小 */size_payload = ntohs(ip->ip_len) - (size_ip + size_tcp);/* * 打印有效载荷的长度 */if (size_payload > 0) {printf("\tPayload (%zu bytes): \n", size_payload);print_payload(payload, size_payload);}}/** PF_PACKET协议簇可以让一个应用程序把数据包变成似乎从网络层接收的样子* 但是没有办法抓到那些不是发向自己主机的包。* 正如我们前面看到的,网卡丢弃所有不含有主机MAC地址的数据包* 这是因为网卡处于非混杂模式,即每个网卡只处理源地址是它自己的帧!* 只有三个例外:* 如果一个帧的目的MAC地址是一个受限的广播地址(255.255.255.255)那么它将被所有的网卡接收:* 如果一个帧的目的地址是组播地址,那么它将被那些打开组播接收功能的网卡所接收;* 网卡如被设置成混杂模式,那么它将接收所有流经它的数据包*/intmain() {    int                 sockfd;    ssize_t             n;    u_char              buf[MAXLINE];    if ((sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP))) < 0) {        perror("create sockt");        exit(EXIT_FAILURE);    }//抓包for ( ; ; ) {n = recvfrom(sockfd, buf, MAXLINE, 0, 0, 0);/******************************************* ** 14   6(dest)+6(source)+2(type or length) ** + ** 20   ip header  ** + ** 8    icmp,tcp or udp header ** = 42 *********************************************/if (n < 42) {fprintf(stdout, "Incomplete header, packet corrupt.\n"); continue;}got_packet(buf);}return 0;}


说明:  此程序中的unp.h 是参考UNP这本书,但是只是简单的包含了socket必须的头文件以及几个出错打印函数。

参考:  Unix Network Programming -v3

                  http://blog.csdn.net/linux_embedded/article/details/8836847     

原创粉丝点击