5. 네트웍 트래픽 분산의 실제

5.1. 설치해야 할 소프트웨어

네트웍 트래픽 분산 및 IP Masquerading, 그리고 PPP와 관련하여 리눅스 방화벽에 설치해야 할 소프트웨어를 살펴보자. 필자의 리눅스 방화벽에 설치되어 있는 소프트웨어 목록은 아래와 같다.

  1. iproute-20001007

  2. iptables-1.2.4

  3. ppp-2.4.1

  4. pppoe-3.2

iproute는 iproute2 라는 이름의 소프트웨어이며 데비안에서는 iproute 라는 이름의 패키지로 배포하고 있다. 이 소프트웨어는 기존의 route 명령을 대체하는 명령어(ip)를 포함하고 있으며 네트웍 대역폭을 조절하는 명령어(tc)도 포함되어 있다.

iptables는 커널 2.2에서 제공하던 ipchains를 대체하는 명령어로 ipchains보다 많은 기능을 제공한다.

5.2. 트래픽 분산의 순서

본론에 들어가기 전에 네트웍 트래픽을 분산시키기 위해서 밟아야 할 순서를 짚어보자.

먼저 트래픽 분산 정책을 결정해야 할 것이다. 즉, a 종류의 패킷은 1번 문으로 내보내고, b 종류의 패킷은 2번 문으로 내보낸다는 식의 정책을 결정해야 할 것이다. 이러한 정책을 결정하기 위해서는 고려해야 할 것이 몇가지 있을 것이다. 예를 들면, 끊김이 없어야 하는 패킷은 전용선 쪽으로 내보내고, 그렇지 않은 패킷은 ADSL 쪽으로 내보낸다는 식이다. 그리고 전체적인 네트웍 트래픽의 양도 감안해야 할 것이다.

그 다음, 결정된 정책에 따라서 ip 명령으로 라우팅 룰을 설정하고, 라우팅 테이블을 만들어야 한다. 그리고 내보낼 패킷과 내보내지 않을 패킷, 들어와서는 안되는 패킷 등을 구분하여 필터링을 할 예정이라면 iptables 명령으로 패킷을 어떻게 걸러낼 것인지 설정한다. 그리고 iptables 명령으로 Masquerading 설정을 한다. 아래에 그 순서를 간단하게 정리하였다.

  1. 네트웍 트래픽 분산 정책을 결정한다.

  2. 분산 정책에 따라서 라우팅 룰을 설정한다.

  3. 분산 정책에 해당하는 라우팅 테이블을 설정한다.

  4. iptables 명령으로 필터링 룰을 설정한다.

  5. iptables 명령으로 Masquerading을 설정한다.

5.3. 호스트 또는 네트웍 기반의 트래픽 분산

3절에서 설명한 네트웍 환경을 기준으로 하여, 네트웍 트래픽을 서브네트웍 별로 분산시키는 상황을 가정한다. 아래는 리눅스 방화벽에 설정되어 있는 라우팅 테이블을 route 명령과 ip 명령으로 본 결과이다. 그리고 그 뒤에 라우팅 룰과 main 라우팅 테이블도 표시 하였다.

# netstat -rn
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
200.200.200.1   0.0.0.0         255.255.255.255 UH       40 0          0 ppp0
100.100.100.0   0.0.0.0         255.255.255.    U        40 0          0 eth0
192.168.1.0     0.0.0.0         255.255.255.0   U        40 0          0 eth1
0.0.0.0         100.100.100.1  0.0.0.0         UG       40 0          0 eth0

# ip route ls
200.200.200.1  dev ppp0  proto kernel  scope link  src 200.200.200.2
100.100.100.0/24 dev eth0  proto kernel  scope link  src 100.100.100.2
192.168.1.0/24 dev eth1  proto kernel  scope link  src 192.168.1.254
default via 100.100.100.1 dev eth0

# ip rule ls
0:      from all lookup local
32766:  from all lookup main
32767:  from all lookup default

# ip route ls table main
200.200.200.1 dev ppp0  proto kernel  scope link  src 200.200.200.2
100.100.100.0/24 dev eth0  proto kernel  scope link  src 100.100.100.2
192.168.1.0/24 dev eth1  proto kernel  scope link  src 192.168.1.254
default via 100.100.100.1 dev eth0

ip rule ls 명령의 결과를 보면 기본적으로 세개의 라우팅 테이블 local, main 그리고 default가 있음을 알 수 있다. 각 라우팅 테이블의 자세한 내용은 ip route ls table local과 같은 명령으로 알 수 있다. 여러분 각자 확인해 보기 바란다. 위에서 보다시피 각 라우팅 테이블 에는 번호가 붙어 있으며 리눅스 커널은 낮은 번호 순서대로 패킷을 처리한다. 즉 패킷이 네트웍을 통해서 들어오면 커널은 그 패킷이 어디로 향하는지 확인하고서는 어떻게 라우팅할 지 local 테이블에서 먼저 찾아본다. local 테이블에 적당한 처리 규정이 없으면 main 테이블을 찾아보고 거기에도 없으면 마지막으로 default 테이블을 찾아보는 것이다.

