사전 Telnet
프로토콜

Telnet

gabury1고친 사람 github-actions[bot]

Telnet 은 멀리 있는 컴퓨터에 글자로 접속하게 해 줍니다. 내 키보드로 친 글자가 상대 컴퓨터로 갑니다. 상대가 낸 글자는 내 화면에 찍힙니다. 주고받는 내용을 감추지 않아서 지금은 원격 접속보다 연결 점검에 더 자주 쓰입니다.

쉽고 빠른 이해

Telnet 은 멀리 있는 서버에 글자 창 하나를 열어 주는 규칙입니다. 서버실에 가지 않고 내 자리에서 서버의 명령 창에 명령을 치는 일이 그 예입니다.

이런 규칙이 없으면 기계마다 줄바꿈을 나타내는 글자도, 지운 글자를 알리는 방법도 달라서 서로 화면이 깨집니다. 양쪽이 같은 규칙으로 글자를 주고받기로 정해 두어야 어떤 기계끼리도 통합니다.

어떻게 도는가:

  1. 서버의 정해진 번호로 연결을 하나 엽니다
  2. 양쪽이 "글자를 되돌려 보여 줄까" 같은 세부 설정을 짧게 묻고 답합니다
  3. 그 뒤로는 내가 친 글자가 서버로 가고 서버의 출력이 내 화면으로 옵니다

대가도 있습니다. 비밀번호까지 전부 암호화 없이 오가서 길목에 있는 누구나 읽을 수 있습니다. 그래서 원격 접속은 암호화를 거는 다른 방식으로 넘어갔습니다. 지금은 서버의 아무 포트에나 연결을 열어 보고 그 포트가 응답하는지 확인하는 점검 도구로 주로 쓰입니다.

상세

Telnet 은 원격 컴퓨터와 글자를 주고받는 프로토콜입니다. 이 절은 먼저 Telnet 이 하는 일과 그 바탕인 연결을 봅니다. 이어서 서로 다른 기계가 같은 글자를 쓰게 하는 규칙, 글자 사이에 명령을 끼우는 방법, 옵션을 맞추는 대화와 그 대표인 에코를 봅니다. 그다음 한 접속을 처음부터 따라갑니다. 마지막으로 암호화가 없다는 약점, Telnet 의 규칙을 빌려 쓰는 다른 프로토콜, 지금 쓰이는 곳을 봅니다.

원격 컴퓨터에 키보드를 잇는 일

Telnet 은 내가 친 글자를 원격 컴퓨터의 입력으로 넣습니다. 원격 컴퓨터가 낸 출력은 내 화면에 찍습니다. 원격 컴퓨터 쪽에서는 그 입력을 셸이 받습니다. 셸은 사용자가 친 명령을 읽어 실행해 주는 프로그램입니다.

접속을 거는 쪽은 클라이언트, 받는 쪽은 서버입니다. 둘 사이의 길은 TCP(Transmission Control Protocol, 전송 제어 프로토콜) 연결 하나입니다. TCP 는 바이트를 보낸 순서대로 빠짐없이 전해 주므로 Telnet 은 글자가 사라지거나 뒤섞일 걱정을 하지 않습니다.

서버는 23 번 포트에서 접속을 기다립니다. 포트는 한 컴퓨터 안에서 어느 프로그램에게 가는 연결인지를 가르는 번호입니다. 웹 서버가 80 번에서 기다리듯 Telnet 서버는 23 번에서 기다립니다.

네트워크 가상 단말

단말기는 사람이 글자를 치고 결과를 읽는 입출력 장치입니다. Telnet 이 생길 무렵에는 단말기마다 글자를 다루는 방식이 달랐습니다. 줄을 바꾸라는 글자도, 앞 글자를 지우라는 글자도 기계마다 제각각이었습니다.

기계끼리 짝마다 번역 규칙을 두면 종류가 늘수록 규칙이 짝의 수만큼 불어납니다. Telnet 은 그 대신 가상의 단말기 하나를 정했습니다. 이것을 NVT(Network Virtual Terminal, 네트워크 가상 단말)라고 부릅니다. 양쪽은 저마다 자기 방식을 NVT 방식으로 바꿔서 보냅니다. 받은 것은 다시 자기 방식으로 바꿉니다.

