Chapter 8
The Point-to-Point Protocol


D.M.Z CONTENT PRE NEXT

8.1 Untangling the P's
8.2 PPP on Linux
8.3 Running the pppd
8.4 Using Options Files
8.5 Dialing out with chat
8.6 Debugging your PPP Setup
8.7 IP Configuration Options
8.8 Link Control Options
8.9 General Security Considerations
8.10 Authentication with PPP
8.11 Configuring a PPP Server

8.1 Untangling the P's

SLIP과 마찬가지로, PPP도 시리얼 커넥션을 통해 데이터그램을 보내는 프로토콜이나, 전자의 몇가지 부족한 점을 보완한다. 그것은 구동시에 통신하는 쪽간에 IP 주소나 최대 데이터그램 크기같은 옵션을 협상할 수 있도록 하고, 클라이언트인증을 제공한다. 이러한 능력 각각에, IP는 별개의 프로토콜을 가진다. 아래에서 우리는 이러한 PPP의 기본 초석을 간략하게나마 다룰 것이나, 이러한 설명은 아마도 당신에겐 턱없이 부족한 것이리라. PPP에 관해 더 많은 것을 알고자 한다면 RFC 1548과, 관련된 십여개의 RFC들에서 그것의 명세서를 읽어보길 권한다.

PPP의 최하위엔 High-Level Data Control Protocol, 약어로 HDLC가 있으며, 이는 개별 PPP 프레임에 대한 경계선을 정의하고 16bit checksum을 제공한다. 보다 원시적인 SLIP 캡슐화 방식과는 대조적으로, PPP 프레임은 IP 이외의 프로토콜, 즉 Novell의 IPX나 Appletalk 같은 것들의 패킷도 수용할 수 있는 능력이 있다. PPP는 기본 HDLC 프레임에 프로토콜 필드를 추가하여, 프레임이 운반하고 있는 패킷의 타입이 인식할 수 있게 함으로해서 위와 같은 일을 수행한다.

LCP, Link Control Protocol은 HDLC의 최상위에 사용되며, Maximum Receive Unit (MRU)같은 데이터링크에 속한 옵션을 협상하는 역할을 한다. MRU는 링크의 한쪽이 받을 수 있다고 동의하는 최대 데이터그램 크기를 나타낸다.

PPP링크의 설정단계에서 한가지 중요한 절차는 클라이언트 인증이다. 그것이 강제적이지는 않더라도 dial-up라인에서 정말로 필요한 것이다. 보통, 전화받는 호스트(서버)는 클라이언트에게 몇가지 secret key를 알고 있는지 증명하게 함으로써 그것을 인증한다. 만약 전화거는 쪽이 정확한 secret key를 만들지 못한다면, 커넥션은 철회된다. PPP에서의 인증은 두 단계이다. 즉 전화거는 쪽은 서버에게 자신을 인증시킬 것을 요구한다. 이 인증 절차들은 완전히 각각 독립적인 것이다. 이러한 다른 인증타입에 대하여 두개의 프로토콜이 존재하며, 좀 더 뒤에 논의할 것이다. 그것들의 이름은 Password Authentiation Protocol (PAP)와 Challenge Handshake Authentication Protocol (CHAP)이다.

IP, AppleTalk 등과 같이 데이터링크를 따라 라우트되는 각 네트웍 프로토콜은, 상응하는 Network Control Protocol (NCP)을 사용하여 동적으로 설정된다. 예를 들어, 링크를 따라 IP 데이터그램을 보내려면, 가장 먼저 각각 어떤 IP를 사용할 것인지 양쪽 PPP가 협상해야 한다. 이를 위해 사용되는 제어 프로토콜은 IPCP, 즉 Internet Protocol Control Protocol이다.

표준 IP 데이터그램 이외에도, PPP는 IP 데이터그램의 header compression (헤더 압축)도 지원하는데, 이것은 TCP의 헤더를 3 byte의 크기로 작게 줄이는 기술이다. 그것은 역시나 CSLIP에서도 사용되며 보다 구어적으로 VJ header compression이라 칭한다. compression의 사용은 구동시에 IPCP를 통해 협약된다.


8.2 PPP on Linux

리눅스 상에서 PPP의 기능은, 커널내의 low-level HDLC 드라이버와 여러 제어 프로토콜을 조정하는 유저 차원의 두 부분으로 나뉜다. 현재의 리눅스용 PPP 릴리즈는 linux-ppp-1.0.0으로 커널 PPP 모듈, pppd, 그리고 리모트 시스템에 dial up 하는데 사용되는 chat이라는 이름의 프로그램을 포함한다.

PPP 커널 드라이버는 Michael Callahan이 썼고 pppd는 Sun과 386 BSD 머신의 공개 PPP implementation에서 유래한 것으로, Drew Perkins를 비롯한 사람들이 쓴 것이며, Paul Mackerras가 관리한다. 그것은 Al Longyear에 의해 리눅스로 포팅되었고, chat은 Karl Fox에 의해 쓰였다.

SLIP과 마찬가지로 PPP는 특수한 라인 규율 (line discipline)에 의해 수행된다. 어떤 시리얼라인을 PPP 링크로 사용하고자 한다면, 먼저 평소와 같이 모뎀으로 커넥션을 성립한 후 그 라인을 PPP모드로 변환한다. 이 모드에서, 들어오는 모든 데이터는 PPP 드라이버로 넘겨지고, PPP 드라이버는 들어오는 HDLC 프레임에 대해 적절성 여부를 체크하고 (각 HDLC 프레임은 16비트 checksum을 갖고 다닌다.), 그것들을 풀어서 발송한다. 현재로 그것은 IP 데이터그램을 다룰 수 있으며, 선택적으로 Van Jacobson header compression을 사용하기도 한다. 리눅스가 IPX를 지원하게 되면, 리눅스가 IPX를 지원하게되면, PPP 드라이버도 IPX 패킷을 다룰 수 있도록 확장될 것이다.

커널 드라이버는, 실제로 네트웍 traffic을 링크를 따라 보낼수 있게 되기 전에 필요한 전반적인 초기화와 인증단계를 수행하는 PPP 데몬인, pppd의 도움을 받는다. pppd의 동작은 여러 옵션을 통해 잘 조절될 수 있다. PPP가 다소 복잡하듯, 단 하나의 chapter에서 그것의 모두를 설명하는건 불가능하다. 따라서 이 책은 pppd의 소스 배포판 내의 매뉴얼 페이지와 README를 참조하라. 그것들은 이 장에서 해결해 줄 수 없는 대부분의 의문점을 해결할 수 있게 도와줄 것이다. 만약 모든 문서를 읽고난 후에도 여전히 의문점이 남아있다면, 뉴스 그룹 comp.protocols.ppp에 도움을 요청하라, 여기는 pppd의 개발에 관계된 사람들의 대부분과 접촉할 수 있는 곳이다.


