블로그 이미지
GUCCI

카테고리

전체보기 (111)
여행 (1)
기기 (2)
쇼핑 (0)
게임 (0)
etc. (6)
취업이야기 (0)
업무일지 (5)
리눅스 (38)
웹프로그래밍 (2)
네트워크 (4)
JAVA (17)
Android (0)
IOS (2)
LUA (8)
C/C++ (1)
Objective C (2)
SERVER (2)
그누보드4 (1)
MSSQL (2)
Programming (1)
자바스크립트 (4)
HTML/CSS (1)
LGNAS (0)
Total
Today
Yesterday

NAT - KLDP

네트워크 / 2012. 2. 10. 00:21

1. 들어가는 글

친애하는 독자 여러분, 반갑습니다.

여러분은 이제 NAT(Network Address Translation, 네트워크 주소 변환)라는 매혹적인 세계(때론 끔찍하기도 하지만)로 들어서려 합니다. 이 HOWTO 문서는 여러분에게 2.4 리눅스 커널 및 그 이후 버젼에 대한 꽤 정확한 가이드가 될겁니다.

리눅스 2.4에서는 넷필터(netfilter)라 불리는 패킷 변경을 위한 인프라가 깔려있습니다. 이를 기반으로 하여 NAT기능이 작동됩니다. 이번 버젼은 예전 커널과 다르게 완전히 새로운 방식으로 구현된 것입니다.

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

2. 공식 웹 사이트와 관련 리스트는 어디에 있나요?

세개의 공식 사이트가 존재합니다:

여러분은 http://www.netfilter.org/ 과 http://www.iptables.org/ 를 경유하여 round-robin DNS를 사용해 그 사이트들에 접속 가능합니다.

공식적인 메일링 리스트를 알아보시고 싶으신 분은 netfilter List를 보세요.

2.1 네트워크 주소 변환이란 무엇입니까?

보통 네트워크 상의 패킷들은 발신지(예를들어 여러분 가정의 컴퓨터)를 출발하여 수신지(예를 들어 www.gnumonks.org라는 사이트)에 도착할때까지 때 여러 링크를 거쳐 전송됩니다. 제가 있는 호주에서는 그 사이트까지는 보통 19개 정도 거칩니다. 이들 링크들은 모두 전송 패킷을 변환시키지 않고 바로 목적지로 보냅니다.

이러한 링크중 하나가 NAT 를 한다고 하면 그 패킷이 통과할 때 발신지 혹은 수신지를 변환시킵니다. 쉽게 짐작되듯 이것은 일반적인 시스템의 동작 방식이 아닙니다. 그러므로 NAT를 거는 것은 언제나 필수가 아닌 선택사양입니다. 보통 NAT를 걸었던 링크는 패킷을 어떻게 변경했는지를 기억할겁니다. 그리고나서 응답 패킷이 다른 길을 통해 그 링크를 통과할 때 패킷을 역으로 변경하여 원복할겁니다. 그렇게되면 모든게 문제없이 돌아가겠죠?

2.2 NAT가 필요한 이유는 무엇입니까?

당신이 완벽한 세상을 산다면 그럴 필요가 없겠죠. 하지만 그렇지 않고 주로 다음과 같은 이유가 있기에 사용됩니다:

모뎀으로 인터넷에 연결하기

대부분의 ISP들은 dial-up 접속을 할 때 단 한개의 IP 주소만을 부여합니다. 패킷을 외부 네트워크로 전송할 때 아무 발신지 주소를 달아서 내보낼 수 있지만 부여받은 IP주소를 발신지로 달아 보냈을 때만 그에 대한 응답이 돌아옵니다. 여러 대의 컴퓨터 머신들이(예를 들어 홈 네트워크) 모두 이 하나의 링크를 통해서 인터넷과 연결되길 원한다면 그 때 NAT가 필요합니다.

이것이 가장 보편적인 사용 이유입니다. 보통 리눅스 세계에서는 이를 매스커레이딩(masquerading)라 하지만 저는 이를 SNAT라고 부르겠습니다. 그 이유는 첫 패킷의 발신지(source) 주소를 바꾸기 때문입니다.

여러대의 서버 운영하기

종종 외부에서 내부 네트워크로 들어오는 패킷들의 수신지를 바꿀 필요가 있습니다. 보통 사용자들이 단 한개의 IP 주소만(위에서 설명된 바와 같이) 할당받아 사용하기 때문입니다. 그러한 환경에서도 부여 받은 단 하나의 실제 IP주소를 가지고 외부에서 내부에 존재하는 여러대의 컴퓨터 박스로 접속되게 하고 싶다는 생각이 들 때가 있습니다. 이 경우 들어오는 패킷의 수신지 주소를 다시 쓰는 방법으로 이 문제를 해결할 수 있습니다. 이러한 형태의 NAT를 전 버젼의 리눅스에서는 포트 포워딩(port forwarding)이라고 불렀습니다.

