UNIX/LINUX network programming 2
(������ telnet client ���α׷��� ����)

    ������(�ѱ��װ����б� ��ǻ�Ͱ��а�)
    Hitel ID : MonaC
    E-mail : monac@ee.korea.ac.kr

     

 

1. �ڳ� ��������

    �ڳ��� ���ͳ� ���� �ٸ� ��ǻ�ͷ� �α����� �� �� �ְ� �ϴ� ���������̴�.
    �ڳݿ��� Ŭ���̾�Ʈ�� �Է� ����̽�(Ű����)�� ��� ����̽�(�����)�� ������, �ڳ� ���� ���α׷��� ���� �ִ� ���� ȣ��Ʈ�� �α��� �Ѵ�. �̶� ���� ȣ��Ʈ�� �Է°� ����� Ŭ���̾�Ʈ�� �Է°� ������� ��ġ�ȴ�. �ڳ� ���������� �⺻ ��ǥ�� �ڳ� ����� �ڳ� Ŭ���̾�Ʈ�� ���� ���� �α��������� ���� �ٸ� �뵵�� ���� ���� �ִ�.

 

2. �ڳ� ���ɾ�

    �ڳ� ���������� ������ Ŭ���̾�Ʈ ���θ� �����ϱ� ���Ͽ� ���� ���ɾ ����Ѵ�. �̷��� ���ɾ�� IAC(interpret as command)���� ������ ��������.
    IAC�� �ƽ�Ű �ڵ� 255���̴�.

     

    �̸�   ascii��ȣ                     �ǹ�

    SE      240    End of subnegotiation parameters.
    NOP    241    No operation Data mark. Indicates the position of a Synch
                       event within the data stream.
    DM     242    This should always be accompanied by a TCP urgent
                       notification.
    BRK   243     Break. Indicates that the "break" or "attention" key was hit.
    IP      244     Suspend, interrupt or abort the process to which the NVT is
                       connected.
    AO     245    Abort output. Allows the current process to run to completion
                       but donot send its output to the user.
    AYT    246    Are you there. Send back to the NVT some visible evidence
                       that the AYT was received.
    EC     247     Erase character. The receiver should delete the last preceding
                       undeleted character from the data stream.
    EL     248     Erase line. Delete characters from the data stream back to but
                       not including the previous CRLF.
    GA    249      Go ahead. Used, under certain circumstances, to tell the
                       other end that it can transmit.
    SB    250      Subnegotiation of the indicated option follows.
    WILL  251     Indicates the desire to begin performing, or confirmation that
                       you are now performing, the indicated option.
    WONT 252    Indicates the refusal to perform, or continue performing, the
                       indicated option.
    DO    253     Indicates the request that the other party perform, or
                       confirmation that you are expecting the other party to perform,
                       the indicated option.    
    DONT 254    Indicates the demand that the other party stop performing, or
                       confirmation that you are no longer expecting the other party
                       to perform, the indicated option.
    IAC    255     Interpret as command.


    < ǥ1 telnet commands >

 

3. �ڳ� �ɼ�

    ���� ���� ���� ���¸� �����ϱ� ���� �ɼ��� �ִ�. �� �ɼǵ��� �������� �缳���� �� ������, ������ Ŭ���̾�Ʈ ��� �ʿ����� ������ �� �ִ�. �ɼ��� ��Ȯ�� ������ ������ rpc�� ���� �Ͽ��� �Ѵ�.

     

    ascii��ȣ      �̸�                              RFC��ȣ

    1               echo                               857
    3               suppress go ahead           858
    5               status                              859
    6               timing mark                      860
    24              terminal type                   1091
    31              window size                    1073
    32              terminal speed                1079
    33              remote flow control          1372
    34              linemode                        1184
    36              environment variables      1408


    < ǥ2 �߿��� �ɼǵ��� rfc��ȣ>

    �ɼ��� Ŭ���̾�Ʈ�� ���� ��� ���ʿ��� �䱸�� �Ͽ�, �ٸ� �� �ʿ��� �װͿ� �����ϴ� ���·� �����ȴ�. �ɼ��� �䱸�� ����

     

    IAC, <�䱸�� ����>,<�ɼ�>

     

    �� ���ʷ� �ڵ带 ������, ���� ���� ���� ����̴�.
    �䱸�� ���´� ������ 4������ �ִ�.

     

    ��ȣ       ascii��ȣ     �䱸�� ����

    Will        251            �ɼ��� ����ϰڴ�.
    DO        252            (���濡��) �ɼ��� ����϶�.
    WONT    253            �ɼ��� ������� �ʰڴ�.
    DONT    254            (���濡��) �ɼ��� ������� ����

     

    WILL�̳� WONT�� �ɼ��� �䱸�ϴ� ���� �� �ɼ��� ��� �Ǵ� ������� �ʰڴٴ� ���̸�, DO�� DONT�� �������� �ɼ��� ��� �Ǵ� ������� ����� �䱸�ϴ� ���̴�.

    ���ʿ��� �䱸�� �ϸ� ������ ������ �ؾ� �Ѵ�. �䱸�� ������ ������ ������ ��츸�� �����ϴ�.

     

    �䱸          ����           ������ �ǹ�

    WILL         DO             �ɼ� ����� ����Ѵ�.
    WILL         DONT         �ɼ� ����� ������� �ʴ´�.
    DO           WILL           �ɼ��� ����ϰڴ�.
    DO           WONT         �ɼ��� ����� �� ����.
    WONT       DONT         �ɼ��� ������� �ʰڴ�.
    DONT       WONT         �ɼ��� ������� ����.

     

    SB���ɾ�� �ϳ� �̻��� �ɼ��� �ʿ�� �� �� ���ȴ�. �͹̳� Ÿ���̳�, �͹̳��� ũ�� ���� ������ �޴µ� ���ȴ�.

    �ڳ� Ŭ���̾�Ʈ�� �ڳ��� �ɼ� ���� ������ ���캸��.

     

    monac:~$telnet
    telnet> toggle options
    Will show option processing.
    telnet> open localhost
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    SENT DO SUPPRESS GO AHEAD
    SENT WILL TERMINAL TYPE
    SENT WILL NAWS
    SENT WILL TSPEED
    SENT WILL LFLOW
    SENT WILL LINEMODE
    SENT WILLOLD-ENVIRON
    SENT DO STATUS
    SENT WILL XDISPLOC
    RCVD DO TERMINAL TYPE
    RCVD DO TSPEED
    RCVD DO XDISPLOC
    RCVD DO NEW-ENVIRON
    SENT WONT NEW-ENVIRON
    RCVD WILL SUPPRESS GO AHEAD
    RCVD DO NAWS
    SENT IAC SB NAWS 0 80 (80) 0 25 (25)
    RCVD DO LFLOW
    RCVD DONT LINEMODE
    RCVD DONT OLD-ENVIRON
    RCVD WILL STATUS
    RCVD IAC SB TERMINAL-SPEED SEND
    SENT IAC SB TERMINAL-SPEED IS 9600,9600
    RCVD IAC SB X-DISPLAY-LOCATION SEND
    SENT IAC SB X-DISPLAY-LOCATION IS "monac:0.0"
    RCVD IAC SB TERMINAL-TYPE SEND
    SENT IAC SB TERMINAL-TYPE IS "XTERM"
    RCVD DO ECHO
    SENT WONT ECHO
    RCVD WILL ECHO
    SENT DO ECHO
    Debian GNU/Linux 1.3 monac.hackers.org
    Monac login: Connection closed by foreign host.


    ���� ����� �ɼǿ� ���� �ڼ��� ������ �����Ѵ�. �ҽ��� �м��ϸ鼭 ������ ������ ��
    ÷���ϵ��� �ϰڴ�. �������ݿ� ���� �ڼ��� ������ RFC�� �����ϱ� �ٶ���.

 

