原始套接字发送UDP
2022-09-23 本文已影响0人
二进制人类
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ether.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netpacket/packet.h>
#include <sys/ioctl.h>
struct UdpHdr {
u_int32_t source;
u_int32_t dest;
u_int8_t flag;
u_int8_t protocol;
u_int16_t len;
};
int SendTo(int sockfd, void *msg, int msg_len, char *eth_name)
{
int ret;
struct ifreq ethreq;
struct sockaddr_ll sll;
/* 获取网络接口类型 */
memset(ðreq, 0, sizeof(ethreq));
strncpy(ethreq.ifr_name, eth_name, IFNAMSIZ);
ret = ioctl(sockfd, SIOCGIFINDEX, ðreq);
if (ret == -1) {
perror("ioctl");
return -1;
}
/* 设置网络接口类型 */
memset(&sll, 0, sizeof(sll));
sll.sll_ifindex = ethreq.ifr_ifindex;
/* 发送数据 */
ret = sendto(sockfd, msg, msg_len, 0, (const struct sockaddr *)&sll, sizeof(sll));
if (ret == -1) {
perror("sendto");
return -1;
}
}
unsigned short checksum(unsigned short *buf, int len)
{
int nword = len / 2;
unsigned long sum;
if (len % 2 == 1)
nword++;
for (sum = 0; nword > 0; nword--)
{
sum += *buf;
buf++;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return ~sum;
}
int main()
{
int ret;
int sockfd;
int msg_len;
unsigned char msg[1024];
/* 创建原始套接字文件:基于链路层,可用于任意协议数据的收发 */
sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if(sockfd == -1) {
perror("socket");
return -1;
}
printf("sockfd = %d\n", sockfd);
/* 组以太网头部报文数据 */
char src_mac[] = {0x00, 0x0c, 0x29, 0x84, 0x0e, 0x96}; //源mac
char dest_mac[] = {0x00, 0xe0, 0x4c, 0x7b, 0x59, 0x17}; //目的mac
struct ether_header *ethead = (struct ether_header *)msg;
memcpy(ethead->ether_dhost, dest_mac, sizeof(dest_mac));
memcpy(ethead->ether_shost, src_mac, sizeof(src_mac));
ethead->ether_type = htons(0x0800);
/* 组IP报文数据 */
char src_ip[] = "10.7.181.10";
char dest_ip[] = "10.7.181.140";
char data[] = "hello raw send udp";
unsigned short data_len = strlen(data) + strlen(data) % 2; /* 数据的发送需要以偶数字节发送 */
struct iphdr *ipheader = (struct iphdr *)(msg+14);
ipheader->version = 4; /* 协议版本:4 = IPV4 */
ipheader->ihl = 5; /* 头部长度 */
ipheader->tos = 0; /* 服务类型 */
ipheader->tot_len = htons(20+8+data_len); /* IP报文数据总长度:20表示IP报文首部长度,8表示UDP报文首部长度,data_len需要发送数据的长度 */
ipheader->id = htons(0); /* 标识 */
ipheader->frag_off = htons(0); /* 偏移量 */
ipheader->ttl = 128; /* 生存时间 */
ipheader->protocol = 17; /* 协议类型:17 = UDP报文 */
ipheader->check = htons(0); /* 不是最后设置的值,只是占位用于数据的校验 */
ipheader->saddr = inet_addr(src_ip); /* 设置源IP */
ipheader->daddr = inet_addr(dest_ip); /* 设置目的IP */
/* IP头部检验和的设置 */
ipheader->check = checksum((unsigned short *)ipheader, 20);
/* 封装UDP报文的头部 */
struct udphdr * udpheader = (struct udphdr *)(msg+14+20);
udpheader->source = htons(8888);
udpheader->dest = htons(8080);
udpheader->len = htons(8+data_len);
udpheader->check = htons(0);
/* 封装需要发送的数据 */
memcpy(msg+14+20+8, data, data_len);
/* 伪首部:只用于头部校验,不用于数据的发送 */
char msg_buf[512];
struct UdpHdr *Udp_Hdr = (struct UdpHdr *)msg_buf;
Udp_Hdr->source = inet_addr(src_ip); /* 设置源IP */
Udp_Hdr->dest = inet_addr(dest_ip); /* 设置目的IP */
Udp_Hdr->flag = 0;
Udp_Hdr->protocol = 17; /* 协议类型:17 = UDP报文 */
Udp_Hdr->len = htons(8+data_len); /* UDP数据长度:8表示UDP头部长度,data_len需要发送数据的长度 */
memcpy(msg_buf+12, udpheader, 8+data_len);
/* 设置UDP头部校验和 */
udpheader->check = checksum((unsigned short *)msg_buf, 12+8+data_len);
/* 发送数据 */
SendTo(sockfd, msg, 14+20+8+data_len, "ens33");
}