Nat기반 P2P 프로그래밍

2007.11.21 19:57

단장 조회 수:1627 추천:30

Nat-based P2P 의 이해
작성자 : 이창민 (chngmn@gmail.com)

예전에 stun이나 p2p와 관련된 프로그램을 짜보기 위해 여기저기 검색을 몇 일간 했었는데 한글 문서는 딱히 직접적으로 도움이 될만한 것을 쉽게 찾을 수 없었다. 그래서 개념적인 내용 위주로 nat기반 p2p를 이해하는데 조금이나마 도움이 될 만한 내용을 정리해 보았다.

[udp]
udp패킷은 도착한다 아니다 믿을 수 없다는 둥 얘기를 하는데 쉽게 말하자면 이것은 패킷이 도착했는지 아닌지를 보낸 쪽 에서 확인할 수 있는 기능 없는 것 뿐이다. 살을 붙여서 어렵게 만들 필요가 없다. 홀펀칭도 마찬가지다. 좀 있어 보이게 말하자면 이런 걸 신뢰 할 수 없다 라고 한다.

[session]
즉 연결이다. 홀펀칭에 관련된 중요하게 사용되는 개념이다. 두 개의 endpoint로 구성되며 session endpoint 는 ip/port의 쌍이다. session이 만들어 지기 위해서는 또 하나의 다른 session endpoint가 필요하다.

session endpoint <—> session endpoint
<———- session ———->

[nat의 종류]

nat는 대략 4가지 형태로 분류한다. 이렿게 구분은 하고는 있지만 중요한 것은 nat 를 몇가지로 분류 하는지가 nat-based p2p에서 이해 하는데 중요한게 아니라는 것이다. 분류는 어덯게 해도 상관없다.

RFC 3489의 정의에 따라 nat 종류를 분류해보면

Full Cone :
같은 ip와 port에서 출발하는 모든 요청(패킷)들은 외부로 나갈때 동일한 ip,port로 매핑된다. 게다가 모든 외부의 호스트는 매핑된 외부주소로 패킷을 보냄으로써 Nat 내부의 해당 호스트에게 패킷을 보낼 수 있다.

Restricted Cone:
내부의 호스트가 외부(ip가 X)로 먼저 패킷을 보낸 후에야 X에서는 내부 호스트 에게 패킷을 보낼 수 가 있다. 그 외는 Full Cone과 동일하다.

Port Restricted Cone:
ip뿐만아니라 port 번호도 제약받는 다는 것을 제외하면 Restricted Cone Nat와 비슷하다. 구체적으로 말하자면 ip주소가 X이고 port 번호가 P인 외부의 호스트는 내부의 호스트가 ip주소가 X이고 port번호 P인 곳으로 패킷을 먼저 보낸 후에야 패킷을 보낼 수 있다.

Symmetric:
Symmetric Nat는 특정 ip와 port로 향하는 모든 동일한 ip주소와 port의 패킷은 nat에 의해 동일한 외부 ip와port로 매핑된다. 만약 동일한 호스트에서 동일한 ip와 port로 해서 패킷을 보낼때 목적지가 바뀌면 다른 매핑이 사용된다.게다가 패킷을 받은 외부의 호스트만이 nat 내부의 호스트에게로 패킷을 보낼 수 있다.

위의 4가지 분류에서 기억해야 할 문장은 “동일한 ip,port로 해서 보낸다” 이다. 예를들어 내가 port번호 2000 으로해서 외부로 패킷을 보낸다면 nat는 나의 내부주소를 public주소로 바꿔서 보내게 되는데 이때 내가 누구에게 패킷을 날리던 nat는 항상 동일 하게 매핑시켜서 내보낸다는 말이다. Symmetric타입을 제외하면 다른 nat타입들은 이렇게 동작한다. Symmetric 아래의 호스트는 같은 주소를 사용 하여 패킷을 보낼 때 외부의주소(endpoint)가 바뀌면 public주소가 바뀐다.

