Cvičení: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14.

V tomto cvičení se budeme věnovat několika tématům: podíváme se na asynchronní komunikaci procesů, seznámíme se s několika zajímavými síťovými nástroji a naučíme se nastavit přesměrování SSH portů. Krátce se také podíváme na nástroje pro tisk a skenování v Linuxu a dále se seznámíme s tím, jak opravit poškozené diskové jednotky.

Toto cvičení nemá žádný bežící příklad a témata tedy můžete číst a zkoušet v libovolném pořadí.

Signály

Linuxové systémy používají signály pro asynchronní komunikaci mezi běžícími programy (procesy). Slovo asynchronní znamená, že signál může být odeslán (a doručen) bez ohledu na stav procesu. Toto je v kontrastu s komunikací prostřednictvím (například) standardního vstupu, kde program řídí, kdy bude ze standardního vstupu číst (tím, že zavolá odpovídající IO funkce pro čtení).

Signály nicméně nenabízejí příliš bohatou možnost komunikace: jediná informace (kromě toho, že byl vůbec poslán) je jejich číslo. Čísla signálů jsou definována v kernelu, který také některé signály sám zpracovává. V ostatních případech jsou signály doručené aplikaci, která na ně může reagovat. Pokud aplikace na signál nereaguje, je signál zpracován výchozím způsobem. V některých případech se jedná o ukončení aplikace. V ostatních případech jsou signály ignorovány.

Toto je také vyjádřeno tím, že nástroj, kterým se signály posílají, se jmenuje kill (protože obvykle proces ukončí).

Bez dalších parametrů kill posílá signál 15 (nazvaný též TERM), který aplikaci říká, že má být ukončena. Aplikace se může rozhodnout, že signál tzv. odchytí, např. zavře otevřené soubory a teprve pak skončí. Aplikace ale může udělat v podstatě cokoliv a dokonce i signál ignorovat. Kromě TERM můžeme též pomocí kill poslat signál KILL (číslo 9), který je vždy odchycen kernelem a okamžitě (a násilně) program ukončí (v případě, že se aplikace pokusí signál odchytit a zpracovávat, je tento požadavek ignorován).

Většina signálů je poslána procesu v reakci na specifickou událost. Například signál PIPE je poslán, pokud proces zkouší zapsat do roury, jejíž čtecí konec byl uzavřen. (Vzpomeňte si na problém z labu 04.) Ukončení programu pomocí Ctrl-C v terminálu ve skutečnosti pošle signál INT (interrupt). Pokud vás zajímají i ostatní signály, mrkněte na signal(7).

Na příklad pokud se systém vypíná, pošle TERM všem procesům. To jim dá možnost rozumně skončit. Procesy, které po nějaké době stále běží, jsou násilně ukončeny signálem KILL.

Použití kill a pkill

Vzpomeňte si na ukázku z cvičení 5, jak můžeme použít kill k ukončení procesů.

Pro rychlé shrnutí si nyní otevřete dva terminály.

Spusťte sleep v prvním, vyhledejte jeho PID v druhém a zabijte jej pomocí SIGTERM (výchozí signál) a poté cvičení zopakujte pomocí SIGKILL (-9).

Solution.

Podobně můžete použít pkill k zabíjení procesů podle jména (ale buďte opatrní, protože s velkou mocí přichází i velká zodpovědnost). Další podrobnosti naleznete na stránkách manuálu.

Dále také existuje příkaz killall, který se chová podobně. V některých Unixových systémech (např. Solaris) má tento příkaz zcela jinou sémantiku a používá se k vypnutí celého počítače.

Reakce na signály v Pythonu

Váš program by obvykle reagoval na TERM (výchozí “měkké” ukončení), INT (Ctrl-C z klávesnice) a možná na USR1 nebo USR2 (jediné uživatelsky definované signály). Systémoví démoni také často reagují na HUP znovu-načtením své konfigurace.

Následující program v jazyce Python reaguje na Ctrl-C ukončením. Uložte jej jako show_signals.py a při spuštění ./show_signals.py stiskněte Ctrl-C.

Při zkoušení níže uvedeného kódu se vyhněte časté pasti: neukládejte jej do souboru signal.py, protože by jeho název kolidoval se standardním balíčkem.
#!/usr/bin/env python3

import sys
import time
import signal

# Actual signal callback
def on_signal(signal_number, frame_info):
    print("")
    print("Caught signal {} ({})".format(signal_number, frame_info))
    sys.exit()

def main():
    # Setting signal callback
    signal.signal(signal.SIGINT, on_signal)
    while True:
        time.sleep(0.5)
        print("Hit Ctrl-C...")

if __name__ == '__main__':
    main()

Cvičení

Napište program, který se pokusí vypsat všechna prvočísla. Při ukončení uloží dosud nalezené nejvyšší číslo a při dalším volání pokračuje od něj.

Solution.

Reakce na signály v shellu

Reakce na signály v shellu se provádí pomocí příkazu trap.

Všimněte si, že typickou akcí pro obsluhu signálů v shellovém skriptu je úklid dočasných souborů.

#!/bin/bash

set -ueo pipefail

on_interrupt() {
    echo "Interrupted, terminating ..." >&2
    exit 17
}

on_exit() {
    echo "Cleaning up..." >&2
    rm -f "$MY_TEMP"
}

MY_TEMP="$( mktemp )"

trap on_interrupt INT TERM
trap on_exit EXIT

echo "Running with PID $$"

counter=1
while [ "$counter" -lt 10 ]; do
    date "+%Y-%m-%d %H:%M:%S | Waiting for Ctrl-C (loop $counter) ..."
    echo "$counter" >"$MY_TEMP"
    sleep 1
    counter=$(( counter + 1 ))