실제 IP주소 하나를 여러대의 컴퓨터 머신들과 매핑하여 패킷들을 여러대의 머신들로 분산시키는 것은 일반적으로 사용되는 부하 분산 방식 중 하나입니다. 큰 규모의 부하 분산을 원한다면 아래를 참조하세요.

리눅스 가상 서버.

투명 프록시 기능(Transparent Proxying)

종종 투명 프록시를 만들고 싶어 리눅스 박스를 통과하는 패킷들을 박스 내부에 동작중인 프로그램으로 향하는 것처럼 방향을 조작하고 싶을 때가 있습니다. 프록시란 내부 네트워크와 외부 네트워크사이에 존재하며 그 둘 사이의 통신을 재조정하는 프로그램을 말합니다. 투명하다는 말이 붙은 이유는 프록시가 동작함에도 불구하고 내부 네트워크가 (실제로는) 프록시와 통신하는 것을 전혀 알지 못하기 때문입니다.

Squid가 이 방식으로 작동되도록 설정 가능합니다. 전 리눅스 버젼에서는 방향 변경(redirection) 혹은 투명 프록시 기능 이라고 불렀습니다.

3. NAT의 두가지 형태

제 경우 NAT를 두가지 형태로 분류했습니다. 하나는 발신지 NAT(SNAT)이고 다른 하나는 수신지 NAT(DNAT)입니다.

발신지 NAT는 첫 패킷의 발신지 주소를 바꾸는 경우를 말합니다. 즉 접속을 시작하는 지점의 주소를 바꾸는 것입니다. 발신지 NAT는 라우팅 후(post-routing)에, 즉 통신선을 타고 밖으로 나가기 직전의 패킷에 대해 이루어집니다. 매스커레이딩은 SNAT의 특별한 형태중 하나입니다.

수신지 NAT는 첫 패킷의 수신지 주소를 전환하는 경우를 말합니다. 즉 패킷의 접속 목적지의 주소를 바꾸는 것입니다. 수신지 NAT는 언제나 라우팅 전에(즉, 패킷이 통신선에서 방금 들어온 시점) 이루어집니다. 포트 포워딩, 부하 분산, 투명 프록시 기능들은 모두 DNAT 방식으로 구현됩니다.

4. 2.0과 2.2 커널에서 현재 방식으로 간단하게 전환하기

2.0(ipfwadm)에서 2.2(ipchains)으로 전환하느라 고생한 분께 미안하군요. 좋은 소식과 나쁜 소식 둘다 있습니다.

좋은 소식부터 말하면 2.4 버젼에서 전과 마찬가지로 ipchains와 ipfwadm를 간단히 사용할 수 있습니다. 예전 것을 사용하고 싶으면 최신 배포반에 있는 `ipchains.o' 이나 `ipfwadm.o' 커널 모듈을 insmod로 올려야 합니다. 한가지 주의할 점은(전에도 말씀드렸지만) 이들은 상호 배타적이어서 신구 버젼을 동시에 사용할 수 없습니다.

이들 신구 버젼중 하나가 인스톨되면 보통때처럼 ipchains나 ipfwadm을 사용할 수 있습니다. 단 차이점은 다음과 같습니다:

  • ipchains -M -S 나 ipfwadm -M -s를 이용하여 매스커레이딩 종료시간을 세팅해도 효과없습니다. 종료시간이 새로운 NAT 인프라보다 길기 때문에 아무 의미가 없습니다.
  • 마스커레이드 리스트를 상세(verbose) 조회를 해도 init_seq, delta, previous_delta 필드는 언제나 0 으로 보입니다.
  • 동시에 두 인자 `-Z -L'를 사용하여 카운터를 0으로 만들고 관련 리스트를 보여주는 기능은 더이상 동작하지 않습니다: 이젠 카운터가 0이 안됩니다.
  • 구버젼 호환용으로 사용되는 방화벽은 scalable하지 않아서 대규모 접속이 이루어지는 네트워크에 사용되기 힘듭니다. 회사 게이트웨이(gateway)같은 곳에는 사용치 말기 바랍니다!

해커들이라면 다음의 경우도 알 필요가 있을지 모르겠군요:

  • 이젠 매스커레이딩 기능이 사용중이어도 포트 61000-65095번을 바인드(bind)할 수 있게 되었습니다. 예전에는 매스커레이딩 코드가 이 범위 내의 포트가 사용중이라고 가정하여 프로그램들이 이 포트를 사용 못했습니다.
  • 이젠 정식 사용법으로 문서화되지 않은 `getsockname' 의 편법적인 사용(해킹)이 더 이상 통하지 않습니다. 접속한 연결의 실제 수신지를 알아내는 투명 프록시 프로그램이 더 이상 그 방법으로 동작하지 않습니다.
  • 외부 주소와 바인드(bind)하는 (정식 사용법이 아닌) 해킹도 이젠 더 이상 작동되지 않습니다. 예전엔 이 방법을 통해 프록시를 완전 투명하게 만들었습니다.