어떤 환경아래에 있든 tcp/ip상에서 p2p통신을 하기 위해서는 우선 상대방이 사용하는 주소를 반드시 알아야 된다. 이것은 기본이다. 그리고 주소를 알았다면 누군가는 먼저 연결을 할 수가 있어야 한다. 정리하자면 p2p를 하기 위 해 필요 한 것은 기본적으로 그냥 통신을 하기 위해 필요한 것과 같다.  주소를 알고 그 다음에 연결하면  된다. 상대방도 마찬가지다. 여기에 기초해서 약간씩 다른 상황만 피해 나가면 된다.

통신을 위해 필요한 것
1.한쪽만이라도 상대방의 주소를 안다.
2.아는 쪽에서 연결한다.

그러나

서로간에 nat아래인 호스트간에 통신을 하려면
1.서로의 주소를 안다.
2.서로 연결을 시도하거나 약속을 하고 한쪽에서 연결을 시도한다.
(누가 먼저 연결하든 연결만 되면 된다)

다시한번 언급하지만 여기서는 서로가 nat아래인 상황을 가정한다. 이게 이해되는데 다른 상황이 쉽게 이해가 안된다는 것은 그 사람의 뇌가 nat 아래에 있는 것인지 모른다.

첫째인 “서로의 주소를 안다” 이다.
먼저 할 얘기는 주소를 아는 방법에 대한 것이다. 이것은 제3자가 알려주거나 그 내부 호스트가 먼저 직접 나에게 연결해 오거나 두 가지다. 내 친구가 아닌이상 일반적 으로 상대방의 미리 주소를 알 수는 없을 것이고 그건 상대방도 마찬가지다. 일반적으로 p2p 신을 위해 서로의 주소를 교환하기 위한 서버가 존재하게 된다. 데뷰서버(or Mediator) 라고 부르는 이 서버를 통해서 서로 주소를 교환하면 된다. 로써 서로의 주소는 서버를 통해 어렵지는 않게 알 수 있다.
(내가 먼저 열결할 수 없으니 서버를 통해 상대방이 나에게 먼저 연결 해 달라고 요청하는 것은 Connection Reversal이라고 한다. 이것은 홀펀칭하는 과정에서 중요한 개념이다.)
그런데 왜 둘다 서로 주소를 알아야 하나? 그것은 처음에는 서로가 서로에게 먼저 연결 수 없는 상황이 존재하기 때문이다. 그리고 이것을 해결하기 위해서 이다. ull Cone타입이 아닌 nat는 외부에서 내부 호스트에게로 먼저 연결해오는 것을 허용하지 않는다. 이런 nat타입의 경우 안에서 밖으로 먼저 연결하는 Outgoing session 만을허용한다. 그리고 이것을 기억해놓기 위해서 mapping table이란 것을 유지 한다. 외부에서 패킷이 도착하면mapping table을 찾아보고 해당 패킷에 대한 session정보가 있으면 통과 키는 것이다. 매핑 테이블에 등록 되려면 내부 호스트가 외부로 패킷을 보내야만 한다. 이렇게 한 후, 즉 내가 상대방에게 패킷을 보낸 이후에 도착하는 상대방패킷은나의 nat가 통과시키게 되는 것이다. 결론적으로 서로가 상대방에게 패킷을 한번씩만 보내면 그 이후부터는 각각의 nat가 상대방의패킷을 통과시킨다. 보다시피 개념은 간단하다. 서로가 주소를 알고 있어야 하는 것이다.

두번째인 “서로 연결을 시도한다”는 결국 위에서 한 이야기에 불과하다. 각자 자신의 nat에 상대편주소로 매핑테이블을 만들어 놓으면 상대방의 패킷이 나의 nat들을 통과할수 있게 된다. 이 상황을 만들기 위해 서로 연결을 시도하는 것이다. 처음 1-2개 패킷은버려지겠지만 이후의 시도는 성공한다.

이렇게 상대방이 들어올수 있도록 nat에 미리 매핑 하는 것을 홀펀칭이라고 한다.

