当前位置:首页 > 行业动态 > 正文

如何深入理解Linux Ping命令的源码?

Linux的ping命令源码可以在其内核源代码中找到,具体路径为:net/ipv4/icmp.c和net/core/dev.c。

Linux中的ping命令是一个网络诊断工具,用于测试主机之间网络的连通性,它通过发送ICMP回显请求消息到目标主机,并等待接收到ICMP回显应答消息来验证网络连接是否正常,以下是一个简单的ping命令源码实现,使用C语言编写:

如何深入理解Linux Ping命令的源码?  第1张

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip_icmp.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#define PACKET_SIZE 64
#define MAX_WAIT_TIME 5
unsigned short checksum(void *b, int len) {
    unsigned short *buf = b;
    unsigned int sum = 0;
    unsigned short result;
    for (sum = 0; len > 1; len = 2)
        sum += *buf++;
    if (len == 1)
        sum += *(unsigned char *)buf;
    sum = (sum >> 16) + (sum & 0xFFFF);
    sum += (sum >> 16);
    result = ~sum;
    return result;
}
int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("Usage: %s <IP address>
", argv[0]);
        exit(1);
    }
    struct sockaddr_in dest_addr;
    int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (sockfd < 0) {
        perror("socket error");
        exit(1);
    }
    memset(&dest_addr, 0, sizeof(dest_addr));
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_addr.s_addr = inet_addr(argv[1]);
    char sendbuf[PACKET_SIZE];
    memset(sendbuf, 0, PACKET_SIZE);
    struct icmphdr *icmp = (struct icmphdr *)sendbuf;
    icmp>type = ICMP_ECHO;
    icmp>code = 0;
    icmp>checksum = 0;
    icmp>un.echo.id = getpid();
    icmp>un.echo.sequence = 1;
    icmp>checksum = checksum((unsigned short *)icmp, sizeof(struct icmphdr));
    if (sendto(sockfd, sendbuf, sizeof(sendbuf), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) <= 0) {
        perror("sendto error");
        exit(1);
    }
    struct timeval timeout;
    timeout.tv_sec = MAX_WAIT_TIME;
    timeout.tv_usec = 0;
    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
    char recvbuf[PACKET_SIZE];
    struct sockaddr_in from;
    socklen_t fromlen = sizeof(from);
    int nbytes = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&from, &fromlen);
    if (nbytes < 0) {
        perror("recvfrom error");
        exit(1);
    }
    struct icmphdr *icmp_recv = (struct icmphdr *)recvbuf;
    if (icmp_recv>type == ICMP_ECHOREPLY && icmp_recv>un.echo.id == getpid()) {
        printf("Received echo reply from %s, sequence = %u, time = %ld ms
",
               inet_ntoa(from.sin_addr), icmp_recv>un.echo.sequence, (long)(icmp_recv>un.echo.data / 1000));
    } else {
        printf("No echo reply received from %s
", inet_ntoa(from.sin_addr));
    }
    close(sockfd);
    return 0;
}

这个程序首先创建一个原始套接字,然后构建一个ICMP回显请求数据包,并将其发送到指定的IP地址,程序设置一个超时时间,等待接收ICMP回显应答数据包,如果收到应答,程序将打印出相关信息,否则输出未收到应答的消息。

小伙伴们,上文介绍了“linux ping 源码”的内容,你了解清楚吗?希望对你有所帮助,任何问题可以给我留言,让我们下期再见吧。

0