개념
Mininet
네트워크 토폴로지를 하나의 컴퓨터 안에서 가상으로 생성할 수 있는 네트워크 시뮬레이터
- 실제 네트워크 장비 없이도, PC 하나만으로 가상의 호스트(PC), 스위치, 링크 등을 만들어서 실제 네트워크처럼 테스트할 수 있게 해주는 도구
- h1~h8 같은 가상 장치를 만들고, 이 장치들을 SDN 스위치에 연결해서, 네트워크 트래픽을 만들어주는 역할
Ryu
Python으로 만들어진 오픈소스 SDN 컨트롤러 프레임워크로, OpenFlow 같은 프로토콜을 통해 네트워크 장비를 제어한다.
- 네트워크의 두뇌. 예전엔 스위치가 알아서 패킷을 처리했지만, SDN에선 스위치가 먼저 컨트롤러(Ryu)에 물어보고, 그에 따라 동작
- MTD 알고리즘을 실행해서 IP 주소나 포트를 무작위로 바꾸고, 네트워크 흐름을 제어해서 스위치에 명령을 내림
Open vSwitch (OVS)
리눅스에서 돌아가는 가상 스위치 소프트웨어로, SDN 환경에서 OpenFlow 프로토콜을 지원한다.
- 실제 스위치를 쓰지 않고, 소프트웨어로 만든 스위치. 물리적인 네트워크 없이도 SDN 실험을 하기 위한 방안
- 가상 호스트들을 연결해주는 스위치 역할을 하며, Ryu 컨트롤러의 명령에 따라 패킷을 전송하거나 차단
1단계: EC2 인스턴스 생성
Amazon Machine Image (AMI): Ubuntu Server 24.04 LTS (HVM), SSD Volume Type
Instance type: t3.xlarge (4 vCPU, 16 GiB Memory)
SSD (8GiB gp3 Root volume, 3000 IOPS, Not encrypted)
- security group SSH 22 my ip / ICMP All
SSH로 EC2 접속
chmod 400 your-key.pem # 권한 변경
ssh -i "your-key.pem" ubuntu@<EC2 퍼블릭 IPv4 주소>.compute-1.amazonaws.com
2단계: 실험 환경 설치
# 1. 필수 패키지 설치
sudo apt update
sudo apt install -y git python3-pip openvswitch-switch net-tools curl
# 2. Mininet 설치
git clone https://github.com/mininet/mininet
cd mininet
# pip3 install pycodestyle
sudo ./util/install.sh -a # 모든 패키지 설치 옵션, 시간 소요 (3분 내외) -> Enjoy Mininet!
# or
# 핵심 패키지 설치
sudo apt update
sudo apt install -y openvswitch-switch openvswitch-common openvswitch-testcontroller \
python3-pip python3-setuptools net-tools iproute2 curl git tcpdump
# Mininet 실행 스크립트 수동 설치
sudo make install
# Mininet 정상 동작 확인
sudo mn --test pingall
# 결과 예시:
# *** Ping: testing ping reachability
# h1 -> h2 h3 h4 ...
# *** Results: 0% dropped (28/28 received)
$ sudo mn --test pingall
*** Creating network
*** Adding controller
*** Adding hosts:
h1 h2
*** Adding switches:
s1
*** Adding links:
(h1, s1) (h2, s1)
*** Configuring hosts
h1 h2
*** Starting controller
c0
*** Starting 1 switches
s1 ...
*** Waiting for switches to connect
s1
*** Ping: testing ping reachability
h1 -> h2
h2 -> h1
*** Results: 0% dropped (2/2 received)
*** Stopping 1 controllers
c0
*** Stopping 2 links
..
*** Stopping 1 switches
s1
*** Stopping 2 hosts
h1 h2
*** Done
completed in 5.329 seconds
# 3. Ryu 설치
pip3 install ryu
# 4. 설치 확인
mn --version # Mininet 버전 출력
# 2.3.1b4
ryu-manager --version # Ryu 버전 출력
3단계: 네트워크 토폴로지 구성 (Mininet)
가상 호스트 및 스위치 생성
sudo mn --controller=remote --topo=tree,depth=2,fanout=2 --switch ovsk,protocols=OpenFlow13
depth = 2 (루트 스위치 + 중간 스위치)
fanout = 4 (각 중간 스위치에 4개 호스트 연결) - 16개 호스트 생성됨
1명의 컨트롤러와 2단계 트리 구조의 스위치-호스트 네트워크를 자동으로 생성
총 8개 호스트(h1h8), 3개 스위치(s1s3) 생성
Ryu 컨트롤러는 외부에서 연결됨
$ sudo mn --controller=remote --topo=tree,depth=2,fanout=2 --switch ovsk,protocols=OpenFlow13
*** Creating network
*** Adding controller
Unable to contact the remote controller at 127.0.0.1:6653
Unable to contact the remote controller at 127.0.0.1:6633
Setting remote controller to 127.0.0.1:6653
*** Adding hosts:
h1 h2 h3 h4
*** Adding switches:
s1 s2 s3
*** Adding links:
(s1, s2) (s1, s3) (s2, h1) (s2, h2) (s3, h3) (s3, h4)
*** Configuring hosts
h1 h2 h3 h4
*** Starting controller
c0
*** Starting 3 switches
s1 s2 s3 ...
*** Starting CLI:
mininet>
Ryu 컨트롤러용 기본 코드 (simple_switch_13 + MTD 기능)
/home/ubuntu/
└── ryu-apps/
├── mtd_controller.py
├── myfirewall.py
└── other_apps.py
mtd_controller.py
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER, set_ev_cls
from ryu.ofproto import ofproto_v1_3
from ryu.lib.packet import packet, ethernet, ipv4
from ryu.controller.handler import HANDSHAKE_DISPATCHER
import random
import time
import threading
class SimpleMTD(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
def __init__(self, *args, **kwargs):
super(SimpleMTD, self).__init__(*args, **kwargs)
self.mac_to_port = {}
self.ip_pool = ["10.0.0." + str(i) for i in range(1, 10)]
self.ip_map = {}
self.mtd_interval = 30 # 매 30초마다 IP 변경
threading.Thread(target=self.ip_randomizer).start()
def ip_randomizer(self):
while True:
time.sleep(self.mtd_interval)
self.logger.info("MTD: 무작위 IP 재할당 시작")
self.ip_map = {} # 기존 맵 제거
for host_id in range(1, 9):
self.ip_map[f"h{host_id}"] = random.choice(self.ip_pool)
self.logger.info(f"새로운 IP 매핑: {self.ip_map}")
@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def switch_features_handler(self, ev):
datapath = ev.msg.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
match = parser.OFPMatch()
actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
ofproto.OFPCML_NO_BUFFER)]
self.add_flow(datapath, 0, match, actions)
def add_flow(self, datapath, priority, match, actions):
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
actions)]
mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
match=match, instructions=inst)
datapath.send_msg(mod)
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
in_port = msg.match['in_port']
pkt = packet.Packet(msg.data)
eth = pkt.get_protocols(ethernet.ethernet)[0]
dst = eth.dst
src = eth.src
dpid = datapath.id
self.mac_to_port.setdefault(dpid, {})
self.mac_to_port[dpid][src] = in_port
out_port = self.mac_to_port[dpid].get(dst, ofproto.OFPP_FLOOD)
actions = [parser.OFPActionOutput(out_port)]
# 흐름 추가
match = parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src)
self.add_flow(datapath, 1, match, actions)
# 패킷 전송
out = parser.OFPPacketOut(datapath=datapath,
buffer_id=msg.buffer_id,
in_port=in_port,
actions=actions,
data=msg.data)
datapath.send_msg(out)
기본적인 스위칭 기능을 하면서, 30초마다 호스트 IP를 무작위로 바꾸는 역할
실시간 IP 변경은 단순히 로그로 표시되고, 실제 호스트 IP를 바꾸지는 않음
4단계: Ryu 실행
ryu-manager mtd_controller.py
# eventlet 라이브러리의 ALREADY_HANDLED를 불러올 수 없을 경우에는, eventlet 버전 다운그레이드
pip install eventlet==0.30.2
# ryu를 찾을 수 없는 경우
pip install ryu "eventlet<0.31"
# 호환성 문제 (실험 환경: Python 3.8, eventlet 0.30.x)
# Python 3.8 설치
sudo apt update
sudo apt install -y software-properties-common
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt update
sudo apt install -y python3.8 python3.8-venv python3.8-dev
# Ryu용 가상환경 생성
python3.8 -m venv ~/ryu-env
source ~/ryu-env/bin/activate
# 필요한 패키지 설치
pip install --upgrade pip
pip install ryu==4.34 eventlet==0.30.2
# eventlet==0.30.2는 Python 3.8 환경에서 Ryu와 안정적으로 호환됨
# 가상환경 만들기
python3.8 -m venv ryu-env
source ryu-env/bin/activate
# prompt: (ryu-env) ubuntu@ip-...:~$
# (가상환경 내) Ryu, eventlet 설치
pip install --upgrade pip
pip install ryu==4.34 eventlet==0.30.2 six==1.16.0
# 안될 경우,
git clone https://github.com/faucetsdn/ryu.git
cd ryu
git checkout tags/v4.34 -b v4.34
pip install setuptools==59.5.0
pip install . --no-use-pep517
# 현재 디렉토리 등록
echo "export PYTHONPATH=." >> ~/ryu-apps/ryu-env/bin/activate
# 재실행
ryu-manager mtd_controller.py
# 버전 오류 시
# 1. pip, setuptools, wheel 다운그레이드
pip install --upgrade pip
pip install "setuptools==56.0.0" "wheel==0.36.2"
# 2. 안정적인 조합 설치
pip install "ryu==4.30" "eventlet==0.30.2"
$ python --version # Python 3.8.20
$ pip show ryu # Version: 4.30
$ pip show setuptools # Version: 56.0.0
$ pip show eventlet # Version: 0.30.2
5단계: 실험 진행
# RTT 측정
mininet> h1 ping h2
# 정찰 공격 시뮬레이션
mininet> h3 nmap -sP 10.0.0.0/24
- 실제 IP 변경은 iptables NAT 규칙으로 시뮬레이션 가능
- 실제 SCADA/PLC 장비 대신 Modbus 시뮬레이터 (ex. mbtget)로 구성 가능
mininet> h1 ping -c 10 h2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.059 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.053 ms
64 bytes from 10.0.0.2: icmp_seq=3 ttl=64 time=0.053 ms
64 bytes from 10.0.0.2: icmp_seq=4 ttl=64 time=0.060 ms
64 bytes from 10.0.0.2: icmp_seq=5 ttl=64 time=0.054 ms
64 bytes from 10.0.0.2: icmp_seq=6 ttl=64 time=0.058 ms
64 bytes from 10.0.0.2: icmp_seq=7 ttl=64 time=0.052 ms
64 bytes from 10.0.0.2: icmp_seq=8 ttl=64 time=0.055 ms
64 bytes from 10.0.0.2: icmp_seq=9 ttl=64 time=0.053 ms
64 bytes from 10.0.0.2: icmp_seq=10 ttl=64 time=0.062 ms
--- 10.0.0.2 ping statistics ---
10 packets transmitted, 10 received, 0% packet loss, time 9205ms
rtt min/avg/max/mdev = 0.052/0.055/0.062/0.003 ms
mininet> h3 nmap -sP 10.0.0.0/24
Starting Nmap 7.80 (
https://nmap.org
) at 2025-04-22 13:52 UTC
Nmap scan report for 10.0.0.1
Host is up (0.022s latency).
MAC Address: 56:DF:00:DC:C1:17 (Unknown)
Nmap scan report for 10.0.0.2
Host is up (0.020s latency).
MAC Address: E2:2C:BE:AF:84:BD (Unknown)
Nmap scan report for 10.0.0.4
Host is up (0.014s latency).
MAC Address: 92:A7:6C:25:F8:8B (Unknown)
Nmap scan report for 10.0.0.3
Host is up.
Nmap done: 256 IP addresses (4 hosts up) scanned in 27.95 seconds
'Networking > Network' 카테고리의 다른 글
[Route53] name servers (0) | 2025.02.07 |
---|---|
[essential#03] Wireshark (0) | 2025.02.07 |
[essentials#02] Telnet (0) | 2025.02.06 |
[essentials#01] Server-Client communication using Netcat (0) | 2025.02.06 |
[AWS] setting up Nginx SSL (0) | 2024.07.30 |