linux 接收udp组播数据包后反馈链路层数据
2017-03-28 16:56
411 查看
这个是借鉴了网上代码,然后自己总结了一下
#include <string.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <pthread.h> #include <linux/if_packet.h> #include <linux/if_ether.h> #include <arpa/inet.h> #include <netdb.h> // struct addrinfo #include <sys/types.h> // needed for socket(), uint8_t, uint16_t, uint32_t #include <sys/socket.h> // needed for socket() #include <netinet/in.h> // IPPROTO_ICMP, INET_ADDRSTRLEN #include <netinet/ip.h> // struct ip and IP_MAXPACKET (which is 65535) #include <netinet/ip_icmp.h> // struct icmp, ICMP_ECHO #include <arpa/inet.h> // inet_pton() and inet_ntop() #include <sys/ioctl.h> // macro ioctl is defined #include <bits/ioctls.h> // defines values for argument "request" of ioctl. #include <net/if.h> // struct ifreq #include <linux/if_ether.h> // ETH_P_IP = 0x0800, ETH_P_IPV6 = 0x86DD #include <linux/if_packet.h> // struct sockaddr_ll (see man 7 packet) #include <net/ethernet.h> #include <errno.h> // errno, perror() #define BUFFER_MAX 2048 #define ETH_P_DEAN 2088 uint8_t dst_mac[6]; char interface[16]; int sendData() { int i, datalen,frame_length, sd, bytes; //char *interface="eth0"; uint8_t data[IP_MAXPACKET]; uint8_t src_mac[6]; //uint8_t src_ip[]; in_addr_t src_ipaddr; uint8_t ether_frame[IP_MAXPACKET]; struct sockaddr_ll device; struct ifreq ifr; struct sockaddr_in sin; // Submit request for a socket descriptor to look up interface. //第一次创建socket是为了获取本地网卡信息 if ((sd = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) { perror ("socket() failed to get socket descriptor for using ioctl() "); exit (EXIT_FAILURE); } // Use ioctl() to look up interface name and get its MAC address. memset (&ifr, 0, sizeof (ifr)); snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "%s", interface); //SIOCGIFADDR 获取interface address if (ioctl(sd, SIOCGIFADDR, &ifr) >= 0) { memcpy(&sin, &ifr.ifr_addr, sizeof(ifr.ifr_addr)); src_ipaddr = sin.sin_addr.s_addr; printf("\n\nip:%x %s\n", sin.sin_addr.s_addr,inet_ntoa(sin.sin_addr)); } if (ioctl (sd, SIOCGIFHWADDR, &ifr) < 0) { perror ("ioctl() failed to get source MAC address "); return (EXIT_FAILURE); } close (sd); // Copy source MAC address. memcpy (src_mac, ifr.ifr_hwaddr.sa_data, 6); // Report source MAC address to stdout. printf ("\n\nMAC address for interface %s is ", interface); for (i=0; i<5; i++) { printf ("%02x:", src_mac[i]); } printf ("%02x\n", src_mac[5]); // Find interface index from interface name and store index in // struct sockaddr_ll device, which will be used as an argument of sendto(). memset (&device, 0, sizeof (device)); if ((device.sll_ifindex = if_nametoindex (interface)) == 0) { perror ("if_nametoindex() failed to obtain interface index "); exit (EXIT_FAILURE); } printf ("Index for interface %s is %i\n", interface, device.sll_ifindex); // Fill out sockaddr_ll. device.sll_family = AF_PACKET; memcpy (device.sll_addr, src_mac, 6); device.sll_halen = htons (6); // 发送的data,长度可以任意,但是抓包时看到最小数据长度为46,这是以太网协议规定 //以太网帧数据域部分最小为46字节,不足的自动补零处理 datalen = 12; data[0] = src_ipaddr & 0x000000ff; src_ipaddr>>=8; data[1] = src_ipaddr & 0x000000ff; src_ipaddr>>=8; data[2] = src_ipaddr & 0x000000ff; src_ipaddr>>=8; data[3] = src_ipaddr & 0x000000ff; data[4] = ' '; data[5] = ' '; data[6] = ' '; data[7] = ' '; data[8] = ' '; data[9] = ' '; data[10] = ' '; data[11] = ' '; char * ip_addr = inet_ntoa(sin.sin_addr); // Fill out ethernet frame header. frame_length = 6 + 6 + 2 + datalen; // Destination and Source MAC addresses memcpy (ether_frame, dst_mac, 6); memcpy (ether_frame + 6, src_mac, 6); ether_frame[12] = ETH_P_DEAN / 256; ether_frame[13] = ETH_P_DEAN % 256; // data memcpy (ether_frame + 14 , data, datalen); for(int i = 0; i < 16; i++){ printf("%.2x ", data[i]); } printf("\n"); // Submit request for a raw socket descriptor. if ((sd = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) {//创建正真发送的socket perror ("socket() failed "); exit (EXIT_FAILURE); } // Send ethernet frame to socket. if ((bytes = sendto (sd, ether_frame, frame_length, 0, (struct sockaddr *) &device, sizeof (device))) <= 0) { perror ("sendto() failed"); exit (EXIT_FAILURE); } printf ("send num=%d,read num=%d\n",frame_length,bytes); // Close socket descriptor. close (sd); return (EXIT_SUCCESS); } int main(int argc, char *argv[]) { if(argc ==1){ memcpy (interface, "eth0", 4); }else{ strcpy(interface, argv[1]); //interface = argv[1]; } int sock, n_read; char buffer[BUFFER_MAX]; char *eth_head; if((sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) { fprintf(stdout, "create socket error\n"); exit(0); } while(1) { struct sockaddr_in clientAddr; int n; socklen_t len = sizeof(clientAddr); n_read = recvfrom(sock, buffer, 2048, 0, (struct sockaddr*)&clientAddr, &len); if(n_read < 42) { fprintf(stdout, "Incomplete header, packet corrupt\n"); continue; } if(n_read > 100){ continue; } eth_head = buffer; if(eth_head[23] == 0x11 && eth_head[34] == 0x06 &ð_head[35] == 0x22){ printf("\n----------------1570 port---------------------\n"); int i=0; for(i=0;i<n_read;i++){ printf("%.2X ",(unsigned char)eth_head[i]); if(((i+1)%16)==0) printf("\n"); } for(int index = 6; index < 12; index++){ dst_mac[index-6] = eth_head[index];//设置目的网卡地址 } sendData(); printf("\n-----------------------------------------------\n"); } } }
相关文章推荐
- linux下使用C语言接收和发送udp组播数据分别怎么写?
- GCDAsyncUdpSocket 组播监听端口接收数据
- linux udp 客户端recvfrom,一直没有数据接收,谁能帮看看这代码哪里出了问题了????
- 查看返回接收到UDP数据包的宿地址结构--(适用于LINUX和BSD系统)
- Linux下发送与接收组播数据(socket编程)
- linux udp组播接收问题及原理分析
- Linux网络编程-UDP接收数据丢包解决方案
- 在Linux上,编写一个每秒接收100万UDP数据包的程序究竟有多难
- java发送接收组播(多播)数据包(UDP包)
- linux udp组播接收问题及原理分析
- Linux下发送与接收组播数据(socket编程)
- 中标麒麟(linux)下QUdpSocket无法使用组播发送数据问题
- Linux网络编程-UDP数据阻塞接收超时设置
- Linux网络编程-UDP接收数据丢包解决方案
- 在Linux 上,编写一个每秒接收 100万UDP数据包的程序究竟有多难?
- Linux下发送与接收组播数据(socket编程)
- linux实用PF_PACKET接收原始链路层数据包
- 在Linux 上,编写一个每秒接收 100万UDP数据包的程序究竟有多难?
- GCDAsyncUdpSocket 组播监听端口接收数据
- linux实用PF_PACKET接收原始链路层数据包