IPFilter - WindyHana's Solanara

목차

개요

설치

솔라리스 10부터 IPFilter 는 번들되어있으며, 별도로 설치할 필요 없다. 솔라리스 9 이하를 사용하는 경우 아래와 같이 설치할 수 있다.

  1. 모든 패킷 막기

    root@wl ~ # vi /etc/opt/ipf/ipf.conf
    block in all
    block out all
    root@wl ~ # /etc/init.d/ipfboot reload
    
    각 단어의 의미는 다음과 같다.

    block: 패킷을 블로킹.
    in: 인바운드 패킷을 지정.
    all: 모든 패킷을 지정.
    out: 아웃바운드 패킷을 지정.

    - 따라서 [block in all]은 들어오는(in) 모든(all) 패킷을 차단(block)한다는 뜻이 되고, [block out all]은 나가는(out) 모든(all)패킷을 차단(block)한다는 뜻이 된다.
    - 이 이후부터는 ipf.conf의 내용만 적도록 하겠다.
  2. 들어오는 패킷은 막고 나가는 패킷은 허용

    위와 같이 하게 되면 인터넷이 안된다. 적어도 워크스테이션에서 파이어폭스를 띄워 인터넷은 되어야 작업이 가능할 것이다. 따라서 다음과 같이 수정해본다.
    block in all
    pass out all
    
    pass: 패킷을 통과시킴.

    - pass out all부분만 바뀌었다. 나가는(out) 모든(all)패킷을 통과(pass)시킨다.
  3. pcn0 장치를 이용한 외부 접속및 데이터 교환 허용

    위와 같이 해도 인터넷 접속은 안된다. 나가는 패킷은 허용되어있는데 들어오는 패킷은 허용되어있지 않기 때문이다. 즉, 데이터를 받을 수가 없다. 우리가 원하는것을 조금 다시 써본다면, 워크스테이션에서 접속을 시도한 곳은 데이터 교환이 되고 외부에서 워크스테이션으로 접속을 시도한 것은 모두 블로킹하도록 하자. 다음과 같이 수정한다.
    block in all
    pass out on pcn0 proto tcp from any to any keep state
    pass out on pcn0 proto udp from any to any keep state
    pass out on pcn0 proto icmp from any to any keep state
    
    on: 다음에 오는 인터페이스를 지정한다.
    proto: 다음에 오는 프로토콜을 지정한다.
    from: 소스 주소
    to: 목적지 주소
    keep state: 상태 유지

    [pass out on pcn0 proto tcp from any to any keep state]는 pcn0인터페이스(on pcn0)에서 모든곳에서(from any) 모든곳으로(to any)으로 가는 tcp 프로토콜을(proto tcp) 아웃바운드 패킷(out)에 한해 상태를 유지하면서(keep state) 허용한다는 뜻이 된다. 접속한 상태는 허용하고 이 상태를 유지하기 때문에 데이터 교환이 된다.
  4. 성능향상

    IPF는 룰을 위에서부터 차례대로 검사한다. (IPF뿐만 아니라 모든 방화벽이 그렇다) 시스템에 있는 NIC로 패킷이 들어오면 ipf.conf에 있는 모든 룰을 위에서부터 하나하나 확인해보는 것이다. 자. 생각해보자. 위의 글에서, 첫번째룰(block in all)에서 인바운드 패킷을 막았다. 그리고 룰의 내용으로 보아 아래의 룰은 더이상 확인할 필요 없다. 그러나 단순한 IPF는 아래의 룰도 확인한다. 한가지 예를 들어보자.
    block in all
    pass out on pcn0 proto tcp from any to any keep state
    pass out on pcn0 proto udp from any to any keep state
    pass in all
    
    위와 같은 룰이 있다면 처음엔 막으려고 생각했는데, 마지막줄에서 모두 통과시킨다. 결과적으로 인바운드 패킷은 통과한다. 물론 위 예는 극단적인 것이다. 따라서 더이상 룰을 확인할 필요 없다는 것을 IPF에 명시해줘야 한다. 그 지시어가 quick이다.
    block in quick all
    pass out on pcn0 proto tcp from any to any keep state
    pass out on pcn0 proto udp from any to any keep state
    pass out on pcn0 proto icmp from any to any keep state
    pass in all
    
    quick: 빨리. 더이상 아래의 룰을 확인할 필요 없다.

    - 첫번째 줄에 quick 지시어를 추가했다. 모든 인바운드 패킷은 첫번째의 룰에서 블록/통과 여부가 블록으로 결정된다. quick지시어가 있기 때문에 이 룰을 만족한 모든 패킷은 아래의 룰을 확인하지 않는다. 마지막 줄에 pass in all이 있지만 첫번째 룰만 보고 더이상 확인하지 않기 때문에 결과적으로 패킷은 블록된다.
    - 성능향상을 위해서는 quick를 잘 써야 한다. 자주 사용될 룰을 위로 올리는 것이 ipf 성능향상의 지름길이다.
    - [pass out quick on pcn0 proto icmp from any to any keep state]이란 룰에서 붉은색 글자는 동작방식을, 파란색 글자는 패킷의 조건을 나타낸다. 파란색 글자의 내용과 일치하는 패킷에 대해 붉은색 글자로 된 내용을 수행한다. 그것이 IPF의 동작 방식이다.
  5. 외부에서 웹서버(80번 포트) 접속

    pass in quick on pcn0 proto tcp from any to any port=80 keep state
    block in quick all
    pass out on pcn0 proto tcp from any to any keep state
    pass out on pcn0 proto udp from any to any keep state
    pass out on pcn0 proto icmp from any to any keep state
    
    port: 포트 번호

    - [to any port=80] 부분이 목적지의 포트 80에 해당하는 패킷임을 가리킨다.
  6. 192.168.0.8에서만 ftp(21번 포트)에 접속하게 하기

    pass in quick on pcn0 from 192.168.0.8 to 192.168.0.11 port=21
    block in quick on pcn0 from any to 192.168.0.11 port=21
    
    - 방화벽에 의해 보호된 FTP 서버에서, 위와 같이 열었을때 FTP 데이터 전송 방식은 반드시 PORT를 사용해야 한다.
  7. IP 192.168.0.0, NetMask 255.255.0.0 에서 ftp에 접속하게 하기

    pass in quick on pcn0 from 192.168.0.0/16 to any port=21
    
  8. ping 차단

    ping(1m)은 ICMP-ECHO_REQUEST 를 서버에 보내면 서버가 ICMP-ECHO_RESPONSE 으로 응답하는데, 보낸 시간과 받은 시간의 차를 구해 응답 시간을 구한다. 따라서 PING 을 작동하지 않게 하려면 들어오는 ICMP-ECHO_REQUEST 를 차단하거나 나가는 ICMP-ECHO_RESPONSE 을 차단하면 된다. 아래는 첫번째 방법을 사용했다.
    block in quick on pcn0 proto icmp from any to any icmp-type echo
    
    물론 전문적인 네트워크 툴은 다른 방식(예를 들어 UDP 를 사용하거나 ECHO 서비스를 사용한 방식)으로 PING 을 구현하기도 하며 이런건 위에 소개한 룰을 사용해서 차단할 수 없다. 윈디하나의 솔라나라: nmap - nping을 읽어보자.
  9. 샘플 룰

    HTTP, HTTPS, DNS, MAIL, POP3, FTP, SSH를 사용하는 룰에 대해서 소개한다. 또한 외부에서 PING도 열어놓았다. 이 룰은 솔라나라 서버의 룰과 비슷하다.
    pass in quick on pcn0 proto icmp from any to any icmp-type 8 code 0 keep state
    pass in quick on pcn0 proto tcp from any to any port=20 keep state
    pass in quick on pcn0 proto tcp from any to any port=21 keep state
    pass in quick on pcn0 proto tcp from any to any port=22 keep state
    pass in quick on pcn0 proto tcp from any to any port=25 keep state
    pass in quick on pcn0 proto tcp from any to any port=53 keep state
    pass in quick on pcn0 proto udp from any to any port=53 keep state
    pass in quick on pcn0 proto tcp from any to any port=80 keep state
    pass in quick on pcn0 proto tcp from any to any port=110 keep state
    pass in quick on pcn0 proto tcp from any to any port=443 keep state
    block in quick on pcn0 all
    pass out on pcn0 proto tcp from any to any keep state
    pass out on pcn0 proto udp from any to any keep state
    pass out on pcn0 proto icmp from any to any keep state
    