8.3 Running pppd

당신이 PPP링크를 통해 인터넷에 연결하고자 할 때, 당신은 loopback 디바이스와 resolver같은 기본적인 네트워킹 수용 능력ㄷ을 셋업해야 한다. 두가지 모두 이전 장에서 다룬것들이다. 시리얼 링크 상에서 DNS를 사용하는 것에 관해 얘기했던 것들도 있다. 이는 SLIP chapter를 참고하라.

어떻게 pppd로 PPP 커넥션을 수립하는지 소개하는 예제로써, 다시금 당신이 vlager에 있다고 가정하자. 당신은 이미 PPP 서버인 c3po에 dial up해서 ppp 계정으로 로그인 해 놓았고, c3po는 자신의 PPP 드라이버에 시동을 걸어놓은 상태이다. 다이얼링에 사용한 프로그램이 종료한 후, 당신의 다음의 커맨드를 실행한다.

     #pppd /dev/cua3 38400 crtscts defaultroute

이것은 시리얼라인 cua3를 PPP 모드로 돌리고 c3po에 IP 링크를 하나 수립한다. 시리얼 포트에 사용되는 전송속도는 38400 bps가 될 것이다. crtscts 옵션은 포트상에서 9600 bps 이상의 속도가 절대적으로 필요한 hardware handshake를 켠다.

pppd가 구동된 후 가장 먼저 하는 것은 LCP를 사용하여 리모트쪽과 시리얼 라인의 성질을 협약하는 것이다. 보통 기본값의 옵션 세트로 pppd가 협약하기 때문에, 여기에 대해 들어가진 않겠다. 이후의 절에서 LCP에 더 자세히 다루어 볼 것이다.

당분간, c3po가 우리에게 어떠한 인증도 요구하지 않는다고 가정하자. 그러면 설정단계는 성공적으로 끝났다.

pppd는 이제 상대와 IPCP, 즉 IP control protocol을 사용하여 IP 파라미터를 협상할 것이다. 우리가 위에서 어떠한 특정 IP 주소도 pppd에 지정해 주지 않았으므로, resolver가 로컬 호스트를 검색하여 얻어진 주소를 사용하려 할 것이다. 그리고 양쪽 모두 자신의 주소를 각각 announce 할 것이다.

보통의 경우 이러한 디폴트 값이 잘못되어 있는 경우는 없다. 심지어는 당신의 머신이 이더넷 상에 있을지라도, 이더넷과 PPP 인터페이스에 동일한 IP 주소를 사용할 수 있다. 그러함에도 불구하고, pppd는 다른 주소를 사용토록 하거나 상대쪽에 어떤 특정 주소를 요구하거나 할 수 있다. 이 옵션은 이후의 절에서 논의한다.

IPCP 셋업단계를 거친후, pppd는 당신 호스트의 네트워킹 레이어가 PPP링크를 사용하도록 준비할 것이다. 그것은 먼저 활성화된 첫번째 PPP 링크에 ppp0를 두번째는 ppp1등을 사용하여 PPP 네트웍 인터페이스를 point-to-point 링크로 설정한다. 다음으로, 링크의 반대편의 호스트를 가리키는 라우팅 테이블 엔트리를 셋업한다. 위에서 본 예제와 같이, pppdc3po를 가리키는 기본 네트웍 루트(route)를 만들 것이며, 그 이유는 우리가 defaultroute 업션을 주었기 때문이다. 이것은 당신의 로컬 네트웍에 존재하지 않는 호스트로의 모든 데이터그램을 c3po에 보내도록 만든다. pppd는 다수의 서로다른 라우팅 구조를 지원하며, 이들은 이 장의 좀 더 후반부에서 다룰 것이다.


8.4 Using Options Files

pppd가 그것의 커맨드라인 인자를 분석하기에 앞서, 그것은 기본 옵션을 위해 몇개의 파일을 살핀다. 이러한 파일들은 임의의 개수의 라인에 걸쳐져있는 적절한 커맨드라인 인자를 지닌다. 주석문은 해쉬 기호로 표시된다.

첫번째 옵션파일은 /etc/ppp/options으로, pppd가 구동될때마다 스캔된다. 그것은 젼역적인 디폴트 값을 지정하는데 쓰는데 적당하다. 왜냐하면, 그것은 당신의 유저들이 보안에 악영향을 끼칙수 있는 일을 하지 못하도록한다. 예를들어, pppd가 어떤 종류의 인증(PAP이나 CHAP중의 하나)을 상대편에 요구하게 만들려면 이 파일에 auth 옵션을 추가하면된다. 이 옵션은 유저에 의해 override될 수 없으므로, 우리쪽의 인증 데이터베이스에 없는 아무 시스템이나 PPP 커넥션을 수립할 수 없게 된다.

/etc/ppp/options 뒤에 읽히는 다른 옵션파일은 유저의 디렉토리내의 .ppprc이다. 그것은 사용자가 자신만의 디폴트 옵션을 지정할 수 있게 한다.

다음은 /etc/ppp/options의 샘플파일이다.

    # Global options for pppd running on vlager.vbrew.com
	auth 				# require authentication
	usehostname			# use local hostname for CHAP
	lock				# use UUCP-style device locking
	domain vbrew.com	# our domain name

이 옵션들 중 처음의 둘은 인증에 적용되고 아래에서 설명한다. lock 키워드는 pppd가 디바이스 잠금(locking)에 표준 UUCP 방식을 쓰도록 만든다. 이를 사용하면, 시리얼 디바이스에 접근하는 각 프로세스, 이를테면 /dev/cua3는 디바이스가 사용중이라는 것을 알리기위해 UUCP spool 디렉토리안에 LCK..cua3라는 lock 파일을 생성한다. 이는 시리얼 디바이스가 PPP에 사용중일때 다른 프로그램, 이를테면 minicom 또는 uucico같은 프로그램이 그것을 열지 못하게 하는데 필요하다.

