linux sock_raw原始套接字编程_第1页
linux sock_raw原始套接字编程_第2页
linux sock_raw原始套接字编程_第3页
linux sock_raw原始套接字编程_第4页
linux sock_raw原始套接字编程_第5页
已阅读5页,还剩6页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

linux sock_raw 原始套接字编程 sock_raw 原始套接字编程可以接收到本机网卡上的数据帧或者数据包,对与监听 网络的流量和分析是很有作用的.一共可以有 3 种方式创建这种 socket 1.socket(AF_INET, SOCK_RAW, IPPROTO_TCP|IPPROTO_UDP|IPPROTO_ICMP)发送接收 ip 数据包 2.socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL) 发送接收以太网数据帧 3.socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL) 过时了,不要用啊 理解一下 SOCK_RAW 的原理, 比如网卡收到了一个 14+20+8+100+4 的 udp 的 以太网数据帧. 首先,网卡对该数据帧进行硬过滤(根据网卡的模式不同会有不同的动作,如果设 置了 promisc 混杂模式的话,则不做任何过滤直接交给下一层输 入例程,否则非 本机 mac 或者广播 mac 会被直接丢弃).按照上面的例子 ,如果成功的话,会进入 ip 输入例程.但是在进入 ip 输入例程之前,系统会检查系 统中是否有通过 socket(AF_PACKET, SOCK_RAW, )创建的套接字.如果有的话并且协议相符,在 这个例子中就是需要 ETH_P_IP 或者 ETH_P_ALL 类型.系统就给每个这样的 socket 接收缓 冲区发送一个数据帧拷贝.然后进入下一步. 其次,进入了 ip 输入例程(ip 层会对该数据包进行软过滤,就是检查校验或者丢弃 非本机 ip 或者广播 ip 的数据包等,具体要参考源代码),例子 中就是如果成功的 话会进入 udp 输入例程.但是在交给 udp 输入例程之前,系统会检查系统中是否有 通过 socket(AF_INET, SOCK_RAW, )创建的套接字.如果有的话并且协议相符, 在这个例子中就是需要 IPPROTO_UDP 类型.系统就给每个这样的 socket 接收缓 冲区发送一个数据 帧拷贝.然后进入下一步. 最后,进入 udp 输入例程 . ps:如果校验和出错的话,内核会直接丢弃该数据包的.而不会拷贝给 sock_raw 的 套接字,因为校验和都出错了,数据肯定有问题的包括所有信息都没有意义了. 进一步分析他们的能力. 1. socket(AF_INET, SOCK_RAW, IPPROTO_UDP); 能:该套接字可以接收协议类型为(tcp udp icmp 等)发往本机的 ip 数据包,从上面 看的就是 20+8+100. 不能:不能收到非发往本地 ip 的数据包(ip 软过滤会丢弃这些不是发往本机 ip 的 数据包). 不能:不能收到从本机发送出去的数据包. 发送的话需要自己组织 tcp udp icmp 等头部.可以 setsockopt 来自己包装 ip 头部 这种套接字用来写个 ping 程序比较适合 2. socket(PF_PACKET, SOCK_RAW, htons(x); 这个套接字比较强大,创建这种套接字可以监听网卡上的所有数据帧.从上面看就 是 20+20+8+100.最后一个以太网 crc 从来都不算进来的,因为内核已经判断过了, 对程序来说没有任何意义了. 能: 接收发往本地 mac 的数据帧 能: 接收从本机发送出去的数据帧(第 3 个参数需要设置为 ETH_P_ALL) 能: 接收非发往本地 mac 的数据帧( 网卡需要设置为 promisc 混杂模式) 协议类型一共有四个 ETH_P_IP 0x800 只接收发往本机 mac 的 ip 类型的数据帧 ETH_P_ARP 0x806 只接受发往本机 mac 的 arp 类型的数据帧 ETH_P_ARP 0x8035 只接受发往本机 mac 的 rarp 类型的数据帧 ETH_P_ALL 0x3 接收发往本机 mac 的所有类型 ip arp rarp 的数据帧, 接收从本机发出的所有类型的数据帧.(混杂模式打开的情况下,会接收到非发往 本地 mac 的数据帧) 发送的时候需要自己组织整个以太网数据帧.所有相关的地址使用 struct sockaddr_ll 而不是 struct sockaddr_in(因为协议簇是 PF_PACKET 不是 AF_INET 了),比如发送给某个机器,对方的地址需要使用 struct sockaddr_ll. 这种 socket 大小通吃,强悍 下面是一段相关的代码: . int sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL); struct sockaddr_ll sll; memset( sll.sll_family = AF_PACKET; struct ifreq ifstruct; strcpy(ifstruct.ifr_name, “eth0“); ioctl(sockfd, SIOCGIFINDEX, sll.sll_ifindex = ifstruct.ifr_ifindex; sll.sll_protocol = htons(ETH_P_ALL); if(bind(fd, (struct sockaddr *) int set_promisc(char *interface, int fd) struct ifreq ifr; strcpy(ifr.ifr_name, interface); if(ioctl(fd, SIOCGIFFLAGS, return -1; ifr.ifr_flags |= IFF_PROMISC; if(ioctl(fd, SIOCSIFFLAGS, return -1; return 0; int unset_promisc(char *interface, int fd) struct ifreq ifr; strcpy(ifr.ifr_name, interface); if(ioctl(fd, SIOCGIFFLAGS, return -1; ifr.ifr_flags if(ioctl(fd, SIOCSIFFLAGS, return -1; return 0; 3. socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL)这个最好不要用,反正 我不用. 总结使用方法: 1.只想收到发往本机某种协议的 ip 数据包的话用第一种就足够了 2. 更多的详细的内容请使用第二种.包括 ETH_P_ALL 参数和混杂 模式都可以使它的能力不断的加强. ps:很多自己的想法.虚拟机测试环境.有错欢迎指出交流 qq:110024218 我写的 ping #include “stdio.h“ #include “stdlib.h“ #include “string.h“ #include “unistd.h“ #include “sys/types.h“ #include “sys/socket.h“ #include “netinet/in.h“ #include “netinet/ip.h“ #include “netinet/ip_icmp.h“ #include “netdb.h“ #include “errno.h“ #include “arpa/inet.h“ #include “signal.h“ #include “sys/time.h“ extern int errno; int sockfd; struct sockaddr_in addr; /peer addr char straddr128; /peer addr ip(char*) char sendbuf2048; char recvbuf2048; int sendnum; int recvnum; int datalen = 30; unsigned short my_cksum(unsigned short *data, int len) int result = 0; for(int i=0; i 16)result = (result return result; void tv_sub(struct timeval* recvtime, const struct timeval* sendtime) int sec = recvtime-tv_sec - sendtime-tv_sec; int usec = recvtime-tv_usec - sendtime-tv_usec; if(usec = 0) recvtime-tv_sec = sec; recvtime-tv_usec = usec; else recvtime-tv_sec = sec-1; recvtime-tv_usec = -usec; void send_icmp() struct icmp* icmp = (struct icmp*)sendbuf; icmp-icmp_type = ICMP_ECHO; icmp-icmp_code = 0; icmp-icmp_cksum = 0; icmp-icmp_id = getpid(); /neednt use htons() call, because peer networking kernel didnt handle this data and wont make different meanings(bigdian litteldian) icmp-icmp_seq = +sendnum; /neednt use hotns() call too. gettimeofday(struct timeval*)icmp-icmp_data, NULL); int len = 8+datalen; icmp-icmp_cksum = my_cksum(unsigned short*)icmp, len); int retval = sendto(sockfd, sendbuf, len, 0, (struct sockaddr*) if(retval = -1) perror(“sendto()“); exit(-1); else / printf(“send icmp request to %s(%d) bytesn“, straddr, len); void recv_icmp() struct timeval *sendtime; struct timeval recvtime; for(;) int n = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, 0, 0); if(n = -1) if(errno = EINTR)continue; else perror(“recvfrom()“); exit(-1); else gettimeofday( struct ip *ip = (struct ip*)recvbuf; if(ip-ip_src.s_addr != addr.sin_addr.s_addr) / printf(“ip_src is not : %sn“, straddr); continue; struct icmp *icmp = (struct icmp*)(recvbuf + (ip- ip_hl)icmp_id != getpid() / printf(“icmp_id is not :%dn“, getpid(); continue; recvnum+; sendtime = (struct timeval*)icmp-icmp_data; tv_sub( printf(“imcp echo from %s(%dbytes)tttl=%dtseq=%dttime=%d.%06d sn“, straddr, n, ip-ip_ttl, icmp- icmp_seq, recvtime.tv_sec, recvtime.tv_usec); void catch_sigalrm(int signum) send_icmp(); alarm(1); void catch_sigint(int signum) printf(“nPing statics:send %d packets, recv %d packets, %d% lost.n“, sendnum, recvnum, (int)(float)(sendnum-recvnum)/sendnum)*100); exit(0); int main(int argc, char *argv) if(argc != 2) printf(“please use format: ping hostnamen“); exit(-1); sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if(sockfd = -1) perror(“socket()“); return -1; /* int sendbufsize = 180; socklen_t sendbufsizelen = sizeof(sendbufsize); if(setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, int recvbufsize; socklen_t recvbufsizelen; if(getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, */ memset( addr.sin_family = AF_INET; int retval = inet_pton(AF_INET, argv1, if(retval = -1 | retval = 0) struct hostent* host = gethostbyname(argv1); if(host = NULL) fprintf(stderr, “gethostbyname(%s):%sn“, argv1, strerror(errno); exit(-1); /* if(host-h_name !=

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论