4.1 전 매스커레이딩만 하면 되요! 어쩌죠!

대부분 이게 궁금할 것입니다. 동적으로 IP를 할당받는 PPP dialup을 사용한다면(당신이 그게 무언지 모른다면 바로 당신이 지금 사용하고 있는 그 접속법이다), 내부 네트워크에서 발생한 모든 패킷들이 PPP dialup 박스에서 발생한 것처럼 보이게 하고 싶을겁니다.

# NAT 모듈을 올려라(다른 것들도 따라 올라간다).
modprobe iptable_nat

# NAT 테이블(-t nat)에, 라우팅후(POSTROUTING)  
#ppp0를 통해 나가는 모든 패킷(-o ppp0) 이 
#마스커레이드(-j MASQUERADE)되도록 규칙을 첨가(-A)
iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE

# IP 패킷이 포워딩되도록 설정
echo 1 > /proc/sys/net/ipv4/ip_forward

매스커레이딩을 하는 지점에서는 패킷 필터링을 하지 않는다는 사실을 알고 있어야 합니다. 무슨 말인지 좀더 자세히 알고 싶으면 패킷 필터링 HOWTO에서 ‘NAT와 패킷 필터링 함께 쓰기’ 편를 보세요.

4.2 ipmasqadm의 경우는 어떻게 하죠?

이것은 현재 소수의 특정 사용자만 이용하고 있습니다. 그래서 저는 이 구 버전과 현재의 것의 호환을 별 신경쓰지 않고 있습니다. 포트 포워딩을 하기 위해서라면 간단히 `iptables -t nat' 를 사용하면 됩니다. 예를 들어 리눅스 2.2에서 아래 방법으로 구현하였다면:

# 리눅스 2.2
# 1.2.3.4 의 포트 8080으로 오는 패킷을 192.168.1.1의 포트 80으로 바꿔 전송
ipmasqadm portfw -a -P tcp -L 1.2.3.4 8080 -R 192.168.1.1 80

현재 버전에서는 다음처럼 하면 됩니다:

# 리눅스 2.4
# 라우팅 전에(-A PREROUTING)  1.2.3.4(-d 1.2.3.4) 의 포트 8080(--dport 8080)으로 
# 들어오는 TCP 패킷이(-p tcp)  192.168.1.1의 포트 80(--to 192.168.1.1:80)으로
# 매핑되도록 NAT 테이블에(-t nat)  규칙을 더하라.
iptables -A PREROUTING -t nat -p tcp -d 1.2.3.4 --dport 8080 \
        -j DNAT --to 192.168.1.1:80

5. NAT 대상 패킷 정하기

iptables 툴(매우 다목적을 사용됩니다)을 사용하면 어떤 연결을 변경할지와 그것을 어떤 식으로 변환할지 정하는 NAT 규칙을 만들어 커널에 설정할 수 있습니다. ‘-t nat’ 옵션을 가지고 이 툴을 이용하면 NAT 테이블이 변경됩니다.

NAT 테이블은 ‘chains’라는 세 종류의 리스트로 구성되어 있습니다 : 패킷이 들어오면 일치하는 규칙을 찾을 때까지 순차적으로 하나씩 검사됩니다. 머신 안으로 막 들어온 패킷의 수신지 주소를 변환하는 PREROUTING chain과 머신 밖 나가는 패킷의 발신지 주소를 변환하는 POSTROUTING chain이 있습니다. 세번째 chain으로 OUTPUT이라는 것이 있는데 일단 이건 논외로 합시다.

아래 도식이 그들 관계를 잘 보여줍니다.(제가 그림을 잘 그린다면):

      _____                                     _____
     /     \                                   /     \
   PREROUTING -->[Routing ]----------------->POSTROUTING----->
     \D-NAT/     [Decision]                    \S-NAT/
                     |                            ^
                     |                            |  
                     |                            |
                     |                            |
                     |                            |
                     |                            |
                     |                            |
                     --------> Local Process ------

위 그림에서 보이는 각 지점을 패킷이 통과할 때 그것이 어떤 연결과 관련되어있는지를 조사합니다. 그것이 만약 새로운 연결이라면 그 패킷을 어떻게 처리할지를 결정하는 해당 chain(NAT 테이블에 존재)를 뒤집니다. 그 테이블에서 찾은 답으로 그 연결에 관련되어 앞으로 올 패킷에 적용시킵니다.

5.1 iptables를 이용한 기본 설정

iptables는 아래에 열거될 많은 표준 옵션을 가지고 있습니다. iptables는 다른 옵션들과 구분 가능하다면 이중 dash(-) 옵션들을 모두 약자화(abbreviation)하여 사용할 수 있습니다. 커널이 iptables를 지원한는 모듈을 가지고 있는경우 먼저 ip_tables.o 모듈을 올려야 겠죠. `insmod ip_tables'하면 됩니다.

