TCP/IP学习--sniffer 实作

     目前大多数操作系统都为应用程序提供访问数据链路层的强大功能。 这种功能可以提供如下能力:
    1.  能够监视由数据链路层接收的分组, 使得诸如tcpdump等程序能够在普通计算机系统上运行, 而无需实用专门的硬件设备来监视分组。 如果结合实用网络接口进入混杂模式的能力, 那么应用程序甚至能够监视本地电缆上流通的所有分组, 而不仅仅是以程序运行所在主机为目的地的分组
     2. 能够作为普遍应用进程而不是内核的一部分运行某些程序。
 要从数据链路层接收所有帧应如下创建套接口:
   sockfd = socket(PF_PACKET,SOCK_RAW, htons(ETH_P_ALL));
   那么由数据链路层接收的任何协议以太网帧将返回到这些套接口。 如果只想捕获IPV4帧,那就如下创建套接口:
   sockfd = socket(PF_PACKET,SOCK_RAW, htons(ETH_P_IP));

下面的简单的tcp row socket 实现,在centos 4 中编译通过

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <string.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <signal.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/if_ether.h>
#include <net/ethernet.h>

void die(char *why,int n) {
    perror(why);
    exit(n);
}

//把网卡置为混杂模式
int do_promisc(char *nif,int sock) {
    struct ifreq ifr;
    strncpy(ifr.ifr_name,nif,strlen(nif)+1);
    if(ioctl(sock,SIOCGIFFLAGS,&ifr) == -1 )
        die("ioctl num1",2);
    ifr.ifr_flags |= IFF_PROMISC;  //reset flag
    if(ioctl(sock,SIOCSIFFLAGS,&ifr) == -1 )
        die("ioctl num2",3);
}
char buf[40960];
main(){
    struct sockaddr_in addr;
    struct ether_header *peth;
    struct iphdr *pip;
    struct tcphdr *ptcp;
    struct udphdr *pudp;
    char mac[16];
    int i,sock,r,len;
    char *data,*ptemp;
    char ss[32],dd[32];
//创建套接口为接收数据链路层的所有帧

   if((sock = socket(AF_PACKET,SOCK_RAW,htons(ETH_P_ALL))) == -1)
        die("socket",1);
    do_promisc("eth0",sock);
    system("ifconfig");
    for(;;) {
        len = sizeof(addr);
        r = recvfrom(sock,(char *)buf,sizeof(buf),0,(struct sockaddr *)&addr,&len);
        printf("get the packet or not %s /n",buf);
        buf[r] = 0;
        ptemp = buf;
        peth = (struct ether_header *)ptemp;
        ptemp += sizeof(struct ether_header);
        pip = (struct ip *)ptemp;

//移动指针到TCP,UDP头部

        ptemp += sizeof(struct ip);
        char *content;

        switch(pip->protocol){、

            case IPPROTO_TCP:

                ptcp = (struct tcphdr *)ptemp;
                printf("tcp pkt:from[%s]:[%d]/n",inet_ntoa(*(struct in_addr*)&(pip->saddr)),ntohs(ptcp->source));
                printf("tcp pkt:to[%s]:[%d]/n",inet_ntoa(*(struct in_addr*)&(pip->daddr)),ntohs(ptcp->dest));   

//要判断具体的是什么应用需要对端口进行判断,如HTTP:80,FTP:23
                ptemp += sizeof(struct tcphdr);
                content = (char *)ptemp;

                printf("tcp content is %s/n",content);
                break;
            case IPPROTO_UDP:
                pudp = (struct udphdr *)ptemp;
//                printf("udp pkt: len:%d payload len:%d   from %s:%d to %s:%d/n",
//                r,
///                ntohs(pudp->len),
//                inet_ntoa(*(struct in_addr*)&(pip->saddr)),
//                ntohs(pudp->source),
//                inet_ntoa(*(struct in_addr*)&(pip->daddr)),
//                ntohs(pudp->dest));
                printf("get udp pkt");
                break;
            case IPPROTO_ICMP:
                printf("icmp pkt:%s/n",inet_ntoa(*(struct in_addr*)&(pip->saddr)));
                break;
            case IPPROTO_IGMP:
                printf("igmp pkt:/n");
                break;
            default:
                printf("unkown pkt,protocol:%d/n",pip->protocol);
                break;
        }
        perror("dump");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值