제임스딘딘의
Tech & Life

개발자의 기록 노트/Embedded Linux

[네트워크/프로토콜] BOOTP 에 대해서. BOOTP 클라이언트/서버의 메세지전송과 주소설정 방법

제임스-딘딘 2017. 5. 7. 11:57

BOOTP 에 대해서: BOOTP 클라이언트/서버의 메세지전송과 주소설정

BOOTP는 다양한 장치에 사용할 수 있지만, 최초 개발의 주된 동기 중 하나는 저장 장치가 없는 "멍청한"장치를 자동으로 구성하는 방법을 제공하는 것이었다.

대부분 이러한 멍청한 장치들은, 비교적 제한된 기능만을 가지고 있기때문에, 근사한 부팅 프로토콜을 지원하도록 요구하는 것은 사실 말이 되지않았다.

따라서 BOOTP는 복잡한 개념이나 근사한 개념 혹은 근사한 구현 요구사항 없이, 호스트 구성을 수행하는 복잡하지 않은 프로토콜이다.



BOOTP 클라이언트 및 서버

다른 많은 TCP / IP 프로토콜과 마찬가지로 BOOTP는 실제로 클라이언트 / 서버이다.
프로토콜의 작동은 BOOTP 클라이언트와 BOOTP 서버 간의 단일 메시지 교환으로 구성된다.

BOOTP 클라이언트는 구성해야하는 모든 유형의 장치가 될 수 있다.
BOOTP 서버는 BOOTP 클라이언트 요청에 응답하도록 특별히 설정된 네트워크 장치이며, 주소 지정 및 필요한 경우 클라이언트에 제공 할 수 있는 기타 정보로 프로그램이 구현된다.

BOOTP 서버는 서비스를 제공하는 클라이언트에 대한 특별한 정보 집합을 유지 관리한다.
여기에서 하나의 핵심 부분은 테이블이다.
이 테이블은 각 클라이언트의 하드웨어 (Layer 2, 데이터 링크 계층) 주소, 즉 MAC주소를 해당 장치에 할당 하고자 하는 IP 주소로 매핑하는 테이블이다.

클라이언트는 요청에서 하드웨어 주소를 지정하고, 서버는 이 주소를 사용하여 클라이언트의 IP 주소를 찾아서 클라이언트로 응답한다.
물론, 구현하기에 따라 다르고, 다른 기술도 사용할 수도 있겠지만, 매핑 테이블이 가장 일반적인 구현방법이다.


메시지 및 전송

그런데, BOOTP 메시징은 몇 가지 이유로인해, 계층 4 전송 프로토콜로 TCP가 아닌 UDP (User Datagram Protocol)를 사용한다. 

첫째, UDP는 다른 레이어 4 전송 프로토콜인 TCP보다 훨씬 덜 복잡하며, BOOTP와 같은 간단한 "요청 / 응답"프로토콜에 이상적이다.

둘째, 클라이언트가 분명히 BOOTP 서버의 주소를 알지 못하기 때문에 요청은 로컬 네트워크에서 브로드 캐스팅되야 한다.
UDP는 브로드 캐스트를 지원하지만 TCP는 브로드 캐스트를 지원하지 않는다.
BOOTP를 공부하는 정도라면 여러분들은 이미 알고 있을 것이다.

UDP는 BOOTP 서버에 대해 잘 알려진 (예약 된) 포트 번호 인 UDP 포트 67을 사용한다.
BOOTP 서버는 클라이언트가 보낸 이러한 브로드 캐스트 BOOTP 요청에 대해 포트 67에서 "수신 대기"한다.
요청을 처리 한 후 서버는 클라이언트에게 응답을 보낸다.
이 처리 방법은 클라이언트가 자체 주소를 알고 있는지 여부에 따라 다르다.


◎ 클라이언트가 주소를 알고 있는 경우
BOOTP 클라이언트가 이미 자신의 주소를 알고있는 경우가 있다. 이 경우는, BOOTP 서버가 이 주소를 직접 응답을 다시 보낼 때 사용할 수 있다.


