iptables 방화벽 설정 관련…

 요즘 공부하고 있는 iptables 를 이용한 방화벽 구축 관련하여…

 한가지 문제가 되는 부분이 있었다.

 그것은 바로 방화벽을 설정하게 되면 이상하게 네임서버 질의가 안되는 것.

 문제의 발단은 다음의 스크립트를 이용하여 방화벽을 설정하는 것 부터 시작이었다.

#!/bin/sh

IPTABLES=/sbin/iptables
MODPROBE=/sbin/modprobe

### 기존 규칙을 제거하고 체인 정책을 DROP으로 설정한다.
echo “[+] Flushing existing iptables rules…”
$IPTABLES -F
$IPTABLES -X
$IPTABLES -P INPUT DROP
$IPTABLES -P OUTPUT DROP
### load connection-tracking modules
$MODPROBE ip_conntrack
$MODPROBE ip_conntrack_ftp

###### INPUT 체인 ######
echo “[+] Setting up INPUT chain…”
### 상태 추적 규칙
$IPTABLES -A INPUT -m state –state INVALID -j LOG –log-prefix “DROP INVALID ” –log-ip-options –log-tcp-options
$IPTABLES -A INPUT -m state –state INVALID -j DROP
$IPTABLES -A INPUT -m state –state ESTABLISHED,RELATED -j ACCEPT

### ACCEPT 규칙
#ftp
$IPTABLES -A INPUT -i eth0 -p tcp –dport 20 –syn -m state –state NEW -j ACCEPT
$IPTABLES -A INPUT -i eth0 -p tcp –dport 21 –syn -m state –state NEW -j ACCEPT
#ssh
$IPTABLES -A INPUT -i eth0 -p tcp –dport 22 –syn -m state –state NEW -j ACCEPT
#whois
$IPTABLES -A INPUT -i eth0 -p tcp –dport 43 –syn -m state –state NEW -j ACCEPT
#domain
$IPTABLES -A INPUT -i eth0 -p tcp –dport 53 –syn -m state –state NEW -j ACCEPT
#http
$IPTABLES -A INPUT -i eth0 -p tcp –dport 80 –syn -m state –state NEW -j ACCEPT
$IPTABLES -A INPUT -i eth0 -p udp –dport 80 -m state –state NEW -j ACCEPT
#https
$IPTABLES -A INPUT -i eth0 -p tcp –dport 443 –syn -m state –state NEW -j ACCEPT
#rsync
$IPTABLES -A INPUT -i eth0 -p tcp –dport 873 –syn -m state –state NEW -j ACCEPT
$IPTABLES -A INPUT -i eth0 -p udp –dport 873 -m state –state NEW -j ACCEPT
$IPTABLES -A INPUT -p icmp –icmp-type echo-request -j ACCEPT
$IPTABLES -A INPUT -i ! lo -j LOG –log-prefix “DROP ” –log-ip-options –log-tcp-options

###### OUTPUT 체인 ######
echo “[+] Setting up OUTPUT chain…”

### 상태 추적 규칙
$IPTABLES -A OUTPUT -m state –state INVALID -j LOG –log-prefix “DROP INVALID ” –log-ip-options –log-tcp-options
$IPTABLES -A OUTPUT -m state –state INVALID -j DROP
$IPTABLES -A OUTPUT -m state –state ESTABLISHED,RELATED -j ACCEPT

