原始套接字

This commit is contained in:
flykhan 2023-09-11 20:58:01 +08:00
parent 1b4be013eb
commit 1fac49bb9b
6 changed files with 515 additions and 0 deletions

22
day6/n1.c Normal file
View File

@ -0,0 +1,22 @@
/*创建链路层的原始套接字*/
#include <netinet/ether.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.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");
close(sock_fd);
return 0;
}

66
day6/n2.c Normal file
View File

@ -0,0 +1,66 @@
/*拆解到IP报文*/
#include <netinet/ether.h>
#include <netinet/in.h>
#include <sys/socket.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(src_mac, "%02x:%02x:%02x:%02x:%02x:%02x", buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]);
// 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]);
sprintf(dst_mac, "%02x:%02x:%02x:%02x:%02x:%02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
// if (strncmp(src_mac, "00:00:00", 8) != 0)
printf("dst_mac %s -> src_mac %s type(%#x)\n", dst_mac, src_mac, mac_type);
sleep(1);
switch (mac_type)
{
case 0x0800:
printf("-----ip 数据包-----\n");
break;
case 0x0806:
printf("-----ARP 数据包-----\n");
break;
case 0x8035:
printf("-----RARP 数据包-----\n");
break;
}
}
close(sock_fd);
return 0;
}

115
day6/n3.c Normal file
View File

@ -0,0 +1,115 @@
/*拆解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;
}

79
day6/n4.c Normal file
View File

@ -0,0 +1,79 @@
/*单播ARP应答*/
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ether.h>
#include <netpacket/packet.h>
#include <sys/ioctl.h>
#include <net/if.h> // ifreq
#include <unistd.h>
#include <string.h> // bzero
#include <stdio.h>
// 发送原始数据报
ssize_t send_datapacket(int fd, unsigned char *buf, ssize_t buf_size, const char *ether_name);
ssize_t send_datapacket(int fd, unsigned char *buf, ssize_t buf_size, const char *ether_name)
{
// 1. 获取网络接口类型(通过网卡名查找网卡索引)
struct ifreq ether_req;
bzero(&ether_req, sizeof(ether_req));
strncpy(ether_req.ifr_name, ether_name, IF_NAMESIZE); // # define ifr_name ifr_ifrn.ifrn_name
if (ioctl(fd, SIOCGIFINDEX, &ether_req) == -1)
{
perror("ioctl");
return -1;
}
// 2. 选择发送数据的网络接口索引(选择合适的网卡索引)
struct sockaddr_ll sll;
bzero(&sll, sizeof(sll));
sll.sll_ifindex = ether_req.ifr_ifindex; // # define ifr_ifindex ifr_ifru.ifru_ivalue
// 3. 发送数据
ssize_t len = sendto(fd, buf, buf_size, 0, (struct sockaddr *)&sll, sizeof(sll));
return len;
}
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;
}
// 组ARP应答报文(如果是ARP欺骗则源MAC为0x00,0x00,0x00,0x00,0x00,0x00)
uint32_t src_ip = inet_addr("10.12.156.204"); // 发送的 ip 地址
uint32_t dst_ip = inet_addr("10.12.156.178"); // 点分十进制转换为数字字符串
unsigned char *src_ip_p = (unsigned char *)&src_ip; // src_ip 的字符类型指针
unsigned char *dst_ip_p = (unsigned char *)&dst_ip;
unsigned char buf[] = {
0x00, 0x0c, 0x29, 0xf7, 0x81, 0x4c, /*目的MAC地址*/
0x00, 0x0c, 0x29, 0x85, 0xcc, 0x67, /* 源MAC地址 */
0x08, 0x06, /* ARP帧类型 */
0x00, 0x01, /* 硬件类型 */
0x08, 0x00, /* 协议类型(IP协议0x0800) */
0x06, 0x04, /* 硬件地址长度(MAC地址长度) 和 协议地址长度(IP 地址长度) */
0x00, 0x02, /* OP操作类型(ARP应答 = 2) */
0x00, 0x0c, 0x29, 0x85, 0xcc, 0x67, /* 发送端MAC地址 */
src_ip_p[0], src_ip_p[1], src_ip_p[2], src_ip_p[3], /* 源(发送端) IP 地址 */
0x00, 0x0c, 0x29, 0xf7, 0x81, 0x4c, /*接收端MAC地址*/
dst_ip_p[0], dst_ip_p[1], dst_ip_p[2], dst_ip_p[3] /* 接收端 IP 地址 */
};
// 单播发送ARP应答
ssize_t len = send_datapacket(sock_fd, buf, sizeof(buf), "ens38");
if (len > 0)
{
printf("send arp success! \n");
}
close(sock_fd);
return 0;
}

