杨坤的分享空间
目录:
原始引用地址: test
time: 20210707
参考:
https://github.com/libnet/libnet/blob/master/sample/udp1.c
https://www.cnblogs.com/zhangshenghui/p/6097492.html
https://austinmarton.wordpress.com/2011/09/14/sending-raw-ethernet-packets-from-a-specific-interface-in-c-on-linux/
raw socket 可以发送原始数据,就是直接从网卡发送数据,不经过tcp/ip打包,看下wireshark抓包
直接上代码:
/******************************************************************************
*
* Filename: raw_socket1.c
*
* Description: 发送raw 网卡数据, 同一局域网下的pc运行wireshark抓包同时,运行此程序,就可以抓到上图中的数据包
*
* Version: 1.0
* Created: 2021年07月07日 20时27分51秒
* Revision: none
* Compiler: gcc
*
* Author: yangkun (yk)
* Email: [email protected]
* Company: yangkun.com
*
*****************************************************************************/
#include <net/ethernet.h> /* the L2 protocols */// ETH_P_ALL
#include <linux/if_packet.h>
#include <linux/if.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
// 发送mac层数据
int main()
{
struct sockaddr_ll stTagAddr;
memset(&stTagAddr, 0 , sizeof(stTagAddr));
stTagAddr.sll_family = AF_PACKET;//填写AF_PACKET,不再经协议层处理
stTagAddr.sll_protocol = htons(ETH_P_ALL);
int ret;
struct ifreq req;
int sd;
sd = socket(PF_INET, SOCK_DGRAM, 0);//这个sd就是用来获取eth0的index,完了就关闭
if(sd == -1)
{
printf("error to create socket pf_inet:%s\n", strerror(errno));
return -1;
}
// todo 此处需要更改为你使用的网卡名称
char *eth_name = "enp3s0";
strncpy(req.ifr_name, eth_name, strlen(eth_name));//通过设备名称获取index
ret=ioctl(sd, SIOCGIFINDEX, &req);
close(sd);
if (ret==-1)
{
printf("Get eth0 index err:%d=>%s \n", errno, strerror(errno));
return -1;
}
// int SockFd = socket(PF_PACKET, SOCK_RAW, htons(VSTRONG_PROTOCOL));
int SockFd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (-1 == SockFd)
{
printf("create socket error:%d.\n",errno);
return -11;
}
stTagAddr.sll_ifindex = req.ifr_ifindex;//网卡eth0的index,非常重要,系统把数据往哪张网卡上发,就靠这个标识
stTagAddr.sll_pkttype = PACKET_OUTGOING;//标识包的类型为发出去的包
stTagAddr.sll_halen = 6; //目标MAC地址长度为6
//填写目标MAC地址
stTagAddr.sll_addr[0] = 0x2c;
stTagAddr.sll_addr[1] = 0xf0;
stTagAddr.sll_addr[2] = 0x5d;
stTagAddr.sll_addr[3] = 0x6e;
stTagAddr.sll_addr[4] = 0x3e;
stTagAddr.sll_addr[5] = 0xa6;
//填充帧头和内容
char szbuff[20] = "abcdefg123456";
// 这样网卡会把sebuff中的内容发送出去
int i32Len = sendto(SockFd, (char *)szbuff, sizeof(szbuff), 0, (const struct sockaddr *)&stTagAddr, sizeof(stTagAddr));
if(-1 == i32Len)
{
printf("error to send data:errno=%d=>%s\n", errno, strerror(errno));
return -1;
}
}
接收端wireshark抓包
代码如下:
/******************************************************************************
*
* Filename: raw_socket2.c
*
* Description: 发送raw 网卡数据
*
* Version: 2.0
* Created: 2021年07月07日 20时27分51秒
* Revision: none
* Compiler: gcc
*
* Author: yangkun (yk)
* Email: [email protected]
* Company: yangkun.com
*
*****************************************************************************/
#include <net/ethernet.h> /* the L2 protocols */// ETH_P_ALL
#include <linux/if_packet.h>
#include <linux/if.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <netinet/ip.h> // ip head
#include <netinet/udp.h> // udp head
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
// 校验和函数
unsigned short csum(unsigned short *buf, int nwords)
{
unsigned long sum;
for(sum=0; nwords>0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum &0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);
}
// 发送mac层数据
int main()
{
struct sockaddr_ll stTagAddr;
memset(&stTagAddr, 0 , sizeof(stTagAddr));
stTagAddr.sll_family = AF_PACKET;//填写AF_PACKET,不再经协议层处理
stTagAddr.sll_protocol = htons(ETH_P_ALL);
int ret;
struct ifreq req;
int sd;
sd = socket(PF_INET, SOCK_DGRAM, 0);//这个sd就是用来获取eth0的index,完了就关闭
if(sd == -1)
{
printf("error to create socket pf_inet:%s\n", strerror(errno));
return -1;
}
// todo 此处需要更改为你使用的网卡名称
char *eth_name = "enp3s0";
strncpy(req.ifr_name, eth_name, strlen(eth_name));//通过设备名称获取index
ret=ioctl(sd, SIOCGIFINDEX, &req);
if(ret <0)
{
perror("SIOCGIFHWADDR");
return -1;
}
// 获取mac地址
struct ifreq if_mac;
memset(&if_mac, 0, sizeof(struct ifreq));
strncpy(if_mac.ifr_name, eth_name, strlen(eth_name));
if (ioctl(sd, SIOCGIFHWADDR, &if_mac) < 0)
{
perror("SIOCGIFHWADDR");
return -1;
}
close(sd);
if (ret==-1)
{
printf("Get eth0 index err:%d=>%s \n", errno, strerror(errno));
return -1;
}
// int SockFd = socket(PF_PACKET, SOCK_RAW, htons(VSTRONG_PROTOCOL));
int SockFd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (-1 == SockFd)
{
printf("create socket error:%d.\n",errno);
return -11;
}
stTagAddr.sll_ifindex = req.ifr_ifindex;//网卡eth0的index,非常重要,系统把数据往哪张网卡上发,就靠这个标识
stTagAddr.sll_pkttype = PACKET_OUTGOING;//标识包的类型为发出去的包
stTagAddr.sll_halen = 6; //目标MAC地址长度为6
//填写目标MAC地址
stTagAddr.sll_addr[0] = 0x2c;
stTagAddr.sll_addr[1] = 0xf0;
stTagAddr.sll_addr[2] = 0x5d;
stTagAddr.sll_addr[3] = 0x6e;
stTagAddr.sll_addr[4] = 0x3e;
stTagAddr.sll_addr[5] = 0xa6;
//填充帧头和内容
// 构造ethernet header
int tx_len = 0;
char sendbuf[1024];
struct ether_header *eh = (struct ether_header *) sendbuf;
memset(sendbuf, 0, 1024);
/* Ethernet header */
// 此处应该根据源mac 和 目的mac做更改
eh->ether_shost[0] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[0];
eh->ether_shost[1] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[1];
eh->ether_shost[2] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[2];
eh->ether_shost[3] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[3];
eh->ether_shost[4] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[4];
eh->ether_shost[5] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[5];
eh->ether_dhost[0] = 0x2c;
eh->ether_dhost[1] = 0xf0;
eh->ether_dhost[2] = 0x5d;
eh->ether_dhost[3] = 0x6e;
eh->ether_dhost[4] = 0x3e;
eh->ether_dhost[5] = 0xa6;
eh->ether_type = htons(ETH_P_IP);
tx_len += sizeof(struct ether_header);
// 构造ip 头
struct iphdr *iph = (struct iphdr *) (sendbuf + sizeof(struct ether_header));
int ttl = 20;
/* IP Header */
iph->ihl = 5;
iph->version = 4;
iph->tos = 16; // Low delay
iph->id = htons(54321);
iph->ttl = ttl; // hops
iph->protocol = 17; // UDP
/* Source IP address, can be spoofed */
//iph->saddr = inet_addr(inet_ntoa(((struct sockaddr_in *)&if_ip.ifr_addr)->sin_addr));
// 此处要更改源ip和目的ip
iph->saddr = inet_addr("172.20.2.7");
/* Destination IP address */
iph->daddr = inet_addr("172.20.2.76");
tx_len += sizeof(struct iphdr);
// 构建udp 数据头
struct udphdr *udph = (struct udphdr *) (sendbuf + sizeof(struct iphdr) + sizeof(struct ether_header));
/* UDP Header */
// 源端口, 目的端口
udph->source = htons(3423);
udph->dest = htons(5342);
udph->check = 0; // skip
tx_len += sizeof(struct udphdr);
//udp 数据
/* Packet data */
sendbuf[tx_len++] = 0xde;
sendbuf[tx_len++] = 0xad;
sendbuf[tx_len++] = 0xbe;
sendbuf[tx_len++] = 0xef;
// 填充头校验信息
/* Length of UDP payload and header */
udph->len = htons(tx_len - sizeof(struct ether_header) - sizeof(struct iphdr));
/* Length of IP payload and header */
iph->tot_len = htons(tx_len - sizeof(struct ether_header));
/* Calculate IP checksum on completed header */
iph->check = csum((unsigned short *)(sendbuf+sizeof(struct ether_header)), sizeof(struct iphdr)/2);
// 这样网卡会把sebuff中的内容发送出去
int i32Len = sendto(SockFd, (char *)sendbuf, tx_len, 0, (const struct sockaddr *)&stTagAddr, sizeof(stTagAddr));
if(-1 == i32Len)
{
printf("error to send data:errno=%d=>%s\n", errno, strerror(errno));
return -1;
}
}