一、报文格式
信息传递:ubuntu---->windows
二、组包
①组MAC报头
struct ether_header *eth_addr = (struct ether_header *)msg;
memcpy(eth_addr->ether_dhost, dst_mac, 6);
memcpy(eth_addr->ether_shost, src_mac, 6);
eth_addr->ether_type = htons(0x0800);
②组IP报头 所在位置/usr/include/netinet/ip.h> 头文件#include <netinet/ip.h> 在结构体定义时,若成员类型为u_int16_t则为2个字节,需要用htons函数。
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;
}
struct iphdr *ip_hdr = (struct iphdr *)(msg+14);
ip_hdr->verson = 4;
ip_hdr->ihl = 5;
ip_hdr->tos = 0;
ip_hdr->tot_len = htons(20+8+data_len);
ip_hdr->id = htons(0);
ip_hdr->frag_off = htons(0);
ip_hdr->ttl = 128;
ip_hdr->protocol = 17;
ip_hdr->check = htons(0);
memcpy(&ip_hdr->saddr,src_ip,4);
memcpy(&ip_hdr->daddr,dst_ip,4);
ip_hdr->check = checksum(ip_hdr,20);
③组UDP报头 所在位置/usr/include/netinet/udp.h> 头文件#include <netinet/udp.h> UDP校验方式: 1.在对UDP校验的时候需要在UDP报文之间加上伪头部,IP校验时不需要伪头部。 注意:伪头部的源IP、目的IP必须和IP报文中源IP、目的IP一致。 如图所示: 在UDP前加伪头部,校验后在赋值回UDP结构体中的check; 创建伪首部结构体:
typedef struct
{
u_int32_t saddr;
u_int32_t daddr;
u_int8_t flag;
u_int8_t type;
u_int16_t len;
}WEIHDR;
伪头部校验:
unsigned char wei_head[256]="";
WEIHDR *wei_hdr = (WEIHDR *)wei_head;
memcpy(&wei_hdr->saddr,src_ip,4);
memcpy(&wei_hdr->daddr,dst_ip,4);
wei_hdr->flag = 0;
wei_hdr->type = 17;
wei_hdr->len = htons(8+data_len);
memcpy(wei_head+12, udp_hdr, 8+data_len);
udp_hdr->check = checksum(wei_head, 12+8+data_len);
组UDP头部
struct udphdr *udp_hdr = (struct udphdr *)(msg+14+20);
udp_hdr->source = htons(8000);
udp_hdr->dest = htons(9000);
udp_hdr->len = htons(8+data_len);
udp_hdr->check = htons(0);
memcpy(msg+14+20+8, data ,data_len);
④应用层数据
my_sendto(sockfd, "enp0s3", msg, 14+20+8+data_len);
三、代码
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ether.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netpacket/packet.h>
#include <unistd.h>
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
typedef struct
{
u_int32_t saddr;
u_int32_t daddr;
u_int8_t flag;
u_int8_t type;
u_int16_t len;
}WEIHDR;
void my_sendto(int sockfd, char *out, unsigned char *msg, int msg_len)
{
struct ifreq ethreq;
strncpy(ethreq.ifr_name, "out", 16);
if( -1 == ioctl(sockfd, SIOCGIFINDEX, ðreq))
{
perror("ioctl");
close(sockfd);
_exit(-1);
}
struct sockaddr_ll sll;
bzero(&sll, sizeof(sll));
sll.sll_ifindex = ethreq.ifr_ifindex;
sendto(sockfd, msg, msg_len, 0, (struct sockaddr *)&sll, sizeof(sll));
}
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 sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if(sockfd <0)
{
perror("socket");
return 0;
}
printf("请输入要发送的消息:\n");
char data[128]="";
fgets(data,sizeof(data),stdin);
data[strlen(data)-1]=0;
int data_len = strlen(data);
if( data_len%2 != 0){
data_len++;
}
unsigned char dst_mac[6]={0x80,0xC5,0xF2,0xB9,0x8C,0x03};
unsigned char src_mac[6]={0x08,0x00,0x27,0x2d,0x9b,0x84};
unsigned char src_ip[4]={192,168,199,208};
unsigned char dst_ip[4]={192,168,199,233};
unsigned char msg[1024]="";
struct ether_header *eth_addr = (struct ether_header *)msg;
memcpy(eth_addr->ether_dhost, dst_mac, 6);
memcpy(eth_addr->ether_shost, src_mac, 6);
eth_addr->ether_type = htons(0x0800);
struct iphdr *ip_hdr = (struct iphdr *)(msg+14);
ip_hdr->version = 4;
ip_hdr->ihl = 5;
ip_hdr->tos = 0;
ip_hdr->tot_len = htons(20+8+data_len);
ip_hdr->id = htons(0);
ip_hdr->frag_off = htons(0);
ip_hdr->ttl = 128;
ip_hdr->protocol = 17;
ip_hdr->check = htons(0);
memcpy(&ip_hdr->saddr,src_ip,4);
memcpy(&ip_hdr->daddr,dst_ip,4);
ip_hdr->check = checksum(ip_hdr,20);
struct udphdr *udp_hdr = (struct udphdr *)(msg+14+20);
udp_hdr->source = htons(8000);
udp_hdr->dest = htons(9000);
udp_hdr->len = htons(8+data_len);
udp_hdr->check = htons(0);
memcpy(msg+14+20+8, data ,data_len);
unsigned char wei_head[256]="";
WEIHDR *wei_hdr = (WEIHDR *)wei_head;
memcpy(&wei_hdr->saddr,src_ip,4);
memcpy(&wei_hdr->daddr,dst_ip,4);
wei_hdr->flag = 0;
wei_hdr->type = 17;
wei_hdr->len = htons(8+data_len);
memcpy(wei_head+12, udp_hdr, 8+data_len);
udp_hdr->check = checksum(wei_head, 12+8+data_len);
memcpy(udp_hdr+8,data,data_len);
my_sendto(sockfd, "enp0s3", msg, 14+20+8+data_len);
close(sockfd);
return 0;
}
四、测试
运行
|