RL_lab
, pe sistemul fizic (mjolnir
) rulați comanda:
student@mjonir:~$ sudo chmod a+rw /dev/vmnet8
Comanda este utilă pentru a permite plasarea interfețelor mașinilor virtuale VMware în modul promiscuous, necesar pentru lucrul cu bridge-uri.
Dacă ați pornit mașina virtuală înainte de a rula comanda de mai sus, opriți mașina virtuală. Comanda trebuie rulată neapărat înainte de pornirea mașinii virtuale.
RL_lab
.host
). În acest fel vom putea folosi copy-paste în terminal sau alte facilități. Pentru aceasta urmați pașii de mai jos:root
cu parola student
.eth0
:root@host:~# ifconfig eth0
student@mjolnir:~$ ssh root@$ADRESA_IP_MV
unde $ADRESA_IP_MV
este adresa IP a mașinii virtuale așa cum ați obținut-o mai sus.
host
) folosiți comenzile următoare din contul utilizatorului root
de pe stația host
(puteți da copy/paste la comenzi în terminal):root@host:~# wget https://raw.github.com/RL-UPB/rl-lab-prepare/master/rl-lab-11-prepare root@host:~# chmod +x rl-lab-11-prepare root@host:~# ./rl-lab-11-prepare
red
, green
și blue
(containere LXC configurate peste mașina virtuală VMware - stația host
) urmăriți pașii de aici.
host
) sunt (username:parola
):
root:student
student:student
Până acum în laboratorul de Rețele Locale am simulat o topologie de rețea folosind containere LXC (Linux Containers). Pentru a vedea ce containere LXC sunt disponibile într-un sistem folosim pe stația host
comanda lxc-list
:
root@host:~# lxc-list RUNNING FROZEN STOPPED blue (auto) green (auto) red (auto)
Pe stația host
sunt disponibile, pe moment, două interfețe: interfața de loopback (lo
) și intefața de rețea a stației (eth0
). Putem observa acest lucru folosind comanda
root@host:~# ip a s 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN [...] 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 [...]
Observăm că sunt 3 containere în sistem (blue
, green
și red
), toate în starea STOPPED
(oprite). Pentru a porni container-ul blue
vom folosi comanda lxc-start -d -n blue
:
root@host:~# lxc-start -n blue -d root@host:~# lxc-list RUNNING blue (auto) FROZEN STOPPED green (auto) red (auto) root@host:~# ip a s 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN [...] 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 [...] 20: veth-blue: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
Observăm că starea container-ului blue
este RUNNING
. Parametrul -d
este folosit pentru a porni containerul în mod daemon
, iar -n
specifică numele containerului ce se dorește a fi pornit. De asemenea, observăm apariția interfeței virtuale veth-blue
, interfață ce face legătura stației host
cu stația blue
(mai precis cu interfața eth0
internă stației blue
).
-d
al comenzii lxc-start
pentru a porni containerul ca un daemon (în background). Altfel, terminalul curent va fi blocat de comenzile rulate în container și nu vom putea ieși din acesta folosind combinația de taste Ctrl+a
și apoi q
.
Porniți container-ul green
și verificați că este în starea RUNNING
root@host:~# lxc-start -n green -d root@host:~# lxc-list RUNNING blue (auto) green (auto) FROZEN STOPPED red (auto) root@host:~# ip a s 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN [...] 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 [...] 20: veth-blue: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 [...] 23: veth-green: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
Observăm că acum sunt pornite containerele blue
și green
. Observăm că pe stația host
există două interfețe virtuale: veth-blue
(legătura cu stația blue
) si veth-green
(legătura cu stația green
).
Dorim să conectăm cele 2 containere (blue
și green
) în același switch virtual. Pe Linux putem simula un switch folosind noțiunea de bridge. Pentru crearea și configurarea unui bridge vom folosi comanda brctl
.
Pe stația host
vom crea un bridge (denumit br0
) executând comanda:
root@host:~# brctl addbr br0
Pentru a verifica că bridge-ul a fost creat folosim comanda brctl show
:
root@host:~# brctl show bridge name bridge id STP enabled interfaces br0 8000.000000000000 no
Pentru a permite conectivitatea între containere și între containere și stația host
va trebui să legăm interfețele virtuale aferente în bridge-ul proaspăt creat. Altfel spus, dorim să conectăm la bridge-ul br0
interfețele aferente de pe stația host
ale lui blue
(adică interfața veth-blue
) și lui green
(interfața veth-green
). Vom folosi comanda brctl addif
:
root@host:~# brctl addif br0 veth-blue root@host:~# brctl show bridge name bridge id STP enabled interfaces br0 8000.7acc4f8a0686 no veth-blue root@host:~# brctl addif br0 veth-green root@host:~# brctl show bridge name bridge id STP enabled interfaces br0 8000.3a89dafa5a72 no veth-blue veth-green
Pentru a valida operațiunea de adăugare folosim comanda brctl show
.
Exercițiu: Pentru a testa conectivitatea între containere, trebuie configurate adrese IP pe interfețele interne (eth0
) alte containerelor. Configurați pe interfața eth0
a stației blue
adresa IP 192.168.1.4/24 și pe interfața eth0
a stației green
adresa IP 192.168.1.3/24. Pentru reamintire, puteți parcurge 1. [10p] Conectare SSH folosind cheie publică.
veth
de pe stația host
. Adică interfețele veth-red
, veth-blue
și veth-green
nu vor avea adrese IP configurate.
Pentru testarea conectivității între containere folosim comanda ping
dintr-un container sau altul:
root@blue:~# ping -c 2 192.168.1.3 PING 192.168.1.3 (192.168.1.3) 56(84) bytes of data. From 192.168.1.4 icmp_seq=1 Destination Host Unreachable From 192.168.1.4 icmp_seq=2 Destination Host Unreachable --- 192.168.1.3 ping statistics --- 2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 999ms pipe 2 root@blue:~# ip r s 192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.4 root@green:~# ping -c 2 192.168.1.4 PING 192.168.1.4 (192.168.1.4) 56(84) bytes of data. From 192.168.1.3 icmp_seq=1 Destination Host Unreachable From 192.168.1.3 icmp_seq=2 Destination Host Unreachable --- 192.168.1.4 ping statistics --- 2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 1007ms pipe 2 root@green:~# ip r s 192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.3
Observăm că nu avem conectivitate deși interfețele sunt active și adresele IP fac parte din aceeași rețea și tabela de rutare conține intrarea corespunzătoare. Problema poate fi de la bridge. Pe stația host
verificăm legătura de nivel 2 a bridge-ului br0
:
root@host:~# ip link show dev br0 20: br0: <BROADCAST,MULTICAST> mtu 1500 qdisc noqueue state DOWN link/ether 3a:89:da:fa:5a:72 brd ff:ff:ff:ff:ff:ff
Observăm că bridge-ul este inactiv (state DOWN
). Activăm bridge-ul:
root@host:~# ip link set dev br0 up root@host:~# ip link show dev br0 20: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP link/ether 3a:89:da:fa:5a:72 brd ff:ff:ff:ff:ff:ff
Testăm din nou conectivitatea între containerele green
și blue
:
root@green:~# ping -c 2 192.168.1.4 PING 192.168.1.4 (192.168.1.4) 56(84) bytes of data. 64 bytes from 192.168.1.4: icmp_req=1 ttl=64 time=0.070 ms 64 bytes from 192.168.1.4: icmp_req=2 ttl=64 time=0.045 ms --- 192.168.1.4 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 999ms rtt min/avg/max/mdev = 0.045/0.057/0.070/0.014 ms root@blue:~# ping -c 2 192.168.1.3 PING 192.168.1.3 (192.168.1.3) 56(84) bytes of data. 64 bytes from 192.168.1.3: icmp_req=1 ttl=64 time=0.036 ms 64 bytes from 192.168.1.3: icmp_req=2 ttl=64 time=0.029 ms --- 192.168.1.3 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 999ms rtt min/avg/max/mdev = 0.029/0.032/0.036/0.006 ms
Acum există conectivitate între cele două containere.
În acest moment, există conectivitate între stațiile blue
și green
. Dorim să le asigurăm conectivitate la Internet. Pentru aceasta trebuie să urmați pașii:
br0
.blue
și green
.host
.MASQUERADE
) pe stația host
pentru a permite accesul stațiilor blue
și green
în Internet.
Configurați, pe interfața br0
a stației host
, adresa 192.168.1.1/24
. Verificați conectivitatea între stația host
și stațiile green
și blue
.
Configurați adresa IP 192.168.1.1
ca default gateway pe stațiile blue
și green
.
Pe stația host
activați rutarea (vedeți 3. [10p] Download și upload de director folosind ''scp'') și configurați NAT de tipul MASQUERADE
(vedeți 01. [15p] Observare porturi deschise pe o stație).
-o
la iptables
pentru precizarea interfeței de ieșire în momentul configurării unei reguli de tipul MASQUERADE
.
După acești pași verificați conectivitatea stațiilor blue
și green
la Internet. Puteți folosi comanda ping 8.8.8.8
de pe fiecare dintre cele două stații.
Afișați starea tuturor containerelor din sistem folosind comanda lxc-list
. Observați că starea containerului red
este STOPPED
.
Porniți containerul red
în mod daemon și adăugați interfața de pe stația host
aferentă acestuia (veth-red
) în bridge-ul br0
creat anterior.
Pe interfața eth0
a stației red
configurați adresa IP 192.168.1.2/24
pe eth0
. Verificați conectivitatea cu celelalte containere.
Apoi configurați default gateway pe stația red
pentru a asigura conectivitatea acesteia la Internet. Puteți testa conectivitatea la Internet prin folosirea unei comenzi de forma ping 8.8.8.8
.
Până acum conectarea la Internet containerelor red
, green
și blue
se face prin intermediul stației host
pe post de ruter/gateway. Stația host
preia pachetele sosite pe interfața br0
și le transferă apoi pe interfața eth0
legată la o rețea pe care vom denumi în continuare rețea publică.
Dorim să realizăm conectarea la Internet a containerelor direct la rețeaua publică, renunțânt astfel la rutare și la NAT pe stația host
. Pentru aceasta vom adăuga inclusiv interfața eth0
la bridge-ul br0
, asigurând astfel o conexiune ,prin bridge, a containerelelor la rețeaua publică.
Pentru început dezactivăm NAT pe stația host
:
root@host:~# iptables -t nat -L POSTROUTING -n -v Chain POSTROUTING (policy ACCEPT 1 packets, 32 bytes) pkts bytes target prot opt in out source destination 50 3166 MASQUERADE all -- * eth1 0.0.0.0/0 0.0.0.0/0 root@host:~# iptables -t nat -F POSTROUTING root@host:~# iptables -t nat -L POSTROUTING -n -v Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination
După cum am precizat, adăugăm interfața eth0
în brige-ul br0
(practic creăm o legătură între switch-ul nostru virtual br0
și rețeaua publică):
root@host:~# brctl addif br0 eth0 root@host:~# brctl show br0 bridge name bridge id STP enabled interfaces br0 8000.080027db5278 no eth0 veth-blue veth-green veth-red
Pentru a reveni la conectare prin SSH de pe sistemul fizic pe stația host
, va trebui să configurăm o adresă IP pe bridge-ul br0
. Pentru acesta vom șterge vechile adrese de pe interfețele eth0
și br0
și vom obține o adresă nouă pe interfața br0
folosind comenzile:
root@host:~# ip a f dev eth0 root@host:~# ip a f dev br0 root@host:~# dhclient br0 root@host:~# ip a s br0 25: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP link/ether 08:00:27:db:52:78 brd ff:ff:ff:ff:ff:ff inet 192.168.56.101/24 brd 192.168.56.255 scope global br0
br0
să fie primită, prin DHCP, aceeași adresă IP. În acest caz conexiunea SSH existentă va fi deblocată și veți putea continua lucrul la exerciții. Adică nu va mai fi nevoie să rulați comanda ssh
indicată imediat mai jos.
Acum ne putem reconecta de pe sistemul fizic la stația host
prin SSH, folosind adresa IP asociată acum interfeței br0
:
student@mjolnir:~$ ssh root@ADRESA_IP_BR0
Acum containerele sunt conectate la rețeaua publică. Pentru a obține adrese din acea rețea, ștergem vechea adresă pe interfața eth0
, rulăm pe fiecare container comanda dhclient eth0
și observăm ce adrese IP a obținut fiecare container:
root@red:~# ip a f dev eth0 root@red:~# dhclient eth0 root@red:~# ip a s dev eth0 26: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:16:3e:8e:84:21 brd ff:ff:ff:ff:ff:ff inet 192.168.56.102/24 brd 192.168.56.255 scope global eth0 root@blue:~# ip a f dev eth0 root@blue:~# dhclient eth0 root@blue:~# ip a s eth0 19: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:16:3e:32:0f:ae brd ff:ff:ff:ff:ff:ff inet 192.168.56.103/24 brd 192.168.56.255 scope global eth0 root@green:~# ip a f dev eth0 root@green:~# dhclient eth0 root@green:~# ip a s dev eth0 22: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:16:3e:d1:b2:95 brd ff:ff:ff:ff:ff:ff inet 192.168.56.104/24 brd 192.168.56.255 scope global eth0
Folosind noile adrese obținute ne putem conecta direct prin SSH de pe sistemul fizic pe containere:
student@mjonir:~$ ssh root@ADRESA_IP_RED [...] root@red:~# student@mjonir:~$ ssh root@ADRESA_IP_GREEN [...] root@green:~# student@mjonir:~$ ssh root@ADRESA_IP_BLUE [...] root@blue:~#
Vrem să facem o legătură simplă directă doar între două containere (red
și green
) astfel încât să comunice între ele fără ca pachetele să fie prelucrate de sistemul host
. Pentru aceasta vom scoate interfețele aferente din bridge-ul br0
și vom crea un nou bridge.
Pentru început scoatem interfețele aferente containerelor red
(veth-red
) și green
(veth-green
) din bridge-ul br0
:
root@host:~# brctl delif br0 veth-red root@host:~# brctl delif br0 veth-green root@host:~# brctl show br0 bridge name bridge id STP enabled interfaces br0 8000.000c2919b1b2 no eth0 veth-blue
Creăm un nou bridge (br1
) și adăugăm interfețele veth-red
și veth-green
în acesta:
root@host:~# brctl addbr br1 root@host:~# brctl addif br1 veth-red root@host:~# brctl addif br1 veth-green root@host:~# brctl show br1 bridge name bridge id STP enabled interfaces br1 8000.f67659f52916 no veth-green veth-red root@host:~# ip l s dev br1 up root@host:~# ip a s dev br1 13: br1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP [...]
Configurăm adrese pe stațiile red
și green
și verificăm apoi conectiviatea între acestea. Configurăm adresele 172.16.12.1/24
, respectiv 172.16.12.2/24
și verificăm conectivitatea între acestea:
root@red:~# ip a f dev eth0 root@red:~# ip a a 172.16.12.1/24 dev eth0 root@red:~# ip a s dev eth0 9: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:16:3e:8e:84:21 brd ff:ff:ff:ff:ff:ff inet 172.16.12.1/24 scope global eth0 root@green:~# ip a f dev eth0 root@green:~# ip a a 172.16.12.2/24 dev eth0 root@green:~# ip a s dev eth0 6: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:16:3e:d1:b2:95 brd ff:ff:ff:ff:ff:ff inet 172.16.12.2/24 scope global eth0 root@red:~# ping 172.16.12.2 PING 172.16.12.2 (172.16.12.2) 56(84) bytes of data. 64 bytes from 172.16.12.2: icmp_req=1 ttl=64 time=0.319 ms ^C --- 172.16.12.2 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.319/0.319/0.319/0.000 ms root@green:~# ping 172.16.12.1 PING 172.16.12.1 (172.16.12.1) 56(84) bytes of data. 64 bytes from 172.16.12.1: icmp_req=1 ttl=64 time=0.191 ms ^C --- 172.16.12.1 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.191/0.191/0.191/0.000 ms
Avem conectivitate completă între cele două stații (red
și green
) inclusiv la nivel de serviciu. Stația green
poate accesa serviciile SSH, FTP, telnet de pe stația red
:
root@green:~# ssh root@172.16.12.1 [...] root@red:~# root@green:~# ftp 172.16.12.1 Connected to 172.16.12.1. 220 (vsFTPd 2.3.5) Name (172.16.12.1:root): [...] root@green:~# telnet 172.16.12.1 Trying 172.16.12.1... Connected to 172.16.12.1. Escape character is '^]'. Ubuntu 12.04.3 LTS red login: [...]
Ne propunem să blocăm traficul nesigur (adică FTP și telnet) de la stația green
la stația red
. Avem soluția configurării unui firewall pe stația red
folosind utilitarul iptables
. Această soluție are două neajunsuri:
iptables
;
De aceea dorim să filtrăm acele pachete direct de pe stația host
. Stația host
nu face însă prelucrarea pachetelor, acestea trec prin bridge-ul br1
deci nu putem folosi iptables
sau alt utilitar de prelucrare a traficului. Soluția o reprezintă însă utilitarul ebtables care permite configurarea de firewall la nivelul bridge-ului.
Pentru început vom instala ebtables
pe stația host
:
root@host:~# apt-get install ebtables
Apoi configurăm ebtables
pentru a împiedica traficul telnet și FTP care vine de la stația green
către stația red
. Sintaxa este similară iptables
:
root@host:~# ebtables -A FORWARD -p IPv4 --ip-src 172.16.12.2 --ip-dst 172.16.12.1 --ip-proto tcp --ip-destination-port 21 -j DROP root@host:~# ebtables -A FORWARD -p IPv4 --ip-src 172.16.12.2 --ip-dst 172.16.12.1 --ip-proto tcp --ip-destination-port 23 -j DROP root@host:~# ebtables -L FORWARD Bridge table: filter Bridge chain: FORWARD, entries: 2, policy: ACCEPT -p IPv4 --ip-src 172.16.12.2 --ip-dst 172.16.12.1 --ip-proto tcp --ip-dport 21 -j DROP -p IPv4 --ip-src 172.16.12.2 --ip-dst 172.16.12.1 --ip-proto tcp --ip-dport 23 -j DROP
Verificăm din nou, conectivitatea SSH, FTP și telnet de la stația green
la stația red
:
root@green:~# ssh root@172.16.12.1 [...] root@red:~# root@green:~# telnet 172.16.12.1 Trying 172.16.12.1... ^C root@green:~# ftp 172.16.12.1 ^C
Observăm că este în continuare funcțională doar conexiunea SSH, nu și FTP și telnet (blocate folosind ebtables
). Avem obiectivul îndeplinit: doar conexiunile sigure (pe porturile implicite) sunt permise între green
și red
.
ebtables
nu are acțiune de tip REJECT
ci doar DROP
. Astfel, inițiatorul unei conexiuni filtrate nu va fi înștiințat de filtrarea pachetelor. Acestea vor fi filtrate iar inițiatorul va trebui să deducă faptul că există o formă de blocare a pachetelor pe drum.
Ne propunem să realizăm o configurație în care fiecare container se găsește în fiecare rețea. Vom renunța la bridge-uri și vom face legături unu-la-unu între containere și stația host
.
Pentru început, extrageți (ștergeți) interfețele din bridge-uri și apoi ștergeți bridge-urile (br0
și br1
). Urmăriți pagina de manual a comenzii brctl
pentru opțiunile utile.
host
.
DOWN
). Folosiți ip link
pentru a realiza acest lucru.
Apoi ștergeți vechile configurații (adrese IP, rute implicite) de pe containere.
După aceea realizați următoarele:
eth0
a stației host
folosind comandaroot@host:~# dhclient eth0
10.10.10.0/24
pe legătura host(veth-red)
↔ red(eth0)
.20.20.20.0/24
pe legătura host(veth-green)
↔ green(eth0)
.30.30.30.0/24
pe legătura host(veth-blue)
↔ blue(eth0)
.host
.
veth
de pe stația host
și pe interfețele eth0
de pe containere. De exemplu, petnru legătura host(veth-red)
↔ red(eth0)
puteți configura:
10.10.10.1/24
pe interfața veth-red
de pe stația host
10.10.10.2/24
pe interfața eth0
de pe stația red
eth0
ale containerele. Verificați acest lucru folosind comanda
# ip a s
și, dacă au dispărut, refaceți rapid configurația pe containerul în cauză.
În cazul unei configurări corecte, veți avea conectivitate între toate containerele, prin intermediul stației host
pe post de ruter. Folosiți ping
pentru testarea conectivității.
Pe configurația de la exercițiul anterior puteți configura reguli de firewall folosind utilitarul iptables
pe stația host
. Acum stația host
are rol de gateway și va prelucra toate pachetele trimise între containere.
Realizați o configurație de firewall astfel încât serviciile nesigure (telnet, FTP, pe porturile implicite) să fie blocate pe containere. De asemenea, stația green
nu poate fi accesată de pe stația blue
prin SSH (dar poate fi accesată de pe stația red
și de pe stația host
). Pentru informații de utilizare a utilitarului iptables
pentru filtrare, urmăriți Laborator 8. Translatarea de adrese.
iptables
aveți două opțiuni:
-i
și -o
)
Nu folosiți numele stațiilor; adică nu folosiți șirurile red
, green
și blue
în regulile iptables
.
În versiunile mai noi de nucleu Linux și distribuții aferente, gestiunea bridge-urilor poate fi realizată prin intermediul suitei iproute2
, mai precis prin intermediul comenzii ip link
.
Pe stația host
folosiți comanda ip link
de mai sus pentru a crea 2 interfețe de tipul dummy (dummy0
și dummy1
), un bridge denumit br0
și apoi a adăuga interfețele în bridge. Faceți apoi operațiile inverse: ștergerea interfețelor din bridge, a bridge-ului și a interfețelor.