4. �ڳ� Ŭ���̾�Ʈ

    ���α׷��� �ҽ��� ���������� ó���ϴ� protocal.c�� �� ���� ��� �Լ��� ���Ե� telnet
    �� �������� �ִ�. �� ���Ͽ� �������� �ʿ��� �Լ��� telnet.h���� ����Ǿ���.
    �Ʒ��� ������ ���α׷� �ҽ��� ���鼭 �о�� �ٶ���.

    �ڳ� Ŭ���̾�Ʈ�� �ؾ� �� ���� �⺻������ ������ ����.

    -�������� stream socket ������ �Ѵ�.
    -���ϰ� ����ڷκ��� �����͸� �а� ����.
    -���� �����͸� �Ľ��Ͽ� ���������� ó���Ѵ�.

���� ���� �� �ʱ� ����

    ������ ������ �����ϴ� ������ �ٸ� stream socket�� �̿��ϴ� ���α׷��� ���������� ��
    ��. �츮�� ���������κ��� �ּҿ� ��Ʈ�� �Է¹ް�, �װ����� ������ ���� ������ �õ��Ѵ�. �̷��� ������ main()�Լ����� ó���ȴ�.
    ������� ������ ���� ȣ�� ���¿��� �ڼ��ϰ� �ٷ�����Ƿ� ���⼭�� �����Ѵ�.

    �ҽ��� main()���� �Ҹ������� init_system()�Լ��� ���캸��.
    �� �Լ������� read_buf, write_buf ����ü�� �ʱ�ȭ�ϰ�, SIGPIPE�� ���� �ñ׳� �ڵ鷯��
    ��ġ, ������ nonblock ���·� ����, �׸��� �͹̳��� �����Ѵ�. Read_buf, write_buf����ü�� ���ؼ��� �ڿ��� �����ϰڴ�
    �츮�� ���μ����� �����Ǵ� ���� ���� ���� ������ nonblock ���·� �����.
    ������ ������ ��쿡 �Ͼ��.

    -���Ͽ� read()�� ȣ���ߴµ� ���� �����Ͱ� ���� ��.
    -���Ͽ� write()�� ȣ���ߴµ� ���忡 �� ���� ���� ��.
    -ioctl()�� ���忡 ����� �� ���� ��.

    �� �ܿ��� ���� ��찡 ������ �� ���α׷������� ���� ��쿡 ������ �Ͼ��. ������ �Ͼ�� ���μ����� ������ ������ ������ ���߾� ����.
    �ڳݿ����� ���� �۾��� ���ÿ� �����ϹǷ� ������ �Ͼ�� ���� ���ƾ� �Ѵ�.
    nonblock ��忡���� ���� �۾��� ����� �������� �ʴ´ٴ� ���� �����Ѵ�.
    ���� nonblock ���·� �����߱� ������ �۾��� �ϼ����� �ʴ´ٸ� �ش� �ý��� ȣ���� ������ �����ϰ�, errno ������ EWOULDBLOCK���� ������ ���̴�.
    nonblock�� ������ ������ ���� ��������.

     

    void nonblock(int onoff)
    {
      if (ioctl(sock, FIONBIO, &onoff)<0)
      {
        perror("ioctl");
        sys_error();
      }
    }

     

    ������ ������ ������ ������ read()�� 0�� �����ϰ� ���� write()�� SIGPIPE �ñ׳��� �߻��Ѵ�. SIGPIPE �ñ׳��� ����è���μ� ���� ������ ������ ���� �� �� �ִ�.

     

    Signal(SIGPIPE,peer_died);

     

    SIGPIPE �ñ׳��� peer_died()�Լ��� ����Ǿ���. Peer_died()�Լ��� ������ ������ ������ ���� ���� ó���� �����Ѵ�. �׷��Ƿ�, ������ ������ �������� write()�� SIGPIPE �ñ׳��� �߻���Ű�� peer_died()�Լ��� ����ȴ�.
    set_terminal()�� ������ �ڳ� ���¿� ���� �͹̳��� �����ϴ� �Լ��̴�.
    �͹̳��� ���´� �ڳ� �������ݷ� ������ �ȴ�. set_terminal()�� �μ��� 0�� ���� �͹̳���
    ������ ���·� �ǵ��� ���´�.  
    �� �������� main() �Լ��� init_telnet((port ==23));�� �����Ѵ�.
    init_telnet()�Լ��� �ڳ� ���������� �Ľ��ϱ� ���� �������� �ʱ�ȭ �ϰ�, �ڳ� ������ �ڳ� ������� ������ �� �ڳ� ������ �ʱ� ������ ���� ���������� ������. �Ϲ������� �ڳݵ����� ��Ʈ�� 23���̹Ƿ� ���⼭�� �� ��Ʈ��ȣ�� �ٰ��ؼ� �ڳ� ������� ���������� �Ǵ��Ѵ�.

