C语言 在Linux中创建套接字错误,而不是MacOS



我有以下程序,我试图重新创建ping。这在我的macOS开发环境中运行时效果很好,但在我的prod Linux环境中运行时,套接字无法创建。我不知道为什么。此外,任何解决这个问题的方法,使其在Linux上工作将是伟大的。

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
/* Calculate ICMP checksum */
uint16_t ip_checksum(void *icmp_header, int size_of_header){
unsigned short *buffer = icmp_header;
unsigned int sum = 0;
uint16_t result;
for(sum=0;size_of_header > 1; size_of_header -=2){
sum += *buffer++;
}
if(size_of_header == 1){
sum += *(unsigned char*)buffer;
}
sum = (sum >> 16) + (sum & 0xffff);
result = ~sum;
return result;
}
int main(int argc, char const *argv[]){
char ip[20]; /* Define variable to hold user entered IP address*/
const int icmp_size=8; /* Size of icmp header */
struct sockaddr_in toSendTo; /* Set sockaddr_in struct */
/* Create ICMP header */
struct icmp_header{ 
unsigned char icmph_type;
unsigned char icmph_code;
uint16_t icmph_checksum;
unsigned short int icmph_ident;
unsigned short int icmph_seqnum;
} icmp_header;
/* Get user to input IP address */
printf("Please enter an IP address: ");
fgets(ip, sizeof(ip), stdin);
/* Loop to send 3 pings requests */
for(int i = 0; i < 3; i++){

icmp_header.icmph_type = 8; /* Set ICMP type to 8 for sending ICMP request */
icmp_header.icmph_code = 0; /* Set ICMP code to 0 for sending ICMP request */
icmp_header.icmph_checksum = 0; /* Initializee checksum to 0 */
icmp_header.icmph_seqnum = i*20; /* Arbitrary sequence number */
icmp_header.icmph_ident = i+50; /* Arbitrary id */
icmp_header.icmph_checksum = ip_checksum(&icmp_header,icmp_size); /* Calculate checksum */
/* Set transport IP in sockaddr struct  */
if (inet_addr(ip) == -1){
printf("Error, invalid IP addressn");
exit(1);
}else{
toSendTo.sin_addr.s_addr = inet_addr(ip);
}
/* Create socket */
int soc = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
/* Check if creation of socket throws an error */
if(soc == -1){
printf("Error creating socketn");
exit(1);
}

/* Send ICMP ping request */
int send = sendto(soc, &icmp_header, icmp_size, 0, (struct sockaddr *)&toSendTo, sizeof(toSendTo));

/* Check if sending ICMP request throws an error */
if (send < 0){
printf("Error sending ping(%d).n", i+1);
exit(1);
}else{
printf("nICMP Echo Request(%d) sent to %s", i+1,ip);
}

unsigned int response_address_size; /* Variable for size of response packet  */
char response_buffer[50]; /* Buffer for content of response */
struct sockaddr response_address; /* Struct to hold response address */
/* Struct to hold ICMP response header information */
typedef struct icmp_resp{
unsigned char icmph_type;
unsigned char icmph_code;
uint16_t icmph_checksum;
unsigned short int icmph_ident;
unsigned short int icmph_seqnum;
} icmp_r;

/* Receive ICMP response */
int resp = recvfrom(soc, response_buffer, sizeof(response_buffer), 0, &response_address, &response_address_size);
/* Check if receiving response throws an error */
if (resp < 0){
printf("Error receiving response (%d)n",i+1);
exit(1);
}
icmp_r* echo_response;
echo_response = (icmp_r *)&response_buffer[20];
/* Determine if Destination Unreachable is response */
if(echo_response->icmph_type == 3 && echo_response->icmph_code == 0){
printf("Destination Unreachable...n");
}else{
/* Print ICMP response information */
printf("ICMP Response(%d) : type=%d,code=%d,checksum=%x, ident=%d, seq=%dnn", i+1,
      echo_response->icmph_type,
      echo_response->icmph_code,
      ntohs(echo_response->icmph_checksum),
      echo_response->icmph_ident,
      echo_response->icmph_seqnum);
}

/* Close Socket */
close(soc);
}

}

下面是我在Linux下运行时的输出:

Please enter an IP address: 8.8.8.8
Error creating socket

您必须像下面的示例一样将ping_group_range设置为sysctl,以指定可以创建IPPROTO_ICMP套接字的组。

sysctl -w net.ipv4.ping_group_range="gid gid"

来自文档:

ping_group_range(两个整数;默认值:见下文;因为Linux2.6.39)组id范围(最小和最大组id,(包括)允许创建ICMP Echo套接字。默认值为"10",这意味着不允许任何组创建ICMP Echo socket .

编辑

套接字类型必须是SOCK_DGRAM而不是int soc = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);中的SOCK_RAW,您还需要定义toSendTo.sin_family = AF_INET;

最新更新