여기서 가장 중요한 옵션은 테이블을 선택케 하는 `-t' 옵션입니다. NAT 작동을 하려면 언제나 NAT테이블에 `-t nat' 인자를 사용해야 합니다. 그 다음으로 중요한 옵션이 chain 끝에 새로운 규칙을 추가하는 ‘-A’옵션(사용 예 : `-A POSTROUTING') 입니다. chain처음에 넣고 싶다면 ‘-I’옵션을 쓰면 됩니다.(사용 예 : `-I PREROUTING')

패킷이 변환된 후의 발신지와 수신지는 각각 `-s' (혹은 `--source')와 `-d'(혹은 `--destination')로 설정합니다. 그 다음으로 IP 주소 한 개 혹은 도메인 이름이나 네트워크 주소를 써야합니다. 예를 들어 IP주소(한개)는 192.168.1.1 과 같이, 도메인 이름은 www.gnumonks.org 그리고 네트워크 주소의 경우 192.168.1.0/24 혹은 192.168.1.0/255.255.255.0 와 같은 식으로 써넣으면 됩니다.

그리고 규칙 일치 대상으로 패킷이 나가고 들어오는 네트워크 인터페이스를 정할 수 있습니다. 들어오는 경우 `-i' 혹은 `--in-interface' 옵션을 사용하고 나가는 경우 `-o' 혹은 `--out-interface' 옵션을 사용합니다. 그러나 이 옵션은 규칙을 집어넣는 위치에 따라 특정 옵션만 들어갈 수 있습니다. PREROUTING 위치에서는 들어오는 인터페이스만 정할 수 있고 POSTROUTING 위치에서는 나가는 인터페이스만 정할 수 있습니다. 틀리게 설정할 경우 iptables가 에러를 냅니다.

5.2 변환 대상 패킷을 더 정교하게 선정하기

변환 대상이 되는 발신지와 수신지 주소를 설정할 수 있다고 앞서 말씀드렸지만 그 발신지 주소 옵션을 생략한 경우 모든 발신지 주소가 변환됩니다. 변환 대상 수신지 주소 옵션을 생략하면 모든 수신지 주소가 변환되버립니다.

그리고 `-p' 혹은 `--protocol'을 사용하여 변환의 대상이 되는 프로토콜을 선정할 수 있습니다. 옵션 인자로 TCP, UDP등을 줄 수 있죠. 이 프로토콜에 해당하는 패킷들만 규칙에 걸립니다. 보통 이 옵션은 그 다음에 추가적으로 따라붙는 발신지/수신지 포트 옵션을 정하기 위해 사용됩니다. 발신지 포트는 `--source-port'로 설정하고 수신지 포트 옵션은 `--destination-port'로 정합니다. 약자로 `--sport' 와 `--dport'이 사용됩니다.

이 옵션을 사용하면 해당 발신지/수신지 포트만 규칙에 걸리죠. 이 설정은 주로 다른 패킷들은 그대로 두고 웹 연결 요청(TCP 포트 80 혹은 8080) 패킷만 자신이 원하는 방향으로 변경되도록 하는 설정을 위해 사용됩니다.

이 옵션 다음에 반드시 ‘-p’ 옵션을 써야합니다.(이 옵션을 쓰면 관련 프로토콜을 위한 확장용 공유 라이브러리가 따라서 올라갑니다) 이 옵션 다음에 포트 번호나 서비스 이름(/etc/services 파일에 존재하는)을 인자로 넣을 수 있습니다.

변환 대상 패킷을 선정을 더 정교하게 하는 다른 방법들은 매뉴얼 페이지(man iptables)에 상세히 기술되어 있습니다.

6. 패킷을 변경하는 방법을 배워봅시다

이제까지 변경 대상 패킷의 선정법을 배웠죠. 지금부터는 그 패킷 대상을 어떻게 변경할지를 커널에 설정하는 법을 배워봅니다. 이것까지 배우면 규칙 설정법을 완전히 익히게 된겁니다.

6.1 발신지 NAT

발신지 NAT 즉 연결에서 발신지 주소를 다르게 변경하는 것은 POSTROUTING chain(즉, 패킷이 머신 밖으로 나가기 직전)에서 이루어집니다. 여기서 변경된다는 사실은 결국 리눅스 박스 그 자체(라우팅, 패킷 필터링을 하는 콤포넌트)는 패킷이 변경되기 전의 것만 본다는 것(매우 중요한 사실입니다)을 뜻합니다. 그리고 이것은 또한 `-o' (패킷을 밖으로 내보내는 인터페이스) 옵션을 사용할 수 있음을 뜻합니다.