커맨드 툴

  1. 기본 룰 생성

    root@wl ~ # /opt/ipf/bin/mkfilters > ipf-example.conf1)
    root@wl ~ # cat ipf-example.conf1)
    #
    # The following routes should be configured, if not already: 2)
    #
    # route add 192.168.0.3 localhost 0
    #
    block in log quick from any to any with ipopts
    block in log quick proto tcp from any to any with short
    pass out on tcge0 all head 150
    block out from 127.0.0.0/8 to any group 150
    block out from any to 127.0.0.0/8 group 150
    block out from any to 192.168.0.3/32 group 150
    pass in on tcge0 all head 100
    block in from 127.0.0.0/8 to any group 100
    block in from 192.168.0.3/32 to any group 100
    
    1) 솔라리스 10 에서는 /usr/share/ipfilter/examples/mkfilters에 있다. 출력 내용을 파일로 저장해 사용하면 된다.
    2) 파일 내용처럼 route 명령을 사용해 자신의 IP로 오는 패킷을 로컬 호스트로 라우팅한다. 아래의 명령을 부팅 스크립트에서 네트워크 초기화할때 넣으면 된다.
  2. 로깅

    어떠한 패킷이 블록되었는지 확인하기 위해 로깅을 해야할 필요가 있다.
    root@wl ~ # vi /etc/opt/ipf/ipf.conf
    block in log quick on pcn0 from any to any # in 또는 out 뒤에 log라는 단어를 추가하면 된다.
    root@wl ~ # /etc/init.d/ipfboot reload
    root@wl ~ # /opt/ipf/bin/ipmon # 로그 보기
    01/01/2005 00:00:00.000000 pcn0 @0:1 b xxx.xxx.xxx.xxx,ppp -> xxx.xxx.xxx.xxx,ppp PR udp len 20 76 IN mbcast
    01/01/2005 00:00:00.000000 pcn0 @0:2 b xxx.xxx.xxx.xxx,ppp -> xxx.xxx.xxx.xxx,ppp PR tcp len 20 52 -SEC IN
    01/01/2005 00:00:00.000000 pcn0 @0:2 b xxx.xxx.xxx.xxx,ppp -> xxx.xxx.xxx.xxx,ppp PR tcp len 20 52 -S IN
    -------------------------1 ---2 ---3 4 -----------------------------------------5 -----6 --------7 --------8
    Ctrl+C
    root@wl ~ #
    
    각 필드의 설명은 다음과 같다.
    1. 패킷 도달 날짜 및 시간
    2. 패킷이 처리된 인터페이스 이름
    3. 룰 이름. 0번째 그룹(기본그룹)의 1번째 룰. 라인번호 등은 [ipfstat -i]명령의 라인 번호와 같다.
    4. 액션
      • b: 차단
      • p: 통과
      • s: 짧은 패킷
      • n: 룰에 매치 되지 않음
      • L: 로깅
    5. 소스주소,포트 -> 목적지주소,포트
    6. [PRotocol 프로토콜이름 또는 번호]
    7. [LENth 헤더길이 총길이]
    8. 추가 정보
      • TCP의 경우: 하이픈(-) 다음에 헤더 플래그가 나온다. S의 경우 SYN 패킷이라는 의미다.
      • icmp의 경우: icmp 문자 다음에 ICMP 메시지타입/서브메시지타입 이 나온다.
  3. SYSLOG로 로깅

    위 내용을 SYSLOG로도 로깅할 수 있다.
    root@wl ~ # vi /etc/syslog.conf
    local0.debug	/var/log/ipflog 1)
    root@wl ~ # touch /var/log/ipflog
    root@wl ~ # pkill -HUP syslogd
    
    1) 간격은 '탭'으로 구분한다
  4. 상태보기

    root@wl ~ # ipf -V 1)
    ipf: IP Filter: v4.1.28 (500)
    Kernel: IP Filter: v4.1.28
    Running: yes
    Log Flags: 0 = none set
    Default: pass all, Logging: available
    Active list: 1
    Feature mask: 0x187
    root@wl ~ # ipfstat
    bad packets:            in 0    out 0
     IPv6 packets:          in 0 out 0
     input packets:         blocked 2749 passed 31451095 nomatch 0 counted 0 short 0
    output packets:         blocked 11 passed 31530632 nomatch 0 counted 0 short 0
     input packets logged:  blocked 0 passed 0
    output packets logged:  blocked 0 passed 0
     packets logged:        input 0 output 0
     log failures:          input 0 output 0
    fragment state(in):     kept 0  lost 0  not fragmented 0
    fragment state(out):    kept 0  lost 0  not fragmented 0
    packet state(in):       kept 0  lost 0
    packet state(out):      kept 0  lost 0
    ICMP replies:   0       TCP RSTs sent:  0
    Invalid source(in):     0
    Result cache hits(in):  6581514 (out):  6534071
    IN Pullups succeeded:   3413    failed: 0
    OUT Pullups succeeded:  192352  failed: 0
    Fastroute successes:    0       failures:       0
    TCP cksum fails(in):    0       (out):  0
    IPF Ticks:      2419893
    Packet log flags set: (0)
            none
    root@wl ~ # ipfstat -io 2)
    ...
    
    1) 버전확인
    2) 설정보기

