동물의 숲 wifi가 잘 안된다

Posted by 미스란디르 Sat, 15 Dec 2007 04:01:00 GMT

시작하기

요즘 동물의 숲을 하고 있다. 이거 무척 재미있는데, 게임이야기를 하려는 것은 아니고, 게임중에서 친구와 노는데 사용되는 wifi에 대한 이야기를 잠시.

동물의 숲은 닌덴도 DS용 게임으로 wifi(네트워크 플레이)를 지원한다. 이하 동숲.

동숲을 하면서 혹시 86420에러를 본적이 있는가? udp에러라고 한다. 사실 몰라도 상관없지만.

아무튼, wifi를 통해 친구네 마을에 놀러가기도 하고 놀러오기도 하고 그러면서 노는데

나랑 할때만 안된다나 뭐라나. 자꾸 저 에러가 뜨면서 접속이 안되는거다. 수십번 하다보면 되긴 되는데,

그냥 잘 되는 사람들도 있거든. 그중의 한분은 네트웍을 상당히 복잡하게 쓰셔서 그 탓이 아닌가 하고 네트웍 설정을 보기도 했다. 참고로 그분의 네트웍은

ndsl ------- (노트북 무선랜  ===  회사 유선랜) --------(VPN으로 어떤 서버에 연결) ------ (NAT를 통해서 외부로 연결) --------

이다. 그래서 VPN설정탓은 아닌지, NAT(리눅스에서 iptables로)탓은 아닌지 점검을 해 보았는데, 몇번 해봤지만 역시 될때는 되고 안될때는 안되더라

그래서 일단 어떤 일이 일어나는지 보기로 했다. 관심 없는 분은 10번으로 뛰어 넘으면 된다.

ndsl이 접속하는 과정 (놀러갈 때)

  1. 802.11b 네트웍으로 연결시도한다. DHCP로 세팅되어 있다면 아이피도 받아온다.
  2. http://conntest.nintendo.co.jp 로 간단한 GET 요청을 날려서 테스트페이지를 받아오는지 확인한다.
  3. acrossingds.available.gs.nintendowifi.net:27960에 udp패킷을 날리기 시작한다
  4. https://nas.nintendowifi.net 로 먼가 작업을 시작한다. 아마도 접속용 인증키를 발급 받는 것 같은데 https라서 까볼 수가 없었다 - 사실 여기서 squid를 가지고 중간자 공격을 시도했지만, 중간에서 가로채니까 ndsl이 바로 뻗어버렸다(이건 인증서가 달라져서 알 수 있는것 같다)
  5. gpcm.gs.nintentowifi.net:279990에서 challenge코드를 받아와서 다시 응답을 날린다. 그러고나서 다시 토큰을 받고, 자기가 등록한 친구들이 누구누구인지 서버에 얘기한다.
  6. http://www.nintendo.co.jp/ds/admj/oidydm/forestmailKOR.bin 로 GET요청을 보낸다. 결과데이터는 바이너리인데 뭔지는 모르겠다.
  7. acrossingds.ms12.gs.nintendowifi.net:28910 으로 역시 먼가 보내고 받는다
  8. acrossingds.natneg1.gs.nintendowifi.net:27901, acrossingds.natneg2.gs.nintendowifi.net:27901 로 "acrossing ds" 가 포함된 몇바이트짜리 udp패킷을 보낸다.
  9. 위에서 보낸 서버들이 뒤에 몇글자를 뺀 응답 패킷을 보낸다.
  10. tcp로 먼가 신호가 오고, natneg1:27901에서 상대편 아이피를 알려온다.

이제 어느 순간, 다음과 같은 패킷들이 오고간다. (111.111.111.57 은 상대편 공인 아이피, 222.222.222.57 은 내 공인 아이피)

22:13:50.458290 IP 111.111.111.57.1024 > 222.222.222.57.59375: UDP, length 20
22:13:50.460578 IP 222.222.222.57 > 111.111.111.57: ICMP 222.222.222.57 udp port 59375 unreachable, length 56
22:13:51.126067 IP 222.222.222.57.59375 > 111.111.111.57.63196: UDP, length 20
22:13:51.126120 IP 111.111.111.57 > 222.222.222.57: ICMP 111.111.111.57 udp port 63196 unreachable, length 56

원래는 서로 통신이 되야하는데, udp port unreachable이 발생한다. 대체 왜? 가만히 보니 포트번호가 이상하다.

내가 상대편에게 보낼때는 111.111.111.57:63196인데, 상대편이 보낼땐 111.111.111.57:1024 으로 온다.

복잡한 생각없이 보면 저게 쌍이 맞아야 할 것 같다.