main_loop()

    main-loop() �Լ��� �ڳ� Ŭ���̾�Ʈ�� �Ϲ����� �۾��� �����Ѵ�. �ϳ��� ���ѷ����� �� �Լ��� ���ϰ� �������� �����, �װ��� �������� ó�� �׸��� Ű����κ����� �Է��� ó���ϴ� ������ �ݺ��ؼ� ó���Ѵ�.
    �̷��� �۾��� select()�ý��� ȣ���� �̿��Ͽ� �̷������.
    �ڳݿ����� ���۵Ǵ� �����Ϳ� ���� ���������� ó���ؾ� �ϸ�, ȿ�������� �����͸� �����ؾ� �ϱ� ������ �츮�� �Է°� ��¿� ���� ���۸� �����Ͽ���.
    ���۴� write_buf�� read_buf�� ������ �̰��� ���� buffer����ü�̴�.

     

    Struct buffer
    {
      char buf;       /*�����͸� ������ �ּҰ���*/
      int size;         /*buf�� �Ҵ�� �޸��� ũ��*/
      int head, tail; /*buf�� ����� �������� ó���� ���� �ε��� */
      int count;      /*buf�� ����� �������� byte��*/
    };

    struct buffer write_buf, read_buf;

     

    �츮�� ���Ͽ� �� �����ʹ� ���� write_buf�� ����ȴ�. �� �����ʹ� main_loop()���� select()�ý��� ȣ��� ���Ͽ� �����͸� �� �� �ִٴ� ���� Ȯ�ε� �ڿ��� write_socket()�Լ��� ���ؼ� ������ ������ �ȴ�. �������� ���� �����ʹ� ���� �����Ͱ� ���� ������ read_socket()�� ���ؼ�, ��� read_buf�� ����ȴ�. read_buf�� ����� �����ʹ� �������� ó���� ���Ͽ� process_protocol() �Լ����� ��������. ǥ3�� �̷��� �������� ó�� ������ ���������� �׸� ���̴�.

     

    KEY_BOARD  --------> write_buf --------> Socket output
              Read_terminal()        write_socket()
    TERMINAL  <--------  read_buf  <-------- Socket input
              Process_protocol()       read_socket()

     

    <ǥ3 ������ ó������>
    main_loop()�� �̷��� ������ �ݺ������� ó���Ѵ�.

���� ó�� �Լ�

    �ڳ� ���������� ó���ϴ� �������� �츮�� ���������� ���������� ���� ���� �־�� �ϰ�, ���Ͽ��� ������ �����͸� �Ľ��Ͽ� �������� ó���� �� ������ read_buf���� �ϳ��� ���ڸ� �о �ʿ��� �������� �κ��� �����ؾ� �Ѵ�.
    �̰��� ���ؼ��� write_buf�� ������ �����͸� �� �� �ִ� �Լ��� �ʿ��ϰ�, read_buf���� �����͸� ���Ƿ� �о� ���̴� �Լ��� �ʿ��ϴ�.

    putc_socket()�� puts_socket()�� write_buf�� �����͸� ����ִ� �Լ��̴�.
    putc_socket()�� �ϳ��� ���ڸ���, puts_socket()�� �ϳ��� ���ڿ��� �μ��� �޴´�. �� �Լ����� ������ ���������� �����ϱ� ���� ������ ���̴�.
    putc_socket()�̳� puts_socket()�� ���޵� �����ʹ� write_buf�� ����� ���̰�, �̰��� Ű����κ��� ���� �����Ϳ� �Բ� ������ ���� ������ ���۵ȴ�.
    getc_socket()�� read_buf�κ��� �ϳ��� ���ڸ� ������ ����.
    Putc_terminal()�� �ϳ��� ���ڸ� �͹̳�, �� ȭ�鿡 ����ϴ� �Լ��̴�.

    �̷��� �����Լ����� ���� ���������� ó���ϴ� �������� �ʿ��� �Լ����̴�.
    ǥ3�� ������ ó���������κ��� ���ٸ�, �� �Լ����� ���� process_protocol()�Լ����� ��
    ��� �Ѵ�.