done

Příkaz trap obdrží jako první argument příkaz, který se má v reakci na signál vykonat. Další argumenty obsahují seznam signálů, na které se má reagovat. Všimněte si, že speciální signál EXIT znamená normální ukončení skriptu. Proto nemusíme po ukončení smyčky volat on_exit.

Pro označení ukončení pomocí obsluhy Ctrl-C použijeme exit 17 (hodnota je sama o sobě libovolná).

Návratovou hodnotu můžete zkontrolovat pomocí echo $? po ukončení příkazu. Speciální proměnná $? obsahuje výstupní kód posledního příkazu.

Pokud váš shellový skript začíná příkazem set -e, budete $? potřebovat jen zřídka, protože jakákoli nenulová hodnota způsobí ukončení skriptu.

Následující konstrukce však zabrání ukončení a umožní vám v případě potřeby větvit kód na základě výstupní hodnoty.

set -e

...
# Prevent termination through set -e
rc=0
some_command_with_interesting_exit_code || rc=$?
if [ $rc -eq 0 ]; then
    ...
elif [ $rc -eq 1 ]; then
    ...
else
    ...
fi

Použití - (pomlčky) místo handleru způsobí, že příslušný handler bude nastaven jako výchozí.

Vaše shellové skripty musí vždy obsahovat obsluhu signálu pro úklid dočasných souborů.

Všimněte si použití $$, které vypíše aktuální PID.

Spusťte výše uvedený skript, poznamenejte si jeho PID a v novém terminálu spusťte následující příkaz.

kill THE_PID_PRINTED_BY_THE_ABOVE_SCRIPT

Skript byl ukončen a byla zavolána rutina pro úklid. Srovnejte se situací, kdy jste příkaz trap odkomentovali.

Spusťte skript znovu, ale předejte -9 do kill, abyste určili, že chcete poslat signál devět (tj. KILL).

Co se stalo? Answer.

Signály jsou sice primitivním mechanismem, který předává binární události bez dalších dat, ale jsou hlavním způsobem řízení procesů v systému Linux.

Pokud potřebujete bohatší komunikační kanál, můžete místo něj použít D-Bus.

Rozumná reakce na základní signály je pro serverové aplikace nutností (např. webový server by měl reagovat na TERM dokončením nevyřízených požadavků bez přijímání nových spojení a následným ukončením). V shellových skriptech se považuje za vhodné vždy zajistit úklid dočasných souborů.

Nedostatky v návrhu a realizaci signálu

Signály jsou základním mechanismem pro komunikaci mezi procesy v systémech Unix. Bohužel jejich návrh má několik chyb, které komplikují jejich bezpečné použití.

Nebudeme zabíhat do podrobností, ale měli byste mít na paměti, že manipulace se signály může být složitá v situacích, kdy si nemůžete dovolit ztratit žádný signál nebo kdy signály mohou přicházet rychle jeden za druhým. A při používání signálů ve vícevláknových programech se otevírá celá Pandořina skříňka problémů.

Na druhou stranu pro jednoduché shellové skripty, ve kterých chceme při násilném ukončení provést úklid, postačí přístup, který jsme si ukázali výše. Ve skriptu tím ohlídáme situaci, kdy uživatelé stiskli Ctrl-C, protože zjistili, že pracují se špatnými daty, nebo něco podobného.

Všimněte si však, že takový skript obsahuje chybu pro případ, kdy uživatelé stisknou Ctrl-C velmi brzy během provádění skriptu.

MY_TEMP="$( mktemp )"
# User hits Ctrl-C here
trap on_interrupt INT TERM
trap on_exit EXIT

Dočasný soubor byl již vytvořen, ale obslužná rutina ještě nebyla zaregistrována, a proto nebude soubor odstraněn. Změna pořadí však komplikuje obsluhu signálu, protože musíme otestovat, že $MY_TEMP byl již inicializován.

Skutečnost, že signály mohou být záludné, však neznamená, že bychom měli opustit základní prostředky, které zajistí, že naše skripty po sobě uklidí i v případě, že jsou násilně ukončeny.

V jiných programovacích jazycích je úklid poněkud jednodušší, protože je možné vytvořit dočasný soubor, který se vždy automaticky odstraní, jakmile se proces ukončí.

Spoléhá na šikovný trik, kdy můžeme soubor otevřít (vytvořit) a ihned jej odstranit. Dokud však uchováváme deskriptor souboru (tj. výsledek Pythonovského open), systém zachovává obsah souboru nedotčený. Soubor je však již pryč (ve smyslu označení obsahu) a zavření souboru jej zcela odstraní.

Protože shell je založen na spouštění více procesů, výše uvedený trik pro shellové skripty nefunguje.

Zkontrolujte si vaše porozumění

Vyberte všechna pravdivá tvrzení o signálech a procesech. You need to have enabled JavaScript for the quiz to work.

Přesměrování portů přes SSH (SSH port forwarding)

Obecně platí, že služby poskytované počítačem by neměly být vystaveny na síti, aby si s nimi mohli hrát náhodní “bezpečnostní výzkumníci”. Proto je brána firewall obvykle nakonfigurována tak, aby kontrolovala přístup k počítači ze sítě.

Pokud má být služba poskytována pouze lokálně, je ještě jednodušší nechat ji poslouchat pouze na zařízení zpětné smyčky (loopback). Tímto způsobem k ní mohou přistupovat pouze místní uživatelé (včetně uživatelů připojených k počítači přes SSH).

