본문 바로가기

서버 개발

CURL로 외부 서버와 통신 테스트(+ 겪을 수 있는 에러로그)

서론

개발 서버에서 외부 서버와의 통신을 테스트하기 위해 나는 주로 CRUL 명령어와 DIG 명령어를 사용한다. 두 명령어는 각각 다음과 같은 장점을 갖고 있기 때문이다.

 

1. curl 명령어는 다음과 같은 장점을 가지고 있다.

  • 다양한 옵션을 통해 HTTP/HTTPS 요청을 세밀하게 제어할 수 있다.
  • 응답 코드, 헤더, 본문 등을 확인하여 통신 결과를 자세하게 분석할 수 있다.

2. dig 명령어는 다음과 같은 장점을 가지고 있다.

  • DNS 레코드를 확인하여 외부 서버의 도메인 이름과 IP 주소 정보를 확인할 수 있다.
  • DNS 서버 정보를 확인하여 네트워크 문제를 해결하는 데 도움이 될 수 있다.

따라서 두 명령어를 적절히 사용하면 통신 테스트에 좀더 효율적일 수 있다고 생각한다. 그래서 각 명령어에 대한 결과에 대해 정리해보고자 한다.

우선 이번글에서는 curl 명령어에 대해서 정리하려고 한다. curl의 옵션들을 정리하는것 보다는 실행 과정에 대한 로그와, 각 단계별로 겪을 수 있는 에러 로그의 원인에 대해 중점적으로 정리하려고 한다.

 

CURL 로그 설명

리눅스의 CURL 명령어를 통하여 https://www.google.com  로 요청을 요청한다고 가정하자. -v 옵션을 사용한다면 실행과정에 대해 자세히 볼 수 있고, 아래와 유사한 로그를 볼 수 있다.

