沿着线路发送 ip 数据包抛出 "Invalid argument"

sending ip packet down the wire throws "Invalid argument"

我正在实施一个简单的 ICMP ping,其中通过网络发送 IP 数据包给我 "Invalid argument"。

代码如下:

 /* Create IP Packet */
int packet_size = IPv4_HDRLEN + (int)sizeof(ICMPHeader) + (int)[payload length];
char *packet = (char *) malloc (packet_size);

if (!packet)
{
    perror("out of memory");
    return;
}

//zero out the packet buffer
memset (packet, 0, packet_size);

//ip header
struct ip *iphdr = (struct ip *) packet;
iphdr->ip_v = 4;
iphdr->ip_hl = 5;
iphdr->ip_tos = 0;
iphdr->ip_len = htons(packet_size);
iphdr->ip_id = (ushort) rand();
iphdr->ip_off = 0;
iphdr->ip_ttl = 255;
iphdr->ip_p = IPPROTO_ICMP;
iphdr->ip_sum = in_cksum((uint16_t *)iphdr, IPv4_HDRLEN);

int status = 0;
char *src_ip = (char *) [@"127.0.0.1" UTF8String];
char *dst_ip = (char *) [@"2.3.4.5" UTF8String];

// Source IPv4 address (32 bits)
if ((status = inet_pton (AF_INET, src_ip, &(iphdr->ip_src))) != 1) {
    fprintf (stderr, "inet_pton() failed.\nError message: %s", strerror (status));
    exit (EXIT_FAILURE);
}

// Destination IPv4 address (32 bits)
if ((status = inet_pton (AF_INET, dst_ip, &(iphdr->ip_dst))) != 1) {
    fprintf (stderr, "inet_pton() failed.\nError message: %s", strerror (status));
    exit (EXIT_FAILURE);
}

icmpPacket = [NSMutableData dataWithLength:sizeof(*icmpPtr) + [payload length]];
assert(icmpPacket != nil);

icmpPtr = [icmpPacket mutableBytes];
icmpPtr->type = kICMPTypeEchoRequest;
icmpPtr->code = 0;
icmpPtr->checksum = 0;
icmpPtr->identifier     = OSSwapHostToBigInt16(self.identifier);
icmpPtr->sequenceNumber = OSSwapHostToBigInt16(self.nextSequenceNumber);
memcpy(&icmpPtr[1], [payload bytes], [payload length]);

icmpPtr->checksum = in_cksum([icmpPacket bytes], [icmpPacket length]);
int on = 1;

/* Copy icmp and data into the packet */
memcpy(packet + IPv4_HDRLEN, icmpPtr, [icmpPacket length]);

// Set flag so socket expects us to provide IPv4 header.
if (setsockopt (CFSocketGetNative(self->_socket), IPPROTO_IP, IP_HDRINCL, &on, sizeof (on)) < 0) {
    perror ("setsockopt() failed to set IP_HDRINCL ");
    exit (EXIT_FAILURE);
}

/* Send the packet */

if (self->_socket == NULL) {
    bytesSent = -1;
    err = EBADF;
} else {
    bytesSent = sendto(
        CFSocketGetNative(self->_socket),
        packet,
        packet_size,
        0, 
        (struct sockaddr *) &sin, 
        sizeof (struct sockaddr)
    );
    err = 0;
    if (bytesSent < 0) {
        err = errno;
    }
}

这实际上是对 Apple 简单 ping 的扩展:https://developer.apple.com/library/mac/samplecode/SimplePing/Listings/SimplePing_m.html#//apple_ref/doc/uid/DTS10000716-SimplePing_m-DontLinkElementID_5

被构造的 IP 数据包看起来很简单,但出于某种原因,它总是给出 errno 22。我不确定代码还有什么问题。

套接字是使用以下方法创建的:

fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);

我不能使用原始套接字,因为我正在为 iOS 应用构建它。

谢谢

万一有人遇到同样的问题,这个问题正是post中提到的:Raw socket sendto() failure in OS X