반응형
ICMP (Internet Control Message Protocol)은 프로토콜 중 하나로 네트워크 상황을 모니터링하는 기본적인 프로토콜입니다.
ICMP는 주로 네트워크 장치 간 통신 문제를 해결하고 네트워크 상태 정보를 전송하는 데 사용됩니다.
ICMP 메시지의 몇 가지 일반적인 용도는 다음과 같습니다:
에코 요청 및 응답 (Ping):
ICMP를 사용하여 호스트 간 연결성을 테스트하고 대상 호스트로 데이터 패킷을 보내고 응답을 확인합니다.
목적지 불능 알림:
ICMP 메시지를 사용하여 목적지 호스트 또는 네트워크가 도달 불능 상태인 것을 확인 할 수 있습니다.
TTL 초과:
ICMP를 사용하여 IP 패킷이 목적지에 도달하지 못하고 TTL (Time To Live) 값이 0으로 감소할 때 TTL 초과 메시지를 생성합니다. 이것은 패킷이 무한 루프에 빠지는 것을 방지합니다.
아래에 간단하게 ICMP ECHO packet을 송수신하여 지연시간을 계산하는 코드를 작성하겠습니다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/ip_icmp.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <errno.h>
#define PACKET_SIZE 32
#define PING_TIMEOUT 1
// 체크섬 계산 함수
unsigned short checksum(void *b, int len)
{
unsigned short *buf = b;
unsigned int sum = 0;
unsigned short result;
// 16비트씩 더하여 합을 계산
for (sum = 0; len > 1; len -= 2)
sum += *buf++;
// 패킷 길이가 홀수인 경우 마지막 1바이트를 더함
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[])
{
// 목적지 IP 주소를 입력받음
if (argc != 2)
{
fprintf(stderr, "Usage: %s <destination IP>\n", argv[0]);
return -1;
}
char *target = argv[1];
struct sockaddr_in dest_addr;
int sockfd;
// 소켓 생성
if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1)
{
fprintf(stderr,"socket error\n");
return -2;
}
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = 0;
// 목적지 IP 주소를 네트워크 바이트 순서로 변환하여 저장
if (inet_pton(AF_INET, target, &(dest_addr.sin_addr)) <= 0)
{
fprintf(stderr,"inet_pton error\n");
close(sockfd);
return -3;
}
char packet[PACKET_SIZE];
struct icmphdr *icmp = (struct icmphdr *)packet;
memset(packet, 0xab, sizeof(packet));
// ICMP Echo Request 패킷 생성
icmp->type = ICMP_ECHO;
icmp->code = 0;
icmp->un.echo.id = getpid();
icmp->un.echo.sequence = 0;
icmp->checksum = 0;
icmp->checksum = checksum(icmp, sizeof(packet));
// 패킷 전송
if (sendto(sockfd, packet, sizeof(packet), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) == -1)
{
fprintf(stderr,"sendto error\n");
close(sockfd);
return -4;
}
// 응답 수신
char recv_packet[PACKET_SIZE];
struct sockaddr_in recv_addr;
socklen_t recv_len = sizeof(recv_addr);
int recv_bytes;
// recvfrom에 대한 타임아웃 설정
struct timeval timeout;
timeout.tv_sec = PING_TIMEOUT;
timeout.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout));
struct timeval start, end;
gettimeofday(&start, NULL);
// 패킷 수신
if (recv_bytes = recvfrom(sockfd, recv_packet, sizeof(recv_packet), 0, (struct sockaddr *)&recv_addr, &recv_len) == -1)
{
if (errno == EAGAIN || errno == EWOULDBLOCK) {
fprintf(stderr,"No response received. Host may not be reachable.\n");
close(sockfd);
return -5;
} else {
fprintf(stderr,"recvfrom error\n");
close(sockfd);
return -5;
}
}
gettimeofday(&end, NULL);
double rtt = (end.tv_sec - start.tv_sec) * 1000.0 + (end.tv_usec - start.tv_usec) / 1000.0;
fprintf(stderr,"Received from %s: icmp_seq=0 time=%.2f ms\n", target, rtt);
close(sockfd);
return 0;
}
반응형
'IT > 개발' 카테고리의 다른 글
OpenAI API 이용 개발 기초(소개, API 사용준비, 기본모델들, ChatGTP) (0) | 2023.11.28 |
---|---|
오디오 raw PCM 데이터에 wav header 생성 하기(파이썬) (0) | 2023.11.22 |
LLM 학습에 사용되는 공개 데이터 (말뭉치, ChatGPT, PaLM, LLaMA 등) (0) | 2023.10.17 |
(9) Langchain에서 VectorStore에 저장된 사용자 데이터를 재사용해보자(user data, embedding) (0) | 2023.08.07 |
(8) Langchain에서 사용자 데이터를 VectorStore에 저장해보자(user data, embedding) (0) | 2023.08.07 |