목공책 하나 들이셔요~

2014년 8월 25일 월요일

Goole Talk로 XMPP 배우기 #1

이 글은 Adarsh Ramamurthy가 작성한 "Fun with XMPP and Google Talk"를 기반으로 번역하고 내용을 추가한 것입니다. 총 두 편의 글이며 그 첫번째 입니다. 2007년에 작성된 것이라 좀 오래된 내용이긴 하지만, 의외로 XMPP에 대한 튜토리얼을 찾기 어렵네요. 신규로 진행하는 프로젝트에서 XMPP를 사용해야 해서 알아 본 내용입니다.  원문은 아래 링크를 확인하세요.

http://www.adarshr.com/papers/xmpp

Google Talk에 로그인 해 본적이 있으신가요? 그러면서 이면에서 어떤 일이 생기는지 궁금하지는 않으시던가요? 당신이 타이핑하는 문자들을 가지고 이 조그만 어플리케이션이 어떻게 요리하는지 생각해 본 적이 있나요? 어떻게 상대방이 타이핑을 하고 있는지 당신에게 알려주는 걸까요? 어떻게 상대방이 자리에 있는지를 실시간으로 알려주는 걸까요?

어느날 그 궁금증이 한계에 이르렀을때 저는 그것을 파헤쳐 보기로 했습니다. 이 두편의 기사를 통해 Google Talk이 어떻게 통신하는지를 찾아나서는 스릴 넘치는 모험을 담아 보겠습니다.


(원래 Google Talk은 XMPP 표준을 준수하고 음성/화상 채팅을 위한 Jingle 확장 표준도 준수했습니다. 그래서 Google Talk 클라이언트를 이용하여 다른 XMPP 메시징서버에 접속할 수도 있었고, Pidgin같은 다른 XMPP 클라이언트들도 GoogleTalk 서버에 접속할 수 있었습니다. 하지만 Google Talk이 Google Hangout으로 개편되고 나서 기능을 확장하기 위해 2014년 5월 XMPP와 Jingle 표준과 더 이상 호환되도록 노력하지 않는다는 발표를 했습니다. 그러므로 이 글의 내용은 현실에 맞지 않을 수 있습니다. 그럼에도 불구하고 제가 이 글을 번역하는 이유는 XMPP를 쉽게 이해할 수 있는 텍스트를 찾기 어려워서 입니다)

기본 지식

무엇보다 먼저 알아두어야 할 것은 Google Talk을 비롯한 어떤 통신 프로그램도 그 기저에는 소켓(socket)을 이용한다는 겁니다. 소켓을 이용한다는 것은 특정한 프로토콜로 네트웍킹을 한다는 뜻이기도 합니다. 그 중에서 TCP/IP는 가장 널리 쓰이고 인터넷에서 널리 사용되는 것이어서 지원도 많습니다. 현재 우리가 주로 사용하는 HTTP, FTP, SMTP 등의 프로토콜들은 모두 TCP/IP를 기반으로 하고 있습니다.

Google Talk이 사용하는 프로토콜

이제 Google Talk이 어떤 프로토콜을 사용하는지 알아낼 차례입니다. 두가지 방법이 있습니다. 첫번째 방법은 Google에 물어보는 겁니다. 두번째 방법은 좀 더 복잡하지만 스릴이 있는 방법입니다. 저는 두번째 방법으로 알아볼 겁니다.

현재 네트웍 패킷 분석을 할 수 있는 몇몇 프로그램들이 나와 있는데, 이들은 프로그램들이 주고 받는 프로토콜의 자세한 내용을 볼 수 있는 기능을 제공합니다. 예를 들어 TCP/IP 등의 패킷을 분석할 수 있습니다. 제가 고른 프로토콜 분석기는Wireshark입니다. (원 글에는 Ethereal을 언급했는데, 이 프로젝트는 상표권 문제로 2006년 5월에 이름을 Wireshark로 바꿉니다) Wireshark는 TCP/IP를 비롯한 다양한 프로토콜을 분석할 수 있는 대단히 복잡한 툴입니다. 하지만 UI가 잘되어 있어 익숙해지면 편리하고 더 좋은 점은 오픈소스에 무료 프로그램이라는 점입니다.


Wireshark를 잘 설치했으면 TCP/IP 패킷을 캡쳐하도록 두고, Google Talk 클라이언트를 띄운 다음 로그인을 합니다. 그러면 아래와 같은 식으로 로그를 볼 수 있습니다.