그래서 계속 조사해보니 안될때는 계속 1024더라. 물론 저게 공유기 안쪽에서는 63196(이경우에는)으로 맞게 온다. 공유기가 바꾸는 것이다. 대체 왜?

wifi의 동작방식

여기서 또 잠깐. nintendo-wifi가 NAT-T(traversal)를 하기 위해 어떤 짓을 하고 있는지 보자.

원래 양쪽이 공유기이면 서버를 통하지 않고는 p2p 통신을 하기가 어렵다. msn에서 하고 있는 짓을 보면, 파일전송 따위의 p2p통신을 할 때

각각 서버를 열어서 상대편 서버로 접속 시도를 해보고, 되는 쪽으로 통신을 한다. 한쪽이 공인아이피를 그대로 쓰고 있다거나 DMZ를 쓴다면 그걸로 ok.

만약 양쪽 다 공유기라면 서버를 통해서 간다. 무슨 소리인지 모르겠다는 분은 그냥 넘어가자.

그런데 DS는 일단 무선랜이고, 인증기능도 단순하기 그지 없다. 따라서 상용 무선 인터넷 보다는 집에서 공유기로 접속할 확률이 3만배 많다. 즉 p2p에 있어서 최악인 공유기 vs 공유기인 설정. 그런데 똑똑한 닌텐도 개발자들은 재미있는 트릭을 썼다. 공유기 때문에 고민한 개발자라면 어떻게 안될까?.. 라고 생각해본적이 있을지도 모르는 트릭이다.

위에서 8번, udp패킷을 서버에 보내는 장면. 이때 서버는 저 패킷을 통해서 ds wifi 패킷이 처한 공유기 환경을 인식한다. 즉 외부 공인아이피가 뭔지를 확인하는 것이다. 그리고 아마도 10번에서 udp패킷으로 상대편 공인 IP / PORT 를 알려준다. 받자마자 ds는 접속시도.

공유기의 동작방식 - NAT가 무엇인가

이제 공유기에서는 어떤일이 일어나는가? 공유기들이 편리한 인터넷 환경을 위해서 무엇을 구현하고 있는가를 알아야 한다.

NAT(Network Address Translation) 은 S-NAT과 D-NAT이 있다. S-NAT은 흔히 말하는 인터넷 공유, 즉 소스 아이피를 바꿔주는 것이다.

D-NAT은 흔히 말하는 포트포워딩에 해당한다. 즉 목적지 주소를 바꿔주는 것이다. 공유기에서 S-NAT 설정을 하게 되면, 조건에 맞는 패킷이 지나갈 때 소스 아이피를 바꿔준다.

예를들면,

192.168.0.3: 공유기 안쪽 PC
192.168.0.1: 공유기 LAN쪽 IP
211.211.211.100: 공유기가 가진 공인 IP
100.100.100.100: 접속하려는 서버


192.168.0.3:54321 -> 100.100.100.100:80 LAN에서는 이랬던 패킷이,
====>  211.211.211.100:54321 -> 100.100.100.100:80 요렇게 변한다.

여기서 192.168.0.3:54321 -> 100.100.100.100:80 이나 211.211.211.100:54321 -> 100.100.100.100:80 을 tuple이라고 하고,

요것 두개를 묶어서 tuple pair라고 하자.

이게 변할 수 있는 것은, 외부로 나가는 패킷의 소스 주소를 211.211.211.100으로 변환해달라는 '규칙' 이 있기 때문인데, 들어오는 규칙에 대해서는 따로 설정을 한 적이 없다. (※ 나가는 규칙도 아이피를 직접 쓰는 일은 거의 없는데, 이건 MASQUERADE라고 해서 나가는 인터페이스의 IP주소를 그걸로 쓴다고 약속하기 때문이다)

그러면 응답패킷이 오면 어떻게 할까?

100.100.100.100:80 -> 211.211.211.100:54321 공유기 밖
====> 100.100.100.100:80 -> 192.168.0.3:54321 공유기 안쪽

가만히 보면 위쪽거랑 거꾸로다. 요걸 inverted tuple이라고 부르자.

이걸 보니, 나가는 패킷이랑 반대로 변환하면 다시 들어오는 패킷도 처리할 수 있을 것 같다.

즉 패킷이 하나 나가면 위의 4가지 정보(혹은 inverted는 생략하고 2가지만)가 공유기의 메모리 어딘가에 딱 생긴다. linux 는 요걸 conntrack (connection tracking)이라고 부르고 /proc/net/ip_conntrack 에서 볼 수 있다. 얘네들은 보통 상태정보도 가진다. tcp라면 SYN 보냄, SYN-ACK 받음, ACK 보냄(ESTABLISHED) 뭐 이런식이다. 또 패킷이 한쪽으로만 가고 한쪽으로 안갔다면 UNREPLIED. 양쪽 다 갔다면 ASSURED라는 딱지가 붙기도 한다.