flowchart TD
    A["기계 A · 자기 방식"]
    B["기계 B · 자기 방식"]
    C["기계 C · 자기 방식"]
    N["NVT · 연결 위의 공통 글자"]
    A <-->|"번역 하나"| N
    B <-->|"번역 하나"| N
    C <-->|"번역 하나"| N

연결 위에는 NVT 글자만 오갑니다. 그래서 새 기계가 생겨도 자기 방식과 NVT 사이의 번역 하나만 갖추면 모든 상대와 통합니다. 그림처럼 기계마다 화살표가 NVT 로 하나씩만 갑니다.

NVT 가 쓰는 글자는 7비트 ASCII(American Standard Code for Information Interchange, 미국 정보 교환 표준 부호)입니다. ASCII 는 영문자·숫자·기호와 몇 가지 제어 문자에 0부터 127까지 번호를 매긴 표입니다. 어느 기계든 이 표 하나만 알면 상대의 글자를 읽습니다.

줄의 끝은 CR(Carriage Return)과 LF(Line Feed) 두 글자를 이어 적습니다. CR 은 줄 맨 앞으로 돌아가라는 글자입니다. LF 는 한 줄 내리라는 글자입니다. 기계마다 다르게 적던 줄 끝을 이 한 가지로 맞춘 것입니다.

글자 사이에 끼우는 명령

글자만 보내서는 모자란 일이 있습니다. 상대에게 "지금 돌고 있는 일을 끊어라"라고 알리거나 글자를 되돌려 보여 줄지 같은 세부 설정을 바꾸자고 말해야 할 때입니다. Telnet 은 이런 세부 설정 하나하나를 옵션이라고 합니다. 명령은 따로 연결을 열지 않고 같은 글자 흐름 안에 끼웁니다.

명령의 시작은 값이 255 인 바이트로 알립니다. 이 바이트를 IAC(Interpret As Command, 명령으로 해석하라)라고 부릅니다. 받는 쪽은 IAC 를 만나면 그 뒤에 오는 바이트를 글자가 아니라 명령으로 읽습니다.

block-beta
columns 3
  a["IAC · 255"]:1 b["하자는 일 · 예: 253 = 해 달라"]:1 c["옵션 번호 · 예: 1 = 에코"]:1

옵션을 묻고 답하는 명령은 이렇게 세 바이트로 짜입니다. 첫 바이트는 명령이 시작됨을 알립니다. 둘째는 무엇을 하자는지, 셋째는 어느 옵션에 대한 것인지를 말합니다. 그림의 예는 「글자를 되돌려 보여 주는 기능을 켜 달라」는 요청입니다.

NVT 글자는 127 을 넘지 않으니 평소에는 255 와 겹칠 일이 없습니다. 그런데 옵션으로 8비트 바이트를 그대로 나르기로 하면 255 가 데이터로 나올 수 있습니다. 그때는 IAC 를 두 번 잇습니다. 받는 쪽은 255 255 를 보면 명령이 아니라 데이터 255 한 바이트로 읽습니다.

옵션 협상

Telnet 연결은 맨 처음에 가장 단순한 NVT 상태로 시작합니다. 앞 절에서 세부 설정이라 부른 옵션은 이 상태에 더하는 기능입니다. 글자를 되돌려 보여 주는 에코, 창 크기 알리기, 단말기 종류 알리기가 그런 옵션입니다.

옵션은 한쪽이 마음대로 켜지 못합니다. 한쪽이 제안하고 다른 쪽이 받아들여야 켜집니다. 이 주고받기를 옵션 협상이라고 부릅니다.