Google Talk은 talk.google.com 서버로 접속하는 걸로 알려져 있습니다. talk.google.com으로 ping을 때려보면 그 서버의 IP를 얻을 수 있습니다. 이 글을 쓸 당시는 209.85.137.125네요. 위 그림에서 Destination 칼럼이 209.85.137.125라고 되어 있는, 즉 행번호 120, 124를 주목할 필요가 있습니다. 그 행의 Source는 192.168.200.190으로 되어 있는데 이 IP는 제 컴퓨터 것입니다. 이로서 우리는 제 컴퓨터에서 Google Talk 서버인 talk.google.com으로 TCP/IP 패킷으로 뭔가를 전달함을 알 수 있습니다.

비슷한 방식으로 행번호 122, 128, 131처럼 talk.google.com에서 제 PC로 뭔가 응답을 보내고 있음을 알 수 있습니다. 이렇게 주목해야 할 행들의 Protocol 항목을 보면 모두 Jabber라고 되어 있음을 알 수 있습니다.

Jabber (그리고 XMPP)에 대해 알아보자

Jabber 홈페이지에서 볼 수 있는 설명을 보면... Jabber는 아래와 같이 정의되어 있습니다. 

Jabber는 "인스턴트 메시징의 리눅스"로 알려져 있습니다. 개방되어 있으며, 안전하고, 광고가 없는 메시징 서비스로 기존의 AIM, ICQ, MSN, Yahoo 메신저들을 대신할 수 있습니다. Jabber는 XML 세트로 정의된 프로토콜입니다. 이를 통해 두 네트웍 피어간에 실시간으로 메시지를 주고 받고, 부재 여부를 파악하며, 구조화된 정보를 전달할 수 있습니다.
Jabber는 일련의 부속 프로토콜을 정의하는데 XMPP는 그 중 핵심 부분입니다. XMPP는 eXtensible Messaging and Presence Protocol을 줄인 말입니다. 2004년 10월에 IETF 표준으로 승인되어 현재 RFC 3920으로 등록되어 있습니다.

이 글에서는 XMPP의 상세한 내용에 대해 다루지는 않을 겁니다. 요약하면 XMPP는 XML 기반의 프토토콜입니다. 이는 요청과 응답이 모두 XML로 이루어진다는 걸 의미합니다. Google Talk 클라이언트는 XML 메시지를 서버 talk.google.com으로 전달하고 그 응답도 역시 XML로 받습니다. 다음 절에서 XMPP의 핵심적인 내용이 무엇인지를 간단한 실험을 통해 알아볼 것입니다.

talk.google.com과의 XMPP 통신

Google Talk 서버가 이해하는 네이티브 언어로 얘기해 보시렵니까? 사실 그리 억지스러운 얘기는 아닙니다. 하지만 이를 시도하기 전에 XMPP 프로토콜의 본성에 대해 먼저 알아야 합니다.

XMPP는 메시징에 있어서 중요한 두가지 용어를 정의합니다. 스트림(Stream)과 스탠자(Stanza, 여러 행으로 된 싯구) 입니다. 이 둘의 정의는 다음과 같습니다.
  • 스트림 : 스트림은 두 피어간에 더 많은 XML 요소들을 주고 받기 전에 먼저 주고 받는 XML문서입니다. 이 두 피어는 클라이언트 혹은 서버일 수 있습니다. 나중에 주고 받게 될 더 많은 XML요소는 스탠자로 정의되며 바로 아래에 정의됩니다. 스트림은 반드시 루트 요소여야 합니다. 선택적인 XML 처리 프롤로그에 이어서 닫히지 않은 <streams:steam> 태그가 이어집니다. 스트림은 서버의 주소, 프로토콜의 버전과 몇몇 네임스페이스 정의들을 포함합니다. 
  • 스탠자 : 스탠자는 형식에 맞는 완전한 XML 요소로서 이미 열려진 XML 스트림 내에 포함되어 전달됩니다. 스탠자는 보통 XML 문서의 첫번째 자식입니다. XMPP 코어는 세가지 타입의 스탠자를 정의합니다. 그것들은 <presence>, <message> 그리고 <iq>입니다. 
하나의 스트림 안에는 여러개의 스탠자가 포함될 수 있습니다. 대부분의 정보들은 스탠자의 내부에 포함된 태그와 속성에 실려 전달됩니다. 스탠자에 대한 더 자세한 설명은 XMPP 문서를 보는 것이 좋습니다.