NAT

NAT이란 네트워크 주소 변환을 의미한다. 쉽게 말하자면 IP공유기가 이 NAT 기법을 이용한 장비이다. NAT에도 분류마다 다르지만 크게 4가지 작동방식이 있다. Full Cone, Restricted Cone, Port Restricted Cone, Symmetric 이 그것인데 여기서는 이에 대한 설명은 생략한다.
  1. 설정

    아래의 예제에서 pcn1은 리얼 IP를 가진 인터페이스의 이름이다. (사설 IP를 가진 인터페이스의 이름은 NAT를 구성할 때 알 필요 없다)
    NAT 설정
    root@wl ~ # vi /etc/opt/ipf/ipnat.conf
    map pcn1 192.168.0.0/16 -> 0.0.0.0/32 proxy port ftp ftp/tcp
    map pcn1 192.168.0.0/16 -> 0.0.0.0/32
    root@wl ~ # /etc/init.d/ipfboot reload
    root@wl ~ # ipnat -slv 3)
    
    3) 상태보기.
    192.168.0.0/16 아이피를 가진 시스템에서 오는 패킷은 pcn1을 통해, pcn1이 가진 리얼 아이피로 바뀌어 재 전송될 것이다. 만약 pcn1이 두개 이상의 아이피를 가졌다면 두가지중 한가지 IP로 바뀌어서 전송된다. 한개의 아이피만 사용하려면 0.0.0.0/32가 아니라 xxx.xxx.xxx.xxx/32로 써주면 된다. 만약 두개 이상의 아이피중 하나로 보내도록 하려면 xxx.xxx.xxx.xxx/16 과 같이 써 주면 된다. [proxy port ftp ftp/tcp] 부분은 192.168.0.0/16을 가진 시스템에서 ftp를 port방식으로 사용하기 위해 필요하다. ftp를 pasv방식으로 사용한다면 지워도 된다.
  2. 포트 포워딩

    포트 포워딩은 rdr 명령을이용한다. 아래에 예제는 pcn1 인터페이스에 대해 FTP 포트 매핑하고, 80포트로 오는 모든 TCP 패킷을 192.168.0.3 번으로 포워딩 하며, 53번 포트로 오는 모든 TCP/UDP 패킷을 192.168.0.3 번으로 포워딩 한다. 물론 해당 IP들은 ipf.conf 에서 열려있어야 한다.
    root@maid /etc/opt/ipf # cat ipnat.conf
    map pcn1 192.168.0.0/16 -> 0.0.0.0/32 proxy port ftp ftp/tcp
    map pcn1 192.168.0.0/16 -> 0.0.0.0/32
    rdr pcn1 0.0.0.0/0 port 80 -> 192.168.0.3 port 80
    rdr pcn1 0.0.0.0/0 port 53 -> 192.168.0.3 port 53 tcp/udp
    root@wl ~ # /etc/init.d/ipfboot reload
    
  3. 로드밸런싱

    포트포워딩시 보낼IP와 포트 콤마(,)를 이용해 로드밸런싱을 구현할 수 있다.(로드 밸런싱 알고리즘은 Round Robin이며 Failover와 같은 기능은 지원되지 않는다)
    rdr pcn1 0.0.0.0/0 port 80 -> 192.168.0.3, 192.168.0.4, 192.168.0.5 port 80
    
    pcn1, 80포트로 들어오는 패킷은 192.168.0.3, 192.168.0.4, 192.168.0.5으로 분산되어 전송된다.