Pro příklad si můžete povšimnout, že na linux.ms.mff.cuni.cz je na portu 8080 naslouchající webový server. Tento webový server není dostupný, pokud se k němu pokusíte přistupovat přes linux.ms.mff.cuni.cz, ale lokální přístup k němu (při přihlášení k linux.ms.mff.cuni.cz) funguje.

you@laptop$ curl http://linux.ms.mff.cuni.cz:8080                # Fails
you@laptop$ ssh linux.ms.mff.cuni.cz curl --silent http://localhost:8080  # Works

Přístup k tomuto webovému serveru pomocí cURL je sice možný, ale není to uživatelsky nejpřívětivější způsob prohlížení webových stránek.

Přesměrování portů přes SSH (SSH local port forwarding)

SSH lze použít k vytvoření bezpečného tunelu, přes který je lokální port přesměrován na port přístupný ze vzdáleného stroje. V podstatě se připojíte ke zpětné smyčce na svém počítači a SSH tuto komunikaci přesměruje na vzdálený server, čímž efektivně zpřístupní vzdálený port.

Následující příkaz způsobí, že se lokální port 8888 bude chovat jako port 8080 na vzdáleném počítači. Část 127.0.0.1 odkazuje na zpětnou smyčku na vzdáleném serveru (můžete tam napsat i localhost)

ssh -L 8888:127.0.0.1:8080 -N linux.ms.mff.cuni.cz

Vždy nejprve uvedete, který lokální port chcete přesměrovat (8888), a poté cíl, jako byste se připojovali ze vzdáleného počítače (172.0.0.1:8080).

Pomocí -N je toto připojení použitelné pouze pro přesměrování – pro jeho ukončení použijte Ctrl-C (bez něj se přihlásíte i ke vzdálenému počítači).

Otevřete http://localhost:8888 v prohlížeči a zkontrolujte, zda vidíte stejný obsah jako při použití výše uvedeného příkazu ssh linux.ms.mff.cuni.cz curl http://localhost:8080.

Často budete přesměrovávat (lokální) port N na stejný (vzdálený) port N, proto je velmi snadné zapomenout na správné pořadí. Pořadí parametrů -L je ale důležité a záměna čísel (např. 8888:127.0.0.1:9090 místo 9090:127.0.0.1:8888) způsobí přesměrování jiných portů (většinou se to však rychle naučíte).

Nemějte však obavy, pokud si je nemůžete zapamatovat. Proto máte k dispozici manuálové stránky, které používají i každodenní uživatelé Linuxu. Není to nic, za co byste se měli stydět nebo čeho byste se měli bát :-).

Reverzní port forward (SSH remote/reverse port forwarding)

SSH umožňuje vytvořit také tzv. reverzní port forward.

V podstatě umožňuje otevřít spojení ze vzdáleného serveru k místnímu počítači (proti směru spojení SSH).

Prakticky můžete nastavit reverzní přesměrování portů například připojením se ze stolního počítače, který máte doma, na počítač v IMPAKTu/Rotundě a poté se pomocí tohoto reverzního přesměrování připojit z IMPAKTu/Rotundy zpět na svůj domácí počítač.

Tato vlastnost bude fungovat i v případě, že je váš počítač za NAT, což znemožňuje přímé připojení zvenčí.

Následující příkaz nastaví reverzní přesměrování portů tak, že připojení k portu 2222 na vzdáleném počítači bude převedeno na připojení k portu 22 (ssh) na lokálním počítači:

ssh -N -R 2222:127.0.0.1:22 u-plN.ms.mff.cuni.cz

Nejprve uvedete vzdálený port k přesměrování (2222) a poté cíl, jako byste se připojovali z lokálního stroje (127.0.0.1:22).

Při zkoušení tohoto postupu se ujistěte, že je spuštěn démon sshd (vzpomeňte si na lab 10 a příkaz systemctl), a použijte jiný port než 2222, abyste zabránili kolizím.

Abyste se mohli připojit k vašemu počítači přes tento přesměrovaný port, musíte tak učinit z laboratoře IMPAKTu/Rotundy pomocí následujícího příkazu.

ssh -p 2222 your-desktop-login@localhost

Používáme localhost, protože připojení je vázáno pouze na rozhraní loopback, nikoli na skutečný síťový adaptér dostupný na laboratorních počítačích. (Ve skutečnosti ssh umožňuje navázat port forward na veřejnou IP adresu, ale správce to často z bezpečnostních důvodů zakazuje.)

Network Manager

Existuje několik způsobů, jak konfigurovat síť v Linuxu. Správci serverů často dávají přednost použití holého příkazu ip; na stolních počítačích dnes většina distribucí používá NetworkManager, takže si jej ukážeme i zde. Všimněte si, že stránka ArchLinux Wiki o NetworkManageru obsahuje také mnoho informací.

NetworkManager má grafické rozhraní (pravděpodobně jste použili jeho applet, aniž byste o tom věděli), rozhraní TUI (které lze spustit pomocí nmtui) a nakonec rozhraní CLI.

Zde se (ze zřejmých důvodů) zaměříme na rozhraní příkazového řádku. Bez parametrů zobrazí nmcli informace o aktuálních spojeních:

wlp58s0: connected to TP-Link_1CE4
        "Intel 8265 / 8275"
        wifi (iwlwifi), 44:03:2C:7F:0F:76, hw, mtu 1500
        ip4 default
        inet4 192.168.0.105/24
        route4 0.0.0.0/0
        route4 192.168.0.0/24
        inet6 fe80::9ba5:fc4b:96e1:f281/64
        route6 fe80::/64
        route6 ff00::/8