141
day6/n5.c Normal file
View File

@ -0,0 +1,141 @@
/*
IP地址的MAC信息
ARP请求报文for循环组成同一个网段的不同IP地址ARP报文信息
*/
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ether.h>
#include <netpacket/packet.h>
#include <sys/ioctl.h>
#include <net/if.h> // ifreq
#include <unistd.h>
#include <string.h> // bzero
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
// 发送原始数据报
ssize_t send_datapacket(int fd, unsigned char *buf, ssize_t buf_size, const char *ether_name);
void *recv_packetdata(void *arg)
{
// 创建原始套接字
int sock_fd = *((int *)arg);
while (1)
{
// 接链接层的数据报文
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] = "";
unsigned char src_mac[18] = "";
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 (mac_type == 0x0806) // 当类型为ARP时
{
printf("------ARP数据报-----\n");
unsigned char src_ip[16] = "";
unsigned char dst_ip[16] = "";
unsigned short op = ntohs(*((unsigned short *)(buf + 20)));
if (op == 2) // 只显示ARP应答的数据
{
// inet_ntop函数被用于将存储在buf + 28位置的二进制IPv4地址转换为字符串表示形式并将结果存储在src_ip变量中。
inet_ntop(AF_INET, (unsigned int *)(buf + 28), src_ip, 16);
inet_ntop(AF_INET, (unsigned int *)(buf + 38), dst_ip, 16);
printf("%s(%s) -> %s(%s)\n", src_mac, src_ip, dst_mac, dst_ip);
}
}
}
}
int main(int argc, char const *argv[])
{
// 创建原始套接字 // htons(ETH_P_ALL)的作用是将以太网协议号转换为网络字节序,以便在创建原始套接字时使用正确的协议号。
int sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sock_fd < 0)
{
perror("raw socket");
return -1;
}
// 创建接收数据报的线程
pthread_t tid;
pthread_create(&tid, NULL, recv_packetdata, &sock_fd);
// pthread_detach(tid);
// 组织ARP应答报文(如果是ARP欺骗则源MAC地址可以修改为全0或修改为其他用于伪装的MAC地址)
uint32_t src_ip = inet_addr("10.12.156.204");
// 扫描所有网内的IP的MAC地址
for (int i = 150; i < 253; i++)
// for (int i = 2; i < 255; i++)
{
unsigned char dst_ip_[16] = "";
sprintf(dst_ip_, "10.12.156.%d", i);
// inet_addr函数被用于将点分十进制表示的IPv4地址转换为32位无符号整数的网络字节序表示。
uint32_t dst_ip = inet_addr(dst_ip_);
unsigned char *src_ip_pointer = (unsigned char *)&src_ip; // 定义源地址ip指针
unsigned char *dst_ip_pointer = (unsigned char *)&dst_ip;
unsigned char buf[] = {
// 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 用于广播, 常用于扫描MAC地址
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /*目标MAC*/
0x00, 0x0c, 0x29, 0x85, 0xcc, 0x67, /*源MAC*/
0x08, 0x06, /*帧类型(ARP)*/
0x00, 0x01, /*硬件类型(以太网)*/
0x08, 0x00, /*协议类型(IP)*/
0x06, 0x04, /*硬件地址长度(6字节)和协议地址长度(4字节)*/
0x00, 0x01, /*操作类型(ARP请求)*/
0x00, 0x0c, 0x29, 0x85, 0xcc, 0x67, /*发送方MAC*/
src_ip_pointer[0], src_ip_pointer[1], src_ip_pointer[2], src_ip_pointer[3], /*发送方IP*/
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /*目标MAC*/
dst_ip_pointer[0], dst_ip_pointer[1], dst_ip_pointer[2], dst_ip_pointer[3] /*目标IP*/
};
// 单播(发送ARP请求): 通过网卡名查找网卡索引, 选择合适的网卡索引, 发送数据
ssize_t len = send_datapacket(sock_fd, buf, sizeof(buf), "ens38");
if (len > 0)
{
printf("发送ARP应答报文成功\n");
}
usleep(1000 * 1000);
}
pthread_join(tid, NULL);
close(sock_fd);
return 0;
}
ssize_t send_datapacket(int fd, unsigned char *buf, ssize_t buf_size, const char *ether_name)
{
// 1. 获取网络接口类型(通过网卡名查找网卡索引)
struct ifreq ether_req;
bzero(&ether_req, sizeof(ether_req));
strncpy(ether_req.ifr_name, ether_name, IF_NAMESIZE); // # define ifr_name ifr_ifrn.ifrn_name
if (ioctl(fd, SIOCGIFINDEX, &ether_req) == -1)
{
perror("ioctl");
return -1;
}
// 2. 选择发送数据的网络接口索引(选择合适的网卡索引)
struct sockaddr_ll sll;
bzero(&sll, sizeof(sll));
sll.sll_ifindex = ether_req.ifr_ifindex; // # define ifr_ifindex ifr_ifru.ifru_ivalue
// 3. 发送数据
ssize_t len = sendto(fd, buf, buf_size, 0, (struct sockaddr *)&sll, sizeof(sll));
return len;
}