from all이 의미하는 바는 패킷이 어디에서 온 것인지를 정의하는 것이다. all 이므로 어디에서 온 것이든 상관없다는 의미이다. from allfrom 192.168.1.100으로 바꾸면 192.168.1.100 에서 출발한 패킷을 의미하게 된다. 즉 출발지에 따라서 라우팅을 결정할 수 있는 것이다. 이를 두고 Source Routing이라 한다.

ip route ls table main 명령의 실행 결과를 살펴보면, main 테이블에 ppp0에 대한 라우팅이 설정되어 있고, E1 전용선에 대한 라우팅이 default로서 설정되어 있음을 알 수 있다. netstat -rn 명령의 결과와 같음을 알 수 있다. 즉, netstat -rn 명령은 main 테이블을 표시한 것이다.

이제 5.2절트래픽 분산의 순서에서 설명한 대로 하나씩 해보자.

네트웍 트래픽의 분산 정책 결정

  1. Net-A와 Net-B로부터 인터넷으로 향하는 패킷은 E1 전용선을 통하여 나간다.

  2. Net-C로부터 인터넷으로 향하는 패킷은 ADSL(ppp0)을 통하여 나간다.

라우팅 룰의 설정

  1. /etc/iproute2/rt_tables에 적당한 라우팅 테이블 이름을 넣어 준다. 라우팅 테이블 이름을 e1line, adslline 이라고 하자.
    # echo 201 e1line >> /etc/iproute2/rt_tables
    # echo 202 adslline >> /etc/iproute2/rt_tables

  2. 분산 정책에 따라서 라우팅 룰을 추가한다.
    # ip rule add from 192.168.1.0/24 table e1line
    # ip rule add from 192.168.2.0/24 table e1line
    # ip rule add from 192.168.3.0/24 table adslline

라우팅 테이블의 설정

e1line과 adslline 라우팅 테이블을 만든다.
# ip route add default via 100.100.100.1 dev eth0 table e1line
# ip route add default via 200.200.200.1 dev ppp0 table adslline

여기서 잠깐

필터링 룰을 설정하기 전에 설정된 라우팅 룰을 살펴보고 고려해야 할 사항을 알아보자.
# ip rule ls
0:      from all lookup local
32763:  from 192.168.3.0/24 lookup adslline
32764:  from 192.168.2.0/24 lookup e1line
32765:  from 192.168.1.0/24 lookup e1line
32766:  from all lookup main
32767:  from all lookup default
라우팅 룰의 번호 및 순서를 살펴보면 위에서 실행시킨 ip rule add 명령의 순서와 역순임을 알 수 있을 것이다. 염두에 두기 바란다. 이제 예를 들면서 고려해야 할 사항을 알아보자.

192.168.1.10에서 111.111.111.100 으로 향하는 패킷을 생각해 보자. 그 패킷이 리눅스 방화벽에 들어가면 리눅스 커널은 0번 라우팅 룰부터 대조하여 어떻게 라우팅 할 것인지 결정할 것이다. 0번 라우팅 룰은 그 패킷이 어디에서 출발 한 것인지 상관없이 (from all) local 라우팅 테이블을 참조하도록 되어 있다. 그러나 local 테이블을 살펴보면 알겠지만 거기에는 111.111.111.100으로 향하는 패킷에 대하여 마땅히 처리할 라우팅 규칙이 없다. 그 다음 라우팅 룰(32763번)은 192.168.3.0네트웍으로부터 출발하는 패킷에 대한 것이므로 해당 사항이 없다. 32764번 룰도 비슷하다. 32765번 룰은 192.168.1.0 네트웍으로부터 출발하는 패킷에 대하여 적용 가능하다. e1line 라우팅 테이블을 살펴보자.
# ip route ls table e1line
default via 100.100.100.1 dev eth0
패킷이 어디로 향하든지 상관없이(default) 100.100.100.1 을 거쳐서 패킷을 라우팅 하도록 설정되어 있음을 알 수 있다. 따라서 192.168.1.10에서 111.111.111.100 으로 향하는 패킷은 32765번 룰을 적용할 수 있는 것이다. 그런데 이 절의 앞부분을 다시 읽어보면 알겠지만, e1line 테이블에 있는 라우팅 규칙과 똑같은 것이 main 테이블에도 있다. 다시 생각해 보면 192.168.1.0네트웍으로부터 출발하는 패킷의 라우팅은 main 테이블에서 처리할 수 있다는 것이다. 즉, e1line 테이블을 굳이 추가 할 필요가 없다는 것이다.