p2p-dev-wlp58s0: disconnected
        "p2p-dev-wlp58s0"
        wifi-p2p, hw

enp0s31f6: unavailable
        "Intel Ethernet"
        ethernet (e1000e), 54:E1:AD:9F:DB:36, hw, mtu 1500

vboxnet0: unmanaged
        "vboxnet0"
        ethernet (vboxnet), 0A:00:27:00:00:00, hw, mtu 1500

lo: unmanaged
        "lo"
        loopback (unknown), 00:00:00:00:00:00, sw, mtu 65536

DNS configuration:
        servers: 192.168.0.1 8.8.8.8
        interface: wlp58s0

...

Porovnejte výše uvedené údaje s výstupem příkazu ip addr. Všimněte si, že NetworkManager explicitně uvádí výchozí trasy a také vás informuje, že některá rozhraní neovládá (zde lo nebo vboxnet0).

Změna IP konfigurace

Přestože většina sítí nabízí DHCP (alespoň ty, ke kterým se připojujete pomocí stolního počítače), někdy je třeba nastavit IP adresy ručně.

Typickým příkladem je situace, kdy potřebujete dočasně propojit dva počítače, např. pro přenos velkého souboru přes kabelové připojení.

Jediné, o čem musíte rozhodnout, je, jakou síť vytvoříte. Nepoužívejte stejnou, jakou používá váš domácí router; naše oblíbená volba je 192.168.177.0/24.

Následující příkaz přidá na enp0s31f6 připojení s názvem wired-static-temp, přičemž vychází z výše uvedeného názvu:

sudo nmcli connection add \
    con-name wired-static-temp \
    ifname enp0s31f6 \
    type ethernet \
    ip4 192.168.177.201/24

Často je potřebné aktivovat spojení pomocí následujícího příkazu:

sudo nmcli connection up wired-static-temp

Stejný postup proveďte i na druhém hostiteli, ale použijte jinou adresu (např. .202). Nyní byste měli být schopni pingnout druhý počítač:

ping 192.168.177.201

Chcete-li demonstrovat, jak se ping chová při výpadku připojení, můžete zkusit odpojit kabel nebo provést totéž softwarově:

sudo nmcli connection down wired-static-temp

Další síťové nástroje

Nebudeme zde suplovat kurzy síťování, ale zmíníme se o některých základních příkazech, které by vám mohly pomoci při ladění základních problémů souvisejících se sítí.

Již znáte ping: základní nástroj pro zjištění, zda je počítač s danou IP adresou spuštěn (a reaguje na síťový provoz).

ping je základní nástroj pro případ, že náhle ztratíte spojení s nějakým serverem. Pingněte cílový server a také nějaký jiný známý server. Pokud pakety procházejí, víte, že problém je někde jinde. Pokud projdou pouze pakety na dobře známý server, problém je pravděpodobně na daném serveru. Pokud selžou oba, síť pravděpodobně nefunguje.

K dispozici jsou však i pokročilejší nástroje.

traceroute (neboli cesta je cíl)

Někdy se může hodit znát přesnou cestu, kterou pakety procházejí. Pro tento druh úloh můžeme použít traceroute.

Podobně jako v případě ping musíme zadat pouze cíl.

traceroute 1.1.1.1
traceroute to 1.1.1.1 (1.1.1.1), 30 hops max, 60 byte packets
 1  _gateway (10.16.2.1)  2.043 ms  1.975 ms  1.948 ms
 2  10.17.0.1 (10.17.0.1)  1.956 ms  1.971 ms  1.961 ms
 3  gw.sh.cvut.cz (147.32.30.1)  1.947 ms  1.973 ms  1.977 ms
 4  r1sh-sush.net.cvut.cz (147.32.252.238)  2.087 ms  2.262 ms  2.527 ms
 5  r1kn-konv.net.cvut.cz (147.32.252.65)  1.856 ms  1.849 ms  1.847 ms
 6  kn-de.net.cvut.cz (147.32.252.57)  1.840 ms  1.029 ms  0.983 ms
 7  195.113.144.172 (195.113.144.172)  1.894 ms  1.900 ms  1.885 ms
 8  195.113.235.99 (195.113.235.99)  4.793 ms  4.748 ms  4.723 ms
 9  nix4.cloudflare.com (91.210.16.171)  2.264 ms  2.807 ms  2.814 ms
10  one.one.one.one (1.1.1.1)  1.883 ms  1.800 ms  1.834 ms

První sloupec odpovídá počtu skoků. Druhý sloupec představuje adresu tohoto skoku a za ním jsou uvedeny tři časy oddělené mezerou v milisekundách. Příkaz traceroute odešle na cíl tři pakety a každý z časů označuje dobu, za kterou paket na cíl dorazí. Z výše uvedeného výstupu tedy vidíme, že balíčky na své cestě mezi místním počítačem a cílem provedly celkem 10 skoků.

Tento nástroj je užitečný zejména tehdy, když máte potíže se sítí a nejste si jisti, kde je problém.

traceroute to 1.1.1.1 (1.1.1.1), 30 hops max, 60 byte packets
 1  10.21.20.2 (10.21.20.2)  0.798 ms  0.588 ms  0.699 ms
 2  10.21.5.1 (10.21.5.1)  0.593 ms  0.506 ms  0.611 ms
 3  192.168.88.1 (192.168.88.1)  0.742 ms  0.637 ms  0.534 ms
 4  10.180.2.113 (10.180.2.113)  1.696 ms  4.106 ms  1.483 ms
 5  46.29.224.17 (46.29.224.17)  14.343 ms  13.749 ms  13.806 ms
 6  * * *
 7  * * *
 8  * * *
 9  * * *