참고

  1. 특별하게 사용되는 주소

  2. 주요 포트 번호

    포트이름                포트 TCP/UDP 여부
    ECHO                       7 (TCP/UDP)
    FTP DATA                  20
    FTP                       21
    SSH                       22 (TCP/UDP) 2)
    TELNET                    23
    SMTP(SENDMAIL)            25
    DOMAIN(BIND)              53 (TCP/UDP)
    NetBoot via DHCP          67 (UDP)
    NetBoot via DHCP          68 (UDP)
    TFTP                      69 (UDP)
    HTTP                      80
    Kerberos                  88
    POP3                     110
    RPC                      111 (TCP/UDP)
    Simple FTP               115
    NNTP                     119
    NTP                      123 (TCP/UDP)
    NetBIOS Name             137 (TCP/UDP)
    NetBIOS Datagram         138 (TCP/UDP)
    NetBIOS Session          139 (TCP/UDP)
    IMAP                     143
    SNMP                     161 (UDP)
    SNMP Trap                162 (UDP)
    IRC                      194
    SNMP Unix Multiplexer    199
    RPC2PORTMAP              369 (TCP/UDP)
    CLEARCASE                371
    LDAP                     389
    HTTPS                    443
    SMB                      445
    SMTPS                    465
    Syslog                   514 (UDP)
    Printer Spooler          515
    klogin                   543
    AFP over IP              548
    SMTP Submission          587
    iSCSI                    860
    rsync                    873
    FTPS DATA                989
    FTPS                     990
    TELNETS                  992
    IMAPS                    993
    POP3S                    995
    TFTP DATA               1390 (UDP)
    ORACLE TCP              1521
    NFS                     2049 (TCP/UDP)
    CVS PSERVER             2401 (TCP/UDP)
    ORACLE TCP/SSL          2484
    iSCSI                   3260
    MySQL                   3306
    Remote Desktop Protocol 3389 1)
    TURN                    3478 (TCP/UDP)
    DDAP(iTunes)            3689
    SVN (Subversion)        3690 (TCP/UDP)
    TFTPS                   3713
    SIP                     5060 (UDP)
    SIP                     5061 (UDP)
    PCAnyWhere              5631
    PCAnyWhere              5632 (UDP)
    VNC                     5900
    X-Window                6000 (TCP/UDP)
    WEB CACHE               8080 (TCP/UDP)
    ANON START              49152 (UDP)3)
    ANON END                65535 (UDP)3)
    
    1) Microsoft의 Terminal Service/Virtual Box의 VRDP 서비스를 위한 포트이다
    2) SSH도 UDP를 필요로 한적이 있었지만 요즘에는 TCP만 사용한다.
    3) TURN 서버용 익명 포트 시작 ~ 끝 포트. RFC 5766 - Traversal Using Relays around NAT (TURN): Relay Extensions to Session Traversal Utilities for NAT (STUN)에 정의되어있다.
  3. netstat 용 상태 변화 차트 (TCP 접속시)

    SERVER> → CLOSED 1 → LISTEN 2 → SYN_RCVD 4 → ESTABLISHED 6
    
    CLIENT> → CLOSED 1 → SYN_SENT 3 → ESTABLISHED 5
    
    1 어떠한 접속 요청도 없는 상태이다. netstat 에서는 CLOSED라는 상태는 표시되지 않는다.
    2 서버쪽에서 포트를 오픈한 상태이다. 오픈된 포트는 LISTEN으로 표시된다.
    3 클라이언트에서 연결요청패킷(SYN패킷)을 보낸 상태이다.
    4 클라이언트에서 보낸 연결요청패킷에 대해 응답패킷(SYN-ACK패킷)을 보낸 상태이다.
    5 서버에서 준 응답패킷에 대해 응답패킷(ACK패킷)을 보낸 후 바로 ESTABLISHED 상태로 넘어간다.
    6 클라이언트에서 보낸 응답패킷을 받으면 바로 ESTABLISHED 상태로 넘어간다.

    ※ 보낸 패킷 위주로 다시 정리하자면
    1) 클라이언트에서 SYN 패킷 전송
    2) 서버에서 SYN-ACK 전송
    3) 클라이언트에서 ACK 전송
    위와 같이 되며 이 3단계를 3-way handshake 라 한다.
  4. netstat 용 상태 변화 차트 (TCP 접속 해제시)

    SERVER> → ESTABLISHED 1 → FIN_WAIT_1 2 → FIN_WAIT_2 4 → TIME_WAIT 5 → CLOSE7
    
    CLIENT> → ESTABLISHED 1 → CLOSE_WAIT 3 → LAST_ACK 6 → CLOSE 8
    
    1 접속된 상태
    2 접속종료요청패킷(FIN-ACK패킷) 전송한 상태. (close(2)를 호출한 상태)
    3 접속종료요청패킷받은 후 응답패킷(ACK패킷) 전송한 상태.
    4 응답패킷을 받은 상태. 여기까지 왔으면 접속은 사실상 끊긴 상태이다.
    5 응답패킷만 받고 두번재 응답패킷(FIN-ACK패킷)을 받지 못한 상태. FIN_WAIT_2에서 일정시간동안 FIN-ACK패킷(6에서 보낸 패킷)을 받지 못하면 TIME_WAIT상태로 된다.
    6 응답패킷(FIN-ACK)패킷을 보낸 상태. (close(2)를 호출해 응답패킷을 보낼 수 있다. 즉 이 패킷을 전송했다는 것은 서버에서 일방적으로 끊은 상태를 클라이언트의 프로그램에서 인지했다는 의미다)
    7 FIN_WAIT_2 또는 TIME_WAIT 상태에서 6에서 전송한 FIN-ACK를 받았거나, TIME_WAIT상태에서 일정 시간이 지났을때 해당된다. FIN-ACK를 받았다면 ACK 패킷를 보낸다.
    8 ACK패킷을 받았거나LAST_ACK에서 일정한 시간이 지나면 CLOSE상태로 된다

    ※ 보낸 패킷 위주로 다시 정리하자면
    1) 클라이언트에서 FIN-ACK 패킷 전송
    2) 서버에서 ACK패킷 전송
    3) 서버에서 FIN-ACK 패킷 전송
    4) 클라이언트에서 ACK 패킷 전송
    위와같이 4단계로 진행된다.
    NETSTAT에서 FIN_WAIT_2, TIME_WAIT가 많은 경우 어플리케이션의 오류일 확률이 있다. 양측에서 명시적으로 커넥션을 종료(close(2)를 호출)해야 TIME_WAIT, FIN_WAIT_2 상태를 줄일 수 있다.
  5. 주요 ICMP 타입 및 코드, 예약어, 설명

    Internet Control Message Protocol (ICMP) Parameters에서 발췌
    이름             타입    코드  ipfilter예약어 설명
    ICMP_ECHOREPLY      0       0  echorep        Ping 응답.
    ICMP_UNREACH        3       4  needfrag       최적의 MTU 세팅을 위해 사용됨.
    ICMP_ECHO           8       0  echo           Ping 요청.
    ICMP_TIMXCEED      11       0  timex          TTL 만료시 사용됨. traceroute 또는 tracert에서 사용.
    
  6. 참고 웹사이트

RSS ATOM XHTML 1.0 CSS3