### 외부로 나가는 연결을 허용하기 위한 ACCEPT 규칙
#ftp
$IPTABLES -A OUTPUT -p tcp –dport 20 –syn -m state –state NEW -j ACCEPT
$IPTABLES -A OUTPUT -p tcp –dport 21 –syn -m state –state NEW -j ACCEPT
#ssh
$IPTABLES -A OUTPUT -p tcp –dport 22 –syn -m state –state NEW -j ACCEPT
#whois
$IPTABLES -A OUTPUT -p tcp –dport 43 –syn -m state –state NEW -j ACCEPT
#domain
$IPTABLES -A OUTPUT -p tcp –dport 53 –syn -m state –state NEW -j ACCEPT
#http
$IPTABLES -A OUTPUT -p tcp –dport 80 –syn -m state –state NEW -j ACCEPT
$IPTABLES -A OUTPUT -p udp –dport 80 -m state –state NEW -j ACCEPT
#https
$IPTABLES -A OUTPUT -p tcp –dport 443 –syn -m state –state NEW -j ACCEPT
#rsync
$IPTABLES -A OUTPUT -p tcp –dport 873 –syn -m state –state NEW -j ACCEPT
$IPTABLES -A OUTPUT -p udp –dport 873 -m state –state NEW -j ACCEPT
$IPTABLES -A OUTPUT -p icmp –icmp-type echo-request -j ACCEPT

### 기본 OUTPUT LOG 규칙
$IPTABLES -A OUTPUT -o ! lo -j LOG –log-prefix “DROP ” –log-ip-options –log-tcp-options

 보기에는 별 문제가 없는 방화벽 스크립트이다.

 기본적으로 모든 입력에 대해 DROP 정책을 고수하고 서비스하는 특정 포트들에 대해 접근을 허가하는 내용인데… 특이점으로 ftp에 대한 포트와 rsync를 위한 포트를 개방한 부분에 있다.

 이는 동아리에서 서비스 중인 미러링 사이트 유지를 위해 필요한 부분이었기 때문에 특별히 신경썼던 부분이었다.

 해당 스크립트를 적용시킨 후, ssh 접속 및 ftp, http 접속이 정상적으로 이루어지는 것을 확인하여 아무런 문제가 없는 줄 알았다.

 하지만… 미러링을 위한 rsync 스크립트를 돌리자마자 다음의 오류를 발생하며 프로세스가 정지가 되는 것이었다.
 

rsync: getaddrinfo: releases.ubuntu.com 873: Temporary failure in name resolution
rsync error: error in socket IO (code 10) at clientserver.c(122) [receiver=3.0.3]

 에러 발생 메시지가 늘 그렇듯이 처음보는 에러메시지였다. 하지만 에러 메시지 중 익숙한 부분이 눈에 들어왔다. 바로 “getaddrinfo” 라는 부분과 “socket IO” 부분.

 그렇다. 네트워크 프로그래밍에서 주소를 받아오는 함수부분인 것이다. 다른곳도 아니고 주소를 알아내는 모듈이 실패를 했다는 메시지가 나오니 그래서..설마하는 마음으로 dig 명령어를 이용한 IP 질의를 해보았다.

 역시나였다. dig, nslookup 등등의 명령어가 먹히지 않는다. 이상했다.

 resolve 질의를 위한 부분 역시 스크립트에서는 명백히 명시를 해놓았기 때문이다. 무엇이 문제일까. 구글링 및 kldp를 비롯하여 여러곳을 뒤져보아도 속시원한 답을 찾을 수 없었다.

 단 하나, 똑같은 상황이 있었는데 네임서버 설정이 잘못되있는 경우 그런 에러가 발생한다는 것만 알 수 있었다.

 하지만 이미 네임서버는 설정이 정상적으로 되어 있는 상황이었고, 같은 네임서버를 설정해놓은 다른 보통의 서버(위의 스크립트를 적용시키지 않은)들은 아무 문제없이 질의가 이루어지는 상황이었다.

 한참….을 헤멘후에야 그 해답을 알 수 있었는데..

 그 정답은 바로 다음의 라인이었다.

$IPTABLES -A INPUT -p udp –dport 53 -m state –state NEW -j ACCEPT
$IPTABLES -A OUTPUT -p udp –dport 53 -m state –state NEW -j ACCEPT

 차이를 알겠는가? 바로 프로토콜 설정부분이었다. 기존의 스크립트는 -p tcp 만을 옵션으로 하였기 때문에 udp의 경우는 방화벽에 차단당했던 것이었다.

 늘 그렇다. 알고나면 별것아닌것. 에효… 진즉에 service 파일좀 살펴볼껄… 별것아닌 에러에 이렇게 곤란을 느낀것이 부끄럽기만 하다.