*   Trying 142.250.189.142...                            --- 1. 연결시도
* Connected to www.google.com (142.250.189.142) port 443 (#0)
* ALPN, offering h2					       --- 2. TLS/SSL 핸드쉐이크
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS header, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* TLSv1.3 (IN), TLS handshake, NewSessionTicket (4):
* TLSv1.2 (OUT), TLS header, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384		--- 3. 연결 설정 완료
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=www.google.com
* start date: Feb  1 00:00:00 2023 GMT
* expire date: Feb  1 23:59:59 2024 GMT
* subjectAltName: host "www.google.com" matched cert's "*.google.com"
* issuer: C=US; O=Google Trust Services; CN=Google Internet Authority G2
* SSL certificate verify ok.
* Using HTTP2, server supports multiplexing		       --- 4. 데이터 요청 및 응답
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x55f36406ce90)
> GET / HTTP/2
> Host: www.google.com
> user-agent: curl/7.81.0
> accept: */*
>
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* < HTTP/2 200
* < date: Mon, 25 Mar 2024 12:45:01 GMT
* < content-type: text/html; charset=UTF-8
* < content-length: 14431
* < alt-svc: h3=":443"; ma=86400
* <
... (본문 데이터 출력) ...
* Connection #0 to host www.google.com left intact              --- 5. 연결 종료

 

각 과정을 자세히 보면 아래와 같이 나눌 수 있다.

 

1. 연결 시도 (Connection Attempt)

  • Trying 142.250.189.142...: curl 명령어가 www.google.com 도메인의 IP 주소를 조회하는데 이 과정에서 먼저 DNS 서버를 통해 도메인 이름을 IP 주소 (142.250.189.142)로 변환한다.
  • Connected to www.google.com (142.250.189.142) port 443 (#0): curl 명령어가 IP 주소 142.250.189.142의 포트 443에 연결을 성공한다. 참고로 포트 443은 보안 통신 프로토콜인 HTTPS 를 사용하는 기본 포트이다.

2. TLS/SSL 핸드쉐이크 (TLS/SSL Handshake)

  • ALPN, offering h2  ~  TLSv1.3 (OUT), TLS handshake, Finished (20) 까지의 과정은 TLS/SSL 핸드쉐이크 과정을 나타낸다.

3. 연결 설정 완료 (Connection Established)

  • SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384  ~ SSL certificate verify ok 까지의 과정은 TLSv1.3 프로토콜과 AES-256-GCM, SHA384 알고리즘을 이용해 연결을 암호화하여 연결을 암호화 하고, 서버는 이를 수락한 후 인증서를 검증하였다는 과정을 나타낸다.

4. 데이터 요청 및 응답 (Data Request and Response)

  •  GET / HTTP/2: curl 명령어가 루트 디렉토리 (/) 에 대한 GET 요청 을 HTTP/2 프로토콜을 사용하여 보낸다.
  • Host: www.google.com: 요청 헤더 정보 중 호스트 정보를 표시.
  • < content-type: text/html; charset=UTF-8: 응답 데이터의 형식과 문자 인코딩 정보.
  • < content-length: 14431: 응답 데이터의 길이.
  • ... (본문 데이터 출력) ...: 서버가 보낸 데이터가 출력된다.

5. 연결 종료 (Connection Closure)

  • curl 명령어 실행이 완료되면 연결이 종료된다.(옵션에 따라 다를 수 있다)

 

 

이를 토대로 각 단계마다 문제가 생길경우 아래와 같은 로그를 확인할 수 있다.

참고로 각 단계마다 다른 오류로그를 출력할 수 있으며 아래 예시는 그중 내가 겪어본 오류중 기억에 남는 로그이다.

(아래의 로그 이외에도 다른 오류로그를 마주칠 수 있다는 점을 알아야 한다.)

 

1. 연결 실패:

* About to connect() to www.example.com port 443 (#0)
*   Trying 192.0.2.45...
* connect to www.example.com port 443: Connection refused
* Could not connect to host
* Closing connection #0

분석:

  • 서버에 연결하려고 했지만 연결이 거부되었다.
  • 서버 IP 주소 또는 포트 번호가 잘못되었거나 서버가 실행 중지상태일 수 있다.
  • DNS 설정 확인, 라우터 재부팅, 네트워크 연결 상태 점검 등을 시도해 볼 수 있다.

2. DNS 쿼리 실패:

* About to connect() to www.example.com port 443 (#0)
*   Trying to resolve host www.example.com...
* failed to connect to www.example.com
* Could not resolve host
* Closing connection #0

분석:

  • 도메인 이름을 IP 주소로 변환하는 DNS 쿼리가 실패한 경우.
  • 도메인 이름이 잘못되었거나 DNS 서버에 문제가 있을 수 있다(설정, 상태 등).
  • DNS 설정, DNS 캐시 비우기(ipconfig / flushdns), etc/hosts 파일 확인, 방화벽 설정 확인 등이 필요하다.

3. TLS/SSL Handshake 실패:

* About to connect() to www.example.com port 443 (#0)
*   Trying 192.0.2.45...
* Connected to www.example.com (192.0.2.45) port 443 (#0)
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
*   CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*   Cipher Suite: [C0, C2]
*   Compression: [00]
* SSL/TLS handshake failed
* Closing connection #0

분석:

  • 서버와의 TLS/SSL 협상이 실패한 경우.
  • 서버 인증서 문제, 암호화 알고리즘 불일치 등의 경우 발생할 수 있다.
  • 서버 인증서 설정 확인, CAfile 업데이트 등을 시도해 볼 수 있다.

4. HTTP 요청 실패:

* About to connect() to www.example.com port 443 (#0)
*   Trying 192.0.2.45...
* Connected to www.example.com (192.0.2.45) port 443 (#0)
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
*   CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*   Cipher Suite: [C0, C2]
*   Compression: [00]
* > GET / HTTP/1.1
* > Host: www.example.com
* > User-Agent: curl/7.74.0
* > Accept: */*
* < HTTP/1.1 404 Not Found
* < Content-Type: text/html; charset=utf-8
* < Content-Length: 162
* <
* Closing connection #0