전역 설정파일에 이 옵션을 주는 이유는 위에서 본 것과 같은 옵션들이 override될 수 없기 때문에 납득할만한 만큼의 보안 레벨을 제공하기 때문이다. 그러나, 어떤 옵션은 이후 override되는데, 이러한 것들 중 하나가 connect이다.


8.5 Dialing out with chat

위의 예제에서 당신도 느꼈을 한가지 불편한 점은 pppd를 구동시키기 전에 커넥션을 수동으로 수립해야 하는 것이다. dip과는 달리, pppd엔 원격 시스템에 전화를 걸고 로그인 하는 용도의 스크립트 언어가 없다. 그러나 그대신 몇몇 외부 프로그램이나 쉘 스크립트에 의존함으로써 이를 해결한다. connect 커맨드라인 옵션을 주면 실행되는 모든 커맨드는 pppd에 주어질 것이고, pppd는 커맨드의 표준입력과 표준출력을 시리얼 라인에 redirect할 것이다. 이를 위한 유용한 프로그램은 Don Libes가 쓴 expect로, 그것은 Tcl 기반의 강력한 언어이며 이러한 종류의 어플리케이션을 위해 디자인 되었다.

pppd 패키지엔 UUCP스타일의 chat 스크립트를 쓸 수 있도록 해주는, 유사 프로그램인 chat이라는 것이 딸려 있다. 기본적으로, chat 스크립트는 리모트 시스템에서 기대되는 문자열과 보내려는 대답을 계속 주고 받는 것으로 이루어진다. 우리는 expect와 send 문자열을 각각 호출할 것이다. 이것은 보편적인 chat 스크립트에서 발췌한 것이다.

     ogin: biff ssword: s3kr3t

이것은 chat에게 리모트 시스템이 로그인 프롬프트를 보내길 기다리라고 말한다. 그리고 로그인 네임 biff를 리턴한다. 우리는 단지 ogin을 기다릴 뿐이고, 로그인 프롬프트의 첫 글자가 대문자 L 이든지 소문자 l이든지, 혹은 변형되어 도착하든지에 상관하지 않는 것이다. 다음의 문자열은 다시 expect 문자열로, chat이 패스워드 프롬프트를 기다리고 그 대답으로 패스워드를 보내도록 만든다.

이는 chat 스크립트에 대한 기본적인 모든것이다. 물론 PPP 서버에 다이얼업 하기위한 완전한 스크립트는 역시나 적절한 모뎀 커맨드도 포함해야 한다. 당신의 모뎀이 Hayes 커맨드 세트를 이해한다고 가정하고, 서버의 전화번호가 318714라면, c3po와 연결하고자 하는 chat 실행문은 다음과 같을 것이다.

     $ chat -v '' ATZ OK ATDT318714 CONNECT '' ogin: ppp word: GaGariN

디폴트로, 첫번째 문자열은 expect 문자열이지만, 우리가 자극을 주지 않으면 모뎀이 아무것도 얘기하지 않기 때문에, 우리는 반드시 문자열에 공백 문자열을 지정함으로써 chat이 첫번째 expect를 건너 뛰어야 한다. 그리고 계속 Hayes 호환 모뎀의 리셋 커맨드인 ATZ를 보내고 그것의 대답 (OK)를 기다린다. 그 다음 문자열은 뒷부분의 전화번호로 다이얼하는 커맨드를 chat에 보내고 CONNECT 메시지를 대답으로 기대한다. 다시금 공백 문자열이 따라 붙는데, 그 이유는 지금 우리는 어떤 것도 보낼 필요없이 단지 로그인 프롬프트를 기다리기 때문이다. chat 스크립트의 나머지 부분은 아래에 적힌대로 동작한다.

-v 옵션은 chat이 모든 동작을 syslog 데몬의 local2에 log를 보내게 만든다.

커맨드라인 상에서 chat 스크립트를 지정하는 것은 일정한 위험 부담을 안고 있다. 왜냐하면 유저가 ps 커맨드로 프로세스의 커맨드 라인을 볼 수 있기 때문으로, 이를 피하기 위해선, 이를테면 dial-c3po라는 파일에 chat 스크립트를 집어 넣으면 된다. 당신은 파일명 앞에 -f 옵션을 주어, chat이 커맨드라인 대신에 파일에서 스크립트를 읽게 만들 수 있다 다음은 완전한 pppd 커맨드이다.

     #pppd connect /dev/cua3 38400 crtscts defaultroute

dialup 스크립트를 지정하는 connect 옵션 외에도, 우리는 두개의 옵션을 커맨드라인에 더 추가하였다: -detach는 ppp가 콘솔에서 떨어져 백그라운드 프로세스가 되지 않게 한다. modem 키워드는 그것이 몇가지의 모뎀 고유동작, 즉 전화 걸기 전후에 라인을 끊는 것과같은 일을 시리얼 디바이스 상에서 수행하도록 만든다. 만약 이 키워드랄 사용하지 으ㄶ는다면, pppd는 포트의 DCD 라인을 모니터하지 않을 것이고, 따라서 리모트 쪽에서 기대치않게 전화를 끊더라도 감지하지 못한다.

위에 보여준 예제는 다소 단순하다; chat은 보다 복잡한 스크립트도 이해할 수 있다. 한가지 유용한 기능은, 에러가 날때 abort시키는 문자열을 지정해 줄 수 있는 것이다. 일반적인 abort 문자열은 BUSY또는 NO CARRIER로, 보통 전화건 번호가 통화중이거나 전화 수신음이 없을 때 모뎀이 발생시키는 것이다. chat이 timeout하는 대신, 이것을 즉시 인지하도록 만들기위해서 당신은 스크립트 처음에 ABORT 키워드로 그것을 지정할 수 있다.

     #chat -v ABORT BUSY ABORT 'NO CARRIER' '' ATZ OK ...

비슷한 양상에서, 당신은 TIMEOUT옵션을 집어넣어 chat 스크립트 일부에 대해 timeout 값을 변경할 수도 있다. 세부적인 설명을 보고자한다면 chat(8) 매뉴얼 페이지를 체크하라.

때때로, 당신은 chat 스크립트에서 일종의 조건 실행을 원할 것이다. 예를 들어, 당신이 리모트 쪽의 로그인 프롬프트로 수신할 수 없을 때, 당신은 BREAK 또는 캐리지 리턴을 보내고자 할 것이다. 이는 첨자를 예상 문자열(expect string)에 덧붙힘으로써 가능하다. 그것은 스크립트 전체가 그러하듯, 전송 문자열과 예상 문자열의 연속으로 구성되며, 연자부호로 구분된다. 그것은, 첨자가 따라붙은 예상 문자열이 시간안에 수신되지 않는때 언제라도 실행된다. 위의 예제에서 다음과 같이 chat 스크립트를 수정할 수 있다.

     ogin:-BREAK-ogin: ppp ssword: GaGariN