`-j SNAT' 옵션을 통해 발신지 주소를 변환시킨다는 것을 지정하고 `--to-source'옵션을 통해 변경될 IP 주소, IP 주소의 범위 그리고 포트 번호나 포트 범위(선택사양임. UDP, TCP 프로토콜만 가능)를 지정합니다.

## 발신지 주소를 1.2.3.4 로 변경하기
# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 1.2.3.4

##발신지 주소를 1.2.3.4, 1.2.3.5 혹은 1.2.3.6 중 하나로 변경하기
# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 1.2.3.4-1.2.3.6

## 발신지 주소를 1.2.3.4이고 포트 범위가 1-1023인 상태로 변경하기
# iptables -t nat -A POSTROUTING -p tcp -o eth0 -j SNAT --to 1.2.3.4:1-1023

매스커레이딩

발신지 NAT의 특수한 케이스중 하나로 매스커레이딩이라는 것이 존재합니다. 이것은 표준 dialup과 같이 동적으로 IP 주소에 할당받는 경우만 사용가능합니다.(정적으로 IP 주소를 할당받는 경우 위의 SNAT를 사용하세요)

매스커레이딩 설정시에 변경될 발신지 주소를 명시적으로 적을 필요없습니다. 매스커레이딩은 자동으로 패킷이 밖으로 나갈때 밖으로 내보내는 인터페이스의 발신지 주소로 바꾸어 나가도록 합니다. 발신지 주소를 적을 필요가 없는 더 큰 이유는 링크가 다운되어 연결이 끊겼다가 새로운 IP 주소를 할당받아 연결이 재개되어도 장애가 크게 발생하지 않는다는 점입니다.

## ppp0로 나가는 모든 패킷을 마스커레이드하라.
# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE

6.2 수신지 NAT

이건 PREROUTING chain에서 즉 패킷이 들어온 직후에 이루어지죠. 그러므로 그 리눅스 박스 자체(라우팅, 패킷 필터링 콤포넌트)는 패킷이 실제(즉 변경 후의) 수신지를 보게되죠. 이 때문에 `-i' (패킷을 받아들이는 인터페이스)옵션을 사용할 수 있죠.

수신지 NAT는 `-j DNAT'을 사용하여 지정됩니다. IP주소(한 개), IP 주소 범위, 그리고 선택사양으로 들어갈 수 있는 포트 범위(TCP, UDP프로토콜만)는 `--to-destination' 옵션을 사용하여 지정됩니다.

## 수신지 주소를 5.6.7.8로 변경한다.
# iptables -t nat -A PREROUTING -i eth0 -j DNAT --to 5.6.7.8

## 수신지 주소를 5.6.7.8., 5.6.7.9, 5.6.7.10으로 변경한다.
# iptables -t nat -A PREROUTING -i eth0 -j DNAT --to 5.6.7.8-5.6.7.10

## 웹 트래픽의 수신지 주소를 5.6.7.8, 포트 8080으로 변경한다.
# iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth0 \
        -j DNAT --to 5.6.7.8:8080

방향 변경(redirection)

방향 변경은 수신지 NAT의 특수한 형태중 하나입니다. 그 설정을 사용하면 간편하게 안으로 들어온 패킷을 그것을 받아들인 인터페이스 주소로 DNAT시킵니다.