또 다른 경우를 살펴보자. 192.168.3.10에서 웹서버인 100.100.100.10 으로 향하는 패킷을 생각해 보자. 앞에서 살펴본 과정과 비슷하게 따라가 보면 이 패킷은 ADSL을 통해서 빠져 나간 후 인터넷을 거쳐서 웹서버로 들어옴을 알 수 있다. eth0를 통해서 빠져 나가면 바로 갈 수 있는 길을 크게 돌아서 온 것이다. 따라서 이에 대한 보완도 필요함을 알 수 있다. ADSL도 비슷한 상황을 가정할 수 있으나 여기서는 굳이 고려하지 않겠다. 왜냐하면 귀찮으니까.... 그리고 생각해 본 적도 없으므로.... 게다가 별 필요가 없으므로...

한 가지 더 고려해야 할 사항은 리눅스 방화벽에서 192.168.1.0 네트웍으로 나가는 라우팅 규칙은 local 테이블에 명시되어 있지만 192.168.2.0, 192.168.3.0 네트웍으로 나가는 라우팅 규칙은 명시되어 있지 않다. 이를 local 테이블에 추가해 주어야 한다. 왜 local 테이블에 추가하는 지는 생각해 보면 알 수 있을 것이다.

위의 상황을 고려하여 라우팅 룰과 라우팅 테이블을 다시 만들어 보자. 앞에서 /etc/iproute2/rt_tablesecho 문으로 추가했던 두 줄을 지운 후 아래 명령을 실행해야 할 것이다.
# echo 201 adslline >> /etc/iproute2/rt_tables
# ip rule add from 192.168.3.0/24 table adslline
# ip route add default via 200.200.200.1 dev ppp0 table adslline
# ip route add 100.100.100.0/24 via 100.100.100.2 dev eth0 table local
# ip route add 192.168.2.0/24 via 192.168.1.254 dev eth1 table local
# ip route add 192.168.3.0/24 via 192.168.1.254 dev eth1 table local
마지막 두 줄은 192.168.0.0 네트웍에 대한 라우팅 규칙으로 생각해서 한 줄로 표현할 수 있다.
# echo 201 adslline >> /etc/iproute2/rt_tables
# ip rule add from 192.168.3.0/24 table adslline
# ip route add default via 200.200.200.1 dev ppp0 table adslline
# ip route add 100.100.100.0/24 via 100.100.100.2 dev eth0 table local
# ip route add 192.168.0.0/16 via 192.168.1.254 dev eth1 table local

필터링 룰의 설정

필터링 룰을 설정하는 것은 여기서 생략한다.

Masquerading의 설정

전용선 쪽으로 나가는 패킷과 ADSL 쪽으로 나가는 패킷에 대한 Masquerading 설정이 필요할 것이다.
# iptables -t nat -A POSTROUTING -o eth0 -s 192.168.0.0/16 ! -d 192.168.0.0/16 -j SNAT --to 100.100.100.2
# iptables -t nat -A POSTROUTING -o ppp0 -s 192.168.0.0/16 ! -d 192.168.0.0/16 -j MASQUERADE
이것으로 호스트 또는 서브네트웍 별로 네트웍 트래픽을 분산시키는 방법을 알아 보았다. 아래에 명령어를 다시 한 번 정리하였다.
# echo 201 adslline >> /etc/iproute2/rt_tables
# ip rule add from 192.168.3.0/24 table adslline
# ip route add default via 200.200.200.1 dev ppp0 table adslline
# ip route add 100.100.100.0/24 via 100.100.100.2 dev eth0 table local
# ip route add 192.168.0.0/16 via 192.168.1.254 dev eth1 table local
# iptables -t nat -A POSTROUTING -o eth0 -s 192.168.0.0/16 ! -d 192.168.0.0/16 -j SNAT --to 100.100.100.2
# iptables -t nat -A POSTROUTING -o ppp0 -s 192.168.0.0/16 ! -d 192.168.0.0/16 -j MASQUERADE

5.4. port 기반의 트래픽 분산

port를 구분해서 패킷을 내보내는 방법과 호스트 또는 서브네트웍을 구분해서 패킷을 내보내는 방법은 한 가지를 제외하고는 큰 차이가 없다. 기본적으로 커널은 어떤 패킷이 어디로 향하는 지를 보고서 라우팅을 어떻게 할 지를 결정하며, 그 패킷이 www port를 사용하는지, telnet port를 사용하는지 등은 라우팅의 기준이 되지 않는다. 따라서 port를 구분해서 라우팅을 하기 위해서는 또 다른 기준을 만들어 주어야 하며, 그 방법은 특정 port를 사용하는 패킷에 표식을 해서 구분하는 것이다. 패킷에 표식을 하는 것은 iptables 명령을 이용한다.

