인디노트

icmp 를 전송한 후 응답을 받아서 해당 응답이 어떤 전송건인지 확인하는 C 코드 본문

개발 플랫폼 및 언어/네트워크 기술

icmp 를 전송한 후 응답을 받아서 해당 응답이 어떤 전송건인지 확인하는 C 코드

인디개발자 2023. 4. 14. 15:41
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <unistd.h>

#define PACKET_SIZE 4096
#define IP_HDR_SIZE sizeof(struct iphdr)
#define ICMP_HDR_SIZE sizeof(struct icmphdr)

// IP 체크섬 계산 함수
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>\n", argv[0]);
        exit(1);
    }

    char *target_ip = argv[1];
    int sockfd, sent, recv;
    struct sockaddr_in addr, sender;
    socklen_t sender_size = sizeof(sender);
    char packet[PACKET_SIZE], recv_packet[PACKET_SIZE];
    struct iphdr *ip_hdr = (struct iphdr *)packet;
    struct icmphdr *icmp_hdr = (struct icmphdr *)(packet + IP_HDR_SIZE);

    // ICMP 요청 생성
    memset(packet, 0, PACKET_SIZE);
    icmp_hdr->type = ICMP_ECHO;
    icmp_hdr->code = 0;
    icmp_hdr->un.echo.id = getpid();
    icmp_hdr->un.echo.sequence = 0;
    icmp_hdr->checksum = 0;
    icmp_hdr->checksum = checksum(icmp_hdr, ICMP_HDR_SIZE);

    // 소켓 생성
    sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (sockfd < 0) {
        perror("socket");
        exit(1);
    }

    // 수신 타임아웃 설정
    struct timeval timeout;
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;
    if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0) {
        perror("setsockopt");
        exit(1);
    }

    // 수신 대기
    memset(&sender, 0, sizeof(sender));
    memset(recv_packet, 0, PACKET_SIZE);
    sent = sendto(sockfd, packet, IP_HDR_SIZE + ICMP_HDR_SIZE, 0, (struct sockaddr *)&addr, sizeof(addr));
    if (sent < 0) {
        perror("sendto");
        exit(1);
    }

    recv = recvfrom(sockfd, recv_packet, PACKET_SIZE, 0, (struct sockaddr *)&sender, &sender_size);
    if (recv < 0) {
        perror("recvfrom");
        exit(1);
    }

    // ICMP 응답 확인
    ip_hdr = (struct iphdr *)recv_packet;
    icmp_hdr = (struct icmphdr *)(recv_packet + IP_HDR_SIZE);
    if (icmp_hdr->type == ICMP_ECHOREPLY && icmp_hdr->un.echo.id == getpid()) {
        printf("Received ICMP echo reply from %s\n", inet_ntoa(sender.sin_addr));
    } else {
        printf("Received unexpected ICMP packet\n");
    }

    close(sockfd);
    return 0;
}

위 코드에서 icmp_hdr->typeICMP_ECHOREPLY이고, icmp_hdr->un.echo.id가 현재 프로세스의 ID와 일치하면 해당 응답이 이전에 전송한 ICMP 요청에 대한 응답임을 확인할 수 있습니다. 이 경우에는 수신한 응답의 IP 주소를 출력합니다. 그렇지 않은 경우에는 예상하지 못한 ICMP 패킷을 수신했음을 알리는 메시지를 출력합니다. 코드에서 소켓을 생성하고, ICMP 요청을 생성하고, 요청을 전송하고, 응답을 수신하고, 응답을 확인하고, 소켓을 닫는 과정을 거칩니다.

반응형
Comments