이제, chat이 리모트 시스템이 보내는 로그인 프롬프트를 보지 못할때, 첨자가 실행되어, 먼저 BREAK를 보내고 다시 로그인 프롬프트를 기다리게 된다. 만약 프롬프트가 나타난다면 스크립트는 평상시와 같이 계속 진행될 것이고, 그렇지 않다면 에러를 내고 종료하게 된다.


8.6 Debugging Your PPP Setup

디폴트로, pppd는 경로와 에러메시지를 syslog 데몬에 보낼것이다. 당신은 이를 파일에 또는 콘살에 redirect하는 엔트리를 syslog.conf에 추가해야 한다.

그렇지 않다면 syslog는 단순히 이 메시지를 파기한다. 다음의 엔트리는 모든 메시지를 /var/log/ppp-log에 보낸다.

     daemon.*			/var/log/ppp-log

만약 당신의 PPP 셋업이 제대로 동작하지 않을 때, 이 로그파일을 살펴보는 것은 무엇이 잘못되어 가고 있는지에 대해 첫번째로 힌트를 줄 것이다. 만약 이것도 별 도움이 되지 않는다면, debug 옵션을 사용하여 별도의 디버깅 출력을 켜줄 수도 있다. 이렇게하면 pppd는, 주고 받는 모든 제어패킷의 내용을 syslog에 보낸다. 모든 메시지는 daemon 기능에 보내어질 것이다.

마지막으로, 가장 강력한 기능을 발휘하는 것은 pppdkdebug 옵션을 주어 실행시킴으로 kernel-level 디버깅을 사용토록 하는 것이다. 그 옵션 뒤에는 다음의 값에 대한 bitwise OR인 숫자 인자가 붙는다: 일반적은 디버깅 메시지를 위해선 1을, 모든 incoming HDLC 프레임의 내용을 출력하기 위해선 2를, 그리고 4의 값은 드라이버가 외부로 나가는 모든 HDLC 프레임을 출력하게 한다. 커널 디버깅 메시지를 capture 하기위해선, syslogd 데몬이 proc/kmsg 파일을 읽도록 실행시키거나 klogd 데몬을 돌려야한다. 그것들중 어느쪽이건 커널디버깅을 syslogkernel기능쪽으로 돌린다.


8.7 IP Configuration Options

IPCP는 링크 설정시기에 몇가지 IP 파라미터를 상호협약하는데 사용된다. 보통, 양쪽은 자신이 어떤값을 디폴트에서 변경하고자 하는지 알리는 IPCP Configuration Request 패킷을 보낼 것이다. 수신측에서 리모트쪽은 각 옵션을 차례로 검사하여 그것을 승인하거나 거부한다.

pppd는 협약하고자하는 IPCP 옵션에 관한 많은 컨트롤을 제공한다. 당신은 아래에 논의할 다양한 커맨드라인 옵션으로 이를 조절할 수 있다.

8.7.1 Choosing IP Address

위의 예제에서, 우리는 pppdc3po에 dialup하고 IP링크를 트도록 했다. 링크의 어느쪽에도 특정한 IP 주소를 선택하도록 준비되지 않았고, 그 대신 vlager의 주소를 로컬 IP 주소로 선택하고 c3po가 자신의 주소를 제공하게 한다. 그러나 때때로 링크의 한쪽 또는 다른 쪽에 어떤 주소가 사용되는지 컨트롤하는 것은 유용한 일이다. pppd는 이에 대한 몇가지 변수를 지원한다.

특정 주소를 요구하기 위새선, 보통 pppd에 다음의 옵션을 준다.

     local_addr:remote_addr

local_addrremote_addr에는 dotted quad notation 또는 호스트네임을 지정해 준다. 이것은 pppd가 첫번째 주소를 자신의 IP 주소로, 그리고 두번째를 상대의 주소로 사용하게 한다. 만약 상대편이 IPCP 협약도중에, 그 둘 중의 한가지라도 거부한다면 IP 링크는 성립되지 않는다.

만약, 상대가 사용하는 주소를 그대로 받아들이고 로컬 주소만을 지정하길 원한다면, 단순히 remote_addr 부분을 비워놓으면 된다. 예를들어, vlager가 자신의 주소대신 130.83.4.27의 IP 주소를 사용하게 하려면, 130.83.4.27이라고 커맨드라인상에 주면된다. 이와 비슷하게, 리모트 주소만을 지정하고자 한다면, local_addr 필드를 공백으로 남기면 된다. 디폴트로, pppd는 당신 호스트의 주소를 사용할 것이다.

많은 클라이언트를 다루는 몇몇 PPP서버는 주소를 동적으로 할당한다: dial in할 때 시스템에 주소를 지정하고 다시 로그오프한 후 그것을 되돌려 받는다. 그과 같은 서버에 dialup할 때는, pppd가 서버에 특정 IP주소를 요청하지 않고, 서버가 사용하라는 주소를 받아들이는지를 확인해야한다. 이 말은 즉, local_addr인자를 지정하면 안된다는 뜻일뿐 아니라, pppd가 로컬 호스브의 주소를 사용하는 대신 상대가 IP 주소를 제공해주길 기다리도록 만드는 noipdefault 옵션을 지정해 주어야 한다는 뜻이다.

8.7.2 Routing Through a PPP Link

네트웍 인터페이스를 설정한 후, pppd는 보통 호스트가 상대편(peer)쪽으로만 라우트하도록 셋업한다. 만약 리모트 호스트가 LAN 상에 있으면, 당연히 상대쪽 호스트 "뒤에" 있는 호스트에도 연결할 수 있어야 한다. 다시말해, 네트웍 루트가 셋업되어야 한다.

우리는 이미 defaultroute옵션을 사용하여 pppd가 디폴트 루트를 지정하도록 할 수 있다는 것을 보았다. 이 옵션은 당신이 dialup한 PPP서버를 당신의 인터넷 게이트웨이로 사용할 때, 매우 유용하다.

