我正在尝试为ICMP库编写ping函数。一切似乎都可以进行,直到sendto
返回Address family not supported by protocol family
为止。我不明白这个错误。我在做什么错了?
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <errno.h>
#include <netdb.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static u_int16_t
checksum(u_int16_t *arr, size_t bytes)
{
u_int32_t sum = 0;
u_int16_t *ptr = arr;
while (bytes > 1) {
sum += *ptr++;
bytes -= 2;
}
if (bytes == 1) {
*(u_int8_t *)&sum += *(u_int8_t *)ptr;
}
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
return (u_int16_t)(~sum);
}
ssize_t
icmp_send(const char *host, const char *data, const size_t datalen)
{
int s, error;
struct addrinfo hints;
struct addrinfo *res = NULL;
bzero(&hints, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_RAW;
hints.ai_protocol = IPPROTO_ICMP;
if ((error = getaddrinfo(host, NULL, &hints, &res))) {
fprintf(stderr, "ping: getaddrinfo: %s\n", gai_strerror(error));
return -1;
}
struct protoent *proto = getprotobyname("icmp");
if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) == -1) {
fprintf(stderr, "ping: socket: %s\n", strerror(errno));
return -1;
}
int on = 1;
if (setsockopt(s, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0) {
fprintf(stderr, "ping: setsockopt: %s\n", strerror(errno));
return -1;
}
struct sockaddr_in to;
bzero(&to, sizeof(to));
to.sin_family = AF_INET;
struct ip ip;
bzero(&ip, sizeof(ip));
ip.ip_v = IPVERSION;
ip.ip_hl = sizeof(struct ip) << 2;
ip.ip_id = 0;
ip.ip_ttl = 255;
ip.ip_p = IPPROTO_ICMP;
ip.ip_src.s_addr = INADDR_ANY;
ip.ip_dst = ((struct sockaddr_in *)res)->sin_addr;
ip.ip_sum = checksum((u_int16_t *)&ip, sizeof(ip));
struct icmp icp;
bzero(&icp, sizeof(icp));
icp.icmp_type = ICMP_ECHOREPLY;
icp.icmp_code = 0;
icp.icmp_cksum = checksum((u_int16_t *)&icp, sizeof(icp));
size_t packetlen = sizeof(ip) + sizeof(icp) + datalen;
char packet[packetlen];
memset(packet, 0, packetlen);
memcpy((char *)packet, &ip, sizeof(ip));
memcpy((char *)packet + sizeof(ip), &icp, sizeof(icp));
memcpy((char *)packet + sizeof(ip) + sizeof(icp), data, packetlen);
ssize_t snd_ret = sendto(s, packet, packetlen, 0, (const struct sockaddr *)&to, sizeof(to));
if (errno) {
fprintf(stderr, "ping: sendto: %s\n", strerror(errno));
return -1;
}
return snd_ret;
}
答案 0 :(得分:2)
res
是指向addrinfo
结构而不是sockaddr
的指针。 sockaddr
在ai_addr
成员中,其长度在ai_addrlen
成员中。这些应该传递给sendto()
。
ssize_t snd_ret = sendto(s, packet, packetlen, 0, res->ai_addr, res->ai_addrlen);