C中的原始套接字数据包接收器,奇怪的输出
Raw socket packet receiver in C, strange output
我使用原始套接字编写了一个简单的数据包接收器,但我得到了奇怪的输出,f.e.:
Received packet: size: 124, type: PACKET_HOST (0)
Sender info: Name: n003-000-000-000.static.ge.com, IP: 3.0.0.0
Data:
74 2f 68 3c d1 9f 00 37 b7 d1 5a a7 08 00 45 00 00 6e 00 00 40
00 40 11 b6 e9 c0 a8 01 01 c0 a8 01 44 00 35 94 08 00 5a 3b aa
e1 78 81 80 00 01 00 01 00 00 00 00 01 30 01 30 01 30 01 33 07
69 6e 2d 61 64 64 72 04 61 72 70 61 00 00 0c 00 01 c0 0c 00 0c
00 01 00 00 65 95 00 20 10 6e 30 30 33 2d 30 30 30 2d 30 30 30
2d 30 30 30 06 73 74 61 74 69 63 02 67 65 03 63 6f 6d 00
当我浏览互联网时,数据包变大了,但主机名和地址保持不变或几乎相同。
谁能帮我找出问题所在?
代码如下:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/if_ether.h>
#include <netdb.h>
#include <linux/if_packet.h>
#include <netinet/ether.h>
#define PACKET_SIZE 1 << 16
void usage();
void packetTypeToStr(int type, char *str);
int main(int argc, char **argv) {
const char *iface_name;
if (argc == 2) {
iface_name = argv[1];
} else if (argc > 2) {
usage();
return 1;
} else {
iface_name = "wlan0";
}
// Opening socket in raw mode
int socketFileDesc = 0;
if ((socketFileDesc = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
perror("socket");
return errno;
}
printf("Opened raw socket\n");
// Acquiring the index of the interface
struct ifreq iface;
memset(&iface, 0, sizeof(struct ifreq));
strncpy(iface.ifr_name, iface_name, strlen(iface_name) + 1);
if (ioctl(socketFileDesc, SIOCGIFINDEX, &iface) < 0) {
perror("SIOCGIFINDEX");
usage();
close(socketFileDesc);
return errno;
}
int index = iface.ifr_ifindex;
printf("Index of the interface %s: %d\n", iface_name, index);
// Acquiring the mac address of the interface
struct ifreq iface_mac;
memset(&iface_mac, 0, sizeof(struct ifreq));
strncpy(iface_mac.ifr_name, iface_name, strlen(iface_name) + 1);
if (ioctl(socketFileDesc, SIOCGIFHWADDR, &iface_mac) < 0) {
perror("SIOCGIFHWADDR");
usage();
close(socketFileDesc);
return errno;
}
printf("MAC address of the interface %s: %s\n", iface_name, ether_ntoa((struct ether_addr*)iface_mac.ifr_hwaddr.sa_data));
// Setting interface in promiscuous mode
struct ifreq iface_options;
memset(&iface_options, 0, sizeof(struct ifreq));
strncpy(iface_options.ifr_name, iface_name, strlen(iface_name) + 1);
if (ioctl(socketFileDesc, SIOCGIFFLAGS, &iface_options) < 0) {
perror("SIOCGIFFLAGS");
close(socketFileDesc);
return errno;
}
iface_options.ifr_flags |= IFF_PROMISC;
if (ioctl(socketFileDesc, SIOCSIFFLAGS, &iface_options) < 0) {
perror("SIOCGIFFLAGS");
close(socketFileDesc);
return errno;
}
printf("Interface %s set in promiscuous mode\n", iface_name);
// Binding socket to the interface
struct sockaddr_ll socketAddress;
memset(&socketAddress, 0, sizeof(socketAddress));
socketAddress.sll_family = AF_PACKET;
socketAddress.sll_protocol = htons(ETH_P_ALL);
socketAddress.sll_ifindex = index;
if (bind(socketFileDesc, (struct sockaddr *) &socketAddress, sizeof(socketAddress)) < 0) {
perror("bind");
close(socketFileDesc);
return errno;
}
printf("Socket bound to the interface: %s\nWaiting for packets...\n", iface_name);
// Receiving packets in a loop
while (1) {
ssize_t n = 0;
uint8_t packet[PACKET_SIZE];
bzero(packet, sizeof(packet));
struct sockaddr_in address;
socklen_t length = sizeof(address);
if ((n = recvfrom(socketFileDesc, packet, sizeof(packet), 0, (struct sockaddr *) &address, &length)) < 0) {
perror("recvfrom");
close(socketFileDesc);
return errno;
}
// Null-terminated data
if (n > 0)
packet[n - 1] = '[=11=]';
else
continue;
// IP address
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(address.sin_addr), ip, length);
// Host name
struct hostent *host = gethostbyaddr(&(address.sin_addr), length, AF_INET);
if (host == NULL) {
herror("gethostbyaddr");
return h_errno;
}
const char *hostName = host->h_name;
// Packet type
char packetType[BUFSIZ];
int type = ((struct sockaddr_ll *) &address)->sll_pkttype;
packetTypeToStr(type, packetType);
// Printing info and data
printf("\n\nReceived packet: size: %li, type: %s\n"
"Sender info: Name: %s, IP: %s\n",
n, packetType, hostName, ip);
printf("Data:\n");
int i = 0;
for (; i < n; ++i)
printf("%02x ", packet[i]);
}
return 0;
}
由于您正在接收原始数据包 recvfrom()
不能 return IP 地址,因为数据通常可能不是互联网数据包。例如,它可能只是一个任意的以太网数据包,它是从一些根本没有 TCP/IP 堆栈的设备发送的。可能 recvfrom()
将传递的 sockaddr 指针视为 struct sockaddr_ll *
和 return 的物理层地址。
您可以尝试通过解析接收到的数据包来获取正确的IP地址。如果它真的是 IP 数据包 - 它将包含所有 headers,以及源地址和目标地址。
我使用原始套接字编写了一个简单的数据包接收器,但我得到了奇怪的输出,f.e.:
Received packet: size: 124, type: PACKET_HOST (0)
Sender info: Name: n003-000-000-000.static.ge.com, IP: 3.0.0.0
Data:
74 2f 68 3c d1 9f 00 37 b7 d1 5a a7 08 00 45 00 00 6e 00 00 40
00 40 11 b6 e9 c0 a8 01 01 c0 a8 01 44 00 35 94 08 00 5a 3b aa
e1 78 81 80 00 01 00 01 00 00 00 00 01 30 01 30 01 30 01 33 07
69 6e 2d 61 64 64 72 04 61 72 70 61 00 00 0c 00 01 c0 0c 00 0c
00 01 00 00 65 95 00 20 10 6e 30 30 33 2d 30 30 30 2d 30 30 30
2d 30 30 30 06 73 74 61 74 69 63 02 67 65 03 63 6f 6d 00
当我浏览互联网时,数据包变大了,但主机名和地址保持不变或几乎相同。
谁能帮我找出问题所在?
代码如下:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/if_ether.h>
#include <netdb.h>
#include <linux/if_packet.h>
#include <netinet/ether.h>
#define PACKET_SIZE 1 << 16
void usage();
void packetTypeToStr(int type, char *str);
int main(int argc, char **argv) {
const char *iface_name;
if (argc == 2) {
iface_name = argv[1];
} else if (argc > 2) {
usage();
return 1;
} else {
iface_name = "wlan0";
}
// Opening socket in raw mode
int socketFileDesc = 0;
if ((socketFileDesc = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
perror("socket");
return errno;
}
printf("Opened raw socket\n");
// Acquiring the index of the interface
struct ifreq iface;
memset(&iface, 0, sizeof(struct ifreq));
strncpy(iface.ifr_name, iface_name, strlen(iface_name) + 1);
if (ioctl(socketFileDesc, SIOCGIFINDEX, &iface) < 0) {
perror("SIOCGIFINDEX");
usage();
close(socketFileDesc);
return errno;
}
int index = iface.ifr_ifindex;
printf("Index of the interface %s: %d\n", iface_name, index);
// Acquiring the mac address of the interface
struct ifreq iface_mac;
memset(&iface_mac, 0, sizeof(struct ifreq));
strncpy(iface_mac.ifr_name, iface_name, strlen(iface_name) + 1);
if (ioctl(socketFileDesc, SIOCGIFHWADDR, &iface_mac) < 0) {
perror("SIOCGIFHWADDR");
usage();
close(socketFileDesc);
return errno;
}
printf("MAC address of the interface %s: %s\n", iface_name, ether_ntoa((struct ether_addr*)iface_mac.ifr_hwaddr.sa_data));
// Setting interface in promiscuous mode
struct ifreq iface_options;
memset(&iface_options, 0, sizeof(struct ifreq));
strncpy(iface_options.ifr_name, iface_name, strlen(iface_name) + 1);
if (ioctl(socketFileDesc, SIOCGIFFLAGS, &iface_options) < 0) {
perror("SIOCGIFFLAGS");
close(socketFileDesc);
return errno;
}
iface_options.ifr_flags |= IFF_PROMISC;
if (ioctl(socketFileDesc, SIOCSIFFLAGS, &iface_options) < 0) {
perror("SIOCGIFFLAGS");
close(socketFileDesc);
return errno;
}
printf("Interface %s set in promiscuous mode\n", iface_name);
// Binding socket to the interface
struct sockaddr_ll socketAddress;
memset(&socketAddress, 0, sizeof(socketAddress));
socketAddress.sll_family = AF_PACKET;
socketAddress.sll_protocol = htons(ETH_P_ALL);
socketAddress.sll_ifindex = index;
if (bind(socketFileDesc, (struct sockaddr *) &socketAddress, sizeof(socketAddress)) < 0) {
perror("bind");
close(socketFileDesc);
return errno;
}
printf("Socket bound to the interface: %s\nWaiting for packets...\n", iface_name);
// Receiving packets in a loop
while (1) {
ssize_t n = 0;
uint8_t packet[PACKET_SIZE];
bzero(packet, sizeof(packet));
struct sockaddr_in address;
socklen_t length = sizeof(address);
if ((n = recvfrom(socketFileDesc, packet, sizeof(packet), 0, (struct sockaddr *) &address, &length)) < 0) {
perror("recvfrom");
close(socketFileDesc);
return errno;
}
// Null-terminated data
if (n > 0)
packet[n - 1] = '[=11=]';
else
continue;
// IP address
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(address.sin_addr), ip, length);
// Host name
struct hostent *host = gethostbyaddr(&(address.sin_addr), length, AF_INET);
if (host == NULL) {
herror("gethostbyaddr");
return h_errno;
}
const char *hostName = host->h_name;
// Packet type
char packetType[BUFSIZ];
int type = ((struct sockaddr_ll *) &address)->sll_pkttype;
packetTypeToStr(type, packetType);
// Printing info and data
printf("\n\nReceived packet: size: %li, type: %s\n"
"Sender info: Name: %s, IP: %s\n",
n, packetType, hostName, ip);
printf("Data:\n");
int i = 0;
for (; i < n; ++i)
printf("%02x ", packet[i]);
}
return 0;
}
由于您正在接收原始数据包 recvfrom()
不能 return IP 地址,因为数据通常可能不是互联网数据包。例如,它可能只是一个任意的以太网数据包,它是从一些根本没有 TCP/IP 堆栈的设备发送的。可能 recvfrom()
将传递的 sockaddr 指针视为 struct sockaddr_ll *
和 return 的物理层地址。
您可以尝试通过解析接收到的数据包来获取正确的IP地址。如果它真的是 IP 数据包 - 它将包含所有 headers,以及源地址和目标地址。