◎ 클라이언트는 자신의 주소를 모르는 경우
물론 BOOTP는 주소를 모르는 클라이언트에게 IP 주소를 제공하기 위해 흔히 사용 된다. 
이것은 종종 "닭고기와 계란"문제라고 불리는데, 그 이유는 "닭고기와 계란"이라는 오래된 수수께끼와 같은 종류의 "고리"를 나타내기 때문이다.
이 딜레마를 해결하기 위해 BOOTP 서버에는 두 가지 선택지가 있다.
운영체제가 이를 지원하면 서버는 클라이언트의 하드웨어 주소를 사용하여 장치에 대한 ARP 항목을 만든 다음 레이어 2 유니 캐스트를 사용하여 응답을 전달할 수 있다.
그렇지 않으면 회신을 로컬 네트워크에서 브로드 캐스트로 전송해야한다.



브로드 캐스트 및 포트 사용

BOOTP 서버가 클라이언트로 다시 브로드캐스트 해야한다는 사실은 대부분의 TCP/IP 프로토콜이 클라이언트 포트를 사용하는 방식에서 약간의 변화가 필요하다.
일반적으로 클라이언트/서버 트랜잭션에 UDP 또는 TCP를 사용하는 클라이언트는 임시 또는 잠시사용하기 위한 포트 번호를 생성하여 요청메세지의 소스포트로 사용한다.

서버는 그 임시 포트 번호를 사용하여 클라이언트의 IP 주소로 응답을 보낸다.
임시 포트 번호는 특정 IP 주소에 대해 고유해야하지만, 네트워크의 모든 장치에서 고유하지는 않는다.

이해하기 쉽게 한가지 예를 들어 보면, 이런것이다.
하나의 네트워크상에 두 장치 A, B가 있다.
장치 A는 웹 서버에 대한 HTTP 요청에 임시 포트 번호 1248을 사용하고, 장치 B는 TCP/IP 스택에서 포트 번호 1248을 사용하여 DNS 요청을 보낼 수 있다.
서로다른 장치가, 동일한 네트워크상에 있다 하더라도, 동일한 포트 1248을 사용할 수 있다는 것이다.

BOOTP의 서버가 브로드캐스트이기 때문에 유니캐스트 전송을 사용하는 특정 장치를 대상으로하지 않는다.
즉, 일시적인 포트 번호로 안전하게 보낼 수 없다는 것을 의미한다.

네트워크상의 다른 장치는 다른 트랜잭션에 대해 동일한 임시 포트 번호를 선택했을 수 있으며 BOOTP 서버의 응답을 실수로 자기에게 보낸것으로 오인 할 수 있다.
이 문제를 피하기 위해 잘 알려진 다른 포트 번호가 BOOTP 클라이언트에만 사용된다.
UDP 포트 68 이 바로 그것이다.

클라이언트는 브로드캐스트 또는 유니캐스트 전송을 위해서 이 포트에서 수신 대기하지만, BOOTP 요청을 보낸적이 없는 클라이언트는 무시할 것이다. 
이 "이중 브로드 캐스트"BOOTP 통신 프로세스는 아래 그림에 나와 있으니 참고하자.

General Operation Of the Boot Protocol

이 그림을 간단히 설명하겠다.

장치 A는 IP 주소 및 기타 매개 변수를 확인하려고 시도하고 있다.

UDP 포트 67을 사용하여 로컬 네트워크에서 BOOTP 요청을 브로드캐스트 한 다음 포트 68에서 응답을 수신한다.

장치 D는 BOOTP 서버로 구성되어있고, 67 포트에서 수신 대기한다.

요청을 받으면 포트 68에서 A에게 IP 주소가 무엇인지 알려주는 브로드캐스트를 보낸다.

BOOTP는 브로드 캐스트를 사용하여 할당 된 IP 주소가없는 장치와의 통신을 허용하는 비교적 간단한 클라이언트/서버 프로토콜임을 생각하면 매우 간단한 과정이다.