반대의 경우, 즉 당신의 시스템이 한 호스트에대해 게이트웨이로 동작할 때에도 역시나 상대적으로 쉽게 성립된다. 예로써, loner라는 머신을 집에 갖고 있는 Virtual Brewery의 사원을 생각해보자. PPP를 통해 vlager에 연결할 때, 그는 Brewery의 서브넷 상의 주소를 사용할 것이다. vlager에서 우리는 loner를 위한 proxy ARP 엔트리를 설치해 줄 proxy arp 옵션을 pppd에게 준다. 이러면 자동적으로 Brewery와 Winery에 있는 모든 호스트에서 loner에 억세스 할 수 있게 된다.

그러나, 예를 들어 두 LAN을 링트할 때와 같은 경우에 모든일이 쉽게 되지만은 않는다. 이는 보통 특정 네트웍 루트를 추가할 것을 요하는데, 왜냐하면 양쪽이 PPP 링크를 default route로 사용한다면 loop가 발생하기 때문이다. 즉 알수 없는 목적지로 향하는 패킷은 time-to-live로 expire될 때까지 양쪽을 왔다갔다 한다는 것이다.

예를 들어, Virtual Brewery가 다른 도시에 지사를 애었다고 가정하자. 그 지사에선 Brewery의 class B 네트웍의 서브넷 3인 IP 네트웍 번호 191.72.3.0을 사용하여 자체 이더넷을 운영한다. 그들은 고객 데이터 베이스등을 업데이트하기 위해 PPP를 통해 Brewery의 주 이더넷에 연결하고자 할 것이다. 이 때 vlager는 또다시 게이트웨이로 동작한다; 그 상대편은 sub-etha라고하며 191.72.3.1의 IP 추소를 갖고 있다.

sub-ethavlager에 연결할 때, 그것은 평상시와 같이 vlager르ㅕ 가리키는 default route를 만들 것이다. 그러나 vlager 상에서는 sub-etha를 통하는 서브넷 3를 위한 네트웍 루트를 설치할 것이다. 이를 위해, 우리는 지금까지 논하지 않았던 pppd의 기능, 즉 ip-up 커맨드를 사용한다. 이것은 /etc/ppp에 위치한 셀 스크립트 또는 프로그램으로, PPP 인터페이스가 설정된 후 실행된다. 현재로, 그것은 다음의 파라미터를 가지고 실행된다.

	ip-up iface device speed local_addr remote_addr

iface란에는 사용하는 인터페이스명을 넣자. 그리고 device는 사용하는 시리얼 디바이스 파일의 경로명이고 (표준 입력/출력이 사용될 때 /dev/tty이다), speed는 디바이스의 속도이다. local_addrremote_addr는 링크의 양쪽에서 사용하는 IP 주소를 dotted quat notation으로 적는다. 우리의 경우, ip-up 스크립트는 다음 코드의 일부를 가지고 있다.

     #!/bin/sh
     case $5 in
     191.72.3.1)            # this is sub-etha
             route add -net 191.72.3.0 gw 191.72.3.1;;
     esac
     exit 0  

이와 비슷하게, /etc/ppp/ip-down은 링크가 분리된 후 ip-up의 모든 동작을 취소하는데 사용된다.

그러나, 라우팅 구조는 아직 완전치 않다. 우리는 양쪽 PPP 호스트에 라우팅 테이블 엔트리를 셋업했으나, 양쪽 네트웍 상의 모든 호스트는 PPP 링크에 대해 전혀 알고 있지 않다. 이는, 지사의 모든 호스트가 sub-etha를 가리키는 default route를 가지고 있고, 모든 Brewery 호스트가 디폴트로 vlager로 라우트한다면, 큰 문제가 되지 않는다. 만약 이와 같은 경우가 아니라면, 보통 당신이 선택할 수 있는 단 한가지 방법은 gated와 같은 라우팅 데몬을 쓰는 것이다. vlager에 네트웍 루트를 생성한 후, 라우팅 데몬은 서브넷에 물려있는 모든 호스트에 새로운 루트를 broadcast할 것이다.


8.8 Link Control Options

위에서 우리는, 링크의 성질을 협약(negotiate)하고 링크를 테스트하는데 사용되는 LCP (Link Control Protocol)을 본 적이 있다.

LCP가 협약하는 가장 중요한 도가지 옵션은 maximum receive unit과 Asynchronous Control Character Map이다. 그 외에도 많은 LCP 제어 옵션들이 존재하나, 여기서 논의하기엔 너무 전문적인 것들이다. 그에대해선 RFC 1548을 참조하라.

흔히 async map이라 부르기도 하는 Asynchronous Control Character Map은 전화선과 같은 비 동기적인 링크상에서, escape 되어야(특정 two-character sequence로 대체되어야)만 하는 컨트롤 캐릭터를 인식하는데 사용된다. 예를 들어, 잘못 설정된 모뎀이 XOFF의 수신으로 링크를 끊어 바럴 수도 있기 때문에 Software handshake에 쓰이는 XON과 XOFF 캐릭터를 피하고자 할 것이다. 또다른 예로써 Ctrl-] (telnet의 escape 캐릭터)를 들 수 있다. PPPㄴ는 ASCII 코드 0에서 31까지를 async map에 지정함으로써 그 캐릭터들을 escape시킬 수 있게 한다.

async map은 ASCII NUL 캐릭터에 상응하는 최소 significant bit과 ASCII 31에 상응하는 최대 significant bit을 가지는 31비트 넓이의 비트맵이다. 만약 비트가 지정되었다면, 보내기 전에 그 캐릭터가 반드시 escape되어야 한다고 알린다. 초기에, async map은 0xffffffff로 지정되며, 모든 컨트롤 캐릭터가 escape된다.

상대편에게, 모든 컨트롤캐릭터가 escape되는 대신 몇가지만을 escape시키고자할 땐, asuncmap옵션을 사용하여 pppd에 새로운 asyncmap을 지정해 줄 수 있다. 예를 들어, 단지 ^S와 ^Q(ASCII 17과 19로, 보통 XON과 XOFF에 사용된다)만을 escape시키려면 다음과 같이 하라.

     asyncmap 0x000A0000

Maximum Recieve Unit (MRU)는 우리가 수신하고자 하는 HDLC 프레임의 최대 크기를 상대편에게 알린다. 이것은 MTU 값(Maximum Transfer Unit)과 비슷한것 같지만 약간의 차이점을 갖고 있다. MTU는 커널 네트웍 디바이스의 파라미터이고, 인터페이스가 다룰 수 있는 최대 프레임 크기를 나타낸다. MRU는 그것보다 큰 프레임을 발생시키지 않도록 리모트에게 조언하는 것이다; 그럼에도 인터페이스는 1500 바이트까지의 프레임을 수신할 수 있다.

