为什么recvfrom
会创建额外的IP标头?
我发送:
-------------
- IP header -
-------------
- Data -
-------------
但是当我尝试接收数据时,看起来似乎有
-------------
- IP header -
-------------
- IP header -
-------------
- Data -
-------------
客户代码:
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <netinet/ip.h>
#define DEBUG 1
int main(void) {
// Create File descrptor for socket
int socket_fd;
if ((socket_fd = socket(AF_INET, SOCK_RAW, IPPROTO_IPV6)) < 0) {
perror("ERROR Socket");
exit(2);
}
char *srcIP = "127.0.0.1";
char *dstIP = "127.0.0.1";
// Create address structure
struct sockaddr_in daddr;
daddr.sin_family = AF_INET;
daddr.sin_port = 0; // Raw sockets can't use ports
inet_pton(AF_INET, "127.0.0.1", &daddr.sin_addr);
memset(daddr.sin_zero, 0, sizeof(daddr.sin_zero));
// Create a Packet
char packet[50];
memset(packet, 0, sizeof(packet));
// Structure packet
struct iphdr *ip_header = (struct iphdr *) packet;
// Data to be appended at the end of the ip header
char *data = (char *) (packet + (sizeof(struct iphdr)));
ip_header->version = 4; // IPv4
ip_header->tos = 0; // Type of service
ip_header->ihl = 5; // 5 x 32-bit words
// ip_header->tot_len = htons(sizeof(struct iphdr) + strlen(data)); // Total IP packet length
ip_header->tot_len = sizeof(packet); // Total IP packet length
ip_header->protocol = IPPROTO_IPV6; // 6in4 protocol
ip_header->frag_off = 0x00; //16 bit field = [0:2] flags + [3:15] offset = 0x0
ip_header->ttl = 0xFF; // Max number of hops 16bit
// ip_header->id = htons(54321); // 0x00; //16 bit id
ip_header->check = 0; //16 bit checksum of IP header. Can't calculate at this point
ip_header->saddr = inet_addr(srcIP);
ip_header->daddr = inet_addr(dstIP);
data[0] = 'T';
data[1] = 'E';
data[2] = 'S';
data[3] = 'T';
data[4] = '7';
data[5] = '\0';
// ip_header->check = csum((unsigned short *) packet, ip_header->tot_len);
#if DEBUG
printf("\nIP header checksum: %d\n", ip_header->check);
#endif
while (1) {
sleep(1);
if (sendto(socket_fd, (char *) packet, sizeof(packet), 0,
(struct sockaddr *) &daddr, (socklen_t) sizeof(daddr)) < 0)
perror("Packet send error");
}
return 0;
}
服务器代码:
/*** IPPROTO_RAW receiver ***/
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int socket_fd;
struct sockaddr_in saddr;
char packet[50];
if ((socket_fd = socket(AF_INET, SOCK_RAW, IPPROTO_IPV6)) < 0) {
perror("socket_fd");
exit(EXIT_FAILURE);
}
memset(packet, 0, sizeof(packet));
socklen_t len = (socklen_t) sizeof(saddr);
while(1) {
if (recvfrom(socket_fd, packet, sizeof(packet), 0,
(struct sockaddr *)&saddr, &len) < 0)
perror("recvfrom");
int i = sizeof(struct iphdr); ////// WHY IS DATA PAYLOAD ON packet[sizeof(struct iphdr) * 2]
while (i < sizeof(packet)) {
fprintf(stderr, "%c", packet[i]);
i++;
}
printf("\n");
}
exit(EXIT_SUCCESS);
}
答案 0 :(得分:0)
在发件人中,您需要设置IP_HDRINCL
套接字选项。这告诉API你手动提供IP头。由于您未设置此选项,因此您可以在系统添加后有效地放置自己的IP标头副本。
答案 1 :(得分:0)
IP_HDRINCL套接字选项通常仅在使用IPPROTO_RAW的情况下隐式设置。如果您没有使用IPPROTO_RAW,那么将生成标头,因为不会隐式设置IP_HDRINCL。