세줄 요약 주요 개념

  1. BOOTP 클라이언트는 브로드 캐스트를 사용하여 청취 BOOTP 서버에 요청을 보낸다.
  2. 대부분의 경우 BOOTP 클라이언트 장치는 프로토콜을 사용할 때 자체 IP 주소를 알지 못한다. 
  3. 이런 이유 때문에 BOOTP 서버는 일반적으로 응답을 전송할 때 브로드 캐스트를 사용하여 클라이언트에 도달하는지 확인한다.

손실 된 메시지의 재전송

BOOTP 메시지 전송을 단순하게 하기위해 UDP를 사용할때의 단점은 전송 품질을 보장할 수 없다는 것이다.

UDP특성을 이미 알고 있겠지만, UDP는 신뢰할 수 없다.

즉, BOOTP 클라이언트로부터 전송된 요청메세지가 서버에 도착하기 전에 손실될수도 있고, 운좋게 서버에 도착했더라도, 클라이언트 방향으로 전송된 서버의 응답 메세지가  도착하지 않을 수 있다. 



이쯤 읽으면 '응? 장난하냐??' 하는 생각이 들겠지만, 진정하고 계속 읽어보자.

BOOTP는 이에대한 대비책을 가지고 있다.



UDP를 사용하는 다른 프로토콜과 마찬가지로 BOOTP 클라이언트도 재전송 타이머를 사용하여이 문제를 처리한다.

클라이언트가 일정 기간 후에 응답을받지 못하면 클라이언트는 요청을 다시 보낸다.


그러나 BOOTP 클라이언트는 재전송 전략을 구현하는 방법에 주의를 기울여야 한다.

한가지 문제시나리오를 가정해보자.
200대의 BOOTP 클라이언트가 있는 네트워크에서, 200대의 모든 클라이언트 전원이 꺼진다고 가정하겠다.
이 기계들은 거의 모두 비슷하게(심지어 동일하게) BOOTP가 구현되었을 것이기 때문에 전원이 다시 켜지면, 모두 재시작되며 거의 동시에 BOOTP 요청을 보내려고 할것이다.
왜? 구현이 동일하니깐.

대부분 이러한 문제로 인해 문제가 발생할 수 있다.
BOOTP 요청 메세지 일부가 손실되기도 할것이고, 심지어 서버가 과부하로 인해 일부 메세지를 drop해야 할 수도 있다. 
서버의 패킷큐 overflow 등의 이유가 예상된다.

그런데 모든 클라이언트는 전송을 실패했으므로 재전송을 하려 할 것이다.
이때, 각각의 클라이언트가 재전송을 위해 동일한 시간을 기다렸다가 재전송을 하게된다면?
그 시간이 지나면 모든 기계가 요청을 다시 보낼것이므로, 동일한 문제를 반복하게 될것이다. ...야 이 멍청이들아!!??

이와 같은 상황을 회피하기 위해 BOOTP 표준에서는 재전송주기 시간 값을 4 초부터 시작해서, 연속 시도를 위해 이 값을 지수적인 증가, 즉 두 배로 증가, 시키는 백 오프(Back-off) 방식을 사용할 것을 권장한다.
재전송을 위해서 말이다.
또한, 여러대의 BOOTP 클라이언트가 동시에 재전송을 하는 중첩 상황을 피할 수 있게 임의성 요소가 추가된다.
이 아이디어는 이더넷(ethernet)에서 사용되는 백 오프 방법과 매우 유사하다. 실제로 BOOTP 표준은 이더넷의 사양서(Specification)를 참조한다.

예를 들어, 첫 번째 재전송은 0에서 4 초 사이의 임의의 시간 간격 후에 발생시킨다. (임의의 양을 더하거나 뺀 값). 
필요한 경우 두 번째 재전송에서는, 0과 8 초 사이의 임의의 시간 간격에서 플러스 또는 마이너스 하는 등...
이렇게하면 재전송이 손실되는 가능성을 줄이는 데 도움이 되며, BOOTP의 과도한 트래픽으로 인해 네트워크가 중단되지 않도록 할 수 있다.