MRU를 선택하는 것은, 링크가 전송할 수 있는 능력의 문제가 아니라, 무엇이 최상의 처리량을 제공하느냐의 문제이다. 만약 링크를 통해 인터랙티브한 어플리케이션을 돌릴 작정이라면, MRU값을 296으로 낮게 지정하는 것이 좋은 생각이다. 그리하여 이따금씩 큰 패킷(이를테면, FTP 세션에서)때문에 당신의 커서가 "jump"되는 일이 없도록한다. pppd에 296의 MRU를 요구하라고 말하려면, mru 296의 옵션을 주면된다. 그러나 작은 MRU는 단지 VJ header compression을 꺼두었을 때만 해당된다(그것은 디폴트로 켜져있다).

pppd는, configuration request의 최대치와 같이, 링크가 종결되기전에 교환되어야할 negotiation process의 동작에 관한 모든 것을 설정하는 몇가지 LCP 옵션또한 가지고 있다. 이것이 무엇을 하는지 정확히 알지 못한다면 건드리지 않는편이 좋다.

마지막으로, LCP echo 메시지에 적용되는 두개의 옵션이 있다. PPP는 Echo Request와 Echo Response의 두개의 메시지를 정의한다. pppd는 링크가 작동중인지 체크하기 위해 이 기능을 사용한며, lcp-echo-internal에 초단위 시간을 줌으로써 이를 모두 사용할 수 있다. 만약 이 시간동안 리모트 호스트에서 프레임을 받지 못할 경우 pppd는 Echo Request를 발생시키고, 상대편의 Echo Response를 기다린다. 만약 상대쪽에서 reponse를 주지 않는다면, 링크는 일정수의 request를 보낸 후 연결을 종료한다. 이 수는 lcp-echo-failure 옵션으로 지정할 수 있다. 디폴트로, 이 기능은 둘다 꺼져 있다.


8.9 General Security Considerations

제대로 설정되지 않은 PPP 데몬은 보안에 구멍을 뚫을 수도 있으며, 누구라도 당신의 이더넷에 접속할 수 있게 만들 정도로 상태를 악화 시킬수 있다 (당연히 이는 무척이나 나쁜일이다). 이 절에서 우리는 당신의 PPP 설정을 안전하게 만들 몇가지 대처방법을 논의할 것이다.

pppd의 한가지 문제점은, 네트웍 디바이스와 라우팅 테이블을 설정할 때 root 권한을 필요로 한다는 것이다. 당신은 보통 이를 root로 setuid하여 해결할 것이나, 이것은 유저들도 여러 보안관련 옵션을 설정할 수 있도록 만든다. 유저들이 이 옵션을 교묘하게 조작하여 attack하는 일을 방지하기 위해선 전역(global)파일인 /etc/ppp/options에, Using Option Files 절의 샘플 파일에서 본 것같이 몇가지 디폴트 값을 지정해 줄 것을 권한다. 인증(authentication) 옵션 같은 것들은 유저에 의해 override 될 수 없기 때문에, 교묘한 조작해대해 적당할 정도의 방어를 해준다.

물론, 당신은 PPP로 교신하는 시스템에서도 당신을 보호해야한다. 다른 누구인 척하는 호스트를 막기 위해서는, 언제나 당신의 상대편에서 일중의 인증을 요구해야할 것이다. 추가로, 당신은 외부 호스트가 그들이 선택한 IP 주소를 제멋대로 사용하도록 내버려 두어선 안되고, 만약 그렇게 할때라도 제한은 해야한다. 다음절에서는 이 주제를 다룬다.


8.10 Authentication with PPP

8.10.1 CHAP and PAP

PPP에서 각 시스템은 상대편에게, 두가지 인증 프로토콜 중 하나를 사용하여 자신을 인증(authenticate)하라고 요구하는데, 이 두 프로토콜은 Password Authentication Protocol (PAP), 그리고 Challange Handshake Authentication Protocol (CHAP)이다. 커넥션이 성립되면 각 측은 전화 거는 쪽이든 전화 받는 쪽이든 상대편에게 자신을 인증할 것을 요구한다.

PAP는 기본적으로 보통의 로그인 프로시저와 동일한 방법으로 동작한다. 클라이언트는 유저 네임과 (암호화 할수도 있는) 패스워드를 서버로 보냄으로써 인증하고, 서버는 secret 데이터베이스에서 그것을 비교한다. 이 기법은 시리얼 라인을 감청하여 패스워드를 얻어내거나, 노가다 attack에는 속수 무책이다.

CHAP엔 이러한 결점이 없다. CHAP에서, 인증하는 쪽(즉, 서버)은 랜덤으로 발생되는 "challenge" 문자열을 그것의 호스트 네임과 함께 클라이언트로 보낸다. 클라이언트는 적절한 secret을 검색하고, challenge와 그것을 결합시키며, one-way해싱함수를 사용하여 그 문자열을 암호화하는데 호스트네임을 사용한다. 그 결과물은 클라이언트의 호스트네임과 함께 서버로 되돌아오며, 서버는 이제 동일한 연산을 수행하여, 동일한 결과에 이를경우 클라이언트를 인증한다.

CHAP의 또다른 기능은, 시작할 때에만 클라이언트에게 인증절차를 요하는 것이 아니라, 클라이언트가 혹시 침입자로 뒤바뀌지는 않았는지 (예를 들어, 전화선 스위칭에 의해) 확인하기 위해 일정간격으로 challenge를 보낸다.

pppd는 CHAP와 PAP을 위한 secret key들을 두 개의 파일에, 즉 /etc/ppp/chap-secretspap-secret에 별도로 보관한다. 어느파일에 있는 호스트에 들어가더라도, 상대편에게 우리자신을 인증시키는데 CHAP 또는 PAP을 사용하더라도 괜찮은 컨트롤을 가질 수 있다. 물론 그 반대의 경우도 마찬가지이다.

디폴트로, pppd는 리모트에서의 인증을 필요로 하지 않으나, 리모트가 자신을 인증하도록 요구하는데는 응한다. CHAP가 PAP보다 훨씬 강력하므로, pppd는 가급적 전자를 사용하려한다. 만약 상대쪽이 그것을 지원하지 않는다면, 혹은 pppdchap-secrets 파일 내에서 리모트 시스템을 위한 CHAP secret을 발견하지 못할 경우, PAP으로 전환한다. 만약 상대편에대한 PAP secret 조차도 갖고 있지 않다면, 인증을 모두 거부한다. 그 결과로 커넥션은 철거된다.

