qfedu-network-advanced-level/day6/n3.c

116 lines
4.2 KiB
C
Raw Normal View History

2023-09-11 20:58:01 +08:00
/*拆解UDP数据报*/
#include <netinet/ether.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char const *argv[])
{
// 创建原始套接字
int sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sock_fd < 0)
{
perror("raw socket");
return -1;
}
printf("原始套接字创建成功\n");
// 多次接收数据
while (1)
{
// 接链路层的数据报文(MAC报文)
unsigned char buf[1518] = ""; // 记得使用无符号类型
int len = recvfrom(sock_fd, buf, sizeof(buf), 0, NULL, NULL);
if (len < 18)
{
perror("recvfrom");
continue;
}
// 拆解 MAC 数据报文
unsigned char dst_mac[18] = ""; // 目的MAC地址
unsigned char src_mac[18] = ""; // 源MAC地址
unsigned short mac_type = ntohs(*((unsigned short *)(buf + 12)));
sprintf(dst_mac, "%02x:%02x:%02x:%02x:%02x:%02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
sprintf(src_mac, "%02x:%02x:%02x:%02x:%02x:%02x", buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]);
if (strncmp(src_mac, "00:00:00", 8) != 0)
printf("src_mac %s -> dst_mac %s type(%#x)\n", src_mac, dst_mac, mac_type);
// sleep(1);
// usleep(5);
switch (mac_type)
{
case 0x0800:
printf("-----ip 数据包-----\n");
// 拆解IP数据报
unsigned char *ip_buf = buf + 14;
// 读取IP首部长度: 单位是 4 字节
unsigned char ip_head_len = (ip_buf[0] & 0x0f) * 4;
printf("IP数据报的首部长度: %d\n", ip_head_len);
unsigned char ip_type = ip_buf[9]; // 协议类型
// 读取源IP和目的IP
unsigned char src_ip[INET_ADDRSTRLEN] = ""; // 源IP
unsigned char dst_ip[INET_ADDRSTRLEN] = ""; // 目的IP
inet_ntop(AF_INET, (unsigned int *)(ip_buf + 12), src_ip, INET_ADDRSTRLEN);
inet_ntop(AF_INET, (unsigned int *)(ip_buf + 16), dst_ip, INET_ADDRSTRLEN);
printf("src_ip: %s -> dst_ip: %s \n", src_ip, dst_ip);
if (ip_type == 1)
{
printf("\t------ICMP 数据报-----\n");
}
else if (ip_type == 2)
{
printf("\t------IGMP 数据报-----\n");
}
else if (ip_type == 6)
{
printf("\t------TCP 数据报-----\n");
// 拆解TCP的数据报
unsigned char *tcp_buf = ip_buf + ip_head_len; // 取出TCP的报文
unsigned short src_port = ntohs(*((unsigned short *)(tcp_buf))); // 源端口
unsigned short dst_port = ntohs(*((unsigned short *)(tcp_buf + 2))); // 目的端口
printf("\tsrc_port: %d -> dst_port: %d\n", src_port, dst_port);
// TCP 的数据报
}
else if (ip_type == 17)
{
printf("\t------UDP 数据报-----\n");
// 拆解UDP的数据报
unsigned char *udp_buf = ip_buf + ip_head_len; // 取出UDP的报文
unsigned short src_port = ntohs(*((unsigned short *)udp_buf));
unsigned short dst_port = ntohs(*((unsigned short *)(udp_buf + 2)));
printf("\tsrc_port: %d -> dst_port: %d\n", src_port, dst_port);
// UDP 的数据报长度: 由首部+数据长度(偶数)组成
unsigned short udp_buf_len = ntohs(*((unsigned short *)(udp_buf + 4))); // ntohs 用于大端转小端
int udp_date_size = udp_buf_len - 8;
char udp_date[128] = ""; // UDP 数据部分
strncpy(udp_date, udp_buf + 8, udp_buf_len - 8);
printf("\t\t %d -> %d data: %s\n", src_port, dst_port, udp_date);
}
break;
case 0x0806:
printf("-----ARP 数据包-----\n");
break;
case 0x8035:
printf("-----RARP 数据包-----\n");
break;
}
}
close(sock_fd);
return 0;
}