iptables (커널 2.4대의 방화벽 관리도구)

 커널 2.4대에서 방화벽, 규칙 설정, IP 매스커레이딩을 조정하는 커널 도구

 iptables -[ADC] chain 상세룰 [옵션]
 iptables -[RI] chain 룰번호 상세룰 [옵션]
 iptables -D chain 룰번호 [옵션]
 iptables -[LFZ] [chain] [옵션]
 iptables -[NX] chain
 iptables -E 이번체인이름 새로운체인이름
 iptables -P chain target [옵션]
 iptables -h

 -A chain, –append chain : chain을 추가한다.
 -D chain, –delete chain : chain에서 룰을 삭제한다.
 -D chain 룰넘버, –delete chain 룰넘버 : chain 정책 중 지정한 룰넘버를 삭제한다. 만일 룰넘버가 1이라면 chain 규칙의 첫 번째 룰을 삭제한다.
 -I chain [룰넘버], –insert chain [룰넘버] : chain 정책에 지정한 숫자번째에 삽입하거나, 마지막에 룰을 삽입한다.
 -R chain 룰넘버, –relace : chain 정책 중 지정한 숫자번째의 룰을 교체한다.
 -L [chain], –list [chain] 모든 chain 정책을 보거나, 지정한 chain 정책을 본다.
 -F [chain], –flush : 모든 chain 정책을 삭제하거나, 지정한 chain 정책을 삭제한다.
 -Z [chain], –zero : 모든 chain 정책을 제로로 만들거나, 지정한 chain 정책을 제로로 만든다.
 -C chain, –check chain : 설정한 chain 정책을 테스트한다.
 -N chain, –new-chain : 새로운 정책을 만든다.
 -X [chain], –delete-chain : 사용자가 만든 chain이나 모든 chain을 삭제한다.
 -P chain target, –policy chain target : chain 정책을 지정한 chain 정책으로 바꾼다.
 -E old-chain new-chain, –rename-chain old-chain new-chain : chain명을 바꾼다.
 -p, –protocol [!] proto : 프로토콜을 지정한다. !은 제외의 의미이다.
 -s, –source [!] address[/mask] : 출발지 주소를 지정한다. mask는 C클래스면 255.255.255.0이나 24비트로 표현된다.
 -d, –destination [!] address[/mask] : 목적지 주소를 지정한다.
 -i, –in-interface [!] input name[+] 수신하는 네트워크 인터페이스 이름을 지정한다. name+은 name으로 시작하는 모든 인터페이스 이름이다.
 -j –jump target : 지정하는 target으로 리다이렉트 시킨다.
 -m : 지정한 match로 확장이 가능하다.
 -n : IP주소와 포트번호를 숫자 그대로 보여준다.
 -o, –out-interface [!] output name[+] : 발신하는 네트워크 인터페이스 이름을 지정한다.
 -v, –verbose : 상세한 정보를 보여준다.
 –line-numbers : 룰정책을 보여줄 때 줄번호도 나타낸다.
 -x, –exact : 정확한 값으로 나타낸다.
 -V, –version : 버전 정보를 보여준다.

 iptables는 netfilter 필터링 룰에 사용한다. 대부분 ipchains와 사용법이 거의 같으나, 가장 큰 차이점은 확장성에 있다. 정상적으로 커널 확장은 커널 모듈 하부 디렉토리(/lib/modules/커널버전/kernel/net)에 존재하는데, iptables는 요구에 의하여 적재된다. 그래서, 아들 모듈을 직접 적재할 필요는 없다. iptables의 확장들은 공유 라이브러리 형태로 보통 /usr/local/lib/iptables 에 위치한다. 배포판은 이것을 /lib/tables나 /usr/lib/tables 에 넣으려 할 것이다.

User image 우분투 8.10-Desktop 의 경우 /lib/iptables 밑에 존재한다.

 ipchain이 iptables에서 변경된 사항들은 다음과 같다.

 * 미리 만들어진 체인 이름 (input, output, forward)가 소문자에서 대문자로 바뀌었다.

 * -i 지시자는 들어오는 인터페이스만 의미하고 INPUT과 FORWARD chain에서만 작동한다. FORWARD나 OUTPUT chain은 -o 로 사용한다.

 * TCP와 UDP 포트는 –source-port, –sport (–destination-port, –dport)과 사용하게 된다. -p tcp 또는 -p udp 옵션과 함께 사용되어져야 한다.

 * TCP -y 지시자는 –syn 으로 바뀌었고 -p tcp 다음에 와야한다.

 * DENY target 는 DROP으로 바뀌었다.

 * iptables 를 이용하여 정책들을 입력하였다면, 이는 메모리에 적재될 뿐이므로 시스템을 다시 시작한 후에는 모두 사라질 것이다. 이를 iptables-save 명령으로 저장이 가능하다.

 # iptables-save > iptables_test

 아래와 같이 iptables-restore 명령으로 저장한 정책 파일을 불러올 수도 있다.

 # iptables-restore < iptables_test

 * 매스커레이딩(iptables)
 ipchain 명령과 마찬가지로 내부 인터넷 연결 공유를 할 수 있다. masquerading 기법으로 한 컴퓨터에 두 개의 네트워크 인터페이스를 설정한 다음, 하나는 외부의 인터넷과 연결되어 있고, 다른 하나는 내부 게이트웨이(192.168.0.1 이라고 가정)의 역할을 하도록 설정한다. 내부 게이트웨이 역할을 하는 인터페이스와 연결된 허브를 통해 같은 192.168.0.0/24 대역의 아이피를 설정하여, 내부에서도 인터넷을 사용할 수 있도록 할 수 있다. 아래의 스크립트는 최소의 masquerading 기법을 위한 입력으로 손쉽게 내부에 인터넷을 공유할 수 있다.

 # /sbin/iptables -F
 # echo “1” > /proc/sys/net/ipv4/ip_forward
 # iptables -t nat -A POSTROUTING -s 192.168.1.2/24 -j MASQUERADE

 * 솔라리스(Solaris)
 솔라리스는 BSD 계열의 SunOS를 바탕으로 하여, System V 계열의 영향을 받은 SunOS 5 버전부터는 Solaris 2.x 라는 이름도 함께 사용해 왔다. 이후 Solaris 2.7 부터는 다시 Solaris 7이라는 이름으로도 통용되고 있다. Sun 사에서는 이 OS를 자사에서 생산하는 스팍 플랫폼 용으로만 개발하였으나 인텔 플랫폼을 사용하는 경우가 늘어나며 인텔용 버전도 함께 개발하였다. 그러나 본질적으로는 거의 동일한 소스를 기반으로 컴파일한 제품이므로 성능 면에서는 큰 차이가 없다.

두번째 미러링 사이트…

 여기에는 포스팅을 하지 않았지만 동아리 FTP 사이트를 꾸며 우분투 리눅스 미러링 서비스를 시작했었다.

 그리고 이번에는 두번째 서비스로 아파치 미러링을 시작하게 되었다… 얏호! 🙂