이제 실제로 클라이언트와 서버간에 어떤 일이 일어나는지 실제 통신 세션을 보도록 합시다. 아래는 클라이언트와 서버의 전형적인 상호작용을 보여 줍니다. 읽기 쉽게 하기 위해 클라이언트에서 서버로 보내는 XML은 파란색으로, 서버에서 클라이언트로 보내는 XML은 빨간색으로 표시했습니다. 이보다 더 많은 예제들은 RFC 3920인 XMPP 코어 문서를 보시기 바랍니다.


<?xml version="1.0"?>
<stream:stream 
  to="example.com" 
  xmlns="jabber:client" 
  xmlns:stream="http://etherx.jabber.org/streams" 
  version="1.0">

<?xml version="1.0"?>
<stream:stream 
  from="example.com" 
  id="someid" 
  xmlns="jabber:client" 
  xmlns:stream="http://etherx.jabber.org/streams" 
  version="1.0">

... encryption, authentication, and resource binding ...

<message 
  from="juliet@example.com" 
  to="romeo@example.net" 
  xml:lang="en"> 
  <body>Art thou not Romeo, and a Montague?</body> 
</message>

<message 
  from="romeo@example.net" 
  to="juliet@example.com" 
  xml:lang="en"> 
  <body>Neither, fair saint, if either thee dislike.</body> 
</message>

</stream:stream>

</stream:stream>

위 메시지 패턴을 보면 두 개의 XML 문서가 포개져 있음을 볼 수 있습니다. 하나는 클라이언트가 열고 닫은 것이고, 다른 하나는 서버가 열고 닫은 것입니다. 실제 통신에서는 이 두 XML 문서는 조각나서 흩어진 모양으로 존재합니다.

자 이제 직접 talk.google.com과 대화해 보도록 합시다. 우리가 구사할 언어는 XMPP가 되고 TCP/IP로 전달될 겁니다.

어떤 서버와 네이티브 프로토콜로 통신하기 위해서는 그 서버의 특정 포트로 터미널 세션을 열어야 합니다. Microsoft Telnet 클라이언트 등의 다양한 텔넷 클라이언트를 사용할 수 있지만 저는 Putty를 쓰기로 합니다. 저는 오랫동안 Putty를 써 왔습니다.

먼저 talk.google.com 서버의 5222 포트로 접속하도록 Putty를 설정합니다. 5222는 Jabber 프로토콜에서 SSL을 사용하지 않는 디폴트 포트 번호입니다. SSL을 쓰려면 5223 포트를 사용합니다. SSL로 암호화된 패킷을 손으로 쳐서 보낼 수는 없으므로 5222 포트를 택합니다.


아래 스크린샷은 실제로 주고 받는 XMPP 패킷을 보여 줍니다. 첫번째와 세번째 XML 조각은 클라이언트가 보낸 것이고, 두번째와 네번째 조각은 서버가 보낸 것입니다. 


제일 윗줄에서 "to" 속성에 "gmail.com"을 넣은 것에 주목하세요. 이 XML을 받으면 서버는 서버가 지원하는 여러 기능들과 암호화 방법 등을 보내줍니다. 서버가 보낸 <starttls><required/></starttls> 구문은 클라이언트로 하여금 TLS 암호화를 사용해야 함을 강제합니다. 그러므로 클라이언트는 세번째 조각처럼 <starttls/> 요소를 보내야 합니다. 이것은 TLS 협상을 받아들임을 의미합니다.

마지막 줄은 서버가 클라이언트로 하여금 협상된 TLS 정책으로 인증을 진행할 것을 지시합니다. 이어서 SASL(Simple Authentication and Security Layer) 협상이 이어집니다. 여기부터는 매우 복잡하므로 생략합니다.

인증 절차가 완료되고 나면, 클라이언트와 서버는 여러 스탠자들을 주고 받을 수 있습니다. 하지만 우리는 이 단계에서 눈으로 볼 수 있는 XML을 주고 받을 수 없습니다. 이 단계 이후로는 협상된 TLS 정책에 의해 암호화된 내용이 왔다 갔다하기 때문입니다.

다음 글에서는

지금까지 어떤 어플리케이션에서 사용하는 프로토콜이 무엇인지 알아내는 방법을 보았고, 이를 통해 Google Talk이 Jabber 프로토콜을 사용함을 알 수 있었습니다. 그리고 XMPP의 기본적인 내용에 대해서 알아 보았습니다. 심지어 우리는 앞부분만 이지만 Google Talk 서버와 직접 XMPP로 대화도 해 보았습니다. 다음 글에서는 한단계 수준을 올려서 XMPP의 다양한 기능을 Google Talk를 통해 알아보도록 합니다.

댓글 없음:

댓글 쓰기