## 들어오는 포트-80 웹 트래픽을 suid(투명) 프록시로 보낸다
# iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 80 \
        -j REDIRECT --to-port 3128

이 때 주의할 점은 squid를 투명 프록시로 설정해야한다는 것입니다!

6.3 고급 매핑 설정

대부분의 사용자가 신경쓰지 않는 난해한 NAT 설정이 존재합니다. 궁금하신 분들을 위해 여기에 적어놓았습니다.

일정 범위를 가진 다수의 주소로 선정한 경우

IP주소가 일정 범위를 가진 다수로 주어지면 변환용으로 사용될 IP주소는 주어진 범위내의 IP주소중 현재 연결 수가 가장 적은 IP로 선정됩니다. 이를 통해 초보적인 부하 분산 기능을 제공합니다.

널(Null) NAT 매핑 만들기

`-j ACCEPT' 을 target으로 잡으면 연결이 맺어질 때 변환없이 그대로 통과합니다.

표준적인 NAT 행동양식

가능하면 기본적으로 사용자가 정한 규칙 한도내에서 연결 패킷이 최소한만 전환되도록합니다. 이러한 행동양식에 따라 꼭 필요한 경우가 아니라면 포트를 변환시키지 않습니다.

암묵적으로 이루어지는 발신지 포트 매핑

NAT가 필요없이 연결이 맺어질 때에도 발신지 포트 변환이 암묵적으로 이루어질 수 있습니다. 이미 성립된 다른 연결의 매핑이 이번에 새로 만들어질 것과 중첩된 케이스가 바로 그런 경우입니다. 흔히 매스커레이딩이 사용될 때 발생합니다:

  1. 192.1.1.1 박스에서 포트 1024를 달고 www.netscape.com의 포트 80으로 웹 연결을 맺으려 합니다.
  2. 이 발신지 주소는 IP 주소(1.2.3.4)를 할당받아 사용하는 매스커레이딩 박스에 의해 그 IP주소로 머스커레이드됩니다.
  3. 그 후 매스커레이딩 박스 자체가 자신의 외부용 인터페이스 주소 1.2.3.4를 발신지로 하여 포트 1024를 달고 www.netscape.com 의 포트 80으로 웹 연결을 맺으려 합니다.
  4. NAT 코드는 두번째로 맺어지는 연결의 발신 포트를 1025로 전환합니다. 그렇기 때문에 두 연결은 충돌이 나지 않습니다.

이러한 암묵적인 발신 매핑이 발생할 때 포트는 세 부류로 나뉘어지게 됩니다:

  • 512 아래의 포트
  • 512와 1023 사이의 포트
  • 포트 1024 이상.

포트가 변환될 때 암묵적으로 다른 부류로는 매핑되지 않습니다.

NAT가 실패하면 어떻게 되나

사용자가 맺고자 하는 연결에 대해 고유 매핑을 만들 수 없는 경우 이 패킷을 파기합니다. 이 외에 패킷이 네트워크 연결의 일환이라고 볼수 없는 기형적인 상태의 경우 혹은 박스의 메모리가 고갈된 상태 및 기타 등등의 상황에서 그 패킷은 파기됩니다.

다중 매핑, 중첩 및 충돌

NAT규칙들을 정할 때 패킷들을 동일 범위로 매핑되도록 중첩해서 정하는 경우가 있습니다. NAT코드는 이러한 경우에도 충돌이 발생하지 않도록 잘 만들어져 있습니다. 그래서 두 개의 규칙이 존재하고 각각의 발신지 주소가 192.168.1.1과 192.168.1.2이고 이것이 둘다 1.2.3.4로 변환되도록 설정해도 문제없이 작동합니다.

게다가 실제 사용되는 다수의 IP주소들을(그 주소들이 박스를 통과해주기만 한다면) 매핑할 수 있습니다. 그래서 만약 실제 네트워크가 1.2.3.0/24 로 되어 있고 이 주소를 사용하는 내부 네트워크가 존재하며 그 내부 사설 인터넷 주소가 192.168.1.0/24라고 가정한다면 아무 충돌없이 간단히 발신지 주소 192.168.1.0/24 를 1.2.3.0 네트워크로 NAT할 수 있습니다:

# iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 \
        -j SNAT --to 1.2.3.0/24

같은 원리가 NAT 박스 자체에도 사용됩니다. 바로 마스커레딩에 적용되는 논리입니다.(그 원리를 통해 마스커레이드되는 패킷과 박스 자체가 만들어낸 실제 패킷이 하나의 인터페이스 주소를 공유합니다)

동일한 종류의 패킷들을 변환 목표가 여러 개인 상태로 매핑하는 것 또한 가능합니다. 이들 변환 목표가 되는 주소들이 모두 함께 사용됩니다. 예를 들어 1.2.3.5로만 매핑하고 싶지 않다면 다음과 같이 설정할 수 있습니다:

# iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 \
        -j SNAT --to 1.2.3.0-1.2.3.4 --to 1.2.3.6-1.2.3.254

머신 내부에서 발생시킨 연결의 수신지를 변환하기

OUTPUT chain에서도 DNAT 규칙을 넣을 수 있습니다. 그러나 2.4에서는 완벽히 지원되는 기능이 아닙니다.(제대로 되게 할 순 있습니다. 그러나 그렇게 하려면 새로운 설정 옵션들이 만들어져야 하고 많은 테스트와 상당 분량의 코딩이 필요합니다. 만약 누군가 Rusty에게 그것을 만들겠노라고 약속하지 않는 이상 쉽게 개발되진 않을 것입니다)

현재는 수신지를 다른 머신이 아닌 자체 머신의 주소로만 변환할 수 있습니다. 예를 들어 `j DNAT --to 127.0.0.1'라고 설정할 수 있습니다. 그렇지 않으면 그 응답 패킷이 올바르게 변환되지 않을 것입니다.

