您的位置:首页 > 运维架构 > Linux

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");
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: