Studia przypadków
Przypadek 1: getty
Studium
Przypadku (Case Study): Jak jedna linia w rc.conf sparaliżowała FreeBSD
i zmyliła diagnostykę systemu
Wstęp i kontekst środowiska
- System operacyjny:
FreeBSD (architektura amd64)
- System plików: UFS2
(klasyczny układ partycji, w tym odrębne punkty montowania / oraz /usr)
- Dodatkowe usługi: Aktywne
kontenery/klatki jail zarządzane z poziomu systemu-gospodarza (hosta).
1. Objawy awarii (Symptomy pierwotne)
Po restarcie maszyny system nie potrafił przejść do normalnego
trybu wielozadaniowego (Multi-User) i wpadał w pętlę krytycznych
błędów konsoli tekstowej:
- Pętla Getty: Ekran był
masowo zalewany komunikatem:
init: cant exec getty /usr/libexec/getty for port /dev/ttyv0: no such file or directory
a
następnie:
getty repeating too quickly on port ttyv0, sleeping 30 secs.
Objaw
ten dotyczył wszystkich konsol wirtualnych od ttyv0 do ttyv7.
- Awaria trybu awaryjnego (Single-User
Mode): Próba wejścia do trybu jednoosobowego
w celu naprawy konfiguracji kończyła się powtarzającym komunikatem:
cannot read termcap database.
Uniemożliwiało to
poprawne działanie standardowych powłok tekstowych i zaawansowanych
edytorów (np. vi), wymuszając pracę w trybie terminala dump.
- Status "Amnesiac": W
rzadkich momentach, gdy system pozwalał na interakcję w trybie
Multi-User, zgłaszał się pod domyślną nazwą jądra: amnesiac. Całkowicie
brakowało dostępu do programu /usr/bin/login, a interfejsy sieciowe
oraz kontenery jail pozostawały nieaktywne.
2. Chronologia diagnostyki i ślepe zaułki (Kolejne
próby rozwiązania)
Próba 1: Podejrzenie uszkodzenia
plików binarnego systemu i bazy termcap
- Hipoteza: Plik
/usr/libexec/getty lub baza /usr/share/misc/termcap uległy fizycznemu
uszkodzeniu, usunięciu lub skróceniu (błąd EOF) podczas
operacji na jailach lub nieudanej aktualizacji.
- Działanie: Ręczne podmienienie
pliku getty oraz bazy termcap ze sprawnej maszyny o identycznej wersji
systemu. Prnebadowanie bazy poleceniem
cap_mkdb
.
- Wynik: Brak rezultatu. Mimo
fizycznej obecności plików o prawidłowych uprawnieniach
(root:wheel, 755/644), system nadal zgłaszał ich brak (No such file or
directory).
Próba 2: Podejrzenie
awarii bibliotek dynamicznych (Błąd linkera)
- Hipoteza: Komunikat No
such file or directory w systemach UNIX przy istniejącym pliku
wykonywalnym często oznacza brak linkera dynamicznego lub powiązanych
bibliotek .so.
- Działanie: Podmieniono kluczowe
biblioteki systemowe: libc.so.7, libutil.so.9 oraz libsys.so.7.
Sprawdzono zależności za pomocą ldd oraz nagłówek ELF
poleceniem
objdump -p
.
- Wynik: Kolejny fałszywy trop.
Plik getty okazał się sprawny, a ldd nie wykazywał braków
(status not found zniknął), jednak jądro wciąż odrzucało wykonanie
programu.
Próba 3: Próba
wymuszenia aktualizacji i naprawy przez freebsd-update
Próba 4: Analiza tabeli
montowania i uprawnień katalogów root
- Hipoteza: Partycja
/usr montuje się w trybie tylko do odczytu (ro) lub doszło do
uszkodzenia wskaźników ścieżek jądra (vnodes/nullfs leakage)
przez nieprawidłowo zamknięte jaile.
- Działanie: Weryfikacja pliku
/etc/fstab oraz komend
mount -u /
i mount -a
.
Próba przeniesienia getty i bazy termcap na partycję
główną / w celu ominięcia struktury /usr.
- Wynik: Częściowy sukces.
Ominięcie ścieżki /usr pozwoliło systemowi ruszyć bez pętli
błędów, ale ujawniło symptom głębszy – system
wstawał jako amnesiac i wciąż ignorował podłączanie dysków w
trybie Multi-User. Ponowne wpisanie exit natychmiast zrzucało system z
powrotem do Single-User.
3. Przełom i identyfikacja prawdziwej przyczyny
Kluczem do rozwiązania zagadki okazało się prześledzenie
rozruchu skryptu startowego linia po linii za pomocą wbudowanego
mechanizmu debugowania powłoki sh w trybie awaryjnym (Single-User Mode):
/bin/sh -x /etc/rc
Wynik
testu: Skrypt /etc/rc rozpoczynał działanie, ładował
podstawowe zmienne, po czym nagle i po cichu kończył pracę (exit 0),
całkowicie przerywając dalszą procedurę bootowania. Dalsza weryfikacja
za pomocą:
/rescue/cat -n /etc/rc.conf
ujawniła
anomalie. Na samym końcu pliku konfiguracyjnego /etc/rc.conf znajdowało
się pojedyncze, ukryte polecenie:
exit
Jak do tego doszło?
Słowo to zostało najprawdopodobniej przypadkowo zapisane do pliku
podczas jednej z sesji SSH (np. poprzez błędne przekierowanie
strumienia
echo "coś" > /etc/rc.conf
zamiast dopisania >>, bądź wklejenie komendy wyjścia z terminala
bezpośrednio do otwartego edytora).
4. Dlaczego ta jedna linia wywołała tak spektakularną lawinę
błędów? (Analiza techniczna)
W systemie FreeBSD plik /etc/rc.conf nie jest pasywnym plikiem
tekstowym (jak np. pliki .ini czy .json). Jest on wykonywany metodą
tzw. sourcingu (kropki lub polecenia . / source) wewnątrz
głównego skryptu startowego /etc/rc. Wstrzyknięcie słowa
exit do rc.conf spowodowało, że:
- Główny proces systemu (init) wywoływał
/etc/rc.
- Skrypt /etc/rc w pierwszych linijkach wczytywał /etc/rc.conf.
- Interpreter natrafiał na instrukcję exit wewnątrz rc.conf i
błyskawicznie zamykał cały proces /etc/rc.
- W efekcie system nigdy nie wykonał kolejnych
kroków rozruchu:
- Nie ustawiono nazwy hosta i parametrów
sieci (stąd status amnesiac).
- Nie uruchomiono skryptu montującego dyski z tabeli /etc/fstab
(partycja /usr pozostawała fizycznie odłączona w trybie Multi-User).
- Gdy init przechodził do kolejnej fazy i
próbował
uruchomić ekrany logowania z pliku /etc/ttys, odpytywał odłączoną
partycję /usr o program /usr/libexec/getty. Ponieważ katalog był pusty,
jądro zwracało błąd No such file or directory, prowokując pętlę
restartów too quickly.
5. Rozwiązanie (Remedium)
Naprawa systemu wymagała całkowitego odcięcia się od
uszkodzonej konfiguracji i przywrócenia spójności
z poziomu czystej, statycznej powłoki ratunkowej:
- Uruchomienie systemu w trybie Single-User Mode.
- Wywołanie w pełni niezależnej powłoki ratunkowej
(niepotrzebującej bibliotek dynamicznych):
Enter full pathname of shell: /rescue/sh
- Zamontowanie
partycji głównej w trybie zapisu:
/rescue/mount -u /
- Usunięcie
wadliwej linii z pliku konfiguracyjnego (za pomocą
/rescue/ee /etc/rc.conf
lub automatycznie przez sed).
- Przywrócenie fabrycznego, czystego pliku
konfiguracji terminali /etc/ttys za pomocą narzędzia fetch.
- Wykonanie
/rescue/reboot
.
Po usunięciu słowa exit, skrypt /etc/rc wykonał się
w całości, automatycznie montując wszystkie partycje UFS2, podnosząc
sieć i przywracając sprawność procesu getty na wszystkich konsolach.
Lekcja dla administratorów (Takeaway)
- Weryfikuj źródło, a nie
objawy: Lawina błędów binarnych (getty,
termcap, ldd) była jedynie efektem domina wywołanym brakiem montowania
partycji /usr.
- Pamiętaj o naturze rc.conf: W
systemach z rodziny BSD pliki konfiguracyjne są częścią kodu powłoki.
Błąd składni lub wstrzyknięte polecenie sterujące w pliku
konfiguracyjnym ma bezpośredni wpływ na stabilność profesjonalnego
procesu init.
- Narzędzia /rescue ratują życie:
W krytycznych momentach niespójności środowiska
współdzielonego, statycznie linkowane binarie z katalogu
/rescue są jedynym pewnym punktem podparcia dla administratora.
Przypadek 2: BIND+DNSSEC+splitDNS
# BIND 9.20 + DNSSEC + split
DNS – przypadek
błędnej konfiguracji i diagnostyki##
Opis problemuAdministrator
utrzymuje własny serwer DNS oparty o BIND 9.20
na FreeBSD.Założenia
były następujące:
- publiczna strefa domena.pl
obsługiwana jest przez
zewnętrznego operatora DNS,
- lokalny
serwer BIND utrzymuje własną wersję tej samej strefy
wyłącznie dla sieci LAN,
- w
sieci lokalnej domena.pl ma adres prywatny (np.
192.168.1.100),
- w
Internecie domena.pl ma adres publiczny (np. 88.x.x.x),
- DNSSEC
realizowany jest automatycznie przez
dnssec-policy default;
oraz
inline-signing yes;
.
Po zmianach w konfiguracji
pojawiły się
jednocześnie dwa problemy:
- strefa zwracała SOA, ale nie
zwracała rekordu A dla
domeny głównej,
- po
restarcie named nie były aktualizowane pliki .signed.
# ObjawyLokalny
serwer DNS odpowiadał:dig @192.168.1.1 domena.pl Awynik:status: NOERROR
ANSWER: 0
AUTHORITY: 1
domena.pl. IN SOA ns1.example.pl. hostmaster.example.pl.Brak
rekordu A mimo obecności wpisu:@ IN A 192.168.1.100w pliku
strefy.Jednocześnie:named-checkzone domena.pl domena.pl.zone.dbzwracał:loaded serial XXXXX
OKco
oznaczało, że plik źródłowy był poprawny.
# Pierwszy trop –
strefa nie korzysta z
aktualnego plikuPolecenie:rndc zonestatus domena.plpokazało:file: domena.pl.zone.db.signed
serial: 202407013
signed serial: 202407376natomiast:named-checkzone domena.pl domena.pl.zone.dbpokazywał
już nowszy numer seryjny:2026060105Oznaczało
to, że:
- plik źródłowy został
zmodyfikowany,
- BIND
widział nowe dane,
- ale
aktywna strefa nadal korzystała ze starego pliku
podpisanego.
# Dodatkowa komplikacja
–
pliki .signed.signedW
katalogu stref pojawiły się pliki:domena.pl.zone.db.signed
domena.pl.zone.db.signed.jbk
domena.pl.zone.db.signed.signed
domena.pl.zone.db.signed.signed.jnlJest
to typowy objaw sytuacji, gdy:file "domena.pl.zone.db.signed";
inline-signing yes;BIND
próbuje podpisać już podpisaną strefę. W efekcie tworzone są
kolejne poziomy:.signed
.signed.signedco
prowadzi do chaosu i utrudnia diagnostykę.
# Prawidłowa konfiguracja
inline-signingDla
automatycznego DNSSEC plik strefy powinien wskazywać na
plik źródłowy:zone "domena.pl" {
type primary;
file "/ścieżka/domena.pl.zone.db";
dnssec-policy default;
inline-signing yes;
allow-update { none; };
};Nie
należy wskazywać:file "domena.pl.zone.db.signed";jako
pliku źródłowego strefy.
# RozwiązaniePo
poprawieniu konfiguracji wykonano:service named stopusunięto
stare pliki:rm domena.pl.zone.db.signed*następnie:service named startPo
uruchomieniu BIND
automatycznie wygenerował nowe pliki:domena.pl.zone.db.signed
domena.pl.zone.db.signed.jbki
załadował aktualną zawartość strefy.Weryfikacja:dig @192.168.1.1 domena.pl A +shortwynik:192.168.1.100Problem
został rozwiązany.
# Drugi problem –
dziwna nazwa
domena.pl.example.plPolecenie:nslookup domena.pl 8.8.8.8zwracało:Aliases: domena.pl.example.plco
sugerowało błędną konfigurację DNS.Po
analizie okazało się, że:cat /etc/resolv.confzawierało:search example.ploraz
publiczna strefa
example.pl posiadała rekord:*.example.pl CNAME example.plW
efekcie
resolver próbował automatycznie dopisywać sufiks:domena.pl → domena.pl.example.pla
wildcard odpowiadał poprawnym rekordem. Nie był to błąd DNS domeny.pl,
lecz efekt działania mechanizmu search domain.
# Split DNS –
poprawna interpretacjaW
tym przypadku administrator celowo utrzymywał dwie
różne wersje tej samej domeny:##
Publiczny DNSdomena.pl -> 88.x.x.xobsługiwany
przez
zewnętrznego operatora.##
Lokalny DNSdomena.pl -> 192.168.1.100obsługiwany
przez własny serwer BIND.Jest
to klasyczna konfiguracja split DNS i sama w sobie nie
stanowi błędu.
# Czy usuwać "search
example.pl"?Nie
zawsze. Jeżeli administrator korzysta z nazw
skróconych:ssh serwer1
ping nas
ping backupto
wpis:search example.pljest
przydatny. Należy
jednak pamiętać, że powoduje on automatyczne rozwijanie nazw:host → host.example.plorazdomena.pl → domena.pl.example.plgdy
resolver uzna, że nazwa nie jest w pełni kwalifikowana.
# Czy usuwać wildcard
*.example.pl?Nie
w każdym przypadku. Wildcard:*.example.pl CNAME example.pljest
często wykorzystywany do obsługi usług typu:jellyfin.example.pl
grafana.example.pl
nextcloud.example.plUsunięcie
go może spowodować niedziałanie wielu istniejących subdomen. Przed
usunięciem należy sprawdzić, czy nie jest używany przez działające
usługi.
# WnioskiNajważniejsze
przyczyny problemu:
- Strefa korzystała ze starego
pliku .signed.
- W
katalogu pojawiły się pliki .signed.signed, co wskazywało
na błędny przebieg podpisywania.
- Po
usunięciu starych plików podpisanych BIND
wygenerował je ponownie i załadował aktualną strefę.
- Rekord
A dla domeny głównej wrócił do
odpowiedzi DNS.
- Alias
domena.pl.example.pl nie wynikał z błędu strefy, lecz z
konfiguracji search w resolverze oraz obecności wildcarda w strefie
nadrzędnej.
- Split DNS działał prawidłowo
– problem dotyczył
procesu DNSSEC i plików podpisanych, a nie samej koncepcji
rozdzielenia DNS publicznego i prywatnego.
Przypadek 3: tworzenie sitemap.xml i 404
Studium przypadku:
sitemap.xml, błędy 404 i problemy z narzędziami analitycznymi
Wstęp
W trakcie pracy nad rozbudowaną witryną
składającą się z kilkuset statycznych stron HTML wykonano standardową
kontrolę techniczną serwisu po wygenerowaniu mapy witryny (sitemap.xml).
Celem było sprawdzenie poprawności indeksacji
oraz weryfikacja, czy wszystkie adresy zwracają kod HTTP 200.
Wyniki pozornie były proste — mapa
witryny działała, a strona była dostępna. Jednak analiza crawlerem
wykazała kilka błędów 404, których lokalizacja w
kodzie nie była oczywista.
Problem
Po uruchomieniu skanowania narzędziem typu
crawler pojawiło się kilka adresów zwracających błąd 404.
Co istotne:
- liczba
błędów była niewielka,
- strony jako całość działały poprawnie,
- nie było oczywistego miejsca w HTML, gdzie te
adresy były używane.
Problem polegał nie
tyle na samej liczbie błędów, co na braku jednoznacznej
informacji, skąd one pochodzą.
Pierwsza diagnoza
Naturalnym krokiem jest przeszukanie kodu
HTML pod kątem błędnego adresu. W praktyce jednak nie zawsze prowadzi
to do rozwiązania problemu.
Odwołania do nieistniejących
zasobów mogą znajdować się w różnych miejscach:
- w znacznikach HTML (
<img>,
<a>,
<script>,
<link>),
-
w CSS (
url(...)),
-
w JavaScript (dynamiczne przypisania),
- w
srcset,
- w szablonach wspólnych dla wielu
podstron,
- w sitemap.xml.
W efekcie ręczne
przeszukiwanie pojedynczych plików często nie daje
natychmiastowego wyniku.
Weryfikacja sitemap.xml
Jednym z pierwszych kroków
powinna być analiza samej mapy witryny.
W wielu przypadkach błędy 404 wynikają z:
- pozostawienia
starych adresów w sitemap.xml,
- nieaktualnych wpisów po zmianie
struktury serwisu,
- błędów generowania mapy przez
automatyczne narzędzia.
Każdy adres w
sitemap.xml powinien zwracać kod HTTP 200. Jeśli tak nie jest, mapa
witryny wprowadza w błąd mechanizmy indeksujące oraz narzędzia
analityczne.
Problemy z narzędziami do skanowania i
generowania sitemap
W trakcie analizy okazało się, że duża część
trudności nie wynikała z samej witryny, ale z narzędzi używanych do jej
analizy.
Różne
wyniki w różnych crawlerach
Różne narzędzia dawały
różne rezultaty:
- jedno wykrywało
błędy 404,
- inne nie raportowało ich wcale,
- jeszcze inne znajdowało adresy,
które nie występowały w kodzie.
Brak
spójności utrudniał jednoznaczną ocenę sytuacji.
Brak informacji o źródle błędu
Część narzędzi wskazywała jedynie adres 404,
bez informacji:
- na
której stronie występuje odwołanie,
- w którym elemencie został
znaleziony link.
Powodowało to
konieczność ręcznego przeszukiwania całej struktury serwisu.
Błędy spoza HTML
Nie wszystkie wykryte adresy pochodziły
bezpośrednio z treści strony.
Część była generowana przez:
- CSS (np. obrazy
tła),
- JavaScript (dynamiczne przypisania),
- elementy ładowane warunkowo,
- stare wpisy w zasobach statycznych.
W efekcie część
błędów nie miała „widocznego” miejsca w
HTML.
Problemy z generatorem sitemap
Dodatkowym źródłem
niejednoznaczności był sam generator sitemap.xml, który:
- potrafił utrzymywać
nieaktualne URL-e,
- nie zawsze odświeżał strukturę po zmianach,
- czasami bazował na danych historycznych.
W rezultacie mapa
witryny mogła zawierać adresy, które nie były już częścią
aktualnej struktury serwisu.
Wnioski praktyczne
Analiza przypadku prowadzi do kilku
wniosków:
- żadne pojedyncze
narzędzie nie daje pełnego obrazu stanu serwisu,
- wyniki crawlerów należy traktować
jako punkt wyjścia, a nie ostateczną prawdę,
- każdy błąd 404 wymaga weryfikacji
źródła, a nie tylko samego adresu,
- sitemap.xml musi być traktowana jako element
aktywny, a nie jednorazowo wygenerowany plik.
W praktyce nawet
niewielka liczba błędów może wskazywać na pozostałości po
wcześniejszych zmianach w strukturze strony.
Zakończenie
W środowisku rozbudowanych
serwisów statycznych najtrudniejszym elementem nie jest samo
wykrycie błędu, ale jego poprawna interpretacja.
Crawler i sitemap są narzędziami
pomocniczymi — przydatnymi, ale nieomylne dane trzeba zawsze
potwierdzić w kodzie źródłowym oraz strukturze serwera.
Dopiero połączenie analizy narzędziowej i
ręcznej weryfikacji pozwala uzyskać pełny obraz stanu technicznego
witryny.
Przypadek 4: sitemap - a co widzi Google
Sitemap, crawlery i
SEO techniczne – czyli co tak naprawdę widzi Google
W praktyce administracji stron WWW bardzo
często pojawia się uproszczenie: „mam sitemapę, więc Google wie
wszystko o mojej stronie”. To jedno z tych zdań,
które brzmią sensownie, ale w realnym świecie technicznym są
tylko częściowo prawdziwe.
Sitemap XML nie jest mapą w sensie
diagnostycznym. To jest raczej lista adresów URL przekazana
robotowi wyszukiwarki. Google dostaje informację: „te strony
istnieją”. Ale to nie oznacza, że te strony są poprawne,
dostępne, dobrze połączone albo wartościowe w strukturze serwisu.
Sitemap –
lista, nie analiza
Plik sitemap.xml pełni jedną funkcję:
pokazuje robotowi wyszukiwarki, jakie adresy URL powinny zostać
uwzględnione w indeksowaniu. I to wszystko.
Nie sprawdza on:
- czy strona zwraca
błąd 404,
- czy linki wewnętrzne prowadzą do
istniejących zasobów,
- czy struktura serwisu jest logiczna,
- czy dana podstrona jest osierocona (orphan
page).
Sitemap jest więc
bardziej deklaracją niż analizą. Można powiedzieć, że to
„spis treści”, ale bez sprawdzania, czy wszystkie
rozdziały nadal istnieją.
Crawlery
– czyli jak Google „czyta” stronę
Zupełnie inną klasą narzędzi są crawlery. To
one działają podobnie do Googlebota: przechodzą po stronie link po
linku i sprawdzają jej rzeczywisty stan.
Crawler:
- odwiedza każdą
stronę jak użytkownik lub bot,
- analizuje odpowiedzi serwera (200, 301, 404,
500),
- wykrywa zerwane linki,
- mapuje strukturę połączeń między
podstronami.
Dopiero na
podstawie takiego skanu można powiedzieć coś o
„zdrowiu” strony, a nie tylko o jej liście
adresów.
Broken links
– sygnał, nie katastrofa
W trakcie crawlowania często pojawiają się
tzw. broken links (np. 404). Wbrew popularnemu podejściu nie są one
automatycznie problemem krytycznym dla SEO. Google nie
„karze” za pojedyncze błędy tego typu.
Problem zaczyna się dopiero wtedy, gdy:
- błędy występują w
linkach wewnętrznych,
- struktura strony opiera się na
nieistniejących zasobach,
- architektura linkowania stopniowo się
rozjeżdża.
Wtedy nie chodzi
już o pojedyncze błędy, ale o degradację spójności całego
serwisu.
Sitemap vs crawler
– różnica, która robi różnicę
W praktyce te dwa podejścia często są
mylone, bo wiele narzędzi łączy je w jednym interfejsie. Ale
funkcjonalnie to są dwa różne światy:
- sitemap
mówi: „co powinno istnieć”
- crawler mówi: „co
faktycznie działa”
I dopiero
zestawienie tych dwóch perspektyw daje realny obraz strony.
Wnioski praktyczne
W przypadku stron średniej wielkości
(kilkaset do kilku tysięcy podstron) często zaczyna się moment, w
którym sama sitemap przestaje być wystarczająca jako
narzędzie kontroli.
Pojawia się wtedy potrzeba spojrzenia na
stronę jak Googlebot:
- przez crawl,
- przez analizę linków,
- przez weryfikację struktury, a nie tylko
listy URL.
I to jest moment, w
którym SEO techniczne zaczyna mieć większe znaczenie niż
sama obecność sitemapy.
Przypadek 5: DNSSEC i zarządzanie domeną
Case study: DNSSEC w
środowisku hostingowym – gdzie kończy się technologia, a
zaczyna organizacja
DNSSEC w teorii jest prostym mechanizmem:
podpisujemy strefę DNS, publikujemy rekordy kryptograficzne i zyskujemy
ochronę przed podszywaniem się pod odpowiedzi DNS. W praktyce jednak
wdrożenie w środowisku hostingowym pokazuje, że największym problemem
nie jest sama technologia, ale model zarządzania domeną.
Założenie
Celem było sprawdzenie, czy DNSSEC można
włączyć w typowej konfiguracji: domena krajowa (.pl), DNS zarządzany
przez dostawcę hostingu, bez własnej infrastruktury DNS.
Weryfikacja stanu
Pierwszym krokiem była kontrola delegacji
zabezpieczeń:
Brak rekordu DS w odpowiedzi oznacza brak
aktywnego DNSSEC po stronie rejestru.
Następnie sprawdzono strefę DNS:
- brak
rekordów DNSKEY
- brak podpisów RRSIG
Wniosek był
jednoznaczny: strefa DNS nie jest podpisana, a DNSSEC nie jest aktywny.
Problem praktyczny
W środowiskach hostingowych często nie ma
bezpośredniego przełącznika DNSSEC w panelu użytkownika, mimo że:
- DNS jest w pełni
zarządzany z poziomu hostingu,
- strefa DNS działa poprawnie,
- rekordy można dowolnie edytować.
Brakuje jednak
elementu kluczowego: publikacji rekordu DS w rejestrze domeny.
Kluczowy wniosek
DNSSEC nie jest usługą „po stronie
hostingu DNS”, tylko elementem łańcucha zależności:
rejestr domeny → delegacja DS
→ serwery DNS → podpisana strefa
Oznacza to, że:
- poprawna
konfiguracja DNS nie gwarantuje DNSSEC,
- panel hostingu nie zawsze daje pełną
kontrolę nad bezpieczeństwem domeny,
- aktywacja często wymaga działania po stronie
rejestratora lub wsparcia technicznego.
Konkluzja
DNSSEC w praktyce ujawnia typowy problem
infrastruktury DNS: rozdzielenie odpowiedzialności.
Z punktu widzenia administratora:
- DNSSEC nie jest
„ustawieniem”, tylko procesem w łańcuchu usług,
- brak jednego elementu (DS) unieważnia całą
konfigurację,
- a widoczność w panelach hostingowych bywa
myląca.
W efekcie
technologia, która ma zwiększać bezpieczeństwo, często
okazuje się trudna nie dlatego, że jest skomplikowana, ale dlatego, że
jest rozproszona między różne systemy.
Przypadek 6: sprzętowe wybory - komputer dla OPNsense
Wybór
sprzętu pod firewall 2.5G / 10G (OPNsense / FreeBSD) – case
study
Wstęp
Dobór sprzętu do nowoczesnego
firewalla opartego o OPNsense przestał być prosty. W praktyce nie
wybiera się już „routera”, tylko mały serwer brzegowy
(edge firewall).
W analizowanym przypadku celem było
zbudowanie urządzenia:
- z systemem OPNsense
(FreeBSD)
- obsługą 2.5G (LAN)
- uplinkiem 10G (WAN/backbone)
- minimum 6× Intel i226-V (interfejsy
LAN)
- RAM 8–16 GB
- stabilnością 24/7
- budżetem ~1500–2000 zł
Kluczowy
problem
W urządzeniach klasy AliExpress (CWWK /
Topton / OEM):
- karta sieciowa (Intel
i226-V) jest stała
- RAM i SSD są drugorzędne
- CPU definiuje realną klasę firewalla
Największe obciążenia
nie wynikają z NAT, ale z:
- VPN (WireGuard /
OpenVPN)
- IDS/IPS (Suricata / Zenarmor)
- burst traffic (szczytowe obciążenia
2.5G–10G)
Testowane
klasy CPU
1. CPU
legacy (i3-5010U / i3-8140U)
- niska wydajność
- brak zapasu CPU
- tylko podstawowy NAT/firewall
👉 wniosek: nie nadają się do
2.5G
2. CPU energooszczędne (N300 /
N305 / N355)
- bardzo niski
pobór energii
- dobra efektywność per Watt
- ograniczona wydajność szczytowa
👉 wniosek:
świetne do routera, ale ograniczone pod IDS
i VPN przy dużym ruchu
3. CPU
wydajnościowe (i5-8259U / i5-1235U)
- wyższy single-core
performance
- lepszy VPN throughput
- większy zapas CPU
- stabilniejsza praca przy IDS
👉 wniosek:
najlepsza klasa dla firewalla 2.5G+ z zapasem
Tabela
porównawcza (realna klasa firewall)
| CPU | Rdzenie | PassMark | NAT
2.5G | VPN | IDS/IPS | Klasa |
|---|
| i3-5010U | 2C/4T | ~2k | ❌ | ❌ | ❌ | legacy |
| i3-8140U | 2C/4T | ~4k | 🟡 | ❌ | ❌ | basic |
| N300 | 8C/8T | ~6k | 🟡 | 🟡 | ❌ | low-power |
| N305 | 8C/8T | ~9–10k | 🟢 | 🟡 | 🟡 | edge router |
| N355 | 8C/8T | ~11k | 🟢 | 🟢 | 🟡🟢 | strong low-power |
| i5-8259U | 4C/8T | ~8k | 🟢 | 🟢 | 🟡 | mid firewall |
| i5-1235U | 10C/12T | ~13–14k | 🟢🟢 | 🟢🟢 | 🟢🟢 | optimal firewall |
Finalna architektura (reference
design)
W toku analizy wybrano docelową konfigurację:
Intel i5-1235U + 6× Intel i226-V +
2× 10GbE uplink
Topologia:
- WAN:
2×10G (uplink / ISP / backbone / agregacja)
- LAN: 6×2.5G Intel i226-V
(segmentacja VLAN / DMZ / LAN)
- CPU: Intel i5-1235U
- RAM: 16 GB DDR4
- Storage: NVMe SSD
Dlaczego
ten wybór wygrał
1.
Zrównoważony CPU
i5-1235U oferuje:
- wysoką wydajność
single-core (VPN, routing)
- 10 rdzeni (P + E cores)
- stabilny throughput przy obciążeniu IDS
- duży zapas CPU
👉 klucz:
firewall musi mieć headroom, nie tylko
„peak performance”
2.
Rozdzielenie warstw sieci
- 2×10G
→ uplink / backbone
- 6×2.5G → segmentacja LAN
👉 efekt:
- brak bottlenecku na
interfejsach
- brak przeciążeń przy VLAN
3.
Kompatybilność FreeBSD
- Intel i226-V
→ driver
igc
- stabilna obsługa OPNsense 24+
- sprawdzona platforma firewall
4. RAM 16
GB
- brak swap przy IDS
- stabilne logowanie
- buffer dla Suricata / Zenarmor
Dlaczego
nie N-series
Mimo dobrych parametrów
energetycznych:
- N300 / N305 / N355
mają ograniczony single-core
- IDS i VPN są CPU-bound
- przy 10G i dużym ruchu brakuje headroomu
👉 wniosek:
N-series = edge router
i5-1235U = edge firewall
Kluczowy
wniosek
W firewallach 2.5G–10G nie wygrywa
najniższy pobór energii, tylko stabilny zapas CPU przy
szczytowym obciążeniu (VPN + IDS + routing).
Podsumowanie
Najlepszy
wybór (reference design)
- i5-1235U +
6× i226-V + 2×10G
Energooszczędna alternatywa
Minimum sensowne
Odrzucone
Konkluzja
Dobór sprzętu firewall w tej
klasie nie polega na wyborze „najmocniejszego CPU”,
tylko na znalezieniu punktu, w którym:
- CPU nie jest
bottleneckiem przy burst traffic
- IDS nie zatyka systemu
- VPN utrzymuje stabilny throughput
- sieć 2.5G/10G nie powoduje throttlingu
1.
Case Study 1
Case
Study: How a Single Line
in rc.conf Paralyzed FreeBSD and Misled System Diagnostics
Introduction
and Environment Context
- Operating System:
FreeBSD (amd64 architecture)
- File
System: UFS2 (classic partition layout, including
separate mount points for / and /usr)
- Additional
Services: Active jail containers managed from the host
system.
1. Failure Symptoms (Primary
Symptoms)
After
a machine reboot, the system failed to enter the normal Multi-User mode
and fell into a loop of critical text console errors:
- Getty Loop:
The screen was massively flooded with the message:
init: cant exec getty /usr/libexec/getty for port /dev/ttyv0: no such file or directory
followed
by:
getty repeating too quickly on port ttyv0, sleeping 30 secs.
This
symptom affected all virtual consoles from ttyv0 to ttyv7.
- Single-User Mode
Failure: Attempts to enter Single-User mode to repair
the configuration resulted in a repeating message:
cannot read termcap database.
This
prevented standard text shells and advanced text editors (e.g., vi)
from functioning properly, forcing operation in dumb terminal mode.
- "Amnesiac" Status:
In rare moments when the system allowed interaction in Multi-User mode,
it identified itself under the default kernel name: amnesiac. Access to
the /usr/bin/login program was completely missing, and network
interfaces as well as jail containers remained inactive.
2. Diagnostic Chronology and
Blind Alleys (Successive Troubleshooting Attempts)
Attempt
1: Suspected Corruption of System Binaries and the Termcap Database
- Hypothesis:
The /usr/libexec/getty file or the /usr/share/misc/termcap database
suffered physical corruption, deletion, or truncation (EOF error)
during jail operations or a failed update.
- Action:
Manually replaced the getty file and termcap database from a working
machine with the identical system version. Rebuilt the database using
the command:
cap_mkdb
.
- Result:
No effect. Despite the physical presence of files with correct
permissions (root:wheel, 755/644), the system continued to report them
as missing (No such file or directory).
Attempt 2:
Suspected Dynamic Library Failure (Linker Error)
- Hypothesis:
A "No such file or directory" message in UNIX systems when the
executable file exists often indicates a missing dynamic linker or
associated .so libraries.
- Action:
Replaced key system libraries: libc.so.7, libutil.so.9, and
libsys.so.7. Checked dependencies using ldd and the ELF header using
the command:
objdump -p
.
- Result:
Another false lead. The getty file proved functional, and ldd showed no
missing dependencies (the "not found" status disappeared), yet the
kernel still refused to execute the program.
Attempt 3:
Attempting a Forced Repair and Update via freebsd-update
Attempt 4:
Analysis of the Mount Table and Root Directory Permissions
- Hypothesis:
The /usr partition is mounting in read-only (ro) mode, or kernel path
pointers (vnodes/nullfs leakage) were corrupted by improperly stopped
jails.
- Action:
Verified the /etc/fstab file and executed commands
mount -u /
and mount -a
.
Attempted to move getty and the termcap database to the root partition
/ to bypass the /usr structure.
- Result:
Partial success. Bypassing the /usr path allowed the system to boot
without the error loop, but revealed a deeper symptom – the
system booted as amnesiac and continued to ignore disk mounting in
Multi-User mode. Typing exit immediately dropped the system back into
Single-User mode.
3. Breakthrough and True Cause
Identification
The
key to solving the puzzle was tracing the boot sequence script
line-by-line using the built-in sh shell debugging mechanism in
Single-User mode:
/bin/sh -x /etc/rc
Test
Result: The /etc/rc script initiated execution, loaded
basic variables, and then suddenly and silently terminated (exit 0),
completely halting the remaining boot procedure. Further verification
via:
/rescue/cat -n /etc/rc.conf
revealed
anomalies. At the very end of the /etc/rc.conf configuration file sat a
single, hidden command:
exit
How
did this happen? This word was most likely accidentally
written to the file during an SSH session (e.g., via an incorrect
stream redirection
echo "something" > /etc/rc.conf
instead
of appending with >>, or pasting a terminal exit command directly into
an open editor).
4.
Why Did This Single Line Trigger Such a Spectacular Cascade of Errors?
(Technical Analysis)
In
FreeBSD, the /etc/rc.conf file is not a passive configuration file
(like .ini or .json files). It is executed via sourcing (using the dot
or source command) inside the primary startup script /etc/rc. Injecting
the word exit into rc.conf caused the following sequence:
- The main system process (init)
invoked /etc/rc.
- The
/etc/rc script read /etc/rc.conf in its first lines.
- The
interpreter encountered the exit instruction inside rc.conf and
instantly terminated the entire /etc/rc process.
- Consequently,
the system never executed the subsequent boot steps:
- The hostname and network
parameters were not set (hence the amnesiac status).
- The
script responsible for mounting disks from the /etc/fstab table was
never run (the /usr partition remained physically unmounted in
Multi-User mode).
- When
init proceeded to the next phase and attempted to spawn login screens
from the /etc/ttys file, it queried the unmounted /usr partition for
the /usr/libexec/getty program. Since the directory was empty, the
kernel returned a "No such file or directory" error, provoking the
"repeating too quickly" restart loop.
5. Resolution (Remedium)
Repairing
the system required completely bypassing the corrupted configuration
and restoring consistency from a clean, static rescue shell:
- Booted the system into
Single-User mode.
- Invoked
a fully independent rescue shell (which does not rely on dynamic
libraries):
Enter full pathname of shell: /rescue/sh
- Mounted
the root partition in write mode:
/rescue/mount -u /
- Removed
the faulty line from the configuration file (using
/rescue/ee /etc/rc.conf
or
automatically via sed).
- Restored
the stock, clean terminal configuration file /etc/ttys using the fetch
tool.
- Executed
/rescue/reboot
.
Once the exit word was removed,
the /etc/rc script executed completely, automatically mounting all UFS2
partitions, bringing up the network, and restoring proper getty
functionality across all consoles.
Lessons
for Administrators (Takeaway)
- Verify the
source, not the symptoms: The avalanche of binary errors
(getty, termcap, ldd) was merely a domino effect caused by the
unmounted /usr partition.
- Remember
the nature of rc.conf: In BSD-family systems,
configuration files are part of the shell code. A syntax error or an
injected control command within a configuration file directly
compromises the stability of the professional init process.
- /rescue
tools save lives: In critical moments of shared
environment inconsistency, the statically linked binaries within the
/rescue directory remain the administrator's only reliable point of
leverage.
Case
Study 2
# BIND 9.20 + DNSSEC + split
DNS – A Case of
Misconfiguration and Diagnostics
##
Problem Description
The
administrator maintains a custom DNS server based on BIND
9.20 on FreeBSD.
The
initial assumptions were as follows:
- the public zone domena.pl is
handled by an external
DNS operator,
- the
local BIND server maintains its own version of the same
zone exclusively for the LAN network,
- in
the local network, domena.pl points to a private address
(e.g., 192.168.1.100),
- on
the Internet, domena.pl points to a public address (e.g.,
88.x.x.x),
- DNSSEC
is automatically implemented via
dnssec-policy default;
and
inline-signing yes;
.
Following configuration
changes, two issues
appeared simultaneously:
- the zone returned the SOA
record, but failed to
return the A record for the apex/root domain,
- after
restarting named, the .signed files were not being
updated.
# Symptoms
The
local DNS server responded to queries as follows:
dig @192.168.1.1 domena.pl A
output:
status: NOERROR
ANSWER: 0
AUTHORITY: 1
domena.pl. IN SOA ns1.example.pl. hostmaster.example.pl.
Missing
A record despite the entry being present:
@ IN A 192.168.1.100
inside
the zone
file.
Concurrently:
named-checkzone domena.pl domena.pl.zone.db
returned:
loaded serial XXXXX
OK
which
indicated that the source file itself was correct.
# First Lead – The
Zone Is Not Using the
Up-to-Date File
The
command:
rndc zonestatus domena.pl
showed:
file: domena.pl.zone.db.signed
serial: 202407013
signed serial: 202407376
whereas:
named-checkzone domena.pl domena.pl.zone.db
displayed
a newer serial number:
2026060105
This
indicated that:
- the source file had been
modified,
- BIND
detected the new data,
- but
the active zone was still utilizing the old, signed file.
# Additional Complication
– The .signed.signed Files
The
following files appeared in the zone directory:
domena.pl.zone.db.signed
domena.pl.zone.db.signed.jbk
domena.pl.zone.db.signed.signed
domena.pl.zone.db.signed.signed.jnl
This
is a typical symptom of a situation where:
file "domena.pl.zone.db.signed";
inline-signing yes;
BIND
attempts to sign an already signed zone. As a result, subsequent nested
layers are created:
.signed
.signed.signed
which
leads to
chaos and misleads diagnostics.
# Correct inline-signing
Configuration
For
automated DNSSEC, the zone file directive should point
strictly to the raw source file:
zone "domena.pl" {
type primary;
file "/path/to/domena.pl.zone.db";
dnssec-policy default;
inline-signing yes;
allow-update { none; };
};You
must not specify:
file "domena.pl.zone.db.signed";
as the
source file for the zone configuration.
# Resolution
After
correcting the configuration, the following commands
were executed:
service named stop
the old
files were
removed:
rm domena.pl.zone.db.signed*
and then:
service named start
Upon
startup, BIND
automatically generated new files:
domena.pl.zone.db.signed
domena.pl.zone.db.signed.jbk
and
successfully loaded the up-to-date contents of the zone.
Verification
query:
dig @192.168.1.1 domena.pl A +short
output:
192.168.1.100
The
issue was resolved.
# The Second Issue –
Strange
domena.pl.example.pl Name Resolution
The
command:
nslookup domena.pl 8.8.8.8
returned:
Aliases: domena.pl.example.pl
which
suggested a DNS misconfiguration.
Upon
analysis, it turned out that:
cat /etc/resolv.conf
contained:
search example.pl
and the
public
example.pl zone featured the following record:
*.example.pl CNAME example.pl
Consequently,
the resolver attempted to automatically append the search suffix:
domena.pl → domena.pl.example.pl
and
the wildcard record responded with a valid answer. This was not a DNS
error within the domena.pl zone itself, but rather a side effect of the
search domain mechanism.
# Split DNS – Proper
Interpretation
In
this scenario, the administrator intentionally maintained
two distinct versions of the same domain:
##
Public DNS
domena.pl -> 88.x.x.x
maintained
by an
external operator.
##
Local DNS
domena.pl -> 192.168.1.100
maintained
by
the local BIND server.
This
is a classic split DNS setup and in itself does not
constitute an error.
# Should "search example.pl" Be
Removed?
Not
necessarily. If the administrator relies on short
hostnames:
ssh server1
ping nas
ping backup
then
the directive:
search example.pl
is
highly useful.
However, it must be kept in mind that it triggers automatic name
expansion:
host → host.example.pl
and
domena.pl → domena.pl.example.pl
whenever
the resolver determines that the requested name is not fully qualified
(FQDN).
# Should the Wildcard
*.example.pl Be Removed?
Not
in every case. The wildcard record:
*.example.pl CNAME example.pl
is
frequently used to route various hosted services, such as:
jellyfin.example.pl
grafana.example.pl
nextcloud.example.pl
Removing
it might break access to multiple existing subdomains. Prior to
deletion, verify whether it is currently utilized by live services.
# Conclusions
The
primary root causes of the issue were identified as
follows:
- The zone was utilizing an
outdated .signed file
instance.
- The
appearance of .signed.signed files in the directory
pointed to a broken zone-signing process loop.
- After
purging the legacy signed assets, BIND successfully
re-generated them and loaded the current zone data.
- The
apex domain A record successfully returned to the DNS
responses.
- The
domena.pl.example.pl alias did not stem from a zone
configuration flaw, but from the search directive in the resolver
combined with a wildcard entry in the parent zone.
- The
split DNS mechanism functioned correctly – the
breakdown exclusively affected the DNSSEC validation sequence and
signed zone files, not the actual public/private DNS separation concept.