92
day6/n6.c Normal file
View File

@ -0,0 +1,92 @@
/* ARP欺骗-练习3
ARP报文MAC地址的全置0.
*/
#include <arpa/inet.h> // inet_addr
#include <netinet/in.h> // in_addr
#include <netinet/ether.h> // ether_aton
#include <netpacket/packet.h> // sockaddr_ll
#include <sys/ioctl.h> // ioctl
#include <net/if.h> // ifreq
#include <unistd.h> // close
#include <string.h> // bzero
#include <stdio.h> // printf
#include <pthread.h> // pthread_create
#include <sys/types.h> // open
#include <sys/stat.h> // open
// 发送原始数据报
ssize_t send_datapacket(int fd, unsigned char *buf, ssize_t buf_size, const char *ether_name);
void *arp_packetdata_send(void *arg)
{
// 创建原始套接字
int sock_fd = *((int *)arg);
while (1)
{
// 发送ARP欺骗应答报文
unsigned char src_ip_pointer[] = {10, 12, 156, 204}; // 发送的 IP 地址
unsigned char dst_ip_pointer[] = {10, 12, 156, 178}; // 目标 IP 地址 点分十进制转换为数字字符串
unsigned char dst_mac[] = {0x00, 0xd8, 0x61, 0x03, 0x45, 0x65}; // 目标 MAC 地址
unsigned char arp_buf[] = {
dst_mac[0], dst_mac[1], dst_mac[2], dst_mac[3], dst_mac[4], dst_mac[5], // 目的MAC地址
// 00:0c:29:85:cc:67
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 源MAC地址
0x00, 0x0c, 0x29, 0x85, 0xcc, 0x67, // 源MAC地址
0x08, 0x06, // ARP帧类型
0x00, 0x01, // 硬件类型
0x08, 0x00, // 协议类型(IP协议0x0800)
0x06, 0x04, // 硬件地址长度(MAC地址长度) 和 协议地址长度(IP 地址长度)
0x00, 0x02, // 操作类型(ARP应答0x0002)
0x00, 0x0c, 0x29, 0x85, 0xcc, 0x67, // 发送方MAC地址
src_ip_pointer[0], src_ip_pointer[1], src_ip_pointer[2], src_ip_pointer[3], // 发送方IP地址
dst_mac[0], dst_mac[1], dst_mac[2], dst_mac[3], dst_mac[4], dst_mac[5], // 目的MAC地址
dst_ip_pointer[0], dst_ip_pointer[1], dst_ip_pointer[2], dst_ip_pointer[3] // 目的IP地址
};
// 单播发送ARP应答报文
ssize_t len = send_datapacket(sock_fd, arp_buf, sizeof(arp_buf), "ens38"); // ens38 为网卡名
}
}
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;
}
// 创建线程发送ARP欺骗应答报文
pthread_t tid;
pthread_create(&tid, NULL, arp_packetdata_send, &sock_fd);
pthread_join(tid, NULL);
close(sock_fd);
return 0;
}
ssize_t send_datapacket(int fd, unsigned char *buf, ssize_t buf_size, const char *ether_name)
{
// 1. 根据网卡名获取网卡索引
struct ifreq ether_req;
bzero(&ether_req, sizeof(ether_req)); // 清空结构体 ether_req
strncpy(ether_req.ifr_name, ether_name, IF_NAMESIZE); // # define ifr_name ifr_ifrn.ifrn_name // 将网卡名复制到 ether_req.ifr_name 中
// 通过网卡名查找网卡索引 SIOCGIFINDEX 为获取网卡索引
if (ioctl(fd, SIOCGIFINDEX, &ether_req) == -1)
{
perror("ioctl");
return -1;
}
// 2. 选择发送数据的网络接口索引
struct sockaddr_ll sll;
bzero(&sll, sizeof(sll)); // 清空结构体 sll
sll.sll_ifindex = ether_req.ifr_ifindex; // # define ifr_ifindex ifr_ifru.ifru_ivalue // 选择发送数据的网络接口索引
// 3. 发送数据
ssize_t len = sendto(fd, buf, buf_size, 0, (struct sockaddr *)&sll, sizeof(sll));
return len;
}