네트웍 트래픽의 분산 정책 결정

  1. www, ftp, ftp-data port를 사용하는 패킷은 ADSL(ppp0)을 통하여 나간다. 나간다.

  2. 이외의 나머지 패킷은 E1 전용선을 통하여 나간다.

라우팅 룰의 설정

  1. /etc/iproute2/rt_tables에 ADSL을 통해서 나가는 패킷을 위해 adslline 라우팅 테이블 이름을 추가한다.
    # echo 201 adslline >> /etc/iproute2/rt_tables

  2. 분산 정책에 따라서 라우팅 룰을 추가한다.
    # ip rule add fwmark 1 table adslline
    위 명령의 의미는 "1"이라고 표시된 패킷은 adslline 테이블을 참조하여 라우팅한다라는 뜻이다. 트래픽 분산 정책에 따라서 www, ftp, ftp-data port를 사용하는 패킷에 대하여 다음과 같이 "1"이라고 표시하면 되는 것이다.
    # iptables -A PREROUTING -i eth1 -s 192.168.0.0/16 ! -d 192.168.0.0/16 \
    -t mangle -p tcp --dport www -j MARK --set-mark 1
    
    # iptables -A PREROUTING -i eth1 -s 192.168.0.0/16 ! -d 192.168.0.0/16 \
    -t mangle -p tcp --dport ftp -j MARK --set-mark 1
    
    # iptables -A PREROUTING -i eth1 -s 192.168.0.0/16 ! -d 192.168.0.0/16 \
    -t mangle -p tcp --dport ftp-data -j MARK --set-mark 1
    첫번째 명령을 해석해 보면, eth1를 통해서 들어오는 패킷 중에서 출발지가 192.168.0.0/16 네트웍이고 목적지는 192.168.0.0/16이 아니며 www port를 사용하는 패킷에 대하여 "1"이라고 표시한다라는 의미이다.

라우팅 테이블의 설정

adslline 라우팅 테이블을 만들고 local 테이블에 필요한 라우팅 규칙을 추가한다.
# ip route add default via 200.200.200.1 dev ppp0 table adslline
# ip route add 100.100.100.0/24 via 100.100.100.2 dev eth0 table local
# ip route add 192.168.0.0/16 via 192.168.1.254 dev eth1 table local

필터링 룰의 설정

필터링 룰을 설정하는 것은 여기서 생략한다.

Masquerading의 설정

5.3절에서와 마찬가지로 전용선 쪽으로 나가는 패킷과 ADSL 쪽으로 나가는 패킷에 대한 Masquerading 설정이 필요할 것이다.
# iptables -t nat -A POSTROUTING -o eth0 -s 192.168.0.0/16 ! -d 192.168.0.0/16 -j SNAT --to 100.100.100.2
# iptables -t nat -A POSTROUTING -o ppp0 -s 192.168.0.0/16 ! -d 192.168.0.0/16 -j MASQUERADE
명령어를 다시 한 번 정리하면,
# echo 201 adslline >> /etc/iproute2/rt_tables
# ip rule add fwmark 1 table adslline
# iptables -A PREROUTING -i eth1 -s 192.168.0.0/16 ! -d 192.168.0.0/16 \
-t mangle -p tcp --dport www -j MARK --set-mark 1
# iptables -A PREROUTING -i eth1 -s 192.168.0.0/16 ! -d 192.168.0.0/16 \
-t mangle -p tcp --dport ftp -j MARK --set-mark 1
# iptables -A PREROUTING -i eth1 -s 192.168.0.0/16 ! -d 192.168.0.0/16 \
-t mangle -p tcp --dport ftp-data -j MARK --set-mark 1
# ip route add default via 200.200.200.1 dev ppp0 table adslline
# ip route add 100.100.100.0/24 via 100.100.100.2 dev eth0 table local
# ip route add 192.168.0.0/16 via 192.168.1.254 dev eth1 table local
# iptables -t nat -A POSTROUTING -o eth0 -s 192.168.0.0/16 ! -d 192.168.0.0/16 -j SNAT --to 100.100.100.2
# iptables -t nat -A POSTROUTING -o ppp0 -s 192.168.0.0/16 ! -d 192.168.0.0/16 -j MASQUERADE

한가지 더

위와 같이 port 별로 네트웍 트래픽을 분산시키려 할 때 전혀 라우팅이 안되는 경우가 있다. 아마도 대부분의 리눅스 배포본에서 이런 현상이 발생할 것으로 생각된다. 이는 spoof protection을 위해 /proc/sys/net/ipv4/conf/*/rp_filter 파일의 값을 "1"로 설정했기 때문이다. 모든 디바이스에 대하여 rp_filter 파일의 값을 "0"으로 설정하면 문제가 해결될 것이다.