분석:

  • 서버가 요청한 URL을 찾을 수 없는 경우이다 (404 Not Found).
  • 이경우 URL 주소가 잘못되었거나 요청 대상 파일이 존재하지 않을 수 있다.
  • 그밖에 500 Internal Server Error, 503 Service Unavailable 등의 오류가 발생할 수 있다.
  • 각 응답값에 따라 해결책을 정할 수 있다.

5. 데이터 송수신 실패:

* About to connect() to www.example.com port 443 (#0)
*   Trying 192.0.2.45...
* Connected to www.example.com (192.0.2.45) port 443 (#0)
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
*   CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*   Cipher Suite: [C0, C2]
*   Compression: [00]
* > GET / HTTP/1.1
* > Host: www.example.com
* > User-Agent: curl/7.74.0
* > Accept: */*
* < HTTP/1.1 200 OK
* < Content-Type: text/html; charset=utf-8
* < Content-Length: 12345
* << [1234 bytes]
* recvfrom() failed: Network is unreachable
* Closing connection #0

분석:

  • recvfrom() 함수 호출 : 네트워크 요청이 불안정하거나 끊어지는 경우에 발생할 수 있다.
  • recvfrom() 함수의 에러 코드를 우선 확인해야 한다. 이에 따라 소켓 설정, 네트워크 연결 확인, 서버 상태 확인, 방화벽 설정 확인 등의 조치를 할 수 있다.

6. 기타 발생할 수 있는 문제:

* About to connect() to www.example.com port 443 (#0)
*   Trying 192.0.2.45...
* Connected to www.example.com (192.0.2.45) port 443 (#0)
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
*   CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*   Cipher Suite: [C0, C2]
*   Compression: [00]
* > GET / HTTP/1.1
* > Host: www.example.com
* > User-Agent: curl/7.74.0
* > Accept: */*
* < HTTP/1.1 500 Internal Server Error
* < Content-Type: text/html; charset=utf-8
* < Content-Length: 158
* <
* Closing connection #0

분석:

  • 서버 코드 문제, 시스템 오류 등의 경우가 발생할 수 있다.
  • Too many redirects : 리다이렉션 횟수 초과.
  • Request aborted : 사용자 취소 또는 시스템 오류 발생.
  • send() failed: Network is unreachable : 서버로 데이터를 전송하는 데 실패.
  • 각 오류에 맞는 조치를 생각해 볼 수 있다.

7. 리다이렉션

* About to connect() to www.example.com port 443 (#0)
*   Trying 192.0.2.45...
* Connected to www.example.com (192.0.2.45) port 443 (#0)
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
*   CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*   Cipher Suite: [C0, C2]
*   Compression: [00]
* > GET / HTTP/1.1
* > Host: www.example.com
* > User-Agent: curl/7.74.0
* > Accept: */*
* < HTTP/1.1 301 Moved Permanently
* < Location: https://www.new-example.com/
* < Content-Length: 0
* <
* Closing connection #0

분석:

8. 시간 초과 :

* About to connect() to www.example.com port 443 (#0)
*   Trying 192.0.2.45...
* connect to www.example.com port 443: Operation timed out
* Could not connect to host
* Closing connection #0

분석:

  • 서버 응답 시간이 초과된 경우 발생.
  • 서버 부하, 네트워크 문제 등의 경우 발생할 수 있다.

 

결론

curl의 로그를 통하여 통신 과정과 결과를 자세히 알 수 있다. 그리고 그 과정중 오류가 발생한다면, 어떤 단계에서 발생한 어떤 오류인지 빠르게 식별하고문제해결을 할 수 있을 것으로 기대한다.

 

ChatGPT4 DALL.E : 통신 오류를 만난 개발자