7. 특수한 프로토콜들

일부 프로토콜들은 NAT를 걸기 마땅치 않다. 올바른 동작을 위해 각 프로토콜에 대해 두가지 확장 프로그램이 개발되어야한다. 하나는 그 프로토콜의 연결을 추적하는 코드이고 나머지 하나는 그 프로토콜용 NAT코드가 필요하다.

넷필터 배포판에는 현재 FTP를 위한 모듈은 들어있다. 모듈 이름은 각각 ip_conntrack_ftp.o 와 ip_nat_ftp.o이다. 커널에 이들을 insmod로 삽입하거나 영구적으로 컴파일하여 포함시킬 경우 FTP에 대한 모든 종류의 NAT가 올바르게 작동된다. 그것이 없으면 passive FTP만 가능하다. 심지어 이조차 단순한 발신지 NAT만 되고 그 이상으로 복잡하게 동작시켜려 하면 오작동이 날 수 있다.

8. NAT사용시 주의 사항

어떤 연결에 대해 NAT를 걸고자 한다면 그 연결 패킷들 양방향(네트워크 외부로 나가는것과 내부로 들어오는 것) 모두 NAT가 걸리는 박스를 통과하도록 해야 한다. 그렇지 않으면 올바른 작동을 보장할 수 없다. 특히나 잘못된 경우 단편화된 IP 패킷들을 재조립하여 연결을 추적하는 코드가 추적을 제대로 못하게 될 뿐 아니라 단편화된 패킷들이 박스 내부에 잡혀있게 되어 사용자가 그 패킷들을 받지 못하게 된다.

9. 발신지 NAT와 라우팅

SNAT가 올바로 작동되게 하기 위해선 SNAT가 걸린 패킷이 경유하는 모든 컴퓨터 머신들은 해당 응답 패킷의 종착지가 그 NAT 박스임을 알고 있도록 설정해야 한다. 예를 들어, 머신 밖으로 나가는 패킷들이 1.2.3.4라는 발신지 주소를 달고 나가도록 매핑을 한 경우 외부의 라우터들은 그 응답 패킷(수신지 주소가 1.2.3.4로 잡혀있는)의 종착지가 이 박스임을 알도록 설정을 잡아줘야 한다. 이것들은 다음과 같은 방법으로 구현된다:

  1. 박스 자체에 할당된 주소(그 주소에 대해서는 라우팅을 비롯한 모든 것이 작동되도록 이미 설정되어 있다)를 가지고 SNAT를 하면 조치를 취할 것이 없다.
  2. NAT박스가 속한 지역 LAN주소중 사용되지 않고 있는 것을 가지고 SNAT를 할 경우가 있다. 예를 들어, 어떤 NAT 박스가 1.2.3.0/24라는 네트워크에 존재하는데1.2.3.99라는 사용되지 않는 IP(그 네트워크에 속하긴 하지만)를 달고 나가도록 매핑할 수 있다. 그러한 경우 그 매핑 주소에 대해서도 자기 자신에 할당된 IP주소와 마찬가지로ARP 요구에 대해 응답토록 해야 한다. 가장 간편한 방법은 아래와 같이 IP 앨리어스(alias)를 주는 것이다:
    # ip address add 1.2.3.99 dev eth0
    
  3. 자신의 네트워크와 완전히 다른 주소로 SNAT되게 하려면 이 SNAT된 패킷이 전송되며 경유하는 각 머신들이 해당 응답 패킷에 대해 다시 NAT 박스로 되돌아오게 할 수 있도록 경로 설정을 잡아주어야 한다. NAT 박스가 이미 그 경유 머신들의 기본 게이트웨이로 잡혀 있다면 달리 할 일은 없다. 그렇지 않은 경우 그 주소에 대한 라우트를 광고하거나(라우팅 프로토콜을 사용중이라면) 아니면 수동적으로 관련된 머신들에 해당 주소에 대한 라우트를 추가해주어야 한다.