�ڳ� �������� �Ľ�

    process_protocol()�� read_buf�� ����� �����͸� �Ľ��Ͽ� �ڳ� ���������� ó���Ѵ�. ��
    �Լ��� main_loop()���� read_buf�� �����Ͱ� ���� ���� �ҷ�����.
    �ڳ� ���������� ���� ���� #define ���� arpa/telnet.h�� ���ǵǾ� �ִ�.

     

    #define TELCMDS
    #define TELOPTS
    #include <arpa/telnet.h>

     

    ���⼭ TELCMDS, TELOPTS�� #include �տ��� ������ ������ telnet.h�� �ִ� �ڳ� ���ɾ� ���̺��� telcmds��, �ڳ� �ɼ� ���̺��� telopts�� ����ϱ� ���ؼ��̴�.
    Process_protocol()������ read_buf���� ���������� �����ϰ�, ���������� �ƴϸ� ȭ�鿡 ����ϴ� �۾��� �Ѵ�. �ڳ� ���ɾ�� �׻� IAC�� �����Ѵ�.
    getc_socket()�� read_buf���� �ϳ��� ���ڸ� ������ ����. �� ���ڰ� IAC�̸� ���� ���ڵ��� �ڳ� ���ɾ�� �ν��� �ϰ� �Ľ��ϰ� �ȴ�. �ƴ϶�� putc_terminal()�� �̿��Ͽ� ȭ�鿡 ����Ѵ�.
    �츮�� ������ �ڳ� ���ɾ�� DO , DON'T, WILL, WONT���� �����ϴ� �ڳ� �ɼǰ�, SB�� �����ϴ� �ڳ� ���� �ɼ��̴�.

�ڳ� �ɼ� ó��

    process_option()�� IAC+[DO|DONT|WILL|WONT]���� ���۵Ǵ� �ɼ��� ó���ϴ� �Լ��̴�. �ɼ��� ó���ϴµ� �־ ���� ����� ���� �ڳ� �ɼ� ���� ������ ��Ī���̶� ���̴�. �� �� ���� �ɼ��� ���� �� �ְ�, ���� ���� �־�� �Ѵٴ� ���̴�. �̷� ���� �����κ��� ���� �ɼ��� �츮�� ���� �ɼ��� �������� �ƴϸ� �䱸�� �ϴ� ���������� �����ϱⰡ ��ƴ�. �� ó���� �ϱ� ���ؼ� option[]�迭�� �������.

    options[]�� ������ �ʵ�� �ش� �ɼǿ� ���� �䱸�� �ߴ����� ���θ� �����Ѵ�.
    �� �迭�� �ٷ�� ���� �����Լ� option_requeted()�� option_request()�� �ִ�.
    option_request()�� option[]���� �ش� �ɼ� �ʵ带 �䱸�ÿ��� 1 ���� ��Ű��, ����ÿ��� 1 ���ҽ�Ŵ���μ� ������ �䱸 ���¸� �����Ѵ�.

    option_requested()�� �ش� �ɼ��� �䱸�Ǿ����� ���θ� �Ǵ��Ѵ�. �̰��� '��'�� �����ϸ� �ش� �ɼ��� �䱸�Ǿ��ٴ� ���� �ǹ��Ѵ�. �� �Լ��� �̿��Ͽ� �츮�� �ɼ��� ������ ���� ������ option_requestd()�� ȣ���Ͽ� �ɼ� �䱸 ���¸� �����ϰ�, �ɼ��� �����κ��� ���� ������ �װ��� �䱸���� ���������� ���θ� option_requested()�� ȣ�������ν� �Ǵ��Ѵ�.

    �ɼ� ���� ������ ���� ó���� �ɼ��� ����Ǿ�� �� ��쿡�� �� ������ mode�� �����Ѵ�. ECHO�� ����(MODE_ECHO)�� ���̳ʸ� ��������� ���� (MODE_INBIN, MODE_OUTBIN) ���� �̷��� ������. Mode�� �ٷ�� �Լ��� mode_set() �̴�. ���� ��忡 ���� ���Ǵ� arpa/telnet.h�� ���ԵǾ� �ִ�. �츮�� �ٷ�� ���� ��� set_terminal()���� ó���ȴ�.
    �ɼ��� ON �Ǵ� OFF �Ǿ��� ��� set_terminal()�� ȣ��Ǿ� �ش� ��忡 ���� �������� ó���� �Ѵ�.

    �ڳ� ���������� ���ǿ� ������ �ڳ� Ŭ���̾�Ʈ�� ��� �ڳ� �ɼ��� ó���� �� �־�� �Ѵٰ� �Ǿ� �ִ�. �츮�� �������� �ʴ� �ɼ��̶� ������ �䱸�ϸ� ������ �� �־�� �Ѵ�. Option_ok()�� �ɼ��� ���� �����Ǵ��� ���θ� �Ǵ��Ѵ�.
    � �ɼ��� �䱸�� ���� �ǹ̿� �䱸 �޾��� ���� �ǹ̰� �ٸ���

    TELOPT_BINARY �ɼ��� 8��Ʈ �������� ó�� ���θ� �����ϴ� �ɼ��̴�. ������ WILL �Ǵ� WONT�� �䱸���� ��쿡�� ������ 8 ��Ʈ �����͸� ó������ ���θ� ���ϴ� ���̹Ƿ�, �츮�� MODE_INBIN �� 8��Ʈ�� �޾Ƶ��̰ڴٴ� ��带 �����ؾ� �Ѵ�. TELOPT_BINARY�� DO �Ǵ� DONT�� �䱸�Ѵٸ� �̴� Ŭ���̾�Ʈ�� 8��Ʈ ó�� ������ũ��, Ʋ���̾�Ʈ�� 8��Ʈ�� ����ϰڴٴ� MODE_OUTBIN�� �����ؾ� �Ѵ�. TELOPT_ECHO�� �͹̳��� Ű����κ����� �Է��� ECHO�ؾ� �ϴ����� �����Ѵ�. ������ ECHO�� �ϰڴٸ� �ö��̾�Ʈ�� ECHO�� ���� ���ƾ��ϰ�, ������ ECHO�� ���� �ʰڴٸ� Ŭ���̾�Ʈ�� ECHO�� �ؾ��Ѵ�.