쓰는 명령은 넷입니다. 이름은 영어 동사를 대문자로 적은 것입니다. WILL(will, 하겠다)과 WONT(won't, 안 하겠다)는 자기 쪽이 옵션을 켤지 말하는 명령입니다.

DO(do, 해 달라)와 DONT(don't, 하지 말라)는 상대 쪽에게 옵션을 켜 달라거나 끄라고 하는 명령입니다. 그래서 답은 반대편 명령으로 합니다. WILL 에는 DO 나 DONT 로 답합니다. DO 에는 WILL 이나 WONT 로 답합니다.

보내는 명령 값 상대의 답
WILL · 내가 하겠다 251 DO 로 받아들이거나 DONT 로 거절한다
WONT · 나는 안 하겠다 252 DONT 로 확인한다
DO · 네가 해 달라 253 WILL 로 받아들이거나 WONT 로 거절한다
DONT · 너는 하지 말라 254 WONT 로 확인한다

켜자는 제안은 언제든 거절할 수 있습니다. 옵션을 모르는 쪽은 거절만 하면 됩니다. 그러면 연결은 기본 NVT 상태로 계속 돕니다. 덕분에 오래된 구현과 새 구현이 서로 모르는 옵션이 있어도 함께 돕니다.

끄자는 말은 거절할 수 없습니다. 표의 둘째·넷째 줄처럼 상대는 확인만 합니다. 어느 쪽이든 원하면 언제나 기본 상태로 돌아갈 수 있게 해 둔 것입니다.

서버가 맡는 에코

내가 친 글자가 화면에 보이는 것을 에코라고 합니다. Telnet 에서는 이 글자를 내 쪽이 바로 찍을 수도 있습니다. 서버가 받은 글자를 되돌려 보내 찍게 할 수도 있습니다. 기본은 서버가 되돌려 보내지 않고 내 쪽 프로그램이 친 글자를 직접 찍는 방식입니다.

실무에서는 대개 서버가 에코를 맡습니다. 그래야 서버가 화면에 무엇을 보일지 정할 수 있기 때문입니다. 서버가 하겠다고 말하고 클라이언트가 받아들이는 바이트는 이렇습니다.

0xFF 0xFB 0x01   // 서버: IAC WILL ECHO
0xFF 0xFD 0x01   // 클라이언트: IAC DO ECHO

바이트는 16진수로 적었습니다. 0xFF 가 255, 0xFB 가 251, 0xFD 가 253 입니다. 마지막 0x01 은 에코 옵션의 번호입니다.

서버가 에코를 맡으면 비밀번호를 가릴 수 있습니다. 비밀번호를 받는 동안에만 글자를 되돌려 보내지 않으면 됩니다. 사용자의 화면에는 아무것도 안 찍히지만 글자는 서버로 갑니다.

한 접속을 따라가기

지금까지 본 것을 한 접속에 모아 봅니다. 연결을 열고, 에코를 맞추고, 로그인해서 명령 창을 받는 데까지입니다.

sequenceDiagram
    participant 클라이언트
    participant 서버
    클라이언트->>서버: TCP 연결 · 23 번 포트
    서버->>클라이언트: IAC WILL ECHO
    클라이언트->>서버: IAC DO ECHO
    서버->>클라이언트: login:
    클라이언트->>서버: 사용자 이름 · 서버가 되돌려 보여 준다
    서버->>클라이언트: Password:
    클라이언트->>서버: 비밀번호 · 서버가 되돌려 보내지 않는다
    서버->>클라이언트: 셸 프롬프트

연결이 열리면 서버가 먼저 에코를 맡겠다고 제안하고 클라이언트가 받아들입니다. 그 뒤로는 로그인 안내와 사용자의 입력이 NVT 글자로 오갑니다. 비밀번호 대목에서만 서버가 에코를 멈춥니다. 로그인이 끝나면 셸이 명령을 기다린다는 표시인 프롬프트가 옵니다.

암호화 없는 연결

Telnet 은 주고받는 바이트를 암호화하지 않습니다. 이렇게 감추지 않은 내용을 평문이라고 부릅니다. 화면에서 가려진 비밀번호도 연결 위에서는 한 글자씩 평문으로 갑니다.

같은 망을 지나는 패킷을 엿볼 수 있는 사람은 그 비밀번호를 읽습니다. 패킷은 네트워크로 나뉘어 오가는 데이터 한 덩어리입니다. 공유기, 회사 망의 스위치, 중간의 서버 어디서든 엿볼 수 있습니다.

Telnet 에는 접속한 상대가 진짜 그 서버인지 확인하는 단계도 없습니다. 그래서 중간에 끼어든 기계가 서버인 척하며 오가는 내용을 읽고 바꾸는 중간자 공격을 막지 못합니다.

이 두 빈틈 때문에 원격 접속은 SSH(Secure Shell, 보안 셸)로 넘어갔습니다. SSH 는 같은 일을 하되 연결 전체를 암호화합니다. 접속 전에는 서버가 진짜인지 확인합니다. 서버는 22 번 포트에서 기다립니다.

FTP 가 빌려 쓰는 규칙

Telnet 의 규칙은 다른 프로토콜 안에도 들어 있습니다. 대표적인 것이 FTP(File Transfer Protocol, 파일 전송 프로토콜)입니다. FTP 는 파일을 올리고 받는 프로토콜입니다. 명령을 주고받는 연결과 파일을 나르는 연결을 따로 엽니다.

그 가운데 명령 연결이 Telnet 의 규칙을 따릅니다. 명령과 대답은 NVT 글자로 적습니다. 한 줄은 CR LF 로 끝납니다. FTP 명령이 사람이 읽을 수 있는 짧은 글자 줄인 까닭이 이것입니다.

지금 Telnet 을 쓰는 곳

원격 접속에는 거의 안 씁니다. 그 대신 telnet 클라이언트 프로그램이 연결 점검 도구로 남았습니다. 아무 서버의 아무 포트에나 TCP 연결을 열고 키보드를 붙여 주기 때문입니다.

상대가 Telnet 서버가 아니면 옵션 협상이 오지 않습니다. 그러면 telnet 은 맨 TCP 연결에 글자를 넣고 받는 창이 됩니다. 아래는 웹 서버의 80 번 포트에 연결해 HTTP(HyperText Transfer Protocol) 요청을 손으로 친 모습입니다. HTTP 는 웹 브라우저와 웹 서버가 주고받는 프로토콜입니다.

터미널
$ telnet example.com 80
GET / HTTP/1.1          // 손으로 친다
Host: example.com       // 손으로 친다
                        // 빈 줄로 요청 끝
HTTP/1.1 200 OK         // 서버의 첫 줄

빈 줄을 치는 순간 서버가 응답을 보냅니다. 연결이 열리기만 해도 쓸모가 있습니다. 그 포트에서 무언가가 듣고 있고 그 사이의 방화벽이 막지 않는다는 뜻이기 때문입니다.

Telnet 서버 자체는 오래된 망 장비와 작은 임베디드 기기에 아직 남아 있습니다. 공장에서 정한 비밀번호를 바꾸지 않은 채 23 번 포트를 열어 둔 기기는 자동으로 접속을 시도하는 공격 프로그램의 표적이 됩니다. 믿을 수 없는 망을 지나는 접속이라면 Telnet 대신 SSH 를 씁니다.

관련 항목

Telnet 이 얹히는 하위 프로토콜

TCP · IP · 포트 번호 · 소켓 · 바이트 스트림

Telnet 을 이루는 약속과 명령

NVT · Interpret As Command · 옵션 협상 · Telnet 옵션 · 에코 · CR LF · 서브네고시에이션 · Go Ahead

Telnet 이 키 입력을 이어 주는 단말과 셸

단말기 · 터미널 에뮬레이터 · TTY · 가상 터미널 · 셸 · ASCII

Telnet 대신 원격 접속을 맡는 프로토콜

SSH · rlogin · rsh · RDP · 시리얼 콘솔

Telnet 의 약속을 빌려 쓰거나 닮은 글자 명령 프로토콜

FTP · SMTP · HTTP · POP3 · IMAP

Telnet 이 드러내는 보안 약점

평문 · 패킷 스니핑 · 중간자 공격 · 기본 비밀번호 · 봇넷 · Mirai

Telnet 클라이언트 대신 포트를 점검하는 도구

netcat · curl · nmap · openssl s_client

Telnet 을 정의하는 표준 문서

RFC 854 · RFC 855 · RFC 857 · IETF

Telnet 이 속하는 상위 분류

응용 계층 · 원격 접속 · 네트워크 프로토콜 · 네트워크

다른 이름: TELNET · 텔넷