유스케이스

    *** 유스 케이스

 – 시스템이 제공하는 각 기능

   ** 유스케이스 이름

  * 명명 규칙1 : 행위 또는 동작을 뜻하는 명사 사용
 – 시스템의 기능을 나타내어야 함
 – ex) 수강 -> 수강신청, 출석부 -> 출석부 조회

  * 명명 규칙2 : 사용자가 얻고자 하는 목적이 명확히 나타나야 함.
 – ex) 수강 과목 선택 -> 수강 신청

  * 명명 규칙3 : 사용자(액터)의 입장에서 명명되어야 함
 – ex) 성적 관리 -> 성적 등록
 – ex) 수강 신청 관리 -> 수강 신청

  * 요약 : 사용자의 관점에서 바라보고 시스템이 제공하는 기능을 이용하여 궁극적으로 하고자 하는 행위를 나타내는 명사를 사용한다.

   ** 유스케이스 설명

  * 유스케이스를 이용하는 사용자에게 이 유스케이스를 통해서 시스템이 어떤 기능을 제공하는 지를 한/두 문장으로 간단하고 명확하게 기술하는 것

   ** 유스케이스의 특성

  * 특성 1 : 하나의 유스케이스는 일련의 액션들로 표현

  * 특성 2 : 하나의 유스케이스는 여러 variants를 포함
 – 기본 흐름(basic flow) : 가장 전형적이고, 정상적인 경우
 – 대안 흐름(alternative) : 기본 흐름을 벗어나는 다른 상황을 나타냄
 – 각 대안 흐름 별로 별도의 유스케이스를 정의하지 않음
 – ex) 카드 판독 실패 이벤트 흐름
+ 카드 판독이 불가능함을 사용자에게 알리고 카드를 배출시킨다.
+ 사용자는 카드를 회수한다.
 – ex) 잔액 부족 이벤트 흐름
+ 잔액 부족을 사용자에게 알리고, 카드를 배출하고, 영수증을 인자한다.
+ 사용자는 카드와 영수증을 회수한다.

  * 특성 3 : 유스케이스는 시스템이 제공하는 기능
 – 시스템에서 제공하지 않을 기능이 유스케이스에 포함되어서는 안됨
 – 수작업을 통해서하는 작업을 유스케이스에 포함시켜서는 안됨
 – ex) 학교에서 배포된 성적표로 성적 확인은 유스케이스에 포함시켜서는 안됨

  * 특성 4 : 유스케이스는 액터가 관찰할 수 있는 결과를 산출
 – ex) 현금 자동 인출기 시스템의 출금 유스케이스
+ 카드 판독의 성공 표시 및 거래 종류의 일력을 요청하는 화면
+ 암호의 입력을 요청하는 화면
+ 암호의 확인 성공 표시 및 인출할 금액의 입력을 요청하는 화면
+ 출금이 진행 중임을 표시하는 화면
+ 출금 시 배출된 현금과 영수증
 – 유스케이스는 액터가 궁극적으로 원하는 결과를 내야 한다.

  * 특성 5 : 유스케이스는 액터에 의해서 수행이 시작
 – ex) 출금 유스케이스 : 사용자 액터가 카드를 삽입함으로써 수행
 – 유스케이스의 이벤트 흐름은 반드시 액터에 의해서 시작된다.

  * 특성 6 : 한 유스케이스 내의 액션들을 트랜젝션처럼 수행
 – 한 유스케이스의 이벤트 흐름을 구성하는 각 이벤트들은 유스케이스가 수행될 때 모두 발생하는 것이며 부분적인 발생은 허용되지 않음.
 – 이벤트 흐름의 부분만을 수행하는 것이 가능하면 그것을 하나의 유스케이스라고 볼 수 없음.
 – ex) 성적 등록
 – ex) 출석부 조회

   ** 유스케이스 찾기

 – 질문1 : 사용자 액터가 시스템이 제공하기를 원하는 기능은 무엇인가?
+ ex) ATM : 입금, 출금, 조회, 이체, 통장 정리
+ ex) 대학 정보 시스템 : 학생(수강신청, 성적조회), 교수(출석부 조회, 성적 등록)
 – 질문2 : 시스템이 어떤 기능을 제공하면 사용자 액터의 일상 작업이 효율적이고 편해지는가?
+ 수업 담당자 : 수강료 청구서 발급
 – 질문3 : 사용자 액터가 시스템에 어떤 정보를 생성/조회/수정/삭제하고 싶어 하는가?
 – 질문4 : 시스템의 입력과 출력은 무엇인가?