Network Virtual Terminal

    �ڳ� ���������� Network Virtual Terminal(NVT)�� �����Ѵ�. Ŭ���̾�Ʈ�� �����κ��� ���� NVT�ڵ带 ȭ�� ó���� ���� ������ �ڵ�� �ٲپ�� �ϰ�, ����� Ű����κ��� ���� �Է��� NVT�ڵ�� �ٲپ�� �Ѵ�. �̰��� CR/NL ����, ���� ó�� ���� �����Ѵ�. �츮�� ���α׷��� �̷��� ó���� set_terminal()���� �͹̳� ������ ���ؼ� ���Ѵ�. �׷��� �̰��� NVT�� �Ϻ��� �������� �ʴ´�. �ٸ� ������ �ϱ� ���� ��ŷ�̴�.

���α׷� ���� �Լ�

    ���α׷��� ������ �Լ��δ� peer_died(), do_bye(), sys_error()�� �ִ�.
    peer_error()�� ������ ������ ������ �� ȣ��ǰ�, sys_error()�� �ý��� ȣ���� ������ ���Ͽ� �� �̻� �۾��� �� �� ���� �� ȣ��ȴ�. Do_bye()�� ����ڰ� ������ ���� �� �Ҹ�������. �� ���� �Լ����� �ϴ� ���� ��� ����.

    -close()�� ������ �ݴ´�.
    -�͹̳��� ������ ���·� ȸ����Ų��.
    -malloc�� �޸𸮸� ��� �����Ѵ�.
    -������ �޽����� ��������.
    -exit()�� ȣ���Ͽ� ���α׷��� ������.

    Set_terminal()���� �͹̳��� �׻� raw ���� �����(������ raw ���� �ƴϴ�). �׷��� ������� Ű���� ���ͷ�Ʈ ���� �������� �ʴ´�. �츮�� escape character�� �������� �ʱ� ������ ���� do_bye()�� ���� ����ڰ� ���α׷��� ���� ���� ��ų ���� ����.

 