10  * * *
11  * * *
12  * * *
13  * * *
14  * * *
15  * * *
16  * * *
17  * * *
18  * * *
19  * * *
20  * * *
21  * * *
22  * * *
23  * * *
24  * * *
25  * * *
26  * * *
27  * * *
28  * * *
29  * * *
30  * * *

Z tohoto protokolu vidíme, že poslední navštívený skok byl 46.29.224.17, takže se můžeme zaměřit na tento síťový prvek.

nmap (též známý jako průzkum vaší sítě)

nmap je velmi mocný nástroj. Bohužel i nevinné – ale opakované – použití může být snadno chybně interpretováno jako škodlivé skenování zranitelností, které jsou náchylné k útoku. Používejte tento nástroj opatrně a experimentujte ve své domácí síti. Bezohledné skenování univerzitní sítě může ve skutečnosti vašemu počítači na nějakou dobu zakázat jakékoli připojení.

nmap je základní nástroj pro skenování sítě. Pokud chcete zjistit, které síťové služby jsou na počítači spuštěny, můžete se zkusit připojit ke všem jeho portům a zjistit, které jsou otevřené. Nmap to umí a ještě mnohem více.

Zkuste nejprve zkontrolovat zařízení zpětné smyčky (loopback), zda v počítači nejsou spuštěny interní služby:

nmap localhost

Výsledek by mohl vypadat takto (počítač má tiskový server a HTTP proxy server):