여기까지면 대부분의 nat는 홀펀칭이 되지만 Symmetric타입은 다르다. Sym 타입은 nat 내부에서 같은 ip-port로 패킷을 보내 더라도 목적지가 다르면 다른 외부주소로 변환(매핑)한다. 즉 이쪽에서는 상대방이 접속 해올 수 있도록 “서버가 알려준 주소로 패킷을 미리 보내는 꼼수(홀펀칭)”로 세션을 테이블에 매핑을 시켜놨는데, 정작 상대방은 다른 주소를 통해서 접속해오므로, 결국 우리의 nat가 Full Cone nat가 아닐경우 그 패킷은 순순히 통과되지 못할 것 이고 Sym-nat 밑의 호스트와는 결국 통신할 수가 없다. 나도 보낼수 없고 (상대방이 엉뚱한 주소로 홀펀칭을 해서) 그리고 나도 상대방쪽으로 패킷을 보낼 수 없다 (나도 엉뚱한데 홀펀칭을 해서). 이렇다 하더라도 방법이 없는 것은 아니다. Sym-nat가 같은 ip-port에 대해서 다르게 매핑을 하더라도 변환이 규칙적이므로 우리는 우리에게 보낼때 사용한 주소를 충분히 예측 할 수 있다. port만 예측하면 되는데 물론 정해진 시간안에 100%로 성공 하지 못할 수 있다. 아마 상대방 nat는 상대호스트 혼자 사용하는 것이 아닐 수 있기 때문에 상황에 의존적인 방법으로 된다. 그러나 이런것도 불가능한 것만은 아니며 그렇다고 모두다 가능하다는 말은 아니다. 그래도 nat밑에 호스트가 수십대 이상이지 않는 한 시도해서 홀펀칭 성공률을 높이는 것도 가치가 있다고 생각한다. relay하지 않으면 않을 수록 좋다. 펀칭이 안되는 피어는 릴레이서버를 사용하여 C/S환경처럼 시뮬레이션 해주면 된다. Tcp 홀펀칭은 Udp만큼 운이 좋은 상황은 아니고 구현도 Udp보다 다소 복잡하지만 같은 방법을 통해 홀펀칭이 가능하다. 마지막으로 mapping table은 idle timer에 의해 일정 시간 동안 사용되지 않는 세션이라고 nat에 의해 판단되면 삭제된다. 보통 60초이다. 테스트 할때 이 점을 깜빡하면 곤란할 수 있다.

댓글 0

파일 첨부

여기에 파일을 끌어 놓거나 파일 첨부 버튼을 클릭하세요.

파일 크기 제한 : 0MB (허용 확장자 : *.*)

0개 첨부 됨 ( / )
 
목록
번호 제목 글쓴이 날짜 조회 수
» Nat기반 P2P 프로그래밍 단장 2007.11.21 1627
43 한국운전면허를 일본운전면허로 바꾸기 [2] 단장 2007.10.26 1351
42 NAT 홀펀칭 단장 2007.10.25 1293
41 버텍스버퍼의 효율적인 사용 단장 2007.10.01 5100
40 효율적인 동기화를 위한 아이디어 하나 단장 2007.09.29 3279
39 윈도우에서 사용하는 포트들 단장 2007.09.06 1157
38 평 <-> 평방미터 도량형 환산. 단장 2007.08.24 1145
37 [C++]function objects 단장 2007.05.01 1341
36 [C++] extern C에 대해 단장 2007.05.01 1256
35 원진살 단장 2007.04.14 1092
34 서울 시내에서 '무료'로 주차하기 단장 2007.03.06 976
33 이해의 선물 단장 2007.03.02 909
32 술의 이력서 단장 2007.02.09 2270
31 이스람(Islam:회교:回敎)에서의 성 단장 2007.02.08 1379
30 유명 다이아몬드들 단장 2007.01.31 960
29 자동차 정비용어 정리 단장 2007.01.20 1660
28 Mercedes-Benz, BMW, Audi 단장 2007.01.20 1030
27 No Silver Bullet 단장 2007.01.04 911
26 네크로노미콘 단장 2006.10.27 1234
25 Guitar World선정 최고의 기타솔로곡 단장 2006.06.14 245259