5. ������ �ڳ� Ŭ���̾�Ʈ�� �ҽ�

    �ڳ��� �ɼ��� ������ ���� �����ϴ�. �̷��� ó���� ��� �����ϱ� ���ؼ��� ���α׷��� ����� ����������. ���⼭�� ������ �ʿ��� �� ���� �ɼǸ� �����ϸ�, �˰����� �����ϰ� �Ͽ� ������ �ڳ� ������ �������� �ʴ´�.

     

    /*
     * telnet.h
     *
     *�Լ� ����.
     *by ������
     */

    /* telnet.c ���� ���ǵ� �Լ�*/
    void peer_died();
    void do_bye();
    void sys_error();

    void putc_terminal(int.c);
    int getc_socket(int*c);
    void putc_socket(int c);
    void puts_socket(char*);

    int set_terminal(int set);
    void nonblock(int onoff);

    void debug(const char*, ...);

    /* protocol.c ���� ���ǵ� �Լ�*/
    void int_telnet(int istelnet);
    void process_protocol(void);

    /*the end of telnet*/

    /*
    *telnet.c
    *
    *by ������
    */

    #include <stdio.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdlib.h>
    #include <signal.h>
    #include <stdarg.h>

    #include <sys/time.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <arpa/inet.h>

    #include <termios.h>
    #include <sys/ioctl.h>

    #include <arpa/telnet.h>

    #include "telnet.h"

    #define MAX_WRITE_BUF PIPE_BUF*2
    #define MAX_READ_BUF PIPE_BUF

    int do_debug = 0;

    char hostname[MAXHOSTNAMELEN]
    int port;
    int sock;

    struct buffer
    {
      char buf;      /*�����͸� ������ �ּҰ���*/
      int size;     /*buf�� �Ҵ�� �޸��� ũ��*/
      int head, tail; /*buf�� ����� �������� ó���� ���� �ε���*/
      int count;    /*buf�� ����� �������� byte��*/
    };

    struct buffer write_buf, read_buf;

    void init_system(void);

    void main_loop();
    void read_socket();
    void read_terminal();
    void write_socket();

    void usage()
    {
      fprintf(stdeer,"usage; mtelnet[-g] [hostname [port]]��n");
      exit(1);
    }

    void main(int argc, char *argv[])
    {
      struct hostent *host;
      struct sockaddr_ serv_addr;
      int c;
      extern int optind;

      while((c = getopt(argc, argv, "g"))!=EOF)
      {
        switch(c )
        {
        case 'g';
          do_debug = 1;
          break;
        default;
          usage();
        }  
    }

            argc-=optind;
            argv+=optind;

    if(argc <=0||argc>2)
      usage();
    if(argc==2)
      port=atoi(argv[1]);
    else
      port=23;

    bzero((char*)&serv_addr,sizeof(serv_addr));
    serv_addr.sin_family=AF_INET;
    serv_addr.sin_port =htons(port);

    if((serv_addr.sin_addr.s_addr=inet_addr(argv[0]))!=INADDR_NONE)
    {
      strcpy(hostname,arv[0]);
    }
    else
    {
      if((host=gethostbyname(argv[0]))==NULL)
      {
        herror("gethostbyname");
        exit(1);
      }
      serv_addr.sin_family=host->h_addrtype;
    bcopy(host->h_addr,(char*) &serv_addr.sin_addr,host->h_length);
    strcpy(hostname, host->h_name);
    }

    if((sock=socket(AF_INET,SOCK_STREAM,0))<0)
    {
    perror("socket");
    exit(1);
    }
    printf("Connected to %s.��n", hostname);

    init_system(void)
    {
    write_buf.buf = (char*) malloc(MAX_WRITE_BUF);
    write_buf.size = MAX_WRITE_BUF;
    write_buf.head = write_buf.tail = 0;
    write_buf.count = 0;

    read_buf.buf = (char*) malloc(MAX_READ_BUF);
    read_buf.size = MAX_READ_BUF;
    read_buf.head = read_buf.tail = 0;
    read_buf.count = 0;

      signal(SIGPIPE, peer_died);
      nonblock(1);
      set_terminal(1);
    }

    void peer_died(void)
    {
      close(sock);
      set_terminal(0);

      free(write_buf.buf);
      free(read_buf.buf);

      fprintf(stderr,"Connection closed by foreign host.��n");
      exit(1);
    }

    void do_bye()
    {
      close(sock);
      set_terminal(0);

      free(write_buf.buf);
      free(read_buf.buf);

              printf("Connection closed.��n");
      exit(0);
    }

    void sys_error()
    {
      close(sock);
      set_terminal(0);

      free(write_buf.buf);
      free(read_buf.buf);

      exit(1);
    }

    void main_loop()
    {
      int maxfd;
      fd_set in_set, out_set, exc_set;
      int ret;

      for(;;)
      {
        FD_ZERO(&in_set);
        FD_ZERO(&out_set);
        FD_ZERO(&exc_set);
        FD_SET(sock, &in_set);
        If(write_buf.count>0)
          FD_SET(sock, &out_set);
        FD_SET(0, &in_set);
        maxfd = sock;
        /*
         *��ũ���Ϳ� �����Ͱ� ���ö����� ��� ��ٸ��� �ϱ� ���Ͽ�
         *timeout�� NULL�� ���� �Ͽ���.
         */
         ret = select(maxfd + 1, &in_set, &out_set, &exc_set, NULL);
         if(ret<0)
         {
           perror("select");
           sys_error();
         }
         /*Ű����κ����� �Է��� �д´�.*/
         if(FD_ISSET(0, &in_set))
         {
           FD_CLR(sock, &in_set);
           read_terminal();
         }
         /*���Ͽ� �����͸� ����.*/
         if(FD_ISEET(sock, &out_set))
         {
           F

    D_DLR(sock, &out_set);
           Write_socket();
         }
         /*�������κ��� �����͸� �д´�.*/
         if(FD_ISSET(sock, &in_set))
         {
            FD_CLR(sock, &in_set);
            read_socket();
         }  
         /*���Ͽ������� ���� �����Ͱ� ������ �װ��� ó���Ѵ�.*/
         if(read_buf.count>0)
         {
           process_protocol();
         }
      
      }
    }
    /*���Ͽ��� �����͸� �о read_bif�� �����Ѵ�. */
    void read_socket()
    {
      int n;

    if(read_buf.size == read_buf.tail)
      return;/*read_buf�� ���������� ����. */

    n=read(sock, read_buf.buf+read_buf.tail, read_buf.size_read_buf.tail);
      if(n< 0 && errno ==EWOULDBLOCK)
         n = 0;
      if(n<0)
      {
        perror("read");
        sys_error();
      }
      if (n ==0)
        peer_died();

      read_buf.count +=n;
      read_buf.tail +=n;
    }

    /*Ű����κ��� �Է��� �޾Ƽ� write_buf�� �����Ѵ�.*/
    void read_terminal()
    {
      int n;

      if (write_buf.size ==write_buf.tail)
         return;

      n = read(0, write_buf.buf+write_buf.tail,
          write_buf.size-write_buf.tail);
      if(n<0 &&errno ==EWOULDBLOCK)
        n = 0;
      if(n<0)
      {
        perror("read");
        sys_error();
      }
      if(n ==0)
      {
        do_bye();
      }

      write_buf.count+= n;
      write_buf.tail+= n;

    }

    /*write_buf�� �ִ� �����͸� ���Ͽ� ����.*/
    void write_socket()
    {
      int n;

      n = write(sock, write_buf.buf+write_buf.head, write_buf.count);
             if(n<0&&(errno==ENOBUFS || errno==EWOULDBLOCK))
        n = 0;
      if(n<0)
      {
        perror("write");
        sys_error();
      }

      write_buf.head+=n;
      write_buf.count-=n;

      if(write_buf.count==0)
        write_buf.hea = write_buf.tail = 0;

    }

    /*
     *putc_socket(int)
     *puts_socket(char*)
     *getc_socket(char*)
     *putc_terminal(int)
     *�� �Լ����� process_protocol() ������ �ʿ��� �Լ����̴�.
     *
     *putc_socket()�� puts_socket()�� write_buf�� �����͸� �������� �Լ�.
     *getc_socket()�� read_buf���� �����͸� �б� ���� �Լ�.
     *putc_terminal()�� �����͸� ȭ�鿡 ��� ���� �Լ��̴�.
     */

    void putc_socket(int c)
    {
    if(write_buf.tail == write_buf.size)
      /*write_buf�� ���������� ����.*/
      write_socket();
    if(write_buf.tail ==write_buf.size)
    {
      fprintf(stderr,"write buffer full!��n");
      return;
    }
    write_buf.buf[write_buf.tail++] = c;
    write_buf.count++;
    }

    void puts_socket(char*s)
    {
    int len = strlen(s);
    if(write_buf.tail + len>write_buf.size)
      /*write_buf�� ���������� ����.*/
      write_socket();
    if(write_buf.tail + len > write_buf.size)
    {
      fprintf(stderr,"write buffer full!��n");
      return;
    }
    strcpy(write_buf.buf+write_buf.tail, s);
    write_buf.tail +=len;
    write_buf.count+=len;
    }

    int getc_socket(int*c)
    {
    if(read_buf.count==0)
      /*�� �̻� ���� ���� ����.*/
      return 0;

    *c = read_buf.buf[read_buf.head++];
    *c = *c & 0xff;

    read_buf.count-;

    if(read_buf.count ==0)
      read_buf.head = read_buf.tail =0;
    return read_buf.count+1;
    }

    void putc_terminal(int c)
    {
    int n;
    n = write(1, &c, 1);
    if(n<0)
    {
      perror("write");
      sys_error();
    }
    }

    /*������ nonblock ���·� �����. */
    void nonblock(int onoff)
    {
    if(ioctl(sock, FIONBIO, &onoff)<0
    {
      perror("ioctl");
      sys_error();
    }

    }

    int set_terminal(int set)
    {
    static struct termios save_termios;
    struct termios buf;
    static int isset = 0;
    extern int mode;

    if(isset == 0 && set ==0)
      return 0;

    if(set ==0)
    {
      if(tcsetattr(0, TCSAFLUSH, &save_termios)<0)
        return -1;
      return 0;
    }

    if(isset == 0)
      if(tcgetattr(0, &save_termios)<0)
        return-1;

    if(tcgetattr(0, &buf)<0)
      return-1;

    buf.c_lflag &=~ISIG;
    buf.c_oflag |=ONLCR;
    buf.c_oflag |=OPOST;
    buf.c_iflag |=ICRNL;

      if(mode & MODE_ECHO)
    {
    buf.c_flag|=ECHO;
    buf.c_oflag|=ONLCR;

    buf.c_iflag|=ICRNL;
    buf.c_lflag|=ICANON;
    }
    else
    {
    buf.c_lflag & =~ECHO;
    /*buf.c_oflag&=~ONLCR;*/

    buf.c_lflag&=~ICANON;
    /*� �ý��ۿ����� NL(0x0A)�� ������ �Ѵ�.*/
    /*buf.c_iflag & =~ICRNL;*/
    buf.c_cc[VMIN] = 1;
    buf.c_cc[VTIME] = 0;
      }

    if(mode & MODE_FLOW)
    buf.c_iflag|=IXANY|IXOFF|IXON;
    else
    buf.c_iflag &=~(IXANY|IXOFF|IXON);

          if (mode & MODE_INBIN)
                    buf.c_iflag & =~ISTRIP;
          else
    buf.c_iflag |=ISTRIP;
          if(mode& MODE_OUTBIN)
    {
                    buf.c_cflag &=~(CSIZE|PARENB);
                    buf.c_cflag|=CS8;
                    /*buf.c_oflag &= ~OPOST;*/
    }
    else
    {
    buf.c_cflag &=~(CSIZE|PARENB);
    buf.c_cflag|=save_termios.c_cflag & (CSIZE|PARENNB);
    buf.c_oflag|=OPOST;
    }
    if(tcsetattr(0, TCSAFLUSH, &buf<0)
      return-1;
    isset = set;
    return 0;
    }

    void debug(const char *msg, ...)
    {
    va_list ap;

    if(!do_debug)
      return;

    va_start( ap,msg);
    vfprintf( stderr, msg, ap);
    va_end(ap);
    fprintf(stderr, "��n");

    }

    /*the end of telnet.c*/

    /*
     *protocol.c
     *
     *�������� ó���� ���� ��ƾ��
     *by ������
     */

    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/ioctl.h>

    #define TELCMDS
    #define TELOPTS
    #include <arpa/telnet.h>

    #include "telnet.h"

    char options[256];
    int mode;

    void process_option(int cmd, int opt);
    void send_option(in cmd, int opt, int);
    int option_ok(int opt);
    void clean_sb();
    void process_sb();
    void send_naws();
    void send_ttype();
    void mode_set(int m, int set);
    int option_requested(int opt);
    void option_request(int opt, int req);

    void init_telnet(int istelnet)
    {
    int i;

    for(i=0;i<256;I++)
    options[i] = 0;

    mode = 0;
    /*���� ����Ʈ�� �����Ǿ� �ִ� ���*/
    mode_set(MODE_ECHO,1);

    set_terminal(1);
    /*�ڳ������� ��쿡�� �ڳ� �ʱ� ������ �Ѵ�.*/
    if(istelnet)
    {
       send_option(DO, TELOPT_SGA, 1);
       send_option(WILL, TELOPT_TTYPE, 1);
       send_option(WILL, TELOPT_NAWS, 1);
       send_option(WILL, TELOPT_LFLOW, 1);
       send_option(WILL, TELOPT_LINEMODE, 1);
       send_option(DO, TELOPT_STATUS, 1);

       /*enter binarymode*/
       send_option(DO, TELOPT_BINARY, 1);
       send_option(WILL, TELOPT_BINARY, 1);
    }
    }

    /*read_buf�� ����Ǿ� �ִ� �����Ϳ��� ���������� ã�Ƽ� ó���Ѵ�.*/
    void process_protocol(void)
    {
    int c;

    while(getc_socket(&c))
    {
      if(c ==IAC)
      {
        if(!getc_socket(&c))
           return;
        switch(c)
        {
        case IAC:
          putc_terminal(c);
          break;
        case DON'T:
        case DO:
        case WONT:
        case WILL:
        {
            int opt;
            if(!getc_socket(&opt))
    return;
            process_option(c, opt);
            break;
    }
    case SB:
       if(!getc_socket(&c))
         return;
       if(c ==TELOPT_TTYPE)
       {
         if(!getc_socket(&c))
           return;
         clean_sb();
         if(c ==TELQUAL_SEND)
           send_ttype();
         break;
       }
       clean_sb();
       break;

    default:
       break;

    }
        }
        else
        {
    putc_terminal(c);
        }
    }
    }

    void clean_sb()
    {
    int c;
    for(;;)
    {
         if(!getc_socket(&c))
            return;
         if(c ==IAC)
         {
    if(!getc_socket(&c))
       return;
    if(c ==SE)
       return;
    }
       }
    }

    void process_option(int cmd, int opt)
    {
    debug("RCVD: IAC %s%s", TELCMD(cmd), TELOPT(opt));

    /* If this is an option we do not understand or have not implemented, refuse any 'DO'
    request. */
    if(!option_ok(opt))
    {
      if( cmd == DO)
         send_option(WONT, opt,0);
      if( cmd == WILL)
         send_option(DONT, opt,0);
    }
    else if(cmd == DO)
    {
      switch(opt)
      {
      case TELOPT_ECHO:
        /*never echo if once turned off*/
        mode_set(MODE_ECHO, 0);
        send_option(WONT, opt, 0);
        goto out_processing;
        return;
      case TELOPT_BINARY:
        mode_set(MODE_OUTBIN, 1);
        break;
      case TELOPT_LFLOW:
        mode_set(MODE_FLOW, 1);
        break;
      case TELOPT_NAWS:
        send_naws();
        break;
      }
      if(!option_requested(opt))

        send_option(WILL, opt, 0);
    }
    else if( cmd == DONT)
    {
      switch(opt)
      {
      case TELOPT_ECHO;
        mode_set(MODE_ECHO, 0);
        break;
      case TELOPT_BINARY:
        mode_set(MODE_OUTBIN, 0);
        break;
      case TELOPT_LFLOW:
        mode_set(MODE_FLOW, 0);
        break;

      }
      if(!option_requested(opt))
        send_option(WONT, opt, 0);
    }
    else if( cmd==WILL)
    {
      switch(opt)
      {
      case TELOPT_ECHO:
        mode_set(MODE_ECHO, 0);
        break;
      case TELOPT_BINARY:
        mode_set(MODE_INBIN, 1);
        break;
      case TELOPT_LFLOW:
        mode_set(MODE_FLOW, 1);
        break;

      }
      if(!option_requested(opt))
        send_option(DO, opt, 0);
    }
    else if(cmd == WONT)
    {
      switch(opt)
      {
      case TELOPT_ECHO:
        mode_set(MODE_ECHO, 1);
        break;
      case TELOPT_BINARY:
        mode_set(MODE_INBIN, 0);
        break;
      case TELOPT_LFLOW:
        mode_set(MODE_FLOW, 0);
        break;
      }
      if(!option_requested(opt))
        send_option(DON'T, opt, 0);
    }
    out_processing:
    set_terminal(1);
    }
    void send_option(int cmd, int opt, int request)
    {
    if(request && !option_ok(opt))
      return;

    option_request(opt, request);

    debug("SENT:IAC%s%s", TELCMD(cmd), TELOPT(opt));
    putc_socket(IAC);
    putc_socket(cmd);
    putc_socket(opt);
    }

    /*�͹̳� Ÿ��*/
    void send_ttype()
    {
    char s[50];
    strcpy(s, (getenv("TERM") ==NULL? "UNKNOWN" : getenv("TERM")));

    putc_socket(IAC);
    putc_socket(SB);
    putc_socket(TELOPT_TTYPE);
    putc_socket(TELQUAL_IS);
    putc_socket(s);
    putc_socket(IAC);
    putc_socket(SE);

    debug("SENT: IAC SB TELOPT_TTYPE IS��"%s��" IAC AE" ,s);

    }

    /*�͹̳� ������ ũ��*/
    void send_naws()
    {
    char s[50];
    struct winsize size;
    if(ioctl(0, TIOCGWINSZ, (char*)&size)<0)
    {
      perror("ioctl");
      sys_error();
    }
    s[0] = (size.ws_col>>8)&0xFF;
    s[1] = (size.ws_col&0xFF);
    s[2] = (size.ws_row>>8)&0xFF;
    s[3] = (size.ws_row&0xFF);
    s[4] = 0;
    putc_socket(IAC);
    putc_socket(SB);
    putc_socket(TELOPT_NAWS);
    putc_socket(s);
    putc_socket(IAC);
    putc_socket(SE);

    debug("SENT:IAC SB TELOPT_NAWS%d%d%d%dIAC SE", s[0],s[1],s[2],s[3]);
    }

    int option_ok(int opt)
    {
    if(opt == TELOPT_ECHO||opt==TELOPT_BINARY||opt==TELOPT_SGA||
      opt == TELOPT_LFLOW||opt==TELOPT_TTYPE||opt==TELOPT_NAWS)
      return 1;
    else
      return 0;
    }

    void mode_set(int m, int set)
    {
    if(set)
      mode |=m;
    else
      mode &=~m;
    }

    int option_requested(int opt)
    {
    return option[opt]>0;
    }

    void option_request(int opt, int req)
    {
    if(req>0)
      options[opt]++;
    else if(options[opt]>0)
      options[opt]-;

    }

    /*the end of protocol.c*/
    ������ �� ���α׷��� ���� Makefile�̴�.
    telnet.h, telnet.c, protocol.c�� ���� ������ �� ���� ���丮�� ������ Makefile�� �����Ͽ� make�ϸ� �ȴ�.

    #Makefile for mtelnet
    CC     = cc
    DEBUG  =
    O_FLAGS=
    C_FLAGS=$(O_FLAGS)-Wall$(DEBUG)
    L_FLAGS=$(O_FLAGS)

    O_FILES = mtelnet
    $(TARGET):$(O_FILES)
             $(CC)$(L_FLAGS)-o$(TARGET)$(O_FILES)

    .c.o:
             $(CC)$-c$(C_FLAGS)$<

    clean:
             rm*.o$(TARGET)

     

7.��ġ�鼭

    �� ���α׷��� �������� ���ø����̼ǿ��� ���̱⿡�� �ʹ��� ���װ� ����, �������� ������ ����ϴ�. �׷��� �ڳ� Ŭ���̾�Ʈ ���α׷����� �����ϱ⿡�� ����ϸ��� �����ȴ�. ���� �������� ������ ���� ���α׷��� ���忡�� �ٷ�� ����.




�� top

home����...