10. 같은 네트워크안에서 수신지 NAT

동일 네트워크에서 발생한 패킷이 올바르게 포트 포워팅되어 다시 내부로 되돌아가게 해야할 경우 먼저 그 다음에 올 패킷들도(응답 패킷 포함) 계속 그 NAT 박스(그래야 그 패킷들의 주소가 전환된다)를 통과하도록 설정해야 한다. 현재 NAT 코드(2.4.0-test6과 그 이후 버전)는 NAT된 패킷이 자신을 받아들인 인터페이스를 향해 다시 나가도록 할 때 발생하는 ICMP redirect 에러 메시지를 차단한다. 그러나 이 패킷을 수신한 서버는 여전히 클라이언트에게 직접 응답하려고(클라이언트는 이것을 올바른 응답 패킷으로 인식하지 않는다) 할 것이다.

그 전형적인 케이스가 내부 직원들이 내부 웹서버의 공인 IP주소로 접속하려할 경우이다. DNAT에 의해 공인 주소(1.2.3.4)에서 내부 머신(192.168.1.1)으로 변환된다. 아래는 그 예이다:

# iptables -t nat -A PREROUTING -d 1.2.3.4 \
        -p tcp --dport 80 -j DNAT --to 192.168.1.1

해결 방안 중 하나는 내부 네트워크에는 공식 웹 사이트의 실제(내부) IP 주소를 알고 있는 내부용 DNS서버를 운영하고 그 외 지역의 DNS 요청은 외부용 DNS서버가 답하도록 하면 된다. 이렇게 되면 내부자들에게는 웹서버의 주소가 내부 IP주소가 보이게 된다.

또 다른 해결 방법이 있는데 NAT박스가 그러한 종류의 연결에 대해서는 발신지 IP 주소를 자기 자신의 내부 주소로 매핑하면 된다. 그리되면 서버가 그 박스를 발신지로 알고 박스에게 해당 응답 패킷을 날린다. 예를 들어 다음과 같은 설정을 할 수 있다(NAT박스의 내부 IP 주소가 192.168.1.250이라고 가정하자):

# iptables -t nat -A POSTROUTING -d 192.168.1.1 -s 192.168.1.0/24 \
        -p tcp --dport 80 -j SNAT --to 192.168.1.250

PREROUTING 규칙을 먼저 타기 때문에 패킷의 목적지는 이미 내부 웹서버 주소로 바뀐 상태이다: 패킷들이 그러한 변환 대상인지 여부는 그 발신지 IP주소를 보고 출처가 내부라는 사실 여부로 구분된다.

11. 감사의 글

먼저 WatchGuard와 David Bonn에게 감사드립니다. 이들은 작업중 넷필터에 대해 좋은 아이디어를 내어 많은 도움을 줬습니다.

그리고 제가 NAT에 있는 불미스러운 문제점을 발견하여 성질을 내어도 이것을 참고 넘어가준 모든 분들과 -특히- 제 다이어리를 읽어준 분들께도 감사의 말씀을 드립니다.

Rusty.

역자 후기 : 원번역자인 김상훈님에게 미리 변경사실을 말씀드리고 싶었지만 연락처가 없어서
어쩔 수없이 통보안하고 덮어 썼습니다. 완전히 덮어쓰게된 명분중 하나는 김상훈님은 v1.0 NAT HOWTO를 번역하셨지만
전 그 개정판인 v1.18을 번역했기 때문입니다. 최대한 어색하지 않으면서도 정확하게 번역하려 했습니다. 오탈자나
 그릇된 번역이 있으면 제게 연락 바랍니다.
---- CategorySoftware

'네트워크' 카테고리의 다른 글

리눅스 - 포트포워딩  (0) 2012.02.10
NAT  (3) 2012.02.10
마스커레이드란? (IP MASQUERADING)  (4) 2012.02.10
Posted by GUCCI
, |

최근에 달린 댓글

글 보관함