몇가지 방법으로 이러한 동작을 바꿀 수 있는데, 예를 들어 auth 키워드를 주면 pppd는 상대편에 자신을 인증하라고 요구한다. pppd는 각각 자신의 CHAP이나 PAP 데이터베이스에서 상대편의 secret을 갖고 있는지에 따라 그 둘중의 하나를 사용하는데 응한다. 그 외에도 특정 인증 프로토콜을 커거나 끌 수 있는 옵션이 몇개 더 있지만 여기에서 거론하진 않는다. 자세한 내용은 pppd(8) 매뉴얼 페이지를 참고하기 바란다.

만약 PPP로 통신하는 모든 시스템이 그들 자신을 인증하는데 동의한다면, auth 옵션을 /etc/ppp/options 전역 파일에 넣고 chap-secrets 파일에 각 시스템에 대한 패스워드를 정의해 두어야 할 것이다. 어떤 시스템이 CHAP을 지원하지 않는대면, pap-secrets 파일에 엔트리를 추가하라. 이러한 방법으로 당신은 인증받지 못한 시스템이 당신의 호스트에 연결할 수 없음을 확신할 수 있다.

다음의 두 서버는 두 가지의 PPP secret 파일인, pap-secretschap-secrets에 관해 논한다. 그 둘은 /etc/ppp내에 있고, 클라이언트와 서버, 그리고 패스워드의 세가지를 포함하며, 추가로 IP 주소의 목록도 들어갈 수 있다. 클라이언트와 서버필드우 해석은 CHAP과 PAP에서 서로 다르며, 이는 상대편이 우리를 인증하도록 할지 또는 우리가 서버에게 인증하라고 요구하는지에 달려있다.


8.10.2 The CHAP Secrets File

CHAP을 사용하여 서버에 자신을 인증시키려할 때, pppd는 클라이언트 필더가 로컬 호스트네임과 동일하고, 서버필드가 CHAP Challenge로 보내온 리모트 호스트네임과 동일한 엔트리가 있는지 pap-secrets파일을 검사한다. 상대편에 자신을 인증하라고 할때, 그 역할은 단순히 그 반대가 된다: 그러면 pppd는 클라이언트 필드가 리모트 호스트네임 (클라이언트의 CHAP Response 내에 보내져 온)과 동일하고, 서버필드가 로컬 호스트네임과 당일한 엔트리를 찾는다.

다음은 vlagerchap-secrets 파일이다.

     # CHAP secrets for vlager.vbrew.com
     #
     # client          server            secret                addrs
     #-------------------------------------------------------------------
     vlager.vbrew.com  c3po.lucas.com    "Use The Source Luke" vlager.vbr
     c3po.lucas.com    vlager.vbrew.com  "riverrun, pasteve"   c3po.lucas
     *                 vlager.vbrew.com  "VeryStupidPassword"  pub.vbrew.

c3po와 PPP 연결을 할 때, c3po는 CHAP Challenge를 보냄으로써, vlager에게 CHAP을 사용하여 자신을 인증하라고 한다. 그러면 pppd는 클라이언트 필드가 vlager.vbrew.com이고 서버 필드가 c3po.lucas.com인 엔트리가 있는지 chap-secrets 파일을 훑어보고 위에 보이는 첫번째 라인을 찾아낸다. 그리고는 challange 문자열과 secret (Use The Source Luke)에서 CHAP Response를 만들어내어 c3po로 보낸다.

그와 동시에, pppd는 고유한 challenge 문자열과 fully qualified 호스트네임 vlager.vbrew.com을 포함한, c3po에 대한 CHAP challenge를 작성한다. c3po는 방금 위에서 말한 것과 같은 양식으로 CHAP Response를 만들어 vlager에 되돌려 준다. 이제 pppd는 Response에서 클라이언트 호스트네임 (c3po.lucas.com)을 풀어내어, 클라이언트 필드에 c3po, 서버 필드에 vlager와 일치하는 라인을 chap-secrets 파일에서 찾는다. 위의 두번째 라인이 이러하다. 그리하여 pppd는 CHAP challenge와 secret인 riverrun, pasteve를 조합하여 암호화한 결과를 c3po의 CHAP Response와 비교한다.

네번째 필드는 옵션으로, 첫번째 필드에 명시된 클라이언트가 받아들이는 IP 주소를 나열한다. 그 주소는 dotted quad notation 또는 resolver로 검색되는 호스트네임을 준다. 예를 들어, 만약 c3po가 IPCP negotiation 중에 리스트에 없는 IP 주소를 사용할 것을 요청한다면, 그 요청은 거부될 것이여 IPCP는 종료한다. 게다가 위에 보이는 샘플 파일에서, c3po는 자신의 고유 IP 주소를 사용하도록 제한 되어 있다. 만약 그 주소 필드가 비어 있다면, 어느 주소도 허용한다; - 값은 클라이언트 모두의 IP 사용을 막는다.

샘플 chap-secrets 파일의 세번째 라인은 어떠한 호스트도 vlager와 PPP 링크를 수립할 수 있도록 허용하는데, 이유는 *의 클라이언트 또는 서버 필드는 모든 호스트에 대응되기 때문이다. 단지 필요한 것은 클라이언트가 secret을 알아야하고, pub.vbrew.com의 주소를 사용해야 한다는 것 뿐이다. pppd가 서버/클라이언트 페어에 적용되는 특정 엔트리 대부분을 언제나 사용할 것이므로, secret 파일 어디에서건 와일드카드 호스트네임 엔트리를 쓸 수 있다.

pppd가, secret 파일에서 호스트 에임을 검색하에 얻어내는 과정에 대해선 몇가지 말할 내용이 있다. 이전에 설명하였덧, 리모트 호스트 네임은 CHAP Challenge 또는 Response 패킷 내에 포함되어 전달된다. 로컬 호스트 네임은 디폴트로 gethostname(2)함수로 얻어진다. 만약 시스템 네임을 인증받지 않은(unqulified) 호스트 네임으로 지정해 두었다면, domain 옵션을 이용하여 pppd에 추가로 도메인 네임을 주어야 한다.

     # pppd ...domain vbrew.com