그런데

가끔 재미있는 경우가 생긴다.

패킷 주소가 변환되는 과정을 다시 한번 보자.

PC가 한대가 아니라 2대이고, 우연히도

192.168.0.3:54321 -> 100.100.100.100:80
192.168.0.4:54321 -> 100.100.100.100:80

이라면,

먼저 온쪽이

211.211.211.100:54321 -> 100.100.100.100:80

을 차지하게 된다.

그럼 또 한놈은? 저걸 또 쓰면 겹치니까 그럴 수는 없고(응답 패킷이 왔을때를 생각해보자. 어찌 되겠는가. 혹은 서버입장에서도 마찬가지) 적당히 다른 번호를 준다.

211.211.211.100:1024 -> 100.100.100.100:80

왜 하필이면 1024인가 하면, 1023번 까지는 중요 포트라서 시스템에서만 쓰도록 하게 둔다. 이것보다 넓게 잡는 os도 있다.

이제 원인을 반쯤 알아냈다. 안될때 1024로 되는 이유는 바로 이거다.

.

.

.

아하

이런 경우는 정말정말정말정말 우연히 일어나기 때문에, ds에서 자꾸 접속이 안되는건 설명이 안된다. 그 수많은 pair가 겹칠리가 있는가? ds가 두대인것도 아니고. 같은 포트를 쓰더라도, 상대편 주소가 다르면 상관 없기 때문에 겹친다는건 말이 안된다.

사실 위 메커니즘을 다시 떠올리느라고 오랜만에 netfilter 소스를 돌아다니면서 기억을 되짚었다. 그러다가 생각난 "아하!"

바로 UNREPLIED conntrack의 존재이다.

222.222.222.57:59375 -> 111.111.111.57:63196

으 로 패킷이 갔다고 치자. 그리고 그게 111.111.111.57 공유기에 도착을 했다. 그런데, 111.111.111.57 공유기에서는 아직 자기쪽 DS에서 패킷이 안나온거다! 그럼 아무정보도 없는 공유기는, 지금 온 패킷을 진짜 자기에게 온 패킷으로 가정하고 시스템한테 던진다. 시스템에서는 이 패킷에 해당하는 listen 소켓이 없으니까 없다고 udp unreachable ICMP메시지를 날린다. 동시에, conntrack에는 이 패킷의 tuple이 UNREPLIED로 등록이 된다(!). 여기서 눈치 챘으리라. 정작 자기 DS에서 나온 패킷이 나갈 때, 이 포트를 쓸 수가 없는거다. UNREPLIED이지만 사용중인 것처럼 보이는거다.

아아 그렇다. 게다가 접속 시도 때문에 이쪽으로 패킷이 계속 오니까 이 tuple 정보는 없어지지도 않는다. 결국 접속시도는 실패.

근 데 양쪽에서 동시에 접속 시도를 한다고 하면 왜 이런일이 생길까? 이유는 간단하다. 네트웍 속도는 동일하지 않기 때문이다. A공유기에는 10ms 만에 서버에서 신호가 오고, B공유기에는 100ms 만에 왔다고 치면, B공유기까지 가는동안 A공유기를 거쳐서 들어갔다가 DS가 다시 응답하는데 충분한 시간일 수도 있다. 그리고 선로 속도는 평균이 있어서 쉽게 변하지 않기 때문에, 우연히 서버와의 속도만 나쁜 회선 사용자가 있다면 저 현상은 쉽게 고쳐지지 않을 것이다. 방법은 반대쪽 사용자가 DMZ같은 세팅을 하는 것 뿐.

사실은 공유기에서 저 UNREPLIED tuple을 만들지 않으면 되는건데.. 그게 실제로 unreachable일 경우에 그렇게 하면 안되는 이유라도 있는건지 모르겠다.

그래서 내가 떠올린 해결책 하나.

ds 에서 접속 시도 패킷을 쏠때, TTL을 1부터 시작해서 하나씩 늘리는거다. 그럼 공유기를 한단계씩 지나가겠지만, 그렇다고 상대편 공유기한테 바로 도달하지는 않는다. 이런식으로 길을 하나씩 뚫으면서 가면, 몇중으로 공유기로 둘러쌓인 환경이라도 문제 없지 않을까.

오늘따라 너굴 상점이 증축공사로 휴업을 하는 바람에 심심해서 써봤다. 재미없는 글 여기까지 읽어주시느라 고생하셨다.

Posted in  | Tags  | 9 comments | no trackbacks