Starting Nmap 7.91 ( https://nmap.org ) at 2021-05-04 16:38 CEST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00011s latency).
Other addresses for localhost (not scanned): ::1
rDNS record for 127.0.0.1: localhost.localdomain
Not shown: 998 closed ports
PORT     STATE SERVICE
631/tcp  open  ipp
3128/tcp open  squid-http

Nmap done: 1 IP address (1 host up) scanned in 0.11 seconds

Pokud chcete zobrazit více informací, můžete zkusit přidat parametr -A.

nmap -A localhost

A pokud jej spustíte pod rootem (tj. sudo nmap -A localhost), může se nmap pokusit detekovat i vzdálený operační systém.

Ve výchozím nastavení nmap skenuje pouze porty často používané síťovými službami. Pomocí volby -p můžete zadat jiný rozsah:

nmap -p1-65535 localhost

Tento příkaz dává nmap pokyn ke skenování všech portů TCP (-p1-65535) na localhost.

Opět: neskenujte všechny porty TCP na počítačích v univerzitní síti!

Cvičení: Který webový server se používá v našem GitLabu? A který je na našich univerzitních webových stránkách? Solution.

nc (netcat)

Podívejme se, jak vytvořit síťové připojení ze shellu. To je nezbytné pro ladění síťových služeb, ale je to také užitečné pro použití sítě ve skriptech.

Švýcarský armádní nůž síťového skriptování se nazývá netcat nebo nc.

Bohužel existuje více implementací netcatu, které se liší možnostmi a schopnostmi. My si ukážeme ncat, který je ve Fedoře standardně nainstalován. Ve vašem systému může být nainstalována jiná varianta.

Nejprve triviální věci: chcete-li se připojit k danému portu TCP na vzdáleném počítači, můžete spustit příkaz nc machine port. Tím se naváže spojení a připojí se k němu stdin a stdout. Můžete tedy komunikovat se vzdáleným serverem.

Netcat se často připojuje k jiným příkazům pomocí rour. Napišme si základního HTTP klienta:

echo -en "GET / HTTP/1.1\r\nHost: www.kernel.org\r\n\r\n" | nc www.kernel.org 80

Používáme \r\n, protože protokol HTTP vyžaduje řádky ukončené CR+LF. Hlavička Host: je povinná, protože protokol HTTP podporuje více webových stránek běžících na stejné kombinaci IP adresy a portu.

Vidíme, že http://www.kernel.org/ nás přesměruje na https://www.kernel.org/, a tak to zkusíme znovu pomocí HTTPS. Naštěstí naše verze programu netcat umí pracovat s protokolem TLS (transport-layer security), který se používá k šifrování:

echo -en "GET / HTTP/1.1\r\nHost: www.kernel.org\r\n\r\n" | nc --ssl www.kernel.org 443

Nyní vytvoříme jednoduchý server. Bude naslouchat na portu TCP 8888, a když se k němu někdo připojí, server pošle na toto připojení obsah daného souboru:

nc --listen 8888 <path-to-file

Můžeme otevřít nový shell a zkusit soubor přijmout:

nc localhost 8888

Soubor obdržíme, ale netcat se neukončí – stále čeká na vstup ze stdin. Stisknutí klávesy Ctrl-D funguje, ale je jednodušší říct netcatu, aby pracoval pouze jedním směrem:

nc localhost 8888 --recv-only

OK, pro přenos jednoho souboru po síti to funguje. (Mějte však na paměti, že přenos není šifrovaný, takže není rozumné jej používat ve veřejné síti.)

Po přenosu souboru se server ukončí. Co když chceme spustit server, který zvládne více připojení? Zde přesměrování nestačí, protože potřebujeme soubor číst vícekrát. Místo toho můžeme požádat netcat, aby pro každé spojení spustil příkaz shellu a propojil spojení se jeho stdin a stdout:

nc --listen 8888 --keep-open --sh-exec 'cat path-to-file'

To lze samozřejmě využít k mnohem zajímavějším věcem, než je odesílání souboru. Můžete vzít libovolný program, který komunikuje přes stdin a stdout, a udělat z něj síťovou službu.

Tisk pomocí CUPSu

Tisk v Linuxu zajišťuje subsystém CUPS, který standardně spolupracuje prakticky s každou tiskárnou podporující IPP (internetový tiskový protokol) a podporuje také mnoho starších tiskáren.

Jednoduché sudo dnf install cups nainstaluje základní subsystém, pro konkrétní modely mohou být potřeba další ovladače. OpenPrinting.org obsahuje databázi, ve které lze vyhledávat, které ovladače jsou potřeba (pokud vůbec nějaké jsou). Například pro většinu tiskáren HP je třeba nainstalovat balíček hplip.

Obvykle chcete mít CUPS v systému neustále spuštěný, a proto jej musíte povolit:

sudo systemctl enable --now cups

CUPS má pěkné webové rozhraní, které můžete použít ke konfiguraci tiskáren. U mnoha moderních tiskáren připojených k síti je to často zbytečné, protože budou správně automaticky objeveny.

Pokud jste již CUPS spustili, zkuste navštívit http://localhost:631/. Na kartě Administration můžete přidat nové tiskárny. Výběr správného modelu pomůže systému CUPS rozhodnout, které možnosti zobrazit v dialogovém okně tisku, a umožní správnou funkci tisku ve stupních šedi a podobné funkce.

Skenování obrázků a dokumentů pomocí Sane

Podpora skenerů v systému Linux je řešena pomocí SANE (Scanner Access Now Easy). Stejně jako u tisku bude většina skenerů automaticky detekována. GIMP, který možná již znáte, má podporu SANE.

Přidejte jej pomocí sudo dnf install xsane-gimp.

Vlastní skenování obrázku lze provést v dialogovém okně File -> Create -> XSane, kde vyberete zařízení, vlastnosti skenování (např. rozlišení nebo barvy) a poté můžete spustit skenování.

Opakované spouštění úloh s Cronem

V systému je mnoho úloh, které je třeba pravidelně provádět. Mnohé z nich souvisejí s údržbou systému, například rotace protokolů (odstraňování zastaralých protokolů), ale i běžní uživatelé mohou chtít provádět pravidelné úlohy.

Typickým příkladem může být zálohování adresáře $HOME nebo každodenní změna tapety na ploše.

Z pohledu správce je třeba nainstalovat démona cron a spustit jej. Ve Fedoře se balíček jmenuje cronie, ale služba se stále jmenuje crond.

Úlohy (tasks) pro celý systém jsou definovány v souboru /etc/cron.*/, kam můžete přímo umístit své skripty. Chcete-li například provádět denní zálohování počítače, můžete umístit skript backup.sh přímo do souboru /etc/cron.daily/. Samozřejmě existují specializované zálohovací nástroje (např. duplicity), vaše řešení z Labu 06 je pro domácí postup docela dobrý začátek.

Pokud chcete přesnější specifikaci, než jakou nabízí adresáře cron.daily nebo cron.hourly, můžete ji zadat ve vlastním souboru uvnitř /etc/cron.d/.

V něm každý řádek specifikuje jednu úlohu: požadavek na spuštění zadaného příkazu v zadaném čase pod zadaným uživatelem (obvykle root). Čas se zadává jako minuta (0-59), hodina (0-23), den v měsíci (1-31), měsíc (1-12) a den v týdnu (0-6, kde 0 je neděle). V každém poli můžete použít * pro “libovolný”. Další podrobnosti naleznete v crontab(5).

Následující příkaz tedy spustí /usr/local/bin/backup.sh každý den 85 minut po půlnoci (tj. v 1:25). Druhý řádek bude volat big-backup.sh každou neděli ráno.

25 1 * * * root /usr/local/bin/backup.sh
0  8 * * 0 root /usr/local/bin/big-backup.sh

Všimněte si, že cron.d obvykle obsahuje speciální volání následujícího tvaru, které zajišťuje, že se skripty cron.hourly spustí (tj. samotný deamon cronie hledá pouze uvnitř /etc/cron.d/, použití cron.daily nebo cron.monthly je řešeno speciálními úlohami).

01 * * * * root run-parts /etc/cron.hourly

Spuštění pod obyčejným uživatelem

Běžní (tj. non-root) uživatelé nemohou upravovat soubory v adresáři /etc/cron.d/. Místo toho mají k dispozici příkaz crontab, který lze použít k úpravě jejich osobní tabulky cronu (tj. seznamu úloh cronu).

Voláním crontab -l zobrazíte aktuální obsah tabulky cron. Pravděpodobně nevypíše nic.

Chcete-li upravit tabulku cronu, spusťte příkaz crontab -e. Spustí se váš oblíbený editor, do kterého můžete přidávat řádky ve výše uvedeném formátu, tentokrát bez zadání uživatele.

Přidáním následující položky se například každý den změní pozadí pracovní plochy:

1 1 * * * /home/intro/bin/change_desktop_background.sh

Samozřejmě za předpokladu, že takový skript v daném umístění máte. Pokud to chcete opravdu vyzkoušet, následující skript funguje pro Xfce a používá Lorem Picsum.

#!/bin/bash

# Update to your hardware configuration
screen_width=1920
screen_height=1080

wallpaper_path="$HOME/.wallpaper.jpg"

curl -L --silent "https://picsum.photos/$screen_width/$screen_height" >"$wallpaper_path"

# Xfce
# Select the right path from xfconf-query -lvc xfce4-desktop
xfconf-query -c xfce4-desktop -p /backdrop/screen0/monitor0/workspace0/last-image -s "$wallpaper_path"

# LXDE
pcmanfm -w "$wallpaper_path"

# Sway
# For more details see `man 5 sway-output`
# You can also set a different wallpaper for each output (display)
# Run `swaymsg -t get_outputs` for getting specific output name
swaymsg output '*' bg "$wallpaper_path" fill

Oprava poškozených disků

Hlavní nástroj systému Linux pro opravu poškozených svazků se nazývá fsck (kontrola souborového systému). Příkaz fsck je vlastně jednoduchý wrapper, který vybírá správnou implementaci podle typu souborového systému. Pro rodinu souborových systémů ext2/ext3/ext4 systému Linux se implementace nazývá e2fsck. Může být užitečnější volat přímo e2fsck, protože specializovanější volby se nepředávají prostřednictvím obecného fsck.

Jak jsme se již krátce zmínili v labu 11, je bezpečnější pracovat na kopii svazku, zejména pokud máte podezření, že je svazek vážně poškozen. Tímto způsobem neriskujete jeho ještě větší poškození. To může být poměrně náročné z hlediska diskového prostoru: nakonec jde o peníze == stojí data za víc než nákup dalšího disku nebo dokonce kompletní přenesení do profesionální firmy zaměřené na tento druh práce.

Případně můžete nejprve spustit e2fsck -n, který kontroluje pouze chyby, a sami posoudit jejich závažnost.

Někdy je disk příliš poškozený na to, aby ho fsck opravil. (Ve skutečnosti se to u souborových systémů ext stává zřídka – byli jsme svědky úspěšných oprav disků, jejichž prvních 10 GB bylo zcela přepsáno. Ale u souborových systémů DOS/Windows, jako jsou vfat a ntfs, jsou automatické opravy méně úspěšné.)

I v takovém případě je stále velká šance na obnovení mnoha souborů. Naštěstí, pokud nebyl disk příliš zaplněn, byla většina souborů ukládána průběžně. Můžeme tedy použít jednoduchý program, který prohledá celý diskový obraz a vyhledá signatury běžných formátů souborů (připomeňte si například, jak vypadá formát GIF). Tím samozřejmě neobnovíme názvy souborů ani hierarchii adresářů.

První program, který si ukážeme, je photorec (sudo dnf install testdisk). Před jeho spuštěním si připravte prázdný adresář, do kterého budete ukládat výsledky.

Přijímá jediný argument: soubor s diskovým obrazem, který se má skenovat. Poté spustí interaktivní režim, ve kterém vyberete, kam se mají obnovené soubory uložit, a také odhadnete typ souborového systému (ve většině případů to bude FAT nebo NTFS). Poté se pokusí soubory obnovit. Nic víc, nic míň.

photorec dokáže obnovit spoustu souborových formátů včetně souborů JPEG, MP3, ZIP (včetně ODT a DOCX) nebo dokonce RTF.

Dalším nástrojem je recoverjpeg, který se zaměřuje na obnovu fotografií. Na rozdíl od photorec pracuje recoverjpeg zcela neinteraktivně a nabízí několik dalších parametrů, které umožňují jemné nastavení procesu obnovy.

Balíček recoverjpeg není pro Fedoru připraven: můžete si ho zkusit nainstalovat ručně nebo si hrát pouze s photorec (a doufat, že ho nikdy nebudete potřebovat).

Úlohy před cvičením (deadline: začátek vašeho cvičení, týden 8. května – 12. května)

Následující úlohy musí být vyřešeny a odevzdány před příchodem na vaše cvičení. Pokud máte cvičení ve středu v 10.40, soubory musí být nahrány do vašeho projektu (repozitáře) na GitLabu nejpozději ve středu v 10.39.

Pro virtuální cvičení je deadline úterý 9:00 (každý týden, vždy ráno, bez ohledu na možné státní svátky apod.).

Všechny úlohy (pokud není explicitně uvedeno jinak) musí být odevzdány přes váš repozitář na úkoly. Pro většinu úloh existují automatické testy, které vám mohou pomoci zkontrolovat úplnost vašeho řešení (zde je popsáno jak číst jejich výsledky).

13/word.txt (50 bodů, skupina net)

Řešením je slovo zobrazené na následující stránce na serveru běžícím na linux.ms.mff.cuni.cz (LOGIN nahraďte jako obvykle svým přihlašovacím jménem do GitLabu).

http://localhost:8080/13/LOGIN

Doporučujeme použít grafický webový prohlížeč pro přístup k této stránce.

Slovo, které byste měli vidět je opět hexadecimální řetězec.

Tato úloha je pouze částečně testována automatickými testy.

13/server.txt (50 bodů, skupina net)

Zjistěte, na kterém (nestandardním) portu naslouchá webový server na linux.ms.mff.cuni.cz. A o jaký druh (výrobce) webového serveru se jedná?

Server naslouchá pouze na rozhraní ens18.

Odpověď uložte do textového souboru v následujícím formátu.

PORT:MANUFACTURER

Očekáváme, že zde použijete nmap. Používejte jej opatrně (připomínáme výše uvedená varování).

V tomto případě je použítí nmapu v pořádku, protože ho spouštíte vůči konkrétnímu rozhraní, nevytvoří vlastně žádný skutečný provoz a navíc to v tomto nastavení explicitně povolujeme.

Například výše uvedený webový server na portu 8080 by měl za výsledek následující soubor.

8080:nginx

Všimněte si, že porty 8080, 9090 ani 80 (obvyklé porty webového serveru) nejsou správnou odpovědí.

Nezapomeňte se na server zeptat a ověřit, zda je správný. Ten správný poznáte okamžitě.

Nezapomeňte zkontrolovat, zda je na daném portu skutečně webový server (tj. zda se vám v prohlížeči zobrazí HTML stránka).

Jako nápovědu uvedeme, že správný server není Nginx ani Apache.

Tato úloha je pouze částečně testována automatickými testy.

Úlohy po cvičení (deadline: 28. května)

Očekáváme, že následující úlohy vyřešíte po cvičení, tj. poté, co budete mít zpětnou vazbu k vašim řešením úloh před cvičením.

Všechny úlohy (pokud není explicitně uvedeno jinak) musí být odevzdány přes váš repozitář na úkoly. Pro většinu úloh existují automatické testy, které vám mohou pomoci zkontrolovat úplnost vašeho řešení (zde je popsáno jak číst jejich výsledky).

Spuštění vlastního serveru SSH (60 bodů, skupina net)

V tomto úkolu chceme, abyste si vyzkoušeli spuštění SSH serveru na vlastním počítači (může to být i virtualizovaná instalace). Protože většina vašich počítačů je za NATem, ověříme to pomocí reverzního přesměrování portů na linux.ms.mff.cuni.cz.

SSH server není nutné spouštět dlouhodobě (tj. není třeba systemctl enable, stačí pouhé start a stop později). Rovněž se nebudeme na váš počítač skutečně přihlašovat, ale pouze zkontrolujeme, zda váš SSH server naslouchá (tj. přijímá spojení).

Připomeňme, že o bezpečnost svého počítače se opravdu nemusíte starat. Připojení je skryto uvnitř tunelu SSH, takže je poměrně obtížné se o jeho přítomnosti vůbec dozvědět. Reverzní připojení bude aktivní pouze v době, kdy je aktivní vaše relace, takže může jít doslova jen o několik sekund. Bude tedy viditelné pouze pro ostatní uživatele na linux.ms.mff.cuni.cz.

Důrazně vás varujeme před pokusy o přístup na počítače vašich kolegů nebo jakoukoli jinou formou škodlivé činnosti v souvislosti s touto úlohou.

Chcete-li zabránit kolizi čísel portů, spusťte následující příkaz na linux.ms.mff.cuni.cz, abyste zjistili číslo portu, které máte použít.

nswi177-reverse-port id

Chcete-li úkol skutečně dokončit, nastavte reverzní přesměrování na tomto portu na vlastní server SSH. Poté proveďte příkaz s parametrem test pro kontrolu připojení (pokusí se připojit k serveru, ale bez pokusu o jakoukoli formu ověření). K tomu zavoláme program ssh-keyscan.

nswi177-reverse-port test

Pokud skript vypíše následující zprávu, můžete začít.

Looks good, there is SSH daemon at the other side.

Poté proveďte příkaz submit a postupujte podle pokynů na obrazovce. Všimněte si, že při vlastním odesílání budete mít k dispozici pouze jeden pokus (proto se nejprve ujistěte, že test funguje).

nswi177-reverse-port submit

Všimněte si, že přístup SSH zkontrolujete tak, že se před spuštěním výše uvedených příkazů přihlásíte zpět do počítače.

Tato úloha je pouze částečně testována automatickými testy.

13/signal.txt (40 bodů, skupina admin)

Spusťte příkaz nswi177-signals na linux.ms.mff.cuni.cz.

Abyste splnili tuto úlohu, budete mu muset ve správném pořadí poslat různé signály.

Program vás úlohou sám provede: vždy vytiskne, jaký signál máte poslat.

Zkopírujte poslední řádek výstupu (budou to dvě čísla) z tohoto programu do 13/signal.txt.

Tato úloha je pouze částečně testována automatickými testy.

Učební výstupy

Učební výstupy podávají zhuštěný souhrn základních konceptů a dovedností, které byste měli umět vysvětlit a/nebo použít po každém cvičení. Také obsahují absolutní minimum, které je potřebné pro pochopení navazujících cvičení (a dalších předmětů).

Znalosti konceptů

Znalost konceptů znamená, že rozumíte významu a kontextu daného tématu a jste schopni témata zasadit do většího rámce. Takže, jste schopni …

  • vysvětlit, proč je použití nmap obvykle omezeno/zakázáno správci sítě

  • vysvětlit rozdíl mezi (normálním) přesměrování SSH portu a tzv. reverzním přesměrováním

  • vysvětlit, co je to signál v kontextu Linux procesů

Praktické dovednosti

Praktické dovednosti se obvykle týkají použití daných programů pro vyřešení různých úloh. Takže, dokážete …

  • použít nc pro základní operace

  • použít pgrep pro vyhledání konkrétních procesů

  • poslat signál běžícímu procesu

  • použít přesměrování portu SSH pro přístup ke službě dostupné na zařízení loopback

  • použít reverzní předávání portů SSH pro připojení k počítači za NAT

  • použít nmap pro základní skenování sítě

  • použít ip k dotazování na stav aktuální síťové konfigurace

  • použít utilit ping a traceroute jako základních nástrojů pro ladění síťových problémů

  • volitelné: použít SSH agenta a SSH klíče chráněné pomocí passphrase

  • volitelné: použít NetworkManager k nastavení statických IP adres

  • volitelné: tisknout a skenovat v Linuxu

  • volitelné: opravit poškozené souborové systémy pomocí programů z rodiny fsck

  • volitelné: používat photorec k obnově souborů z poškozeného souborového systému

Seznam změn na této stránce

  • 2023-05-02: Přidány hodnocené úlohy

  • 2023-05-19: Přeformulováno přesměrování portů přes SSH