이는 인증에 관계된 모든 절차에 있어서, Brewery의 도메인 네임을 vlager에 첨부한다. pppd의 로컬 호스트 네임 내용을 수정하는 또 다른 옵션들로는 usehostnamename이 있다. "local:varremote"를 사용하여 로컬 IP 주소를 주거나, local에 dotted quad 대신 이름을 준다면, pppd는 이를 호스트네임으로 사용할 것이다. 더 자세한 사항은 pppd(8) 매뉴얼 페이지를 참고하라.

8.10.3 The PAP Secrets Files

PAP secret 파일은 CHAP의 그것과 아주 유사하다. 처음 도 필드엔 항상 유저 네임과 서버 네임이 들어 있고, 세번째는 PAP secret이 들어간다. 리모트가 인증 요청을 보내면, pppd는 서버 필드가 로컬 호스트 네임과 동일하고, 유저 필드가 request 내의 유저 네임과 동일한 엔트리를 사용한다. 자신을 상대에게 인증할 경우에 pppd는 유저 필드가 로컬 유저 네임과 동일하고 서버 필드가 리모트 호스트 네임과 같은 라인에서 secret을 추출할 것이다.

다음은 PAP secret 예제 파일이다.

     # /etc/ppp/pap-secrets
     #
     # user		server		secret		addrs
     vlager-pap	c3po		cresspahl	vlager.vbrew.com
     c3po		vlager		DonaldGNUth	c3po.lucas.com

첫번째 라인은 우리를 c3po에 인증할 때 사용된다. 도번째 라인은 c3po라은 유저가 어떻게 자신을 우리에게 인증시키는가를 보여준다.

첫번째 컬럼의 vlager-pap라는 이름은 우리가 c3po에 보내는 유저 네임이다. 디폴트로, pppd로컬 호스트 네임을 유저네임으로 쓰나, user 옵션뒤에 이름을 주어 다른 이름을 지정할 수도 있다.

상대편과의 인증을 위해 pap-secret 파일에서 엔트리 하나를 뽑아낼 때, pppd는 리모트 호스트 네임을 알아야만 한다. pppd 자체로는 상대편 호스트 네임을 찾아내진 못하므로, 커맨드 라인 상에서 remotename 키워드 뒤에 상대편 호스트 네임을 주어 지정할 수 일다. 예를 들어, 위의 c3po와 인증하는 엔트리를 사용하기 위해선, 커맨드 라인에 다음의 옵션을 pppd에 추가해야 한다.

     \#{} pppd ... remotename c3po user vlager-pap

마치 CHAP secret 파일에서처럼, 네번째 필드에(그리고 뒤따르는 모든 필드에) 특정 호스트가 어떤 IP 주소를 쓰도록 허용할 지를 지정해 줄 수 있다. 그러면, 상대편은 그 목록 내의 주소만을 요구할 것이다. 예제 파일에서는 c3po가 실제 자신의 IP 주소를 사용하길 요구한다.

PAP이 다소 약한 인증 방식이라는데 주의하라. 그리고 가능하다면 CHAP를 대신 사용하라고 권한다. 그리하여 우리는 여기서 PAP의 좀 더 세부적인 사항은 다루지 않았다. PAP 사용에 관심이 있다면, pppd(8) 매뉴얼 페이지에서 그것의 기능을 좀더 찾을 수 있을 것이다.


8.11 Configuring a PPP Server

pppd를 서버모드로 돌리려면, 커맨드라인에 적당한 옵션을 좀 더 주기만하면 된다. 추상적으로 얘기할때, 당신은 특수한 계정, 이를테면 ppp를 만들고 거기에 pppd를 이 옵션을 주고 실행시키는 스크립트 또는 프로그램을 로그인 쉘로 준다. 예를 들자면, 다음과 같은 라인을 /etc/passwd에 넣는다.

     ppp:*:500:200:Publiv PPP Account:/tmp:/etc/ppp/ppplogin

물론, 위에서 보는 것과는 다른 uid와 gid를 지정해 줄 수 있다. 그리고 passwd 커맨드를 써서 위의 계정에 패스워드를 지정해 줘야할 것이다.

ppplogin 스크립트는 다음과 같다.

     #!/bin/sh
     # ppplogin - script to fire up pppd on login
     mesg n
     stty -echo
     exec pppd -detach silent modem crtscts

mesg 커맨드는 다른 사용자가, write 커맨드 등으로, 사용중인 tty에 쓰기를 할 수 없게 한다. stty 커맨드는 Character echoing을 끈다. 이것은 꼭 필요하다. 만약 이를 사용하지 않는다면 상대편에서 보낸 것들이 다시 echo되어 돌아가게 되기 때문이다. 위에 준 옵션 중에 가장 중요한 pppd 옵션은 -detach이다. 왜냐하면 그것이 pppd가 제어중인 tty에서 따로 분리되어 나오지 않게 하기 때문이다. 만약 이 옵션을 지정해 주지 않는다면, pppd는 백그라운드로 가버리게 되고 쉘 스크립트는 종료된다. 따라서 시리얼라인이 hang up되어 커넥션이 drop된다. silent 옵션은 pppd가 sending을 시작하기 전에, 전화건 시스템에서의 패킷을 수신할 때까지 대기하게 한다. 이는 그 시스템이 PPP 클라이언트를 구동하는데 시간이 걸리더라도 transmit timeout이 일어나지 않게 한다. modem 커맨드는, pppd가 상대편이 커넥션을 drop 했는지 DTR 라인을 살펴보게하고, crtscts는 hardware handshake를 켠다.

이 옵션들 외에도, auth를 커맨드 라인이나 전역 옵션 파일에 지정하여 주어, 어떠한 인증단계를 거치게끔 할 수 일다. 매뉴얼 페이지에서는 개별적인 인증 포로토콜을 켜고 끄는 등의 조절을 하는 특정 옵션들에 대해 자세히 다루고 있다.

Other Chapters

1. Introduction to Networking
2. Issues of TCP/IP Networking
3. Configuring the Networking Hardware
4. Setting up the Serial Hardware
5. Configuring TCP/IP Networking
6. Name Service and Resolver Configuration
7. Serial Line IP
8. The Point-to-Point Protocol
9. Various Network Applications
10. The Network Information System
11. The Network File System
12. Managing Taylor UUCP
13. Electronic Mail
14. Getting smail Up and Running
15. Sendmail+IDA
16. Netnews
17. C News
18. A Description of NNTP
19. Newsreader Configuration

Appendix

A. A Null Printer Cable for PLIP
B. Sample smail Configuration Files
C. The GNU General Public License