Quantcast
Channel: Debian Users Gang - teksty
Viewing all 160 articles
Browse latest View live

Instalacja sterownika fglrx - karty AMD Radeon

$
0
0

Sterownik własnościowy (zamknięty) od otwartego różni się tym, że: - rozwijany jest przez producenta, (otwarty - generalnie społeczność) - nie wspiera starszych kart - mimo lepszej wydajności i większej oszczędności energii, czasami potrafi sprawić absurdalne problemy

Możemy skorzystać z binarki producenta. Binarka zawiera instalator krok po kroku, ale instalacja z repozytorium (według mnie) jest o wiele wygodniejsza:

aptitude install fglrx-control fglrx-driver fglrx-modules-dkms fglrx-source glx-alternative-fglrx libfglrx libfglrx-amdxvba1 libgl1-fglrx-glx kernel-package xserver-xorg x11-xserver-utils xserver-common

Lub:

aptitude install fglrx-legacy-control fglrx-legacy-driver fglrx-legacy-modules-dkms fglrx-legacy-source glx-alternative-fglrx libfglrx-legacy libfglrx-legacy-amdxvba1 libgl1-fglrx-legacy-glx kernel-package xserver-xorg x11-xserver-utils xserver-common

Po czym:

aticonfig --initial

Powyższe polecenie wygeneruje nam plik /etc/X11/xorg.conf. W pliku tym zapisana jest konfiguracja X'ów. Możemy ją zostawić domyślną, lub skonfigurować według manual'a dostępnego tutaj, lub po wydaniu polecenia:

man xorg.conf

Po wszystkim restartujemy system. Jeżeli menedżer logowania uruchomił się - sterownik działa poprawnie.

Jak na wstępie wspomniałem, sterownik ten nie wspiera starszych kart. Trzeba więc sprawdzić w opisie paczki fglrx-driver lub fglrx-legacy-driver, które serie kart są wspierane. Jeżeli Twojej tam nie ma, wtedy jesteś skazany na sterownik otwarty. Plusem tego sterownika jest to, że grafika teoretycznie działać może nieco wydajniej w porównaniu do sterownika otwartego i nieco mniej energii (prądu) może pobierać (więc i mniejsze temperatury wydzielać). Ale jest też o wiele mniejsze prawdopodobieństwo (w porównaniu do sterownika otwartego), że hibernacja / usypianie będą poprawnie działać.

Opis jest uzupełnieniem tego wpisu. Pytania i sugestie tutaj (forum), lub XMPP/Jabber - pavlo950@linux.pl.


Opis działania obecnej wersji protokołu sieci Bitcoin.

$
0
0

Artykuł autorstwa Pana Michaela Nielsena. Tłumaczenie własne, za zgodą Pana Michaela Nielsena. Pierwotnie esej został opublikowany 6 grudnia 2013 roku w Internecie pod adresem http://www.michaelnielsen.org/ddi/how-the-bitcoin-protocol-actually-works/. Artykuł został przez Bruce'a Schneiera skomentowany tymi słowami:

To najlepszy opis protokołu Bitcoin jaki do tej pory przeczytałem.

Tłumaczenie może zawierać błędy. Jeśli tak jest, to bardzo przepraszam i proszę o zwrócenie mi na nie uwagi, wtedy je poprawię. Zwrócić uwagę można m.in. poprzez ten wątek. Jednocześnie oświadczam, że nie biorę żadnej odpowiedzialności za informacje zawarte w tym artykule. Informacji tych używasz na własne ryzyko.

Życzę miłego czytanie jednego z najobszerniejszych artykułów w języku polskim poświęconych tematowi jak działa Bitcoin. Mam nadzieję, że zdobyta wiedza pozwoli bezpieczniej i efektywniej wykorzystywać tę internetową kryptowalutę, dzięki zrozumieniu czym jest Bitcoin.

Opis działania obecnej wersji protokołu sieci Bitcoin.

  • Oryginalny tytuł: How the Bitcoin protocol actually works
  • Autor: Michael Nielsen
  • Tłumaczenie: uzytkownikubunt

Wiele tysięcy artykułów zostało napisanych w celu wyjaśnienia, czym jest Bitcoin, Internetowa, działająca w oparciu o sieć rozproszoną, waluta. Większość z tych artykułów daje ogólnikowy opis działania protokołu kryptograficznego, omijając wiele szczegółów. Nawet te artykuły, które drążą temat głębiej często omijają bardzo ważne szczegóły. Moim celem w tym artykule jest wyjaśnienie głównych idei stojących za protokołem Bitcoin w sposób jasny, łatwy, wyczerpujący temat. Zaczniemy od ogólnych zasad, budując szerokie teoretyczne zrozumienia jak działa protokół, a następnie zaczniemy zagłębiać się w konkretne detale, rozpatrując surowe dane transakcji Bitcoin.

Zrozumienie protokołu w ten szczegółowy sposób jest ciężką pracą. Kusi, by po prostu używać Bitcoina, i zastanawiać się jak stać się dzięki niemu bogatym, czy Bitcoin jest bańką spekulacyjną, czy Bitcoin pewnego dnia pozwoli pewnego dnia uwolnić ludzi od podatków, i tak dalej. Jest to przyjemne, ale mocno ogranicza Twoje zrozumienie. Zrozumienie szczegółów protokołu Bitcoin otwiera, z dotychczasową wiedzą niedostępne, nowe horyzonty. W szczególności, to podstawa dla zrozumienia wbudowanego języka skryptowego, który pozwala używać Bitcoina by tworzyć nowe typy instrumentów finansowych, takich jak smart contracts. Te z kolei mogą zostać użyte do tworzenia nowych rynków i otworzyć drogę do dalszych form kolektywnego zachowania. Porozmawiajmy o ciekawych zagadnieniach!

Język skryptowy w Bitcoinie i koncepcje jak „smart contracts” opiszę w przyszłych wpisach. Ten wpis koncentruje się na wyjaśnianiu niezbędnych szczegółów/podstaw działania protokołu Bitcoin. By zrozumieć ten wpis, musisz już posiadać wiedzę z zakresu kryptografii klucza publicznego, i powiązanej idei cyfrowego podpisu. Założę również, że znasz temat kryptograficznych funkcji skrótu. Nic z powyższych nie jest specjalnie trudne. Podstawowe idee mogą być nauczane w nauczane w kursach dla świeżaków przygotowujących do podjęcia studiów z dziedzin wiedzy takich jak matematyka czy informatyka. Pomysły te są piękno, więc jeśli nie jesteś z nimi zapoznany, rekomenduję przeznaczyć kilka godzin by się z nimi zapoznać.

To może wydawać się zaskakujące, że podstawy Bitcoina opierają się na kryptografii. Czyż nie jest Bitcoin walutą, a nie sposobem wysyłania tajnych wiadomości? Fakt jest taki, że problemy konieczne do rozwiązania przez protokół polegają na zabezpieczaniu transakcji – zapewnieniu, że ludzie nie mogą kraść od innych, podszywać się pod innych i tak dalej. W świecie materii z atomów utrzymujemy bezpieczeństwo przez urządzenia jak zamki, sejfy, sygnatury i skrytki/depozyty w bankach. W świecie bitów utrzymujemy ten rodzaj bezpieczeństwa dzięki kryptografii. I to jest powód, dla którego Bitcoin jest w swoim rdzeniu protokołem kryptograficznym.

Moją strategią w tym wpisie jest zbudowanie Bitcoina krok po kroku. Rozpocznę od wyjaśnienia bardzo prostej cyfrowej waluty, opartej na oczywistych pomysłach. Będziemy nazywać tą walutę Infocoin, by odróżnić ją od Bitcoina. Oczywiście, nasza pierwsza wersja Infocoina będzie miała wiele braków, więc będziemy przechodzili poprzez kolejne fazy rozwoju Infocoina, z każdą fazą wprowadzając jeden lub dwa nowe, proste pomysły. Po wielu takich fazach, otrzymamy protokół Bitcoin. Otrzymamy wymyślonego na nowo Bitcoina! Ta strategia jest wolniejsza niż gdybym wyjaśnił cały protokół Bitcoin od razu. Ale podczas, gdy Ty mógłbyś zrozumieć mechanikę Bitcoina w jednostkowym wyjaśnieniu, byłoby ciężko zrozumieć, dlaczego Bitcoin jest zaprojektowany w ten sposób. Zaletą wolniejszego, wielokrokowego podejścia w wyjaśnianiu jest to, że daje zdecydowanie mocniejsze zrozumienie każdego elementu Bitcoina.

Ostatecznie, powinienem wspomnieć, że jestem relatywnym nowicjuszem, jeżeli chodzi o Bitcoin. Śledziłem Bitcoin od 2011 (i kryptowaluty od późnych lat 90 ubiegłego wieku), ale poważne szczegóły protokołu zacząłem analizować na początku tego roku. Więc pragnę powiedzieć, że będę cenić wszystkie korekcje jakichkolwiek błędów z mojej strony. We wpisie również zawarłem pewną liczbę „problemów dla autora” – notatki dla siebie na temat pytań, które naszły mnie podczas pisania. Być może będą dla Ciebie ciekawe, ale równie dobrze możesz je pominąć całkowicie bez tracenia wątku głównego tekstu.

Pierwszy krok: podpisany list-zlecenie

Więc jak możemy zaprojektować cyfrową walutę?

Wstępnie, cyfrowa waluta brzmi niemożliwie. Przyjmijmy, że pewna osoba – nazwijmy ją Ala – ma pewną cyfrową walutę, którą chce wydać. Jeżeli Ala może użyć ciągu bitów, jako pieniędzy, jak możemy zapobiec by nie mogła używać tego samego ciągu znaków kolejny i kolejny raz, tak jakby posiadała nieskończone źródło pieniędzy? Albo, jeżeli możemy w jakiś sposób rozwiązać ten problem, jak możemy zapobiec by ktokolwiek inny nie mógł podrobić takiego ciągu bitów, i używać go by kraść od Ali?

To tylko dwa z wielu problemów, z którymi musimy sobie poradzić by używać informacji jako pieniędzy.

W pierwszej wersji Infocoina, spróbujmy znaleźć metodę, by Ala mogła używać ciągu bitów, jako (bardzo uproszczoną i niekompletną) formę waluty, w sposób w który daje jej przynajmniej minimalną ochronę przeciwko podrabianiu i kradzieży jej pieniędzy. Przyjmijmy, że Ala chce podarować innej osobie, Bobowi, infocoina. By tego dokonać, Ala pisze wiadomość „Ja, Ala, przyznaję Bobowi jeden infocoin”. Następnie dokonuje cyfrowego podpisu wiadomości używając prywatnego klucza kryptograficznego, i obwieszcza podpisany ciąg bitów całemu światu.

(Przy okazji, używam słowa Infocoin pisanego z wielkiej litery by nawiązać do protokołu i generalnej koncepcji, a słowa pisanego małymi literami „infocoin” by nawiązać do konkretnej porcji waluty (tak jak do konkretnego banknotu). Zwykle podobna konwencja, choć nie zawsze, występuje w świecie Bitcoina.)

To nie jest szczególnie wymyślna cyfrowa waluta! Ale posiada pewne zalety. Każdy w świecie (łącznie z Bobem) może użyć klucza publicznego Ali by zweryfikować czy rzeczywiście to Ala była osobą, która napisała wiadomość „Ja, Ala, przyznaję Bobowi jeden infocoin”. Nikt inny nie mógł stworzyć takiego ciągu bitów, więc Ala nie mogła później zaprzeczyć mówiąc: „Nie, I nie przyznałam Bobowi infocoina”. Więc protokół pozwala na ustalenie, że Ala naprawdę oświadczyła przyznanie Bobowi jednego infocoina. Ten sam fakt – nikt inny nie mógł stworzyć tak podpisanej wiadomości – również pozwala ustanowić dla Ali ograniczoną ochronę przed kradzieżą. Oczywiście, po tym jak Ala opublikowała jej wiadomość, dla innych osób staje się możliwe by duplikować wiadomość, więc w tym sensie kradzież jest możliwa. Ale nie jest możliwe to od początku. Te dwie własności – pozwolenie na ustalenie czy Ala rzeczywiście przyznała infocoiny, i ograniczona ochrona przed kradzieżą – są naprawdę znaczącymi właściwościami jego protokołu.

Nie powiedziałem (nie zupełnie), czym w ogóle są cyfrowe pieniądze. By napisać to wyraźnie: To wiadomości same w sobie, na przykład ciąg bitów reprezentujący cyfrowo podpisaną wiadomość „Ja, Ala, przyznaję Bobowi jeden infocoin”. Późniejsze protokoły będą podobne, w każdej następnej formie naszej cyfrowej waluty będą po prostu bardziej i bardziej złożone wiadomości [1].

Używanie numerów seryjnych by uczynić monety jednoznacznie identyfikowalne

Problem z pierwszą wersją Infocoina jest taki, że Ala może po prostu wysyłać Bobowi ciągle ten sam ciąg bitów. Przyjmijmy, że Bob odbiera 10 kopii podpisanych wiadomości „Ja, Ala, przyznaję Bobowi jeden infocoin”. Czy to oznacza, że Ala wysłał dziesięć różnych infocoinów? Czy może jej wiadomość została przypadkowo zduplikowana? Być może Ala próbowała oszukać Boba, by ten uwierzył, iż ona przyznała mu dziesięć różnych infocoinów, podczas gdy wiadomość udowadniała światu przyznanie tylko jednego infocoina.

Tym, co chcemy osiągnąć jest sposób by jednoznacznie odróżniać infocoiny od siebie. Potrzebują etykiety lub numeru seryjnego. Ala pisałaby wtedy wiadomość „Ja, Ala, przyznaję Bobowi jeden infocoin z numerem seryjnym 8770431”, i Bob (jak i ktokolwiek inny) mógłby wiedzieć, że został wysłany inny infocoin.

By ten sposób zadziałał potrzebujemy zaufane źródło numerów seryjnych dla infocoinów. Jednym ze sposobów by stworzyć takie źródło jest wprowadzenie banku. Ten bank miałby zapewniać numery seryjne dla infocoinów, śledzić kto posiada które infocoiny, i weryfikować czy strony w czasie transakcji nie oszukują.

Bardziej szczegółowo, przyjmijmy że Ala idzie do banku i mówi „Chcę pobrać jeden infocoin z mojego konta”. Bank redukuje saldo jej konta o jeden infocoin, i przypisuje jej nowy, nigdy nieużywany numer seryjny, powiedzmy 1234567. Wtedy, gdy Ala chce przesłać jej infocoin do Boba, ona podpisuje wiadomość „Ja, Ala, przyznaję Bobowi jeden infocoin, z numerem seryjnym 1234567”. Ale Bob nie akceptuje tak po prostu infocoina. Zamiast tego, kontaktuje się z bankiem, weryfikuje:

  • a) Czy infocoin z danym numerem należy do Ali
  • b) Ala nie wydała już wcześniej tego infocoina

Jeżeli oba warunki są spełnione, wtedy Bob mówi bankowi, że chce zaakceptować transfer infocoina, a bank aktualizuje swoje zapisy odnośnie infocoina. Infocoin należy od tej chwili do Boba i już dłużej nie należy do Ali.

Sprawienie, by wszyscy stali się kolektywnym bankiem.

Zaprezentowana ostatnio wersja protokołu brzmi obiecująco. Jednakże, my chcemy stworzyć coś bardziej ambitnego. Możemy wyeliminować bank całkowicie z protokołu. To wyraźnie zmienia naturę kryptowaluty. Oznacza to, że nie ma pojedynczej organizacji kontrolującej walutę. I wtedy, gdy pomyślisz o niewyobrażalnej władzy jaką dzierżyłby bank centralny – kontrola nad podażą pieniądza – to ogromna zmiana.

Pomysł polega na sprawieniu, by wszyscy w sieci P2P (kolektywnie) stali się bankiem. W szczególności, przyjmiemy że każdy używający Infocoina trzyma kompletny zbiór informacji o tym do kogo należą które infocoiny. Możesz myśleć o tym jako o ogólnodostępnym rejestrze przechowującym wszystkie informacje o wszystkich transakcjach w sieci Infocoin. Będziemy nazywali ten rejestr „block chain” (z ang. Łańcuch bloków [transakcji]), gdyż to w tak nazwanym elemencie Bitcoina znajduje się kompletny rejestr transakcji w sieci Bitcoin.

Teraz załóżmy, że Ala chce przesłać infocoin do Boba. Podpisuje wiadomość „Ja, Ala, przesyłam Bobowi jeden infocoin, z numerem seryjnym 1234567”, i dostarcza podpisaną wiadomość do Boba. Bob może użyć jego kopii łańcucha bloków by sprawdzić, czy rzeczywiście infocoin o podanym numerze seryjnym należy do Ali. Jeżeli należy, wtedy wysyła zarówno wiadomość Ali jak i jego wiadomość o akceptacji transakcji do całej sieci, i wszyscy w sieci Infocoin aktualizują ich kopie łańcucha bloków.

Obecnie mamy problem jak nadawane są numery seryjne, ale to jest wyjątkowo prosty problem do rozwiązania, z tego powodu odłożę jego rozwiązanie na później, w części poświęconej już Bitcoinowi. Trudniejszym problemem jest to, że protokół pozwala Ali oszukiwać przez wielokrotne wydawanie tych samych infocoinów (z ang. Double spending). Ala wysyła podpisaną wiadomość „Ja, Ala, przyznaję Bobowi jeden infocoin, z numerem seryjnym 1234567” do Boba, a jednocześnie podpisaną wiadomość „Ja, Ala, przyznaję Karolowi jeden infocoin, z [tym samym] numerem seryjnym 1234567” do Karola. Zarówno Bob jak i Karol używają ich kopii łańcucha bloków do zweryfikowania czy infocoin należy do Ali. Po warunkiem, że dojdzie do weryfikacji w prawie tej samej chwili (zanim będą mogli się nawzajem skomunikować), obaj zauważą, że tak, według ich kopii rejestru block chain infocoin należy do Ali. Z tego powodu obaj zaakceptują transakcję, jak również wyślą do sieci Infocoin ich wiadomość o akceptacji. I tutaj jest problem. W jaki sposób inni ludzie powinni aktualizować swoją kopię łańcucha bloków? Może nie być łatwego sposobu by zapewnić taki spójny, ogólnodostępny rejestr transakcji. I nawet gdy wszyscy mogą zgodzić się na spójny sposób aktualizacji ich kopii łańcucha bloków, ciągle istnieje problem czy to Bob czy Karol będzie oszukiwany.

Na pierwszy rzut oka zadanie Ali, która chce wielokrotnie wydać ten sam infocoin, wygląda na trudne. Jeżeli Ala wyśle wiadomość do Boba, Bob następnie może zweryfikować wiadomość, i powiedzieć wszystkim w sieci Infocoin (włączając w to Karola) by zaktualizowali swój łańcuch bloków. Gdy tak się stanie, Karol nie mógłby być oszukany przez Alę. Więc istnieje bardzo krótka chwila, przez którą Ala może wielokrotnie wydać ten sam infocoin. Tak czy inaczej jest to niepożądane by istniał w ogóle taki czas. Co gorsza, istnieją techniki które pozwoliłyby Ali wydłużyć ten czas. Mogłaby, na przykład, użyć analizy przepływu danych w sieci, by znaleźć moment w czasie, w którym Bob i Karol będą mieli duże opóźnienie w komunikacji. Albo mogłaby zrobić coś, by przerwać ich komunikację. Nawet jeśli może spowolnić komunikację między Karolem a Bobem chociażby o trochę, to pozwala na wielokrotne wydawanie w sposób dużo prostszy.

Jakie rozwiązanie możemy zaproponować, by uniemożliwić wielokrotne wydawanie? Oczywistym rozwiązaniem jest takie, w którym Ala wysyła Bobowi infocoina, a Bob nie próbuje zweryfikować transakcji samodzielnie. Zamiast tego, powinien wysłać wiadomość o możliwości transakcji z Alą do całej sieci użytkowników Infocoina, i poprosić ich o pomoc w rozstrzygnięciu czy transakcja jest prawowite. Jeśli kolektywnie zdecydują, że transakcja jest w porządku, wtedy Bob może zaakceptować infocoin, i wszyscy zaktualizują ich block chain. Taki typ protokołu może pomóc uniemożliwić wielokrotne wydawanie. Odtąd jeżeli Ala próbuje wydawać te same infocoiny zarówno do Boba i Karola, inne osoby w sieci zauważą to, powiedzą zarówno Bobowi i Karolowi, że jest problem z transakcją, i transakcja nie powinna dojść do skutku.

Bardziej szczegółowo, przyjmijmy że Ala chce przyznać Bobowi infocoin. Jak wcześniej, podpisuje wiadomość „Ja, Ala, przyznaję Bobowi jeden infocoin, z numerem seryjnym 1234567”, i dostarcza podpisaną wiadomość Bobowi. Jak wcześniej, Bob sprawdza poprawność transakcji, używając jego kopii łańcucha bloków, by upewnić się czy infocoin należy do Ali. Ale w tym momencie protokół jest zmodyfikowany. Bob nie akceptuje tak po prostu transakcji. Zamiast tego, wysyła wiadomość Ali do całej sieci. Inni uczestnicy sieci sprawdzają, czy Ala posiada ten infocoin. Jeśli tak, sieć wysyła informację „Tak, Ala posiada infocoin 1234567, może być zatem wysłany Bobowi”. Gdy wystarczająca ilość osób prześle wiadomość, każdy zaktualizuje swój block chain by pokazać że infocoin 1234567 teraz należy do Boba, a transakcja została zakończona sukcesem.

Ten protokół ma wiele nieprecyzyjnych elementów w obecnej fazie. Dla przykładu, co znaczy „wystarczająca liczba osób prześle wiadomość”? Co konkretnie oznacza „wystarczająca” w tym miejscu? Nie może to oznaczać każdego w sieci, gdyż nie możemy a priori zakładać, że wiemy jacy ludzie są w sieci Infocoin. Z tego samego powodu nie może oznaczać ustaloną, stałą część użytkowników sieci. Nie będziemy próbować skonkretyzować tych pomysłów w tej chwili. Zamiast tego, w następnym rozdziale określę poważny problem z tym podejściem, które powyżej zostało opisane. Naprawianie tego problemu będzie miało jednocześnie przyjemny skutek uboczny – uściśli powyższe pojęcia.

Dowód pracy

Załóżmy, że Ala chce wielokrotnie wydać swoje infocoiny w opisanym protokole, w którym weryfikacja opiera się o sieć. Mogłaby zrobić to przez przejęcie dużej części sieci Infocoin. Przyjmijmy, że używa zautomatyzowanego systemu by uruchomić dużą liczbę oddzielnych peerów w sieci, a reszta sieci nie wie, że są powiązane. Niech ich liczba wynosi miliard. Tak jak wcześniej, próbuje wielokrotnie wydać ten sam infocoin zarówno do Boba jak i Karola. Ale gdy Bob i Karol proszą sieć o walidację tranakcji, marionetki Ali zalewają sieć, ogłaszając do Boba, że pozytywnie zweryfikowali transakcję, i również do Karola. W ten sposób prawdopodobnie Bob i/lub Karol zostali oszukani. Istnieje sprytny sposób zapobiegania tego typu problemowi, używając pomysłu znanego pod pojęciem dowód pracy (z ang. Proof-of-work). Pomysł jest dla wielu nie intuicyjny i wymaga kombinacji dwóch pomysłów:

  • 1) By zweryfikowanie transakcji w sieci stało się obliczeniowo kosztowne (umyślne podwyższenie złożoności obliczeniowej)
  • 2) Wynagradzać użytkowników walidujących transakcję za ich pracę

Wynagrodzenie jest używane, by uczestnicy sieci próbowali walidować transakcje, nawet jeśli jest to obliczeniowo kosztowny proces. Zaletą zwiększenia kosztowności walidacji jest to, że walidacja nie może już być oszukana przez włączenie do sieci dużej ilości kontrolowanych przez atakującego członków sieci, ale przez całkowitą moc obliczeniową, którą mają do dyspozycji. Jak zobaczymy, w połączeniu ze sprytnym projektem będziemy mogli sprawić, że oszukiwanie wymagałoby by moc ta musiałaby być niewyobrażalnie wielka, co powoduje że byłoby niemożliwe lub przynajmniej nieekonomiczne by ją uzbierać.

To istota dowodu pracy. Ale by w pełni zrozumieć dowód pracy, musimy przejść poprzez szczegóły.

Przyjmijmy, że Ala wysyła do sieci wiadomość „Ja, Ala, wysyłam Bobowi jeden infocoin z numerem seryjnym 1234567”. Gdy inni członkowi sieci odbierają wiadomość, każdy dodaje ją do swojej kolejki, w której trzymane są wykonywane transakcje, o których zostali poinformowani, ale które nie zostały jeszcze zaakceptowane przez sieć. Na przykład inny użytkownik sieci, Dawid, może mieć następującą kolejkę realizowanych transakcji:

Ja, Tom, przyznaję Sue jeden infocoin, z numerem seryjnym 1201174.

Ja, Sydney, przyznaję Cynthii jeden infocoin, z numerem seryjnym 1295618.

Ja, Ala, przyznaję Bobowi jeden infocoin, z numerem seryjnym 1234567.

Dawid sprawdza jego kopię łańcucha bloków, i może sprawdzić czy każda transakcja jest poprawna. Chciałby pomóc przez rozesłanie wiadomości o poprawności transakcji do całej sieci.

Jednakże, zanim to zrobi, jako część protokołu walidacji Dawid musi rozwiązać ciężkie komputerowe puzzle – dowód pracy. Bez rozwiązania tych puzzli, reszta sieci nie zaakceptuje jego pozytywnej weryfikacji tranakcji.

Jakie puzzle musi Dawid rozwiązać? By to wyjaśnić, niech h będzie pewną funkcją skrótu (inaczej hashującą, miksującą) znana całej sieci – jest wbudowana w protokół. Bitcoin używa znanej funkcji SHA-256, ale jakakolwiek kryptograficznie bezpieczna funkcja skrótu będzie dobrze spełniać swoją rolę. Nadajmy kolejce transakcji Dawida etykietę l, by mieć nazwę do której będziemy móc się odnosić. Przypuśćmy, że Dawid dodał numer x (określany w języku angielskim jako nonce) do l i hashuje kombinację. Dla przykładu, jeżeli użyjemy l = „Hello, world!” (z ang. Witaj świecie. Oczywiście nie jest to lista transakcji, tylko ciąg użyty do celów zobrazowania działania) i noncję x = 0 wtedy (liczba wyjściowa jest w systemie szesnastkowym)

h("Hello, world!0") = 1312af178c253f84028d480a6adc1e25e81caa44c749ec81976192e2ec934c64

Puzzle, które Dawid musi rozwiązać – dowód pracy – polegają na znalezieniu takiej nonce x, by po dodaniu x do l i shashowaniu kombinacji wyjście zaczynało się od odpowiedniej liczby zer. Puzzle mogą być bardziej lub mniej trudne poprzez wymaganie mniejszej lub większej liczby zer na początku. Relatywnie prosty dowód pracy może wymagać trzech lub czterech zer na początku liczby, a bardziej złożony dowód pracy może wymagać zdecydowanie dłuższej sekwencji zer, powiedzmy 15 kolejnych zer. W obu przypadkach, powyższa próba do znalezienia nonce, gdy x =0, jest porażką, ponieważ wyjście z funkcji nie zaczyna się zerem. Próba z x = 1 również nie przynosi rezultatów.

h("Hello, world!1") = e9afc424b79e4f6ab42d99c81156d3a17228d6e1eef4139be78e948a9332a7d8

Możemy próbować po kolei kolejnych wartości dla nonce, x = 2,3,… W końcu, dla x = 4250 otrzymujemy:

h("Hello, world!4250") = 0000c3af42fc31103f1fdc0151fa747ff87349a4714df7cc52ea464e12dcd4e9

Ta nonce daje nam ciąg zaczynający się czterema zerami na początku wyjście z funkcji hashującej. To wystarczy, by rozwiązać prosty dowód pracy, ale nie jest wystarczające by rozwiązać bardziej trudny dowód pracy.

To, co powoduje trudność z rozwiązywaniem zagadki, jest fakt iż wyjście z kryptograficznej funkcji hashującej zachowuje się jak liczba losowa: zmiana na wejściu chociażby jednego bita powoduje całkowitą zmianę wartości wyjściowej, w sposób który ciężko przewidzieć. Więc jeśli chcemy mieć na wyjściu funkcji hashującej wartość zaczynającą się od 10 zer, Dawid będzie potrzebował średnio wypróbować ilość kombinacji różnych kombinacji dla x zanim znajdzie odpowiednią liczbę nonce. To bardzo wymagające zadanie, do rozwiązania którego potrzebna jest ogromna ilość mocy obliczeniowej.

Oczywiście, jest możliwe sprawienie by zagadka była bardziej lub mniej trudna do rozwiązania przez wymagania większej lub mniejszej ilości zer na wyjściu funkcji hashującej. W rzeczy samej, Bitcoin posiada dobrą kontrolę nad trudnością zagadki, przez używanie małej modyfikacji powyżej opisanej metody dowodu pracy. Zamiast wymagać odpowiedniej ilości zer, zagadka pracy w sieci Bitcoin opiera się na tym, by hash nagłówka bloku był mniejszy albo równy numerowi znanemu jako cel. Ten cel jest automatycznie dostosowywany by średnio walidacja bloków Bitcoina wymagała 10 minut.

(W praktyce istnieje tutaj spora losowość w tym jak długo sieć będzie walidować blok – czasem nowy blok jest walidowany w minutę lub dwie czasem może zabrać to nawet 20 minut lub dłużej. To dosyć prosta sprawa, by zmodyfikować protokół Bitcoin by czas walidacji miał mniejszy rozrzut wokół 10 minut. Zamiast rozwiązywać pojedynczą zagadkę, możemy wymagać by wiele zagadek zostało rozwiązanych; z odpowiednio ostrożnym projektowaniem jest możliwe zdecydowane zmniejszenie wariacji czasu podczas walidacji bloku transakcji.)

W porządku, przypuśćmy że Dawid ma szczęście i znalazł odpowiednią nonce, x. Świętujemy! (Będzie nagrodzony za znalezienie odpowiedniej liczby nonce, jak opisano poniżej). Wysyła blok transakcji, które zatwierdza do sieci, razem z odpowiednią, znalezioną wartością x. Inni uczestnicy w sieci Infocoin mogą zweryfikować, że x jest poprawnym rozwiązaniem zagadki będącej dowodem pracy. I wtedy oni aktualizują ich łańcuch bloków, by zawierał nowy blok transakcji.

By pomysł, że dowód pracy mógł w ogóle być zrealizowany, użytkownicy sieci muszą mieć zachętę do weryfikowania transakcji. Bez tej nagrody nie maja powodu by rozszerzać wartościową moc obliczeniową, by pomagać walidować transakcje innych osób. A jeśli użytkownicy sieci nie chcą rozszerzyć ich mocy obliczeniowej, wtedy cały system nie będzie działał. Rozwiązaniem tego problemu jest nagradzanie ludzi, którzy walidują realizowane transakcje. W szczególności, przyjmijmy że nagroda dla każdego kto skutecznie zweryfikuje transakcje, będzie opłacana za pomocą pewnej ilości infocoinów. Nagroda w infocoinach jest wystarczająco wysoka, jeśli daje zachętę do uczestnictwa w walidacji.

W protokole Bitcoin, ten proces walidacji nazywany jest kopaniem (z ang. Mining). Dla każdego bloku zweryfikowanych transakcji, osoba której udało się je zweryfikować, otrzymuje nagrodę w bitcoinach. Wstępnie, została ona ustalona na 50 bitcoinów. Po każdych 210,000 zweryfikowanych bloków (w przybliżeniu raz na cztery lata) nagroda jest dwa razy mniejsza (licząc w bitcoinach). Na tą chwilę zdarzyło się to tylko raz, i obecna nagroda wynosi 25 bitcoinów. To zmniejszanie o połowę będzie kontynuowane co około cztery lata aż do roku 2140. We wspomnianym roku nagroda spadnie poniżej 10-8 bitcoina za blok. Akutalnie 10-8 jest najmniejszą porcją Bitcoina, i jest nazywana satoshi. Więc w 2140 podaż przestanie rosnąć. Jednakże, to nie spowoduje eliminacji zachęty do walidacji transakcji. Bitcoin pozwala również ustanowić pewną kwotę podczas wysyłania transakcji jako opłata/prowizja transakcyjna, która idzie do górnika który pomaga zweryfikować transakcję. Na początku, gdy sieć Bitcoin dopiero powstawała, prowizje transakcyjne były zwykle ustawione na zero, ale gdy Bitcoin zdobył popularność, opłaty transakcyjne stopniowo rosły, aby teraz były pokaźnym dodatkiem do zachęty na poziomie 25 bitcoinów za blok.

Możesz myśleć o dowodzie pracy jako konkurencji wobec akceptowania transakcji. Każdy wpis o transakcji kosztuje odrobinę mocy obliczeniowej. Szansa na wygranie przez danego górnika konkurencji jest (w przybliżeniu, z pewnymi zastrzeżeniami) proporcjonalne do całkowitej mocy obliczeniowej którą posiada. Więc, na przykład, jeżeli górnik kontroluje jeden procent mocy obliczeniowej używanej do weryfikacji transakcji, wtedy mają w przybliżeniu jeden procent szansy na wygranie konkurencji (w hashowaniu tego konkretnego bloku, później będzie kolejna szansa i kolejna). Więc jeśli w konkurencji bierze udział dużo osób z dużą ilością mocy obliczeniowej, nieuczciwy górnik będzie miał małą szansę, by zakłócić proces weryfikacji, chyba że rozszerzy on ogromnie swoją moc obliczeniową.

Oczywiście, to że nieuczciwy górnik ma małą szansę na uszkodzenie łańcucha bloków, nie jest wystarczające by dać nam bezpieczną walutę. W szczególności, dalej nie omówiliśmy jak ostatecznie uporać się z problemem wielokrotnego wydawania.

Przeanalizuję wielokrotne wydawanie krótko. Zanim to zrobię, chcę powiedzieć jeszcze o jednym, dotychczas nie omówionym, istotnym szczególe Infocoina. Chcielibyśmy, by sieć Infocoin dokładnie zgadzała się co do kolejności w której przebiegają transakcje. Jeśli nie mamy tego typu porządkowania, wtedy w danym momencie może nie być możliwe rozstrzygnięcie do kogo należy dany infocoin. By móc rozwiązać ten problem będziemy potrzebowali by nowe bloki zawsze zawierały wskaźnik, do ostatniego zweryfikowanego już bloku w łańcuchu, dodany obok danych o zatwierdzonych transakcjach. (Wskaźnik jest obecnie po prostu hashem wcześniejszego bloku). Więc zwykle łańcuch bloków jest tylko liniowym łańcuchem bloków transakcji, ułożonych jeden po drugim, z ostatnimi blokami zawierającymi wskaźnik do bloku wykonanego bezpośrednio przed nim:

block chain przykład 1

Most recent block – ostatnio wygenerowany blok (najnowszy)

Od czasu do czasu, w łańcuchu bloków znajdzie się rozwidlenie. Może się ono zdarzyć, na przykład, jeśli dwóch górników zweryfikuje blok transakcji niemal jednocześnie – zarówno rozgłoszą sieci ich nowo zweryfikowane bloki, i niektórzy ludzie zaktualizują ich łańcuch bloków dodając blok od pierwszego, a pozostali od drugiego górnika:

block chain przykład 2

To powoduje dokładnie taki problem, którego chcemy uniknąć – nie jest dalej jasne w której kolejności transakcje zaszły, i może nie być jasne kto jest właścicielem których infocoinów. Szczęśliwi się składa, że istnieje prosty sposób usuwania rozwidleń. Zasada jest taka: jeśli zachodzi rozwidlenie, uczestnicy sieci Infocoin śledzą oba rozwiązania. Ale w pewnym momencie, poszczególni górnicy pracują by rozszerzyć tylko jeden z bloków, który jest dłuższy w łańcuchu bloków.

Przyjmijmy, dla przykładu, że mamy rozwidlenie w którym niektórzy górnicy otrzymają najpierw blok A, a niektórzy blok B. Ci górnicy, którzy otrzymają blok A będą kontynuować kopanie w oparciu o to rozwidlenie łańcucha, podczas gdy inni będą kopać w oparciu o rozwidlenie B. Załóżmy, że górnicy pracujący na rozwidleniu B jako pierwsi udanie zweryfikują następny blok realizowanych transakcji:

block chain przykład 3

Po tym, jak rozgłoszą to w sieci, górnicy pracujący nad rozwidleniem A zauważą to, że rozwidlenie B jest dłuższe, i przestawią się na pracę nad tym rozwidleniem. Szybko praca nad rozgałęzieniem A przestanie być wykonywana, i wszyscy będą pracować nad tym samym łańcuchem bloków, a blok A będzie ignorowany. Oczywiście, każda niezrealizowana transakcja w A będzie ciągle w kolejkach górników pracujących nad rozgałęzieniem B, z tego powodu wszystkie transakcje zostaną zrealizowane.

To samo stałoby się, gdyby to blok A został zweryfikowany – przez górnika, który pracował nad wydłużeniem rozwidlenia z blokiem A.

Nie ważne jaki potoczy się los, ten proces pozwala zapewnić iż łańcuch bloków jest w tej samej postaci akceptowany przez całą sieć Infocoin, w określonej kolejności. W przypadku Bitcoina, transakcja nie jest uznawana za potwierdzoną dopóki:

  • 1) Jest częścią bloku o najdłuższym rozwidleniu
  • 2) Powstało przynajmniej 5 bloków, które są nowsze niż blok w którym znajduje się transakcja

W tym przypadku powiemy, że transakcja ma 6 potwierdzeń. To daje sieci czas do wspólnego uzgodnienia dotyczącego kolejności bloków. Użyjemy tej strategii dla Infocina.

Po tym, jak zrozumieliśmy porządkowanie kolejności transakcji w czasie, przyjrzymy się co stanie się, gdy nieuczciwy uczestnik sieci próbuje wielokrotnie wydać te same infocoiny. Przyjmijmy, Ala próbuje wielokrotnie wydać infocoiny do Boba i Karola. Jednym z możliwych podejść jest dla niej próba walidacji bloku zawierającego obie transakcje. Przyjmując, że ma jeden procent całkowitej mocy obliczeniowej sieci, może okazjonalnie mieć szczęście i zweryfikować blok poprzez wykonanie dowodu pracy. Nieszczęśliwie dla Ali, wielokrotne wydawanie będzie natychmiastowo dostrzeżone przez innych uczestników sieci i odrzucone, pomimo rozwiązania dowodu pracy. Więc nie musimy się tego obawiać.

Bardziej poważnym problemem jest, jeśli roześle dwie oddzielne transakcje, w których przyznaje ten sam infocoin odpowiednio Bobowi i Karolowi. Może, na przykład, rozesłać jedną transakcję do podgrupy górników, a drugą do drugiej grupy górników, mając nadzieję że w ten sposób obie transakcje zostaną zweryfikowane. Na szczęście, w tym przypadku, jak już zobaczyliśmy, sieć potwierdzi jedną z tych transakcji, ale nie obie. Więc, dla przykładu, transakcja Boba może być zweryfikowana, w tym przypadku Bob będzie mógł być pewny tego, że transakcja zaszła. W tym czasie, Karol zauważy iż jego transakcja nie został potwierdzona, więc odrzuci ofertę Ali. Więc to nie jest już dalej problemem. Ala wiedząc to, w zasadzie nie ma po co nawet próbować oszukiwać.

Ważnym przypadek wielokrotnego wydawania zachodzi, gdy Ala = Bob, na przykład Ala próbuje wydać infocoin do Karola, który jednocześnie próbuje dać sobie. To brzmi jakby było łatwe do wykrycia i obsłużenia przez sieć, ale oczywiście, łatwo jest w sieci, dla jednej organizacji/osoby ustanowić, wiele identyfikatorów, więc taka możliwość musi być brana pod uwagę. W tym przypadku, strategia Ali to czekanie zanim Karol zaakceptuje infocoin, co stanie się po 6 krotnym potwierdzeniu transakcji w najdłuższym łańcuchu. Wtedy spróbuje rozwidlić łańcuch przed blokiem z transakcją z Karolem, dodając blok który zawiera transakcję w której ona płaci sama sobie.

block chain przykład 4

Nieszczęśliwie dla Ali, teraz będzie jej bardzo trudno dogonić najdłuższe rozwidlenie. Inni górnicy nie będą chcieli jej pomóc, odkąd oni będą pracować na najdłuższym rozwidleniem. I jeśli Ala nie jest w stanie rozwiązywać dowód pracy co najmniej tak samo szybko jak cała reszta sieci łącznie – w przybliżeniu oznacza to kontrolę ponad 50% mocy całej sieci – wtedy będzie coraz bardziej z tyłu w wyścigu rozwiązywania dowodu pracy. Oczywiście, może mieć szczęście. My możemy, na przykład, wyobrazić sobie scenariusz w którym Ala kontroluje jeden procent mocy obliczeniowej sieci, ale tak się przydarza, że Ala ma szczęście i bardzo szybko znajduje rozwiązanie dla 6 kolejnych zagadek – dowodów pracy, zanim reszta sieci znajdzie więcej bloków. W tym przypadku, będzie mogła przejąć kontrolę nad łańcuchem bloków. Tylko, że taki przypadek może się przydarzyć z prawdopodobieństwem prawdopodobieństwo . Bardziej ogólna analiza pokazuje, że prawdopodobieństwo iż Ali kiedykolwiek uda się dogonić resztę sieci jest pomijalnie małe, chyba że ma moc obliczeniową pozwalającą rozwiązywać zagadkę co najmniej tak szybko jak wszyscy inni górnicy razem wzięci.

Oczywiście, to nie jest rygorystyczna analiza bezpieczeństwa pokazująca, że Ala nie może wielokrotnie wydawać. To tylko argument dotyczący prawdopodobieństwo takiego zdarzenia. Oryginalne pismo dotyczące i wprowadzające Bitcoina, w prawdzie, nie zawiera rygorystycznej analizy bezpieczeństwa, a jedynie nieformalny argument, który tutaj przytoczyłem. Społeczność badaczy bezpieczeństwa ciągle analizuje protokół Bitcoin i próbuje znaleźć możliwe jego wady. Możesz zajrzeć do tych badań, i ja również wspomniałem o kilku powiązanych problemach w „Problemy dla autora” poniżej. Będąc uczciwym w tym miejscu myślę, że werdykt jak bezpieczny jest Bitcon jest ciągle niewydany.

Dowód pracy i pomysł na kopanie jest powodem do wielu pytań. Jak wielka powinna być nagroda do zachęcenia ludzi do kopania? Jak zmiana podaży infocoinów wpłynie na Infocoinową gospodarkę? Czy w przyszłości kopanie w sieci Infocoin skończy w rękach niewielkiej lub co gorsza pojedynczej organizacji? Jeśli będzie ich mało, czy nie zagraża to całej sieci? Możliwe, że opłaty transakcyjne zrównoważą problemy wynikłe z małej ilości nagrody za kopanie – nie spowoduje to niechcianego źródła problemów, i uczyni małych transakcji niemile widzianymi? To ważne pytania, ale cel tego artykułu jest inny niż odpowiadanie na nie. W przyszłych wpisach być może powrócę (w kontekście Bitcoina) do tych pytań. Na razie pozostańmy na drodze od zrozumienia jak protokół Bitcoin działa.

Problemy dla autora

  1. Nie rozumiem dlaczego wielokrotne wydawania nie może być uniemożliwione w prostszy sposób używając two-phase commit (dwu fazowe wykonywanie). Przyjmijmy, że Ala chce wielokrotnie wydać infocoin do zarówno Boba i Karola. Pomysł jest taki, że Bob i Karol mogliby rozesłać do sieci wiadomości z pytaniem: „Czy powinienem zaakceptować transakcję?”. Wtedy czekaliby oni pewien odcinek czasu – prawdopodobnie liczony w minutach – by usłyszeć jakikolwiek oznak sprzeciwu, które dowiodłyby że Ala próbuje wielokrotnego wydawania. Jeżeli nic takiego by nie usłyszeli (i jeśli nie byłoby sygnałów o problemach z utrzymaniem transmisji w sieci), wtedy zaakceptowaliby transakcje. Ten protokół potrzebuje być zabezpieczony przed atakami sieciowymi, ale wygląda mi na rdzeń dobrej alternatywnej idei. Jak dobrze takie rozwiązanie by działało? Jakie skutki uboczne i zalety miałoby to w porównaniu do pełnego protokołu Bitcoin?
  2. Wcześniej w sekcji wspomniałem, że istnieje prosta droga redukcji wariacji czasu potrzebnego do walidowania bloku transakcji. Jeżeli ta wariacja jest zbytnio zredukowana, wtedy tworzy się nowy sposób ataku. Przypuśćmy, że Ala próbuje rozwidlić łańcuch bloków w taki sposób, że: a) Jedno rozwidlenie zaczyna się blokiem, którym Ala wpłaca pieniądze samej sobie, natomiast drugie rozwidlenia zaczyna się blokiem w którym Ala płaci Bobowi; b) Oba bloki są rozgłoszone w [prawie] tym samym momencie, a górnicy podzielą się na dwie równe części próbujące rozwiązać nowy blok, jedna część z rozwidleniem A, druga B c) Ala próbuje użyć swojej mocy obliczeniowej do prób utrzymania rozwidlenia na blisko takim samym poziomie, kopiąc w tym bloku, który staje się krótszy – jest to w normalnych warunkach trudne zadanie, ale staje się wiele prostsze jeżeli odchylenie standardowe czasu walidacji jest zdecydowanie mniejsze niż opóźnienie sieci d) Po tym, jak po obu stronach rozwidlenia dokonana została nadbudowa przez 5 kolejnych bloków, Ala rzuca swą moc obliczeniową by zwiększyć prawdopodobieństwo, że to transakcja do Karola została potwierdzona e) Po tym, jak transakcja do Karola została potwierdzona, wtedy rzuca swoją moc do drugiego rozwidlenia i próbuje dogonić dłuższy łańcuch. Ta strategia balansowania będzie miała niewielką szansę sukcesu, lecz o wiele większą niż w przypadku normalnego protokołu Bitcoin, z dużą wariacją czasu potrzebnego do weryfikacji. Czy istnieje możliwość ominięcia tego problemu?
  3. Przyjmijmy że oprogramowanie do kopania zawsze odkrywa nonce rozpoczynając od x=0, następnie x=1;x=2;…. Jeżeli tak robią wszyscy, albo nawet wyraźna część, kopiący w sieci Bitcoin, wtedy tworzy to podatność na atak. Dosłownie, istnieje możliwość dla kogoś do zwiększenia jego szans w rozwiązywaniu dowodu pracy tylko przez rozpoczęcie od innej, większej liczby nonce. Bardziej ogólnie, może być możliwe dla atakujących wykorzystanie symetrycznych wzorców w sposobie, w którym kopiący odkrywają przestrzeń liczb nonce. Bardziej ogólnie, w analizie tej sekcji niebezpośrednio założyłem pewien rodzaj symetrii pomiędzy kopiącymi. W praktyce będą asymetrie i przez to analiza bezpieczeństwa będzie musiała brać pod uwagę te asymetrie.

Bitcoin

Nie zajmujmy się już projektowaniem Infocoina, ale opisem aktualnej wersji protokołu Bitcoin. W protokole jest kilka nowych pomysłów, ale z jednym wyjątkiem (opisanym poniżej) są głównie oczywistymi modyfikacjami protokołu Infocoin.

By używać Bitcoina w praktyce, najpierw musisz zainstalować program-portfel na swoim komputerze. By dać Tobie obraz jak to wygląda, poniżej zamieszczam zrzut ekranu ukazujący program MultiBit. Możesz zobaczyć saldo konta po lewo – 0.06555555, około 70 dolarów przy kursie wymiany, w którym tworzyłem zrzut ekranu – a po prawej dwie ostatnie transakcje, którymi przesłano mi te bitcoiny.

Tak wygląda portfel - program MultiBit

Przyjmując, że jesteś handlowcem, który otworzył sklep w Internecie, i zdecydował się pozwolić ludziom płacić za pomocą sieci Bitcoin. To, co musisz zrobić to powiedzieć swojemu programowi-portfelowi by wygenerował adres Bitcoin. W odpowiedzi, wygeneruje to parę kluczy: prywatny i publiczny, a wtedy zahashuje Twój klucz publiczny i w ten sposób uformuje Twój adres w sieci Bitcoin:

Tak wygląda portfel - program MultiBit

Wtedy Ty wysyłasz Twój adres Bitcoin do osób, które chcą kupować od Ciebie. Możesz to zrobić w emailu, albo nawet opublikować go publicznie na stronie internetowej. Jest to bezpieczne, gdyż adres to tylko hash klucza publicznego, który bez utraty bezpieczeństwa można opublikować światu. (Powrócę później do tematu dlaczego adres Bitcoin jest hashem, a nie kluczem publicznym.)

Osoba, które chce Tobie zapłacić generuje transakcję. Spójrzmy na dane z aktualnej transakcji opiewającej na kwota bitcoinów. To co przedstawiłem poniżej jest bardzo podobne do surowych danych. Jest zmienione na trzy sposoby:

  • a) Dane zostały zdeserializowane
  • b) Dodano numery linii by móc się do nich odnosić
  • c) Skróciłem wiele hashy i kluczy publicznych, przez wstawienie pierwszych 6 cyfr w zapisie szesnastkowym, gdy w rzeczywistości są dłuższe.

Oto dane:

1.  {"hash":"7c4025...",
2.  "ver":1,
3.  "vin_sz":1,
4.  "vout_sz":1,
5.  "lock_time":0,
6.  "size":224,
7.  "in":[
8.    {"prev_out":
9.      {"hash":"2007ae...",
10.      "n":0},
11.    "scriptSig":"304502... 042b2d..."}],
12. "out":[
13.   {"value":"0.31900000",
14.    "scriptPubKey":"OP_DUP OP_HASH160 a7db6f OP_EQUALVERIFY OP_CHECKSIG"}]}

Przyjrzyjmy się danym linia po linii. Linia pierwsza zawiera hash reszty transakcji, 7c4025…, wyrażony w liczbach szesnastkowych. Jest używany jako identyfikator dla transakcji.

Linia 2 mówi nam, że ta transakcja w wersji 1 protokołu Bitcoin.

Linie 3 i 4 mówią nam, że transakcja ma odpowiednio: jedno wejście i jedno wyjście. Omówią później transakcje z większą ilością wejść i wyjść i dlaczego jest to użyteczne.

Linia 5 zawiera wartość dla lock_time, który może być do kontroli tego, kiedy transakcja ma być sfinalizowana. Dla większości dzisiaj wykonywanych transakcji w sieci Bitcoin lock_time jest ustawione na 0, co oznacza że transakcja jest finalizowana natychmiast.

Linia 6 mówi nam o rozmiarze (w bajtach) transakcji. Warto zanotować, że nie jest to związane z ilość przesyłanych jednostek pieniężnych. Na omówienie tego przyjdzie czas.

Linie od 7 do 11 definiują wejście transakcji. W szczególności, linie od 8 do 10 mówią nam, iż wejście ma być wzięte z wyjścia wcześniejszej transakcji, o podanym hashu, który jest wyrażony w numerze o notacji szesnastkowej jako 2007ae…. Zapis n=0, że to będzie dotyczyło pierwszego wyjścia tej transakcji; omówię później jak działają wielokrotne wejścia i wyjścia transakcji, więc nie zastanawiaj się nad tym teraz. Linia 11 zawiera sygnaturę osoby wysyłającej walutę, 304502…, po której występuje spacja, a następnie odpowiedni klucz publiczny, 04b2d…. Znów, liczby są w formacie szesnastkowym.

Jedna z rzeczy wartych zanotowania o wejściu nie ma tutaj niczego dokładnie określającego jaka ilość bitcoinów z poprzedniej transakcji powinna zostać wydana w tej transakcji. Wszystkie bitcoiny z n=0-wego wyjścia z poprzedniej transakcji zostały wydane. Więc, dla przykładu, jeżeli n=0-we wyjście wcześniejszej transakcji było równe dwóm bitcoinom, wtedy 2 bitcoiny będą wydane w tej transakcji. Wygląda to na niewygodne ograniczenie – jak próba kupowania chleba za pomocą 20 dolarowego banknotu, i brak możliwości rozmienienia banknotu. Rozwiązaniem jest, oczywiście, posiadanie mechanizmu dla zapewnienia wymiany. To może być wykonane używając transakcji z wieloma wejściami i wyjściami, które będziemy omawiali w następnej sekcji.

Linie od 12 do 14 opisują nasze wyjście z transakcji. W szczególności, linia 13 mówi nam o wartości na wyjściu, 0.319 bitcoinów. Linia 14 jest trochę skomplikowana. Główną rzeczą wartą podkreślenia jest ciąg a7db6f… który jest adresem Bitcoin odbiorcy środków (zapisany w postaci heksadecymalnej). Linia 14 jest aktualnie wyrażeniem w Bitcoinowym języku skryptowym. Nie zamierzam opisać tego języka w tym wpisie, ważną rzeczą jest to że a7db6f… jest adresem Bitcoin.

Możesz teraz zauważyć, przy okazji, jak Bitcoin odpowiada na problem z wcześniejszej sekcji: Skąd pochodzą numery seryjne bitcoinów? Rolę numerów seryjnych spełniają hashe transakcji. W transakcji powyżej, dla przykładu, odbiorca otrzymuje 0.319 bitcoinów, które wychodzą z pierwszego wyjścia wcześniejszej transakcji z hashem 2007ae… (linia 9). Jeśli wrócisz i spojrzysz w łańcuch bloków szukając tej transakcji, zobaczyłbyś że wyjście przychodzi z wcześniejszej transakcji. I tak dalej.

Z używania hashy transakcji zamiast numerów seryjnych wynikają dwie właściwości. Po pierwsze w Bitcoinie nie potrzeba trwałych „monet”, jest tylko długi łańcuch transakcji. Po drugie, przez tego rodzaju rozwiązanie nie potrzebny jest żaden zcentralizowany autorytet wydający numery seryjne. Zamiast tego, numery seryjne mogą być samo-generowalne, po prostu przez hashowanie transakcji.

Fakt jest taki, że możliwe jest podążaniem po łańcuchu bloków transakcji wstecz i prześledzenie historii. Ostatecznie, proces ten musi zostać przerwany. To może się stać w jeden z dwóch sposobów. Pierwszy to znalezienie pierwszej dokonanej transakcji, zawartej w tak zwanym Genesis block (Blok genezy, stworzenia? Pierwszy stworzony blok, po angielsku pierwsza księga Biblii zwie się The Book of Genesis). To specjalna transakcja, nie posiadająca wejść, ale 50 bitcoinów na wyjściu. W innych słowach, ta transakcja ustanawia początkową podaż bitcoinów. Pierwszy Blok jest traktowany różnie przez różne klienty sieci Bitcoin, i nie będę się wdawał w szczegóły, pomimo że jest podobny do powyżej omówionej transakcji. Możesz zobaczyć zdeserializowane dane tutaj, a poczytać o tym bloku tutaj.

Drugą możliwością jest podążanie wstecz po łańcuchu, aż dotrzesz do tak zwanej transakcji coinbase transaction. Z wyjątkiem pierwszego bloku, każdy blok transakcji w łańcuchu bloków zaczyna się od specjalnej transakcji coinbase. To transakcja, w której górnik za poprawne zwalidowanie bloku dostaje nagrodę. Transakcja ta używa podobnego, ale nie identycznego formatu w porównaniu do omówionego przykładu. Nie będę opisywał szczegółów formatu, ale jeśli chcesz zobaczyć przykład, spójrz tutaj. Możesz również poczytać o transakcjach coinbase tutaj.

Coś o czym nie mówiłem wcześniej precyzyjnie – co dokładnie jest cyfrowo podpisywane przez sygnaturę w linii 11. Oczywistym jest, że ten który płaci musi podpisać całą transakcję (niezależnie od hashu transakcji, który oczywiście musi być wygenerowany później). Obecnie, to nie jest przeprowadzane – niektóre części transakcji są omijane. To powoduje, że niektóre części transakcji są podatne na atak np. mogą być zmienione po podpisaniu. Jednakże, ta podatność na atak nie zawiera części takich jak ilość bitcoinów na którą opiewa transakcja, adres odbiorcy i nadawcy. Wspomniane części są podpisywane i nie mogą być zmienione później. Muszę przyznać nie wczytywałem się w szczegóły tej kwestii protokołu Bitcoin. Zebrałem informacje, że podatność ta jest dyskutowana przez deweloperów społeczności Bitcoina, i podjęto wysiłki by zniwelować lub wyeliminować te podatności.

Transakcje z wieloma wejściami i wyjściami

W ostatniej sekcji opisałem jak działają transakcje z pojedynczymi wejściami i wyjściami. W praktyce, często jest bardzo potrzebne stworzenie transakcji Bitcoin z wieloma wejściami lub wyjściami. O tym dlaczego powiem później. Najpierw spójrzmy na dane z aktualnej transakcji:

1. {"hash":"993830...",
2. "ver":1,
3. "vin_sz":3,
4.  "vout_sz":2,
5.  "lock_time":0,
6.  "size":552,
7.  "in":[
8.    {"prev_out":{
9.      "hash":"3beabc...",
10.        "n":0},
11.     "scriptSig":"304402... 04c7d2..."},
12.    {"prev_out":{
13.        "hash":"fdae9b...",
14.        "n":0},
15.      "scriptSig":"304502... 026e15..."},
16.    {"prev_out":{
17.        "hash":"20c86b...",
18.        "n":1},
19.      "scriptSig":"304402... 038a52..."}],
20.  "out":[
21.    {"value":"0.01068000",
22.      "scriptPubKey":"OP_DUP OP_HASH160 e8c306... OP_EQUALVERIFY OP_CHECKSIG"},
23.    {"value":"4.00000000",
24.      "scriptPubKey":"OP_DUP OP_HASH160 d644e3... OP_EQUALVERIFY OP_CHECKSIG"}]}

Omówmy linia po linii. Format jest bardzo podobny do transakcji pojedynczego wejścia i wyjścia, więc omówię ten format szybko.

Linia 1 zawiera hash reszty transakcji. Jest używany jako identyfikator transakcji.

Linia 2 mówi o tym, że transakcja jest w wersji 1 protokołu Bitcoin.

Linie 3 i 4 mówi o tym, że transakcja ma odpowiednio trzy wejścia i dwa wyjścia.

Linia 5 zawiera lock_time. Jak we wcześniejszym przykładzie jest ustawiona na 0, co oznacza że transakcja będzie sfinalizowana natychmiast.

Linia 6 mówi o wielkości transakcji w bajtach.

Linie od 7 do 19 definiują listę wejść transakcji. Każde odpowiada do wyjścia poprzedniej transakcji Bitcoin.

Pierwsze wejście jest opisane w liniach od 8 do 11.

W szczególności, od linie od 8 do 10 mówią nam, że wejście jest wzięte z n=0-wego wyjścia poprzedniej transakcji identyfikowanej hashem 3beabc…. Linia 11 zawiera sygnaturę, po niej występuje spacja, a następnie klucz publiczny osoby wysyłającej bitcoiny.

Linie od 12 do 15 definiują drugie wejście, o podobnym formacie do tego z liń 8..11. Linie od 16 do 19 definiują trzecie wejście.

Linie od 20 do 24 definiują listę zawierającą dwa wyjścia z każdej transakcji.

Pierwsze wyjście jest zdefiniowane w liniach 21 i 22. Linia 21 mówi, że wartość na wyjściu wynosi 0.01068000 bitcoina. Jak wcześniej, linia 22 jest wyrażeniem w języku skryptowym Bitcoina. Najważniejszym elementem do zauważenia jest ciąg e8c30622…, które jest adresem Bitcoin odbiorcy środków.

Drugie wyjście jest zdefiniowane w liniach 23 i 24, z podobnym formatem do pierwszego wyjścia.

Jedyną widoczną dziwnością w tym opisie jest to, że każde wyjście ma przypisaną wartość Bitcoin, natomiast wejścia nie. Oczywiście, te wartości odpowiednich wejść mogą być znalezione sprawdzając odpowiednie wyjście wcześniejszych transakcjach. W standardowej transakcji Bitcoin, suma wszystkich wejść musi być co najmniej tak duża jak suma wszystkich wyjść. (Jedynym wyjątkiem jest Pierwszy Blok i transakcje coinbase, które dodają do ogólnej puli pewną ilość bitcoinów.) Jeżeli wejście po zsumowaniu jest większe niż suma wszystkich na wyjściu, wtedy różnica jest używana jako prowizja transakcyjna. Jest ona płacona do tego górnika, któremu uda się zwalidować blok zawierający tą transakcję.

To wszystko jeżeli chodzi o transakcje z wieloma wejściami i wyjściami. Są bardzo prostą modyfikacją transakcji pojedynczego wejścia-wyjścia.

Jednym z fajnych zastosowań transakcji z wieloma wejściami i wyjściem jest pomysł na rozmienianie. Przyjmijmy, że chcę wysłać Tobie 0.15 bitcoina. Mogę to zrobić wydając 0.2 bitcoina, którego otrzymałem w poprzedniej transakcji. Oczywiście, nie chcę wysłać Ci całe 0.2 bitcoina. Rozwiązaniem jest wysłanie tobie 0.15 bitcoin, i wysłanie 0.05 bitcoina do mojego adresu. Te 0.05 będą służyły do rozmienia transakcji Bitcoin. Oczywiście, różni się to od rozmieniania pieniędzy w sklepie, w tym przypadku przecież płacisz sam sobie, ale ogólny, szerszy pomysł jest podobny.

Wnioski

To zakończenie podstawowego opisu głównych idei stojących u fundamentów protokołu Bitcoin. Oczywiście, ominąłem wiele szczegółów – to nie jest oficjalna specyfikacja. Jednakże opisałem główne idee używane w najbardziej typowych zastosowaniach.

Jako, że zasady Bitcoina są proste i łatwe do zrozumienia, to nie oznacza że łatwo jest zrozumieć konsekwencje tych zasad. O Bitcoinie można powiedzieć wiele więcej, i prześledzę wiele z tych zagadnień w następnych wpisach. Obecnie, odniosę się do kilku niewspomnianych spraw.

Jak anonimowy jest Bitcoin? Wiele osób twierdzi, że Bitcoin może być używany anonimowo. Te twierdzenia zaprowadziły do zorganizowania takich miejsc jak Silk Road (i wielu sukcesorów), które specjalizują się w handlu nielegalnymi dobrami. Jednakże, twierdzenie że Bitcoin jest anonimowy to mit. Łańcuch bloków jest ogólnodostępny, co oznacza że jest możliwe dla każdego sprawdzenie każdej kiedykolwiek dokonanej transakcji w sieci Bitcoin.

Pomimo tego, że adresy Bitcoin nie są natychmiastowo powiązywalne z identyfikatorami z prawdziwego świata (imię, nazwisko itd.), naukowcy zajmujący się techniką cyfrową wykonali kawał roboty odkrywając jak de-anonimizować „anonimowe” sieci społecznościowe. Łańcuch bloków jest bajkowym celem dla tych technik. Byłbym bardzo zdziwiony, gdyby zdecydowana większość użytkowników Bitcoina nie była identyfikowalna z dużym stopniem pewności w prosty sposób w bliskiej przyszłości. Stopień pewności nie byłby wystarczająco wysoki, by postawić kogoś w stan oskarżenia, ale wystarczająco duży by zidentyfikować prawdopodobne cele. Ponadto, identyfikacja byłaby możliwa przez cały czas trwania sieci Bitcoin, co oznacza że osoba która kupiła narkotyki z Silk Road w 2011 roku byłaby ciągle identyfikowalna w, powiedzmy, 2020 roku. Te techniki deanonimizacji są szeroko znane badaczom bezpieczeństwa IT jak i również dla NSA. Nie byłbym zdziwiony, gdyby NSA i inne agencje już teraz nie zdeanonimizowały wielu użytkowników. To ironia losu, że Bicoin jest często jest reklamowany jako anonimowy. Nie jest. Bitcoin jest za to prawdopodobnie najbardziej otwartym i transparentnym instrumentem finansowym, jaki widział świat.

Czy możesz stać się bogaty za sprawą Bitcoina? Być może. Tim O’Reilly pewnego razu powiedział: „Pieniądze są jak paliwo w samochodzie – musisz na nie uważać albo skończysz na poboczu drogi – ale dobrze żyte życie nie jest podróżą po stacjach benzynowych!” Wiele osób zainteresowało się Bitcoinem, których życiową misją wydaje się być podróż do rzeczywiście dużej stacji paliw. Muszę przyznać, że bardzo mnie to dziwi. To, co według mnie, jest bardziej interesujące jest myślenie o Bitcoinie i innych kryptowalutach jako drodze do tworzenia nowych form kolektywnego zachowania. To intelektualnie fascynujące, oferuj wiele cudownych, nowych możliwości, jest społecznie wartościowe, i może również przynieść trochę pieniędzy. Jeśli jednak zarobienie pieniędzy jest Twoim głównym celem, to myślę że inne sposoby na jego osiągnięcie są lepszym pomysłem.

Szczegóły, które pominąłem: Pomimo, że ten wpis miał opisać główne idee stojące za Bitcoinem, jest wiele szczegółów które ominąłem. Jednym jest sztuczka oszczędzająca miejsce używana przez protokół oparta na strukturze danych znanej jako drzewo Merkla/Merklego. To szczegół, ale okazały szczegół, i warty poznania, jeśli lubisz czytać o tego typu rozwiązaniach. Możesz przeczytać przegląd z oryginalnego referatu o Bitcoinie. Po drugie mało pisałem o sieci Bitcoin– tematy takie jak sieć radzi sobie z atakami DOS, jak węzły dołączają i opuszczają sieć i tak dalej. To fascynujący temat, ale równocześnie zawiera mnóstwo szczegółów, więc go ominąłem. Możesz o tych tematach poczytać w powyższych linkach.

Skrypty w protokole Bitcoin: W tym wpisie wyjaśniłem Bitcoin jako formę cyfrowej, internetowej waluty. Ale to tylko mała część większej i bardziej interesującej historii. Jak widzieliśmy, każda transakcja w siecie Bitcoin ma przydzielony skrypt w Bitcoinowym języku programowania. Skrypty, które widzieliśmy we wpisie opisują prostą transakcję jak „Ala przyznaje Bobowi 10 bitcoinów”. Ale język skryptowy może być również użyty do wyrażenia dużo bardziej skomplikowanych transakcji. Innymi słowy, Bitcoin to programowalna waluta. W następnych wpisach omówię język skryptowy i jak można użyć skryptów jako platforma do eksperymentowania z całym zbiorem zadziwiających instrumentów finansowych.

Dziękuję za uwagę. Jeśli zaciekawił Cię ten esej, być może zainteresuje Cię też pierwszy rozdział mojej książki, którą niedługo wydam o sieciach neuronowych i głębokim uczeniu, i rozważ wsparcie tej książki przez Indiegogo. Możesz również mnie zasubskryptować na Twitterze.

Przypisy

[1] W Stanach Zjednoczonych pytanie „Czy pieniądze to forma mowy?” to ważne zagadnienie prawne, ponieważ Konstytucja Stanów Zjednoczonych chroni wolność słowa. W mojej opinii (prawnie niedoinformowanej) cyfrowe waluty powodują, że odpowiedzenie na to pytanie jest jeszcze trudniejsze. Jak zobaczymy, protokół Bitcoin jest naprawdę sposobem nad powiedzenie całemu światu (albo przynajmniej reszcie sieci Bitcoin) „Zamierzam dać taką a taką ilość bitcoinów takiej a takiej osobie” w sposób, któremu później ekstremalnie trudno zaprzeczyć. Dla osób bez odpowiedniej wiedzy taka mowa wygląda bardziej na przemowę niż wymianę miedzianych monet.

SSH na telefonach z Javą (J2ME).

$
0
0

Na początku mojej przygody z GNU/Linux zapragnąłem kontroli nad systemem poprzez protokół SSH z poziomu kilkuletniego telefonu z obsługą Javy (J2ME). Jeden z Forumowiczów polecił mi aplikację pod nazwą MidpSSH.

Komendy są 'odbierane' chwilę po tym, jak zostały wysłane z telefonu, nie ma bugów i innych wad - przynajmniej ja niczego się nie dopatrzyłem. Aplikacja umożliwia dostosowanie kilku podstawowych ustawień do własnych wygód. W opcjach konfiguracyjnych przykładowo znajdziemy: - możliwość ustawienia sobie proxy [HTTP proxy] i jego pracy / typu pracy [HTTP Proxy Mode] - typ Terminala - coś takiego jak "Polling I/O" - orientację wyświetlanego obrazu - rozmiar / typ czcionki wyświetlanej na ekranie - wyborem pomiędzy SSH1 a SSH2 na czele.

Aplikacja jest dostępna na telefony BlackBerry.

To byłoby na tyle. Na koniec zamieszczam trzy linki: midpSSH Wątek na forum. Aplikacja podobna do midpSSH, ale przeznaczona na Symbiana.

Może komuś się jeszcze przyda. Pytania i sugestie tutaj (forum), lub przez XMPP/Jabber - pavlo950@linux.pl

Uruchamianie Firefoksa w osobnej przestrzeni nazw zasobów sieciowych (osobna kopia stosu sieciowego) i przekierowanie całego ruchu poprzez sieć Tor

$
0
0

W dalszej części będę często wyrażenie "przestrzeń nazw zasobów sieciowych" zastępował skrótem ns (z ang. namespace).

Cel:

  • Firefox nie może sprawdzić Twojego adresu IP i MAC za pomocą wywołań systemowych
  • Wszystkie pakiety TCP i DNS z /do Firefoksa przechodzą przez wirtualny interfejs sieciowy powiązany z instancją Tora
  1. Tworzymy ns

    sudo ip netns add afirefox

  2. Tworzymy parę veth0veth1

    sudo ip link add veth0 type veth peer name veth1

  3. Wrzucamy veth1 do ns:

    sudo ip link set veth1 netns afirefox

  4. Konfigurujemy veth1 w ns:

    sudo ip netns exec afirefox ifconfig veth1 192.168.0.1/24 up

  5. Konfigurujemy veth0:

    sudo ifconfig veth0 192.168.0.2/24 up

  6. Ustawiamy routing w ns. Następnie będzie go można go sprawdzić komendą od drugiej linijki:

    sudo ip netns exec afirefox ip route add default via 192.168.0.2

    sudo ip netns exec afirefox ip route show

    default via 192.168.0.2 dev veth0

    192.168.0.0/24 dev veth0 proto kernel scope link src 192.168.0.1

  7. Włączamy loopback w ns:

    sudo ip netns exec afirefox ifconfig lo up

  8. (Krok opcjonalny, dla dodaniach swojego rodzaju checkpointu). Teraz za pomocą iptables na hoście przesyłamy przez maskaradę:

    su -c 'echo 1 > /proc/sys/net/ipv4/ip_forward'

    sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

    sudo iptables -A FORWARD -i eth0 -o veth0 -m state --state RELATED,ESTABLISHED -j ACCEPT

    sudo iptables -A FORWARD -i veth0 -o eth0 -j ACCEPT

  9. Ustawiamy adresy DNS np. poprzez /etc/resolv.conf To ważne, gdyż jeśli mamy DNS na hoście automatycznie zapewniany przez jakiś automat, to środowisko w ns nie będzie mogło się z nim skomunikować

    nameserver 87.118.100.175

    nameserver 77.109.138.45

Po tym wszystkim powinniśmy móc połączyć się z Internetem z wewnątrz ns (uruchamiamy przez su, bo normalnie ruchomilibyśmy firefoksa spod konta roota).

sudo ip netns exec afirefox su -c 'firefox' uzytkownikubuntu

  1. Teraz konfigurujemy, by wszystko szło przez tora z wewnątrz ns. Trzeba będzie usunąć regułki z iptables z hosta, którymi w punkcie 8 ustanowiliśmy maskaradę (NAT). Czyścimy tablicę prerouting i postrouting

    sudo iptables -t nat -F

  2. Musimy skorzystać z pewnej funkcji klienta sieci Tor zwanej Transparent Proxy. Backupujemy stary plik konfiguracji /etc/tor/torrc

mv /etc/tor/torrc /etc/tor/torrc.kopia

W pliku /etc/tor/torrc ustawiamy:

 SocksPort 0 # Wyłączamy zwykłe proxy socks
 TransListenAddress 192.168.0.2:9040
 TransPort 9040
 DNSListenAddress 192.168.0.2:53
 DNSPort 53
 AutomapHostsOnResolve 1
 VirtualAddrNetwork 10.192.0.0/16 # tutaj musimy uważać, by ta podsieć nie pokrywała się z  jakąkolwiek podłączoną do naszego komputera o tej samej numeracji. Tor będzie mapował adresy domen .onion na te adresy ip i jeśli prześlemy ruch przez tora z adresem docelowym o tym ip to połączy nas ze stroną .onion.
  1. Restartujemy Tora, by działał na podstawie nowej konfiguracji:

/etc/init.d/tor restart

  1. Wyłączamy ip forwarding i ustawiamy w iptables przesyłanie całego ruchu po tcp i dns (53 port UDP) do klienta Tor, przy okazji ustanawiając prosty firewall:

    su -c 'echo 0 > /proc/sys/net/ipv4/ip_forward'

    sudo /sbin/iptables -t nat -A PREROUTING -i veth0 -p udp --dport 53 -j DNAT --to-destination 192.168.0.2:53

    sudo /sbin/iptables -t nat -A PREROUTING -i veth0 -p tcp -j DNAT --to-destination 192.168.0.2:9040

    sudo iptables -F INPUT

    sudo iptables -I INPUT 1 -i lo -j ACCEPT

    sudo iptables -I INPUT 2 -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT

    sudo /sbin/iptables -I INPUT 3 -i veth0 -p udp --dport 53 -j ACCEPT

    sudo /sbin/iptables -I INPUT 4 -i veth0 -p tcp --dport 9040 -j ACCEPT

    sudo /sbin/iptables -I INPUT 5 -i veth0 -j REJECT

    sudo iptables -P INPUT DROP

    sudo /sbin/iptables -F FORWARD

    sudo /sbin/iptables -P FORWARD DROP

  2. W końcu uruchamiamy Firefoksa z wewnątrz oddzielnej przestrzeni nazw sieciowych, z której wyjście kierowane jest przez Tora:

sudo ip netns exec afirefox su -c 'firefox' nazwauzytkownika

Kontener mkv

$
0
0

Wiele osób posiada pliki video i ci co uczą się angielskiego, czy innych języków, niezbyt przepadają za słuchaniem polskiego lektora na filmach -- bo zagłusza całą oryginalną ścieżkę audio no i tłumaczenie jakie dostajemy jest co najmniej śmieszne. Co prawda z samego słuchu ciężko się człowiek uczy, zwłaszcza jak zaczyna naukę nowego języka, dlatego też można sobie dociągnąć polskie napisy. Jeden plik video, jedne napisy, to nic wielkiego, a co w przypadku jeśli chcemy mieć kilka ścieżek audio czy napisów, po jednej dla każdego języka, którego chcemy się nauczyć? Posiadanie wielu plików wprowadza trochę zamętu. Poniżej zostanie opisany sposób na ogarnięcie kolekcji filmowej, tak by został nam się tylko jeden plik na każdy lubiany przez nas film.

Będzie trzeba dociągnąć trochę pakietów, poniżej lista:

sptitude install mkvtoolnix-gui mkvtoolnix vobsub2srt tesseract-ocr-pol tesseract-ocr-fra tesseract-ocr-spa

Mamy przykładowy plik filmowy: 01 - North and South - (summer 1842 - summer 1844).mkv . Zobaczmy co skrywa w środku:

$ mkvmerge -i "01 - North and South - (summer 1842 - summer 1844).mkv" File '01 - North and South - (summer 1842 - summer 1844).mkv': container: Matroska Track ID 0: video (MPEG-4p10/AVC/h.264) Track ID 1: audio (AAC) Track ID 2: subtitles (VobSub) Track ID 3: subtitles (VobSub) Track ID 4: subtitles (VobSub) Track ID 5: subtitles (SubRip/SRT) Chapters: 23 entries

Możemy też zobaczyć więcej szczegółów i zamiast -i sprecyzować opcję -I:

$ mkvmerge -I "01 - North and South - (summer 1842 - summer 1844).mkv" File '01 - North and South - (summer 1842 - summer 1844).mkv': container: Matroska [duration:5583088500000 segment_uid:9c796174bceeb6a93afa8cbc6da5731b is_providing_timecodes:1] Track ID 0: video (MPEG-4p10/AVC/h.264) [number:1 uid:553933625 codec_id:V_MPEG4/ISO/AVC codec_private_length:47 codec_private_data:014d401effe10020674d401eeca05a1ef5ffe00100012d418041900000030010002bf200f162d96001000468efbc80 language:eng pixel_dimensions:718x480 display_dimensions:638x480 default_track:1 forced_track:0 enabled_track:1 packetizer:mpeg4_p10_video default_duration:33366534] Track ID 1: audio (AAC) [number:2 uid:618205836 codec_id:A_AAC codec_private_length:2 codec_private_data:1188 language:eng default_track:1 forced_track:0 enabled_track:1 audio_sampling_frequency:48000 audio_channels:1] Track ID 2: subtitles (VobSub) [number:3 uid:1500043313 codec_id:S_VOBSUB codec_private_length:349 codec_private_data:73697a653a20373230783438300a6f72673a20302c20300a7363616c653a20313030252c20313030250a616c7068613a20313030250a736d6f6f74683a204f46460a66616465696e2f6f75743a2035302c2035300a616c69676e3a204f4646206174204c45465420544f500a74696d65206f66667365743a20300a666f7263656420737562733a204f46460a70616c657474653a203437343734372c206633663366312c203134313431342c206664666466642c206438363030372c206533393732382c203763376337632c203763376337632c203763376337632c203763376337632c203763376337632c203763376337632c203763376337632c203763376337632c203763376337632c203763376337630a637573746f6d20636f6c6f72733a204f46462c2074726964783a20303030302c20636f6c6f72733a203030303030302c203030303030302c203030303030302c203030303030300a00 language:eng default_track:0 forced_track:0 enabled_track:1] Track ID 3: subtitles (VobSub) [number:4 uid:1468010306 codec_id:S_VOBSUB codec_private_length:349 codec_private_data:73697a653a20373230783438300a6f72673a20302c20300a7363616c653a20313030252c20313030250a616c7068613a20313030250a736d6f6f74683a204f46460a66616465696e2f6f75743a2035302c2035300a616c69676e3a204f4646206174204c45465420544f500a74696d65206f66667365743a20300a666f7263656420737562733a204f46460a70616c657474653a203437343734372c206633663366312c203134313431342c206664666466642c206438363030372c206533393732382c203763376337632c203763376337632c203763376337632c203763376337632c203763376337632c203763376337632c203763376337632c203763376337632c203763376337632c203763376337630a637573746f6d20636f6c6f72733a204f46462c2074726964783a20303030302c20636f6c6f72733a203030303030302c203030303030302c203030303030302c203030303030300a00 language:fre default_track:0 forced_track:0 enabled_track:1] Track ID 4: subtitles (VobSub) [number:5 uid:656633113 codec_id:S_VOBSUB codec_private_length:349 codec_private_data:73697a653a20373230783438300a6f72673a20302c20300a7363616c653a20313030252c20313030250a616c7068613a20313030250a736d6f6f74683a204f46460a66616465696e2f6f75743a2035302c2035300a616c69676e3a204f4646206174204c45465420544f500a74696d65206f66667365743a20300a666f7263656420737562733a204f46460a70616c657474653a203437343734372c206633663366312c203134313431342c206664666466642c206438363030372c206533393732382c203763376337632c203763376337632c203763376337632c203763376337632c203763376337632c203763376337632c203763376337632c203763376337632c203763376337632c203763376337630a637573746f6d20636f6c6f72733a204f46462c2074726964783a20303030302c20636f6c6f72733a203030303030302c203030303030302c203030303030302c203030303030300a00 language:spa default_track:0 forced_track:0 enabled_track:1] Track ID 5: subtitles (SubRip/SRT) [number:6 uid:1025152577 codec_id:S_TEXT/UTF8 codec_private_length:0 language:eng default_track:0 forced_track:0 enabled_track:1] Chapters: 23 entries

Mamy w pliku sześć ścieżek -- video, audio, napisy w wersji angielskiej, francuskiej oraz hiszpańskiej (format VobSub). Dodatkowo są też drugie napisy angielskie, tym razem w formacie SubRip/SRT, no i rozdziały (zakładki na filmie).

Wyciągnijmy zatem całą zawartość kontenera do osobnych plików:

$ mkvextract tracks "01 - North and South - (summer 1842 - summer 1844).mkv" 0:video 1:audio 2:eng 3:fra 4:spa 5:eng2 Extracting track 0 with the CodecID 'V_MPEG4/ISO/AVC' to the file 'video'. Container format: AVC/h.264 elementary stream Extracting track 1 with the CodecID 'A_AAC' to the file 'audio'. Container format: raw AAC file with ADTS headers Extracting track 2 with the CodecID 'S_VOBSUB' to the file 'eng'. Container format: VobSubs Extracting track 3 with the CodecID 'S_VOBSUB' to the file 'fra'. Container format: VobSubs Extracting track 4 with the CodecID 'S_VOBSUB' to the file 'spa'. Container format: VobSubs Extracting track 5 with the CodecID 'S_TEXT/UTF8' to the file 'eng2'. Container format: SRT text subtitles Writing the VobSub index file 'eng.idx'. Writing the VobSub index file 'fra.idx'. Writing the VobSub index file 'spa.idx'. Progress: 100%

Dodatkowo trzeba wyciągnąć metadane opisujące dźwięk i obraz, bez tego będą problemy z odtwarzaniem filmu:

$ mkvextract timecodes_v2 "01 - North and South - (summer 1842 - summer 1844).mkv" 0:video.txt 1:audio.txt Progress: 100%

No i jeszcze wyciągnijmy rozdziały:

$ mkvextract chapters "01 - North and South - (summer 1842 - summer 1844).mkv"> chapters.xml

Nie każdy film posiada wszystkie z powyższych, także jakby czegoś brakowało to bez obaw.

Ten film akurat nie ma polskich napisów w kontenerze, ale można je dociągnąć przez qnapi. Pozostaje tylko problem z kodowaniem. Co prawda qnapi umożliwia przekodowanie pobieranych napisów ale co zrobić w przypadku gdy już posiadamy jakieś napisy i mają one inne kodowanie niż utf-8?

Napisy można przekonwertować przy pomocy iconv -- w polsce są używane chyba 3 rodzaje kodowań - utf-8, windows-1250 i iso8859-2. Jeśli mamy krzaki przy ustawieniu kodowania na utf-8, musimy zmienić kodowanie pliku jedną z poniższych linijek:

$ iconv -f iso8859-2 -t utf8 "01 - North and South - (summer 1842 - summer 1844).txt" -o pol.srt $ iconv -f windows-1250 -t utf8 "01 - North and South - (summer 1842 - summer 1844).txt" -o pol.srt

Czasami file może nam coś więcej powiedzieć o pliku:

$ file "01 - North and South - (summer 1842 - summer 1844).txt" 01 - North and South - (summer 1842 - summer 1844).txt: Non-ISO extended-ASCII text, with CRLF line terminators

Ale w tym przypadku na nic się on zbytnio nie zda.

Z kontenera .mkv wyciągnęliśmy jeden format napisów w SRT, pozostałe trzy mają format VobSub, a tego nie odtwarza mi smplayer. Vlc nawet łapie ten format napisów ale ich czcionka czy jakość pozostawia wiele do życzenia. Przekonwertujmy zatem wszystkie napisy do formatu SRT:

Oczywiście w zależności od tego na jakich językach będziemy operować, trzeba dociągnąć odpowiednie pakiety. Gdy już je mamy, przerabiamy napisy:

$ vobsub2srt --langlist ./eng Languages: 0: en $ vobsub2srt --langlist ./fre Languages: 0: fr $ vobsub2srt --langlist ./spa Languages: 0: es

$ vobsub2srt eng Wrote Subtitles to 'eng.srt' $ vobsub2srt spa Wrote Subtitles to 'spa.srt' $ vobsub2srt fre Wrote Subtitles to 'fre.srt'

Polskie napisy, które będziemy pobierać, prawdopodobnie będą miały format SRT, mimo, że będą zapisane w pliku z rozszerzeniem .txt . Tak jest w tym przypadku. Jeśli jednak trafią się napisy w formacie innym niże SRT, możemy je łatwo przekonwertować np. przy pomocy gnome-subtitles .

Mamy zatem wyodrębnioną ścieżkę video, ścieżkę audio, rozdziały oraz 4 wersje napisów. Czas to posklejać:

$ "mkvmerge" -o "./01 - North and South - (summer 1842 - summer 1844).mkv.fix" \

"--aac-is-sbr""0:1" \ "--language""0:eng""--default-track""0:yes""--forced-track""0:no""--timecodes""0:./audio.txt""-a""0""-D""-S""-T""--no-global-tags""--no-chapters""(""./audio"")" \ "--sub-charset""0:UTF-8""--language""0:eng""--forced-track""0:no""-s""0""-D""-A""-T""--no-global-tags""--no-chapters""(""./eng.srt"")" \ "--sub-charset""0:UTF8""--language""0:fre""--default-track""0:no""--forced-track""0:no""-s""0""-D""-A""-T""--no-global-tags""--no-chapters""(""./fre.srt"")" \ "--sub-charset""0:UTF8""--language""0:pol""--default-track""0:no""--forced-track""0:no""-s""0""-D""-A""-T""--no-global-tags""--no-chapters""(""./pol.srt"")" \ "--sub-charset""0:UTF-8""--language""0:spa""--default-track""0:no""--forced-track""0:no""-s""0""-D""-A""-T""--no-global-tags""--no-chapters""(""./spa.srt"")" \ "--language""0:eng""--default-track""0:yes""--forced-track""0:no""--timecodes""0:./video.txt""-d""0""-A""-S""-T""--no-global-tags""--no-chapters""(""./video"")" \ "--track-order""5:0,0:0,1:0,3:0,2:0,4:0" \ "--chapter-language""eng""--chapters""./chapters.xml" mkvmerge v6.7.0 ('Back to the Ground') 64bit built on Jan 9 2014 11:05:23 './audio': Using the demultiplexer for the format 'AAC'. './eng.srt': Using the demultiplexer for the format 'SRT subtitles'. './fre.srt': Using the demultiplexer for the format 'SRT subtitles'. './pol.srt': Using the demultiplexer for the format 'SRT subtitles'. './spa.srt': Using the demultiplexer for the format 'SRT subtitles'. './video': Using the demultiplexer for the format 'AVC/h.264'. './audio' track 0: Using the output module for the format 'AAC'. './eng.srt' track 0: Using the output module for the format 'text subtitles'. './fre.srt' track 0: Using the output module for the format 'text subtitles'. './pol.srt' track 0: Using the output module for the format 'text subtitles'. './spa.srt' track 0: Using the output module for the format 'text subtitles'. './video' track 0: Using the output module for the format 'AVC/h.264 (unframed)'. The file './01 - North and South - (summer 1842 - summer 1844).mkv.fix' has been opened for writing. './video' track 0: Extracted the aspect ratio information from the MPEG-4 layer 10 (AVC) video data and set the display dimensions to 718/540. Progress: 100% The cue entries (the index) are being written... Muxing took 1 minute 51 seconds.

Składanie kontenera .mkv dużo prościej odbywa się przez gui -- mmg. Sprawdzamy jeszcze czy kontener ma wszystko co chcieliśmy by miał:

$ mkvmerge -I "01 - North and South - (summer 1842 - summer 1844).mkv.fix" File '01 - North and South - (summer 1842 - summer 1844).mkv.fix': container: Matroska [duration:5583087000000 segment_uid:1ad821ab54deea131d9870fc37c063ce is_providing_timecodes:1] Track ID 0: video (MPEG-4p10/AVC/h.264) [number:1 uid:5542766029373557832 codec_id:V_MPEG4/ISO/AVC codec_private_length:47 codec_private_data:014d401effe10020674d401eeca05a1ef5ffe00100012d418041900000030010002bf200f162d96001000468efbc80 language:eng pixel_dimensions:718x480 display_dimensions:718x540 default_track:1 forced_track:0 enabled_track:1 packetizer:mpeg4_p10_video default_duration:33000000] Track ID 1: audio (AAC) [number:2 uid:5497098133708685637 codec_id:A_AAC codec_private_length:5 codec_private_data:118856e580 language:eng default_track:1 forced_track:0 enabled_track:1 default_duration:21000000 audio_sampling_frequency:48000 audio_channels:1] Track ID 2: subtitles (SubRip/SRT) [number:3 uid:15137279790666575565 codec_id:S_TEXT/UTF8 codec_private_length:0 language:eng default_track:1 forced_track:0 enabled_track:1] Track ID 3: subtitles (SubRip/SRT) [number:4 uid:14594798366566068182 codec_id:S_TEXT/UTF8 codec_private_length:0 language:pol default_track:0 forced_track:0 enabled_track:1] Track ID 4: subtitles (SubRip/SRT) [number:5 uid:4699787031062832735 codec_id:S_TEXT/UTF8 codec_private_length:0 language:fre default_track:0 forced_track:0 enabled_track:1] Track ID 5: subtitles (SubRip/SRT) [number:6 uid:11943351849052802566 codec_id:S_TEXT/UTF8 codec_private_length:0 language:spa default_track:0 forced_track:0 enabled_track:1] Chapters: 23 entries

Teraz już tylko wystarczy wrzucić film do smplayera czy vlc i sprawdzić czy działa prawidłowo. U mnie wszystko jak najbardziej w porządku.

Gdy staramy się przeformatować swoją kolekcję filmów tak by wszystkie pliki były w kontenerach .mkv, czasami się może zdarzyć, że będziemy mieli do czynienia z innymi kontenerami. Póki co natrafiłem na kontener QuickTime/MP4 . Przy wypisywaniu informacji za pomocą mkvmerge -i nie zostaną pokazane wszystkie ścieżki. Tak u mnie się prezentuje kontener QuickTime/MP4 w mkvmerge:

$ mkvmerge -i film.mp4 File 'film': container: QuickTime/MP4 Track ID 0: video (MPEG-4p10/AVC/h.264) Track ID 1: audio (AAC) Chapters: 45 entries

Jedyne czego brakuje to napisów, a te są w dość egzotycznym formacje -- można sprawdzić za pomocą mediainfo:

Text #1 ID : 3 Format : Timed Text Codec ID : tx3g Duration : 3h 5mn Bit rate mode : Variable Bit rate : 36 bps Stream size : 48.5 KiB (0%) Title : *srt#trackID=1:lang=en@GPAC0.5.1-DEV-rev4283 Language : English Encoded date : UTC 2013-10-23 14:19:12 Tagged date : UTC 2013-10-23 14:19:12

Trzeba te napisy jakoś wyciągnąć i przekonwertować do formatu SRT. Do tego celu musimy doinstalować pakiet gpac:

aptitude install gpac

Podglądamy plik przy pomocy MP4Box:

$ MP4Box -info film.mp4 * Movie Info * Timescale 600 - Duration 03:16:02.900 5 track(s) Fragmented File: no File suitable for progressive download (moov before mdat) File Brand isom - version 1 Created: GMT Wed Oct 23 14:07:50 2013

File has root IOD (9 bytes) Scene PL 0xff - Graphics PL 0xff - OD PL 0xff Visual PL: AVC/H264 Profile (0x15) Audio PL: AAC Profile @ Level 2 (0x29) No streams included in root OD

Chapters: Chapter #1 - 00:00:00.000 - "Foreword" Chapter #2 - 00:01:30.090 - "Awaiting Achilles" Chapter #3 - 00:08:16.329 - ""Is There No One Else?"" Chapter #4 - 00:11:06.332 - "Secret Lovers" Chapter #5 - 00:18:22.101 - "Brothers' Pledges" Chapter #6 - 00:25:33.365 - "Greatest War" Chapter #7 - 00:27:41.493 - "Recruiter Odysseus" Chapter #8 - 00:33:23.335 - "Glory and Doom" Chapter #9 - 00:36:39.864 - "Royal Welcome" Chapter #10 - 00:40:01.566 - "They're Coming for Me" Chapter #11 - 00:44:50.187 - "Immortality Is Yours" Chapter #12 - 00:52:32.316 - "Beach Combat" Chapter #13 - 00:58:00.143 - "Too Early in the Day" Chapter #14 - 01:03:48.992 - "No Need to Fear" Chapter #15 - 01:07:41.224 - "Spoils of War" Chapter #16 - 01:12:36.352 - "The Way I Love Helen" Chapter #17 - 01:17:55.838 - "Power, Not Love" Chapter #18 - 01:21:31.720 - "Soldiers Obey" Chapter #19 - 01:23:55.864 - "Gathering Forces" Chapter #20 - 01:28:49.324 - "Brave Offer" Chapter #21 - 01:32:23.371 - "Paris vs. Menelaus" Chapter #22 - 01:36:58.146 - "Battle Cry" Chapter #23 - 01:41:39.093 - "Greek Retreat" Chapter #24 - 01:44:56.957 - "Weak Morale" Chapter #25 - 01:48:15.322 - "Everyone Dies" Chapter #26 - 01:54:20.687 - "Born for This War" Chapter #27 - 01:57:26.039 - "Priam's Order" Chapter #28 - 02:00:05.698 - "Flaming Attack" Chapter #29 - 02:03:47.086 - "Hector's Adversary" Chapter #30 - 02:08:40.212 - "Tragic Mistake" Chapter #31 - 02:10:42.668 - "Night of Torments" Chapter #32 - 02:15:10.436 - "Summoned to Fight" Chapter #33 - 02:20:47.773 - "Now You Know" Chapter #34 - 02:23:08.246 - "Hector vs. Achilles" Chapter #35 - 02:26:25.110 - "Desecrating the Dead" Chapter #36 - 02:28:29.734 - "A Father's Plea" Chapter #37 - 02:34:48.446 - "Achilles' Word" Chapter #38 - 02:37:28.939 - "Inspirations and Honors" Chapter #39 - 02:41:20.170 - "Parting Gift" Chapter #40 - 02:45:40.764 - "Troy Under Siege" Chapter #41 - 02:51:09.759 - "We Will Be Together" Chapter #42 - 02:55:39.028 - "Royal Bloodshed" Chapter #43 - 02:58:42.712 - "Brought to Hell" Chapter #44 - 03:02:24.433 - "I Walked With Giants" Chapter #45 - 03:05:12.601 - "End Credits"

Track # 1 Info - TrackID 1 - TimeScale 24000 - Media Duration 03:16:02.751 Media Info: Language "Undetermined" - Type "vide:avc1" - 282024 samples Visual Track layout: x=0 y=0 width=1280 height=528 MPEG-4 Config: Visual Stream - ObjectTypeIndication 0x21 AVC/H264 Video - Visual Size 1280 x 528 AVC Info: 1 SPS - 1 PPS - Profile High @ Level 4.1 NAL Unit length bits: 32 Pixel Aspect Ratio 1:1 - Indicated track size 1280 x 528 Chroma format 1 - Luma bit depth 8 - chroma bit depth 8 Self-synchronized

Track # 2 Info - TrackID 2 - TimeScale 48000 - Media Duration 03:16:02.901 Media Info: Language "English" - Type "soun:mp4a" - 551386 samples MPEG-4 Config: Audio Stream - ObjectTypeIndication 0x40 MPEG-4 Audio AAC LC - 2 Channel(s) - SampleRate 48000 Synchronized on stream 1

Track # 3 Info - TrackID 3 - TimeScale 1000 - Media Duration 03:05:05.671 Media Info: Language "English" - Type "text:tx3g" - 2748 samples 3GPP/MPEG-4 Timed Text - Size 1280 x 528 - Translation X=0 Y=0 - Layer 0

Track # 4 Info - TrackID 4 - TimeScale 1000 - Media Duration 03:06:09.928 Media Info: Language "Romanian; Moldavian; Moldovan" - Type "text:tx3g" - 2689 samples 3GPP/MPEG-4 Timed Text - Size 1280 x 528 - Translation X=0 Y=0 - Layer 0

Track # 5 Info - TrackID 5 - TimeScale 1000 - Media Duration 03:05:05.619 Media Info: Language "Russian" - Type "text:tx3g" - 2796 samples 3GPP/MPEG-4 Timed Text - Size 1280 x 528 - Translation X=0 Y=0 - Layer 0

I jak widzimy powyżej, mamy trochę więcej ścieżek niż nam pokazał mkvmerge. Teraz już tylko pozostało nam wyciągnąć napisy:

$ MP4Box -srt 3 film.mp4 Conversion done

Zostaną one przekonwertowane do formatu SRT czyli tak jak tego chcieliśmy na początku.

Dodatkowa autoryzacja w SSH GOOGLE

$
0
0

Dodatkowa autoryzacja w SSH GOOGLE

Witam wszystkich, chcę dziś Wam pokazać dodatkową autoryzację w usłudze ssh za pomocą biblioteki google. Uprzedzę Wasze wszystkie pytania, po co , czy to bezpieczne?, opisuję to jako ciekawostkę dodatek do ssh, nie zwalniający z dodatkowych zabezpieczeń i myślenia Administratorów. Jest do fajny dodatek, dosyć przyjazny, nie trzeba za niego płacić i jak na razie działa. No dobrze koniec gadania, czas zabrać się do prania do czego ? taaaa zmęczenie .. do instalowania.

Oczywiście cała instalacja jest dla Debiana 7.

Sudo czy jak ktoś tam woli od razu na koncie root, zróbcie tak

[root@toor]#wget http://ftp.us.debian.org/debian/pool/main/g/googleauthenticator/libpam-google-authenticator_20130529-2_amd64.deb .

Oczywiście to dla 64 dla 32 trzeba skorzystać z tego linku

[root@toor]#wget http://ftp.us.debian.org/debian/pool/main/g/google-authenticator/libpam-google-authenticator_20130529-2_i386.deb

Można oczywiście pobrać najnowszą wersję i skompilować ją samemu, ale ja jestem pczkowy i tak tu opiszę. Teraz zaczynamy instalację.

[root@toor]#dpkg –i libpam-google-authenticator_20130529-2_amd64.deb wszystko się zainstaluje ładnie, choć nie zawsze na kilku maszynach wywaliło mi brak libqrencode3 więc może warto to doinstalować wcześniej nie zaszkodzi, a unikniemy problemów.

Po zakończonej operacji można już wygenerować sobie pliczek z autoryzacją. UWAGA !! jeśli w ssh mamy zablokowane logowanie na konto root, trzeba to zrobić na użytkowniku, który może się logować. Jeśli tego nie sprawdzimy wcześniej to czeka Nas wyprawa do serwera ☺))

[piotr@toor]$google-authenticator

Do you want authentication tokens to be time-based (y/n)y 
https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/piotr@zfs%3Fsecret%3D4J7HMT2O2JUR2UMJ

TU PIĘKNY OBRAZEK BY ZROBIĆ ZDJĘCIE TELEFONEM !!

Your new secret key is: 4J7HMT2O2JUR2UMJ
Your verification code is 749225
Your emergency scratch codes are:
  21020080
  87408497
  62094299
  82524514
  30315016

Do you want me to update your "/home/piotr/.google_authenticator" file (y/n)y
Do you want me to update your "/home/piotr/.google_authenticator" file (y/n) y
Do you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n) y

By default, tokens are good for 30 seconds and in order to compensate for
possible time-skew between the client and the server, we allow an extra
token before and after the current time. If you experience problems with poor
time synchronization, you can increase the window from its default
size of 1:30min to about 4min. Do you want to do so (y/n) n

If the computer that you are logging into isn't hardened against brute-force
login attempts, you can enable rate-limiting for the authentication module.
By default, this limits attackers to no more than 3 login attempts every 30s.
Do you want to enable rate-limiting (y/n) y

Poczytać i ustawić sobie zgodnie z zapotrzebowaniem :))) nie sugerujcie się kodami , które tu są podawane dla przykładu nie włamiecie mi się na serwer to tylko przykład ☺))

Teraz musimy pobrać aplikację na nasz telefon, hmm smartfon ? na innym nie testowałem. Aplikacja jest dostępna w Sklepie Gogle na Android, i AppStore iPhone na Windows nie wiem nie mam ☺ Nazywa się Authenticator, pobieramy i instalujemy. Do aplikacji można wpisać kod ręcznie , lub zrobić za pomocą niej zdjęcie, tego obrazka co powstał nam podczas generowania kodu. Kod do wpisania ręcznego to **Your new secret key is: 4J7HMT2O2JUR2UMJ ** pierwsza linijka. Potem można go podejrzeć w katalogu domowym

[piotr@toor]$ cat /home/piotr/.google_authenticator

No dobra aplikacja zainstalowana, kod przepisany do telefonu no to pora na odcięcie się od ssh ☺)). Nie sprawdzałem czy działa jak ktoś ma klucze, ale to pozostawiam Wam do zweryfikowania. Musimy dokonać zmian w pliku

[root@toor]# vim /etc/pam.d/sshd

Ja dokonałem zmiany ok ~ linijki 6 i wpisałem to auth required pam_google_authenticator.so

Wychodzimy zapisujemy i edytujemy konfigurację SSH.

[root@toor]# vim /etc/ssh/sshd_config

Szukamy linijki ok ~36 ChallengeResponseAuthentication no i zmieniamy ją na

ChallengeResponseAuthentication yes

Restartujemy ssh [root@toor]# service ssh restart

Iii dziękuję zablokowałem sobie dostęp do serwera w stanach … uuuppssss to kurtka na grzbiet i lecisz. Czytać uważnie przetrenować gdzieś na testowych maszynach.

Powodzonka i miłej zabawy !!!

Ograniczanie zasobów zbyt żarłocznym procesom

$
0
0

Niektóre procesy czasem zjadają trochę więcej zasobów niż powinny, co może przyczynić się w pewnych sytuacjach do powieszenia systemu i bez twardego resetu się nie obejdzie. Oczywiście, najlepszym rozwiązaniem jest rozbudowanie maszyny ale co w przypadku gdy chcemy dać jakiemuś procesowi pierwszeństwo w korzystaniu z zasobów pc?

  1. Cgroups

Istnieje kilka rozwiązań, które mogą nam pomóc w ogarnięciu zasobożernych procesów. Pierwsze z nich to cgroups. Jest on trochę pobugowany i ciężko jest go ogarnąć tymi narzędziami, które są dostępne w pakiecie cgroup-bin ale generalnie nic z czym nie można by sobie było dać rady.

Cgroups ma postać wirtualnego systemu plików, w którego skład wchodzą: blkio, cpu, cpuacct, cpusets, devices, freezer, memory, net_cls, net_prio oraz perf_event. Na stronie red hata jest to trochę bardziej przyjaźnie opisane niż na stronie kernela.

Z grubsza moduły odpowiadają kolejno kontrolę I/O dysków, za przydział procesora, za statystyki cpu, za przydział konkretnego rdzenia i nodów pamięci, za dostęp do urządzeń, za zatrzymywanie i wznawianie procesów, za przydział pamięci i staty pamięci, za przypisywanie pakietom sieciowym odpowiednich klas dla traffic control, za ustawianie priorytetu pakietom sieciowym generowanym przez określone aplikacje w oparciu o soket SO_PRIORITY i ostatnia pozycja za monitorowanie grup przy pomocy narzędzia pref .

Problem z cgroups w debianie jest taki, że dołączone skrypty nie bardzo działają. Musimy zatem stworzyć parę skryptów konfiguracyjnych i wywołać je przy starcie systemu ale po kolei. Najpierw instalujemy dwa pakiety libcgroup1 oraz cgroup-bin:

aptitude install libcgroup1 cgroup-bin

Trzeba się także upewnić czy aby na pewno mamy odpowiednie moduły w kernelu:

grep -i cgroup /boot/config-3.12-1-amd64

CONFIG_CGROUPS=y

CONFIG_CGROUP_DEBUG is not set

CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_DEVICE=y CONFIG_CGROUP_CPUACCT=y

CONFIG_CGROUP_HUGETLB is not set

CONFIG_CGROUP_PERF=y CONFIG_CGROUP_SCHED=y CONFIG_BLK_CGROUP=y

CONFIG_DEBUG_BLK_CGROUP is not set

CONFIG_NET_CLS_CGROUP=y CONFIG_NETPRIO_CGROUP=m

W tym przypadku by móc skorzystać w pełni z możliwości oferowanych przez cgroups, trzeba będzie załadować moduł od netprio, oczywiście jeśli będziemy potrzebować tego ficzera. W tym celu trzeba będzie dodać do /etc/modules poniższy wpis:

netprio_cgroup

Dzięki czemu, ten moduł będzie ładowany na starcie systemu i nie będziemy musieli sobie nim głowy zawracać.

W debianie dodatkowo trzeba dopisać do linijki kernela (extlinux,grub) poniższy parametr umożliwiający włączenie zarządzania pamięcią w cgroups:

cgroup_enable=memory

Można również zaciągnąć lxc w celu sprawdzenia odpowiedniej konfiguracji cgroups, z tym, że w obecnych wersjach pakietów w debianie (testing) cgroup-bin i lxc się gryzą. Istnieje możliwość doinstalowania lxc i rozwiązanie zależności ale trzeba to zrobić z gałęzi experimental:

aptitude install lxc

The following NEW packages will be installed: libapparmor1{a} lxc{b} 0 packages upgraded, 2 newly installed, 0 to remove and 3 not upgraded. Need to get 46.1 kB/238 kB of archives. After unpacking 739 kB will be used. The following packages have unmet dependencies: lxc : Conflicts: cgroup-bin but 0.38-3 is installed. The following actions will resolve these dependencies:

 Remove the following packages:

1) cgroup-bin

Accept this solution? [Y/n/q/?]

The following actions will resolve these dependencies:

 Install the following packages:                 

1) libseccomp2 [2.1.0+dfsg-1 (testing, unstable)] 2) lxc [1.0.0~beta1-5 (experimental)]

Accept this solution? [Y/n/q/?]

LXC posłuży nam tylko do sprawdzenia konfiguracji cgroups i jeśli będzie ona poprawna, możemy usunąć lxc, oczywiście jeśli go nie potrzebujemy.

Samo sprawdzenie konfiguracji odbywa się przez wydanie polecenia lxc-checkconfig :

lxc-checkconfig

Kernel configuration not found at /proc/config.gz; searching... Kernel configuration found at /boot/config-3.12-1-amd64 --- Namespaces --- Namespaces: enabled Utsname namespace: enabled Ipc namespace: enabled Pid namespace: enabled User namespace: enabled Network namespace: enabled Multiple /dev/pts instances: enabled

--- Control groups --- Cgroup: enabled Cgroup clone_children flag: enabled Cgroup device: enabled Cgroup sched: enabled Cgroup cpu account: enabled Cgroup memory controller: enabled Cgroup cpuset: enabled

--- Misc --- Veth pair device: enabled Macvlan: enabled Vlan: enabled File capabilities: enabled

Note : Before booting a new kernel, you can check its configuration usage : CONFIG=/path/to/config /usr/bin/lxc-checkconfig

Z tak przygotowanym setupem możemy przejść do tworzenia drzewa katalogów, podobnego do tego poniżej:

$ tree -L 1 /cgroups/ /cgroups/ ├── blkio ├── cpu ├── cpuacct ├── cpuset ├── devices ├── freezer ├── memory ├── net_cls ├── net_prio └── perf_event

Operowanie na cgroups odbywa się przez identyfikację procesu i aplikowanie reguł, co do tego ile zasobów ten proces może wykorzystać. Tylko RAM można ustawić na sztywno. Pozostałe parametry nie będą limitować zasobów w taki sposób jak człowiek może przypuszczać -- jeśli ustawimy max 50% procesora pod jakiś proces, to ten proces będzie zjadał dostępne zasoby jak gdyby nigdy nic ale w przypadku obciążenia maszyny jeśli by ten proces chciał zjadać więcej niż 50%, to mu zostanie to zabronione, dzięki czemu inny proces będzie mógł wykorzystać swój przydział i nie zostanie zduszony przez żarłoczną aplikację.

Potrzebujemy zatem dwóch rzeczy -- pliku konfiguracyjnego z regułami, na których to podstawie będą ograniczane zasoby oraz demona, który będzie identyfikował procesy jak tylko te zostaną zainicjowane i uzupełniał plik tasks o odpowiednie pidy.

Tworzymy zatem dwa skrypty startowe. Pierwszy z nich, plik /etc/init.d/cgrulesengd , będzie uruchamiał demona cgrulesengd:

! /bin/sh

BEGIN INIT INFO

Provides: cgrulesengd

Required-Start: $remote_fs $syslog

Required-Stop: $remote_fs $syslog

Should-Start: cgconfig

Should-Stop: cgconfig

Default-Start: 2 3 4 5

Default-Stop: 0 1 6

Short-Description: CGroups rules engine daemon

Description: CGroup Rules Engine is a tool for automatically using

cgroups to classify processes

END INIT INFO

Author: Mikhail Morfikov morfikov[at]gmail.com

Do NOT "set -e"

Read configuration variable file if it is present

if [ -f "/etc/default/cgrulesengd" ] ; then . /etc/default/cgrulesengd OPTIONS="$NODAEMON $LOG" if [ -n "$LOG_FILE" ]; then OPTIONS="$OPTIONS --logfile=$LOG_FILE" fi if [ -n "$SOCKET_USER" ]; then OPTIONS="$OPTIONS -u $SOCKET_USER" fi if [ -n "$SOCKET_GROUP" ]; then OPTIONS="$OPTIONS -g $SOCKET_GROUP" fi else OPTIONS="" fi

PATH should only include /usr/* if it runs after the mountnfs.sh script

PATH=/sbin:/usr/sbin:/bin:/usr/bin DESC="CGroups rules engine daemon" NAME=cgrulesengd DAEMON=/usr/sbin/$NAME DAEMON_ARGS="$OPTIONS" PIDFILE=/var/run/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME

Exit if the package is not installed

[ -x "$DAEMON" ] || exit 1

. /lib/init/vars.sh . /lib/lsb/init-functions

do_start() { start-stop-daemon --start --quiet --make-pidfile --pidfile $PIDFILE --background --name $NAME --exec $DAEMON -- $DAEMON_ARGS \ || return 2 }

do_stop() { start-stop-daemon --stop --quiet --pidfile $PIDFILE --name $NAME RETVAL="$?" [ "$RETVAL" = 2 ] && return 2 rm -f $PIDFILE return "$RETVAL" }

do_reload() { start-stop-daemon --stop --quiet --signal 1 --pidfile $PIDFILE --name $NAME return 0 } VERBOSE="yes"

case "$1" in start) [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC""$NAME" do_start case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; stop) [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC""$NAME" do_stop case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; status) status_of_proc "$DAEMON""$NAME"&& exit 0 || exit $? ;; restart|force-reload) log_daemon_msg "Restarting $DESC""$NAME" do_stop case "$?" in 0|1) do_start case "$?" in 0) log_end_msg 0 ;; 1) log_end_msg 1 ;; # Old process is still running *) log_end_msg 1 ;; # Failed to start esac ;; *) # Failed to stop log_end_msg 1 ;; esac ;; *) echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}">&2 exit 3 ;; esac

Nic innego mi nie przyszło do głowy przy przerabianiu tego niedziałającego skryptu dołączonego w pakiecie cgroup-bin . W każdym razie trzeba zwrócić uwagę na nagłówek -- ten skrypt musi się odpalić po skrypcie z regułami.

Drugi ze skryptów, /etc/init.d/cgconfig :

!/bin/bash

BEGIN INIT INFO

Provides: cgconfig

Required-Start: $remote_fs $syslog

Required-Stop: $remote_fs $syslog

Should-Start:

Should-Stop:

Default-Start: 2 3 4 5

Default-Stop: 0 1 6

Short-Description: Create and setup control group filesystem(s)

Description: Create and setup control group filesystem(s)

END INIT INFO

CGDIR='/cgroups'

. /lib/init/vars.sh . /lib/lsb/init-functions

if [ ! -d $CGDIR ]; then mkdir -p $CGDIR/{cpuset,cpu,cpuacct,memory,devices,freezer,net_cls,blkio,net_prio,perf_event} fi

do_mount() { mount -t cgroup -oblkio none $CGDIR/blkio mount -t cgroup -ocpu none $CGDIR/cpu mount -t cgroup -ocpuacct none $CGDIR/cpuacct mount -t cgroup -ocpuset none $CGDIR/cpuset mount -t cgroup -odevices none $CGDIR/devices mount -t cgroup -ofreezer none $CGDIR/freezer mount -t cgroup -omemory none $CGDIR/memory mount -t cgroup -onet_cls none $CGDIR/net_cls mount -t cgroup -onet_prio none $CGDIR/net_prio mount -t cgroup -operf_event none $CGDIR/perf_event }

start() { echo -e "Starting cgconfig service."

for clone in `ls $CGDIR/*/cgroup.clone_children`;
do echo 1 > $clone; done;

### FIREFOX ###
mkdir -p $CGDIR/cpu/users/firefox
echo '300' > $CGDIR/cpu/users/firefox/cpu.shares
mkdir -p $CGDIR/cpuacct/users/firefox
mkdir -p $CGDIR/cpuset/users/firefox
mkdir -p $CGDIR/memory/users/firefox
echo '340m' >   $CGDIR/memory/users/firefox/memory.limit_in_bytes
echo '200m' >   $CGDIR/memory/users/firefox/memory.soft_limit_in_bytes
mkdir -p $CGDIR/net_cls/users/firefox
echo '0x00010003' > $CGDIR/net_cls/users/firefox/net_cls.classid

### QBITTORRENT ### 
mkdir -p $CGDIR/cpu/users/qbittorrent
echo '300' > $CGDIR/cpu/users/qbittorrent/cpu.shares
mkdir -p $CGDIR/net_cls/users/qbittorrent
echo '0x00010002' > $CGDIR/net_cls/users/qbittorrent/net_cls.classid
mkdir -p $CGDIR/net_prio/users/qbittorrent
echo "eth0 1"> $CGDIR/net_prio/users/qbittorrent/net_prio.ifpriomap

### MINITUBE ###
mkdir -p $CGDIR/cpu/users/minitube
echo '300' > $CGDIR/cpu/users/minitube/cpu.shares
mkdir -p $CGDIR/net_cls/users/minitube
echo '0x00010003' > $CGDIR/net_cls/users/minitube/net_cls.classid

chmod 660 $CGDIR/*/*/*/tasks
chown root:cgroup $CGDIR/*/users/*/tasks

}

stop() { echo -e "Stopping cgconfig service." cgclear }

restart() { stop && sleep 1 montowanie && start }

usage() { echo "$0 start|stop|restart" exit 2 }

RETVAL=0

case $1 in 'stop') stop ;; 'start') do_mount && start ;; 'restart'|'reload') restart ;; *) usage ;; esac

exit 0

Każdy podsystem zawiera swoje pliki konfiguracyjne, powyższy skrypt przesyła odpowiednie wartości do tych plików przy pomocy polecenia echo. Nie będę opisywał tutaj wszystkich możliwych wartości we wszystkich plikach każdego modułu cgroups, bo z połowy nigdy nie korzystałem, a drugiej połowy jeszcze do końca nie poznałem. xD Wszystko jest dość obszernie opisane zarówno na stronie kernela jak i red hata.

Niemniej jednak opcje użyte przeze mnie w powyższym skrypcie trzeba opisać, poza tym nie jest ich tam aż tak dużo. Weźmy sobie przykład firefoxa, bo ma tych linijek najwięcej. Pozycje z mkdir tworzą odpowiednie grupy w drzewie katalogów cgroups. W tym przypadku, w sekcjach cpuacct, cpu, cpuset, memory i net_cls, zostanie utworzona grupa główna users i podgrupa firefox, nazwy są dowolne. Przy pomocy echo są przesyłane odpowiednie wartości do plików. W przypadku pliku cpu.shares, wartość 300 oznacza 300/1024, czyli około 1/3 czasu procesora. Domyślną wartością dla wszystkich procesów jest 1024 i tą wartością można się dowolnie bawić. Jeśli ustawimy więcej niż 1024, np. 2048, proces dostałby 2/3 czasu procesora w przypadku wysokiego obciążenia maszyny, bo 2048+1024=3072 i 2048/3072=2/3 . Oczywiście to wszystko przy założeniu, że tylko dwa procesy by wykorzystywały procesor w 100% ale życie jest trochę bardziej skompilowane.

Trzeba uważać trochę w przypadku podgrup, bo grupa główna może mieć własny przydział procesora i podgrupy również, w takim przypadku czas procesora będzie liczony trochę inaczej. Dla uproszczenia, załóżmy, że mamy 2 grupy główne -- A oraz B, które mają cpu.shares odpowiednio 1024 i 2048. Grupa A ma dwie podgrupy A1 i A2, a grupa B ma tylko jedną podgrupę B1. Te podgrupy zaś mają następujące wartości w cpu.shares : 512, 1024 i 2048 . Pytanie jest takie -- jak się rozłoży czas procesora przy maksymalnym obciążeniu? Najpierw analizujemy grupy główne, czas procka na te grupy rozłoży się w stosunku 1/3 i 2/3, odpowiednio dla grup A i B (1024+2048=3072, 1024/3072 oraz 2048/3072).

Teraz podgrupy. Jeśli w grupie A nie będzie żadnych procesów (mogą być ale załóżmy, że nie ma), to procesor przypadnie w 1/3 na grupę A1 i w 2/3 na grupę A2 (512/(512+1024) oraz 1024/(512+1024) . Jeśli by były jakieś procesy w grupie A, to rozkład mocy procesora by przybrał następującą postać: dla grupy A 2/5 , dla A1 1/5 i dla A2 2/5 . Czemu tak? trzeba wziąć pod uwagę przydziały wszystkich trzech grup (grupy głównej i dwóch podgrup), co daje nam 1024 (A) + 512 (A1) + 1024 (A2) = 2560 i odpowiednio 1024/2560 , 512/2560 , 1024/2560, co daje 2/5, 1/5 i 2/5 . To tyle jeśli chodzi o grupę A, została jeszcze gruba B.

W grupie B jest tylko jedna podgrupa B1 i w przypadku gdy procesy będą tylko w podgrupie B1, cały przydział procka jej przypadnie. Gdyby procesy także były w grupie B, podział procka rozłoży się 1/2 dla B i 1/2 dla B1, bo obie mają takie same wartości cpu.shares (2048).

I chyba najbardziej złożony model, który można by rozpisać, biorąc pod uwagę powyższy przykład, to gdy procesy trafiają do grup A, A1, A2, B oraz B1. Jak w takim przypadku rozłoży się czas procesora? Jak już wiemy, grupy A i B podzielą procesor w stosunku 1/3 i 2/3. Rozkład w grupie A wynosi 2/5, 1/5 i 2/5 , mnożymy to przez ratio wyższej grupy -- 1/3 -- i dostajemy wartości 2/15, 1/15 i 2/15. Łącznie daje nam to 5/15, czyli 1/3. Podobnie postępujemy z grupami B i B1 -- mają współczynniki przydziału 1/2 i 1/2, mnożymy przez ratio 2/3, co daje 2/6 i 2/6, rzem 4/6=2/3 , a 1/3+2/3=1, czyli wszystko się zgadza. Jeszcze dajemy to na wspólny mianownik 80 (6*15) i mamy współczynniki 12/90, 6/90, 12/90, 30/90 i 30/90, odpowiednio dla A, A1, A2, B i B1. Łącznie daje 1, więc chyba wszystko się zgadza. xD Przykład zaczerpnięty z tej strony ale odrobinę został zmieniony.

Trzeba jeszcze tylko pamiętać, że cpu.shares odnosi się do całego procesora, czyli wszystkich rdzeni i jeśli będzie ustawimy przydział, powiedzmy, 512, to na dwu rdzeniowym procku, proces mógłby zjeść jeden rdzeń w pełni.

Dość tego liczenia. Następna linijka w sekcji z firefoxem to memory.limit_in_bytes. Ustawia ona limit pamięci dla grupy i w tym przypadku jest to 340MiB . Po przekroczeniu tej wartości, dane będą zrzucane do swap. Kolejna linijka to memory.soft_limit_in_bytes. Parametr jest podobny do tego powyżej i ma znaczenie głównie przy zbyt dużym wykorzystaniu pamięci RAM, czyli gdy brakuje zasobów. W takim przypadku trzeba będzie zwolnić zasoby pamięci, które? To zależy od tego parametru właśnie. W tym przypadku, na pierwszy ogień pójdzie 100MiB z przydziału firefoxa. Przez zwolnienie, ma się rozumieć, że dane trafią do swap, a nie, że wylecą permanentnie z pamięci.

Jeśli ktoś jest ciekaw jak prezentują się statystyki pamięci, może je podejrzeć w dwóch poniższych plikach:

cat /proc/pidof firefox/status

Name: firefox State: S (sleeping) Tgid: 30859 Pid: 30859 PPid: 30858 TracerPid: 0 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 FDSize: 128 Groups: 24 25 27 29 30 44 46 100 115 1000 1004 5001 5004 VmPeak: 977992 kB VmSize: 944208 kB VmLck: 0 kB VmPin: 0 kB VmHWM: 270780 kB VmRSS: 124944 kB VmData: 562404 kB VmStk: 152 kB VmExe: 124 kB VmLib: 66632 kB VmPTE: 1500 kB VmSwap: 113628 kB Threads: 36 SigQ: 0/7866 SigPnd: 0000000000000000 ShdPnd: 0000000000000000 SigBlk: 0000000000000000 SigIgn: 0000000000001004 SigCgt: 0000000f800044eb CapInh: 0000000000000000 CapPrm: 0000000000000000 CapEff: 0000000000000000 CapBnd: 0000001fffffffff Seccomp: 0 Cpus_allowed: 3 Cpus_allowed_list: 0-1 Mems_allowed: 00000000,00000001 Mems_allowed_list: 0 voluntary_ctxt_switches: 79553 nonvoluntary_ctxt_switches: 181247

oraz:

cat /cgroups/memory/users/firefox/memory.stat

cache 9502720 rss 122515456 rss_huge 0 mapped_file 9482240 writeback 0 pgpgin 3718856 pgpgout 3686625 pgfault 3737370 pgmajfault 19419 inactive_anon 61382656 active_anon 61132800 inactive_file 4710400 active_file 4792320 unevictable 0 hierarchical_memory_limit 18446744073709551615 total_cache 9502720 total_rss 122515456 total_rss_huge 0 total_mapped_file 9482240 total_writeback 0 total_pgpgin 3718856 total_pgpgout 3686625 total_pgfault 3737370 total_pgmajfault 19419 total_inactive_anon 61382656 total_active_anon 61132800 total_inactive_file 4710400 total_active_file 4792320 total_unevictable 0

W tych plikach są również zawarte informacje na temat tego ile dany proces zajmuje miejsca w swapie.

Ostatnią pozycją tyczącą się firefoxa jest net_cls.classid. Moduł net_cls odpowiada za nadawanie pakietom sieciowym odpowiednich klas, które są używane przy traffic control. Jeśli chodzi o firefoxa, ta aplikacja korzysta z internetu i przydałoby się odrobinę kontrolować jej ruch. W tym celu nadawany jest id grupy pakietom tworzonym przez procesy firefoxa. Oznaczenie 0x00010003 jest zapisem hexalnym i w jego skład wchodzą dwie liczby -- 0001 oraz 0003. Po przeliczeniu tego na system decymalny otrzymujemy 1 i 3, które narzędzie tc traktuje jako grupę 1:3 i tam właśnie wysyła pakiety, którym można nadać wyższy priorytet, określić pasmo i tego podobne rzeczy. Jeśli nie mamy pojęcia co to takiego to całe tc, to raczej nie potrzebujemy tej linijki.

Przy pomocy chown i chmod nadajemy odpowiednie uprawnienia plikom tasks, za pośrednictwem których to możemy wskazywać pidy procesów. Chodzi głównie o ustawienie odpowiednich praw dostępu do tych plików, by użytkownicy w grupie cgroup mogli swobodnie operować na nich.

Linijka z cgroup.clone_children sprawi, że konfiguracja katalogów nadrzędnych będzie kopiowana do tych podrzędnych przy ich inicjacji, czyli przy zakładaniu kolejnych grup i podgrup.

Musimy jeszcze stworzyć dwa pliki konfiguracyjne: /etc/default/cgrulesengd oraz /etc/cgrules.conf .

Plik /etc/default/cgrulesengd :

CGroup Rules Engine Daemon configuration file

The four options listed below (CONFIG_FILE, LOG_FILE, NODAEMON, LOG) are

the only valid ones. Defining anything else in this file will cause the

CGroup Rules Engine program to fail. So, don't do it.

The pathname to the configuration file for CGroup Rules Engine

CONFIG_FILE="/etc/cgrules.conf"

Uncomment the following line to log to specified file instead of syslog

LOG_FILE="/var/log/cgrulesengd.log"

Uncomment the second line to run CGroup Rules Engine in non-daemon mode

NODAEMON="-n"

NODAEMON="--nodaemon"

Set owner of cgred socket. 'cgexec' tool should have write access there

(either using suid and/or sgid permissions or Linux capabilities).

SOCKET_USER=""

SOCKET_GROUP="cgred"

Uncomment the second line to disable logging for CGroup Rules Engine

Uncomment the third line to enable more verbose logging.

LOG=""

LOG="--nolog"

LOG="-v"

Plik /etc/cgrules.conf :

:firefox cpu,memory users/firefox/ *:firefox cpu,memory users/firefox/

:qbittorrent cpu users/qbittorrent/ *:qbittorrent cpu users/qbittorrent/ :qbittorrent-nox cpu users/qbittorrent/ *:qbittorrent-nox cpu users/qbittorrent/

:minitube cpu users/minitube/ *:minitube cpu users/minitube/

W pliku /etc/cgrules.conf są definiowane reguły dla cgrulesengd. Pierwsza kolumna może się składać z samego użytkownika, w tym przypadku * odnosi się do wszystkich użytkowników w systemie. W tym miejscu może być także określona grupa za pomocą @morfik zamiast użytkownika. Proces nie jest wymagany ale można go sprecyzować po :. Przyjmuje on wartość, albo pełnej ścieżki do programu, albo nazwy procesu widocznego np. w ps . Następna kolumna odpowiada za moduły cgroups, do których proces będzie przypisywany. Jeśli proces ma być przypisany do wszystkich podsystemów cgroups, można posłużyć się * . Ostatnia kolumna to położenie w drzewie katalogów cgroups, czyli tam gdzie plik tasks się powinien znajdować, do którego to cgrulesengd będzie przesyłał pidy procesów.

Dodajemy skrypty do autostartu:

update-rc.d cgrulesengd defaults

update-rc.d cgconfig defaults

I to w zasadzie tyle jeśli chodzi o implementację cgroups w debianie. Wszystkie procesy, które chcemy kontrolować definiujemy w /etc/cgrules.conf , a linijki z wartościami dla określonych plików wpisujemy do /etc/init.d/cgconfig .

W przypadku gdyby coś nie działało można użyć poniższych poleceń w celu sprawdzenia czy cgroups jest poprawnie montowany, w których miejscach i czy procesy są przypisane do odpowiednich grup. Można w tym celu użyć albo narzędzi dostarczonych przez cgroup-bin albo też i ręcznie odpytywać określone pliki. I tak np. sprawdźmy czy jest coś w ogóle łapane przez cgroups:

lscgroup

blkio:/ cpu:/ cpu:/users cpu:/users/minitube cpu:/users/qbittorrent cpu:/users/firefox cpuacct:/ cpuacct:/users cpuacct:/users/firefox cpuset:/ cpuset:/users cpuset:/users/firefox devices:/ freezer:/ memory:/ memory:/users memory:/users/firefox net_cls:/users net_cls:/users/minitube net_cls:/users/qbittorrent net_cls:/users/firefox net_prio:/ perf_event:/

Jak widać powyżej, grupy są utworzone prawidłowo i cgroups je widzi w strukturze katalogów. Jeśli jednak byśmy mieli więcej aplikacji kontrolowanych przez cgroups, możemy ograniczyć się do wyszukania konkretnego procesu i sprawdzenia czy z nim jest wszystko w porządku. W tym celu trzeba odszukać pid w /proc/ :

cat /proc/pidof firefox/cgroup

11:perf_event:/ 10:net_prio:/ 9:net_cls:/users/firefox 8:memory:/users/firefox 7:freezer:/ 6:devices:/ 5:cpuset:/ 4:cpuacct:/ 3:cpu:/users/firefox 2:blkio:/

Jeśli nie wiemy czy wirtualny system plików cgroups jest w ogóle montowany, możemy to sprawdzić przez:

lssubsys -am

cpuset /cgroups/cpuset cpu /cgroups/cpu cpuacct /cgroups/cpuacct memory /cgroups/memory devices /cgroups/devices freezer /cgroups/freezer net_cls /cgroups/net_cls blkio /cgroups/blkio perf_event /cgroups/perf_event net_prio /cgroups/net_prio

Jeśli chcemy mieć trochę więcej info możemy odpytać /proc/mounts :

grep 'cgroup' /proc/mounts

none /cgroups/blkio cgroup rw,relatime,blkio,clone_children 0 0 none /cgroups/cpu cgroup rw,relatime,cpu,clone_children 0 0 none /cgroups/cpuacct cgroup rw,relatime,cpuacct,clone_children 0 0 none /cgroups/cpuset cgroup rw,relatime,cpuset,clone_children 0 0 none /cgroups/devices cgroup rw,relatime,devices,clone_children 0 0 none /cgroups/freezer cgroup rw,relatime,freezer,clone_children 0 0 none /cgroups/memory cgroup rw,relatime,memory,clone_children 0 0 none /cgroups/net_cls cgroup rw,relatime,net_cls,clone_children 0 0 none /cgroups/net_prio cgroup rw,relatime,net_prio,clone_children 0 0 none /cgroups/perf_event cgroup rw,relatime,perf_event,clone_children 0 0

Informacje na temat dostępnych podsystemów cgroups i ich hierarchii można odnaleźć pod:

cat /proc/cgroups

subsys_name hierarchy num_cgroups enabled

cpuset 5 3 1 cpu 3 5 1 cpuacct 4 3 1 memory 8 3 1 devices 6 1 1 freezer 7 1 1 net_cls 9 1 1 blkio 2 1 1 perf_event 11 1 1 net_prio 10 1 1

Jeśli problem leży gdzieś indziej i powyższe polecenia zwracają pożądane wartości, być może problem tkwi w demonie cgrulesengd . Najlepszym wyjściem jest sprawdzenie czy aby na pewno pidy procesów trafiają do plików tasks:

morfik:~$ cat /cgroups/cpu/users/firefox/tasks 30859 30921 30922 30923 30924 30925 30926 30927 30928 30929 30931 30932 30933 30934 30935 30973 30974 30975 30976 30978 30979 30980 30989 30990 30991 30992 31003 31005 31024 31025 31081 31082 31101

W przypadku braku pidów w pliku tasks, oznacza to, że demon, albo nie działa, albo jest źle skonfigurowany. W takiej sytuacji zostaną również wyrzucone informacje w syslogu ilekroć tylko odpalimy aplikację, której pid powinien powędrować do pliku tasks. Watro zajrzeć w logi systemowe w przypadku problemów.

  1. NICE, IONICE, TASKSET oraz TRICKLE

Jeśli cgroups nas przerasta albo z jakiegoś powodu nie możemy z niego korzystać, jest inne wyjście, które bardzo dobrze sprawdza się przy skryptach czy programach. Mowa tutaj o nice, ionice, taskset oraz trickle. Ten pierwszy limituje wykorzystanie procesora, drugi zaś dysku twardego. Z kolei pozostałe dwa odpowiadają za przypisanie procesu konkretnemu rdzeniowi oraz za limitowanie sieci.

Jeśli chodzi o nice i ionice, to bardzo często wykorzystuje się te dwa razem, konfigurując przy ich pomocy procesy, które mają za zadanie działać w tle i nie sprawiać pozorów swojego istnienia, np. przy backupie danych. Każdy chyba wie, że w takich sytuacjach dysk ostro ryje i czasem to zachowanie uniemożliwia normalną pracę na kompie.

Jeśli chcemy ograniczyć zasoby jakiemuś procesowi, przy jego wywoływaniu dodajemy nice, ionice, taskset albo trickle z odpowiednimi opcjami, w zależności od tego do jakich zasobów chcemy mu ograniczyć dostęp. Możliwe jest sprecyzowanie kilku z nich jeden po drugim, co stworzy drzewo procesów, na końcu którego będzie nasza aplikacja, a działa to na zasadzie dziedziczenia parametrów procesów -- jeśli proces z nice -n 19 wywoła inny proces, ten drugi również dostanie nice -n 19. Przykładowe wywołanie skryptu od backupu:

$ nice -n 19 ionice -c 3 backup.sh

Priorytety dla nice są z zakresu -20 do 19. Zwykły użytkownik może nadawać tylko priorytety od 0 do 19. Im wyższy numer tym niższy priorytet, czyli procesy z numerem -20 mają najwyższy priorytet, a te z numerem 19 najniższy.

W przypadku ionice, przy pomocy -c 3 ustalamy zapis/odczyt dysku na tryb idle, czyli gdy inne procesy go nie wykorzystują. Możliwe jest także sprecyzowanie mniej agresywnego rozwiązani czyli -c 2 -n 7. Przy czym opcja -n w tym przypadku jest z zakresu 0-7 i również im mniejsza wartość, tym wyższy priorytet, a im wyższy priorytet, tym lepszy dostęp do dysku.

Warto jeszcze wiedzieć jak zmieniać priorytety uruchomionych programów. Jeśli chcemy zmienić wcześniej nadany priorytet przy pomocy nice, używamy renice, z tym, że definiujemy proces za pomocą opcji -p:

$ renice -n 10 -p 1110

Podobnie z ionice:

$ ionice -c 2 -n 5 -p 1110

Jest tylko jeden problem. Co w przypadku drzewa procesów? Raczej nikomu się nie będzie chciało zmieniać 20 procesów potomnych. Można to zrobić szybciej przez uzyskanie id sesji procesów:

ps -j

PID PGID SID TTY TIME CMD 8077 8077 9924 pts/8 00:00:00 build 8252 8077 9924 pts/8 00:00:00 build 8253 8077 9924 pts/8 00:00:00 build 8254 8077 9924 pts/8 00:00:00 tee 8351 8077 9924 pts/8 00:00:00 bootstrap 9443 8077 9924 pts/8 00:00:00 bootstrap_archi 9561 8077 9924 pts/8 00:00:00 aptitude 9567 8077 9924 pts/8 00:00:00 http 9572 8077 9924 pts/8 00:00:00 gpgv 9595 8077 9924 pts/8 00:00:00 bzip2 9970 9970 9924 pts/8 00:00:00 su 10009 10009 9924 pts/8 00:00:00 ps 10051 10051 9924 pts/8 00:00:00 bash

Id procesów można także wyciągnąć z pgrep , o ile znamy id sesji:

pgrep -s 9924

8077 8252 8253 8254 8351 9443 9561 9567 9572 9595 9924 9970 10051

lub też przez:

ps -eo sess:1=,pid:1=,nice:1= | grep 9924

9924 8077 0 9924 8252 0 9924 8253 0 9924 8254 0 9924 8351 0 9924 9443 0 9924 9561 0 9924 9567 0 9924 9572 0 9924 9595 0 9924 9924 0 9924 9970 0 9924 10051 0

Ten ostatni pokazuje także aktualny nice. By zmienić nice wszystkim procesom podpiętym do jednej sesji, wydajemy poniższe polecenie :

renice -n 19 $(pgrep -s 9924)

8252 (process ID) old priority 0, new priority 19 8253 (process ID) old priority 0, new priority 19 8254 (process ID) old priority 0, new priority 19 8351 (process ID) old priority 0, new priority 19 9443 (process ID) old priority 0, new priority 19 9561 (process ID) old priority 0, new priority 19 9567 (process ID) old priority 0, new priority 19 9572 (process ID) old priority 0, new priority 19 9595 (process ID) old priority 0, new priority 19 9924 (process ID) old priority 0, new priority 19 9970 (process ID) old priority 0, new priority 19 10051 (process ID) old priority 0, new priority 19

Jak widać priorytety uległy zmianie. Podobnie postępujemy z ionice:

ionice -c 3 -p $(pgrep -s 9924)

Jeśli interesuje nas by danym procesem zajmował się określony rdzeń, możemy dodatkowo dopisać do linijki wywoławczej taskset i numer rdzenia, a te są numerowane od 0. I tak dla przykładu jeśli chcemy by amarok działał na pierwszym rdzeniu (numer zero), wydajemy poniższe polecenie:

$ taskset -c 0 amarok

Jeśli chcemy zmienić przydział rdzeni procesora dla uruchomionego już procesu:

$ taskset -p -c 0 15538 pid 15538's current affinity list: 0,1 pid 15538's new affinity list: 0

I na dwa rdzenie:

$ taskset -p -c 0,1 15538 pid 15538's current affinity list: 0 pid 15538's new affinity list: 0,1

Z kolei trickle zajmuje się ograniczaniem pasma sieciowego dla danego procesu. Jednak trzeba uważać by nie ustawić zbyt niskiej wartości, bo wtedy odpalany program zacznie sypać błędami typu segfault. Jeśli chcemy nadać ograniczenie jakiemuś programu, który komunikuje się z siecią, powiedzmy 500KB/s down i 100KB/s up, robimy to w ten sposób:

$ trickle -s -d 500 -u 100 qbittorrent

Więcej informacji na temat nice, renice, ionice, taskset i trickle możn znaleźć tu i tu.

Traffic control, czyli jak limitować sieć p2p bez uszczerbku dla niej samej

$
0
0
  1. Interfejsy IMQ

     1.1. Konfiguracja przepływu
    
  2. Jeśli nie IMQ, to co w takim razie?

     2.1. Kształtowanie ruchu wychodzącego przy pomocy -j CLASSIFY
     2.2. Kształtowanie ruchu wychodzącego przy pomocy cgroups
    
  3. Interfejsy IFB

  4. Statystyki ruchu
  5. Jak odpalać qbittorrenta?

Od wielu miesięcy chodziło mi po głowie zrealizowanie pewnego projektu polegającego na wydzieleniu określonego pasma sieciowego pod qbittorrenta, tak by on sobie działał w tle non stop i konsumował możliwie dużo łącza (download/upload), przy czym bez strat dla pozostałych usług sieciowych. Każdy chyba wie, że gdy odpalimy torrenta na full, to pingi nam zaraz skaczą na paręset ms, czy nawet parę sekund. Dodatkowo jeśli coś pobieramy na torrencie i zachodzi potrzeba pobrania czegoś via firefox, to transfer w najlepszym wypadku rozłoży się w proporcjach 50:50 -- pół łącza przydzielone zostanie qbittorrentowi, a drugi pół firefoxowi. To samo tyczy się uploadu, gdy chcemy coś wysłać np. na dropboxa, wtedy nie ma innego wyjścia jak albo przykręcić kurek qbittorrentowi bezpośrednio w kliencie, albo wyłączyć qbittorrenta zupełnie na czas wysyłania danych do dropboxa. Teoretycznie niby UTP ma łagodzić skutki korzystania z sieci p2p ale coś to nie bardzo u mnie działa. Qbittorrent, co prawda, ma też wbudowany scheduler i można z niego korzystać, np ustawiając transfer wyższy w określonych godzinach, tych, w których wiemy, że nic na kompie nie będziemy robić, czyli w nocy. Ja korzystałem z tego typu rozwiązania przez pewien czas ale ciągle musiałem te godziny przestawiać, w końcu to wyłączyłem i przeszedłem na manualny system zmiany prędkości, przez klikanie tego miernika w qbittorencie, co mnie doprowadzało do szaleństwa.

W każdym razie to przeszłość, od paru dni walczyłem z zaimplementowaniem traffic control, czyli kontroli ruchu sieciowego, bezpośrednio w kernelu, coś co umożliwia dynamiczny przydział łącza w zależności od obciążenia sieci. Oczywiście to jaki wynik chcemy osiągnąć zależy w dużej mierze od konfiguracji ale udało mi się stworzyć setup, który przydziela qbittorrentowi tyle łącza ile jest aktualnie wolnego i nie trzeba przy tym sobie głowy zawracać.

Jest kilka różnych sposobów na osiągnięcie zadowalających nas efektów, ale nie w każdym z nich idzie zrealizować pewne rzeczy. Największe problemy stwarza ruch przychodzący i jeśli chcemy go również kształtować, będziemy musieli się trochę napracować. Oczywiście nic z czym byśmy sobie nie poradzili ale w przypadku qbittorrenta jest to trochę uciążliwe, bo ten lata po portach i adresach ip jak szalony i nie da się stworzyć żadnej prostej reguły by złapać ten ruch. W każdym innym przypadku, kształtowanie ruchu przychodzącego nie będzie raczej nastręczać większych problemów ale my się nie zajmiemy "każdym innym przypadkiem", my tu rozpracujemy jak ogarnąć ruch p2p, tak by człowiek nie bał się odpalić qbittorrenta, bo ten mu uniemożliwi przeglądanie pornusów czy fejsa...

Jak zatem kształtować ruch? Do dyspozycji mamy kilka narzędzi -- podstawowe to tc z pakietu iproute2 . To za jego pomocą wyznaczymy kolejki na interfejsach sieciowych, do których będą napływać pakiety. To tu również będą ustawione gwarantowane limity łącza, oraz jak dużo pasma może zapożyczyć sobie dana kolejka. Jednak samo stworzenie kolejek nic nam nie da, pakiety trzeba jakoś do nich przekierować i tu, w zależności od tego co tak naprawdę chcemy osiągnąć, możemy skorzystać z filtra tc albo też zaciągnąć do pomocy iptables albo nawet i cgroups. Należy pamiętać przy tym, że cgroups może oznaczać tylko (chyba) pakiety wychodzące i nie da rady go użyć na ruchu skierowanym do naszej maszyny.

  1. Interfejsy IMQ

Na sam początek walimy z grubej rury, czyli spróbujemy kształtować ruch zarówno wychodzący jak i przychodzący. Najprościej to zrobić przy pomocy interfejsów IMQ ale kernel debianowy (jak i każdy inny) domyślnie nie obsługuje ich. Podobnie też jest z iptables, gdyż nie ma jak przekierować ruchu na te interfejsy -- no nieźle. Bez rekompilacji kernela i iptables się niestety nie obejdzie. Musimy założyć patche IMQ, dostępne pod tym linkiem http://www.linuximq.net/patches.html. Musimy pobrać patch dla kernel 3.12.4+ oraz patch dla iptables 1.4.13.x . Musimy także skołować źródła kernela oraz iptables. Źródła iptables można pobrać z repo debiana:

apt-get -t testing source iptables

Reading package lists... Done Building dependency tree Reading state information... Done Selected version '1.4.21-1' (testing) for iptables Need to get 609 kB of source archives. Get:1 http://ftp.pl.debian.org/debian/ testing/main iptables 1.4.21-1 (dsc) [1,290 B] Get:2 http://ftp.pl.debian.org/debian/ testing/main iptables 1.4.21-1 (tar) [547 kB] Get:3 http://ftp.pl.debian.org/debian/ testing/main iptables 1.4.21-1 (diff) [60.6 kB] Fetched 609 kB in 0s (644 kB/s) dpkg-source: info: extracting iptables in iptables-1.4.21 dpkg-source: info: unpacking iptables_1.4.21.orig.tar.bz2 dpkg-source: info: unpacking iptables_1.4.21-1.debian.tar.gz dpkg-source: info: applying 0101-changelog.patch dpkg-source: info: applying 0102-add_manpages.patch dpkg-source: info: applying 0103-lintian_allows_to.patch dpkg-source: info: applying 0104-lintian_hyphens.patch dpkg-source: info: applying 0105-lintian_spelling.patch dpkg-source: info: applying 0201-660748-iptables_apply_man.patch dpkg-source: info: applying 0202-725413-sctp_man_description.patch dpkg-source: info: applying 0301-install_iptables_apply.patch dpkg-source: info: applying 0401-580941-iptables_apply_update.patch

Przy czym trzeba dodać deb-src do /etc/apt/sources.list

deb http://ftp.pl.debian.org/debian/ testing main non-free contrib deb-src http://ftp.pl.debian.org/debian/ testing main non-free contrib

Mając odpowiednią łatę na iptables, nakładamy ją na źródła:

cd iptables-1.4.21/

patch -p1 < ../iptables-1.4.13-IMQ-test1.diff

patching file extensions/libxt_IMQ.c patching file extensions/libxt_IMQ.man patching file include/linux/netfilter/xt_IMQ.h

I budujemy paczuszkę deb:

aptitude build-dep iptables

dpkg-buildpackage -uc -us -b

Ze źródłami kernela jest trochę gorzej, bo te debianowe mają zaaplikowane własne patche, co trochę uniemożliwia bezstresowe założenie patcha IMQ. Niby na stronie IMQ jest tam wzmianka o tym problemie ale nie mam zielonego pojęcia co powinno zostać zmienione, by ten patch wszedł bez problemu. W każdym razie, jeśli nie debianowy kernel, to trzeba pobrać źródła z oficjalnej strony kernela, https://www.kernel.org/ i tym przypadku jest to 3.12.9 .

Po pobraniu źródeł kernela sprawdzamy podpis:

xz -cd linux-3.12.9.tar.xz | gpg --verify linux-3.12.9.tar.sign -

gpg: Signature made Sat 25 Jan 2014 06:22:11 PM CET using RSA key ID 6092693E gpg: Good signature from "Greg Kroah-Hartman (Linux kernel stable release signing key) greg@kroah.com" gpg: WARNING: This key is not certified with a trusted signature! gpg: There is no indication that the signature belongs to the owner. Primary key fingerprint: 647F 2865 4894 E3BD 4571 99BE 38DB BDC8 6092 693E

Jeśli by były jakieś problemy z weryfikacją podpisu, na stronie kernela jest dokładna rozpiska co i jak.

Łatamy kernela:

tar xfp linux-3.12.9.tar.xz

xz -d linux-imqmq-3.12.4+.patch.xz

cd linux-3.12.9/

patch -p1 < ../linux-imqmq-3.12.4+.patch

patching file drivers/net/Kconfig patching file drivers/net/Makefile patching file drivers/net/imq.c patching file include/linux/imq.h patching file include/linux/netfilter/xt_IMQ.h patching file include/linux/netfilter_ipv4/ipt_IMQ.h patching file include/linux/netfilter_ipv6/ip6t_IMQ.h patching file include/linux/skbuff.h Hunk #6 succeeded at 2658 (offset 5 lines). patching file include/net/netfilter/nf_queue.h patching file include/uapi/linux/netfilter.h patching file net/core/dev.c patching file net/core/skbuff.c patching file net/ipv6/ip6_output.c patching file net/netfilter/Kconfig patching file net/netfilter/Makefile patching file net/netfilter/core.c patching file net/netfilter/nf_internals.h patching file net/netfilter/nf_queue.c patching file net/netfilter/xt_IMQ.c

Kopiujemy starą konfigurację kernela i odpalamy menuconfig:

cp /boot/config-3.12-1-amd64 ./.config

make menuconfig

 -> Device Drivers --->
   -> Network device support --->
     -> Network core driver support --->
         <M>     IMQ (intermediate queueing device) support

 -> Networking support --->
   -> Networking options --->
     -> Network packet filtering framework (Netfilter) --->
       -> Core Netfilter Configuration --->
           <M>   "IMQ" target support

Zapisujemy konfigurację, kompilujemy i robimy paczuszkę deb:

aptitude build-dep linux-image-uname -r

make-kpkg -j2 --initrd kernel-image kernel-headers

Po kompilacji powinniśmy mieć 4 paczki, instalujemy je:

dpkg -i iptables_1.4.21-1_amd64.deb libxtables10_1.4.21-1_amd64.deb linux-image-3.12.9-morfik-imq_amd64.deb linux-headers-3.12.9-morfik-imq_amd64.deb

Musimy jeszcze załadować odpowiednie moduły na starcie systemu:

cat /etc/modules

... imq numdevs=2 ipt_IMQ ...

Jeśli wszystko przebiegło bez problemów, możemy zresetować maszynę.

1.1. Konfiguracja przepływu

Powinniśmy mieć już w systemie interfejsy IMQ, sprawdźmy zatem czy tak faktycznie jest:

ip link show

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000 link/ether 00:e0:4c:75:03:09 brd ff:ff:ff:ff:ff:ff 3: imq0: <NOARP> mtu 16000 qdisc htb state DOWN mode DEFAULT group default qlen 11000 link/void 4: imq1: <NOARP> mtu 16000 qdisc htb state DOWN mode DEFAULT group default qlen 11000 link/void

Jak widać, nie są jeszcze aktywowane, podnieśmy je:

ip link set imq0 up

ip link set imq1 u

W tej chwili możemy już kierować ruch do nich, potrzebujemy jeszcze odpowiednich kolejek i konfiguracji iptables. Kolejki tworzymy przy pomocy narzędzia tc:

tc qdisc add dev imq0 root handle 1:0 htb default 4

tc class add dev imq0 parent 1:0 classid 1:1 htb rate 950kbit ceil 950kbit

tc class add dev imq0 parent 1:1 classid 1:2 htb rate 250kbit ceil 950kbit prio 5

tc class add dev imq0 parent 1:1 classid 1:3 htb rate 450kbit ceil 950kbit prio 0

tc class add dev imq0 parent 1:1 classid 1:4 htb rate 250kbit ceil 950kbit prio 2

tc qdisc add dev imq1 root handle 2:0 htb default 4

tc class add dev imq1 parent 2:0 classid 2:1 htb rate 9500kbit ceil 9500kbit

tc class add dev imq1 parent 2:1 classid 2:2 htb rate 2500kbit ceil 9500kbit prio 5

tc class add dev imq1 parent 2:1 classid 2:3 htb rate 4500kbit ceil 9500kbit prio 0

tc class add dev imq1 parent 2:1 classid 2:4 htb rate 2500kbit ceil 9500kbit prio 2

Powyższe linijki stworzą nam 3 klasy dla każdego interfejsu. Do kolejek 1:2 i 2:2 będzie szedł ruch z qbittorrenta, przez 1:3 i 2:3 będzie przepuszczony ruch użytkownika root oraz morfik, a na klasy 1:4 oraz 2:4 będzie szło wszystko co się nie załapie do powyższych. W tym przypadku korzystam z algorytmu HTB ale jest też kilka innych, a wszystkie można podzielić na dwie kategorie -- bezklasowe (pfifo, bfifo, pfifo_fast, red, sfq, tbf) i klasowe (CBQ, HTB, PRIO). Informacje na temat każdego z powyższych algorytmów można znaleźć w manie tc. Jest też całkiem przyzwoity opis każdego z algorytmów, dostępny pod tym linkiem.

Składnia HTB jest prosta i tam gdzie nie precyzujemy opcji, są one ustawiane na wartości domyślne. W powyższym przykładzie tworzymy qdisc na interfejsie imq0 i określamy 4 jako domyślą kolejkę, do której będzie trafiał ruch. Jeśli nie określimy domyślnej kolejki, ruch który nie trafi do żadnej z kolejek, nie będzie ulegał kształtowaniu. Zakładamy główną kolejkę (1:1) i ustawiamy jej limit 950kbitów. Mam, co prawda, 1mbit uploadu ale zaleca się by ten limit był troszeczkę mniejszy niż maksymalna przepustowość łącza, bo musimy mieć najwęższe ogniwo w tym całym procesie przesyłania informacji, by móc kształtować ruch. Następnie tworzymy 3 kolejki wewnątrz wyznaczonego pasma, odpowiednio nadając im parametr rate i ceil. Parametr rate odpowiada za gwarantowaną przepustowość jaką otrzyma kolejka. W przypadku gdy łącze będzie obciążone na full, kolejka 1:2 będzie miała do dyspozycji 250kbitów i nikt jej tego nie pozbawi. Podobnie z pozostałymi kolejkami. Parametr ceil z kolei ustawia górny limit, czyli ile kolejka może pożyczyć łącza od innych kolejek ale tylko w przypadku gdy te nie wykorzystują swojego pasma w pełni. Przykładowo, qbittorrent ma przeznaczone 250kbitów uploadu, gdy osiągnie ten limit sprawdzi czy może sobie coś pożyczyć i jeśli łącze nie będzie obciążone, to zwiększy sobie dostępne zasoby do 950kbitów. Jak tylko jakiś proces, który jest przypisany do pozostałych dwóch kolejek będzie chciał skorzystać z internetu, natychmiast zostanie przykręcony kurek qbittorrentowi. Jeśli proces zakończy buszowanie po internecie i zwolni zasoby, qbittorrent automatycznie zacznie wykorzystywać łącze w pełni ponownie i tak dalej. Podobnie z pobieraniem danych z internetu. Ważne jest by ustawić jeszcze odpowiedni priorytet. Jeśli kolejka ma wyższy priorytet (mniejszy numer), będzie miała dostęp do niewykorzystanych zasobów jako pierwsza, tj. jeśli kolejka 1:2 i 1:3 będą zjadać 100% swojego przydziału, zostanie im rywalizacja o pozostałe 250kbitów dostępnych w kolejce 1:4. Jeśli grupa 1:3 będzie miała wyższy priorytet i będzie chciała dodatkowe 250kbitów, będzie mogła skorzystać z dostępnego pasma 1:4 w pełni, a qbittorrent na linii 1:2 będzie musiał ograniczyć zużycie do 100% swojego pasma. Dopiero w przypadku gdy kolejka 1:3 nie będzie w pełni wykorzystywać zasobów kolejki 1:4, qbittorrent (1:2) będzie mógł skorzystać z dodatkowych zasobów kolejki 1:4. I o takie zachowanie nam chodzi.

Mamy zatem zrobionych parę kolejek. Trzeba jeszcze jakoś przekierować tam ruch. Najprościej to zrobić przy pomocy iptables:

iptables -t mangle -A PREROUTING -i eth0 -j IMQ --todev 1

iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark

iptables -t mangle -N IMQ-OUT

iptables -t mangle -A POSTROUTING -o eth0 -j IMQ-OUT

iptables -t mangle -A IMQ-OUT -m owner --gid-owner p2p -j MARK --set-mark 2

iptables -t mangle -A IMQ-OUT -m owner --gid-owner p2p -j RETURN

iptables -t mangle -A IMQ-OUT -m owner --uid-owner morfik -j MARK --set-mark 3

iptables -t mangle -A IMQ-OUT -m owner --uid-owner morfik -j RETURN

iptables -t mangle -A IMQ-OUT -m owner --uid-owner root -j MARK --set-mark 3

iptables -t mangle -A IMQ-OUT -m owner --uid-owner root -j RETURN

iptables -t mangle -A POSTROUTING -j CONNMARK --save-mark

iptables -t mangle -A POSTROUTING -o eth0 -j IMQ --todev 0

Ten patch co założyliśmy na iptables daje nam możliwość zastosowania celu -j IMQ, a ten przyjmuje tylko argument --todev i numer interfejsu. Zatem przekierowaniem ruchu na interfejsy zajmują się te dwie linijki z -j IMQ. W zależności czy jest to ruch wychodzący czy przychodzący, pakiety biegną odpowiednio do interfejsów imq0 i imq1. Reguły z -j CONNMARK zapiszą oznaczenia w /proc/net/ip_conntrack , a samo oznaczenie dokonuje się przez -j MARK --set-mark. Trzeba jednak uważać by czasem nie nadpisać marków, bo jeśli pakiet przechodzić przez pierwszą pozycję z -j MARK , to nie kończy jego podróży w łańcuchu, dlatego właśnie został zrobiony osobny łańcuch do markowania pakietów i tam skorzystaliśmy z -j RETURN -- jak tylko pakiet zostanie przypasowany, zostaje zwrócony do łańcucha wyżej, w tym przypadku POSTROUTING i biegnie sobie dalej przez reguły tego łańcucha. Bez -j RETURN, pakiet by przeszedł przez wszystkie reguły w łańcuchu IMQ-OUT, co w pewnych sytuacjach ustawi złego marka. Mamy dodatkowo większe opóźnienie spowodowane dłuższą trasą pakietu. W powyższym przykładzie został wykorzystany moduł -m owner jako baza przy oznaczaniu pakietów i pakiety konkretnych użytkowników/grup zostaną oznaczone. Można oczywiście w dowolny sposób oznaczać pakiety, ale za bardzo nie widzę innej opcji by wyłapać ruch qbittorrenta.

Potrzebujemy jeszcze odpowiednich filtrów tc by przekierować konkretne pakiety do przeznaczonych dla nich kolejek:

tc filter add dev imq0 protocol ip parent 1:0 prio 1 handle 2 fw classid 1:2

tc filter add dev imq0 protocol ip parent 1:0 prio 5 handle 3 fw classid 1:3

tc filter add dev imq1 protocol ip parent 2:0 prio 3 handle 2 fw classid 2:2

tc filter add dev imq1 protocol ip parent 2:0 prio 7 handle 3 fw classid 2:3

Przypisujemy filter do określonego interfejsu (tc filter add dev imq0 protocol ip) nadajemy mu priorytet (prio 1) i ustawiamy znacznik (handle 2), na podstawie którego pakiet zostanie przekierowany do odpowiedniej kolejki (classid 1:2). Liczba w handle musi odpowiada tej w --set-mark .

Powinno działać. Przy pomocy narzędzia bmon możemy zaobserwować cośmy uczynili. Poniżej prezentuje się rozpiska przy oglądaniu przez morfika czegoś na yt:

Interfaces | RX bps pps %| TX bps pps % lo | 294B 2 | 294B 2 eth0 | 1.13MiB 871 | 76.13KiB 545 qdisc none (pfifo_fast) | 0 0 | 74.37KiB 545 imq0 | 66.84KiB 545 | 67.30KiB 547 qdisc 1: (htb) | 0 0 | 67.30KiB 547 cls :2 (fw) | 0 0 | 0 0 cls none (fw) | 0 0 | 0 0 cls :3 (fw) | 0 0 | 0 0 class 1:1 (htb) | 0 0 | 67.30KiB 547 58% -> class 1:2 (htb) | 0 0 | 55.18KiB 245 181% class 1:3 (htb) | 0 0 | 11.70KiB 299 21% class 1:4 (htb) | 0 0 | 431B 3 1% imq1 | 1.12MiB 866 | 1.13MiB 878 qdisc 2: (htb) | 0 0 | 1.13MiB 878 cls :2 (fw) | 0 0 | 0 0 cls none (fw) | 0 0 | 0 0 cls :3 (fw) | 0 0 | 0 0 class 2:1 (htb) | 0 0 | 1.13MiB 878 100% class 2:2 (htb) | 0 0 | 278.65KiB 275 91% class 2:3 (htb) | 0 0 | 882.11KiB 602 161% class 2:4 (htb) | 0 0 | 62B 0 0%

Jak można zaobserwować, stan downloadu/uploadu wynosi 100%/58%. Klasa 2:3 konsumuje 161% przewidzianych zasobów dla tej kolejki -- zjada wolny przydział klasy 2:4 i trochę transferu 2:2, bo qbittorrent nie wykorzystuje swojego pasma w pełni. Podobnie jest z uploadem. Kolejka morfika ma wykorzystane nieco ponad 20% przewidzianych środków, dlatego qbittorrent sobie nieco zapożyczył z innych kolejek. I to tak sobie będzie się automatycznie regulować.

W przypadku gdyby łącze nie było obciążone, staty będą się prezentować następująco:

Interfaces | RX bps pps %| TX bps pps % ->lo | 196B 2 | 196B 2 eth0 | 14.70KiB 115 | 117.72KiB 129 qdisc none (pfifo_fast) | 0 0 | 117.71KiB 129 imq0 | 116.28KiB 128 | 116.03KiB 129 qdisc 1: (htb) | 0 0 | 116.03KiB 129 cls :2 (fw) | 0 0 | 0 0 cls none (fw) | 0 0 | 0 0 cls :3 (fw) | 0 0 | 0 0 class 1:1 (htb) | 0 0 | 116.03KiB 129 100% class 1:2 (htb) | 0 0 | 115.76KiB 126 379% class 1:3 (htb) | 0 0 | 164B 2 0% class 1:4 (htb) | 0 0 | 109B 0 0% imq1 | 12.99KiB 111 | 12.99KiB 111 qdisc 2: (htb) | 0 0 | 12.99KiB 111 cls :2 (fw) | 0 0 | 0 0 cls none (fw) | 0 0 | 0 0 cls :3 (fw) | 0 0 | 0 0 class 2:1 (htb) | 0 0 | 12.99KiB 111 1% class 2:2 (htb) | 0 0 | 7.58KiB 107 2% class 2:3 (htb) | 0 0 | 5.34KiB 3 1% class 2:4 (htb) | 0 0 | 62B 0 0%

I jak widzimy, qbittorrent zjada całe pasmo uploadu, 279% ponad swój przydział. Sprawdźmy zatem jak wyglądają opóźnienia w takiej sytuacji:

$ ping wp.pl -c 10 PING wp.pl (212.77.100.101) 56(84) bytes of data. 64 bytes from www.wp.pl (212.77.100.101): icmp_seq=1 ttl=247 time=22.0 ms 64 bytes from www.wp.pl (212.77.100.101): icmp_seq=2 ttl=247 time=28.4 ms 64 bytes from www.wp.pl (212.77.100.101): icmp_seq=3 ttl=247 time=24.1 ms 64 bytes from www.wp.pl (212.77.100.101): icmp_seq=4 ttl=247 time=25.2 ms 64 bytes from www.wp.pl (212.77.100.101): icmp_seq=5 ttl=247 time=20.3 ms 64 bytes from www.wp.pl (212.77.100.101): icmp_seq=6 ttl=247 time=22.2 ms 64 bytes from www.wp.pl (212.77.100.101): icmp_seq=7 ttl=247 time=23.9 ms 64 bytes from www.wp.pl (212.77.100.101): icmp_seq=8 ttl=247 time=34.3 ms 64 bytes from www.wp.pl (212.77.100.101): icmp_seq=9 ttl=247 time=21.9 ms 64 bytes from www.wp.pl (212.77.100.101): icmp_seq=10 ttl=247 time=23.6 ms

--- wp.pl ping statistics --- 10 packets transmitted, 10 received, 0% packet loss, time 9004ms rtt min/avg/max/mdev = 20.371/24.638/34.344/3.859 ms

Całkiem nieźle jak na zapchane łącze przez p2p. Taka mała uwaga jeszcze, może i to fajnie działa ale u mnie przy pobieraniu czegoś przez qbittorrenta, download w nim trochę ssie, a właściwie nie bardzo chce ssać. Trzeba nieco upload przykręcić, tak 5-7% powinno wystarczyć, bo jak nie patrzeć przy pobieraniu plików, pakiety również trzeba wysłać. Trochę to dziwne, że qbittorrent tego nie reguluje automatycznie, a może to ja nie potrafię tego skonfigurować.

Gdzieś na necie znalazłem sposób na wyłapanie tych pakietów i nadanie im wyższego priorytetu. U mnie podziałało, także jeśli nie chce nam się ograniczać uploadu w qbittorrencie, możemy dopisać poniższe regułki w iptables i wstawić je na pierwsze miejsce w łańcuchu IMQ-OUT :

iptables -t mangle -A IMQ-OUT -o eth0 -m length --length 40:68 -j MARK --set-mark 3

iptables -t mangle -A IMQ-OUT -o eth0 -m length --length 40:68 -j RETURN

Można oczywiście stworzyć osobną kolejkę dla tych pakietów, tak by przy pobieraniu czegoś, nie przydusiły one pozostałych procesów korzystających z internetu.

Przydałoby się jeszcze zrobić skrypt startowy, co by nam te kolejki konfigurował na starcie systemu. W sumie to można poskładać powyższą konfigurację tc i iptables i wrzucić do jednego skryptu, a ten umieścić na odpowiedniej pozycji w autostarcie systemu. Mój skrypt wygląda tak:

BEGIN INIT INFO

Provides: imq

Required-Start: mountkernfs $local_fs

Required-Stop: $local_fs

Should-Start:

Should-Stop:

Default-Start: S

Default-Stop:

X-Start-Before:

X-Stop-After:

Short-Description: tc

Description: tc configuration for imq interfaces

END INIT INFO

SCRIPTNAME="imq"

load_tc() { echo -n "Loading tc configuration... " tc qdisc add dev imq0 root handle 1:0 htb default 4 tc class add dev imq0 parent 1:0 classid 1:1 htb rate 950kbit ceil 950kbit tc class add dev imq0 parent 1:1 classid 1:2 htb rate 250kbit ceil 950kbit prio 5 tc class add dev imq0 parent 1:1 classid 1:3 htb rate 450kbit ceil 950kbit prio 0 tc class add dev imq0 parent 1:1 classid 1:4 htb rate 250kbit ceil 950kbit prio 2

tc qdisc add dev imq1 root handle 2:0 htb default 4
tc class add dev imq1 parent 2:0 classid 2:1 htb rate 9500kbit ceil 9500kbit
tc class add dev imq1 parent 2:1 classid 2:2 htb rate 2500kbit ceil 9500kbit prio 5
tc class add dev imq1 parent 2:1 classid 2:3 htb rate 4500kbit ceil 9500kbit prio 0
tc class add dev imq1 parent 2:1 classid 2:4 htb rate 2500kbit ceil 9500kbit prio 2

tc filter add dev imq0 protocol ip parent 1:0 prio 1 handle 2 fw classid 1:2
tc filter add dev imq0 protocol ip parent 1:0 prio 5 handle 3 fw classid 1:3
tc filter add dev imq1 protocol ip parent 2:0 prio 3 handle 2 fw classid 2:2
tc filter add dev imq1 protocol ip parent 2:0 prio 7 handle 3 fw classid 2:3
echo "done!"

}

load_iptables() {
echo -n "Loading iptables configuration... " iptables -t mangle -A PREROUTING -i eth0 -j IMQ --todev 1 iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark

iptables -t mangle -N IMQ-OUT
iptables -t mangle -A POSTROUTING -o eth0 -j IMQ-OUT

iptables -t mangle -A IMQ-OUT -o eth0 -m length --length 40:68 -j MARK --set-mark 3 iptables -t mangle -A IMQ-OUT -o eth0 -m length --length 40:68 -j RETURN iptables -t mangle -A IMQ-OUT -o eth0 -m owner --gid-owner p2p -j MARK --set-mark 2 iptables -t mangle -A IMQ-OUT -o eth0 -m owner --gid-owner p2p -j RETURN iptables -t mangle -A IMQ-OUT -o eth0 -m owner --uid-owner morfik -j MARK --set-mark 3 iptables -t mangle -A IMQ-OUT -o eth0 -m owner --uid-owner morfik -j RETURN iptables -t mangle -A IMQ-OUT -o eth0 -m owner --uid-owner root -j MARK --set-mark 3 iptables -t mangle -A IMQ-OUT -o eth0 -m owner --uid-owner root -j RETURN

iptables -t mangle -A POSTROUTING -j CONNMARK  --save-mark
iptables -t mangle -A POSTROUTING -o eth0 -j IMQ --todev 0
echo "done!"

}

interfaces_up() { ip link set imq0 up ip link set imq1 up }

flush_tc() { echo -n "Removing tc qdiscs... " tc qdisc del dev eth0 root 2> /dev/null tc qdisc del dev eth0 ingress 2> /dev/null tc qdisc del dev imq0 root 2> /dev/null tc qdisc del dev imq1 root 2> /dev/null echo "done!" }

flush_iptables() { echo -n "Flushing mangle table... " iptables -t mangle -F 2> /dev/null iptables -t mangle -X IMQ-OUT 2> /dev/null echo "done!" }

interfaces_down() { ip link set imq0 down ip link set imq1 down }

case "$1" in start) interfaces_up && load_tc && load_iptables || exit 1 ;; stop) flush_tc && flush_iptables && interfaces_down || exit 1 ;; force-reload|restart) flush_tc && flush_iptables && interfaces_down && sleep 1 interfaces_up && load_tc && load_iptables ;;
*) echo "Usage: $SCRIPTNAME {start|stop|restart}" exit 1 ;;
esac

exit 0

Nie jest to szczyt techniki ale działa, a to najważniejsze. Dodatkowo ten skrypt ma się odpalić przed skryptem sieciowym -- trzeba wyedytować nagłówek skryptu /etc/init.d/networking ale pierw usuńmy ten skrypt z autostartu:

update-rc.d networking remove

Dopisujemy teraz imq w odpowiednich sekcjach:

BEGIN INIT INFO

Provides: networking ifupdown

Required-Start: mountkernfs $local_fs urandom

Required-Stop: $local_fs

Should-Start: peerblock iptables-persistent imq

Should-Stop: peerblock iptables-persistent imq

Default-Start: S

Default-Stop: 0 6

Short-Description: Raise network interfaces.

Description: Prepare /run/network directory, ifstate file and raise network interfaces, or take them down.

END INIT INFO

I dodajemy oba skrypty do autostartu:

update-rc.d networking defaults

update-rc.d imq defaults

Reboot maszyny i powinno działać.

  1. Jeśli nie IMQ, to co w takim razie?

Jeśli nie odpowiada nam za bardzo zabawa z kompilacją kernela i iptables, bo jak nie patrzeć jest to trochę upierdliwe, istnieje inne rozwiązanie, przy wdrażaniu którego za bardzo nie trzeba się wysilać. Umożliwia ono, co prawda, kontrolę tylko ruchu wychodzącego ale nie ma się większego wpływu na ruch przychodzący. Jednak ten sposób również potrafi sprawić, że nie zauważymy większej różnicy w użytkowaniu internetu przy odpalonym na full qbittorrencie, dlatego trzeba o nim parę słów napisać.

2.1. Kształtowanie ruchu wychodzącego przy pomocy -j CLASSIFY

Do kształtowania tego ruchu możemy wykorzystać iptables z celami -j MARK oraz -j CLASSIFY, mamy też możliwość skorzystania z cgroups, oraz z tc filter. Nie będę tutaj opisywał celu -j MARK, bo to już zostało zrobione przy okazji zabawy z interfejsami IMQ i zasadniczo reguły tam zastosowane nie różnią się zbytnio od tych, które by zostały użyte w tym przypadku, jedyne co, to trzeba by było pozmieniać interfejsy. W każdym razie w tym przypadku jest to wielce nieporęczne i nie ma sobie co tym głowy zawracać.

Cel -j CLASSIFY daje nam możliwość przekierowania ruchu do odpowiednich kolejek bez potrzeby zaprzęgania do tego tc filter -- od razu po przypasowaniu reguły w iptables, pakiet trafia do odpowiedniej kolejki. Poniżej jest przedstawiony prosty setup na ograniczenie ruchu wychodzącego z wykorzystaniem tego celu:

tc qdisc del dev eth0 root

iptables -t mangle -F 2> /dev/null

tc qdisc add dev eth0 root handle 1: htb default 4

tc class add dev eth0 parent 1:0 classid 1:1 htb rate 950kbit ceil 950kbit

tc class add dev eth0 parent 1:1 classid 1:2 htb rate 450kbit ceil 950kbit prio 5

tc class add dev eth0 parent 1:1 classid 1:3 htb rate 250kbit ceil 950kbit prio 0

tc class add dev eth0 parent 1:1 classid 1:4 htb rate 250kbit ceil 950kbit prio 2

iptables -t mangle -A POSTROUTING -o eth0 -m owner --gid-owner p2p -j CLASSIFY --set-class 1:2

iptables -t mangle -A POSTROUTING -o eth0 -m owner --gid-owner p2p -j ACCEPT

iptables -t mangle -A POSTROUTING -o eth0 -m owner --uid-owner morfik -j CLASSIFY --set-class 1:3

iptables -t mangle -A POSTROUTING -o eth0 -m owner --gid-owner morfik -j ACCEPT

iptables -t mangle -A POSTROUTING -o eth0 -m owner --uid-owner root -j CLASSIFY --set-class 1:3

iptables -t mangle -A POSTROUTING -o eth0 -m owner --gid-owner root -j ACCEPT

Jakież to proste. xD Większość parametrów użytych w powyższym skrypcie zostały już opisane wcześniej. To co zasługuje na uwagę, to --set-class . Wartość tego parametru musi pasować do wartości classid w tc.

2.2. Kształtowanie ruchu wychodzącego przy pomocy cgroups

Jeśli używamy cgroups, możemy przy jego pomocy skierować ruch do odpowiednich kolejek. Samą instalację (i trochę konfiguracji) cgroups opisałem tutaj. By kontrolować pakiety jakieś aplikacji, musimy dopisać odpowiednią linijkę z uwzględnieniem net_cls w /etc/cgrules.conf . Mój wpis od qbittorrenta wygląda następująco:

:qbittorrent cpu,net_cls users/qbittorrent/ *:qbittorrent cpu,net_cls users/qbittorrent/ :qbittorrent-nox cpu,net_cls users/qbittorrent/ *:qbittorrent-nox cpu,net_cls users/qbittorrent/

Uzupełniamy skrypt /etc/init.d/cgconfig o poniższe linijki:

mkdir -p $CGDIR/net_cls/users/qbittorrent echo '1' > $CGDIR/net_cls/users/qbittorrent/cgroup.clone_children echo '0x00010002' > $CGDIR/net_cls/users/qbittorrent/net_cls.classid

Ten numerek 0x00010002 , to są dwie liczby hexalne, składające się na określenie grupy. Ta ma numer w postaci 1:2. Cztery pierwsze cyfry odpowiadają liczbie przed ":" , cztery kolejne, cyfrze po ":". Tak więc mamy dwie liczby 0001 oraz 0002, co daje 1:2. Każda z pozycji może przyjąć 16 wartości, w końcu to zapisz szesnastkowy.

Ładujemy ponownie skrypt od konfiguracji oraz restartujemy demona cgrulesengd:

/etc/init.d/cgrulesengd stop

/etc/init.d/cgconfig restart

/etc/init.d/cgrulesengd start

Tworzymy kolejki:

tc qdisc del dev eth0 root 2> /dev/null

iptables -t mangle -F 2> /dev/null

tc qdisc add dev eth0 root handle 1: htb default 4

tc class add dev eth0 parent 1:0 classid 1:1 htb rate 950kbit ceil 950kbit

tc class add dev eth0 parent 1:1 classid 1:2 htb rate 450kbit ceil 950kbit prio 5

tc class add dev eth0 parent 1:1 classid 1:3 htb rate 250kbit ceil 950kbit prio 0

tc class add dev eth0 parent 1:1 classid 1:4 htb rate 250kbit ceil 950kbit prio 2

Potrzebujemy jeszcze odpowiedniego przekierowania pakietów do klas w tc. Posłuży nam do tego celu tc filter:

tc filter add dev eth0 protocol ip parent 1:0 prio 10 handle 1 cgroup

Nie potrzebujemy żadnych wpisów w iptables, wszystko jest zarządzane przez cgroups w w połączeniu z tc. W bmon wygląda to tak:

Interfaces | RX bps pps %| TX bps pps % lo | 271B 1 | 271B 1 ->eth0 | 5.99KiB 62 | 117.03KiB 119 qdisc 1: (htb) | 0 0 | 117.03KiB 119 class 1:1 (htb) | 0 0 | 116.99KiB 118 101% class 1:2 (htb) | 0 0 | 116.92KiB 117 213% class 1:3 (htb) | 0 0 | 0 0 0% class 1:4 (htb) | 0 0 | 63B 0 0% cls :1 (cgroup) | 0 0 | 0 0

U mnie się pojawiały dziwne problemy przy wykorzystaniu cgroups -- albo nie brało pakietów do odpowiednich grup, mimo, że id kolejki był sprecyzowany w pliku net_cls.classid, albo po pewnym czasie ruch się rozdzielał na kolejkę, do której iść powinien i kolejkę domyślną. W przypadku gdy ruch w ogóle nie szedł do przeznaczonej kolejki, można było przy pomocy echo jeszcze raz zapisać plik net_cls.classid. Nie wiem czemu tak się dzieje, może to tylko u mnie. W każdym razie cele -j MARK i -j CLASSIFY działają bez zarzutu, także jeśli mamy jakieś problemy z cgroups, zawsze możemy z tych targetów skorzystać i przekierować ruch przy pomocy iptables.

  1. Interfejsy IFB

Jeśli jednak interesuje nas kontrola ruchu w obie strony ale nie mamy zamiaru przy tym kompilować kernela i iptables z łatami IMQ, możemy skorzystać z natywnego rozwiązania oferowanego przez kernel, czyli interfejsów IFB. Działają na podobnej zasadzie co interfejsy IMQ, również będą dwa, z których jeden będzie łapał i kształtował ruch wychodzący, a drugi ruch skierowany do naszej maszyny. W tym przypadku nie da rady kształtować ruchu przychodzącego przy pomocy iptables. Trzeba do tego celu użyć tc filter. Nie wiem czy da radę nim złapać ruch na qbittorrencie, bo składnia tc filter jest trochę skompilowana ale bez problemu idzie wyłapać wszystko inne.

By móc operować na interfejsach IFB i przy ich pomocy rozgraniczyć pakiety wychodzące od przychodzących, musimy załadować kilka modułów. Dopisujemy zatem do pliku /etc/modules poniższe linijki:

ifb numifbs=2 sch_fq_codel act_mirred

Moduły z /etc/modules są ładowane na starcie systemu. Jeśli chcemy załadować jakiś moduł w systemie ręcznie, musimy użyć do tego celu modprobe .

Tworzymy kolejki:

tc qdisc del dev eth0 root

tc qdisc del dev eth0 ingress

tc qdisc del dev ifb0 root

tc qdisc del dev ifb1 root

iptables -t mangle -F 2> /dev/null

iptables -t mangle -X IFB-OUT 2> /dev/null

ip link set ifb0 up

ip link set ifb1 up

tc qdisc add dev eth0 parent root handle 1:0 htb

tc filter add dev eth0 parent 1:0 protocol ip prio 10 u32 match ip dst 0.0.0.0/0 flowid 1:1 action mirred egress redirect dev ifb0

tc qdisc add dev eth0 handle ffff: ingress

tc filter add dev eth0 parent ffff: protocol ip prio 10 u32 match ip src 0.0.0.0/0 flowid 2:1 action mirred egress redirect dev ifb1

tc qdisc add dev ifb0 root handle 1: htb default 4

tc class add dev ifb0 parent 1:0 classid 1:1 htb rate 950kbit ceil 950kbit

tc class add dev ifb0 parent 1:1 classid 1:2 htb rate 250kbit ceil 950kbit prio 5

tc class add dev ifb0 parent 1:1 classid 1:3 htb rate 450kbit ceil 950kbit prio 0

tc class add dev ifb0 parent 1:1 classid 1:4 htb rate 250kbit ceil 950kbit prio 2

tc qdisc add dev ifb1 root handle 2: htb default 4

tc class add dev ifb1 parent 2:0 classid 2:1 htb rate 9500kbit ceil 9500kbit

tc class add dev ifb1 parent 2:1 classid 2:2 htb rate 2500kbit ceil 9500kbit prio 2

tc class add dev ifb1 parent 2:1 classid 2:3 htb rate 4500kbit ceil 9500kbit prio 0

tc class add dev ifb1 parent 2:1 classid 2:4 htb rate 2500kbit ceil 9500kbit prio 5

Pakietami wyjściowymi możemy sterować tak jak w poprzednich przypadkach, czyli przez iptables z celami -j MARK oraz -j CLASSIFY i cgroups. By kontrolować ruch wychodzący w tym przypadku, stworzyłem sobie kilka regułek z targetem -j CLASSIFY :

iptables -t mangle -A POSTROUTING -m owner --gid-owner p2p -j CLASSIFY --set-class 1:2

iptables -t mangle -A POSTROUTING -m owner --gid-owner p2p -j ACCEPT

iptables -t mangle -A POSTROUTING -m owner --uid-owner morfik -j CLASSIFY --set-class 1:3

iptables -t mangle -A POSTROUTING -m owner --uid-owner morfik -j ACCEPT

iptables -t mangle -A POSTROUTING -m owner --uid-owner root -j CLASSIFY --set-class 1:3

iptables -t mangle -A POSTROUTING -m owner --uid-owner root -j ACCEPT

I to w zasadzie działa, przynajmniej jeśli chodzi o ruch wychodzący.

Teraz kolej na ruch skierowany do naszej maszyny. Jeśli chcemy dać wyższy priorytet dla stron www, to musimy napisać odpowiednie regułki dla tc filter uwzględniające porty źródłowe 80 i 443, po czym przekierować je do kolejki z niższym numerem prio. Najprościej to można zrobić tak:

tc filter add dev ifb1 parent 2: protocol ip prio 10 u32 match ip sport 443 0xffff classid 2:3

tc filter add dev ifb1 parent 2: protocol ip prio 10 u32 match ip sport 80 0xffff classid 2:3

Teraz odpalmy firefoxa i wchodzimy na jakąś stronę www. U mnie bmon pokazuje poniższy wynik:

Interfaces | RX bps pps %| TX bps pps % ->lo | 683B 10 | 683B 10 eth0 | 82.31KiB 140 | 74.95KiB 153 qdisc 1: (htb) | 0 0 | 74.94KiB 153 cls none (u32) | 0 0 | 0 0 cls 8000: (u32) | 0 0 | 0 0 cls 8000:800 (u32) | 0 0 | 0 0 qdisc ffff: (ingress) | 0 0 | 80.39KiB 140 cls none (u32) | 0 0 | 0 0 cls 8000: (u32) | 0 0 | 0 0 cls 8000:800 (u32) | 0 0 | 0 0 ifb0 | 74.94KiB 153 | 74.94KiB 153 qdisc 1: (htb) | 0 0 | 74.94KiB 153 class 1:1 (htb) | 0 0 | 74.89KiB 153 65% class 1:2 (htb) | 0 0 | 67.92KiB 98 223% class 1:3 (htb) | 0 0 | 6.81KiB 51 12% class 1:4 (htb) | 0 0 | 165B 2 1% ifb1 | 239.97KiB 241 | 239.97KiB 241 qdisc 2: (htb) | 0 0 | 239.97KiB 241 class 2:1 (htb) | 0 0 | 241.08KiB 242 21% class 2:2 (htb) | 0 0 | 0 0 0% class 2:3 (htb) | 0 0 | 236.88KiB 185 43% class 2:4 (htb) | 0 0 | 4.20KiB 56 1% cls none (u32) | 0 0 | 0 0 cls 8000: (u32) | 0 0 | 0 0 cls 8000:800 (u32) | 0 0 | 0 0 cls 8000:801 (u32) | 0 0 | 0 0

Ten 0xffff jest to maska dla portów, podobna do tej dla adresów ip. W przypadku ustawienia ffff, oznacza to tylko jeden port. Można oczywiście ustawić zakres portów przez zmianę tej maski ale jest to trochę upierdliwe i ja tego raczej w pamięci nie policzę. W zrozumieniu składni u32 mogą przydatne okazać się te linki: man ematch oraz man u32 filter.

Jak widać jest to trochę skomplikowane ale dla naszych potrzeb spokojnie wystarczą te cztery parametry: src, dst, sport i dport. By sprecyzować adres ip zamiast portu, wstawiamy dst 222.28.1.40/32 w miejsce sport 80 0xffff. Reguła będzie odnosić się do adresu docelowego 222.28.1.40. Bu ustawić zakres adresów, wystarczy zmienić maskę, podobnie jak w przypadku portów.

Jeśli jednak chcielibyśmy się pobawić w coś bardziej zaawansowanego z wykorzystaniem selektora u32 (i innych) warto nauczyć się przeliczać liczy hex, binarne i decymalne. Poniżej jest kilka przykładów.

Zamiana hex na dec:

$ echo "obase=10;ibase=16;C0A80100" | bc 3232235776

Zamiana hex na bi

$ echo "obase=2;ibase=16;C0A80100" | bc 11000000101010000000000100000000

Zamiana bi na dec:

$ echo "obase=10;ibase=2;11000000101010000000000100000000" | bc 3232235776

I tak dalej. Kluczowe to odpowiednio dobrać obase oraz ibase, które definiują format liczb -- ibase to format wejściowy, a obase wyjściowy.

Warto też się zaznajomić z wyglądem nagłówków tcp i ip.

Podobnie jak w przypadku interfejsów IMQ, możemy sobie zrobić skrypt startowy z użytymi powyżej regułami. Mój skrypt prezentuje się tak:

BEGIN INIT INFO

Provides: ifb

Required-Start: mountkernfs $local_fs

Required-Stop: $local_fs

Should-Start:

Should-Stop:

Default-Start: S

Default-Stop:

X-Start-Before:

X-Stop-After:

Short-Description: tc

Description: tc configuration for ifb interfaces

END INIT INFO

SCRIPTNAME="ifb"

load_tc() { echo -n "Loading tc configuration... " tc qdisc add dev eth0 parent root handle 1:0 htb tc filter add dev eth0 parent 1:0 protocol ip prio 10 u32 match ip dst 0.0.0.0/0 flowid 1:1 action mirred egress redirect dev ifb0 tc qdisc add dev eth0 handle ffff: ingress tc filter add dev eth0 parent ffff: protocol ip prio 10 u32 match ip src 0.0.0.0/0 flowid 2:1 action mirred egress redirect dev ifb1

tc qdisc add dev ifb0 root handle 1: htb default 5
tc class add dev ifb0 parent 1:0 classid 1:1 htb rate 950kbit ceil 950kbit 
tc class add dev ifb0 parent 1:1 classid 1:2 htb rate 150kbit ceil 950kbit prio 5
tc class add dev ifb0 parent 1:1 classid 1:3 htb rate 200kbit ceil 950kbit prio 4
tc class add dev ifb0 parent 1:1 classid 1:4 htb rate 450kbit ceil 950kbit prio 0
tc class add dev ifb0 parent 1:1 classid 1:5 htb rate 150kbit ceil 950kbit prio 2

tc qdisc add dev ifb1 root handle 2: htb default 5
tc class add dev ifb1 parent 2:0 classid 2:1 htb rate 9500kbit ceil 9500kbit
tc class add dev ifb1 parent 2:1 classid 2:2 htb rate 1500kbit ceil 9500kbit prio 2
tc class add dev ifb1 parent 2:1 classid 2:3 htb rate 2000kbit ceil 9500kbit prio 4
tc class add dev ifb1 parent 2:1 classid 2:4 htb rate 4500kbit ceil 9500kbit prio 0
tc class add dev ifb1 parent 2:1 classid 2:5 htb rate 1500kbit ceil 9500kbit prio 5

tc filter add dev ifb1 parent 2: protocol ip prio 7 u32 match ip sport 80 0xffff classid 2:3
tc filter add dev ifb1 parent 2: protocol ip prio 8 u32 match ip sport 443 0xffff classid 2:3
tc filter add dev ifb1 parent 2: protocol ip prio 20 u32 match ip sport 993 0xffff classid 2:2
tc filter add dev ifb1 parent 2: protocol ip prio 21 u32 match ip sport 143 0xffff classid 2:2
tc filter add dev ifb1 parent 2: protocol ip prio 22 u32 match ip sport 465 0xffff classid 2:2
tc filter add dev ifb1 parent 2: protocol ip prio 35 u32 match ip sport 5222 0xffff classid 2:2
tc filter add dev ifb1 parent 2: protocol ip prio 36 u32 match ip sport 5223 0xffff classid 2:2
echo "done!"

}

load_iptables() {
echo -n "Loading iptables configuration... " iptables -t mangle -A POSTROUTING -o eth0 -m length --length 40:68 -j CLASSIFY --set-class 1:3 iptables -t mangle -A POSTROUTING -o eth0 -m length --length 40:68 -j ACCEPT iptables -t mangle -A POSTROUTING -o eth0 -m owner --gid-owner p2p -j CLASSIFY --set-class 1:2 iptables -t mangle -A POSTROUTING -o eth0 -m owner --gid-owner p2p -j ACCEPT iptables -t mangle -A POSTROUTING -o eth0 -m owner --uid-owner morfik -j CLASSIFY --set-class 1:4 iptables -t mangle -A POSTROUTING -o eth0 -m owner --uid-owner morfik -j ACCEPT iptables -t mangle -A POSTROUTING -o eth0 -m owner --uid-owner root -j CLASSIFY --set-class 1:4 iptables -t mangle -A POSTROUTING -o eth0 -m owner --uid-owner root -j ACCEPT echo "done!" }

interfaces_up() { ip link set ifb0 up ip link set ifb1 up }

flush_tc() { echo -n "Removing tc qdiscs... " tc qdisc del dev eth0 root tc qdisc del dev eth0 ingress tc qdisc del dev ifb0 root tc qdisc del dev ifb1 root echo "done!" }

flush_iptables() { echo -n "Flushing mangle table... " iptables -t mangle -F 2> /dev/null echo "done!" }

interfaces_down() { ip link set ifb0 down ip link set ifb1 down }

case "$1" in start) interfaces_up && load_tc && load_iptables || exit 1 ;; stop) flush_tc && flush_iptables && interfaces_down || exit 1 ;; force-reload|restart) flush_tc && flush_iptables && interfaces_down && sleep 1 interfaces_up && load_tc && load_iptables ;;
*) echo "Usage: $SCRIPTNAME {start|stop|restart}" exit 1 ;;
esac

exit 0

Edytujemy jeszcze nagłówki skryptu /etc/init.d/networking ale pierw musimy go usunąć z autostartu:

update-rc.d networking remove

Teraz dodajemy w odpowiednie sekcje ifb:

BEGIN INIT INFO

Provides: networking ifupdown

Required-Start: mountkernfs $local_fs urandom

Required-Stop: $local_fs

Should-Start: peerblock iptables-persistent ifb

Should-Stop: peerblock iptables-persistent ifb

Default-Start: S

Default-Stop: 0 6

Short-Description: Raise network interfaces.

Description: Prepare /run/network directory, ifstate file and raise network interfaces, or take them down.

END INIT INFO

Dodajemy oba skrypty do autostartu:

update-rc.d networking defaults

update-rc.d ifb defaults

  1. Statystyki ruchu

Istnieje kilka narzędzi, które pokazują rozpiskę aktualnej konfiguracji traffic control.

Inforamcje o qdisc:

tc -d -s qdisc show dev eth0

qdisc htb 1: root refcnt 2 r2q 10 default 0 direct_packets_stat 1044925 ver 3.17 direct_qlen 1000 Sent 161806806 bytes 1065008 pkt (dropped 11997, overlimits 0 requeues 0) backlog 0b 0p requeues 0 qdisc ingress ffff: parent ffff:fff1 ---------------- Sent 1280866443 bytes 1058357 pkt (dropped 7425, overlimits 0 requeues 0) backlog 0b 0p requeues 0

tc -d -s qdisc show dev ifb0

qdisc htb 1: root refcnt 2 r2q 10 default 5 direct_packets_stat 0 ver 3.17 direct_qlen 32 Sent 163118498 bytes 1074893 pkt (dropped 12069, overlimits 2223331 requeues 0) backlog 0b 28p requeues 0

tc -d -s qdisc show dev ifb1

qdisc htb 2: root refcnt 2 r2q 10 default 5 direct_packets_stat 0 ver 3.17 direct_qlen 32 Sent 1302094010 bytes 1057023 pkt (dropped 7561, overlimits 1957564 requeues 0) backlog 0b 29p requeues 0

Informacje o filtrach:

tc -s -d -p filter show dev ifb1 filter parent 2: protocol ip pref 7 u32 filter parent 2: protocol ip pref 7 u32 fh 800: ht divisor 1 filter parent 2: protocol ip pref 7 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 2:3 (rule hit 1388968 success 6829) match sport 80 (success 6829 ) filter parent 2: protocol ip pref 8 u32 filter parent 2: protocol ip pref 8 u32 fh 801: ht divisor 1 filter parent 2: protocol ip pref 8 u32 fh 801::800 order 2048 key ht 801 bkt 0 flowid 2:3 (rule hit 1382139 success 5130) match sport 443 (success 5130 ) filter parent 2: protocol ip pref 20 u32 filter parent 2: protocol ip pref 20 u32 fh 802: ht divisor 1 filter parent 2: protocol ip pref 20 u32 fh 802::800 order 2048 key ht 802 bkt 0 flowid 2:2 (rule hit 1377009 success 1940) match sport 993 (success 1940 ) filter parent 2: protocol ip pref 21 u32 filter parent 2: protocol ip pref 21 u32 fh 803: ht divisor 1 filter parent 2: protocol ip pref 21 u32 fh 803::800 order 2048 key ht 803 bkt 0 flowid 2:2 (rule hit 1375069 success 105) match sport 143 (success 105 ) filter parent 2: protocol ip pref 22 u32 filter parent 2: protocol ip pref 22 u32 fh 804: ht divisor 1 filter parent 2: protocol ip pref 22 u32 fh 804::800 order 2048 key ht 804 bkt 0 flowid 2:2 (rule hit 1374964 success 0) match sport 465 (success 0 ) filter parent 2: protocol ip pref 35 u32 filter parent 2: protocol ip pref 35 u32 fh 805: ht divisor 1 filter parent 2: protocol ip pref 35 u32 fh 805::800 order 2048 key ht 805 bkt 0 flowid 2:2 (rule hit 1374964 success 111) match sport 5222 (success 111 ) filter parent 2: protocol ip pref 36 u32 filter parent 2: protocol ip pref 36 u32 fh 806: ht divisor 1 filter parent 2: protocol ip pref 36 u32 fh 806::800 order 2048 key ht 806 bkt 0 flowid 2:2 (rule hit 1374853 success 113) match sport 5223 (success 113 )

root:~# tc -s -d -p filter show dev eth0 filter parent 1: protocol ip pref 10 u32 filter parent 1: protocol ip pref 10 u32 fh 800: ht divisor 1 filter parent 1: protocol ip pref 10 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1 (rule hit 2787825 success 2787825) match IP dst 0.0.0.0/0 (success 2787825 ) action order 1: mirred (Egress Redirect to device ifb0) stolen index 1 ref 1 bind 1 installed 1852 sec Action statistics: Sent 212247685 bytes 1425206 pkt (dropped 0, overlimits 14476 requeues 0) backlog 0b 0p requeues 0

Jeśli komuś niezbyt odpowiada zapis tekstowy i wolałby zobaczyć rozpiskę w postaci jakiegoś wykresu czy coś, to istnieje narzędzie, które na podstawie tych literek i cyferek zrobi nam miły dla oka obrazek. Sam programik znalazłem na tym blogu, a jego kod jest dostępny pod tym adresem. Program wywołujemy przez:

$ ./tcviz.py eth0 | dot -Tpng > tc.png

  1. Jak odpalać qbittorrenta?

Przez parę dni zastanawiałem się jak ogarnąć uruchamianie qbittorrenta, bo pakiety trzeba przecie łapać albo po uid albo po gid. Propozycji było kilka. Pierwsza z nich zakładała wykorzystanie sudo ale w tym przypadku jest trochę za dużo roboty -- trzeba pilnować uprawnień plików, trzeba przenosić konfigurację i tworzyć nowego użytkownika, bawić się aclem. Niby nic wielkiego ale istnieje inny, dużo prostszy sposób, który wykorzystuje grupy. Normalnie proces jest odpalany z prawami użytkownika, który ten proces uruchamia. Dodatkowo grupa główna tego użytkownika jest brana pod uwagę przy uruchamianiu procesu, w efekcie czego proces jest uruchomiony jako użytkownik morfik i grupa również morfik. Ale przecie grupy nie zostały stworzone po to by używać cały czas tylko jednej z nich, a biorąc pod uwagę fakt, że pakiety możemy filtrować również po grupie, uruchomimy proces z inną grupą.

Tworzymy zatem nową grupę p2p i dodajemy swojego użytkownika do niej:

groupadd -g 5004 p2p

adduser morfik p2p

By móc bez hasła używać id innej grupy musimy być podpięci pod tę grupę, można to sprawdzić wklepując do terminala id.

By odpalić proces z inną grupą, wydajemy poniższe polecenie:

$ nice -n 19 ionice -c 2 -n 7 sg p2p -c qbittorrent

Kluczowe w powyższej linijce jest sg. To za jego pomocą ustawiamy procesowi odpowiednią grupę. Dodatkowo, jest jeszcze zaprzęgnięty do pracy nice oraz ionice -- mają na celu odciążenie procesora i dysku w przypadku gdyby inne procesy dość gwałtownie wykorzystywały zasoby maszyny.

QBittorrent posiada klienta nox, czyli coś co działa bez potrzeby odpalania X-ów, a zarządzać nim można przez www. Zjada 2-3 krotnie mniej zasobów niż jego graficzny odpowiednik, co powinno ucieszyć ludzi, którzy... mają mniej RAMu niż ja. xD Posiada on także skrypt startowy, choć domyślnie nie jest dołączony w pakiecie. Wykorzystuje on do uruchomienia qbittorrenta start-stop-daemon -- standardowy mechanizm odpalania procesów startowych w debianie i można przy jego pomocy także sprecyzować grupę. Skrypt prezentuje się tak:

! /bin/sh

BEGIN INIT INFO

Provides: qbittorrent-nox

Required-Start: $remote_fs $syslog

Required-Stop: $remote_fs $syslog

Should-Start: iptables-persistent pgl

Should-Stop: iptables-persistent pgl

Default-Start: 2 3 4 5

Default-Stop: 0 1 6

Short-Description: Starts QBittorrent

Description: Start qbittorrent-nox on start. Change USER= before running

END INIT INFO

Author: Jesper Smith

#

Do NOT "set -e"

PATH should only include /usr/* if it runs after the mountnfs.sh script

PATH=/sbin:/usr/sbin:/bin:/usr/bin DESC="QBittorrent" NAME=qbittorrent-nox DAEMON=/usr/bin/$NAME DAEMON_ARGS="" PIDFILE=/var/run/$NAME.pid SCRIPTNAME=/etc/init.d/qbittorrent-nox USER=morfik:p2p

Exit if the package is not installed

[ -x "$DAEMON" ] || exit 0

Read configuration variable file if it is present

[ -r /etc/default/$NAME ] && . /etc/default/$NAME

if [ "$START" = "no" ]; then echo "Autostart wyłączony -- zobacz /etc/default/$NAME ." exit 0 fi

Load the VERBOSE setting and other rcS variables

. /lib/init/vars.sh

Define LSB log_* functions.

Depend on lsb-base (>= 3.0-6) to ensure that this file is present.

. /lib/lsb/init-functions

#

Function that starts the daemon/service

# do_start() { # Return # 0 if daemon has been started # 1 if daemon was already running # 2 if daemon could not be started start-stop-daemon -c $USER -b -t --start --quiet --exec $DAEMON \ || return 1

start-stop-daemon -c $USER -b --start --quiet --exec $DAEMON -- \
    $DAEMON_ARGS \
    || return 2
sleep 1

}

#

Function that stops the daemon/service

# do_stop() { start-stop-daemon -c $USER --quiet --stop --exec $DAEMON sleep 2 return "$?" }

VERBOSE="yes"

case "$1" in start) [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC""$NAME" do_start case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; stop) [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC""$NAME" do_stop case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; status) status_of_proc "$DAEMON""$NAME"&& exit 0 || exit $? ;; restart|force-reload) log_daemon_msg "Restarting $DESC""$NAME" do_stop case "$?" in 0|1) do_start case "$?" in 0) log_end_msg 0 ;; 1) log_end_msg 1 ;; # Old process is still running *) log_end_msg 1 ;; # Failed to start esac ;; *) # Failed to stop log_end_msg 1 ;; esac ;; *) #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}">&2 echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}">&2 exit 3 ;; esac

Jedyne co musimy dostosować to linijkę z USER=morfik:p2p. Dodajemy skrypt do autostartu przy pomocy:

update-rc.d qbittorrent-nox defaults

I będzie sobie działał w tle cały czas od chwili załadowania się systemu.

Więcej informacji można znaleźć w poniższych linkach: https://wiki.gentoo.org/wiki/Traffic_shaping https://wiki.archlinux.org/index.php/Advanced_Traffic_Control http://lartc.org/lartc.html#LARTC.QDISC http://bromirski.net/docs/translations/lartc-pl.html#LARTC.QDISC (PL) http://wampir.mroczna-zaloga.org/archives/21-o-ksztaltowaniu-ruchu.html http://robert.nowotniak.com/en/security/htb/ https://www.kernel.org/doc/Documentation/cgroups/net_cls.txt http://edseek.com/~jasonb/articles/traffic_shaping/index.html http://manpages.debian.net/cgi-bin/man.cgi?query=tc&sektion=8&apropos=0&manpath=Debian+7.0+wheezy&locale= http://www.tamos.net/~rhay/wp/overhead/overhead.htm http://linux-ip.net/articles/Traffic-Control-HOWTO/intro.html


Instalujemy MATE 1.7 w Debian GNU/Linux

$
0
0

Developerzy środowiska MATE udostępnili specjalne repozytorium z rozwojową wersją środowiska (1.7). Poniżej umieszczę krótki poradnik opisujący proces instalacji tego środowiska.

Na początek musimy edytować plik /etc/apt/sources.list i dopisać do niego odpowiednią linijkę:

deb http://dev.mate-desktop.org/debian jessie main

Następnie powinniśmy edytować plik /etc/apt/preferences i umieścić w nim następujący zapis:

Package: *
Pin: origin dev.mate-desktop.org
Pin-Priority: 980

Teraz musimy odświeżyć listę repozytoriów i zainstalować środowisko:

apt-get update && apt-get install mate-desktop-environment

Po zakończeniu pracy instalatora pozostaje tylko przelogować się na nowe środowisko. Miłej zabawy!

Pamiętajmy, że jest to wersja rozwojowa i nie wszystko może działać tak, jakbyśmy sobie tego życzyli. Niemniej, od kilku dni testuję środowisko w systemie Arch Linux i nie sprawia żadnych problemów.

Rezygnacja z graficznego menadżera logowania

$
0
0

Przez parę miesięcy używałem lightdm jako graficzny menadżer logowania ale od paru dni mam z nim trochę problemów. Prawdopodobnie te problemy istniały wcześniej ale rzadko kiedy resetowałem środowisko graficzne przez /etc/init.d/lightdm restart. Problem jest taki, że po wydaniu tego polecenia środowisko graficzne się nie odpala, sam lightdm nie wstaje. Co ciekawe, po resecie maszyny wszystko wraca do normy ale po ponownym restarcie usługi lightdm znów nie można wbić na X-y. Samo startx działa dobrze. Na próbę cofnąłem wersję lightdm do tej ze stable i tam o dziwo lightdm się resetuje, więc to raczej wskazuje na problem z lightdm, choć na dobrą sprawę, to nie mam zielonego pojęcia czemu takie cuda się u mnie dzieją.

W każdym razie, od jakiegoś czasu planowałem przejście na tekstowy tryb odpalania X-ów, przez startx . Jest kilka problemów, które powstają w wyniku zlikwidowania graficznego menadżera logowania, np. problem z inicjacją keyringa gnome, czy odblokowanie go po zalogowaniu się do systemu.

Jak zatem pozbierać to wszystko do kupy by działało jak trza bez większych problemów? Na początek tworzymy plik .xinitrc i wrzucamy do niego poniższą treść:

!/bin/bash

numlockx &

xrdb /home/morfik/.Xresources

exec ck-launch-session dbus-launch --sh-syntax --exit-with-session openbox-session

Pierwsza linijka odpowiada za aktywację numlocka, potrzebna jest instalacja pakietu numlockx. Druga linijka z kolei wczytuje ustawienia X-ów z pliku .Xresources , bo część aplikacji nie była wyświetlana tak jak być powinna. Ostatnia zaś odpala sesję openboxa.

Jeśli przejdziemy teraz na TTY i zalogujemy się do systemu oraz wpiszemy startx, powinien nam się załadować tryb graficzny. Ale tego typu akcja jest niezbyt poręczna -- trzeba to jakoś zautomatyzować, tak by po zalogowaniu się na TTY, X-y startowały samodzielnie. No jest tylko jeden problem, bo nie chcemy by zalogowanie się na każdej konsoli TTY odpalało X-y, co mogłoby się skończyć tragicznie w przypadku uszkodzenia X-servera. Wydelegujemy do tego celu konsolę 4. Musimy zatem dopisać parę linijek do pliku ~/.profile albo ~/.bash_profile :

if [[ $(tty) = /dev/tty4 ]]; then mv ~/.xsession-errors ~/.xsession-errors.old exec startx &> ~/.xsession-errors fi

Warto zauważyć, że przy wydaniu samego polecenia startx, komunikaty będą wyrzucane na konsolę TTY, a graficzne menadżery logowania przekierowują wyjście do pliku .xsession-errors , podobnie robi powyższa linijka.

Pozostaje nam jeszcze konfiguracja odpowiednich zmiennych. Nie wiem, który plik nadaje się do definiowania zmiennych lepiej, bo mamy do wyboru kilka: .xinitrc, openboxowy environment czy zwyczajny .bashrc. Ja miałem wcześniej wszystkie zmienne w environment, także dopiszę je tam. Nie zauważyłem przy tym jakiejś różnicy w działaniu.

By zainicjować gnome-keyring dopisujemy do pliku ~/.config/openbox/environment poniższe linijki:

eval $(/usr/bin/gnome-keyring-daemon --start --components=gpg,pkcs11,secrets,ssh) if which dbus-launch >/dev/null && test -z "$DBUS_SESSION_BUS_ADDRESS"; then eval dbus-launch --sh-syntax --exit-with-session fi

Normalnie to chyba bym ten kod dodał do autostartu openboxa ale trzeba także wyeksportować parę zmiennych i wolałbym mieć to wszystko razem w jednym pliku. Oto te zmienne:

export GNOME_KEYRING_CONTROL GNOME_KEYRING_PID GPG_AGENT_INFO SSH_AUTH_SOCK

Powyższe działania nie sprawią jednak, że keyring będzie się automatycznie otwierał ilekroć tylko się zalogujemy do systemu. Tu trzeba dopisać parę linijek do konfiguracji PAM . Musimy zmienić 2 pliki.

Po ostatnim wystąpieniu auth w /etc/pam.d/login dopisujemy poniższą linijkę:

gnome-keyring

auth optional pam_gnome_keyring.so

W tym samym pliku, tylko tym razem po ostatnim wystąpieniu session dopisujemy:

gnome-keyring

session optional pam_gnome_keyring.so auto_start

Drugi z plików to /etc/pam.d/passwd i w nim na końcu dopisujemy poniższy kod:

gnome-keyring

password optional pam_gnome_keyring.so

W tej chwili gnome-keyring powinien być poprawnie inicjowany oraz otwierany automatycznie po zalogowaniu się użytkownika.

Kolejna sprawa z jaką trzeba się rozprawić to wygląd konsoli TTY przed zalogowaniem się do systemu. Przydałoby się ją trochę urozmaicić. Natknąłem się na pakiet zwany linuxlogo -- generuje on loga różnych dystrybucji linuxowy, jest też i logo debiana. Oczywiście nie będziemy dekorować wszystkich konsol TTY, pierwsza (tę z logiem) zostawimy w spokoju, a pozostałym (2-6) dokleimy to logo.

Po zainstalowaniu pakietu, możemy odrobinę skonfigurować wygląd samego loga, dopisując parametry w pliku /etc/linux_logo.conf . Ja chciałem tylko logo debiana bez dodatkowych opcji i u mnie ta linijka wygląda jak poniżej:

-l -L debian_banner_2

Musimy jeszcze w pliku /etc/inittab wskazać alternatywny plik issue dla konsol TTY 2-6:

1:2345:respawn:/sbin/getty -8 38400 --noclear tty1 2:23:respawn:/sbin/getty -8 38400 --issue-file /etc/issue.linuxlogo tty2 3:23:respawn:/sbin/getty -8 38400 --issue-file /etc/issue.linuxlogo tty3 4:23:respawn:/sbin/getty -8 38400 --issue-file /etc/issue.linuxlogo tty4 5:23:respawn:/sbin/getty -8 38400 --issue-file /etc/issue.linuxlogo tty5 6:23:respawn:/sbin/getty -8 38400 --issue-file /etc/issue.linuxlogo tty6

Programik linuxlogo dołącza zawartość podstawowego ppliku /etc/issue gdy generuje plik /etc/issue.linuxlogo . Można w nim sprecyzować kilka opcji, takich jak czas czy data. Mój plik /etc/issue wygląda tak:

Debian GNU/Linux jessie/sid \n \l Time: \t , Date: \d

Co prawda czas jest aktualizowany tylko przy przejściu do konsoli TTY i nie jest odświeżany ale w przypadku gdy potrzebujemy odczytać aktualną godzinę i nie jesteśmy przy tym zalogowani do systemu, możemy wcisnąć enter mając przed oczami prompt TTY, co spowoduje odświeżenie ekranu.

Jako, że w tym przypadku X-y będą odpalane z konsoli 4, jest wielce prawdopodobne, że zaraz po załadowaniu się systemu trzeba będzie przejść do tej konsoli, co troszeczkę może człowieka denerwować ale można poinstruować system by po załadowaniu wszystkich skryptów startowych automatycznie nas przeniósł na TTY4, gdzie tylko wpiszemy login i hasło i załadują się X-y. Do tego celu posłuży nam chvt . Musimy dopisać poniższą linijkę do /etc/rc.local :

chvt 4

W przypadku gdy nie używa się graficznego narzędzia do odpalania X-ów, w pewnych sytuacjach mogą pojawić się problemy przy wyłączaniu systemu, np. gdy chcemy podejrzeć komunikaty, które są wyrzucane na konsolę. Ja dodatkowo sobie wrzuciłem skrypt do autostartu, który zatrzymuje shutdown, by zobaczyć czy skrypt się poprawnie wykonują przy zamykaniu systemu i ten skrypt zawieszał mi cały system.

Rozwiązaniem tego problemu jest stworzenie aliasów na polecenia, którymi zamykamy system, z reguły są to reboot albo poweroff, w zależności od tego czy chcemy zresetować maszynę czy ją wyłączyć. By stworzyć takie aliasy, edytujemy plik .bashrc roota i dodajemy do niego poniższą zawartość:

alias reboot='openbox --exit && reboot' alias poweroff='openbox --exit && poweroff'

Kluczowe w tych aliasach jest wywołanie openbox --exit, co wyloguje nas pierw z sesji openboxa, zwalniając tym samym konsolę, na której było wywołane polecenie startx. Dzięki temu komunikaty końcowe będą mogły się tam bez problemu wyświetlić. Jeśli korzystamy z polecenia shutdown z odpowiednimi opcjami, trzeba sprecyzować dodatkowe aliasy.

W przypadku gdy chcemy wyłączać/resetować maszynę z konta zwykłego użytkownika, powyższe aliasy trzeba także dopisać bo pliki .bashrc danego użytkownika. Można to także zrobić globalnie dla wszystkich użytkowników w pliku /etc/bash.bashrc . Dodatkowo trzeba zaprzęgnąć sudo do pomocy i dopisać 2 linijki do jego pliki konfiguracyjnego. Odpalamy zatem visudo i dodajemy poniższą zawartość:

%powerpc ALL = (root) NOPASSWD: /sbin/poweroff %powerpc ALL = (root) NOPASSWD: /sbin/reboot

Musimy także się dodać do grupy powerpc ale domyślnie ona nie istnieje w systemie. Tworzymy ją i dodajemy pożądanych użytkowników do niej:

groupadd -g 5005 powerpc

adduser morfik powerpc

I to w zasadzie wszystko. Jeśli ktoś ciekaw jak zatrzymać procedurę shutdownu tuż przed wyłączeniem maszyny, poniżej skrypt, który trzeba dodać do autostartu via update-rc.d :

$ cat /etc/init.d/pause_hook

! /bin/sh

BEGIN INIT INFO

Provides: pause_hook

Required-Start:

Required-Stop: halt reboot

Default-Start:

Default-Stop: 0 6

X-Stop-After: umountroot

X-Interactive: true

Short-Description: Pause before halt or reboot

Description:

END INIT INFO

do_stop () { [ -r /etc/pause_hook.conf ] && . /etc/pause_hook.conf

[ "$PAUSE_HOOK_ENABLED" = "true" ] && read -p "Press enter to continue" reply

}

case "$1" in start) # No-op ;; restart|reload|force-reload) echo "Error: argument '$1' not supported">&2 exit 3 ;; stop) do_stop ;; *) echo "Usage: $0 start|stop">&2 exit 3 ;; esac

By było po debianowemu, potrzebny jest jeszcze plik konfiguracyjny /etc/pause_hook.conf o treści:

PAUSE_HOOK_ENABLED="true"

Kompresja RAMu i SWAPu

$
0
0

Jakiś czas temu, ktoś na forum napisał posta o kompresji danych w pamięci RAM, dodatkowo była też wzmianka o SWAPie. Jako, że wszyscy zachwalają ten sposób z kompresją danych, zwłaszcza na słabych maszynach, tych z małą ilością RAM, to postanowiłem sprawdzić na ile są wiarygodne te wierzenia w rzekomy lepszy performance, no jakby nie patrzeć ciężko znaleźć kogoś kto ma mniej RAMu ode mnie.

Na sam początek trochę słów o moim sprzęcie, a konkretnie o RAMie i procesorze, bo głównie od tych dwóch czynników będzie zależał wynik końcowy. Zgodnie z tym co pokazuje inxi, RAM i procek prezentuje się następująco:

inxi -F -c 21

... CPU: Dual core Intel Pentium D CPU (-MCP-) cache: 2048 KB flags: (lm nx sse sse2 sse3) Clock Speeds: 1: 3000.00 MHz 2: 3000.00 MHz ... Info: Processes: 227 Uptime: 10:24 Memory: 829.6/1001.2MB Client: Shell (bash) inxi: 1.9.17

Czyli mam dwurdzeniowy procesor i 1GiB pamięci RAM, czyli skompresowany RAM i SWAP powinny przypaść mi do gustu. Spróbujmy zatem wdrożyć tę technologię.

Kernel musi posiadać odpowiedni moduł, by w ogóle była możliwa zabawa ze ZRAMem:

cat /boot/config-3.12-1-amd64 | grep -i zram

CONFIG_ZRAM=m

CONFIG_ZRAM_DEBUG is not set

Bez tego ani rusz i jeśli nasz kernel nie posiada tego modułu, konieczna będzie rekompilacja kernela. Kolejna sprawa to załadowanie tego modułu na starcie systemu, zatem dopisujemy w /etc/modules poniższą linijkę:

zram num_devices=2

Trzeba tylko dobrać odpowiednią liczbę urządzeń, a zależy ona od ilości rdzeni procesora, mój procek ma 2 rdzenie, więc parametr num_devices przyjął wartość 2. Ale samo załadowanie modułu nic nam nie da, trzeba jeszcze stworzyć odpowiednie RAM dyski. Te RAM dyski to nic innego jak sformatowane na SWAP urządzenia zamontowane w RAMie. Mamy dwie opcje -- albo stworzyć skrypt startowy, albo zaprzęgnąć do tego celu udeva. Jeśli chcemy skrypt, to wygląda on mniej więcej tak:

!/bin/bash

BEGIN INIT INFO

Provides: zram

Required-Start: $syslog $remote_fs

Required-Stop: $syslog $remote_fs

Default-Start: 2 3 4 5

Default-Stop: 0 1 6

Short-Description: zram devices

Description: zram devices

END INIT INFO

Author: Mikhail Morfikov morfikov[at]gmail.com

PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin

SCRIPTNAME="zram"

zram_start () { modprobe zram num_devices=2

SIZE="250" echo $(($SIZE10241024)) > /sys/block/zram0/disksize echo $(($SIZE10241024)) > /sys/block/zram1/disksize

mkswap -L zram0 /dev/zram0 mkswap -L zram1 /dev/zram1

swapon /dev/zram0 -p 70 swapon /dev/zram1 -p 70 }

zram_stop () { swapoff /dev/zram0 swapoff /dev/zram1

echo 1 > /sys/block/zram0/reset echo 1 > /sys/block/zram1/reset

modprobe -r zram }

case "$1" in start) zram_start || exit 1 ;; stop) zram_stop || exit 1 ;; force-reload|restart) zram_stop && sleep 1 zram_start || exit 1 ;; *) echo "Usage: $SCRIPTNAME {start|stop|restart}" exit 1 ;;
esac

exit 0

Można również skorzystać z udeva. To wymaga stworzenia pliku z regułami /etc/udev/rules.d/70-zram.rules o treści:

KERNEL=="zram0", SUBSYSTEM=="block", DRIVER=="", ACTION=="add", ATTR{disksize}=="0", ATTR{disksize}="150M", RUN+="/sbin/mkswap $env{DEVNAME}" KERNEL=="zram1", SUBSYSTEM=="block", DRIVER=="", ACTION=="add", ATTR{disksize}=="0", ATTR{disksize}="150M", RUN+="/sbin/mkswap $env{DEVNAME}"

Kluczowe jest tutaj ustalenie wartości ATTR{disksize}, która to określa rozmiar jednego RAM dysku. Teoretycznie nie powinno się stosować wartości większej niż 50% dostępnego RAMu, czyli jeśli ja mam 1GiB, to maksymalna wartość jaką mógłbym użyć na ZRAM to 512MiB, po 256MiB na każdy z rdzeni procesora. Ale przy takiej wartości, komp trochę zaczynał mulić i zadziałało to zjadliwie przy wartości 300MiB, czyli 150MiB na każdy rdzeń. Dodatkowo trzeba dodać do /etc/fstab dwa wpisy, które zamontują nam te urządzenia ZRAM przy starcie systemu:

/dev/zram0 swap swap defaults,pri=70 0 0 /dev/zram1 swap swap defaults,pri=70 0 0 UUID=3f9f24d7-86d1-4e21-93e9-f3c181d05cf0 swap swap defaults,pri=10 0 0

Powyżej jest również pokazany mój zwykły SWAP. Różni się on jedynie priorytetem -- trzeba je nadać tak by wyższy priorytet przypadł urządzeniom ZRAM, bo w takim przypadku dane pierw będą zrzucane do tych RAM dysków, a gdy zabranie w nich miejsca, dane polecą do tradycyjnego SWAPa.

Pozostała jeszcze kwestia skompresowanego SWAPu, tego zwykłego. Tutaj sprawa ma się dość prosto, trzeba dopisać jeden parametr do linijki kernela -- zswap.enabled=1 . Edytujemy zatem konfigurację extlinuxa (lub gruba), plik /boot/extlinux/extlinux.conf i dopisujemy ten parametr:

APPEND root=/dev/mapper/debian_crypt-root cgroup_enable=memory zswap.enabled=1 fbcon=scrollback:124k ro

Po resecie maszyny sprawdzamy czy aby wszytko zostało utworzone i zamontowane prawidłowo:

swapon -s

Filename Type Size Used Priority /dev/mapper/debian_crypt-swap partition 2097148 398368 10 /dev/zram0 partition 153596 153480 70 /dev/zram1 partition 153596 153500 70

Jak widać powyżej, mam zapchane oba urządzenia ZRAM, łącznie prawie 700MiB siedzi w tych SWAPach. Samo zachowanie się urządzeń ZRAM można monitorować przez pliki w katalogu /sys/block/zram0 oraz /sys/block/zram1 . Dodatkowo znalazłem skrypt, który pokazuje stopień kompresji danych:

!/bin/sh -eu

TOTAL_DATA=0 TOTAL_COMP=0 HAS_ZRAM=

Iterate through swap devices searching for compressed ones

while read NAME _; do

Filter zram swaps and let's hope your ordinary swap doesn't have

"zram" in its name :D

case $NAME in zram) ;; *) continue esac

DIR=/sysudevadm info --query=path --name=$NAME read DATA

Konfiguracja środowiska pbuilder dla dystrybucji Raspbian

$
0
0

Raspbian jest systemem bazującym na Debianie przystosowanym do platformy Raspberry Pi. Jednak zasadniczą różnicą jest fakt, iż platforma korzysta ze starszej architektury procesora niż maszyny budujące pakiety dla Debiana. Instalacja z repozytoriów kończy się zwykle błędem naruszenia ochrony pamięci. Repozytoria Raspbiana zawierają pakiety przebudowane specjalnie na platformę Raspberry Pi, ale co gdy chcemy nowszy pakiet lub skompilować coś samemu?

Tutaj na pomoc przychodzi narzędzie developerów Debian - pbuilder. Przy czym może być używane przez zwykłych śmiertelników. Narzędzie to utrzymuje minimalny systemy pracy w środowisku chroot, zainstalować tylko niezbędne zależności budowania wymienione w pliku debian/control i usunąć je, gdy budowa jest zakończona. Dlatego, korzystając z pbuilder, opiekun pakietu może wykryć, jeśli niektóre zależności budowania nie zostały określone w debian/control. Również pbuilder umożliwia testową budowę dla gałęzi innych niż jeden wersja na której jest uruchomiany, na przykład: w wersji rozwojowej, podczas gdy w rzeczywistości działa na wersji stabilnej.

Aby korzystać z programu potrzebne są uprawnienia użytkownika root, może być poprzez sudo. Jako pierwszy krok instalujemy następujące pakiety:

sudo apt-get install pbuilder debootstrap devscripts

Następnym krokiem jest konfiguracja programu. pbuilder umożliwia dość złożoną konfigurację, chociaż w tym przypadku przyda się w miarę prosta. Pełne możliwości zostały opisane na wiki Ubuntu.

Przygotowałem gotową konfigurację dla Raspbiana w wersji stabilnej i testowej:

# Codenames for Raspbian suites according to their alias. Update these when
# needed.
TESTING_CODENAME="jessie"
STABLE_CODENAME="wheezy"

# List of Raspbian suites.
RASPBIAN_SUITES=($TESTING_CODENAME $STABLE_CODENAME
    "testing""stable")

# Mirrors to use. Update these to your preferred mirror.
RASPBIAN_MIRROR="archive.raspbian.org"

# Optionally use the changelog of a package to determine the suite to use if
# none set.
if [ -z "${DIST}" ] && [ -r "debian/changelog" ]; then
    DIST=$(dpkg-parsechangelog | awk '/^Distribution: / {print $2}')
fi

# Optionally set a default distribution if none is used. Note that you can set
# your own default (i.e. ${DIST:="unstable"}).
: ${DIST:="$(lsb_release --short --codename)"}

# Optionally change Debian codenames in $DIST to their aliases.
case "$DIST" in
    $TESTING_CODENAME)
        DIST="testing"
        ;;
    $STABLE_CODENAME)
        DIST="stable"
        ;;
esac

# Optionally set the architecture to the host architecture if none set. Note
# that you can set your own default (i.e. ${ARCH:="i386"}).
: ${ARCH:="$(dpkg --print-architecture)"}

NAME="$DIST"
if [ -n "${ARCH}" ]; then
    NAME="$NAME-$ARCH"
    DEBOOTSTRAPOPTS=("--arch""$ARCH""${DEBOOTSTRAPOPTS[@]}""--keyring""/etc/apt/trusted.gpg""--variant=buildd")
fi
BASETGZ="/var/cache/pbuilder/$NAME-base.tgz"
DISTRIBUTION="$DIST"
BUILDRESULT="/var/cache/pbuilder/$NAME/result/"
APTCACHE="/var/cache/pbuilder/$NAME/aptcache/"
BUILDPLACE="/var/cache/pbuilder/build/"
AUTOCLEANAPTCACHE="yes"


if $(echo ${RASPBIAN_SUITES[@]} | grep -q $DIST); then
    # Debian configuration
    MIRRORSITE="http://$RASPBIAN_MIRROR/raspbian/"
    COMPONENTS="main contrib non-free"
else
    echo "Unknown distribution: $DIST"
    exit 1
fi

Umieszczamy ją w pliku /root/.pbuilderrc. Następne tworzymy środowisko spakowane chroot:

sudo pbuilder create --debootstrapopts --variant=buildd

Zostanie ono stworzone w wersji jak system host czy stabilnej bądź testowej. Jeśli używamy wersji testowej i interesuje nas środowisko w wersji stabilnej możemy użyć flagi DIST:

sudo DIST=stable pbuilder create

lub gdy chcemy odwrotnie:

sudo DIST=testing pbuilder create

Teraz możemy przejść do budowy interesującego nas pakiety lub samemu przygotować źródła. Do budowy będzie nam potrzebny plik dsc zawierający informacje o źródłach. Powiedzmy interesuje mnie pakiet viewnior którego nie ma jeszcze w repozytorium testowym i chce zbudować.

Zaczynam od pobrania źródeł: dget http://ftp.de.debian.org/debian/pool/main/v/viewnior/viewnior_1.4-1.dsc

Pobranie powinno wyglądać mniej więcej tak:

dget: retrieving http://ftp.de.debian.org/debian/pool/main/v/viewnior/viewnior_1.4-1.dsc
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1918  100  1918    0     0   3007      0 --:--:-- --:--:-- --:--:--  3015
dget: retrieving http://ftp.de.debian.org/debian/pool/main/v/viewnior/viewnior_1.4.orig.tar.gz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  547k  100  547k    0     0   301k      0  0:00:01  0:00:01 --:--:--  301k
dget: retrieving http://ftp.de.debian.org/debian/pool/main/v/viewnior/viewnior_1.4-1.debian.tar.xz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  3136  100  3136    0     0   7545      0 --:--:-- --:--:-- --:--:--  7556
dscverify: can't find any system keyrings

Następnie rozpoczynam budowę pakietu:

sudo pbuilder --build viewnior_1.4-1.dsc 

Wygląda to tak:

I: using fakeroot in build.
I: Current time: Sat Feb 22 18:09:41 CET 2014
I: pbuilder-time-stamp: 1393088981
I: Building the build Environment
I: extracting base tarball [/var/cache/pbuilder/testing-armhf-base.tgz]
I: creating local configuration
I: copying local configuration
I: mounting /proc filesystem
I: mounting /run/shm filesystem
I: mounting /dev/pts filesystem
I: policy-rc.d already exists
I: Obtaining the cached apt archive contents
I: Installing the build-deps
 -> Attempting to satisfy build-dependencies
 -> Creating pbuilder-satisfydepends-dummy package
Package: pbuilder-satisfydepends-dummy
Version: 0.invalid.0
Architecture: armhf
Maintainer: Debian Pbuilder Team 
Description: Dummy package to satisfy dependencies with aptitude - created by pbuilder
 This package was created automatically by pbuilder to satisfy the
 build-dependencies of the package being currently built.
Depends: debhelper (>= 9), libgtk2.0-dev, intltool (>= 0.35.0), libexiv2-dev, libexiv2-12, dh-autoreconf
dpkg-deb: building package `pbuilder-satisfydepends-dummy' in `/tmp/satisfydepends-aptitude/pbuilder-satisfydepends-dummy.deb'.
Selecting previously unselected package pbuilder-satisfydepends-dummy.
(Reading database ... 11809 files and directories currently installed.)
Preparing to unpack .../pbuilder-satisfydepends-dummy.deb ...
Unpacking pbuilder-satisfydepends-dummy (0.invalid.0) ...
dpkg: pbuilder-satisfydepends-dummy: dependency problems, but configuring anyway as you requested:
 pbuilder-satisfydepends-dummy depends on debhelper (>= 9); however:
  Package debhelper is not installed.
 pbuilder-satisfydepends-dummy depends on libgtk2.0-dev; however:
  Package libgtk2.0-dev is not installed.
 pbuilder-satisfydepends-dummy depends on intltool (>= 0.35.0); however:
  Package intltool is not installed.
 pbuilder-satisfydepends-dummy depends on libexiv2-dev; however:
  Package libexiv2-dev is not installed.
 pbuilder-satisfydepends-dummy depends on libexiv2-12; however:
  Package libexiv2-12 is not installed.
 pbuilder-satisfydepends-dummy depends on dh-autoreconf; however:
  Package dh-autoreconf is not installed.

Setting up pbuilder-satisfydepends-dummy (0.invalid.0) ...
dpkg: pbuilder-satisfydepends-dummy: dependency problems, but configuring anyway as you requested:
 pbuilder-satisfydepends-dummy depends on debhelper (>= 9); however:
  Package debhelper is not installed.
 pbuilder-satisfydepends-dummy depends on libgtk2.0-dev; however:
  Package libgtk2.0-dev is not installed.
 pbuilder-satisfydepends-dummy depends on intltool (>= 0.35.0); however:
  Package intltool is not installed.
 pbuilder-satisfydepends-dummy depends on libexiv2-dev; however:
  Package libexiv2-dev is not installed.
 pbuilder-satisfydepends-dummy depends on libexiv2-12; however:
  Package libexiv2-12 is not installed.
 pbuilder-satisfydepends-dummy depends on dh-autoreconf; however:
  Package dh-autoreconf is not installed.

Setting up pbuilder-satisfydepends-dummy (0.invalid.0) ...
The following NEW packages will be installed:
  autoconf{a} automake{a} autopoint{a} autotools-dev{a} bsdmainutils{a} 
  ca-certificates{a} debhelper{a} dh-autoreconf{a} file{a} fontconfig{a} 
  fontconfig-config{a} fonts-dejavu-core{a} gettext{a} gettext-base{a} 
  gir1.2-atk-1.0{a} gir1.2-freedesktop{a} gir1.2-gdkpixbuf-2.0{a} 
  gir1.2-glib-2.0{a} gir1.2-gtk-2.0{a} gir1.2-pango-1.0{a} groff-base{a} 
  intltool{a} intltool-debian{a} libasprintf0c2{a} libatk1.0-0{a} 
  libatk1.0-data{a} libatk1.0-dev{a} libavahi-client3{a} 
  libavahi-common-data{a} libavahi-common3{a} libcairo-gobject2{a} 
  libcairo-script-interpreter2{a} libcairo2{a} libcairo2-dev{a} 
  libcroco3{a} libcups2{a} libdatrie1{a} libdrm-dev{a} libdrm-nouveau2{a} 
  libdrm-omap1{a} libdrm-radeon1{a} libdrm2{a} libelfg0{a} 
  libencode-locale-perl{a} libexiv2-12{a} libexiv2-dev{a} libexpat1{a} 
  libexpat1-dev{a} libffi6{a} libfile-listing-perl{a} libfontconfig1{a} 
  libfontconfig1-dev{a} libfreetype6{a} libfreetype6-dev{a} libgcrypt11{a} 
  libgdk-pixbuf2.0-0{a} libgdk-pixbuf2.0-common{a} libgdk-pixbuf2.0-dev{a} 
  libgirepository-1.0-1{a} libgl1-mesa-dev{a} libgl1-mesa-glx{a} 
  libglapi-mesa{a} libglib2.0-0{a} libglib2.0-bin{a} libglib2.0-data{a} 
  libglib2.0-dev{a} libgnutls26{a} libgpg-error0{a} libgraphite2-3{a} 
  libgssapi-krb5-2{a} libgtk2.0-0{a} libgtk2.0-common{a} libgtk2.0-dev{a} 
  libharfbuzz-dev{a} libharfbuzz-gobject0{a} libharfbuzz-icu0{a} 
  libharfbuzz0b{a} libhtml-parser-perl{a} libhtml-tagset-perl{a} 
  libhtml-tree-perl{a} libhttp-cookies-perl{a} libhttp-date-perl{a} 
  libhttp-message-perl{a} libhttp-negotiate-perl{a} libice-dev{a} 
  libice6{a} libicu52{a} libio-html-perl{a} libio-socket-ssl-perl{a} 
  libjasper1{a} libjbig0 libjpeg8{a} libk5crypto3{a} libkeyutils1{a} 
  libkrb5-3{a} libkrb5support0{a} liblwp-mediatypes-perl{a} 
  liblwp-protocol-https-perl{a} liblzo2-2{a} libmagic1{a} 
  libnet-http-perl{a} libnet-ssleay-perl{a} libp11-kit0{a} 
  libpango-1.0-0{a} libpango1.0-dev{a} libpangocairo-1.0-0{a} 
  libpangoft2-1.0-0{a} libpangoxft-1.0-0{a} libpcre3-dev{a} libpcrecpp0{a} 
  libpipeline1{a} libpixman-1-0{a} libpixman-1-dev{a} libpng12-0{a} 
  libpng12-dev{a} libpopt0{a} libpthread-stubs0-dev{a} libpython-stdlib{a} 
  libpython2.7-minimal{a} libpython2.7-stdlib{a} libsigsegv2{a} 
  libsm-dev{a} libsm6{a} libssl1.0.0{a} libtasn1-6{a} libthai-data{a} 
  libthai0{a} libtiff4{a} libtool{a} libunistring0{a} liburi-perl{a} 
  libwww-perl{a} libwww-robotrules-perl{a} libx11-6{a} libx11-data{a} 
  libx11-dev{a} libx11-xcb-dev{a} libx11-xcb1{a} libxau-dev{a} libxau6{a} 
  libxcb-dri2-0{a} libxcb-dri2-0-dev{a} libxcb-glx0{a} libxcb-glx0-dev{a} 
  libxcb-render0{a} libxcb-render0-dev{a} libxcb-shm0{a} libxcb-shm0-dev{a} 
  libxcb1{a} libxcb1-dev{a} libxcomposite-dev{a} libxcomposite1{a} 
  libxcursor-dev{a} libxcursor1{a} libxdamage-dev{a} libxdamage1{a} 
  libxdmcp-dev{a} libxdmcp6{a} libxext-dev{a} libxext6{a} libxfixes-dev{a} 
  libxfixes3{a} libxft-dev{a} libxft2{a} libxi-dev{a} libxi6{a} 
  libxinerama-dev{a} libxinerama1{a} libxml-parser-perl{a} libxml2{a} 
  libxml2-utils{a} libxrandr-dev{a} libxrandr2{a} libxrender-dev{a} 
  libxrender1{a} libxxf86vm-dev{a} libxxf86vm1{a} m4{a} man-db{a} 
  mesa-common-dev{a} mime-support{a} netbase{a} openssl{a} pkg-config{a} 
  po-debconf{a} python{a} python-minimal{a} python2.7{a} 
  python2.7-minimal{a} shared-mime-info{a} ucf{a} x11-common{a} 
  x11proto-composite-dev{a} x11proto-core-dev{a} x11proto-damage-dev{a} 
  x11proto-dri2-dev{a} x11proto-fixes-dev{a} x11proto-gl-dev{a} 
  x11proto-input-dev{a} x11proto-kb-dev{a} x11proto-randr-dev{a} 
  x11proto-render-dev{a} x11proto-xext-dev{a} x11proto-xf86vidmode-dev{a} 
  x11proto-xinerama-dev{a} xorg-sgml-doctools{a} xtrans-dev{a} 
  zlib1g-dev{a} 
The following packages are RECOMMENDED but will NOT be installed:
  curl hicolor-icon-theme ifupdown krb5-locales libasprintf-dev 
  libgettextpo-dev libgl1-mesa-dri libgtk2.0-bin libhtml-form-perl 
  libhtml-format-perl libhttp-daemon-perl libio-socket-inet6-perl 
  libio-socket-ip-perl libltdl-dev libmail-sendmail-perl libmailtools-perl 
  libx11-doc lynx-cur netscript-2.4 wget xml-core 
0 packages upgraded, 208 newly installed, 0 to remove and 0 not upgraded.
Need to get 4442 kB/63.9 MB of archives. After unpacking 211 MB will be used.
Get: 1 http://archive.raspbian.org/raspbian/ testing/main libgnutls26 armhf 2.12.23-12 [490 kB]
Get: 2 http://archive.raspbian.org/raspbian/ testing/main libmagic1 armhf 1:5.17-0.1 [224 kB]
Get: 3 http://archive.raspbian.org/raspbian/ testing/main x11-common all 1:7.7+6 [287 kB]
Get: 4 http://archive.raspbian.org/raspbian/ testing/main file armhf 1:5.17-0.1 [54.8 kB]
Get: 5 http://archive.raspbian.org/raspbian/ testing/main autoconf all 2.69-4 [339 kB]
Get: 6 http://archive.raspbian.org/raspbian/ testing/main libtool armhf 2.4.2-1.7 [505 kB]
Get: 7 http://archive.raspbian.org/raspbian/ testing/main dh-autoreconf all 9 [15.5 kB]
Get: 8 http://archive.raspbian.org/raspbian/ testing/main libio-socket-ssl-perl all 1.967-1 [97.3 kB]
Get: 9 http://archive.raspbian.org/raspbian/ testing/main libexiv2-12 armhf 0.23-1 [742 kB]
Get: 10 http://archive.raspbian.org/raspbian/ testing/main libexiv2-dev armhf 0.23-1 [1687 kB]
Fetched 4442 kB in 6s (740 kB/s)         
debconf: delaying package configuration, since apt-utils is not installed
Selecting previously unselected package libpipeline1:armhf.
(Reading database ... 11809 files and directories currently installed.)
Preparing to unpack .../libpipeline1_1.2.6-2_armhf.deb ...
Unpacking libpipeline1:armhf (1.2.6-2) ...
Selecting previously unselected package libpopt0:armhf.
Preparing to unpack .../libpopt0_1.16-8_armhf.deb ...
Unpacking libpopt0:armhf (1.16-8) ...
Selecting previously unselected package libssl1.0.0:armhf.
Preparing to unpack .../libssl1.0.0_1.0.1f-1_armhf.deb ...
Unpacking libssl1.0.0:armhf (1.0.1f-1) ...
Selecting previously unselected package groff-base.
Preparing to unpack .../groff-base_1.22.2-5_armhf.deb ...
Unpacking groff-base (1.22.2-5) ...
Selecting previously unselected package bsdmainutils.
Preparing to unpack .../bsdmainutils_9.0.5_armhf.deb ...
Unpacking bsdmainutils (9.0.5) ...
Selecting previously unselected package man-db.
Preparing to unpack .../man-db_2.6.6-1_armhf.deb ...
Unpacking man-db (2.6.6-1) ...
Selecting previously unselected package libasprintf0c2:armhf.
Preparing to unpack .../libasprintf0c2_0.18.3.2-1_armhf.deb ...
Unpacking libasprintf0c2:armhf (0.18.3.2-1) ...
Selecting previously unselected package libgpg-error0:armhf.
Preparing to unpack .../libgpg-error0_1.12-0.2_armhf.deb ...
Unpacking libgpg-error0:armhf (1.12-0.2) ...
Selecting previously unselected package libgcrypt11:armhf.
Preparing to unpack .../libgcrypt11_1.5.3-3_armhf.deb ...
Unpacking libgcrypt11:armhf (1.5.3-3) ...
Selecting previously unselected package libffi6:armhf.
Preparing to unpack .../libffi6_3.0.13-12_armhf.deb ...
Unpacking libffi6:armhf (3.0.13-12) ...
Selecting previously unselected package libp11-kit0:armhf.
Preparing to unpack .../libp11-kit0_0.20.2-1_armhf.deb ...
Unpacking libp11-kit0:armhf (0.20.2-1) ...
Selecting previously unselected package libtasn1-6:armhf.
Preparing to unpack .../libtasn1-6_3.4-3_armhf.deb ...
Unpacking libtasn1-6:armhf (3.4-3) ...
Selecting previously unselected package libgnutls26:armhf.
Preparing to unpack .../libgnutls26_2.12.23-12_armhf.deb ...
Unpacking libgnutls26:armhf (2.12.23-12) ...
Selecting previously unselected package libkeyutils1:armhf.
Preparing to unpack .../libkeyutils1_1.5.6-1_armhf.deb ...
Unpacking libkeyutils1:armhf (1.5.6-1) ...
Selecting previously unselected package libkrb5support0:armhf.
Preparing to unpack .../libkrb5support0_1.12+dfsg-2_armhf.deb ...
Unpacking libkrb5support0:armhf (1.12+dfsg-2) ...
Selecting previously unselected package libk5crypto3:armhf.
Preparing to unpack .../libk5crypto3_1.12+dfsg-2_armhf.deb ...
Unpacking libk5crypto3:armhf (1.12+dfsg-2) ...
Selecting previously unselected package libkrb5-3:armhf.
Preparing to unpack .../libkrb5-3_1.12+dfsg-2_armhf.deb ...
Unpacking libkrb5-3:armhf (1.12+dfsg-2) ...
Selecting previously unselected package libgssapi-krb5-2:armhf.
Preparing to unpack .../libgssapi-krb5-2_1.12+dfsg-2_armhf.deb ...
Unpacking libgssapi-krb5-2:armhf (1.12+dfsg-2) ...
Selecting previously unselected package libmagic1:armhf.
Preparing to unpack .../libmagic1_1%3a5.17-0.1_armhf.deb ...
Unpacking libmagic1:armhf (1:5.17-0.1) ...
Selecting previously unselected package libxml2:armhf.
Preparing to unpack .../libxml2_2.9.1+dfsg1-3_armhf.deb ...
Unpacking libxml2:armhf (2.9.1+dfsg1-3) ...
Selecting previously unselected package libpython2.7-minimal:armhf.
Preparing to unpack .../libpython2.7-minimal_2.7.6-5_armhf.deb ...
Unpacking libpython2.7-minimal:armhf (2.7.6-5) ...
Selecting previously unselected package python2.7-minimal.
Preparing to unpack .../python2.7-minimal_2.7.6-5_armhf.deb ...
Unpacking python2.7-minimal (2.7.6-5) ...
Selecting previously unselected package libglib2.0-0:armhf.
Preparing to unpack .../libglib2.0-0_2.36.4-1_armhf.deb ...
Unpacking libglib2.0-0:armhf (2.36.4-1) ...
Selecting previously unselected package libatk1.0-data.
Preparing to unpack .../libatk1.0-data_2.10.0-2_all.deb ...
Unpacking libatk1.0-data (2.10.0-2) ...
Selecting previously unselected package libatk1.0-0:armhf.
Preparing to unpack .../libatk1.0-0_2.10.0-2_armhf.deb ...
Unpacking libatk1.0-0:armhf (2.10.0-2) ...
Selecting previously unselected package libavahi-common-data:armhf.
Preparing to unpack .../libavahi-common-data_0.6.31-4_armhf.deb ...
Unpacking libavahi-common-data:armhf (0.6.31-4) ...
Selecting previously unselected package libavahi-common3:armhf.
Preparing to unpack .../libavahi-common3_0.6.31-4_armhf.deb ...
Unpacking libavahi-common3:armhf (0.6.31-4) ...
Selecting previously unselected package libavahi-client3:armhf.
Preparing to unpack .../libavahi-client3_0.6.31-4_armhf.deb ...
Unpacking libavahi-client3:armhf (0.6.31-4) ...
Selecting previously unselected package libexpat1:armhf.
Preparing to unpack .../libexpat1_2.1.0-4_armhf.deb ...
Unpacking libexpat1:armhf (2.1.0-4) ...
Selecting previously unselected package libpng12-0:armhf.
Preparing to unpack .../libpng12-0_1.2.50-1_armhf.deb ...
Unpacking libpng12-0:armhf (1.2.50-1) ...
Selecting previously unselected package libfreetype6:armhf.
Preparing to unpack .../libfreetype6_2.5.2-1_armhf.deb ...
Unpacking libfreetype6:armhf (2.5.2-1) ...
Selecting previously unselected package ucf.
Preparing to unpack .../ucf_3.0027+nmu1_all.deb ...
Moving old data out of the way
Unpacking ucf (3.0027+nmu1) ...
Selecting previously unselected package fonts-dejavu-core.
Preparing to unpack .../fonts-dejavu-core_2.34-1_all.deb ...
Unpacking fonts-dejavu-core (2.34-1) ...
Selecting previously unselected package fontconfig-config.
Preparing to unpack .../fontconfig-config_2.11.0-2_all.deb ...
Unpacking fontconfig-config (2.11.0-2) ...
Selecting previously unselected package libfontconfig1:armhf.
Preparing to unpack .../libfontconfig1_2.11.0-2_armhf.deb ...
Unpacking libfontconfig1:armhf (2.11.0-2) ...
Selecting previously unselected package libdrm2:armhf.
Preparing to unpack .../libdrm2_2.4.52-1_armhf.deb ...
Unpacking libdrm2:armhf (2.4.52-1) ...
Selecting previously unselected package libglapi-mesa:armhf.
Preparing to unpack .../libglapi-mesa_9.2.2-1_armhf.deb ...
Unpacking libglapi-mesa:armhf (9.2.2-1) ...
Selecting previously unselected package libxau6:armhf.
Preparing to unpack .../libxau6_1%3a1.0.8-1_armhf.deb ...
Unpacking libxau6:armhf (1:1.0.8-1) ...
Selecting previously unselected package libxdmcp6:armhf.
Preparing to unpack .../libxdmcp6_1%3a1.1.1-1_armhf.deb ...
Unpacking libxdmcp6:armhf (1:1.1.1-1) ...
Selecting previously unselected package libxcb1:armhf.
Preparing to unpack .../libxcb1_1.10-2_armhf.deb ...
Unpacking libxcb1:armhf (1.10-2) ...
Selecting previously unselected package libx11-data.
Preparing to unpack .../libx11-data_2%3a1.6.2-1_all.deb ...
Unpacking libx11-data (2:1.6.2-1) ...
Selecting previously unselected package libx11-6:armhf.
Preparing to unpack .../libx11-6_2%3a1.6.2-1_armhf.deb ...
Unpacking libx11-6:armhf (2:1.6.2-1) ...
Selecting previously unselected package libx11-xcb1:armhf.
Preparing to unpack .../libx11-xcb1_2%3a1.6.2-1_armhf.deb ...
Unpacking libx11-xcb1:armhf (2:1.6.2-1) ...
Selecting previously unselected package libxcb-dri2-0:armhf.
Preparing to unpack .../libxcb-dri2-0_1.10-2_armhf.deb ...
Unpacking libxcb-dri2-0:armhf (1.10-2) ...
Selecting previously unselected package libxcb-glx0:armhf.
Preparing to unpack .../libxcb-glx0_1.10-2_armhf.deb ...
Unpacking libxcb-glx0:armhf (1.10-2) ...
Selecting previously unselected package libxfixes3:armhf.
Preparing to unpack .../libxfixes3_1%3a5.0.1-1_armhf.deb ...
Unpacking libxfixes3:armhf (1:5.0.1-1) ...
Selecting previously unselected package libxdamage1:armhf.
Preparing to unpack .../libxdamage1_1%3a1.1.4-1_armhf.deb ...
Unpacking libxdamage1:armhf (1:1.1.4-1) ...
Selecting previously unselected package libxext6:armhf.
Preparing to unpack .../libxext6_2%3a1.3.2-1_armhf.deb ...
Unpacking libxext6:armhf (2:1.3.2-1) ...
Selecting previously unselected package libxxf86vm1:armhf.
Preparing to unpack .../libxxf86vm1_1%3a1.1.3-1_armhf.deb ...
Unpacking libxxf86vm1:armhf (1:1.1.3-1) ...
Selecting previously unselected package libgl1-mesa-glx:armhf.
Preparing to unpack .../libgl1-mesa-glx_9.2.2-1_armhf.deb ...
Unpacking libgl1-mesa-glx:armhf (9.2.2-1) ...
Selecting previously unselected package libpixman-1-0:armhf.
Preparing to unpack .../libpixman-1-0_0.32.4-1_armhf.deb ...
Unpacking libpixman-1-0:armhf (0.32.4-1) ...
Selecting previously unselected package libxcb-render0:armhf.
Preparing to unpack .../libxcb-render0_1.10-2_armhf.deb ...
Unpacking libxcb-render0:armhf (1.10-2) ...
Selecting previously unselected package libxcb-shm0:armhf.
Preparing to unpack .../libxcb-shm0_1.10-2_armhf.deb ...
Unpacking libxcb-shm0:armhf (1.10-2) ...
Selecting previously unselected package libxrender1:armhf.
Preparing to unpack .../libxrender1_1%3a0.9.8-1_armhf.deb ...
Unpacking libxrender1:armhf (1:0.9.8-1) ...
Selecting previously unselected package libcairo2:armhf.
Preparing to unpack .../libcairo2_1.12.16-2+rpi1_armhf.deb ...
Unpacking libcairo2:armhf (1.12.16-2+rpi1) ...
Selecting previously unselected package libcairo-gobject2:armhf.
Preparing to unpack .../libcairo-gobject2_1.12.16-2+rpi1_armhf.deb ...
Unpacking libcairo-gobject2:armhf (1.12.16-2+rpi1) ...
Selecting previously unselected package liblzo2-2:armhf.
Preparing to unpack .../liblzo2-2_2.06-1.2_armhf.deb ...
Unpacking liblzo2-2:armhf (2.06-1.2) ...
Selecting previously unselected package libcairo-script-interpreter2:armhf.
Preparing to unpack .../libcairo-script-interpreter2_1.12.16-2+rpi1_armhf.deb ...
Unpacking libcairo-script-interpreter2:armhf (1.12.16-2+rpi1) ...
Selecting previously unselected package libcroco3:armhf.
Preparing to unpack .../libcroco3_0.6.8-2_armhf.deb ...
Unpacking libcroco3:armhf (0.6.8-2) ...
Selecting previously unselected package libcups2:armhf.
Preparing to unpack .../libcups2_1.7.1-4_armhf.deb ...
Unpacking libcups2:armhf (1.7.1-4) ...
Selecting previously unselected package libdatrie1:armhf.
Preparing to unpack .../libdatrie1_0.2.8-1_armhf.deb ...
Unpacking libdatrie1:armhf (0.2.8-1) ...
Selecting previously unselected package libdrm-nouveau2:armhf.
Preparing to unpack .../libdrm-nouveau2_2.4.52-1_armhf.deb ...
Unpacking libdrm-nouveau2:armhf (2.4.52-1) ...
Selecting previously unselected package libdrm-omap1:armhf.
Preparing to unpack .../libdrm-omap1_2.4.52-1_armhf.deb ...
Unpacking libdrm-omap1:armhf (2.4.52-1) ...
Selecting previously unselected package libdrm-radeon1:armhf.
Preparing to unpack .../libdrm-radeon1_2.4.52-1_armhf.deb ...
Unpacking libdrm-radeon1:armhf (2.4.52-1) ...
Selecting previously unselected package libelfg0:armhf.
Preparing to unpack .../libelfg0_0.8.13-5_armhf.deb ...
Unpacking libelfg0:armhf (0.8.13-5) ...
Selecting previously unselected package libjpeg8:armhf.
Preparing to unpack .../libjpeg8_8d-2_armhf.deb ...
Unpacking libjpeg8:armhf (8d-2) ...
Selecting previously unselected package libjasper1:armhf.
Preparing to unpack .../libjasper1_1.900.1-14_armhf.deb ...
Unpacking libjasper1:armhf (1.900.1-14) ...
Selecting previously unselected package libjbig0:armhf.
Preparing to unpack .../libjbig0_2.0-2_armhf.deb ...
Unpacking libjbig0:armhf (2.0-2) ...
Selecting previously unselected package libtiff4:armhf.
Preparing to unpack .../libtiff4_3.9.7-3_armhf.deb ...
Unpacking libtiff4:armhf (3.9.7-3) ...
Selecting previously unselected package libgdk-pixbuf2.0-common.
Preparing to unpack .../libgdk-pixbuf2.0-common_2.28.2-1_all.deb ...
Unpacking libgdk-pixbuf2.0-common (2.28.2-1) ...
Selecting previously unselected package libgdk-pixbuf2.0-0:armhf.
Preparing to unpack .../libgdk-pixbuf2.0-0_2.28.2-1_armhf.deb ...
Unpacking libgdk-pixbuf2.0-0:armhf (2.28.2-1) ...
Selecting previously unselected package libgraphite2-3:armhf.
Preparing to unpack .../libgraphite2-3_1.2.4-1_armhf.deb ...
Unpacking libgraphite2-3:armhf (1.2.4-1) ...
Selecting previously unselected package libgtk2.0-common.
Preparing to unpack .../libgtk2.0-common_2.24.22-1_all.deb ...
Unpacking libgtk2.0-common (2.24.22-1) ...
Selecting previously unselected package libthai-data.
Preparing to unpack .../libthai-data_0.1.20-3_all.deb ...
Unpacking libthai-data (0.1.20-3) ...
Selecting previously unselected package libthai0:armhf.
Preparing to unpack .../libthai0_0.1.20-3_armhf.deb ...
Unpacking libthai0:armhf (0.1.20-3) ...
Selecting previously unselected package fontconfig.
Preparing to unpack .../fontconfig_2.11.0-2_armhf.deb ...
Unpacking fontconfig (2.11.0-2) ...
Selecting previously unselected package libpango-1.0-0:armhf.
Preparing to unpack .../libpango-1.0-0_1.36.0-1+b1_armhf.deb ...
Unpacking libpango-1.0-0:armhf (1.36.0-1+b1) ...
Selecting previously unselected package libharfbuzz0b:armhf.
Preparing to unpack .../libharfbuzz0b_0.9.26-4_armhf.deb ...
Unpacking libharfbuzz0b:armhf (0.9.26-4) ...
Selecting previously unselected package libpangoft2-1.0-0:armhf.
Preparing to unpack .../libpangoft2-1.0-0_1.36.0-1+b1_armhf.deb ...
Unpacking libpangoft2-1.0-0:armhf (1.36.0-1+b1) ...
Selecting previously unselected package libpangocairo-1.0-0:armhf.
Preparing to unpack .../libpangocairo-1.0-0_1.36.0-1+b1_armhf.deb ...
Unpacking libpangocairo-1.0-0:armhf (1.36.0-1+b1) ...
Selecting previously unselected package libxcomposite1:armhf.
Preparing to unpack .../libxcomposite1_1%3a0.4.4-1_armhf.deb ...
Unpacking libxcomposite1:armhf (1:0.4.4-1) ...
Selecting previously unselected package libxcursor1:armhf.
Preparing to unpack .../libxcursor1_1%3a1.1.14-1_armhf.deb ...
Unpacking libxcursor1:armhf (1:1.1.14-1) ...
Selecting previously unselected package libxi6:armhf.
Preparing to unpack .../libxi6_2%3a1.7.2-1_armhf.deb ...
Unpacking libxi6:armhf (2:1.7.2-1) ...
Selecting previously unselected package libxinerama1:armhf.
Preparing to unpack .../libxinerama1_2%3a1.1.3-1_armhf.deb ...
Unpacking libxinerama1:armhf (2:1.1.3-1) ...
Selecting previously unselected package libxrandr2:armhf.
Preparing to unpack .../libxrandr2_2%3a1.4.2-1_armhf.deb ...
Unpacking libxrandr2:armhf (2:1.4.2-1) ...
Selecting previously unselected package shared-mime-info.
Preparing to unpack .../shared-mime-info_1.0-1_armhf.deb ...
Unpacking shared-mime-info (1.0-1) ...
Selecting previously unselected package libgtk2.0-0:armhf.
Preparing to unpack .../libgtk2.0-0_2.24.22-1_armhf.deb ...
Unpacking libgtk2.0-0:armhf (2.24.22-1) ...
Selecting previously unselected package libharfbuzz-gobject0:armhf.
Preparing to unpack .../libharfbuzz-gobject0_0.9.26-4_armhf.deb ...
Unpacking libharfbuzz-gobject0:armhf (0.9.26-4) ...
Selecting previously unselected package libicu52:armhf.
Preparing to unpack .../libicu52_52.1-3_armhf.deb ...
Unpacking libicu52:armhf (52.1-3) ...
Selecting previously unselected package libharfbuzz-icu0:armhf.
Preparing to unpack .../libharfbuzz-icu0_0.9.26-4_armhf.deb ...
Unpacking libharfbuzz-icu0:armhf (0.9.26-4) ...
Selecting previously unselected package x11-common.
Preparing to unpack .../x11-common_1%3a7.7+6_all.deb ...
Unpacking x11-common (1:7.7+6) ...
Selecting previously unselected package libice6:armhf.
Preparing to unpack .../libice6_2%3a1.0.8-2_armhf.deb ...
Unpacking libice6:armhf (2:1.0.8-2) ...
Selecting previously unselected package libxft2:armhf.
Preparing to unpack .../libxft2_2.3.1-2_armhf.deb ...
Unpacking libxft2:armhf (2.3.1-2) ...
Selecting previously unselected package libpangoxft-1.0-0:armhf.
Preparing to unpack .../libpangoxft-1.0-0_1.36.0-1+b1_armhf.deb ...
Unpacking libpangoxft-1.0-0:armhf (1.36.0-1+b1) ...
Selecting previously unselected package libpcrecpp0:armhf.
Preparing to unpack .../libpcrecpp0_1%3a8.31-2_armhf.deb ...
Unpacking libpcrecpp0:armhf (1:8.31-2) ...
Selecting previously unselected package libsigsegv2:armhf.
Preparing to unpack .../libsigsegv2_2.10-2_armhf.deb ...
Unpacking libsigsegv2:armhf (2.10-2) ...
Selecting previously unselected package libsm6:armhf.
Preparing to unpack .../libsm6_2%3a1.2.1-2_armhf.deb ...
Unpacking libsm6:armhf (2:1.2.1-2) ...
Selecting previously unselected package libunistring0:armhf.
Preparing to unpack .../libunistring0_0.9.3-5_armhf.deb ...
Unpacking libunistring0:armhf (0.9.3-5) ...
Selecting previously unselected package netbase.
Preparing to unpack .../archives/netbase_5.2_all.deb ...
Unpacking netbase (5.2) ...
Selecting previously unselected package file.
Preparing to unpack .../file_1%3a5.17-0.1_armhf.deb ...
Unpacking file (1:5.17-0.1) ...
Selecting previously unselected package gettext-base.
Preparing to unpack .../gettext-base_0.18.3.2-1_armhf.deb ...
Unpacking gettext-base (0.18.3.2-1) ...
Selecting previously unselected package mime-support.
Preparing to unpack .../mime-support_3.54_all.deb ...
Unpacking mime-support (3.54) ...
Selecting previously unselected package libpython2.7-stdlib:armhf.
Preparing to unpack .../libpython2.7-stdlib_2.7.6-5_armhf.deb ...
Unpacking libpython2.7-stdlib:armhf (2.7.6-5) ...
Selecting previously unselected package m4.
Preparing to unpack .../archives/m4_1.4.17-2_armhf.deb ...
Unpacking m4 (1.4.17-2) ...
Selecting previously unselected package python2.7.
Preparing to unpack .../python2.7_2.7.6-5_armhf.deb ...
Unpacking python2.7 (2.7.6-5) ...
Selecting previously unselected package python-minimal.
Preparing to unpack .../python-minimal_2.7.5-5_armhf.deb ...
Unpacking python-minimal (2.7.5-5) ...
Selecting previously unselected package libpython-stdlib:armhf.
Preparing to unpack .../libpython-stdlib_2.7.5-5_armhf.deb ...
Unpacking libpython-stdlib:armhf (2.7.5-5) ...
Selecting previously unselected package python.
Preparing to unpack .../python_2.7.5-5_armhf.deb ...
Unpacking python (2.7.5-5) ...
Selecting previously unselected package autoconf.
Preparing to unpack .../autoconf_2.69-4_all.deb ...
Unpacking autoconf (2.69-4) ...
Selecting previously unselected package autotools-dev.
Preparing to unpack .../autotools-dev_20130810.1_all.deb ...
Unpacking autotools-dev (20130810.1) ...
Selecting previously unselected package automake.
Preparing to unpack .../automake_1%3a1.14.1-2_all.deb ...
Unpacking automake (1:1.14.1-2) ...
Selecting previously unselected package autopoint.
Preparing to unpack .../autopoint_0.18.3.2-1_all.deb ...
Unpacking autopoint (0.18.3.2-1) ...
Selecting previously unselected package openssl.
Preparing to unpack .../openssl_1.0.1f-1_armhf.deb ...
Unpacking openssl (1.0.1f-1) ...
Selecting previously unselected package ca-certificates.
Preparing to unpack .../ca-certificates_20130906_all.deb ...
Unpacking ca-certificates (20130906) ...
Selecting previously unselected package gettext.
Preparing to unpack .../gettext_0.18.3.2-1_armhf.deb ...
Unpacking gettext (0.18.3.2-1) ...
Selecting previously unselected package intltool-debian.
Preparing to unpack .../intltool-debian_0.35.0+20060710.1_all.deb ...
Unpacking intltool-debian (0.35.0+20060710.1) ...
Selecting previously unselected package po-debconf.
Preparing to unpack .../po-debconf_1.0.16+nmu2_all.deb ...
Unpacking po-debconf (1.0.16+nmu2) ...
Selecting previously unselected package debhelper.
Preparing to unpack .../debhelper_9.20131227_all.deb ...
Unpacking debhelper (9.20131227) ...
Selecting previously unselected package libtool.
Preparing to unpack .../libtool_2.4.2-1.7_armhf.deb ...
Unpacking libtool (2.4.2-1.7) ...
Selecting previously unselected package dh-autoreconf.
Preparing to unpack .../dh-autoreconf_9_all.deb ...
Unpacking dh-autoreconf (9) ...
Selecting previously unselected package libgirepository-1.0-1.
Preparing to unpack .../libgirepository-1.0-1_1.36.0-2_armhf.deb ...
Unpacking libgirepository-1.0-1 (1.36.0-2) ...
Selecting previously unselected package gir1.2-glib-2.0.
Preparing to unpack .../gir1.2-glib-2.0_1.36.0-2_armhf.deb ...
Unpacking gir1.2-glib-2.0 (1.36.0-2) ...
Selecting previously unselected package gir1.2-atk-1.0.
Preparing to unpack .../gir1.2-atk-1.0_2.10.0-2_armhf.deb ...
Unpacking gir1.2-atk-1.0 (2.10.0-2) ...
Selecting previously unselected package gir1.2-freedesktop.
Preparing to unpack .../gir1.2-freedesktop_1.36.0-2_armhf.deb ...
Unpacking gir1.2-freedesktop (1.36.0-2) ...
Selecting previously unselected package gir1.2-gdkpixbuf-2.0.
Preparing to unpack .../gir1.2-gdkpixbuf-2.0_2.28.2-1_armhf.deb ...
Unpacking gir1.2-gdkpixbuf-2.0 (2.28.2-1) ...
Selecting previously unselected package gir1.2-pango-1.0.
Preparing to unpack .../gir1.2-pango-1.0_1.36.0-1+b1_armhf.deb ...
Unpacking gir1.2-pango-1.0 (1.36.0-1+b1) ...
Selecting previously unselected package gir1.2-gtk-2.0.
Preparing to unpack .../gir1.2-gtk-2.0_2.24.22-1_armhf.deb ...
Unpacking gir1.2-gtk-2.0 (2.24.22-1) ...
Selecting previously unselected package liburi-perl.
Preparing to unpack .../liburi-perl_1.60-1_all.deb ...
Unpacking liburi-perl (1.60-1) ...
Selecting previously unselected package libencode-locale-perl.
Preparing to unpack .../libencode-locale-perl_1.03-1_all.deb ...
Unpacking libencode-locale-perl (1.03-1) ...
Selecting previously unselected package libhttp-date-perl.
Preparing to unpack .../libhttp-date-perl_6.02-1_all.deb ...
Unpacking libhttp-date-perl (6.02-1) ...
Selecting previously unselected package libfile-listing-perl.
Preparing to unpack .../libfile-listing-perl_6.04-1_all.deb ...
Unpacking libfile-listing-perl (6.04-1) ...
Selecting previously unselected package libhtml-tagset-perl.
Preparing to unpack .../libhtml-tagset-perl_3.20-2_all.deb ...
Unpacking libhtml-tagset-perl (3.20-2) ...
Selecting previously unselected package libhtml-parser-perl.
Preparing to unpack .../libhtml-parser-perl_3.71-1+b2_armhf.deb ...
Unpacking libhtml-parser-perl (3.71-1+b2) ...
Selecting previously unselected package libhtml-tree-perl.
Preparing to unpack .../libhtml-tree-perl_5.03-1_all.deb ...
Unpacking libhtml-tree-perl (5.03-1) ...
Selecting previously unselected package libio-html-perl.
Preparing to unpack .../libio-html-perl_1.00-1_all.deb ...
Unpacking libio-html-perl (1.00-1) ...
Selecting previously unselected package liblwp-mediatypes-perl.
Preparing to unpack .../liblwp-mediatypes-perl_6.02-1_all.deb ...
Unpacking liblwp-mediatypes-perl (6.02-1) ...
Selecting previously unselected package libhttp-message-perl.
Preparing to unpack .../libhttp-message-perl_6.06-1_all.deb ...
Unpacking libhttp-message-perl (6.06-1) ...
Selecting previously unselected package libhttp-cookies-perl.
Preparing to unpack .../libhttp-cookies-perl_6.00-2_all.deb ...
Unpacking libhttp-cookies-perl (6.00-2) ...
Selecting previously unselected package libhttp-negotiate-perl.
Preparing to unpack .../libhttp-negotiate-perl_6.00-2_all.deb ...
Unpacking libhttp-negotiate-perl (6.00-2) ...
Selecting previously unselected package libnet-ssleay-perl.
Preparing to unpack .../libnet-ssleay-perl_1.58-1_armhf.deb ...
Unpacking libnet-ssleay-perl (1.58-1) ...
Selecting previously unselected package libio-socket-ssl-perl.
Preparing to unpack .../libio-socket-ssl-perl_1.967-1_all.deb ...
Unpacking libio-socket-ssl-perl (1.967-1) ...
Selecting previously unselected package libnet-http-perl.
Preparing to unpack .../libnet-http-perl_6.06-1_all.deb ...
Unpacking libnet-http-perl (6.06-1) ...
Selecting previously unselected package liblwp-protocol-https-perl.
Preparing to unpack .../liblwp-protocol-https-perl_6.04-2_all.deb ...
Unpacking liblwp-protocol-https-perl (6.04-2) ...
Selecting previously unselected package libwww-robotrules-perl.
Preparing to unpack .../libwww-robotrules-perl_6.01-1_all.deb ...
Unpacking libwww-robotrules-perl (6.01-1) ...
Selecting previously unselected package libwww-perl.
Preparing to unpack .../libwww-perl_6.05-2_all.deb ...
Unpacking libwww-perl (6.05-2) ...
Selecting previously unselected package libxml-parser-perl.
Preparing to unpack .../libxml-parser-perl_2.41-1+b1_armhf.deb ...
Unpacking libxml-parser-perl (2.41-1+b1) ...
Selecting previously unselected package intltool.
Preparing to unpack .../intltool_0.50.2-2_all.deb ...
Unpacking intltool (0.50.2-2) ...
Selecting previously unselected package pkg-config.
Preparing to unpack .../pkg-config_0.26-1_armhf.deb ...
Unpacking pkg-config (0.26-1) ...
Selecting previously unselected package libglib2.0-data.
Preparing to unpack .../libglib2.0-data_2.36.4-1_all.deb ...
Unpacking libglib2.0-data (2.36.4-1) ...
Selecting previously unselected package libglib2.0-bin.
Preparing to unpack .../libglib2.0-bin_2.36.4-1_armhf.deb ...
Unpacking libglib2.0-bin (2.36.4-1) ...
Selecting previously unselected package libpcre3-dev:armhf.
Preparing to unpack .../libpcre3-dev_1%3a8.31-2_armhf.deb ...
Unpacking libpcre3-dev:armhf (1:8.31-2) ...
Selecting previously unselected package zlib1g-dev:armhf.
Preparing to unpack .../zlib1g-dev_1%3a1.2.8.dfsg-1_armhf.deb ...
Unpacking zlib1g-dev:armhf (1:1.2.8.dfsg-1) ...
Selecting previously unselected package libglib2.0-dev.
Preparing to unpack .../libglib2.0-dev_2.36.4-1_armhf.deb ...
Unpacking libglib2.0-dev (2.36.4-1) ...
Selecting previously unselected package libatk1.0-dev.
Preparing to unpack .../libatk1.0-dev_2.10.0-2_armhf.deb ...
Unpacking libatk1.0-dev (2.10.0-2) ...
Selecting previously unselected package libexpat1-dev:armhf.
Preparing to unpack .../libexpat1-dev_2.1.0-4_armhf.deb ...
Unpacking libexpat1-dev:armhf (2.1.0-4) ...
Selecting previously unselected package libpng12-dev.
Preparing to unpack .../libpng12-dev_1.2.50-1_armhf.deb ...
Unpacking libpng12-dev (1.2.50-1) ...
Selecting previously unselected package libfreetype6-dev.
Preparing to unpack .../libfreetype6-dev_2.5.2-1_armhf.deb ...
Unpacking libfreetype6-dev (2.5.2-1) ...
Selecting previously unselected package libfontconfig1-dev:armhf.
Preparing to unpack .../libfontconfig1-dev_2.11.0-2_armhf.deb ...
Unpacking libfontconfig1-dev:armhf (2.11.0-2) ...
Selecting previously unselected package xorg-sgml-doctools.
Preparing to unpack .../xorg-sgml-doctools_1%3a1.11-1_all.deb ...
Unpacking xorg-sgml-doctools (1:1.11-1) ...
Selecting previously unselected package x11proto-core-dev.
Preparing to unpack .../x11proto-core-dev_7.0.24-1_all.deb ...
Unpacking x11proto-core-dev (7.0.24-1) ...
Selecting previously unselected package libxau-dev:armhf.
Preparing to unpack .../libxau-dev_1%3a1.0.8-1_armhf.deb ...
Unpacking libxau-dev:armhf (1:1.0.8-1) ...
Selecting previously unselected package libxdmcp-dev:armhf.
Preparing to unpack .../libxdmcp-dev_1%3a1.1.1-1_armhf.deb ...
Unpacking libxdmcp-dev:armhf (1:1.1.1-1) ...
Selecting previously unselected package x11proto-input-dev.
Preparing to unpack .../x11proto-input-dev_2.3-1_all.deb ...
Unpacking x11proto-input-dev (2.3-1) ...
Selecting previously unselected package x11proto-kb-dev.
Preparing to unpack .../x11proto-kb-dev_1.0.6-2_all.deb ...
Unpacking x11proto-kb-dev (1.0.6-2) ...
Selecting previously unselected package xtrans-dev.
Preparing to unpack .../xtrans-dev_1.3.2-1_all.deb ...
Unpacking xtrans-dev (1.3.2-1) ...
Selecting previously unselected package libpthread-stubs0-dev:armhf.
Preparing to unpack .../libpthread-stubs0-dev_0.3-4_armhf.deb ...
Unpacking libpthread-stubs0-dev:armhf (0.3-4) ...
Selecting previously unselected package libxcb1-dev:armhf.
Preparing to unpack .../libxcb1-dev_1.10-2_armhf.deb ...
Unpacking libxcb1-dev:armhf (1.10-2) ...
Selecting previously unselected package libx11-dev:armhf.
Preparing to unpack .../libx11-dev_2%3a1.6.2-1_armhf.deb ...
Unpacking libx11-dev:armhf (2:1.6.2-1) ...
Selecting previously unselected package x11proto-render-dev.
Preparing to unpack .../x11proto-render-dev_2%3a0.11.1-2_all.deb ...
Unpacking x11proto-render-dev (2:0.11.1-2) ...
Selecting previously unselected package libxrender-dev:armhf.
Preparing to unpack .../libxrender-dev_1%3a0.9.8-1_armhf.deb ...
Unpacking libxrender-dev:armhf (1:0.9.8-1) ...
Selecting previously unselected package x11proto-xext-dev.
Preparing to unpack .../x11proto-xext-dev_7.3.0-1_all.deb ...
Unpacking x11proto-xext-dev (7.3.0-1) ...
Selecting previously unselected package libxext-dev:armhf.
Preparing to unpack .../libxext-dev_2%3a1.3.2-1_armhf.deb ...
Unpacking libxext-dev:armhf (2:1.3.2-1) ...
Selecting previously unselected package libice-dev:armhf.
Preparing to unpack .../libice-dev_2%3a1.0.8-2_armhf.deb ...
Unpacking libice-dev:armhf (2:1.0.8-2) ...
Selecting previously unselected package libsm-dev:armhf.
Preparing to unpack .../libsm-dev_2%3a1.2.1-2_armhf.deb ...
Unpacking libsm-dev:armhf (2:1.2.1-2) ...
Selecting previously unselected package libpixman-1-dev.
Preparing to unpack .../libpixman-1-dev_0.32.4-1_armhf.deb ...
Unpacking libpixman-1-dev (0.32.4-1) ...
Selecting previously unselected package libxcb-render0-dev:armhf.
Preparing to unpack .../libxcb-render0-dev_1.10-2_armhf.deb ...
Unpacking libxcb-render0-dev:armhf (1.10-2) ...
Selecting previously unselected package libxcb-shm0-dev:armhf.
Preparing to unpack .../libxcb-shm0-dev_1.10-2_armhf.deb ...
Unpacking libxcb-shm0-dev:armhf (1.10-2) ...
Selecting previously unselected package libdrm-dev:armhf.
Preparing to unpack .../libdrm-dev_2.4.52-1_armhf.deb ...
Unpacking libdrm-dev:armhf (2.4.52-1) ...
Selecting previously unselected package mesa-common-dev.
Preparing to unpack .../mesa-common-dev_9.2.2-1_armhf.deb ...
Unpacking mesa-common-dev (9.2.2-1) ...
Selecting previously unselected package libx11-xcb-dev.
Preparing to unpack .../libx11-xcb-dev_2%3a1.6.2-1_armhf.deb ...
Unpacking libx11-xcb-dev (2:1.6.2-1) ...
Selecting previously unselected package libxcb-dri2-0-dev:armhf.
Preparing to unpack .../libxcb-dri2-0-dev_1.10-2_armhf.deb ...
Unpacking libxcb-dri2-0-dev:armhf (1.10-2) ...
Selecting previously unselected package libxcb-glx0-dev:armhf.
Preparing to unpack .../libxcb-glx0-dev_1.10-2_armhf.deb ...
Unpacking libxcb-glx0-dev:armhf (1.10-2) ...
Selecting previously unselected package x11proto-fixes-dev.
Preparing to unpack .../x11proto-fixes-dev_1%3a5.0-2_all.deb ...
Unpacking x11proto-fixes-dev (1:5.0-2) ...
Selecting previously unselected package libxfixes-dev.
Preparing to unpack .../libxfixes-dev_1%3a5.0.1-1_armhf.deb ...
Unpacking libxfixes-dev (1:5.0.1-1) ...
Selecting previously unselected package x11proto-damage-dev.
Preparing to unpack .../x11proto-damage-dev_1%3a1.2.1-2_all.deb ...
Unpacking x11proto-damage-dev (1:1.2.1-2) ...
Selecting previously unselected package libxdamage-dev.
Preparing to unpack .../libxdamage-dev_1%3a1.1.4-1_armhf.deb ...
Unpacking libxdamage-dev (1:1.1.4-1) ...
Selecting previously unselected package x11proto-xf86vidmode-dev.
Preparing to unpack .../x11proto-xf86vidmode-dev_2.3.1-2_all.deb ...
Unpacking x11proto-xf86vidmode-dev (2.3.1-2) ...
Selecting previously unselected package libxxf86vm-dev:armhf.
Preparing to unpack .../libxxf86vm-dev_1%3a1.1.3-1_armhf.deb ...
Unpacking libxxf86vm-dev:armhf (1:1.1.3-1) ...
Selecting previously unselected package x11proto-dri2-dev.
Preparing to unpack .../x11proto-dri2-dev_2.8-2_all.deb ...
Unpacking x11proto-dri2-dev (2.8-2) ...
Selecting previously unselected package x11proto-gl-dev.
Preparing to unpack .../x11proto-gl-dev_1.4.17-1_all.deb ...
Unpacking x11proto-gl-dev (1.4.17-1) ...
Selecting previously unselected package libgl1-mesa-dev.
Preparing to unpack .../libgl1-mesa-dev_9.2.2-1_armhf.deb ...
Unpacking libgl1-mesa-dev (9.2.2-1) ...
Selecting previously unselected package libcairo2-dev.
Preparing to unpack .../libcairo2-dev_1.12.16-2+rpi1_armhf.deb ...
Unpacking libcairo2-dev (1.12.16-2+rpi1) ...
Selecting previously unselected package libexiv2-12.
Preparing to unpack .../libexiv2-12_0.23-1_armhf.deb ...
Unpacking libexiv2-12 (0.23-1) ...
Selecting previously unselected package libexiv2-dev.
Preparing to unpack .../libexiv2-dev_0.23-1_armhf.deb ...
Unpacking libexiv2-dev (0.23-1) ...
Selecting previously unselected package libgdk-pixbuf2.0-dev.
Preparing to unpack .../libgdk-pixbuf2.0-dev_2.28.2-1_armhf.deb ...
Unpacking libgdk-pixbuf2.0-dev (2.28.2-1) ...
Selecting previously unselected package libxft-dev.
Preparing to unpack .../libxft-dev_2.3.1-2_armhf.deb ...
Unpacking libxft-dev (2.3.1-2) ...
Selecting previously unselected package libharfbuzz-dev.
Preparing to unpack .../libharfbuzz-dev_0.9.26-4_armhf.deb ...
Unpacking libharfbuzz-dev (0.9.26-4) ...
Selecting previously unselected package libpango1.0-dev.
Preparing to unpack .../libpango1.0-dev_1.36.0-1+b1_armhf.deb ...
Unpacking libpango1.0-dev (1.36.0-1+b1) ...
Selecting previously unselected package x11proto-xinerama-dev.
Preparing to unpack .../x11proto-xinerama-dev_1.2.1-2_all.deb ...
Unpacking x11proto-xinerama-dev (1.2.1-2) ...
Selecting previously unselected package libxinerama-dev:armhf.
Preparing to unpack .../libxinerama-dev_2%3a1.1.3-1_armhf.deb ...
Unpacking libxinerama-dev:armhf (2:1.1.3-1) ...
Selecting previously unselected package libxi-dev.
Preparing to unpack .../libxi-dev_2%3a1.7.2-1_armhf.deb ...
Unpacking libxi-dev (2:1.7.2-1) ...
Selecting previously unselected package x11proto-randr-dev.
Preparing to unpack .../x11proto-randr-dev_1.4.0-2_all.deb ...
Unpacking x11proto-randr-dev (1.4.0-2) ...
Selecting previously unselected package libxrandr-dev:armhf.
Preparing to unpack .../libxrandr-dev_2%3a1.4.2-1_armhf.deb ...
Unpacking libxrandr-dev:armhf (2:1.4.2-1) ...
Selecting previously unselected package libxcursor-dev:armhf.
Preparing to unpack .../libxcursor-dev_1%3a1.1.14-1_armhf.deb ...
Unpacking libxcursor-dev:armhf (1:1.1.14-1) ...
Selecting previously unselected package x11proto-composite-dev.
Preparing to unpack .../x11proto-composite-dev_1%3a0.4.2-2_all.deb ...
Unpacking x11proto-composite-dev (1:0.4.2-2) ...
Selecting previously unselected package libxcomposite-dev.
Preparing to unpack .../libxcomposite-dev_1%3a0.4.4-1_armhf.deb ...
Unpacking libxcomposite-dev (1:0.4.4-1) ...
Selecting previously unselected package libxml2-utils.
Preparing to unpack .../libxml2-utils_2.9.1+dfsg1-3_armhf.deb ...
Unpacking libxml2-utils (2.9.1+dfsg1-3) ...
Selecting previously unselected package libgtk2.0-dev.
Preparing to unpack .../libgtk2.0-dev_2.24.22-1_armhf.deb ...
Unpacking libgtk2.0-dev (2.24.22-1) ...
Setting up libpipeline1:armhf (1.2.6-2) ...
Setting up libpopt0:armhf (1.16-8) ...
Setting up libssl1.0.0:armhf (1.0.1f-1) ...
Setting up groff-base (1.22.2-5) ...
Setting up bsdmainutils (9.0.5) ...
update-alternatives: using /usr/bin/bsd-write to provide /usr/bin/write (write) in auto mode
update-alternatives: using /usr/bin/bsd-from to provide /usr/bin/from (from) in auto mode
Setting up man-db (2.6.6-1) ...
Building database of manual pages ...
Setting up libasprintf0c2:armhf (0.18.3.2-1) ...
Setting up libgpg-error0:armhf (1.12-0.2) ...
Setting up libgcrypt11:armhf (1.5.3-3) ...
Setting up libffi6:armhf (3.0.13-12) ...
Setting up libp11-kit0:armhf (0.20.2-1) ...
Setting up libtasn1-6:armhf (3.4-3) ...
Setting up libgnutls26:armhf (2.12.23-12) ...
Setting up libkeyutils1:armhf (1.5.6-1) ...
Setting up libkrb5support0:armhf (1.12+dfsg-2) ...
Setting up libk5crypto3:armhf (1.12+dfsg-2) ...
Setting up libkrb5-3:armhf (1.12+dfsg-2) ...
Setting up libgssapi-krb5-2:armhf (1.12+dfsg-2) ...
Setting up libmagic1:armhf (1:5.17-0.1) ...
Setting up libxml2:armhf (2.9.1+dfsg1-3) ...
Setting up libpython2.7-minimal:armhf (2.7.6-5) ...
Setting up python2.7-minimal (2.7.6-5) ...
Setting up libglib2.0-0:armhf (2.36.4-1) ...
No schema files found: doing nothing.
Setting up libatk1.0-data (2.10.0-2) ...
Setting up libatk1.0-0:armhf (2.10.0-2) ...
Setting up libavahi-common-data:armhf (0.6.31-4) ...
Setting up libavahi-common3:armhf (0.6.31-4) ...
Setting up libavahi-client3:armhf (0.6.31-4) ...
Setting up libexpat1:armhf (2.1.0-4) ...
Setting up libpng12-0:armhf (1.2.50-1) ...
Setting up libfreetype6:armhf (2.5.2-1) ...
Setting up ucf (3.0027+nmu1) ...
Setting up fonts-dejavu-core (2.34-1) ...
Setting up fontconfig-config (2.11.0-2) ...
Setting up libfontconfig1:armhf (2.11.0-2) ...
Setting up libdrm2:armhf (2.4.52-1) ...
Setting up libglapi-mesa:armhf (9.2.2-1) ...
Setting up libxau6:armhf (1:1.0.8-1) ...
Setting up libxdmcp6:armhf (1:1.1.1-1) ...
Setting up libxcb1:armhf (1.10-2) ...
Setting up libx11-data (2:1.6.2-1) ...
Setting up libx11-6:armhf (2:1.6.2-1) ...
Setting up libx11-xcb1:armhf (2:1.6.2-1) ...
Setting up libxcb-dri2-0:armhf (1.10-2) ...
Setting up libxcb-glx0:armhf (1.10-2) ...
Setting up libxfixes3:armhf (1:5.0.1-1) ...
Setting up libxdamage1:armhf (1:1.1.4-1) ...
Setting up libxext6:armhf (2:1.3.2-1) ...
Setting up libxxf86vm1:armhf (1:1.1.3-1) ...
Setting up libgl1-mesa-glx:armhf (9.2.2-1) ...
Setting up libpixman-1-0:armhf (0.32.4-1) ...
Setting up libxcb-render0:armhf (1.10-2) ...
Setting up libxcb-shm0:armhf (1.10-2) ...
Setting up libxrender1:armhf (1:0.9.8-1) ...
Setting up libcairo2:armhf (1.12.16-2+rpi1) ...
Setting up libcairo-gobject2:armhf (1.12.16-2+rpi1) ...
Setting up liblzo2-2:armhf (2.06-1.2) ...
Setting up libcairo-script-interpreter2:armhf (1.12.16-2+rpi1) ...
Setting up libcroco3:armhf (0.6.8-2) ...
Setting up libcups2:armhf (1.7.1-4) ...
Setting up libdatrie1:armhf (0.2.8-1) ...
Setting up libdrm-nouveau2:armhf (2.4.52-1) ...
Setting up libdrm-omap1:armhf (2.4.52-1) ...
Setting up libdrm-radeon1:armhf (2.4.52-1) ...
Setting up libelfg0:armhf (0.8.13-5) ...
Setting up libjpeg8:armhf (8d-2) ...
Setting up libjasper1:armhf (1.900.1-14) ...
Setting up libjbig0:armhf (2.0-2) ...
Setting up libtiff4:armhf (3.9.7-3) ...
Setting up libgdk-pixbuf2.0-common (2.28.2-1) ...
Setting up libgdk-pixbuf2.0-0:armhf (2.28.2-1) ...
Setting up libgraphite2-3:armhf (1.2.4-1) ...
Setting up libgtk2.0-common (2.24.22-1) ...
Setting up libthai-data (0.1.20-3) ...
Setting up libthai0:armhf (0.1.20-3) ...
Setting up fontconfig (2.11.0-2) ...
Regenerating fonts cache... done.
Setting up libpango-1.0-0:armhf (1.36.0-1+b1) ...
Setting up libharfbuzz0b:armhf (0.9.26-4) ...
Setting up libpangoft2-1.0-0:armhf (1.36.0-1+b1) ...
Setting up libpangocairo-1.0-0:armhf (1.36.0-1+b1) ...
Setting up libxcomposite1:armhf (1:0.4.4-1) ...
Setting up libxcursor1:armhf (1:1.1.14-1) ...
Setting up libxi6:armhf (2:1.7.2-1) ...
Setting up libxinerama1:armhf (2:1.1.3-1) ...
Setting up libxrandr2:armhf (2:1.4.2-1) ...
Setting up shared-mime-info (1.0-1) ...
Setting up libgtk2.0-0:armhf (2.24.22-1) ...
Setting up libharfbuzz-gobject0:armhf (0.9.26-4) ...
Setting up libicu52:armhf (52.1-3) ...
Setting up libharfbuzz-icu0:armhf (0.9.26-4) ...
Setting up x11-common (1:7.7+6) ...
update-rc.d: warning: start and stop actions are no longer supported; falling back to defaults
[ ok ] Setting up X socket directories... /tmp/.X11-unix /tmp/.ICE-unix.
Setting up libice6:armhf (2:1.0.8-2) ...
Setting up libxft2:armhf (2.3.1-2) ...
Setting up libpangoxft-1.0-0:armhf (1.36.0-1+b1) ...
Setting up libpcrecpp0:armhf (1:8.31-2) ...
Setting up libsigsegv2:armhf (2.10-2) ...
Setting up libsm6:armhf (2:1.2.1-2) ...
Setting up libunistring0:armhf (0.9.3-5) ...
Setting up netbase (5.2) ...
Setting up file (1:5.17-0.1) ...
Setting up gettext-base (0.18.3.2-1) ...
Setting up mime-support (3.54) ...
update-alternatives: using /usr/bin/see to provide /usr/bin/view (view) in auto mode
Setting up libpython2.7-stdlib:armhf (2.7.6-5) ...
Setting up m4 (1.4.17-2) ...
Setting up python2.7 (2.7.6-5) ...
Setting up python-minimal (2.7.5-5) ...
Setting up libpython-stdlib:armhf (2.7.5-5) ...
Setting up python (2.7.5-5) ...
Setting up autoconf (2.69-4) ...
Setting up autotools-dev (20130810.1) ...
Setting up automake (1:1.14.1-2) ...
update-alternatives: using /usr/bin/automake-1.14 to provide /usr/bin/automake (automake) in auto mode
Setting up autopoint (0.18.3.2-1) ...
Setting up openssl (1.0.1f-1) ...
Setting up ca-certificates (20130906) ...
Setting up gettext (0.18.3.2-1) ...
Setting up intltool-debian (0.35.0+20060710.1) ...
Setting up po-debconf (1.0.16+nmu2) ...
Setting up debhelper (9.20131227) ...
Setting up libtool (2.4.2-1.7) ...
Setting up dh-autoreconf (9) ...
Setting up libgirepository-1.0-1 (1.36.0-2) ...
Setting up gir1.2-glib-2.0 (1.36.0-2) ...
Setting up gir1.2-atk-1.0 (2.10.0-2) ...
Setting up gir1.2-freedesktop (1.36.0-2) ...
Setting up gir1.2-gdkpixbuf-2.0 (2.28.2-1) ...
Setting up gir1.2-pango-1.0 (1.36.0-1+b1) ...
Setting up gir1.2-gtk-2.0 (2.24.22-1) ...
Setting up liburi-perl (1.60-1) ...
Setting up libencode-locale-perl (1.03-1) ...
Setting up libhttp-date-perl (6.02-1) ...
Setting up libfile-listing-perl (6.04-1) ...
Setting up libhtml-tagset-perl (3.20-2) ...
Setting up libhtml-parser-perl (3.71-1+b2) ...
Setting up libhtml-tree-perl (5.03-1) ...
Setting up libio-html-perl (1.00-1) ...
Setting up liblwp-mediatypes-perl (6.02-1) ...
Setting up libhttp-message-perl (6.06-1) ...
Setting up libhttp-cookies-perl (6.00-2) ...
Setting up libhttp-negotiate-perl (6.00-2) ...
Setting up libnet-ssleay-perl (1.58-1) ...
Setting up libio-socket-ssl-perl (1.967-1) ...
Setting up libnet-http-perl (6.06-1) ...
Setting up libwww-robotrules-perl (6.01-1) ...
Setting up pkg-config (0.26-1) ...
Setting up libglib2.0-data (2.36.4-1) ...
Setting up libglib2.0-bin (2.36.4-1) ...
Setting up libpcre3-dev:armhf (1:8.31-2) ...
Setting up zlib1g-dev:armhf (1:1.2.8.dfsg-1) ...
Setting up libglib2.0-dev (2.36.4-1) ...
Setting up libatk1.0-dev (2.10.0-2) ...
Setting up libexpat1-dev:armhf (2.1.0-4) ...
Setting up libpng12-dev (1.2.50-1) ...
Setting up libfreetype6-dev (2.5.2-1) ...
Setting up libfontconfig1-dev:armhf (2.11.0-2) ...
Setting up xorg-sgml-doctools (1:1.11-1) ...
Setting up x11proto-core-dev (7.0.24-1) ...
Setting up libxau-dev:armhf (1:1.0.8-1) ...
Setting up libxdmcp-dev:armhf (1:1.1.1-1) ...
Setting up x11proto-input-dev (2.3-1) ...
Setting up x11proto-kb-dev (1.0.6-2) ...
Setting up xtrans-dev (1.3.2-1) ...
Setting up libpthread-stubs0-dev:armhf (0.3-4) ...
Setting up libxcb1-dev:armhf (1.10-2) ...
Setting up libx11-dev:armhf (2:1.6.2-1) ...
Setting up x11proto-render-dev (2:0.11.1-2) ...
Setting up libxrender-dev:armhf (1:0.9.8-1) ...
Setting up x11proto-xext-dev (7.3.0-1) ...
Setting up libxext-dev:armhf (2:1.3.2-1) ...
Setting up libice-dev:armhf (2:1.0.8-2) ...
Setting up libsm-dev:armhf (2:1.2.1-2) ...
Setting up libpixman-1-dev (0.32.4-1) ...
Setting up libxcb-render0-dev:armhf (1.10-2) ...
Setting up libxcb-shm0-dev:armhf (1.10-2) ...
Setting up libdrm-dev:armhf (2.4.52-1) ...
Setting up mesa-common-dev (9.2.2-1) ...
Setting up libx11-xcb-dev (2:1.6.2-1) ...
Setting up libxcb-dri2-0-dev:armhf (1.10-2) ...
Setting up libxcb-glx0-dev:armhf (1.10-2) ...
Setting up x11proto-fixes-dev (1:5.0-2) ...
Setting up libxfixes-dev (1:5.0.1-1) ...
Setting up x11proto-damage-dev (1:1.2.1-2) ...
Setting up libxdamage-dev (1:1.1.4-1) ...
Setting up x11proto-xf86vidmode-dev (2.3.1-2) ...
Setting up libxxf86vm-dev:armhf (1:1.1.3-1) ...
Setting up x11proto-dri2-dev (2.8-2) ...
Setting up x11proto-gl-dev (1.4.17-1) ...
Setting up libgl1-mesa-dev (9.2.2-1) ...
Setting up libcairo2-dev (1.12.16-2+rpi1) ...
Setting up libexiv2-12 (0.23-1) ...
Setting up libexiv2-dev (0.23-1) ...
Setting up libgdk-pixbuf2.0-dev (2.28.2-1) ...
Setting up libxft-dev (2.3.1-2) ...
Setting up libharfbuzz-dev (0.9.26-4) ...
Setting up libpango1.0-dev (1.36.0-1+b1) ...
Setting up x11proto-xinerama-dev (1.2.1-2) ...
Setting up libxinerama-dev:armhf (2:1.1.3-1) ...
Setting up libxi-dev (2:1.7.2-1) ...
Setting up x11proto-randr-dev (1.4.0-2) ...
Setting up libxrandr-dev:armhf (2:1.4.2-1) ...
Setting up libxcursor-dev:armhf (1:1.1.14-1) ...
Setting up x11proto-composite-dev (1:0.4.2-2) ...
Setting up libxcomposite-dev (1:0.4.4-1) ...
Setting up libxml2-utils (2.9.1+dfsg1-3) ...
Setting up libgtk2.0-dev (2.24.22-1) ...
Setting up liblwp-protocol-https-perl (6.04-2) ...
Setting up libwww-perl (6.05-2) ...
Setting up libxml-parser-perl (2.41-1+b1) ...
Setting up intltool (0.50.2-2) ...
Processing triggers for libc-bin (2.17-97) ...
Processing triggers for ca-certificates (20130906) ...
Updating certificates in /etc/ssl/certs... 164 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d....done.

Current status: 0 broken [-1].
 -> Finished parsing the build-deps
Reading package lists...
Building dependency tree...
Reading state information...
The following NEW packages will be installed:
  fakeroot
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 0 B/104 kB of archives.
After this operation, 308 kB of additional disk space will be used.
debconf: delaying package configuration, since apt-utils is not installed
Selecting previously unselected package fakeroot.
(Reading database ... 19681 files and directories currently installed.)
Preparing to unpack .../fakeroot_1.18.4-2_armhf.deb ...
Unpacking fakeroot (1.18.4-2) ...
Processing triggers for man-db (2.6.6-1) ...
Setting up fakeroot (1.18.4-2) ...
update-alternatives: using /usr/bin/fakeroot-sysv to provide /usr/bin/fakeroot (fakeroot) in auto mode
I: Copying back the cached apt archive contents
I: new cache content file_1%3a5.17-0.1_armhf.deb added
I: new cache content libio-socket-ssl-perl_1.967-1_all.deb added
I: new cache content x11-common_1%3a7.7+6_all.deb added
I: new cache content libtool_2.4.2-1.7_armhf.deb added
I: new cache content libmagic1_1%3a5.17-0.1_armhf.deb added
I: new cache content libexiv2-12_0.23-1_armhf.deb added
I: new cache content libgnutls26_2.12.23-12_armhf.deb added
I: new cache content dh-autoreconf_9_all.deb added
I: new cache content libexiv2-dev_0.23-1_armhf.deb added
I: new cache content autoconf_2.69-4_all.deb added
I: Copying source file
I: copying [viewnior_1.4-1.dsc]
I: copying [./viewnior_1.4.orig.tar.gz]
I: copying [./viewnior_1.4-1.debian.tar.xz]
I: Extracting source
gpgv: keyblock resource `/tmp/buildd/.gnupg/trustedkeys.gpg': file open error
gpgv: Signature made Fri Feb 14 21:30:03 2014 UTC using RSA key ID 9A0C52FA
gpgv: Can't check signature: public key not found
dpkg-source: warning: failed to verify signature on ./viewnior_1.4-1.dsc
dpkg-source: info: extracting viewnior in viewnior-1.4
dpkg-source: info: unpacking viewnior_1.4.orig.tar.gz
dpkg-source: info: unpacking viewnior_1.4-1.debian.tar.xz
I: Building the package
I: Running cd tmp/buildd/*/ && env PATH="/usr/sbin:/usr/bin:/sbin:/bin" dpkg-buildpackage -us -uc  -rfakeroot
dpkg-buildpackage: source package viewnior
dpkg-buildpackage: source version 1.4-1
dpkg-buildpackage: source distribution unstable
dpkg-buildpackage: source changed by Dariusz Dwornikowski 
dpkg-buildpackage: host architecture armhf
 dpkg-source --before-build viewnior-1.4
 fakeroot debian/rules clean
dh clean  --with autoreconf
   dh_testdir
   dh_auto_clean
   dh_autoreconf_clean
   dh_clean
 dpkg-source -b viewnior-1.4
dpkg-source: info: using source format `3.0 (quilt)'
dpkg-source: info: building viewnior using existing ./viewnior_1.4.orig.tar.gz
dpkg-source: info: building viewnior in viewnior_1.4-1.debian.tar.xz
dpkg-source: info: building viewnior in viewnior_1.4-1.dsc
 debian/rules build
dh build  --with autoreconf
   dh_testdir
   dh_autoreconf
   dh_testdir
   dh_auto_clean
   dh_autoreconf_clean
   dh_clean
 dpkg-source -b viewnior-1.4
dpkg-source: info: using source format `3.0 (quilt)'
dpkg-source: info: building viewnior using existing ./viewnior_1.4.orig.tar.gz
dpkg-source: info: building viewnior in viewnior_1.4-1.debian.tar.xz
dpkg-source: info: building viewnior in viewnior_1.4-1.dsc
 debian/rules build
dh build  --with autoreconf
   dh_testdir
   dh_autoreconf
libtoolize: putting auxiliary files in `.'.
libtoolize: copying file `./ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIR, `m4'.
libtoolize: copying file `m4/libtool.m4'
libtoolize: copying file `m4/ltoptions.m4'
libtoolize: copying file `m4/ltsugar.m4'
libtoolize: copying file `m4/ltversion.m4'
libtoolize: copying file `m4/lt~obsolete.m4'
libtoolize: Consider adding `-I m4' to ACLOCAL_AMFLAGS in Makefile.am.
   dh_auto_configure
configure: WARNING: unrecognized options: --disable-maintainer-mode
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... no
checking for mawk... mawk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
checking whether make supports nested variables... (cached) yes
checking build system type... arm-unknown-linux-gnueabihf
checking host system type... arm-unknown-linux-gnueabihf
checking how to print strings... printf
checking for style of include used by make... GNU
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables... 
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking whether gcc understands -c and -o together... yes
checking dependency style of gcc... none
checking for a sed that does not truncate output... /bin/sed
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for fgrep... /bin/grep -F
checking for ld used by gcc... /usr/bin/ld
checking if the linker (/usr/bin/ld) is GNU ld... yes
checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
checking the name lister (/usr/bin/nm -B) interface... BSD nm
checking whether ln -s works... yes
checking the maximum length of command line arguments... 805306365
checking whether the shell understands some XSI constructs... yes
checking whether the shell understands "+="... yes
checking how to convert arm-unknown-linux-gnueabihf file names to arm-unknown-linux-gnueabihf format... func_convert_file_noop
checking how to convert arm-unknown-linux-gnueabihf file names to toolchain format... func_convert_file_noop
checking for /usr/bin/ld option to reload object files... -r
checking for objdump... objdump
checking how to recognize dependent libraries... pass_all
checking for dlltool... no
checking how to associate runtime and link libraries... printf %s\n
checking for ar... ar
checking for archiver @FILE support... @
checking for strip... strip
checking for ranlib... ranlib
checking command to parse /usr/bin/nm -B output from gcc object... ok
checking for sysroot... no
checking for mt... mt
checking if mt is a manifest tool... no
checking how to run the C preprocessor... gcc -E
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/stat.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for memory.h... yes
checking for strings.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking for dlfcn.h... yes
checking for objdir... .libs
checking if gcc supports -fno-rtti -fno-exceptions... no
checking for gcc option to produce PIC... -fPIC -DPIC
checking if gcc PIC flag -fPIC -DPIC works... yes
checking if gcc static flag -static works... yes
checking if gcc supports -c -o file.o... yes
checking if gcc supports -c -o file.o... (cached) yes
checking whether the gcc linker (/usr/bin/ld) supports shared libraries... yes
checking whether -lc should be explicitly linked in... no
checking dynamic linker characteristics... GNU/Linux ld.so
checking how to hardcode library paths into programs... immediate
checking whether stripping libraries is possible... yes
checking if libtool supports shared libraries... yes
checking whether to build shared libraries... yes
checking whether to build static libraries... yes
checking for library containing strerror... none required
checking for gcc... (cached) gcc
checking whether we are using the GNU C compiler... (cached) yes
checking whether gcc accepts -g... (cached) yes
checking for gcc option to accept ISO C89... (cached) none needed
checking whether gcc understands -c and -o together... (cached) yes
checking dependency style of gcc... (cached) none
checking for gcc... (cached) gcc
checking whether we are using the GNU C compiler... (cached) yes
checking whether gcc accepts -g... (cached) yes
checking for gcc option to accept ISO C89... (cached) none needed
checking whether gcc understands -c and -o together... (cached) yes
checking dependency style of gcc... (cached) none
checking for ANSI C header files... (cached) yes
checking for g++... g++
checking whether we are using the GNU C++ compiler... yes
checking whether g++ accepts -g... yes
checking dependency style of g++... none
checking how to run the C++ preprocessor... g++ -E
checking for ld used by g++... /usr/bin/ld
checking if the linker (/usr/bin/ld) is GNU ld... yes
checking whether the g++ linker (/usr/bin/ld) supports shared libraries... yes
checking for g++ option to produce PIC... -fPIC -DPIC
checking if g++ PIC flag -fPIC -DPIC works... yes
checking if g++ static flag -static works... yes
checking if g++ supports -c -o file.o... yes
checking if g++ supports -c -o file.o... (cached) yes
checking whether the g++ linker (/usr/bin/ld) supports shared libraries... yes
checking dynamic linker characteristics... (cached) GNU/Linux ld.so
checking how to hardcode library paths into programs... immediate
checking whether NLS is requested... yes
checking for intltool >= 0.35.0... 0.50.2 found
checking for intltool-update... /usr/bin/intltool-update
checking for intltool-merge... /usr/bin/intltool-merge
checking for intltool-extract... /usr/bin/intltool-extract
checking for xgettext... /usr/bin/xgettext
checking for msgmerge... /usr/bin/msgmerge
checking for msgfmt... /usr/bin/msgfmt
checking for gmsgfmt... /usr/bin/msgfmt
checking for perl... /usr/bin/perl
checking for perl >= 5.8.1... 5.18.2
checking for XML::Parser... ok
checking locale.h usability... yes
checking locale.h presence... yes
checking for locale.h... yes
checking for LC_MESSAGES... yes
checking libintl.h usability... yes
checking libintl.h presence... yes
checking for libintl.h... yes
checking for ngettext in libc... yes
checking for dgettext in libc... yes
checking for bind_textdomain_codeset... yes
checking for msgfmt... (cached) /usr/bin/msgfmt
checking for dcgettext... yes
checking if msgfmt accepts -c... yes
checking for gmsgfmt... (cached) /usr/bin/msgfmt
checking for xgettext... (cached) /usr/bin/xgettext
checking for glib-genmarshal... /usr/bin/glib-genmarshal
checking for pkg-config... /usr/bin/pkg-config
checking pkg-config is at least version 0.9.0... yes
checking for VNR... yes
checking that generated files are newer than configure... done
configure: creating ./config.status
config.status: creating Makefile
config.status: creating src/Makefile
config.status: creating data/Makefile
config.status: creating data/viewnior.desktop.in
config.status: creating data/icons/Makefile
config.status: creating data/icons/16x16/Makefile
config.status: creating data/icons/16x16/apps/Makefile
config.status: creating data/icons/22x22/Makefile
config.status: creating data/icons/22x22/apps/Makefile
config.status: creating data/icons/24x24/Makefile
config.status: creating data/icons/24x24/apps/Makefile
config.status: creating data/icons/32x32/Makefile
config.status: creating data/icons/32x32/apps/Makefile
config.status: creating data/icons/48x48/Makefile
config.status: creating data/icons/48x48/apps/Makefile
config.status: creating data/icons/scalable/Makefile
config.status: creating data/icons/scalable/apps/Makefile
config.status: creating po/Makefile.in
config.status: creating man/Makefile
config.status: creating config.h
config.status: executing depfiles commands
config.status: executing libtool commands
config.status: executing default-1 commands
config.status: executing po/stamp-it commands
configure: WARNING: unrecognized options: --disable-maintainer-mode

    Viewnior ........... : Version 1.4
    Location ........... : /usr/bin
    CFLAGS ............. : -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security


    To compile and install:
    1. Become root (using su)
    2. Type 'make install'

   debian/rules override_dh_auto_build
make[1]: Entering directory `/tmp/buildd/viewnior-1.4'
dh_auto_build -- LDFLAGS="-Wl,-z,relro -lm"
make[2]: Entering directory `/tmp/buildd/viewnior-1.4'
make  all-recursive
make[3]: Entering directory `/tmp/buildd/viewnior-1.4'
Making all in src
make[4]: Entering directory `/tmp/buildd/viewnior-1.4/src'
make  all-am
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/src'
  CC       viewnior-main.o
  CC       viewnior-vnr-window.o
  CC       viewnior-uni-cache.o
  CC       viewnior-uni-anim-view.o
  CC       viewnior-uni-nav.o
  CC       viewnior-uni-scroll-win.o
  CC       viewnior-uni-dragger.o
  CC       viewnior-uni-image-view.o
  CC       viewnior-vnr-message-area.o
  CC       viewnior-vnr-properties-dialog.o
  CC       viewnior-vnr-file.o
  CC       viewnior-uni-utils.o
  CC       viewnior-vnr-prefs.o
  CC       viewnior-vnr-crop.o
  CC       viewnior-vnr-tools.o
  CXX      viewnior-uni-exiv2.o
In file included from /usr/include/exiv2/metadatum.hpp:39:0,
                 from /usr/include/exiv2/exif.hpp:34,
                 from /usr/include/exiv2/bmpimage.hpp:34,
                 from /usr/include/exiv2/exiv2.hpp:35,
                 from uni-exiv2.cpp:23:
/usr/include/exiv2/value.hpp:984:25: note: attribute for 'struct Exiv2::DateValue::Date' must follow the 'struct' keyword
         EXIV2API struct Date
                         ^
  CC       viewnior-uni-marshal.o
  CXXLD    viewnior
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/src'
make[4]: Leaving directory `/tmp/buildd/viewnior-1.4/src'
Making all in data
make[4]: Entering directory `/tmp/buildd/viewnior-1.4/data'
Making all in icons
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons'
Making all in 16x16
make[6]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/16x16'
Making all in apps
make[7]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/16x16/apps'
make[7]: Nothing to be done for `all'.
make[7]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/16x16/apps'
make[7]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/16x16'
make[7]: Nothing to be done for `all-am'.
make[7]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/16x16'
make[6]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/16x16'
Making all in 22x22
make[6]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/22x22'
Making all in apps
make[7]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/22x22/apps'
make[7]: Nothing to be done for `all'.
make[7]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/22x22/apps'
make[7]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/22x22'
make[7]: Nothing to be done for `all-am'.
make[7]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/22x22'
make[6]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/22x22'
Making all in 24x24
make[6]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/24x24'
Making all in apps
make[7]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/24x24/apps'
make[7]: Nothing to be done for `all'.
make[7]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/24x24/apps'
make[7]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/24x24'
make[7]: Nothing to be done for `all-am'.
make[7]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/24x24'
make[6]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/24x24'
Making all in 32x32
make[6]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/32x32'
Making all in apps
make[7]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/32x32/apps'
make[7]: Nothing to be done for `all'.
make[7]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/32x32/apps'
make[7]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/32x32'
make[7]: Nothing to be done for `all-am'.
make[7]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/32x32'
make[6]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/32x32'
Making all in 48x48
make[6]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/48x48'
Making all in apps
make[7]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/48x48/apps'
make[7]: Nothing to be done for `all'.
make[7]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/48x48/apps'
make[7]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/48x48'
make[7]: Nothing to be done for `all-am'.
make[7]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/48x48'
make[6]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/48x48'
Making all in scalable
make[6]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/scalable'
Making all in apps
make[7]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/scalable/apps'
make[7]: Nothing to be done for `all'.
make[7]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/scalable/apps'
make[7]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/scalable'
make[7]: Nothing to be done for `all-am'.
make[7]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/scalable'
make[6]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/scalable'
make[6]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons'
make[6]: Nothing to be done for `all-am'.
make[6]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons'
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons'
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data'
  ITMRG  viewnior.desktop
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data'
make[4]: Leaving directory `/tmp/buildd/viewnior-1.4/data'
Making all in po
make[4]: Entering directory `/tmp/buildd/viewnior-1.4/po'
  MSGFMT ar.gmo
  MSGFMT bg.gmo
  MSGFMT cs.gmo
  MSGFMT ca.gmo
  MSGFMT ca@valencia.gmo
  MSGFMT da.gmo
  MSGFMT de.gmo
  MSGFMT el.gmo
  MSGFMT es.gmo
  MSGFMT fi.gmo
  MSGFMT fr.gmo
  MSGFMT gl.gmo
  MSGFMT he.gmo
  MSGFMT hu.gmo
  MSGFMT it.gmo
  MSGFMT ja.gmo
  MSGFMT lt.gmo
  MSGFMT nl.gmo
  MSGFMT oc.gmo
  MSGFMT pl.gmo
  MSGFMT pt.gmo
  MSGFMT pt_BR.gmo
  MSGFMT ru.gmo
  MSGFMT sk.gmo
  MSGFMT sr.gmo
  MSGFMT sv.gmo
  MSGFMT tr.gmo
  MSGFMT uk.gmo
  MSGFMT zh_CN.gmo
make[4]: Leaving directory `/tmp/buildd/viewnior-1.4/po'
Making all in man
make[4]: Entering directory `/tmp/buildd/viewnior-1.4/man'
make[4]: Nothing to be done for `all'.
make[4]: Leaving directory `/tmp/buildd/viewnior-1.4/man'
make[4]: Entering directory `/tmp/buildd/viewnior-1.4'
make[4]: Leaving directory `/tmp/buildd/viewnior-1.4'
make[3]: Leaving directory `/tmp/buildd/viewnior-1.4'
make[2]: Leaving directory `/tmp/buildd/viewnior-1.4'
make[1]: Leaving directory `/tmp/buildd/viewnior-1.4'
   dh_auto_test
make[1]: Entering directory `/tmp/buildd/viewnior-1.4'
Making check in src
make[2]: Entering directory `/tmp/buildd/viewnior-1.4/src'
make  check-am
make[3]: Entering directory `/tmp/buildd/viewnior-1.4/src'
make[3]: Nothing to be done for `check-am'.
make[3]: Leaving directory `/tmp/buildd/viewnior-1.4/src'
make[2]: Leaving directory `/tmp/buildd/viewnior-1.4/src'
Making check in data
make[2]: Entering directory `/tmp/buildd/viewnior-1.4/data'
Making check in icons
make[3]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons'
Making check in 16x16
make[4]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/16x16'
Making check in apps
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/16x16/apps'
make[5]: Nothing to be done for `check'.
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/16x16/apps'
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/16x16'
make[5]: Nothing to be done for `check-am'.
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/16x16'
make[4]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/16x16'
Making check in 22x22
make[4]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/22x22'
Making check in apps
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/22x22/apps'
make[5]: Nothing to be done for `check'.
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/22x22/apps'
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/22x22'
make[5]: Nothing to be done for `check-am'.
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/22x22'
make[4]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/22x22'
Making check in 24x24
make[4]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/24x24'
Making check in apps
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/24x24/apps'
make[5]: Nothing to be done for `check'.
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/24x24/apps'
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/24x24'
make[5]: Nothing to be done for `check-am'.
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/24x24'
make[4]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/24x24'
Making check in 32x32
make[4]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/32x32'
Making check in apps
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/32x32/apps'
make[5]: Nothing to be done for `check'.
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/32x32/apps'
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/32x32'
make[5]: Nothing to be done for `check-am'.
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/32x32'
make[4]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/32x32'
Making check in 48x48
make[4]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/48x48'
Making check in apps
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/48x48/apps'
make[5]: Nothing to be done for `check'.
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/48x48/apps'
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/48x48'
make[5]: Nothing to be done for `check-am'.
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/48x48'
make[4]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/48x48'
Making check in scalable
make[4]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/scalable'
Making check in apps
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/scalable/apps'
make[5]: Nothing to be done for `check'.
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/scalable/apps'
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/scalable'
make[5]: Nothing to be done for `check-am'.
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/scalable'
make[4]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/scalable'
make[4]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons'
make[4]: Nothing to be done for `check-am'.
make[4]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons'
make[3]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons'
make[3]: Entering directory `/tmp/buildd/viewnior-1.4/data'
make[3]: Nothing to be done for `check-am'.
make[3]: Leaving directory `/tmp/buildd/viewnior-1.4/data'
make[2]: Leaving directory `/tmp/buildd/viewnior-1.4/data'
Making check in po
make[2]: Entering directory `/tmp/buildd/viewnior-1.4/po'
INTLTOOL_EXTRACT="/usr/bin/intltool-extract" XGETTEXT="/usr/bin/xgettext" srcdir=. /usr/bin/intltool-update --gettext-package viewnior --pot
rm -f missing notexist
srcdir=. /usr/bin/intltool-update -m
if [ -r missing -o -r notexist ]; then \
      exit 1; \
    fi
make[2]: Leaving directory `/tmp/buildd/viewnior-1.4/po'
Making check in man
make[2]: Entering directory `/tmp/buildd/viewnior-1.4/man'
make[2]: Nothing to be done for `check'.
make[2]: Leaving directory `/tmp/buildd/viewnior-1.4/man'
make[2]: Entering directory `/tmp/buildd/viewnior-1.4'
make[2]: Leaving directory `/tmp/buildd/viewnior-1.4'
make[1]: Leaving directory `/tmp/buildd/viewnior-1.4'
 fakeroot debian/rules binary
dh binary  --with autoreconf
   dh_testroot
   dh_prep
   dh_auto_install
make[1]: Entering directory `/tmp/buildd/viewnior-1.4'
Making install in src
make[2]: Entering directory `/tmp/buildd/viewnior-1.4/src'
make  install-am
make[3]: Entering directory `/tmp/buildd/viewnior-1.4/src'
make[4]: Entering directory `/tmp/buildd/viewnior-1.4/src'
 /bin/mkdir -p '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/bin'
  /bin/bash ../libtool   --mode=install /usr/bin/install -c viewnior '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/bin'
libtool: install: /usr/bin/install -c viewnior /tmp/buildd/viewnior-1.4/debian/viewnior/usr/bin/viewnior
make[4]: Nothing to be done for `install-data-am'.
make[4]: Leaving directory `/tmp/buildd/viewnior-1.4/src'
make[3]: Leaving directory `/tmp/buildd/viewnior-1.4/src'
make[2]: Leaving directory `/tmp/buildd/viewnior-1.4/src'
Making install in data
make[2]: Entering directory `/tmp/buildd/viewnior-1.4/data'
Making install in icons
make[3]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons'
Making install in 16x16
make[4]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/16x16'
Making install in apps
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/16x16/apps'
make[6]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/16x16/apps'
make[6]: Nothing to be done for `install-exec-am'.
 /bin/mkdir -p '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/icons/hicolor/16x16/apps'
 /usr/bin/install -c -m 644 viewnior.png '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/icons/hicolor/16x16/apps'
make[6]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/16x16/apps'
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/16x16/apps'
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/16x16'
make[6]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/16x16'
make[6]: Nothing to be done for `install-exec-am'.
make[6]: Nothing to be done for `install-data-am'.
make[6]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/16x16'
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/16x16'
make[4]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/16x16'
Making install in 22x22
make[4]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/22x22'
Making install in apps
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/22x22/apps'
make[6]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/22x22/apps'
make[6]: Nothing to be done for `install-exec-am'.
 /bin/mkdir -p '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/icons/hicolor/22x22/apps'
 /usr/bin/install -c -m 644 viewnior.png '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/icons/hicolor/22x22/apps'
make[6]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/22x22/apps'
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/22x22/apps'
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/22x22'
make[6]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/22x22'
make[6]: Nothing to be done for `install-exec-am'.
make[6]: Nothing to be done for `install-data-am'.
make[6]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/22x22'
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/22x22'
make[4]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/22x22'
Making install in 24x24
make[4]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/24x24'
Making install in apps
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/24x24/apps'
make[6]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/24x24/apps'
make[6]: Nothing to be done for `install-exec-am'.
 /bin/mkdir -p '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/icons/hicolor/24x24/apps'
 /usr/bin/install -c -m 644 viewnior.png '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/icons/hicolor/24x24/apps'
make[6]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/24x24/apps'
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/24x24/apps'
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/24x24'
make[6]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/24x24'
make[6]: Nothing to be done for `install-exec-am'.
make[6]: Nothing to be done for `install-data-am'.
make[6]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/24x24'
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/24x24'
make[4]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/24x24'
Making install in 32x32
make[4]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/32x32'
Making install in apps
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/32x32/apps'
make[6]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/32x32/apps'
make[6]: Nothing to be done for `install-exec-am'.
 /bin/mkdir -p '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/icons/hicolor/32x32/apps'
 /usr/bin/install -c -m 644 viewnior.png '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/icons/hicolor/32x32/apps'
make[6]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/32x32/apps'
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/32x32/apps'
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/32x32'
make[6]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/32x32'
make[6]: Nothing to be done for `install-exec-am'.
make[6]: Nothing to be done for `install-data-am'.
make[6]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/32x32'
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/32x32'
make[4]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/32x32'
Making install in 48x48
make[4]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/48x48'
Making install in apps
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/48x48/apps'
make[6]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/48x48/apps'
make[6]: Nothing to be done for `install-exec-am'.
 /bin/mkdir -p '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/icons/hicolor/48x48/apps'
 /usr/bin/install -c -m 644 viewnior.png '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/icons/hicolor/48x48/apps'
make[6]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/48x48/apps'
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/48x48/apps'
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/48x48'
make[6]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/48x48'
make[6]: Nothing to be done for `install-exec-am'.
make[6]: Nothing to be done for `install-data-am'.
make[6]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/48x48'
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/48x48'
make[4]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/48x48'
Making install in scalable
make[4]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/scalable'
Making install in apps
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/scalable/apps'
make[6]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/scalable/apps'
make[6]: Nothing to be done for `install-exec-am'.
 /bin/mkdir -p '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/icons/hicolor/scalable/apps'
 /usr/bin/install -c -m 644 viewnior.svg '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/icons/hicolor/scalable/apps'
make  install-data-hook
make[7]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/scalable/apps'
*** Icon cache not updated.  After install, run this:
***   gtk-update-icon-cache -f -t /usr/share/icons/hicolor
make[7]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/scalable/apps'
make[6]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/scalable/apps'
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/scalable/apps'
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/scalable'
make[6]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons/scalable'
make[6]: Nothing to be done for `install-exec-am'.
make[6]: Nothing to be done for `install-data-am'.
make[6]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/scalable'
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/scalable'
make[4]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons/scalable'
make[4]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons'
make[5]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons'
make[5]: Nothing to be done for `install-exec-am'.
make  install-data-hook
make[6]: Entering directory `/tmp/buildd/viewnior-1.4/data/icons'
*** Icon cache not updated.  After (un)install, run this:
***   gtk-update-icon-cache -f -t /usr/share/icons/hicolor
make[6]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons'
make[5]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons'
make[4]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons'
make[3]: Leaving directory `/tmp/buildd/viewnior-1.4/data/icons'
make[3]: Entering directory `/tmp/buildd/viewnior-1.4/data'
make[4]: Entering directory `/tmp/buildd/viewnior-1.4/data'
make[4]: Nothing to be done for `install-exec-am'.
 /bin/mkdir -p '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/applications'
 /usr/bin/install -c -m 644 viewnior.desktop '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/applications'
 /bin/mkdir -p '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/viewnior'
 /usr/bin/install -c -m 644 vnr-preferences-dialog.ui vnr-crop-dialog.ui '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/viewnior'
 /bin/mkdir -p '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/viewnior/pixmaps'
 /usr/bin/install -c -m 644 pixmaps/object-rotate-right.png pixmaps/object-rotate-left.png pixmaps/object-flip-horizontal.png pixmaps/object-flip-vertical.png '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/viewnior/pixmaps'
make[4]: Leaving directory `/tmp/buildd/viewnior-1.4/data'
make[3]: Leaving directory `/tmp/buildd/viewnior-1.4/data'
make[2]: Leaving directory `/tmp/buildd/viewnior-1.4/data'
Making install in po
make[2]: Entering directory `/tmp/buildd/viewnior-1.4/po'
linguas="ar bg cs ca ca@valencia da de el es fi fr gl he hu it ja lt nl oc pl pt pt_BR ru sk sr sv tr uk zh_CN "; \
    for lang in $linguas; do \
      dir=/tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/$lang/LC_MESSAGES; \
      /bin/bash /tmp/buildd/viewnior-1.4/install-sh -d $dir; \
      if test -r $lang.gmo; then \
        /usr/bin/install -c -m 644 $lang.gmo $dir/viewnior.mo; \
        echo "installing $lang.gmo as $dir/viewnior.mo"; \
      else \
        /usr/bin/install -c -m 644 ./$lang.gmo $dir/viewnior.mo; \
        echo "installing ./$lang.gmo as" \
         "$dir/viewnior.mo"; \
      fi; \
      if test -r $lang.gmo.m; then \
        /usr/bin/install -c -m 644 $lang.gmo.m $dir/viewnior.mo.m; \
        echo "installing $lang.gmo.m as $dir/viewnior.mo.m"; \
      else \
        if test -r ./$lang.gmo.m ; then \
          /usr/bin/install -c -m 644 ./$lang.gmo.m \
        $dir/viewnior.mo.m; \
          echo "installing ./$lang.gmo.m as" \
           "$dir/viewnior.mo.m"; \
        else \
          true; \
        fi; \
      fi; \
    done
installing ar.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/ar/LC_MESSAGES/viewnior.mo
installing bg.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/bg/LC_MESSAGES/viewnior.mo
installing cs.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/cs/LC_MESSAGES/viewnior.mo
installing ca.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/ca/LC_MESSAGES/viewnior.mo
installing ca@valencia.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/ca@valencia/LC_MESSAGES/viewnior.mo
installing da.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/da/LC_MESSAGES/viewnior.mo
installing de.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/de/LC_MESSAGES/viewnior.mo
installing el.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/el/LC_MESSAGES/viewnior.mo
installing es.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/es/LC_MESSAGES/viewnior.mo
installing fi.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/fi/LC_MESSAGES/viewnior.mo
installing fr.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/fr/LC_MESSAGES/viewnior.mo
installing gl.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/gl/LC_MESSAGES/viewnior.mo
installing he.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/he/LC_MESSAGES/viewnior.mo
installing hu.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/hu/LC_MESSAGES/viewnior.mo
installing it.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/it/LC_MESSAGES/viewnior.mo
installing ja.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/ja/LC_MESSAGES/viewnior.mo
installing lt.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/lt/LC_MESSAGES/viewnior.mo
installing nl.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/nl/LC_MESSAGES/viewnior.mo
installing oc.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/oc/LC_MESSAGES/viewnior.mo
installing pl.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/pl/LC_MESSAGES/viewnior.mo
installing pt.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/pt/LC_MESSAGES/viewnior.mo
installing pt_BR.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/pt_BR/LC_MESSAGES/viewnior.mo
installing ru.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/ru/LC_MESSAGES/viewnior.mo
installing sk.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/sk/LC_MESSAGES/viewnior.mo
installing sr.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/sr/LC_MESSAGES/viewnior.mo
installing sv.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/sv/LC_MESSAGES/viewnior.mo
installing tr.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/tr/LC_MESSAGES/viewnior.mo
installing uk.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/uk/LC_MESSAGES/viewnior.mo
installing zh_CN.gmo as /tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/locale/zh_CN/LC_MESSAGES/viewnior.mo
make[2]: Leaving directory `/tmp/buildd/viewnior-1.4/po'
Making install in man
make[2]: Entering directory `/tmp/buildd/viewnior-1.4/man'
make[3]: Entering directory `/tmp/buildd/viewnior-1.4/man'
make[3]: Nothing to be done for `install-exec-am'.
 /bin/mkdir -p '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/man/man1'
 /usr/bin/install -c -m 644 viewnior.1 '/tmp/buildd/viewnior-1.4/debian/viewnior/usr/share/man/man1'
make[3]: Leaving directory `/tmp/buildd/viewnior-1.4/man'
make[2]: Leaving directory `/tmp/buildd/viewnior-1.4/man'
make[2]: Entering directory `/tmp/buildd/viewnior-1.4'
make[3]: Entering directory `/tmp/buildd/viewnior-1.4'
make[3]: Nothing to be done for `install-exec-am'.
make[3]: Nothing to be done for `install-data-am'.
make[3]: Leaving directory `/tmp/buildd/viewnior-1.4'
make[2]: Leaving directory `/tmp/buildd/viewnior-1.4'
make[1]: Leaving directory `/tmp/buildd/viewnior-1.4'
   dh_install
   dh_installdocs
   debian/rules override_dh_installchangelogs
make[1]: Entering directory `/tmp/buildd/viewnior-1.4'
dh_installchangelogs
cp ChangeLog-20090517 debian/viewnior/usr/share/doc/viewnior/changelog
gzip -9 debian/viewnior/usr/share/doc/viewnior/changelog
make[1]: Leaving directory `/tmp/buildd/viewnior-1.4'
   dh_installman
   dh_installmenu
   dh_icons
   dh_perl
   dh_link
   dh_compress
   dh_fixperms
   dh_strip
   dh_makeshlibs
   dh_shlibdeps
dpkg-shlibdeps: warning: package could avoid a useless dependency if debian/viewnior/usr/bin/viewnior was not linked against libatk-1.0.so.0 (it uses none of the library's symbols)
dpkg-shlibdeps: warning: package could avoid a useless dependency if debian/viewnior/usr/bin/viewnior was not linked against libfontconfig.so.1 (it uses none of the library's symbols)
dpkg-shlibdeps: warning: package could avoid a useless dependency if debian/viewnior/usr/bin/viewnior was not linked against libpangocairo-1.0.so.0 (it uses none of the library's symbols)
dpkg-shlibdeps: warning: package could avoid a useless dependency if debian/viewnior/usr/bin/viewnior was not linked against libpango-1.0.so.0 (it uses none of the library's symbols)
dpkg-shlibdeps: warning: package could avoid a useless dependency if debian/viewnior/usr/bin/viewnior was not linked against libpangoft2-1.0.so.0 (it uses none of the library's symbols)
dpkg-shlibdeps: warning: package could avoid a useless dependency if debian/viewnior/usr/bin/viewnior was not linked against libcairo.so.2 (it uses none of the library's symbols)
dpkg-shlibdeps: warning: package could avoid a useless dependency if debian/viewnior/usr/bin/viewnior was not linked against libfreetype.so.6 (it uses none of the library's symbols)
   dh_installdeb
   dh_gencontrol
dpkg-gencontrol: warning: File::FcntlLock not available; using flock which is not NFS-safe
   dh_md5sums
   dh_builddeb
dpkg-deb: building package `viewnior' in `../viewnior_1.4-1_armhf.deb'.
 dpkg-genchanges  >../viewnior_1.4-1_armhf.changes
dpkg-genchanges: including full source code in upload
 dpkg-source --after-build viewnior-1.4
dpkg-buildpackage: full upload (original source is included)
I: Copying back the cached apt archive contents
I: unmounting dev/pts filesystem
I: unmounting run/shm filesystem
I: unmounting proc filesystem
I: cleaning the build env 
I: removing directory /var/cache/pbuilder/build//6749 and its subdirectories
I: Current time: Sat Feb 22 18:32:38 CET 2014
I: pbuilder-time-stamp: 1393090358

Jeśli interesuje nas inna wersja systemu używamy flagi DIST np.:

sudo DIST=stable pbuilder --build viewnior_1.4-1.dsc 

Aktualizację środowiska przeprowadzamy za pomocą komendy:

sudo pbuilder --update --autocleanaptcache

--autocleanaptcache usuwa nam przestarzałe pakiety z pamięci cache programu apt

Po więcej szczegółów odsyłam do wiki Debiana oraz Ubuntu.

Masz jakieś spostrzeżenia, uwagi proszę o prywatną wiadomość lub e-mail.

Jak zaktualizować Linux Mint Debian 201403?

$
0
0

Linux Mint Debian Edition korzysta z własnych repozytoriów oparty o Debian w wersji testowej. Tworząc tzw. update packi, czyli kopię repozytoriów z danego dnia. Są one wydawane średnio raz na 3 miesiące. Jako osoba związana dość bardzo z projektem Debian uważam, że jest to straszny błąd, ponieważ gałąź testowa jak przystało na nazwę może zawierać bądź zawiera błędy. Zablokowanie powoduje, że odcinamy się od poprawek pakietów. Gdy tworzyliśmy system w pierwszej wersji miał on korzystać z głównych repozytoriów, lecz później historia potoczyła się inaczej.

Oczywiście można obejść tą sytuacje.

Aktualizacja systemu w oparciu o repozytoria Debian Testing:

Jeśli chcemy mieć system taki jakie było do niego założenia należy go zaktualizować do wersji testowej. Zaczynamy jak wyżej od edycji repozytorium. Podam pełny zapis jak ma wyglądać, będzie prościej:

  1. Edytujemy plik z wpisami repozytorium np. tak:

sudo nano /etc/apt/sources.list

zastępujemy takie lub podobne wpisy (mogą się różnić serwerami lustrzanymi):

deb http://packages.linuxmint.com/ debian import main upstream backport romeo deb http://mirror.rts-informatique.fr/linuxmint/debian/latest testing main contrib non-free deb http://mirror.rts-informatique.fr/linuxmint/debian/latest/security testing/updates main contrib non-free deb http://mirror.rts-informatique.fr/linuxmint/debian/latest/multimedia testing main non-free

na:

deb http://packages.linuxmint.com/ debian import main upstream backport romeo deb http://http.debian.net/debian/ testing main contrib non-free deb http://security.debian.org/ testing/updates main contrib non-free deb http://www.deb-multimedia.org/ testing main non-free deb http://repo.mate-desktop.org/debian jessie main

W przypadku nano zapisujemy plik kombinacją klawiszy Ctrl + o i wychodzi z programu Ctrl + x.

  1. Usuwamy preferencje dla repozytoriów: sudo rm /etc/apt/preferences
  2. Aktualizujemy listę repozytoriów: sudo apt-get update

  3. Wgrywamy nowe klucze publiczne i aktualizujemy ponownie listę: sudo apt-get --yes --quiet --allow-unauthenticated install mate-archive-keyring sudo apt-get update

  4. Przeprowadzamy pełną aktualizacje systemu: sudo apt-get dist-upgrade

i od tego momentu mamy system ciągły, z aktualizacjami codziennymi oraz błędami naprawianymi na bieżąco. Przy czym gdy korzystamy ze środowiska Mate wkrótce będzie ono dostępne w repozytorium Debiana, więc gdy będziemy mieli problem z aktualizacją niektórych elementów należy zastosować takie rozwiązanie: http://sparkylinux.org/mate-problem-fix/

Rozwiązanie problemu montowania napędów CD/DVD i USB w Debianie Jessie

$
0
0

Głównie problem dotyczy środowiska Xfce i menadżera plików Thunar, choć zdarza się również w innych konfiguracjach. Winnym jest pakiet udev, który w Debianie Jessie jest częścią pakietu systemd i z jego źródeł jest budowany. Ma on problem z poprawnym przypisaniem wartości dla Kernel Polling.

Zaczynamy od sprawdzenia wartości Kernel Polling:

cat /sys/module/block/parameters/events_dfl_poll_msecs

Gdy zostanie zwrócona wartość 0, wtedy możemy przejść to naprawienia. Jeśli występuje inna wartość to problem leży gdzie indziej.

Sprawdzamy czy opisywany sposób działa: echo 2000 > /sys/module/block/parameters/events_dfl_poll_msecs

Przykład:

Przed wykonaniem polecenia:

Po wykonaniu:

Jeśli wykonane polecenie pomogło przechodzimy dalej.

Problem można rozwiązać na dwa sposoby. Można je stosować wymiennie, ale nigdy razem!

Sposób 1

Dopisujemy wykonanie polecenia do skryptu startowego /etc/rc.local, polecenie musi być umieszczone przed linią exit

Edycja pliku: nano /etc/rc.local Dopisujemy: echo 2000 > /sys/module/block/parameters/events_dfl_poll_msecs

Sposób 2

Drugim sposobem i łatwiejszym jest dopisanie reguły dla aplikacji udev. echo 'ACTION=="add", ATTR{removable}=="1", ATTR{events_poll_msecs}=="-1", ATTR{events_poll_msecs}="2500"' > /etc/udev/rules.d/61-removable-storage-polling.rules

Wszelkie inne sugestie rozwiązania tego problemu można zgłaszać w tym temacie na forum.

Zastosowanie mechanizmu PAM przy korzystaniu z encfs

$
0
0

Wielu ludzi uważa, że szyfrowanie całego dysku jest zbędne i pozbawione większego sensu, no bo przecie "system nie zawiera żadnych wrażliwych danych, które by wymagały szyfrowania". Nie będę się tutaj spierał co do tego punktu widzenia, bo raczej wszyscy znają moje zdanie na temat "danych wymagających szyfrowania" i skupię się tu raczej na tym jak troszeczkę podratować niepełne szyfrowanie, które ludzie, nie wiedząc czemu, są bardziej skłonni stosować, niż cały ten full disk encryption.

  1. Szyfrowanie katalogu domowego

Zwykle ludzie próbują szyfrować pojedyncze foldery czy pliki, które są dla nich dość istotne. Takim folderem na pewno jest katalog /home/$USER ale wielu ludzi nie ma pojęcia jak się zabrać do jego zaszyfrowania, poza tym samo zaszyfrowanie to nie wszystko, trzeba go jeszcze otworzyć przy logowaniu się do systemu. Ponadto, potrzebne są również dodatkowe zabezpieczenia, które uchronią nas przed wyciekiem wrażliwych informacji.

Większość dystrybucji linuxowych ma opcję zaszyfrowania katalogu /home/$USER w instalatorze i z tego co zauważyłem, to ta opcja ma zastosowanie jedynie dla głównego użytkownika systemu -- tego tworzonego w instalatorze. Pozostali userzy już nie mają zaszyfrowanych swoich katalogów domowych . Jeśli posiadamy kilku użytkowników w systemie i chcemy dać każdemu z nich możliwość zaszyfrowania swojego folderu w katalogu /home/ , musimy nauczyć się jak to robić ręcznie i zrezygnować z dobrodziejstw oferowanych przez graficzne instalatory.

Na sam początek instalujemy potrzebne narzędzia:

aptitude install encfs libpam-encfs libpam-mount fuse

Ważne jest by załadować moduł fuse na starcie systemu oraz by dodać użytkownika do grupy fuse. Moduł dodajemy do pliku /etc/modules , a użytkownika przez:

adduser morfik fuse

Zmiany wejdą w życie po ponownym zalogowaniu się do systemu.

Przechodzimy teraz do edycji kilku plików konfiguracyjnych. Z racji tego, że kolejność linijek w tych plikach jest ważna, powklejam tutaj całe pliki, usuwając tylko komentarze, tak by można było się łatwiej zorientować co dodać do swoich plików konfiguracyjnych.

Plik /etc/security/pam_encfs.conf :

drop_permissions encfs_default fuse_default nonempty - /home/.encfs - -v allow_root

Plik /etc/security/pam_env.conf :

ICEAUTHORITY DEFAULT=/tmp/.ICEauthority_@{PAM_USER}

Plik /etc/fuse.conf :

user_allow_other

Plik /etc/pam.d/common-auth :

auth sufficient pam_encfs.so auth [success=1 default=ignore] pam_unix.so use_first_pass nullok_secure auth requisite pam_deny.so auth required pam_permit.so auth optional pam_mount.so

Robimy teraz backup katalogu /home/

mkdir /home.original/

cp -a /home/ /home.original/

Edytujemy także plik /etc/passwd zmieniając w nim katalog użytkownika:

morfik:x:1000:1000:Morfik,,,:/home.original/morfik:/bin/bash

I relogujemy się. W tej chwili ustawienia konta są czytane z nowej lokalizacji i możemy opróżnić stary katalog /home/ . Gdy jest on już pusty, tworzymy w nim kilka folderów:

mkdir -p /home/.encfs/morfik /home/morfik

chown morfik:morfik /home/.encfs/morfik/ /home/morfik/

Powyższe polecenia trzeba powtórzyć dla każdego użytkownika, który ma mieć zaszyfrowany swój katalog /home/ .

Następnie musimy nauczyć system co i jak ma szyfrować:

$ encfs -v /home/.encfs/morfik/ /home/morfik/ 16:23:46 (main.cpp:523) Root directory: /home/.encfs/morfik/ 16:23:46 (main.cpp:524) Fuse arguments: (daemon) (threaded) (keyCheck) encfs /home/morfik/ -s -o use_ino -o default_permissions Creating new encrypted volume. Please choose from one of the following options: enter "x" for expert configuration mode, enter "p" for pre-configured paranoia mode, anything else, or an empty line will select standard mode. ?> x

Manual configuration mode selected. The following cipher algorithms are available: 1. AES : 16 byte block cipher -- Supports key lengths of 128 to 256 bits -- Supports block sizes of 64 to 4096 bytes 2. Blowfish : 8 byte block cipher -- Supports key lengths of 128 to 256 bits -- Supports block sizes of 64 to 4096 bytes

Enter the number corresponding to your choice: 1

Selected algorithm "AES"

Please select a key size in bits. The cipher you have chosen supports sizes from 128 to 256 bits in increments of 64 bits. For example: 128, 192, 256 Selected key size: 256

Using key size of 256 bits

Select a block size in bytes. The cipher you have chosen supports sizes from 64 to 4096 bytes in increments of 16. Or just hit enter for the default (1024 bytes)

filesystem block size: 4096

Using filesystem block size of 4096 bytes

The following filename encoding algorithms are available: 1. Block : Block encoding, hides file name size somewhat 2. Null : No encryption of filenames 3. Stream : Stream encoding, keeps filenames as short as possible

Enter the number corresponding to your choice: 1

Selected algorithm "Block""

Enable filename initialization vector chaining? This makes filename encoding dependent on the complete path, rather then encoding each path element individually. The default here is Yes. Any response that does not begin with 'n' will mean Yes:

Enable per-file initialization vectors? This adds about 8 bytes per file to the storage requirements. It should not affect performance except possibly with applications which rely on block-aligned file io for performance. The default here is Yes. Any response that does not begin with 'n' will mean Yes:

Enable filename to IV header chaining? This makes file data encoding dependent on the complete file path. If a file is renamed, it will not decode sucessfully unless it was renamed by encfs with the proper key. If this option is enabled, then hard links will not be supported in the filesystem. The default here is No. Any response that does not begin with 'y' will mean No:

Enable block authentication code headers on every block in a file? This adds about 12 bytes per block to the storage requirements for a file, and significantly affects performance but it also means [almost] any modifications or errors within a block will be caught and will cause a read error. The default here is No. Any response that does not begin with 'y' will mean No:

Add random bytes to each block header? This adds a performance penalty, but ensures that blocks have different authentication codes. Note that you can have the same benefits by enabling per-file initialization vectors, which does not come with as great of performance penalty. Select a number of bytes, from 0 (no random bytes) to 8: 0

Enable file-hole pass-through? This avoids writing encrypted blocks when file holes are created. The default here is Yes. Any response that does not begin with 'n' will mean Yes:

16:28:41 (SSL_Cipher.cpp:370) allocated cipher ssl/aes, keySize 32, ivlength 16 16:28:41 (FileUtils.cpp:1123) Using cipher AES, key size 256, block size 4096

Configuration finished. The filesystem to be created has the following properties: 16:28:41 (Interface.cpp:165) checking if ssl/aes(3:0:2) implements ssl/aes(3:0:2) 16:28:41 (SSL_Cipher.cpp:370) allocated cipher ssl/aes, keySize 24, ivlength 16 Filesystem cipher: "ssl/aes", version 3:0:2 16:28:41 (Interface.cpp:165) checking if nameio/block(3:0:1) implements nameio/block(3:0:1) Filename encoding: "nameio/block", version 3:0:1 16:28:41 (Interface.cpp:165) checking if ssl/aes(3:0:2) implements ssl/aes(3:0:2) 16:28:41 (SSL_Cipher.cpp:370) allocated cipher ssl/aes, keySize 32, ivlength 16 Key Size: 256 bits Block Size: 4096 bytes Each file contains 8 byte header with unique IV data. Filenames encoded using IV chaining mode. File holes passed through to ciphertext.

Now you will need to enter a password for your filesystem. You will need to remember this password, as there is absolutely no recovery mechanism. However, the password can be changed later using encfsctl.

16:28:41 (openssl.cpp:48) Allocating 41 locks for OpenSSL 16:28:41 (FileUtils.cpp:1180) useStdin: 0 New Encfs Password: Verify Encfs Password: 16:28:53 (Interface.cpp:165) checking if ssl/aes(3:0:2) implements ssl/aes(3:0:2) 16:28:53 (SSL_Cipher.cpp:370) allocated cipher ssl/aes, keySize 32, ivlength 16 16:28:53 (Interface.cpp:165) checking if nameio/block(3:0:1) implements nameio/block(3:0:1)

Oczywiście można wybrać domyślne opcje. Jedyne co nas tutaj interesuje, to hasło -- musi ono pasować do tego, którego używamy do logowania się, w przeciwnym wypadku trzeba będzie podawać dwa hasła, a nam zależy na tym by odblokowanie katalogu domowego nie rzucała się za bardzo w oczy.

Sprawdzamy czy system zamontował zaszyfrowany katalog:

$ mount | grep encfs encfs on /home/morfik type fuse.encfs (rw,nosuid,nodev,relatime,user_id=1000,group_id=1000,default_permissions,allow_root)

Przenosimy/kopiujemy teraz zawartość uprzednio zrobionego backupu do odpowiednich katalogów. W moim przypadku to wygląda jak poniżej:

$ mv /home.original/morfik/* /home/morfik/ $ mv /home.original/morfik/.* /home/morfik/

Pamiętajmy również o zmianie katalogu domowego w /etc/passwd .

Po zakończeniu procesu kopiowania możemy zresetować maszynę. Jeśli chcemy sprawdzić czy faktycznie system montuje katalog użytkownika, możemy zalogować się na TTY. Powinna zostać wyrzucona informacja o montowaniu zasobu.

Jeśli z jakiegoś powodu chcielibyśmy odmontować katalog /home/$USER , robimy to w poniższy sposób:

$ fusermount -u /home/morfik

Przydatną rzeczą też jest umiejętność zmiany hasła do zaszyfrowanego katalogu. Trzeba tylko pamiętać by zmienić również hasło do konta:

$ passwd Changing password for morfik. (current) UNIX password: Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully

$ encfsctl passwd /home/.encfs/morfik/ Enter current Encfs password EncFS Password: Enter new Encfs password New Encfs Password: Verify Encfs Password: Volume Key successfully updated.

I została jeszcze ostatnia kwestia tycząca się zaszyfrowanego katalogu z wykorzystaniem encfs -- trzeba zadbać o plik .encfs6.xml , który w tym przypadku znajduje się w /home/.encfs/morfik/.encfs6.xml . Jeśli stracimy ten plik, nie uzyskamy już dostępu do danych. Dlatego trzeba go skopiować i trzymać gdzieś w ukryciu. 2. A co ze SWAP?

Samo zaszyfrowanie katalogu home to nie wszystko -- wrażliwe dane mogą być złapane przez SWAP i zapisane na dysku w formie niezaszyfrowanej. W przypadku gdy posiadamy SWAP z jakiegoś powodu, np korzystamy z hibernacji, trzeba go zaszyfrować. Tworzymy zatem partycję, np. w gparted i robimy kontener:

cryptsetup --cipher aes-xts-plain64 --key-size 512 --hash sha512 --iter-time 5000 --use-random --verify-passphrase --verbose luksFormat /dev/sda3

Otwieramy go i tworzymy przestrzeń wymiany:

cryptsetup luksOpen /dev/sda3 swap

Enter passphrase for /dev/sda3:

mkswap /dev/mapper/swap

mkswap: /dev/mapper/swap: warning: don't erase bootbits sectors on whole disk. Use -f to force. Setting up swapspace version 1, size = 1950716 KiB no label, UUID=22614608-5406-4562-8532-9e8203a7721d

Listujemy UUID dysków, w moim przypadku sprawa ma się tak:

lsblk -o name,mountpoint,uuid /dev/sda

NAME MOUNTPOINT UUID sda ├─sda1 /boot 62d13fcc-8b32-464c-b751-f124781c84b6 ├─sda2 / 9b13095c-cd1c-4787-a2ba-e2b7c9d5b1be ├─sda3 95f1f54d-a1d6-4e02-8ee6-7f79d7558ebd │ └─swap (dm-0) 22614608-5406-4562-8532-9e8203a7721d └─sda4 e05e671f-770b-4401-a28e-80f6356c959e

Trzeba teraz uzupełnić odpowiednie pliki:

Plik /etc/fstab :

UUID=22614608-5406-4562-8532-9e8203a7721d swap swap 0 0

Plik /etc/crypttab:

swap UUID=95f1f54d-a1d6-4e02-8ee6-7f79d7558ebd none luks

Plik /etc/initramfs-tools/conf.d/resume:

RESUME=UUID=22614608-5406-4562-8532-9e8203a7721d

W przypadku niektórych linuxów, takich jak linux mint, są jakieś dziwne problemy z UUID i zamiast UUID lepiej jest sprecyzować ścieżkę do urządzeń w katalogu /dev/ .

  1. A może by tak i dropboxa?

Skoro mowa już o automatycznym odszyfrowaniu i montowaniu zasobów to na myśl przychodzi mi dropbox. Kiedyś na forum użytkownik megabajt podał sposób na ogarnięcie dropboxa z wykorzystaniem encfs ale niezbyt mi tamten mechanizm przypadł do gustu. Pomyślałem sobie więc, a czemu by nie przerobić tamtego sposobu i dorobić mu otwierania podobnego do tego co w przypadku katalogu /home/$USER ?

Zatem do dzieła, tworzymy dwa katalogi i szyfrujemy jeden z nich:

$ mkdir -p /media/Server/Dropbox.encfs/Dropbox/encrypted /media/Server/Dropbox $ encfs -v /media/Server/Dropbox.encfs/Dropbox/encrypted /media/Server/Dropbox 14:04:58 (main.cpp:523) Root directory: /media/Server/Dropbox.encfs/Dropbox/encrypted/ 14:04:58 (main.cpp:524) Fuse arguments: (daemon) (threaded) (keyCheck) encfs /media/Server/Dropbox -s -o use_ino -o default_permissions Creating new encrypted volume. Please choose from one of the following options: enter "x" for expert configuration mode, enter "p" for pre-configured paranoia mode, anything else, or an empty line will select standard mode. ?> x

Manual configuration mode selected. The following cipher algorithms are available: 1. AES : 16 byte block cipher -- Supports key lengths of 128 to 256 bits -- Supports block sizes of 64 to 4096 bytes 2. Blowfish : 8 byte block cipher -- Supports key lengths of 128 to 256 bits -- Supports block sizes of 64 to 4096 bytes

Enter the number corresponding to your choice: 1

Selected algorithm "AES"

Please select a key size in bits. The cipher you have chosen supports sizes from 128 to 256 bits in increments of 64 bits. For example: 128, 192, 256 Selected key size: 256

Using key size of 256 bits

Select a block size in bytes. The cipher you have chosen supports sizes from 64 to 4096 bytes in increments of 16. Or just hit enter for the default (1024 bytes)

filesystem block size: 4096

Using filesystem block size of 4096 bytes

The following filename encoding algorithms are available: 1. Block : Block encoding, hides file name size somewhat 2. Null : No encryption of filenames 3. Stream : Stream encoding, keeps filenames as short as possible

Enter the number corresponding to your choice: 1

Selected algorithm "Block""

Enable filename initialization vector chaining? This makes filename encoding dependent on the complete path, rather then encoding each path element individually. The default here is Yes. Any response that does not begin with 'n' will mean Yes:

Enable per-file initialization vectors? This adds about 8 bytes per file to the storage requirements. It should not affect performance except possibly with applications which rely on block-aligned file io for performance. The default here is Yes. Any response that does not begin with 'n' will mean Yes:

Enable filename to IV header chaining? This makes file data encoding dependent on the complete file path. If a file is renamed, it will not decode sucessfully unless it was renamed by encfs with the proper key. If this option is enabled, then hard links will not be supported in the filesystem. The default here is No. Any response that does not begin with 'y' will mean No:

Enable block authentication code headers on every block in a file? This adds about 12 bytes per block to the storage requirements for a file, and significantly affects performance but it also means [almost] any modifications or errors within a block will be caught and will cause a read error. The default here is No. Any response that does not begin with 'y' will mean No:

Add random bytes to each block header? This adds a performance penalty, but ensures that blocks have different authentication codes. Note that you can have the same benefits by enabling per-file initialization vectors, which does not come with as great of performance penalty. Select a number of bytes, from 0 (no random bytes) to 8: 0

Enable file-hole pass-through? This avoids writing encrypted blocks when file holes are created. The default here is Yes. Any response that does not begin with 'n' will mean Yes:

14:05:21 (SSL_Cipher.cpp:370) allocated cipher ssl/aes, keySize 32, ivlength 16 14:05:21 (FileUtils.cpp:1123) Using cipher AES, key size 256, block size 4096

Configuration finished. The filesystem to be created has the following properties: 14:05:21 (Interface.cpp:165) checking if ssl/aes(3:0:2) implements ssl/aes(3:0:2) 14:05:21 (SSL_Cipher.cpp:370) allocated cipher ssl/aes, keySize 24, ivlength 16 Filesystem cipher: "ssl/aes", version 3:0:2 14:05:21 (Interface.cpp:165) checking if nameio/block(3:0:1) implements nameio/block(3:0:1) Filename encoding: "nameio/block", version 3:0:1 14:05:21 (Interface.cpp:165) checking if ssl/aes(3:0:2) implements ssl/aes(3:0:2) 14:05:21 (SSL_Cipher.cpp:370) allocated cipher ssl/aes, keySize 32, ivlength 16 Key Size: 256 bits Block Size: 4096 bytes Each file contains 8 byte header with unique IV data. Filenames encoded using IV chaining mode. File holes passed through to ciphertext.

Now you will need to enter a password for your filesystem. You will need to remember this password, as there is absolutely no recovery mechanism. However, the password can be changed later using encfsctl.

14:05:21 (openssl.cpp:48) Allocating 41 locks for OpenSSL 14:05:21 (FileUtils.cpp:1180) useStdin: 0 New Encfs Password: Verify Encfs Password: 14:05:38 (Interface.cpp:165) checking if ssl/aes(3:0:2) implements ssl/aes(3:0:2) 14:05:38 (SSL_Cipher.cpp:370) allocated cipher ssl/aes, keySize 32, ivlength 16 14:05:39 (Interface.cpp:165) checking if nameio/block(3:0:1) implements nameio/block(3:0:1)

Hasło musi być takie samo co w przypadku katalogu użytkownika. Czyli będziemy logować się i otwierać szyfrowany katalog /home/$USER oraz folder dropboxa używając tego samego hasła.

Problem jest jeden, nie da rady tego zrobić przez plik /etc/security/pam_encfs.conf . Wychodzi na to, że można tam sprecyzować tylko jedną regułkę per user , czyli jeśli już mamy jedną, kolejnej nie damy rady tam dopisać, a jeśli dopiszemy, to zostanie zwyczajnie zignorowana. Co zatem nam pozostaje? Na szczęście możemy sprecyzować tyle punktów montowania ile chcemy, tylko trzeba to zrobić w innym pliku -- /etc/security/pam_mount.conf.xml . Edytujemy go zatem i dodajemy coś na wzór poniższej linijki:

<!-- Volume definitions --> <volume user="morfik" fstype="fuse" path="encfs#/media/Server/Dropbox.encfs/Dropbox/encrypted" mountpoint="/media/Server/Dropbox" options="nonempty" />

Restartujemy pc i sprawdzamy czy oba katalogi zostały zamontowane po zalogowaniu się do systemu:

$ mount | grep encfs encfs on /home/morfik type fuse.encfs (rw,nosuid,nodev,relatime,user_id=1000,group_id=1000,default_permissions,allow_root) encfs on /media/Server/Dropbox type fuse.encfs (rw,nosuid,nodev,relatime,user_id=1000,group_id=1000,default_permissions)

  1. Kwestia katalogu /tmp/

Ostatnia kwestia, która mi przychodzi na myśl, jeśli już mowa o zabezpieczeniach, to katalog /tmp/ . Jak nie patrzeć on zostaje odszyfrowany, a tam przecie trafiają pliki użytkownika. Można go oczywiście zaszyfrować w podobny sposób co i przestrzeń wymiany. Tylko, że pozostanie kwestia montowania dwóch voluminów na starcie systemu przy pomocy jednego hasła. Można tutaj skorzystać z zaprojektowanych do tego celu skryptów i wpiąć oba voluminy na jedno hasło.

Generalnie cały proces tworzenia zaszyfrowanego kontenera pod katalog /tmp/ jest dokładnie taki sam jak w przypadku przestrzeni wymiany i nie będę go opisywał po raz drugi, jedynie co to zamiast mkswap, trzeba użyć mkfs z odpowiednim systemem plików (no i dodać odpowiedni wpis w fstabie). Potem trzeba edytować plik /etc/crypttab i dopisać w nim poniższe linijki:

swap UUID=95f1f54d-a1d6-4e02-8ee6-7f79d7558ebd haslo luks,keyscript=/lib/cryptsetup/scripts/decrypt_keyctl tmp UUID=dc7f4586-a33d-4707-98e9-8b55c559b0d2 haslo luks,keyscript=/lib/cryptsetup/scripts/decrypt_keyctl

W miejscu haslo nie podajemy hasła, tylko jakiś ciąg znaków, grunt by był jednakowy dla obu voluminów.

Jak widać, trochę śmieszne się wydaje nieszyfrowanie pozostałej części systemu ale powyższe ustawienia powinny zatrzymać wyciek wrażliwych informacji. Nie dają jednak żadnej gwarancji nienaruszalności plików systemowych...


Oswajanie się z UDEVem, czyli jak pisać reguły dla urządzeń

$
0
0

Zapuszczając się w coraz to i głębsze warstwy systemu podczas dążenia do zbadania jak on tak naprawdę działa, zacząłem się stykać z regułami udeva -- tymi, które zwykle się umieszcza w katalogu /etc/udev/rules.d/ . Jako, że nazbierało mi się już ich kilka, zaistniała potrzeba zbadania tego co ten katalog zawiera. Na dobrą sprawę nigdy się nad tym nie zastanawiałem, jedynie kopiowałem rozwiązanie ze stronki i wklejałem do odpowiedniego pliku i jeśli takie rozwiązanie działało, to odznaczałem problem jako rozwiązany.

Zwykle takich reguł się nie potrzebuje, temu praktycznie niewielu ludzi w ogóle się orientuje jak ogarnąć tego całego udeva. Są przypadki kiedy przepisanie nazw urządzeń czy wykonanie określonych akcji po podłączeniu jakiegoś urządzenia do komputera jest wielce niezbędne i nie ma innej opcji jak tylko zrozumieć co udev tak naprawdę robi.

Za królika doświadczalnego będzie robił mój pendrak weteran, który posiada 3 partycje, z których jedna jest zaszyfrowana. Spróbujemy przy pomocy udeva wejść w interakcję z tym pendrivem, oraz wykonać pod jego adresem szereg akcji pisząc kilka regułek dla tego konkretnego urządzenia.

Pliki reguł

Na samym początku przyjrzyjmy się nieco katalogowi /etc/udev/rules.d/ -- zawiera on pliki zaczynające się od numerka od 00 do 99 . Na końcu każdego pliku musi być także .rules . Przykładowy plik wygląda zatem tak: 70-persistent-net.rules . Pliki są wczytywane jeden po drugim, te z niższymi numerkami jako pierwsze.

Same regułki wyglądają mniej więcej tak:

SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?", ATTR{address}=="00:e0:4c:75:03:09", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="eth", NAME="eth0"

Reguły również są parsowane jedna po drugiej (od góry do dołu w pliku) i jeśli udev znajdzie jakąś pasującą regułę dla urządzenia, to nie zatrzymuje się na niej. Dzięki temu można precyzować wiele reguł i zostaną one wszystkie zaaplikowane dla dopasowanego urządzenia.

Reguła składa się z grubsza z dwóch części. Pierwsza z nich ma za zadanie dopasowanie urządzenia, druga zaś ma to urządzenie odpowiednio dostosować. Jak odróżnić zatem te części od siebie? Parametry, na podstawie których urządzenie jest dopasowywane można poznać po znaku == . Pojedynczy znak = przypisuje konkretne wartości dla dopasowanego urządzenia, odpowiednio je zmieniając.

Pozyskiwanie informacji o urządzeniu

Nasuwa się zatem pytanie -- skąd brać te atrybuty, na których to podstawie urządzenie ma być dopasowane? Do tego celu służy narzędzie udevadm. Posiada ono kilka parametrów i jeszcze więcej opcji ale jeśli chodzi o szukanie informacji na temat urządzenia, to do tego celu służy udevadm info. Poniżej info na temat mojego pendrive:

udevadm info --name /dev/sdb --attribute-walk

Udevadm info starts with the device specified by the devpath and then walks up the chain of parent devices. It prints for every device found, all possible attributes in the udev rules key format. A rule to match, can be composed by the attributes of the device and the attributes from one single parent device.

looking at device '/devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host18/target18:0:0/18:0:0:0/block/sdb': KERNEL=="sdb" SUBSYSTEM=="block" DRIVER=="" ATTR{ro}=="0" ATTR{size}=="30299520" ATTR{stat}==" 253 0 2024 808 0 0 0 0 0 708 808" ATTR{range}=="16" ATTR{discard_alignment}=="0" ATTR{events}=="media_change" ATTR{ext_range}=="256" ATTR{events_poll_msecs}=="3000" ATTR{alignment_offset}=="0" ATTR{inflight}==" 0 0" ATTR{removable}=="1" ATTR{capability}=="51" ATTR{events_async}==""

looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host18/target18:0:0/18:0:0:0': KERNELS=="18:0:0:0" SUBSYSTEMS=="scsi" DRIVERS=="sd" ATTRS{rev}=="PMAP" ATTRS{type}=="0" ATTRS{scsi_level}=="0" ATTRS{model}=="DT 101 G2 " ATTRS{state}=="running" ATTRS{queue_type}=="none" ATTRS{iodone_cnt}=="0x12d" ATTRS{iorequest_cnt}=="0x12d" ATTRS{device_busy}=="0" ATTRS{evt_capacity_change_reported}=="0" ATTRS{timeout}=="30" ATTRS{evt_media_change}=="0" ATTRS{max_sectors}=="240" ATTRS{ioerr_cnt}=="0x2" ATTRS{queue_depth}=="1" ATTRS{vendor}=="Kingston" ATTRS{evt_soft_threshold_reached}=="0" ATTRS{device_blocked}=="0" ATTRS{evt_mode_parameter_change_reported}=="0" ATTRS{evt_lun_change_reported}=="0" ATTRS{evt_inquiry_change_reported}=="0" ATTRS{iocounterbits}=="32" ATTRS{eh_timeout}=="10"

looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host18/target18:0:0': KERNELS=="target18:0:0" SUBSYSTEMS=="scsi" DRIVERS==""

looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host18': KERNELS=="host18" SUBSYSTEMS=="scsi" DRIVERS==""

looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0': KERNELS=="4-5:1.0" SUBSYSTEMS=="usb" DRIVERS=="usb-storage" ATTRS{bInterfaceClass}=="08" ATTRS{bInterfaceSubClass}=="06" ATTRS{bInterfaceProtocol}=="50" ATTRS{bNumEndpoints}=="02" ATTRS{supports_autosuspend}=="1" ATTRS{bAlternateSetting}==" 0" ATTRS{bInterfaceNumber}=="00"

looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb4/4-5': KERNELS=="4-5" SUBSYSTEMS=="usb" DRIVERS=="usb" ATTRS{bDeviceSubClass}=="00" ATTRS{bDeviceProtocol}=="00" ATTRS{devpath}=="5" ATTRS{idVendor}=="0951" ATTRS{speed}=="480" ATTRS{bNumInterfaces}==" 1" ATTRS{bConfigurationValue}=="1" ATTRS{bMaxPacketSize0}=="64" ATTRS{busnum}=="4" ATTRS{devnum}=="20" ATTRS{configuration}=="" ATTRS{bMaxPower}=="200mA" ATTRS{authorized}=="1" ATTRS{bmAttributes}=="80" ATTRS{bNumConfigurations}=="1" ATTRS{maxchild}=="0" ATTRS{bcdDevice}=="0100" ATTRS{avoid_reset_quirk}=="0" ATTRS{quirks}=="0x0" ATTRS{serial}=="001CC0EC34A2BB318709004B" ATTRS{version}==" 2.00" ATTRS{urbnum}=="889" ATTRS{ltm_capable}=="no" ATTRS{manufacturer}=="Kingston" ATTRS{removable}=="unknown" ATTRS{idProduct}=="1642" ATTRS{bDeviceClass}=="00" ATTRS{product}=="DT 101 G2"

looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb4': KERNELS=="usb4" SUBSYSTEMS=="usb" DRIVERS=="usb" ATTRS{bDeviceSubClass}=="00" ATTRS{bDeviceProtocol}=="00" ATTRS{devpath}=="0" ATTRS{idVendor}=="1d6b" ATTRS{speed}=="480" ATTRS{bNumInterfaces}==" 1" ATTRS{bConfigurationValue}=="1" ATTRS{bMaxPacketSize0}=="64" ATTRS{authorized_default}=="1" ATTRS{busnum}=="4" ATTRS{devnum}=="1" ATTRS{configuration}=="" ATTRS{bMaxPower}=="0mA" ATTRS{authorized}=="1" ATTRS{bmAttributes}=="e0" ATTRS{bNumConfigurations}=="1" ATTRS{maxchild}=="8" ATTRS{bcdDevice}=="0313" ATTRS{avoid_reset_quirk}=="0" ATTRS{quirks}=="0x0" ATTRS{serial}=="0000:00:1d.7" ATTRS{version}==" 2.00" ATTRS{urbnum}=="521" ATTRS{ltm_capable}=="no" ATTRS{manufacturer}=="Linux 3.13-1-amd64 ehci_hcd" ATTRS{removable}=="unknown" ATTRS{idProduct}=="0002" ATTRS{bDeviceClass}=="09" ATTRS{product}=="EHCI Host Controller"

looking at parent device '/devices/pci0000:00/0000:00:1d.7': KERNELS=="0000:00:1d.7" SUBSYSTEMS=="pci" DRIVERS=="ehci-pci" ATTRS{irq}=="23" ATTRS{subsystem_vendor}=="0x1458" ATTRS{broken_parity_status}=="0" ATTRS{class}=="0x0c0320" ATTRS{companion}=="" ATTRS{enabled}=="1" ATTRS{consistent_dma_mask_bits}=="32" ATTRS{dma_mask_bits}=="32" ATTRS{local_cpus}=="00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000003" ATTRS{device}=="0x27cc" ATTRS{uframe_periodic_max}=="100" ATTRS{msi_bus}=="" ATTRS{local_cpulist}=="0-1" ATTRS{vendor}=="0x8086" ATTRS{subsystem_device}=="0x5006" ATTRS{numa_node}=="-1" ATTRS{d3cold_allowed}=="1"

looking at parent device '/devices/pci0000:00': KERNELS=="pci0000:00" SUBSYSTEMS=="" DRIVERS==""

Generalnie te parametry można bezpośrednio kopiować do pliku reguł. Są one oddzielone od siebie przecinkami. Dodatkowo dla większej przejrzystości i czytelności reguły, linie mogą być łamane przy pomocy znaku \ .

Poza suchymi parametrami, które można wykorzystać jedynie w plikach reguł udeva, istnieją jeszcze zmienne środowiskowe, które są uzupełniane i eksportowane tuż po podłączeniu urządzenia. W przypadku gdy przy wykryciu danego zasobu potrzeba jest uruchomienia jakiegoś skryptu, te zmienne mogą okazać się wielce użyteczne, bo będą widoczne dla tego skryptu. Jeśli interesują nas te zmienne, możemy skorzystać z udevadm info --name /dev/sdb by je podejrzeć:

udevadm info --name /dev/sdb

P: /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host18/target18:0:0/18:0:0:0/block/sdb N: sdb S: disk/by-id/usb-Kingston_DT_101_G2_001CC0EC34A2BB318709004B-0:0 S: disk/by-path/pci-0000:00:1d.7-usb-0:5:1.0-scsi-0:0:0:0 E: DEVLINKS=/dev/disk/by-id/usb-Kingston_DT_101_G2_001CC0EC34A2BB318709004B-0:0 /dev/disk/by-path/pci-0000:00:1d.7-usb-0:5:1.0-scsi-0:0:0:0 E: DEVNAME=/dev/sdb E: DEVPATH=/devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host18/target18:0:0/18:0:0:0/block/sdb E: DEVTYPE=disk E: ID_BUS=usb E: ID_INSTANCE=0:0 E: ID_MODEL=DT_101_G2 E: ID_MODEL_ENC=DT\x20101\x20G2\x20\x20\x20\x20\x20\x20\x20 E: ID_MODEL_ID=1642 E: ID_PART_TABLE_TYPE=dos E: ID_PATH=pci-0000:00:1d.7-usb-0:5:1.0-scsi-0:0:0:0 E: ID_PATH_TAG=pci-0000_00_1d_7-usb-0_5_1_0-scsi-0_0_0_0 E: ID_REVISION=PMAP E: ID_SERIAL=Kingston_DT_101_G2_001CC0EC34A2BB318709004B-0:0 E: ID_SERIAL_SHORT=001CC0EC34A2BB318709004B E: ID_TYPE=disk E: ID_USB_DRIVER=usb-storage E: ID_USB_INTERFACES=:080650: E: ID_USB_INTERFACE_NUM=00 E: ID_VENDOR=Kingston E: ID_VENDOR_ENC=Kingston E: ID_VENDOR_ID=0951 E: MAJOR=8 E: MINOR=16 E: SUBSYSTEM=block E: USEC_INITIALIZED=284488623

Te zmienne również można wykorzystać w plikach reguł.

Składnia reguł

Jeszcze parę słów o znakach wykorzystywanych w plikach reguł. Wiemy już po co nam == oraz = ale spotkamy się z szeregiem innych "krzaków" i wypadało by również wiedzieć co one oznaczają. I tak np. przeciwieństwem == jest != . Jeśli reguła ma przyjąć kilka wartości, kolejne z nich przypisujemy przez +=. Z kolei jeśli po danej wartości już nie spodziewamy się by jakieś dalsze zmiany dla urządzenia zachodziły, przypisujemy tę wartość przy pomocy := .

Dodatkowo można również używać maski, czyli znaków, pod którymi mogą kryć się inne znaki. I tak * oznacza dowolny znak powtórzony 0 lub więcej razy. Z kolei zaś ? oznacza dowolny znak powtórzony tylko jeden raz. I mamy jeszcze możliwość sprecyzowania znaków przy pomocy [ ] . Jeśli chcemy użyć zakresu od "a" do "z", precyzujemy go w taki sposób: [a-z] . Można również wyłączyć określone znaki przy dopasowaniu za pomocą !, przykładowo bez "a-c": [!a-c] .

Możemy również skorzystać z krótkich nazw oferowanych przez udev przy podłączaniu urządzenia:

%r, $root -- katalog urządzeń, domyślnie /dev %p, $devpath -- wartość DEVPATH %k, $kernel -- wartość KERNEL %n, $number -- numer urządzenia, dla sda3 to 3 %N, $tempnode -- tymczasowa nazwa pliku urządzenia %M, $major -- większy numer urządzenia %m, $minor -- mniejszy numer urządzenia %s{attribute}, $attr{attribute} -- wartość atrybutu sysfs %E{variable}, $attr{variable} -- wartość zmiennej środowiskowej %c, $result -- wartość PROGRAM %% -- znak % $$ -- znak $

Omówienie reguł na przykładzie

Jak wspomniałem na wstępie, będziemy operować na pendrive, który ma 3 partycje, w tym też jedną zaszyfrowaną. Załóżmy, że chcemy aby partycje tego konkretnego urządzenia były montowane po jego podłączeniu. W przypadku zaszyfrowanej partycji, dodatkowo trzeba ją pierw odszyfrować. Jest tylko jeden problem, nazwy urządzenia (te widoczne w katalogu /dev/) się zmieniają. Jasne, że istnieją inne drogi by osiągnąć to co chcemy, np. można użyć UUID ale my tutaj skupimy się na rozwiązaniu tej kwestii przez udev, co ma też i swoje zalety, bo UUID może ulec zmianie, a numer seryjny urządzenia raczej jest nieco trwalszy.

Tworzymy zatem plik /etc/udev/rules.d/99-local.rules i dopisujemy tam regułki:

KERNEL=="sd?3", ACTION=="add", ENV{ID_SERIAL_SHORT}=="001CC0EC34A2BB318709004B", \ SYMLINK+="pen%n", \ RUN+="/usr/bin/udevil mount /dev/pen%n /mnt/dane"

KERNEL=="sd?1", ACTION=="add", ENV{ID_SERIAL_SHORT}=="001CC0EC34A2BB318709004B", \ SYMLINK+="pen%n", \ RUN+="/usr/bin/udevil mount /dev/pen%n /mnt/debian"

KERNEL=="sd?2", ACTION=="add", ENV{ID_SERIAL_SHORT}=="001CC0EC34A2BB318709004B", \ SYMLINK+="pen%n", \ RUN+="/sbin/cryptsetup luksOpen /dev/pen%n pen%n --key-file=/home/morfik/Desktop/pen2.key", \ RUN+="/usr/bin/udevil mount /dev/mapper/pen%n /mnt/szyfr" KERNEL=="sd?2", ACTION=="remove", ENV{ID_SERIAL_SHORT}=="001CC0EC34A2BB318709004B", \ RUN+="/sbin/cryptsetup luksClose pen%n"

Co zatem mówią nam powyższe reguły?

Pierwsza z nich: jeśli urządzenie zostanie zarejestrowane z nazwą sd?3 przez kernel (znak ? oznacza dowolny znak, czyli sda3, sdb3, etc) oraz zmienna środowiskowa numeru seryjnego urządzenia to 001CC0EC34A2BB318709004B , udev ma utworzyć link do tego urządzenia (pen3, bo %n odpowiada 3) i zamontować urządzenie przez ten link w katalogu /mnt/dane . Pozycja z ACTION informuje udev, by tę regułę zaaplikował tylko przy podłączaniu urządzenia.

Druga reguła jest praktycznie taka sama co pierwsza, z tym, że numerki partycji się zmieniły.

Trzecia reguła różni się dodatkową linijką RUN, która odszyfrowuje kontener

Ostatnia reguła ma na celu zamknąć kontener, na wypadek gdyby ten nie został zamknięty ręcznie, np. w wyniku zbyt wczesnego wyciągnięcia pendrive, bo pierw trzeba odmontować partycję, a potem zamknąć kontener. W przypadku gdy jednak odmontujemy zasób i wyciągniemy pendriva, system dalej będzie widział otwarty kontener. Niby nic się nie powinno dziać w takim przypadku, ale gdy ponownie wsadzimy pendrive do portu USB, zostanie wykryty jako sdc, a nie sdb.

Udev i udevil

Jak widać w powyższych regułach został zastosowany udevil, nie zwykły mount, czy pmount. Ma on przewagę nad pozostałymi, bo potrafi precyzować kto może jakie urządzenia gdzie montować. I w tym przypadku może i root zamontował tego pendrive w podkatalogach /mnt ale użytkownik może bez problemu je odmontować i to nie każdy użytkownik tylko ten, któremu na to pozwolono.

Jeśli nie mamy zainstalowanego pakietu udevil w systemie, to koniecznie doinstalujmy go. Można oczywiście użyć innego systemu montowania ale ja tutaj skupię się tylko na udevilu.

Udevil posiada pliki konfiguracyjne w katalogu /etc/udevil/ i domyślnie jest tam jeden plik -- udevil.conf . Jest to konfiguracja systemowa określająca co gdzie może być montowane. Można tam utworzyć plik z konfiguracją per user. Ten plik musi posiadać nazwę podobną do tej: udevil-user-morfik.conf . Można zrobić kopię konfiguracji systemowej i pozmieniać tylko odpowiednie linijki. W tym przypadku zostały zmienione następujące wpisy:

allowed_media_dirs = /media/$USER, /media, /run/media/$USER, /mnt allowed_devices = /dev/*, /dev/mapper/pen* allowed_internal_devices = /dev/mapper/pen*

Krótko pisząc, zostało tam dopisane urządzenie /dev/mapper/pen* (można by zamiast * dać 2), bo jest ono wykrywane jako urządzenie wewnętrzne, a nie jako zewnętrzne, jak w przypadku pozostałych dwóch odszyfrowanych partycji na pendrive, przez co tylko root mógłby takie urządzenie zamontować, chyba, że zezwoli się na zamontowanie tego urządzenia komuś innemu i to właśnie zrobiliśmy w tym przypadku. Jak można również zobaczyć w pierwszej linijce, mamy tam katalogi, w których można montować zasoby. W przypadku mount możemy co prawda montować wszystko gdzie chcemy ale potrzebne są uprawnienia roota, z kolei w przypadku pmount możemy montować w katalogu /media/ jako zwykli użytkownicy, a udevil daje nam możliwość wybrania sobie co, gdzie i jak montować i temu deklasuje konkurencję.

Wywoływanie skryptów

Jeśli z jakichś powodów nie chcemy używać wielu linijek z "RUN" w konfiguracji reguł udeva, możemy sprecyzować do wykonania skrypt. Wtedy reguła dla zamontowania pen2 zmieni postać, np. na taką:

KERNEL=="sd?2", ACTION=="add", ENV{ID_SERIAL_SHORT}=="001CC0EC34A2BB318709004B", \ SYMLINK+="pen%n", \ RUN+="/home/morfik/Desktop/mount.sh open" KERNEL=="sd?2", ACTION=="remove", ENV{ID_SERIAL_SHORT}=="001CC0EC34A2BB318709004B", \ RUN+="/home/morfik/Desktop/mount.sh close"

A skrypt może wyglądać np. tak:

!/bin/bash

open () { cryptsetup luksOpen /dev/pen2 pen2 --key-file=/home/morfik/Desktop/pen2.key && udevil mount /dev/mapper/pen2 /mnt/szyfr }

close () { cryptsetup luksClose pen2 }

case "$1" in open) open ;; close) close ;;
*) echo "Usage: mount.sh {open|close}" exit 1 ;;
esac

exit 0

Jeśli posiadamy na pendrive 3 partycje (lub przynajmniej więcej niż 1) i nie są one zaszyfrowane, możemy uprościć reguły samego montowania do postaci:

KERNEL=="sd??", ACTION=="add", ENV{ID_SERIAL_SHORT}=="001CC0EC34A2BB318709004B", \ SYMLINK+="pen%n", \ RUN+="/usr/bin/udevil mount /dev/pen%n /mnt/%E{ID_FS_LABEL_ENC}"

Powyższa regułka mówi, że przy dodawaniu urządzenia o numerze seryjnym 001CC0EC34A2BB318709004B, zostanie utworzony link do każdej z jego partycji, w tym przypadku pen1, pen2, pen3, oraz każda partycja zostanie zamontowana w katalogu /mnt/ w oparciu o jej etykietę -- %E{ID_FS_LABEL_ENC} .

Testowanie reguł

W przypadku gdy jakaś reguła nam nie działa i nie możemy dociec o co tak naprawdę chodzi, możemy przetestować taką regułę i zobaczyć co zostanie wypisane na konsoli. Partycja druga na pendrive jest opisana za pomocą:

udevadm info --name /dev/sdb2

P: /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host26/target26:0:0/26:0:0:0/block/sdb/sdb2 ...

Teraz testujemy reguły dla tego urządzenia:

udevadm test /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host26/target26:0:0/26:0:0:0/block/sdb/sdb2

calling: test version 204 This program is for debugging only, it does not run any program specified by a RUN key. It may show incorrect results, because some values may be different, or not available at a simulation run.

=== trie on-disk === tool version: 204 file size: 5729797 bytes header size 80 bytes strings 1262125 bytes nodes 4467592 bytes load module index read rules file: /lib/udev/rules.d/42-usb-hid-pm.rules read rules file: /lib/udev/rules.d/50-firmware.rules read rules file: /lib/udev/rules.d/50-udev-default.rules read rules file: /lib/udev/rules.d/55-dm.rules read rules file: /lib/udev/rules.d/56-lvm.rules read rules file: /lib/udev/rules.d/60-cdrom_id.rules read rules file: /lib/udev/rules.d/60-fuse.rules read rules file: /lib/udev/rules.d/60-gnupg.rules read rules file: /lib/udev/rules.d/60-libfreenect0.2.rules read rules file: /lib/udev/rules.d/60-libgphoto2-6.rules read rules file: /lib/udev/rules.d/60-libpisock9.rules read rules file: /lib/udev/rules.d/60-libsane.rules read rules file: /lib/udev/rules.d/60-nvidia-kernel-common.rules read rules file: /lib/udev/rules.d/60-pcmcia.rules read rules file: /lib/udev/rules.d/60-persistent-alsa.rules read rules file: /lib/udev/rules.d/60-persistent-input.rules read rules file: /lib/udev/rules.d/60-persistent-serial.rules read rules file: /lib/udev/rules.d/60-persistent-storage-dm.rules read rules file: /lib/udev/rules.d/60-persistent-storage-tape.rules read rules file: /lib/udev/rules.d/60-persistent-storage.rules read rules file: /lib/udev/rules.d/60-persistent-v4l.rules read rules file: /lib/udev/rules.d/60-virtualbox-dkms.rules read rules file: /lib/udev/rules.d/60-virtualbox.rules read rules file: /lib/udev/rules.d/61-accelerometer.rules read rules file: /etc/udev/rules.d/61-removable-storage-polling.rules read rules file: /lib/udev/rules.d/64-btrfs.rules read rules file: /lib/udev/rules.d/64-xorg-xkb.rules read rules file: /lib/udev/rules.d/69-cd-sensors.rules IMPORT found builtin 'usb_id --export %p', replacing /lib/udev/rules.d/69-cd-sensors.rules:89 read rules file: /lib/udev/rules.d/69-libmtp.rules read rules file: /lib/udev/rules.d/69-lvm-metad.rules read rules file: /lib/udev/rules.d/69-xorg-vmmouse.rules read rules file: /lib/udev/rules.d/70-btrfs.rules read rules file: /etc/udev/rules.d/70-persistent-cd.rules read rules file: /etc/udev/rules.d/70-persistent-net.rules read rules file: /lib/udev/rules.d/70-power-switch.rules read rules file: /lib/udev/rules.d/70-udev-acl.rules read rules file: /etc/udev/rules.d/70-zram.rules read rules file: /lib/udev/rules.d/75-cd-aliases-generator.rules read rules file: /lib/udev/rules.d/75-net-description.rules read rules file: /lib/udev/rules.d/75-persistent-net-generator.rules read rules file: /lib/udev/rules.d/75-probe_mtd.rules read rules file: /lib/udev/rules.d/75-tty-description.rules read rules file: /lib/udev/rules.d/78-sound-card.rules read rules file: /lib/udev/rules.d/80-btrfs-lvm.rules read rules file: /lib/udev/rules.d/80-drivers.rules read rules file: /lib/udev/rules.d/80-net-name-slot.rules read rules file: /lib/udev/rules.d/80-networking.rules read rules file: /lib/udev/rules.d/85-hdparm.rules read rules file: /lib/udev/rules.d/85-hwclock.rules read rules file: /lib/udev/rules.d/90-alsa-restore.rules read rules file: /lib/udev/rules.d/90-pulseaudio.rules read rules file: /lib/udev/rules.d/91-permissions.rules read rules file: /lib/udev/rules.d/95-cd-devices.rules read rules file: /lib/udev/rules.d/95-keyboard-force-release.rules read rules file: /etc/udev/rules.d/95-keymap-media-keyboard-elite.rules read rules file: /lib/udev/rules.d/95-keymap.rules read rules file: /lib/udev/rules.d/95-udev-late.rules read rules file: /lib/udev/rules.d/97-bluetooth-hid2hci.rules read rules file: /etc/udev/rules.d/99-local.rules rules contain 393216 bytes tokens (32768 * 12 bytes), 31439 bytes strings 27771 strings (226797 bytes), 24689 de-duplicated (198441 bytes), 3083 trie nodes used LINK 'disk/by-id/usb-Kingston_DT_101_G2_001CC0EC34A2BB318709004B-0:0-part2' /lib/udev/rules.d/60-persistent-storage.rules:110 LINK 'disk/by-path/pci-0000:00:1d.7-usb-0:5:1.0-scsi-0:0:0:0-part2' /lib/udev/rules.d/60-persistent-storage.rules:132 IMPORT '/sbin/blkid -o udev -p /dev/sdb2' /lib/udev/rules.d/60-persistent-storage.rules:151 starting '/sbin/blkid -o udev -p /dev/sdb2' '/sbin/blkid -o udev -p /dev/sdb2' [2404] exit with return code 0 LINK 'disk/by-uuid/90ec6f73-8fdb-4c8d-aebd-cadd0f51b412' /lib/udev/rules.d/60-persistent-storage.rules:158 RUN '/etc/init.d/hdparm hotplug' /lib/udev/rules.d/85-hdparm.rules:1 GROUP 6 /lib/udev/rules.d/91-permissions.rules:4 GROUP 25 /lib/udev/rules.d/91-permissions.rules:5 GROUP 25 /lib/udev/rules.d/91-permissions.rules:9 LINK 'pen2' /etc/udev/rules.d/99-local.rules:16 RUN '/sbin/cryptsetup luksOpen /dev/pen%n pen%n --key-file=/home/morfik/Desktop/pen2.key' /etc/udev/rules.d/99-local.rules:16 RUN '/usr/bin/udevil mount /dev/mapper/pen%n /mnt/szyfr' /etc/udev/rules.d/99-local.rules:16 handling device node '/dev/sdb2', devnum=b8:18, mode=0660, uid=0, gid=25 preserve permissions /dev/sdb2, 060660, uid=0, gid=25 preserve already existing symlink '/dev/block/8:18' to '../sdb2' found 'b8:18' claiming '/run/udev/links/\x2fdisk\x2fby-id\x2fusb-Kingston_DT_101_G2_001CC0EC34A2BB318709004B-0:0-part2' creating link '/dev/disk/by-id/usb-Kingston_DT_101_G2_001CC0EC34A2BB318709004B-0:0-part2' to '/dev/sdb2' preserve already existing symlink '/dev/disk/by-id/usb-Kingston_DT_101_G2_001CC0EC34A2BB318709004B-0:0-part2' to '../../sdb2' found 'b8:18' claiming '/run/udev/links/\x2fdisk\x2fby-path\x2fpci-0000:00:1d.7-usb-0:5:1.0-scsi-0:0:0:0-part2' creating link '/dev/disk/by-path/pci-0000:00:1d.7-usb-0:5:1.0-scsi-0:0:0:0-part2' to '/dev/sdb2' preserve already existing symlink '/dev/disk/by-path/pci-0000:00:1d.7-usb-0:5:1.0-scsi-0:0:0:0-part2' to '../../sdb2' found 'b8:18' claiming '/run/udev/links/\x2fdisk\x2fby-uuid\x2f90ec6f73-8fdb-4c8d-aebd-cadd0f51b412' creating link '/dev/disk/by-uuid/90ec6f73-8fdb-4c8d-aebd-cadd0f51b412' to '/dev/sdb2' preserve already existing symlink '/dev/disk/by-uuid/90ec6f73-8fdb-4c8d-aebd-cadd0f51b412' to '../../sdb2' found 'b8:18' claiming '/run/udev/links/\x2fpen2' creating link '/dev/pen2' to '/dev/sdb2' preserve already existing symlink '/dev/pen2' to 'sdb2' .ID_FS_TYPE_NEW=crypto_LUKS ACTION=add DEVLINKS=/dev/disk/by-id/usb-Kingston_DT_101_G2_001CC0EC34A2BB318709004B-0:0-part2 /dev/disk/by-path/pci-0000:00:1d.7-usb-0:5:1.0-scsi-0:0:0:0-part2 /dev/disk/by-uuid/90ec6f73-8fdb-4c8d-aebd-cadd0f51b412 /dev/pen2 DEVNAME=/dev/sdb2 DEVPATH=/devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host26/target26:0:0/26:0:0:0/block/sdb/sdb2 DEVTYPE=partition ID_BUS=usb ID_FS_TYPE=crypto_LUKS ID_FS_USAGE=crypto ID_FS_UUID=90ec6f73-8fdb-4c8d-aebd-cadd0f51b412 ID_FS_UUID_ENC=90ec6f73-8fdb-4c8d-aebd-cadd0f51b412 ID_FS_VERSION=1 ID_INSTANCE=0:0 ID_MODEL=DT_101_G2 ID_MODEL_ENC=DT\x20101\x20G2\x20\x20\x20\x20\x20\x20\x20 ID_MODEL_ID=1642 ID_PART_ENTRY_DISK=8:16 ID_PART_ENTRY_NUMBER=2 ID_PART_ENTRY_OFFSET=6293504 ID_PART_ENTRY_SCHEME=dos ID_PART_ENTRY_SIZE=4194304 ID_PART_ENTRY_TYPE=0x83 ID_PART_TABLE_TYPE=dos ID_PATH=pci-0000:00:1d.7-usb-0:5:1.0-scsi-0:0:0:0 ID_PATH_TAG=pci-0000_00_1d_7-usb-0_5_1_0-scsi-0_0_0_0 ID_REVISION=PMAP ID_SERIAL=Kingston_DT_101_G2_001CC0EC34A2BB318709004B-0:0 ID_SERIAL_SHORT=001CC0EC34A2BB318709004B ID_TYPE=disk ID_USB_DRIVER=usb-storage ID_USB_INTERFACES=:080650: ID_USB_INTERFACE_NUM=00 ID_VENDOR=Kingston ID_VENDOR_ENC=Kingston ID_VENDOR_ID=0951 MAJOR=8 MINOR=18 SUBSYSTEM=block USEC_INITIALIZED=150393548 run: '/etc/init.d/hdparm hotplug' run: '/sbin/cryptsetup luksOpen /dev/pen2 pen2 --key-file=/home/morfik/Desktop/pen2.key' run: '/usr/bin/udevil mount /dev/mapper/pen2 /mnt/szyfr' unload module index

Dobrze jest prześledzić linijki zawierające, w tym przypadku, plik reguł /etc/udev/rules.d/99-local.rules i sprawdzić czy polecenia, które chcemy wykonać nie zawierają czasem jakiejś literówki. Należy też prześledzić log pod kątem dopasowania reguły do urządzenia.

Dodatkowe informacje

W przypadku gdy zmieniamy reguły trzeba je ponownie załadować by udev mógł być świadom zmian. Można to zrobić przez:

udevadm control --reload

Nazw urządzeń w kernelu nie można zmienić. W manualu jest tylko informacja, że "The name of a device node cannot be changed by udev, only additional symlinks can be created". Więc jeśli chcemy by urządzenie było dostępne pod inną nazwą trzeba tworzyć do niego linki, tak jak w przykładach powyżej.

Udev posiada także monitor zdarzeń i potrafi w czasie rzeczywistym wypisywać informacje na temat podłączanych/odłączanych urządzeń na konsoli. Można go wywołać przez:

$ udev monitor

Można mu także sprecyzować dodatkowe opcje w zależności od tego jakie informacje nam są potrzebne. Przykładowy log monitora wygląda jak poniżej:

udevadm monitor

monitor will print the received events for: UDEV - the event which udev sends out after rule processing KERNEL - the kernel uevent

KERNEL[19007.937212] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5 (usb) KERNEL[19007.937343] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0 (usb) KERNEL[19007.938339] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28 (scsi) KERNEL[19007.938370] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/scsi_host/host28 (scsi_host) UDEV [19008.068405] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5 (usb) UDEV [19008.107014] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0 (usb) UDEV [19008.107501] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28 (scsi) UDEV [19008.107726] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/scsi_host/host28 (scsi_host) KERNEL[19009.029324] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0 (scsi) KERNEL[19009.029366] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0 (scsi) KERNEL[19009.029618] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/scsi_disk/28:0:0:0 (scsi_disk) KERNEL[19009.029649] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/scsi_device/28:0:0:0 (scsi_device) UDEV [19009.030458] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0 (scsi) KERNEL[19009.030483] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/scsi_generic/sg1 (scsi_generic) KERNEL[19009.030505] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/bsg/28:0:0:0 (bsg) UDEV [19009.036115] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0 (scsi) UDEV [19009.036155] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/scsi_disk/28:0:0:0 (scsi_disk) UDEV [19009.036178] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/bsg/28:0:0:0 (bsg) UDEV [19009.037390] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/scsi_generic/sg1 (scsi_generic) UDEV [19009.040637] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/scsi_device/28:0:0:0 (scsi_device) KERNEL[19009.569827] add /devices/virtual/bdi/8:16 (bdi) UDEV [19009.570568] add /devices/virtual/bdi/8:16 (bdi) KERNEL[19009.591083] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/block/sdb (block) KERNEL[19009.591114] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/block/sdb/sdb1 (block) KERNEL[19009.591136] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/block/sdb/sdb2 (block) KERNEL[19009.591157] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/block/sdb/sdb3 (block) UDEV [19010.248771] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/block/sdb (block) UDEV [19010.343415] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/block/sdb/sdb3 (block) UDEV [19010.397643] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/block/sdb/sdb1 (block) KERNEL[19011.151289] add /devices/virtual/bdi/254:10 (bdi) KERNEL[19011.156149] add /devices/virtual/block/dm-10 (block) UDEV [19011.156181] add /devices/virtual/bdi/254:10 (bdi) UDEV [19011.156265] add /devices/virtual/block/dm-10 (block) KERNEL[19011.157713] change /devices/virtual/block/dm-10 (block) KERNEL[19011.157742] change /devices/virtual/block/dm-10 (block) UDEV [19011.158529] change /devices/virtual/block/dm-10 (block) UDEV [19011.167694] change /devices/virtual/block/dm-10 (block) KERNEL[19011.182633] remove /devices/virtual/block/dm-10 (block) KERNEL[19011.183922] remove /devices/virtual/bdi/254:10 (bdi) KERNEL[19011.184066] remove /devices/virtual/block/dm-10 (block) UDEV [19011.184377] remove /devices/virtual/bdi/254:10 (bdi) UDEV [19011.197199] remove /devices/virtual/block/dm-10 (block) UDEV [19011.197446] remove /devices/virtual/block/dm-10 (block) KERNEL[19011.483240] add /devices/virtual/bdi/254:10 (bdi) KERNEL[19011.484219] add /devices/virtual/block/dm-10 (block) UDEV [19011.484242] add /devices/virtual/bdi/254:10 (bdi) UDEV [19011.484269] add /devices/virtual/block/dm-10 (block) KERNEL[19011.484998] change /devices/virtual/block/dm-10 (block) UDEV [19011.562665] change /devices/virtual/block/dm-10 (block) UDEV [19011.608092] add /devices/pci0000:00/0000:00:1d.7/usb4/4-5/4-5:1.0/host28/target28:0:0/28:0:0:0/block/sdb/sdb2 (block)

Jeśli interesują nas tylko zdarzenia kernela (te zaczynające się od KERNEL), możemy sprecyzować --kernel przy wywoływaniu monitora. Można także mieć wgląda do zdarzeń udeva przez podanie parametru --udev .

Keyfile trzymany w głębokim ukryciu

$
0
0

Pisząc ostatni artykuł na temat udeva i montowania przy jego pomocy zaszyfrowanego kontenera, wpadł mi do głowy ciekawy pomysł na trzymanie keyfile w czymś co się potocznie nazywa "głębokim ukryciem". Z reguły ludzie nie chcą używać haseł do odblokowywania swoich systemów czy partycji. Zamiast tego wolą keyfile, czyli małe pliki, zwykle o rozmiarze paru KiB, które, jak nie patrzeć, są dość unikatowe i odporne na ataki słownikowe czy inne formy przemocy. Jedyny problem z jakim człowiek musi się zmierzyć to z zabezpieczeniem takiego keyfile i tutaj sprawa nie wygląda wcale dobrze. Keyfile są trzymane zwykle na tym samym urządzeniu, do którego mają dostarczyć dostęp, a nawet jeśli nie na tym samym, to w jego pobliżu i zwykle przechwycenie zaszyfrowanego dysku skutkuje przechwyceniem klucza, który może posłużyć do otwarcia urządzenia.

A może istnieje jakiś sposób, który by ukrył taki keyfile by nikt, kto o jego istnieniu nie wie, nie mógł go użyć do odszyfrowania urządzenia? Jeśli przypatrzymy się takiemu pendrivowi, to możemy zobaczyć poniższy układ partycji:

fdisk -l /dev/sdb

Disk /dev/sdb: 15.5 GB, 15513354240 bytes 64 heads, 32 sectors/track, 14794 cylinders, total 30299520 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x0005c7f0

Device Boot Start End Blocks Id System /dev/sdb1 2048 6293503 3145728 83 Linux /dev/sdb2 6293504 10487807 2097152 83 Linux /dev/sdb3 10487808 30298111 9905152 83 Linux

Gdzie można by schować keyfile? Moim zdaniem gdzieś poniżej 2048 sektora, bo tam nic nie ma, bo partycja pierwsza zaczyna się na 2048 sektorze w wyniku równania do 1MiB. 2047 sektorów (bo jeden to MBR) daje nam 1048064 bajtów wolnego miejsca, a my potrzebujemy 2KiB . Czyli mamy dość miejsca by ulokować keyfile tak by nie można było zgadnąć gdzie on jest. Ten keyfile nie będzie miał nazwy, bo jest to tylko zbitka bitów na dysku i nie pozostawia praktycznie żadnych wskazówek co do swojego istnienia.

Naturalnie można by stworzyć mały pliczek i wgrać go w któreś miejsce między 0 a 2048 sektorem ale istnieje lepszy sposób na zachowanie poufności keyfile. Bo w przypadku gdyby tam były same 0 i wgralibyśmy losowe dane o długości 2048 bajtów, to będą one widoczne jak na dłoni. Dlatego też zapiszemy losowymi danymi całą wolną przestrzeń pierw, po czym określimy, które sektory będą robić za keyfile.

To do dzieła. Zapisujemy 2047 sektorów 512 bajtowych pomijając pierwszy z nich, w którym siedzi MBR -- nie chcemy sobie wpinąć przy okazji tablicy partycji.

dd if=/dev/urandom of=/dev/sdb bs=512 count=2047 seek=1

2047+0 records in 2047+0 records out 1048064 bytes (1.0 MB) copied, 0.346335 s, 3.0 MB/s

W ten sposób mamy losowe dane w MBR-GAP. Nasz keyfile ma 2KiB długości i by w ogóle coś z nim robić to musimy go pierw dodać do nagłówka LUKS:

dd if=/dev/sdb bs=512 count=4 skip=100 > ./keyfile

4+0 records in 4+0 records out 2048 bytes (2.0 kB) copied, 0.00102532 s, 2.0 MB/s

ls -al ./keyfile

-rw-r--r-- 1 root root 2.0K Mar 17 19:17 ./keyfile

cryptsetup luksAddKey /dev/sdb2 ./keyfile

Enter any passphrase:

Oczywiście rozmiar keyfile może być dowolny, tzn. nie większy niż 8192KiB. Powyższa linijka czyta 4512 bajtów, czyli 2KiB, pomijając pierwsze 100 sektorów czyli 100512=51200 bajtów od początku pendrive. To tam właśnie będzie znajdował się nasz keyfile.

Sprawdzamy czy keyfile został dodany do nagłówka:

cryptsetup luksDump /dev/sdb2

LUKS header information for /dev/sdb2

Version: 1 Cipher name: aes Cipher mode: xts-plain64 Hash spec: sha512 Payload offset: 4096 MK bits: 512 MK digest: d0 9d 3d b3 34 2d 0c d3 0e 99 59 79 14 71 f3 00 07 b5 b8 76 MK salt: d6 9f 77 4f f0 2d c8 07 c9 cf a7 60 c4 6f 3d 90 c9 4d 5c ae f4 e5 36 d3 e5 75 b4 5d 3b 83 c9 79 MK iterations: 18125 UUID: 90ec6f73-8fdb-4c8d-aebd-cadd0f51b412

Key Slot 0: ENABLED Iterations: 37558 Salt: c1 1a 6f 49 5f f4 49 94 e2 4d 56 3a 49 39 87 14 95 38 2f d3 cd 99 43 73 50 9b 44 09 cb c5 ad 9f Key material offset: 8 AF stripes: 4000 Key Slot 1: ENABLED Iterations: 15685 Salt: 95 f7 1b 27 04 c6 87 c8 3c 14 23 5b c7 99 f8 c2 cf ab 1c ed 8c 70 69 b4 da a3 a7 67 97 5e f6 a4 Key material offset: 512 AF stripes: 4000 Key Slot 2: ENABLED Iterations: 37036 Salt: dc cf 2b ff da a1 4a cf ee 54 c0 19 5a d4 48 cd ed 25 52 b6 0c e8 ad ae 35 56 96 35 64 22 db ce Key material offset: 1016 AF stripes: 4000 Key Slot 3: DISABLED Key Slot 4: DISABLED Key Slot 5: DISABLED Key Slot 6: DISABLED Key Slot 7: DISABLED

By otworzyć partycję na pendraku z wykorzystaniem tego keyfile, wpisujemy poniższą linijkę:

dd if=/dev/sdb bs=512 count=4 skip=100 | cryptsetup luksOpen /dev/sdb2 sdb2 --key-file=-

4+0 records in 4+0 records out 2048 bytes (2.0 kB) copied, 0.000904289 s, 2.3 MB/s

I jeszcze możemy sprawdzić czy aby na pewno kontener się otwiera gdy podamy parametry 512 4 100 dla dd. Podmieńmy zatem 100 na 101:

dd if=/dev/sdb bs=512 count=4 skip=101 | cryptsetup luksOpen /dev/sdb2 sdb2 --key-file=-

4+0 records in 4+0 records out 2048 bytes (2.0 kB) copied, 0.00220645 s, 928 kB/s No key available with this passphrase.

Nasz keyfile co prawda jest dostarczany razem z zaszyfrowanym urządzeniem ale pozostaje w głębokim ukryciu i nikt kto nie zna tych 3 parametrów, nie uzyska dostępu do pena, poza tym, kto by chował keyfile w MBR-GAP? xD

Wirtualizacja wine 32bit w systemie 64bit przy wykorzystaniu kontenera LXC

$
0
0
  1. Konfiguracja systemu pod LXC
  2. Przygotowanie kontenera LXC

     2.1. Konfiguracja sieci
    
  3. Kontener LXC od środka

     3.1. Problemy z udev i ręczne tworzenie urządzeń
    
  4. Połączenie z Xserverem

     4.1. Parę słów o zabezpieczeniu Xservera
     4.2. Zmienna $DISPLAY
        4.3. Szyfrowanie połączenia do Xservera
    
  5. Instalacja wine i sterowników do grafiki

  6. Dźwięk, pulseaudio i problemy z nimi związane

     6.1. Szyfrowanie dźwięku
    
  7. Test szyfrowania

  8. Problem z urxvt przy połączeniu ssh

Każdy kto zmienił system z i386 na amd64 raczej nie dostrzegł większej różnicy w operowaniu na którymś z nich, czasem jedynie pakiety w nazwie mają 64 zamiast 32. Jednak jest jedna rzecz, która drażni chyba każdego. Mowa tutaj o wine, bo jego rozwój został daleko za murzynami, już pominę, że nie umie obsługiwać natywnie pulse (w ogóle nie umie...) to jeszcze dochodzi do tego pierdolnik jaki nam robi w systemie wine 32bit, którego zwykle ludzie używają do odpalania gier, czy programów.

Jeśli chcielibyśmy zainstalować wine na maszynie 64bit w debianie, trzeba by dodać architekturę 32bit i doinstalować xxx pakietów (w tym też sterowniki do grafy), wszystko 32bitowe by w ogóle mieć możliwość zainstalowania wine. Ja może nie gram za dużo i praktycznie nie korzystam z wine ale gdy zmieniłem architekturę systemu, miałem w planach opracować sposób odseparowania wine, nie tylko tego 32 bitowego, jeśli już jest 64 bitowy, od reszty systemu.

W końcu udało mi się to zrobić. Nie wiem jak tam wyglądają prace na wine64 i czy da radę na nim odpalać aplikacje albo gry 32 bitowe, w każdym razie tutaj zostanie rozważony wariant grania w starsze gry na wine32. Raczej nie będzie większego problemu z przeniesieniem całej konfiguracji na wine64.

By odseparować jedną część systemu od drugiej, potrzeba czegoś na wzór maszyny wirtualnej, np. virtalbox. Problem z vboxem jest taki, że po pierwsze trzeba mu przydzielić określone zasoby oraz wymaga od procesora wsparcia wirtualizacji, a jak wiadomo, nie wszystkie procki mają jeszcze ten ficzer, przynajmniej mój nie ma. Zamiast więc posługiwać się rozwiązaniem w stylu virtualboxa, skorzystamy z LXC.

  1. Konfiguracja systemu pod LXC

LXC to pseudo wirtualny system, który działa jak zwykły chroot ale posiada kilka znaczących różnic, choćby urządzenia -- w chroot nie ma możliwości określenia z jakich urządzeń chroot będzie korzystał -- bierze cały /dev/ , a LXC może określić, którym urządzeniom zezwolić na działanie. LXC nie korzysta z ustawień sieci hosta -- można na nim ustawić NAT i w iptables przepuszczać/blokować połączenia. Jest też spora różnica w procesach, bo w chroot jak zamontujemy katalog /proc , to ujrzymy wszystkie procesy dostępne w całym systemie, a LXC pozwala zobaczyć jedynie tylko te procesy, które działają w jego obrębie. Naturalnie, host dalej ma możliwość wglądu w procesy wewnątrz kontenera LXC i może dowolnie nimi zarządzać. Dodatkowo LXC jest kontrolowany przez cgroups i można w ten sposób przydzielać zasoby pod określone kontenery. Można nawet zawiesić (zamrozić) taki kontener, by nie pobierał żadnych zasobów, aż do czasu odmrożenia.

I tu zaczynają się schody, bo o ile mechanizm cgroups jest, lub może się okazać, użyteczny, to LXC nie może bez niego żyć i wszystko by było w porządku gdyby nie fakt, że obecnie pakiety od cgroups i LXC się żrą w debianie. Idzie je co prawda pogodzić ale najniższa wersja LXC, którą da radę zainstalować, przy jednoczesnym posiadaniu w systemie cgroups, pochodzi z gałęzi experimental, więc to nawet nie jest sid i raczej wątpię, by ktoś na stable ten mechanizm wdrożył.

Jeśli jednak nie boimy się wyzwań, możemy dodać eksperymentalną gałąź do /etc/apt/sources.list :

deb     http://ftp.pl.debian.org/debian/ experimental main contrib non-free

deb-src http://ftp.pl.debian.org/debian/ experimental main contrib non-free

Instalujemy także potrzebne pakiety:

aptitude -t experimental install lxc

W chwili pisania tego tekstu, pakiet lxc ma wersję 1.0.0-4 .

Dodatkowo trzeba zainstalować cgroups:

aptitude install cgroup-bin libcgroup1

Cgroups także są pobugowane w debianie, zawierają skrypty z redhata, które nie działają na debianie i pewnie jest cała masa innych bugów, których jeszcze nie doświadczyłem -- jednym słowem zajebiście. Być może samo zamontowanie cgroups przez fstab otworzy drogę do używania kontenerów LXC. Poniżej jest linijka z wiki debiana, którą trzeba dodać do /etc/fstab :

cgroup /sys/fs/cgroup cgroup defaults 0 0

U mnie jednak było parę błędów przy startowaniu kontenera. Nie wiem czy, któryś z nich był krytyczny, generalnie to w miarę działało. Ja już z cgroups miałem do czynienia wcześniej i napisałem inny artykuł na temat konfiguracji cgroups i ten setup przedstawiony w tamtym artykule działa bez zarzutu. Także warto też rzucić okiem na niego i spróbować skonfigurować montowanie cgroups ręcznie.

W tej chwili powinniśmy mieć już skonfigurowane cgroups, a lxc-checkconfig powinien mieć zapalone wszędzie zielone lampki, tak jak w logu poniżej:

lxc-checkconfig

Kernel configuration not found at /proc/config.gz; searching... Kernel configuration found at /boot/config-3.13-1-amd64 --- Namespaces --- Namespaces: enabled Utsname namespace: enabled Ipc namespace: enabled Pid namespace: enabled User namespace: enabled Network namespace: enabled Multiple /dev/pts instances: enabled

--- Control groups --- Cgroup: enabled Cgroup clone_children flag: enabled Cgroup device: enabled Cgroup sched: enabled Cgroup cpu account: enabled Cgroup memory controller: enabled Cgroup cpuset: enabled

--- Misc --- Veth pair device: enabled Macvlan: enabled Vlan: enabled File capabilities: enabled

Note : Before booting a new kernel, you can check its configuration usage : CONFIG=/path/to/config /usr/bin/lxc-checkconfig

  1. Przygotowanie kontenera LXC

Jeśli tak jest w istocie, przechodzimy do zbudowania kontenera:

lxc-create -n wine32 -t debian -P /media/Server/lxc_wine/ -- -r sid -a i386

debootstrap is /usr/sbin/debootstrap Checking cache download in /var/cache/lxc/debian/rootfs-sid-i386 ... Downloading debian minimal ... I: Retrieving Release I: Retrieving Release.gpg I: Checking Release signature I: Valid Release signature (key id A1BD8E9D78F7FE5C3E65D8AF8B48AD6246925553) I: Retrieving Packages I: Validating Packages I: Resolving dependencies of required packages... I: Resolving dependencies of base packages... ... I: Base system installed successfully. Download complete. Copying rootfs to /media/Server/lxc_wine/wine32/rootfs...Generating locales (this might take a while)... en_US.UTF-8... done Generation complete. Creating SSH2 RSA key; this may take some time ... Creating SSH2 DSA key; this may take some time ... Creating SSH2 ECDSA key; this may take some time ... Creating SSH2 ED25519 key; this may take some time ... invoke-rc.d: policy-rc.d denied execution of start.

Current default time zone: 'Europe/Warsaw' Local time is now: Fri Mar 28 10:51:16 CET 2014. Universal Time is now: Fri Mar 28 09:51:16 UTC 2014.

Root password is 'root', please change !

Parametry w powyższej linijce oznaczają: -n -- nazwa kontenera -t -- szablon użyty do zbudowania systemu -P -- ścieżka do zapisu plików kontenera -r -- release tego co zostało użyte w opcji -t -a -- architektura budowanego systemu

Gdy budujemy kontener po raz pierwszy, zostanie zainicjowany debootstrap i pobierze, zainstaluje i skonfiguruje on minimalny system. W przypadku budowania kolejnego kontenera (ta sama architektura, ta sama gałąź), zostanie wykorzystany ten poprzedni minimalny system i nie będzie trzeba pobierać go z sieci jeszcze raz.

Edytujemy teraz plik konfiguracyjny kontenera, u mnie znajduje się on w /media/Server/lxc_wine/wine32/config . To w nim precyzujemy, urządzenia, punkty montowania oraz konfigurację sieci dla kontenera. Dobór urządzeń może sprawić problemy -- trzeba po prostu zajrzeć w katalog /dev/ na hoście w celu określenia parametrów urządzeń tam się znajdujących ale tylko tych, które będą nam potrzebne.

Jeśli zamierzamy korzystać z karty graficznej, a zamierzamy, kluczową rolę grają tutaj sterowniki. Ja korzystam z karty nvidii i mam do wyboru, albo zamknięte stery, albo te otwarte z modułem nouveau. To jakie sterowniki wybierzemy wpływa na urządzenia tworzone w katalogu /dev/ . Na zamkniętych sterach nvidii, mamy urządzenia /dev/nvidia* , na otwartych jest katalog /dev/dri/ i w nim kilka urządzeń. Potrzebne będą także urządzenia od myszy oraz klawiatury, no i od dźwięku.

Poniżej jest plik konfiguracyjny dla mojego kontenera LXC:

Template used to create this container: /usr/share/lxc/templates/lxc-debian

Parameters passed to the template: -r sid -a i386

For additional config options, please look at lxc.conf(5)

lxc.rootfs = /media/Server/lxc_wine/wine32/rootfs

Common configuration

lxc.include = /usr/share/lxc/config/debian.common.conf

Container specific configuration

lxc.mount = /media/Server/lxc_wine/wine32/fstab lxc.utsname = wine32 lxc.arch = i386

lxc.network.type = empty

lxc.network.type = veth lxc.network.name = veth0 lxc.network.flags = up lxc.network.link = br0 lxc.network.veth.pair = veth0-sid lxc.network.ipv4 = 192.168.1.2/24 lxc.network.ipv4.gateway = 192.168.1.253

nvidia

lxc.cgroup.devices.allow = c 195:0 rwm lxc.cgroup.devices.allow = c 195:255 rwm

dri -- card0 controlD64

lxc.cgroup.devices.allow = c 226:0 rwm

lxc.cgroup.devices.allow = c 226:64 rwm

input

lxc.cgroup.devices.allow = c 13:* rwm

snd

lxc.cgroup.devices.allow = c 116:* rwm

mount

lxc.mount.entry=/media/Server/wow /media/Server/lxc_wine/wine32/rootfs/wow none bind 0 0

2.1. Konfiguracja sieci

Powyżej mamy ustawioną konfigurację sieci dla kontenera LXC, jednak nie zadziała ona OOTB, trzeba skonfigurować mostek (bridge), w przeciwnym razie nie będziemy mieli dostępu do internetu w kontenerze.

By móc stworzyć wirtualny interfejs dla mostka, potrzebne nam są narzędzia, a te są dostarczane przez pakiet bridge-utils . Instalujemy go i dopisujemy poniższe linijki do pliku /etc/network/interfaces :

auto br0 iface br0 inet static address 192.168.1.253 netmask 255.255.255.0 broadcast 192.168.1.255 bridge_ports none

up iptables -t nat -F POSTROUTING up iptables -t nat -A POSTROUTING -o eth0 -s 192.168.1.0/24 -d 0/0 -j MASQUERADE

Ustawiamy również odpowiednie reguły w iptables dla łańcucha FORWARD :

iptables -t filter -A FORWARD -s 192.168.1.0/255.255.255.0 -d 0/0 -j ACCEPT iptables -t filter -A FORWARD -s 0/0 -d 192.168.1.0/255.255.255.0 -j ACCEPT

Włączamy także forwarding dla pakietów sieciowych w kernelu. Dopisujemy w /etc/sysctl.conf poniższe linijki:

net.ipv4.ip_forward=1 net.ipv6.conf.all.forwarding=1

Niektóre opcje definiowane w /etc/sysctl.conf mogą nie zostać załadowane na starcie systemu, czego efektem będzie brak sieci w kontenerze LXC po restarcie maszyny głównej. Możemy dopisać poniższą linijkę w /etc/rc.local :

sysctl -p >/dev/null 2>&1

Jeśli z jakichś powodów chcemy uczynić kontener czymś w rodzaju środowiska testowego, np. będziemy chcieli się łączyć po ssh, czy stawiać jakieś serwery, musimy przepuścić dodatkowy ruch w iptables. W zależności od tego jak się będziemy podłączać do kontenera, reguły nie będą takie same, bo raz będzie nawiązane połączenie z mostkiem, a innym razem z maszyną hosta -- wyskrobałem coś takiego dla iptables:

iptables -t filter -A INPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -j ACCEPT iptables -t filter -A INPUT -s 192.168.1.0/24 -d 10.1.4.41 -j ACCEPT iptables -t filter -A OUTPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -j ACCEPT iptables -t filter -A OUTPUT -s 10.1.4.41 -d 192.168.1.0/24 -j ACCEPT

gdzie 10.1.4.41 to realne ip mojej maszyny, a 192.168.1.0/24 to sieć kontenera, w której znajduje się również ip mostka.

Dobrze jest też dodać poniższe wpisy dla ping, na wypadek gdyby były problemy z połączeniem:

iptables -t filter -A INPUT --protocol icmp --jump ICMP iptables -t filter -A ICMP --protocol icmp --jump ACCEPT

Przy czym trzeba pamiętać, że system w kontenerze nie zawiera narzędzia ping -- trzeba doinstalować pakiet iputils-ping . Jak to zrobić nie mając dostępu do sieci? Trzeba po prostu zwyczajnie się chrootnąć do kontenera.

Restartujemy teraz połączenie sieciowe lub uruchamiamy komputer ponownie, by mieć pewność, że wszystko zostało skonfigurowane i załadowane jak należy. Jeśli jesteśmy pewni, że wszystko zrobiliśmy jak trza, możemy zwyczajnie wklepać poniższą linijkę:

/etc/init.d/networking restart

Jeśli teraz podejrzymy interfejsy sieciowe (przez ifconfig albo ip addr show), powinniśmy ujrzeć br0 :

ifconfig

... br0 Link encap:Ethernet HWaddr 00:00:00:00:00:00 inet addr:192.168.1.253 Bcast:192.168.1.255 Mask:255.255.255.0 inet6 addr: fe80::bc0f:3bff:fee8:3dc4/64 Scope:Link UP BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:1330 errors:0 dropped:0 overruns:0 frame:0 TX packets:1656 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:137020 (133.8 KiB) TX bytes:2374307 (2.2 MiB)

Przy włączonym kontenerze, powinien być widoczny także wirtualny interfejs kontenera:

... veth0-sid Link encap:Ethernet HWaddr fe:87:75:07:82:a2 inet6 addr: fe80::fc87:75ff:fe07:82a2/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:8 errors:0 dropped:0 overruns:0 frame:0 TX packets:40 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:648 (648.0 B) TX bytes:4042 (3.9 KiB)

I powinniśmy mieć dodatkową trasę w tablicy routingu:

route

Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface default 10.1.255.253 0.0.0.0 UG 0 0 0 eth0 10.1.0.0 * 255.255.0.0 U 0 0 0 eth0 192.168.1.0 * 255.255.255.0 U 0 0 0 br0

Jeśli chodzi o samą konfigurację mostka, to wygląda ona tak:

brctl show

bridge name bridge id STP enabled interfaces br0 8000.000000000000 no

Połączenie z kontenerem już powinniśmy uzyskać ale potrzebujemy jeszcze konfiguracji resolvera. Edytujemy zatem plik /media/Server/lxc_wine/wine32/rootfs/etc/resolv.conf i dodajemy tam poniższe wpisy:

nameserver 208.67.222.222 nameserver 208.67.220.220

Dobrze jest także ustawić plik /etc/hosts zarówno na hoście jak i w kontenerze, zwłaszcza jeśli chcemy używać jakichś usług, np. apache , niemniej zawsze można operować na cyferkach. Ja sobie dodałem coś takiego:

Plik /etc/hosts :

192.168.1.2 lxc.mhouse lxc

Plik /media/Server/lxc_wine/wine32/rootfs/etc/hosts :

10.1.4.41 morfikownia.mhouse morfikownia

Jeśli zamierzamy instalować sporo rzeczy możemy rozważyć edycję pliku sources.list w kontenerze (/media/Server/lxc_wine/wine32/rootfs/etc/apt/sources.list), zmieniając domyślny mirror na bardziej nam odpowiadający, np:

deb http://ftp.pl.debian.org/debian/ sid main non-free contrib

deb-src http://ftp.pl.debian.org/debian/ sid main non-free contrib

  1. Kontener LXC od środka

Możemy teraz podnieść kontener. Przy czym, taka uwaga -- w configu kontenera LXC umieściłem także jeden wpis od montowania lokalnego zasobu. Jeśli chcemy coś w taki sposób montować, musimy się upewnić, że katalog docelowy, czyli ten w kontenerze, istnieje, w przeciwnym razie dostaniemy poniższy błąd:

lxc-start: No such file or directory - failed to mount '/media/Server/wow' on '/usr/lib/x86_64-linux-gnu/lxc/rootfs//wow' lxc-start: failed to setup the mount entries for 'wine32' lxc-start: failed to setup the container lxc-start: invalid sequence number 1. expected 2 lxc-start: failed to spawn 'wine32'

By wystartować kontener, wklepujemy do terminala taką oto linijkę:

lxc-start -n wine32 -P /media/Server/lxc_wine/

Logujemy się za pomocą użytkownika root oraz hasła root i sprawdzamy czy działa sieć:

Debian GNU/Linux jessie/sid wine32 console

wine32 login: root Password:

root@wine32:~# apt-get update Get:1 http://ftp.pl.debian.org sid InRelease [205 kB] Get:2 http://ftp.pl.debian.org sid/contrib Translation-en [42.3 kB] Get:3 http://ftp.pl.debian.org sid/main Translation-en [4,537 kB] Get:4 http://ftp.pl.debian.org sid/non-free Translation-en [77.1 kB] Get:5 http://ftp.pl.debian.org sid/main i386 Packages [6,657 kB] Get:6 http://ftp.pl.debian.org sid/non-free i386 Packages [88.5 kB] Get:7 http://ftp.pl.debian.org sid/contrib i386 Packages [53.5 kB] Fetched 11.7 MB in 15s (752 kB/s) Reading package lists... Done

Zatrzymać kontener możemy albo przez zalogowanie się do niego i wydanie zwykłego polecenia zamykającego system, np. shutdown z odpowiednimi opcjami, czy też poweroff. Możemy także wyłączyć kontener z maszyny hosta przy pomocy:

lxc-stop -n wine32 -P /media/Server/lxc_wine/

3.1. Problemy z udev i ręczne tworzenie urządzeń

Udev nie działa z kontenerami LXC i przy startowaniu kontenera zwraca takie oto ostrzeżenie:

udev does not support containers, not started ... (warning).

Nie ma się co tym przejmować, tylko nie mamy dostępu do pewnych urządzeń, tych charakterystycznych dla naszej maszyny. Skoro udev nie może ich stworzyć, sami musimy to zrobić. Urządzenia, które nas interesują znajdują się w: /dev/input/* -- klawiatura oraz myszka /dev/snd/* -- dźwięk /dev/nvidia* lub /dev/dri/* -- w zależności od sterowników, grafika

Urządzenia tworzymy przy pomocy mknod . Zaglądamy zatem do katalogu /dev i dla przykładu, urządzenie nvidia0 wygląda tak:

$ ls -al /dev/nvidia0 crw-rw-rw-+ 1 root root 195, 0 Mar 26 12:01 /dev/nvidia0

Kluczowa sprawa to te dwie liczby: 195 oraz 0 . By stworzyć to urządzenie, w kontenerze wpisujemy poniższą linijkę:

root@wine32:/dev# mknod -m 666 /dev/nvidia0 c 195 0

Podobnie postępujemy dla wszystkich pozostałych urządzeń, których obsługę chcemy mieć w kontenerze, w tym przypadku są to:

root@wine32:/dev# mkdir /dev/input root@wine32:/dev# mknod -m 666 /dev/input/mice c 13 63 root@wine32:/dev# mknod -m 666 /dev/input/mouse0 c 13 32 root@wine32:/dev# mknod -m 666 /dev/input/event0 c 13 64 root@wine32:/dev# mknod -m 666 /dev/input/event1 c 13 65 root@wine32:/dev# mknod -m 666 /dev/input/event2 c 13 66 root@wine32:/dev# mknod -m 666 /dev/input/event3 c 13 67 root@wine32:/dev# mknod -m 666 /dev/input/event4 c 13 68 root@wine32:/dev# mknod -m 666 /dev/input/event5 c 13 69 root@wine32:/dev# mknod -m 666 /dev/input/event6 c 13 70 root@wine32:/dev# chmod 600 /dev/input/*

root@wine32:/dev# mkdir /dev/snd root@wine32:/dev# mknod -m 666 /dev/snd/controlC0 c 116 11 root@wine32:/dev# mknod -m 666 /dev/snd/midiC0D0 c 116 2 root@wine32:/dev# mknod -m 666 /dev/snd/pcmC0D0c c 116 10 root@wine32:/dev# mknod -m 666 /dev/snd/pcmC0D0p c 116 9 root@wine32:/dev# mknod -m 666 /dev/snd/pcmC0D1c c 116 8 root@wine32:/dev# mknod -m 666 /dev/snd/pcmC0D1p c 116 7 root@wine32:/dev# mknod -m 666 /dev/snd/pcmC0D2c c 116 6 root@wine32:/dev# mknod -m 666 /dev/snd/pcmC0D2p c 116 5 root@wine32:/dev# mknod -m 666 /dev/snd/pcmC0D3c c 116 4 root@wine32:/dev# mknod -m 666 /dev/snd/pcmC0D3p c 116 3 root@wine32:/dev# mknod -m 666 /dev/snd/seq c 116 1 root@wine32:/dev# mknod -m 666 /dev/snd/timer c 116 33 root@wine32:/dev# chown root:audio /dev/snd/*

root@wine32:/dev# mknod -m 666 /dev/nvidia0 c 195 0 root@wine32:/dev# mknod -m 666 /dev/nvidiactl c 195 255

Zmieniamy hasło roota na coś innego oraz tworzymy nowego użytkownika w kontenerze i dodajemy go do grup audio oraz video:

root@wine32:~# passwd Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully root@wine32:~# adduser morfik Adding user morfik' ... Adding new groupmorfik' (1000) ... Adding new user morfik' (1000) with groupmorfik' ... Creating home directory /home/morfik' ... Copying files from/etc/skel' ... Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully Changing the user information for morfik Enter the new value, or press ENTER for the default Full Name []: Room Number []: Work Phone []: Home Phone []: Other []: Is the information correct? [Y/n] y

root@wine32:~# adduser morfik video Adding user morfik' to groupvideo' ... Adding user morfik to group video Done. root@wine32:~# adduser morfik audio Adding user morfik' to groupaudio' ... Adding user morfik to group audio Done.

  1. Połączenie z Xserverem

Podstawową konfigurację mamy z głowy. Teraz trzeba przygotować Xserver do pracy. Jeśli korzystamy z DM, czyli graficznego menadżera logowania, to trzeba poszukać w opcjach tegoż programu jak ustawić odpowiednie parametry dla procesu X . Ja odpalam Xserver przez startx (plik ~/.xinitrc), a konfigurację procesu X mam pliku w ~/.xserverc . Na debianie Xserver startuje z opcją -nolisten tcp , co powoduje, że zdalne połączenia do tego Xservera są niemożliwe i jeśli mamy w planach korzystanie z Xservera, a mamy, to trzeba usunąć ten parametr, w moim przypadku wystarczył sam plik ~/.xserverrc zawierający:

exec /usr/bin/X -nolisten tcp "$@"

exec /usr/bin/X "$@"

exec /usr/bin/X "$@" -auth "$HOME/.Xauthority"

4.1. Parę słów o zabezpieczeniu Xservera

To, że zezwalamy Xserverowi na akceptowanie połączeń przez sieć, nie znaczy automatycznie, że on zacznie nawiązywać połączenia z każdym kto tego będzie chciał. Są dwa (właściwie trzy, wliczając -nolisten tcp) mechanizmy chroniące przed nieautoryzowanym dostępem do Xservera. Pierwszy z nich to xhost , drugi zaś to xauth .

xhost jest podatny na szereg ataków, np. nie rozróżnia on użytkowników zdalnych, czyli jeśli mamy adres ip i na nim wielu użytkowników, to możemy zezwolić, albo im wszystkim na połączenie, albo żadnemu. xhost nie sprawdza też czy ten kto się łączy jest tym za kogo się podaje. Jeśli jednak mamy zaufaną sieć, a tak jest w tym przypadku, możemy zezwolić adresowi ip kontenera LXC (192.168.1.2) na podłączenie się do sesji Xservera na hoście. W tym celu na głównej maszynie wydajemy poniższe polecenie:

$ xhost +192.168.1.2

Można również sprecyzować nazwę ustawioną przez plik /etc/hosts . Jeśli teraz sprawdzimy jakie hosty mogą nawiązywać połączenia z naszym Xserverem, powinniśmy ujrzeć coś podobnego do tego poniżej:

$ xhost access control enabled, only authorized clients can connect INET:lxc.mhouse SI:localuser:morfik

Ustawienia nie są trwałe i znikają po zamknięciu sesji, dlatego dobrze jest dodać powyższą linijkę do autostartu na maszynie hosta.

Innym rozwiązaniem, o wiele bezpieczniejszym są ciasteczka Xservera, trzymane z reguły w katalogu użytkownika w pliku ~/.Xauthority . By skorzystać z tego mechanizmu, musimy wygenerować ciasteczko oraz odpalić proces X z opcją -auth "$HOME/.Xauthority" , tak jak jest to zrobione powyżej. Domyślnie ten plik ląduje w katalogu /tmp i jest generowany per sesja. Jeśli wskażemy ciastko Xserverowi, tylko ci klienci co mają to ciasteczko będą mogli się połączyć z naszym Xserverem.

By skorzystać z ciasteczek Xservera, musimy mieć zainstalowany w kontenerze pakiet xauth . Jeśli w grę jednak wchodzi tylko kontener LXC na lokalnej maszynie, to raczej nie potrzebujemy tego mechanizmu i nie musimy sobie nim głowy zawracać. Jeśli jednak byśmy mieli do czynienia z maszyną znajdującą się na drugim końcu wszechświata, to dobrze jest zainstalować ten pakiet:

root@wine32:~# apt-get install xauth ... The following NEW packages will be installed: libx11-6 libx11-data libxau6 libxcb1 libxdmcp6 libxext6 libxmuu1 xauth 0 upgraded, 8 newly installed, 0 to remove and 0 not upgraded. Need to get 1,049 kB of archives. After this operation, 3,441 kB of additional disk space will be used.

Pakiet xauth jest także wymagany przy forwardingu połączeń Xservera przez ssh.

W przypadku gdybyśmy nie mieli jeszcze tego ciasteczka ($HOME/.Xauthority) możemy utworzyć je ręcznie:

$ mcookie|sed -e 's/^/add :0 . /'|xauth -q

Jednak to, że go nie mamy jest mało prawdopodobne, bo program startujący Xserver, czy to startx, czy też DM, tworzą ten plik automatycznie. Jedyny problem przed jakim teraz stoimy, to przesłanie informacji autoryzujących połączenie do Xservera na drugą maszynę. Możemy to zrobić przy pomocy ssh:

morfik:~$ xauth extract - morfikownia.mhouse:0 | ssh -x morfik@192.168.1.2 xauth merge - morfik@192.168.1.2's password:

Zaglądnijmy teraz do pliku $HOME/.Xauthority w kontenerze:

morfik:~$ ssh morfik@192.168.1.2 morfik@192.168.1.2's password:

morfik@wine32:~$ ls -al $HOME/.Xauthority -rw------- 1 morfik morfik 101 Mar 27 11:59 /home/morfik/.Xauthority

morfik@wine32:~$ xauth Using authority file /home/morfik/.Xauthority xauth> list morfikownia.mhouse:0 MIT-MAGIC-COOKIE-1 a578170842011b9f496ab3d8d91456bc

Mechanizmy xhost oraz xauth dają nam dość spore pole manewru (szczególnie ten drugi) jeśli chodzi o to komu pozwalamy się łączyć z naszym Xserverem. Nie chronią nas jednak przed podsłuchem komunikacji.

4.2. Zmienna $DISPLAY

Dostęp do kontenera mamy zagwarantowany, jednak by moc przesłać dane do Xservera musimy wskazać systemowi gdzie ten Xserver się znajduje. Robimy to przez wyeksportowanie zmiennej $DISPLAY . Musi ona zawierać adres ip lub nazwę hosta, na którym nasłuchuje Xserver. W tym przypadku jest to 10.1.4.41 lub morfikownia.mhouse :

morfik@wine32:~$ DISPLAY="morfikownia.mhouse:0"

Oczywiście na localhoście, między interfejsem karty sieciowej i wirtualnym interfejsem naszego kontenera LXC raczej nikt podsłuchu nie zamontuje ale co w przypadku gdybyśmy pracowali zdalnie i zapragnęlibyśmy korzystać z graficznych aplikacji? Nie mówię o graniu (choć w sumie czemu by nie), tylko o np. graficznym edytorze tekstu. Moglibyśmy przesłać ruch przez ssh i zestawić okienka lokalnie, zamiast na serwerze.

4.3. Szyfrowanie połączenia do Xservera

Spróbujmy zatem na chwilę przyjąć, że nasz kontener jest gdzieś daleko i mamy do niego dostęp przez shella. Musimy skonfigurować dwa pliki od ssh -- jeden na kliencie, drugi na serwerze. Klienta możemy konfigurować albo globalnie w pliku /etc/ssh/ssh_config albo lokalnie w ~/.ssh/config . Można nawet konfigurować połączenia niezależnie i jeśli będziemy korzystać z Xservera tylko w jednym lub kilku z nich, możemy skonfigurować klienta ssh w poniższy sposób:

Host 192.168.1.2 ForwardX11 yes Compression yes Ciphers blowfish-cbc

Zawsze możemy sprecyzować te opcje przy połączeniu, podając parametr -X dla ForwardX11, -C dla Compression, oraz -c blowfish-cbc dla Ciphers.

Na serwerze z kolei trzeba wyedytować plik /etc/ssh/sshd_config i ustawić w nim:

X11Forwarding yes X11DisplayOffset 10

Zalogujmy się na serwer przez ssh i sprawdźmy zmienną $DISPLAY :

morfik:~$ ssh -vvv morfik@192.168.1.2 OpenSSH_6.5, OpenSSL 1.0.1f 6 Jan 2014 debug1: Reading configuration data /home/morfik/.ssh/config debug1: /home/morfik/.ssh/config line 1: Applying options for 192.168.1.2 debug3: cipher ok: blowfish-cbc [blowfish-cbc] debug3: ciphers ok: [blowfish-cbc] debug1: Reading configuration data /etc/ssh/ssh_config debug1: /etc/ssh/ssh_config line 19: Applying options for * debug2: ssh_connect: needpriv 0 debug1: Connecting to 192.168.1.2 [192.168.1.2] port 22. debug1: Connection established. ... debug1: Next authentication method: password morfik@192.168.1.2's password: ... debug1: Enabling compression at level 6. ... debug2: x11_get_proto: /usr/bin/xauth list :0 2>/dev/null debug1: Requesting X11 forwarding with authentication spoofing. debug2: channel 0: request x11-req confirm 1 ... debug2: X11 forwarding request accepted on channel 0 ...

morfik@wine32:~$ echo $DISPLAY localhost:10.0

Jak widać zmienna $DISPLAY została automatycznie ustawiona, podobnie jak i plik .Xauthority i bez problemu możemy odpalać graficzne aplikacje na serwerze, a okienka zostaną przesłane do naszego lokalnego Xservera. W logu powyżej możemy również zaobserwować, że konfiguracja dla kontenera czytana jest z pliku /home/morfik/.ssh/config . Jest też włączona kompresja i wybrany szyfr blowfish-cbc oraz połączenie z Xserverem leci po ssh.

Z tego co wyczytałem na sieci, to zwykłe połączenie bez kompresji i z szyfrem AES jest bardzo wolne i nie nadaje się zbytnio do szyfrowania połączeń z Xserverem. Oczywiście można jechać na standardowych ustawieniach ssh ale wtedy, jeśli faktycznie mamy maszynę zdalną, okienka nie będą się płynnie ładować. Jeśli jednak korzystamy z LXC na lokalnej maszynie, to nie musimy ani kompresować ani szyfrować ruchu z Xserverem, co odciąży nam trochę procesor.

  1. Instalacja wine i sterowników do grafiki

Przyszła pora by zainstalować wine w kontenerze:

root@wine32:~# apt-get install wine ... The following NEW packages will be installed: dbus file fontconfig-config fonts-dejavu-core fonts-liberation libasound2 libasound2-data libasyncns0 libcap-ng0 libdbus-1-3 libdrm-intel1 libdrm-nouveau2 libdrm-radeon1 libdrm2 libelf1 libexif12 libexpat1 libffi6 libflac8 libfontconfig1 libfontenc1 libfreetype6 libgcrypt11 libgd3 libgl1-mesa-dri libgl1-mesa-glx libglapi-mesa libglu1-mesa libgnutls26 libgpg-error0 libgphoto2-6 libgphoto2-l10n libgphoto2-port10 libice6 libjbig0 libjpeg8 libjson-c2 libkmod2 liblcms2-2 libldap-2.4-2 libllvm3.4 libltdl7 libmagic1 libmpg123-0 libogg0 libopenal-data libopenal1 libp11-kit0 libpciaccess0 libpng12-0 libpulse0 libsasl2-2 libsasl2-modules libsasl2-modules-db libsm6 libsndfile1 libsystemd-journal0 libsystemd-login0 libtasn1-6 libtiff5 libtxc-dxtn-s2tc0 libudev1 libusb-1.0-0 libvorbis0a libvorbisenc2 libvpx1 libwine libwine-gecko-2.21 libx11-6 libx11-data libx11-xcb1 libxau6 libxaw7 libxcb-dri2-0 libxcb-dri3-0 libxcb-glx0 libxcb-present0 libxcb-shape0 libxcb-sync1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxdmcp6 libxext6 libxfixes3 libxft2 libxi6 libxinerama1 libxml2 libxmu6 libxmuu1 libxpm4 libxrandr2 libxrender1 libxshmfence1 libxt6 libxtst6 libxv1 libxxf86dga1 libxxf86vm1 sgml-base ucf udev wine wine32 x11-common x11-utils xml-core 0 upgraded, 109 newly installed, 0 to remove and 8 not upgraded. Need to get 86.9 MB of archives. After this operation, 295 MB of additional disk space will be used. Do you want to continue? [Y/n]

Dodatkowo jest to system 32bit osadzony wewnątrz innej maszyny 64bit, więc trzeba także doinstalować 32bitowe sterowniki dla grafiki:

root@wine32:~# apt-get install nvidia-legacy-304xx-driver ... The following NEW packages will be installed: binutils cpp cpp-4.8 dkms fakeroot fontconfig gcc gcc-4.8 glx-alternative-mesa glx-alternative-nvidia glx-diversions hicolor-icon-theme keyboard-configuration kmod libasan0 libatk1.0-0 libatk1.0-data libatomic1 libavahi-client3 libavahi-common-data libavahi-common3 libc-dev-bin libc6-dev libcairo2 libcloog-isl4 libcups2 libdatrie1 libegl1-mesa libegl1-mesa-drivers libfakeroot libgbm1 libgcc-4.8-dev libgcrypt20 libgdk-pixbuf2.0-0 libgdk-pixbuf2.0-common libgl1-nvidia-legacy-304xx-glx libglib2.0-0 libglib2.0-data libgmp10 libgomp1 libgraphite2-3 libgtk2.0-0 libgtk2.0-bin libgtk2.0-common libharfbuzz0b libisl10 libitm1 libjasper1 libmpc3 libmpfr4 libopenvg1-mesa libpango-1.0-0 libpangocairo-1.0-0 libpangoft2-1.0-0 libpixman-1-0 libpopt0 libquadmath0 libthai-data libthai0 libwayland-client0 libwayland-egl1-mesa libwayland-server0 libxcb-render0 libxcb-shm0 libxcb-xfixes0 libxfont1 libxkbfile1 libxvmc1 linux-compiler-gcc-4.8-x86 linux-headers-3.13-1-686-pae linux-headers-3.13-1-common linux-headers-686-pae linux-kbuild-3.13 linux-libc-dev make manpages manpages-dev menu module-init-tools nvidia-installer-cleanup nvidia-kernel-common nvidia-legacy-304xx-alternative nvidia-legacy-304xx-driver nvidia-legacy-304xx-kernel-dkms nvidia-settings-legacy-304xx nvidia-support patch pkg-config shared-mime-info x11-xkb-utils xauth xfonts-base xfonts-encodings xfonts-utils xkb-data xserver-common xserver-xorg-core xserver-xorg-video-nvidia-legacy-304xx 0 upgraded, 98 newly installed, 0 to remove and 5 not upgraded. Need to get 77.7 MB of archives. After this operation, 296 MB of additional disk space will be used. Do you want to continue? [Y/n]

Łącznie 600MiB + system podstawowy, z tym, że instalowane z sugerowanymi pakietami. Pewnie dałoby radę jeszcze to odchudzić.

  1. Dźwięk, pulseaudio i problemy z nimi związane

U mnie dźwięk na wine zawsze stwarzał problemy i nigdy mi się nie udało go skonfigurować tak by bez problemu współpracował z pulseaudio. Tak samo jest i w tym przypadku. Jeśli odpalę grę w kontenerze, to wine zajmuje urządzenie dźwiękowe i nie da rady nic odtwarzać w tym czasie na maszynie hosta. Nie wiem jak sprawa wygląda na samej alsie, bo u mnie ona też nie chce za bardzo działać w normalnych warunkach (temu używam pulse) ale myślę, że nie powinno być z nią żadnych problemów. Być może trzeba będzie doinstalować jakiś pakiet od alsy w kontenerze i coś ustawić w pliku ~/.asoundrc . Jeśli jednak odpalę wine na standardowych ustawieniach i nie będę nic odtwarzał na maszynie hosta w tym czasie, dźwięk jak najbardziej działa.

Z tego co zauważyłem, przy złej konfiguracji dźwięku proces Xorga może dość w znacznym stopniu utylizować procesor. Jedyne wyjście, w przypadku gdy nie potrafimy dojść do ładu z dźwiękiem, to wyłączyć go w wine całkowicie przy pomocy skryptu winetricks .

Jeśli znajdujemy się w sytuacji takiej jak moja i dźwięk w kontenerze zbytnio nie jest nam potrzebny, logujemy się do kontenera i pobieramy winetricks. Prawdopodobnie trzeba będzie doinstalować wget. Można oczywiście przekopiować ręcznie ten skrypt:

Debian GNU/Linux jessie/sid wine32 console

wine32 login: morfik Password:

morfik@wine32:~$ wget http://winetricks.org/winetricks --2014-03-27 13:13:23-- http://winetricks.org/winetricks Resolving winetricks.org (winetricks.org)... 216.92.137.144 Connecting to winetricks.org (winetricks.org)|216.92.137.144|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 640757 (626K) [text/plain] Saving to: ‘winetricks.1’

100%[===================================>] 640,757 447KB/s in 1.4s

2014-03-27 13:13:24 (447 KB/s) - ‘winetricks.1’ saved [640757/640757]

morfik@wine32:~$ chmod +x winetricks

By wyłączyć dźwięk w wine wklepujemy poniższą linijkę:

morfik@wine32:~$ ./winetricks sound=disabled Executing w_do_call sound=disabled Executing load_sound disabled Setting sound driver to disabled Executing winetricks_early_wine regedit C:\windows\Temp_sound=disabled\set-sound.reg

LXC świetnie się nadaje na sandboxa i można w nim odpalać aplikacje A/V czy też przeglądarki ale w tym celu trzeba przesłać i obraz i dźwiek przez sieć. Przesył obrazu już mamy z głowy, jak zatem przesłać dźwięk? Nie mam pojęcia czy da radę jakoś to zrobić z alsą ale pulse, można by rzec, działa OOTB, przynajmniej z grubsza.

Na serwerze, czyli maszynie hoście, musimy załadować dodatkowy moduł dla pulse i oznaczyć adresy ip jako zaufane -- te które będą mogły się łączyć z naszym serwerem dźwięku. W tym celu edytujemy plik /etc/pulse/default.pa i dopisujemy tam poniższą linijkę:

load-module module-native-protocol-tcp auth-ip-acl=192.168.1.0/24

Po tej operacji trzeba zrestartować pulse:

$ pulseaudio -k $ pulseaudio -D

Moduły można też dodawać i usuwać przy pomocy pactl bez konieczności restartowania pulse:

$ pactl load-module module-native-protocol-tcp auth-ip-acl=192.168.1.0/24 $ pactl unload-module module-native-protocol-tcp

To cała praca jeśli chodzi o serwer pulseaudio. Na kliencie, musimy wyeksportować jedną zmienną, nie trzeba nawet tam instalować pulseaudio, przynajmniej całego. Ja po instalacji wine i sterowników do grafiki mam tylko jeden pakiet od pulse:

morfik@wine32:~$ dpkg -l | grep -i pulse ii libpulse0:i386 4.0-6+b1 i386 PulseAudio client libraries

I ten pakiet szuka zmiennej $PULSE_SERVER w środowisku i jeśli znajdzie, kieruje tam ruch. Trzeba tylko ją wyeksportować na zdalnej maszynie:

morfik@wine32:~$ export PULSE_SERVER=10.1.4.41

Można oczywiście ustawić tą zmienną per aplikacja:

morfik@wine32:~$ PULSE_SERVER=10.1.4.41 smplayer

6.1. Szyfrowanie dźwięku

Ruch do serwera pulseaudio nie zostanie zaszyfrowany. Jeśli chcemy mieć szyfrowany również i dźwięk, trzeba skorzystać z tcp forwardingu w ssh i przekierować pakiety, tak by szły w kanał ssh. W tym celu musimy logować się do zdalnej maszyny przez:

$ ssh -R 4713:localhost:4713 morfik@192.168.1.2

Oczywiście nie musimy tego przekierowania portów precyzować za każdym razem gdy się łączymy do serwera ssh. Wszystkie opcje połączenia możemy wpisać do pliku konfiguracyjnego klienta -- /home/morfik/.ssh/config . W tym przypadku przekierowujemy port 4713 zdalnej maszynie, zatem musimy dodać do pliku poniższa linijkę:

RemoteForward 127.0.0.1:4713 127.0.0.1:4713

Trzeba jeszcze wskazać systemowi gdzie ma szukać serwera pulseaudio -- zmienna $PULSE_SERVER ma wskazywać na lokalny port na zdalnej maszynie:

morfik@wine32:~$ export PULSE_SERVER="tcp:localhost:4713"

Teraz pakiety zamiast bezpośrednio do serwera pulse, będą szły na localhost maszyny zdalnej na port 4713 i będą forwardowane na port 4713 tunelem ssh do serwera dźwięku.

Nie ważne jakby się starać, wine i tak nie zadziała. Generalnie dźwięk jest -- amarok na hoście i smplayer w LXC odtwarzają dźwięk równolegle i nie kolidują ze sobą.

Jeśli mamy jakieś problemy z ustaleniem przyczyny problemów z forwardingiem dźwięku, pomocne mogą okazać się poniższe dwa narzędzia:

$ pax11publish Server: {811ce104b3874ec4ec8e21d452802763}unix:/tmp/pulse-4uCknDXO1C7j/native tcp:morfikownia.mhouse:4713 tcp6:morfikownia.mhouse:4713 Cookie: c7c011a564ee890b8e2204617d9bb74392fb71571d5c51236484d72749ea67ed9b369dc02903e04 b9e272969b18b09ccd4782673719a07111c2dc7e4922e07a7e766a64f801146fd961f8186a545e5feb480e5 8e2342c80326a0c41f197842a055fa1236bd9baa2b8840c37dc2ee2d50516b5f0216a950b5762cc407a2a50 387c33d615daac6e66a613ccc2e59f9390b7d1c07a4567da7c048c2687599020872cb7009c2628ee9096239 8d71780b5182b5e1adbdfcde41401c8f996e4554b5sa7daee2e939efe1bb4401e2642599bcac65eca251f90 a76b652f17e93fc6134701a48150c77431070c132c0e5eab2ceb9ad63d186cf1b3d79fa45e41c939e1d66

lub:

$ xprop -root PULSE_SERVER PULSE_SERVER(STRING) = "{811ce104b3874ec4ec8e21d452802763}unix:/tmp/pulse-4uCknDXO1C7j/native tcp:morfikownia.mhouse:4713 tcp6:morfikownia.mhouse:4713"

  1. Test szyfrowania

Jeśli powyższe czynności były przeprowadzane na zdalnej maszynie i chcemy sprawdzić czy faktycznie cały ruch jest szyfrowany, możemy zobaczyć to przez netstart. Jeśli na adresie zdalnym będziemy mieli coś takiego jak poniżej:

root:~# netstat -tupan | grep 192 tcp 0 0 10.1.4.41:6000 192.168.1.2:60571 ESTABLISHED 21488/X tcp 0 32 10.1.4.41:6000 192.168.1.2:60574 ESTABLISHED 21488/X tcp 0 0 192.168.1.253:52868 192.168.1.2:22 ESTABLISHED 12839/ssh tcp 0 0 10.1.4.41:4713 192.168.1.2:33222 ESTABLISHED 4979/pulseaudio

oznacza to, że ani połączenie z Xserverem, ani z serwerem dźwięku pulseaudio nie jest szyfrowane, czyli krótko mówiąc: obraz/dźwięk/klawiaturę/myszę można podejrzeć/podsłuchać . Jeśli byśmy przesyłali ruch zdalnie, to mamy zobaczyć, tam w logu netstat, jeden proces na porcie 22 (lub innym, ustawionym w konfiguracji ssh) i nic poza tym.

  1. Problem z urxvt przy połączeniu ssh

W przypadku urxvt, ssh zachowuje się trochę dziwnie -- gdy spróbujemy odpalić graficzny program, zostanie wyświetlony taki komunikat:

'rxvt-unicode-256color': unknown terminal type.

Rozwiązaniem jest umieszczenie pliku /usr/share/terminfo/r/rxvt-unicode-256color w katalogu użytkownika, na serwerze. Do tego celu posłuży scp ale najpierw, na serwerze stwórzmy katalog /home/morfik/.terminfo/r/ . Potem przy pomocy scp kopiujemy:

morfik:~$ scp /usr/share/terminfo/r/rxvt-unicode-256color morfik@192.168.1.2:/home/morfik/.terminfo/r/ morfik@192.168.1.2's password: rxvt-unicode-256color 100% 2226 2.2KB/s 00:00

I to by było na tyle. W zależności od tego czy potrzebujemy szyfrowania, trzeba korzystać z ssh, w przeciwnym wypadku, można je sobie odpuścić.

Remapowanie niedziałających klawiszy

$
0
0

Na sieci znalazłem sporo nieaktualnych już informacji na temat tego jak powinno się przemapować klawisze, które nie do końca są wykrywane w systemie. Zwykle są to klawisze multimedialne lub inne niestandardowe przyciski, które nie pasują do układu 104 klawiszy. Większość z tego co znalazłem można, co prawda, wdrożyć z większym lub mniejszym powodzeniem, jednak zaleca się nie stosować tamtych rozwiązań, poza tym istnieją nowsze i lepsze alternatywy, które nieco upraszczają cały proces zmiany układu klawiatury.

  1. Konfiguracja klawiatury

Klawiaturę można konfigurować w kilku miejscach, w debianie można tego dokonać, albo w plikach konfiguracyjnych Xorga, albo przez dpkg-reconfigure keyboard-configuration . I tak dla przykładu, plik Xorga z konfiguracją klawiatury może wyglądać tak:

Section "InputClass" Identifier "Logitech Media Keyboard Elite" MatchIsKeyboard "on" MatchDevicePath "/dev/input/event*" Driver "evdev" Option "XkbModel""logimel" Option "XkbLayout""pl"

Option "XkbVariant"""

Option "XkbOptions""lv3:ralt_switch,compose:rctrl,terminate:ctrl_alt_bksp" EndSection

Powyższą zawartość trzeba umieścić np. w /etc/X11/xorg.conf.d/10-keyboard.conf . Jeśli mamy inną klawiaturę, musimy dowiedzieć się jakie wartości powpisywać do powyższego pliku.

XkbModel można wyciągnąć z pliku /usr/share/X11/xkb/rules/xorg.lst znając oczywiście model klawiatury , zaś XkbLayout można odszukać w /usr/share/X11/xkb/symbols/ , w przypadku polskiego układu, jest to pl .

Jeśli chodzi o debianowy sposób, ten z konfiguracją pakietu keyboard-configuration , to w przeciwieństwie do tego powyżej nie musimy ręcznie uzupełniać pliku. Po wydaniu polecenia:

dpkg-reconfigure keyboard-configuration

zostaniemy po prostu poproszeni o wybranie szeregu parametrów dla naszej klawiatury i tu już raczej nie powinno być problemów co do tego jaki model klawiatury należy wybrać, bo prawdopodobnie jego nazwa widnieje na liście.

  1. Błędy Xservera

Samo wybranie modelu powinno rozwiązać większość problemów. Jednak bywają przypadki kiedy nie wszystkie klawisze działają tak jakbyśmy tego chcieli, a niektóre nawet wcale nie są wykrywane. Zanim jednak przejdziemy do ich przemapowania, w moim przypadku Xserver wyrzucił mi kilka błędów, niby nie są to jakieś krytyczne sprawy ale przydało by się je wyeliminować.

Błędy można zaobserwować albo w logach Xservera, w pliku /var/log/Xorg.0.log albo w pliku błędów sesji zlokalizowanym w katalogu domowym -- plik /home/morfik/.xsession-errors . Nie wszędzie i nie zawsze te błędy będą widoczne, np. w przypadku posiadania graficznego menadżera logowania, część z tych błędów może, albo zostać wyeliminowana, albo ukryta, dokładnie nie wiem, w każdym razie mogą nie być widoczne. Ja podnoszę Xserver przez zwykłe startx i u mnie w logu sesji mam poniższe komunikaty:

The XKEYBOARD keymap compiler (xkbcomp) reports: > Error: Meta_L added to symbol map for multiple modifiers > Using Mod4, ignoring Mod1. > Error: Key <META> added to map for multiple modifiers > Using Mod4, ignoring Mod1. > Warning: Type "ONE_LEVEL" has 1 levels, but <RALT> has 2 symbols > Ignoring extra symbols Errors from xkbcomp are not fatal to the X server The XKEYBOARD keymap compiler (xkbcomp) reports: > Warning: Compat map for group 2 redefined > Using new definition > Warning: Compat map for group 3 redefined > Using new definition > Warning: Compat map for group 4 redefined > Using new definition Errors from xkbcomp are not fatal to the X server

By poprawić te błędy, trzeba wyedytować plik /usr/share/X11/xkb/symbols/level3 i wykomentować poniższe dwie linijki:

// type[Group1]="ONE_LEVEL", // symbols[Group1] = [ ISO_Level3_Shift ]

Pod nimi trzeba dopisać poniższe dwie:

 type[Group1]="TWO_LEVEL",
 symbols[Group1] = [ ISO_Level3_Shift, ISO_Level3_Shift ]

W ten sposób pozbędziemy się błędu z RALT, który służy do wstawiania polskich znaków.

By pozbyć się pozostałych błędów, trzeba wykomentować 3 linijki w pliku /usr/share/X11/xkb/compat/basic :

// group 2 = AltGr; // group 3 = AltGr; // group 4 = AltGr;

Po powyższych operacjach, te błędy, które zostały zalogowane w pliku błędów sesji, powinny zniknąć.

  1. SCANCODE, KEYCODE oraz KEYSYM

Ja posiadam klawiaturę Logitech Media Keyboard Elite i w jej przypadku połowa klawiszy dodatkowych zwyczajnie nie działa. By móc ustalić przyczynę, trzeba wiedzieć co się tak naprawdę dzieje po tym jak wciskamy klawisz na klawiaturze. Są generalnie trzy terminy, z którymi można się spotkać: SCANCODE, KEYCODE oraz KEYSYM.

SCANCODE jest to kod klawisza, który klawiatura przesyła do kernela po przyciśnięciu czegoś na klawiaturze. KEYCODE jest to przemapowany przez kernel SCANCODE -- każdy kernel posiada tablicę z parami KEYCODE-SCANCODE. Jeśli kernel jest w stanie odczytać SCANCODE, powinien wypluć KEYCODE. Z kolei KEYSYM jest tym co my rozpoznajemy jako literki i cyferki lub też inne znaki jakie mamy zwykle nadrukowane na klawiszach naszej klawiatury.

  1. Problemy z showkey i xev

Jest szereg narzędzi, które potrafią odczytać SCANCODE lub/i KEYCODE. Zwykle ludzie używają do tego celu showkey . Jednak jest bardzo duże prawdopodobieństwo, że znajdziemy się w takiej sytuacji gdzie klawisz będzie miał KEYCODE, a nie będzie miał przy tym SCANCODE. Czyli to by było tak jakby klawiatura nie wysłała żadnego sygnału do kernela, a ten jakimś cudem potrafił go zidentyfikować. Tak było z klawiszami na mojej klawiaturze.

Innym narzędzie szeroko rozpowszechnionym i też przy tym dość często używanym jest xev . Podobnie jak poprzednik, nie jest pozbawiony wad, a ma ich dość sporo. Przede wszystkim wypluwa złe kody. Dla przykładu, jeśli wklepiemy poniższą linijkę do terminala:

$ xev | grep -A2 --line-buffered '^KeyRelease' | sed -n '/keycode /s/^.keycode ([0-9]).* (.*, (.)).$/\1 \2/p'

po wciśnięciu klawisza a dostaniemy:

38 a

Co w tym dziwnego? Mamy KEYCODE oraz odpowiadający mu znak. No nie do końca. Jeśli byśmy skorzystali z showkey:

showkey --keycode

akeycode 30 press keycode 30 release

mamy inny KEYCODE. Komu wierzyć? Xserver potrafi obsłużyć niezbyt wygórowaną liczbę KEYCODE -- wynosi ona 255. Z jakichś powodów pierwsze 8 kodów (0-7) jest zarezerwowanych. Tak więc do dyspozycji mamy znaki od 8 do 255 włącznie i to co xev rozumie pod znakiem 38, w rzeczywistości nie ma kodu 38, a 30. Dodatkowo kod 8 i 255 również są zarezerwowane, czyniąc tym samym kod 9 pierwszym możliwym, który możemy przypisać -- domyślnie jest on przeznaczony dla klawisza ESC. I tak w showkey ESC jest widziany jako 1, w xev zaś jako 9. Jeśli ktoś chce korzystać z xev, musi pamiętać by odjąć 8 od wartości KEYCODE zwracanej przez ten program.

Problem z podbijaniem numerków przez xev to nie jedyna z jego wad -- inną jest to, że czasami nie podaje on zupełnie żadnego KEYCODE i tak było też w moim przypadku. Nawet po przemapowaniu klawiszy, xev nie zwraca żadnego KEYCODE po przyciśnięciu tych klawiszy. Jednym słowem xev ssie.

  1. Błędne wartości SCANCODE

Szukając czegoś na temat SCANCODE, natknąłem się na informację, że czasami kernel może zwracać złe wartości SCANCODE oraz iż można dopisać do linijki kernela w extlinux czy grubie odpowiedni parametr by to przekłamanie kernela naprawić.

atkbd.softraw=0

  1. Narzędzie evtest

Jak nie showkey i nie xev to jaka pozostaje nam alternatywa? Na szczęście nie jest tak źle jakby mogło się wydawać. Mamy jeszcze w zanadrzu pakiet evtest . Zainstalujmy i odpalmy go:

evtest

No device specified, trying to scan all of /dev/input/event* Available devices: /dev/input/event0: Logitech Logitech USB Keyboard /dev/input/event1: Logitech Logitech USB Keyboard /dev/input/event2: Power Button /dev/input/event3: Power Button /dev/input/event4: PC Speaker /dev/input/event5: A4Tech USB Mouse /dev/input/event6: ACPI Virtual Keyboard Device Select the device event number [0-6]:

Jak widzimy, zostały przeskanowane wszystkie urządzenia w katalogu /dev/input i jak możemy również zauważyć event0 oraz event1 są od mojej klawiatury. Pytanie się nasuwa: czemu są dwa, a nie jeden, przecie klawiatura jest tylko jedna. Do końca nie wiem jak to wygląda na innych klawiaturach ale w przypadku tej, pierwsza pozycja (event0) odpowiada za zwykłe klawisze, druga zaś (event1) za klawisze multimedialne. Jako, że mi nie działa tylko połowa klawiszy multimedialnych, będę korzystał z urządzenia event1.

Poniżej jest przedstawione przykładowe wyjście programu evtest:

evtest

No device specified, trying to scan all of /dev/input/event* Available devices: /dev/input/event0: Logitech Logitech USB Keyboard /dev/input/event1: Logitech Logitech USB Keyboard /dev/input/event2: Power Button /dev/input/event3: Power Button /dev/input/event4: PC Speaker /dev/input/event5: A4Tech USB Mouse /dev/input/event6: ACPI Virtual Keyboard Device Select the device event number [0-6]: 0 Input driver version is 1.0.1 Input device ID: bus 0x3 vendor 0x46d product 0xc30f version 0x110 Input device name: "Logitech Logitech USB Keyboard" Supported events: Event type 0 (EV_SYN) Event type 1 (EV_KEY) Event code 1 (KEY_ESC) Event code 2 (KEY_1) Event code 3 (KEY_2) Event code 4 (KEY_3) Event code 5 (KEY_4) Event code 6 (KEY_5) Event code 7 (KEY_6) Event code 8 (KEY_7) Event code 9 (KEY_8) Event code 10 (KEY_9) Event code 11 (KEY_0) Event code 12 (KEY_MINUS) Event code 13 (KEY_EQUAL) Event code 14 (KEY_BACKSPACE) Event code 15 (KEY_TAB) Event code 16 (KEY_Q) Event code 17 (KEY_W) Event code 18 (KEY_E) Event code 19 (KEY_R) Event code 20 (KEY_T) Event code 21 (KEY_Y) Event code 22 (KEY_U) Event code 23 (KEY_I) Event code 24 (KEY_O) Event code 25 (KEY_P) Event code 26 (KEY_LEFTBRACE) Event code 27 (KEY_RIGHTBRACE) Event code 28 (KEY_ENTER) Event code 29 (KEY_LEFTCTRL) Event code 30 (KEY_A) Event code 31 (KEY_S) Event code 32 (KEY_D) Event code 33 (KEY_F) Event code 34 (KEY_G) Event code 35 (KEY_H) Event code 36 (KEY_J) Event code 37 (KEY_K) Event code 38 (KEY_L) Event code 39 (KEY_SEMICOLON) Event code 40 (KEY_APOSTROPHE) Event code 41 (KEY_GRAVE) Event code 42 (KEY_LEFTSHIFT) Event code 43 (KEY_BACKSLASH) Event code 44 (KEY_Z) Event code 45 (KEY_X) Event code 46 (KEY_C) Event code 47 (KEY_V) Event code 48 (KEY_B) Event code 49 (KEY_N) Event code 50 (KEY_M) Event code 51 (KEY_COMMA) Event code 52 (KEY_DOT) Event code 53 (KEY_SLASH) Event code 54 (KEY_RIGHTSHIFT) Event code 55 (KEY_KPASTERISK) Event code 56 (KEY_LEFTALT) Event code 57 (KEY_SPACE) Event code 58 (KEY_CAPSLOCK) Event code 59 (KEY_F1) Event code 60 (KEY_F2) Event code 61 (KEY_F3) Event code 62 (KEY_F4) Event code 63 (KEY_F5) Event code 64 (KEY_F6) Event code 65 (KEY_F7) Event code 66 (KEY_F8) Event code 67 (KEY_F9) Event code 68 (KEY_F10) Event code 69 (KEY_NUMLOCK) Event code 70 (KEY_SCROLLLOCK) Event code 71 (KEY_KP7) Event code 72 (KEY_KP8) Event code 73 (KEY_KP9) Event code 74 (KEY_KPMINUS) Event code 75 (KEY_KP4) Event code 76 (KEY_KP5) Event code 77 (KEY_KP6) Event code 78 (KEY_KPPLUS) Event code 79 (KEY_KP1) Event code 80 (KEY_KP2) Event code 81 (KEY_KP3) Event code 82 (KEY_KP0) Event code 83 (KEY_KPDOT) Event code 85 (KEY_ZENKAKUHANKAKU) Event code 86 (KEY_102ND) Event code 87 (KEY_F11) Event code 88 (KEY_F12) Event code 89 (KEY_RO) Event code 90 (KEY_KATAKANA) Event code 91 (KEY_HIRAGANA) Event code 92 (KEY_HENKAN) Event code 93 (KEY_KATAKANAHIRAGANA) Event code 94 (KEY_MUHENKAN) Event code 95 (KEY_KPJPCOMMA) Event code 96 (KEY_KPENTER) Event code 97 (KEY_RIGHTCTRL) Event code 98 (KEY_KPSLASH) Event code 99 (KEY_SYSRQ) Event code 100 (KEY_RIGHTALT) Event code 102 (KEY_HOME) Event code 103 (KEY_UP) Event code 104 (KEY_PAGEUP) Event code 105 (KEY_LEFT) Event code 106 (KEY_RIGHT) Event code 107 (KEY_END) Event code 108 (KEY_DOWN) Event code 109 (KEY_PAGEDOWN) Event code 110 (KEY_INSERT) Event code 111 (KEY_DELETE) Event code 113 (KEY_MUTE) Event code 114 (KEY_VOLUMEDOWN) Event code 115 (KEY_VOLUMEUP) Event code 116 (KEY_POWER) Event code 117 (KEY_KPEQUAL) Event code 119 (KEY_PAUSE) Event code 121 (KEY_KPCOMMA) Event code 122 (KEY_HANGUEL) Event code 123 (KEY_HANJA) Event code 124 (KEY_YEN) Event code 125 (KEY_LEFTMETA) Event code 126 (KEY_RIGHTMETA) Event code 127 (KEY_COMPOSE) Event code 128 (KEY_STOP) Event code 129 (KEY_AGAIN) Event code 130 (KEY_PROPS) Event code 131 (KEY_UNDO) Event code 132 (KEY_FRONT) Event code 133 (KEY_COPY) Event code 134 (KEY_OPEN) Event code 135 (KEY_PASTE) Event code 136 (KEY_FIND) Event code 137 (KEY_CUT) Event code 138 (KEY_HELP) Event code 183 (KEY_F13) Event code 184 (KEY_F14) Event code 185 (KEY_F15) Event code 186 (KEY_F16) Event code 187 (KEY_F17) Event code 188 (KEY_F18) Event code 189 (KEY_F19) Event code 190 (KEY_F20) Event code 191 (KEY_F21) Event code 192 (KEY_F22) Event code 193 (KEY_F23) Event code 194 (KEY_F24) Event code 240 (KEY_UNKNOWN) Event type 4 (EV_MSC) Event code 4 (MSC_SCAN) Event type 17 (EV_LED) Event code 0 (LED_NUML) Event code 1 (LED_CAPSL) Event code 2 (LED_SCROLLL) Event code 3 (LED_COMPOSE) Event code 4 (LED_KANA) Properties: Property type 20 (EV_REP) Property code 0 (REP_DELAY) Value 250 Property code 1 (REP_PERIOD) Value 33 Testing ... (interrupt to exit) Event: time 1396640460.310836, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70028 Event: time 1396640460.310836, type 1 (EV_KEY), code 28 (KEY_ENTER), value 0 Event: time 1396640460.310836, -------------- SYN_REPORT ------------ Event: time 1396640461.998826, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70004 Event: time 1396640461.998826, type 1 (EV_KEY), code 30 (KEY_A), value 1 Event: time 1396640461.998826, -------------- SYN_REPORT ------------ aEvent: time 1396640462.102821, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70004 Event: time 1396640462.102821, type 1 (EV_KEY), code 30 (KEY_A), value 0 Event: time 1396640462.102821, -------------- SYN_REPORT ------------

Jak widzimy, spora część logu to klawisze, które aktualnie są przypisane, czyli zwykła mapa klawiatury. Na samym dole mamy wciśnięty klawisz a. Mamy trochę info, w tym też code 30 . Zatem program zdaje się wypisywać aktualnie przypisane klawisze oraz zwraca poprawne kody. Pamiętać trzeba, że drugi event może mieć również przypisane pewne klawisze. Jeśli poddamy testowi drugie urządzenie, zobaczymy, że KEYCODE niektórych klawiszy mają dość spore wartości:

evtest

No device specified, trying to scan all of /dev/input/event* Available devices: /dev/input/event0: Logitech Logitech USB Keyboard /dev/input/event1: Logitech Logitech USB Keyboard /dev/input/event2: Power Button /dev/input/event3: Power Button /dev/input/event4: PC Speaker /dev/input/event5: A4Tech USB Mouse /dev/input/event6: ACPI Virtual Keyboard Device Select the device event number [0-6]: 1 Input driver version is 1.0.1 Input device ID: bus 0x3 vendor 0x46d product 0xc30f version 0x110 Input device name: "Logitech Logitech USB Keyboard" Supported events: Event type 0 (EV_SYN) Event type 1 (EV_KEY) Event code 113 (KEY_MUTE) Event code 114 (KEY_VOLUMEDOWN) Event code 115 (KEY_VOLUMEUP) Event code 116 (KEY_POWER) Event code 131 (KEY_UNDO) Event code 138 (KEY_HELP) Event code 140 (KEY_CALC) Event code 142 (KEY_SLEEP) Event code 143 (KEY_WAKEUP) Event code 155 (KEY_MAIL) Event code 156 (KEY_BOOKMARKS) Event code 158 (KEY_BACK) Event code 159 (KEY_FORWARD) Event code 163 (KEY_NEXTSONG) Event code 164 (KEY_PLAYPAUSE) Event code 165 (KEY_PREVIOUSSONG) Event code 166 (KEY_STOPCD) Event code 168 (KEY_REWIND) Event code 171 (KEY_CONFIG) Event code 172 (KEY_HOMEPAGE) Event code 182 (KEY_REDO) Event code 208 (KEY_FASTFORWARD) Event code 210 (KEY_PRINT) Event code 217 (KEY_SEARCH) Event code 234 (KEY_SAVE) Event code 319 (?) Event code 328 (BTN_TOOL_QUINTTAP) Event code 329 (?) Event code 330 (BTN_TOUCH) Event code 331 (BTN_STYLUS) Event code 418 (KEY_ZOOMIN) Event code 419 (KEY_ZOOMOUT) Event code 420 (KEY_ZOOMRESET) Event code 421 (KEY_WORDPROCESSOR) Event code 423 (KEY_SPREADSHEET) Event code 425 (KEY_PRESENTATION) Event code 430 (KEY_MESSENGER) Event type 4 (EV_MSC) Event code 4 (MSC_SCAN) Properties: Testing ... (interrupt to exit) Event: time 1396640828.951618, type 4 (EV_MSC), code 4 (MSC_SCAN), value c022d Event: time 1396640828.951618, type 1 (EV_KEY), code 418 (KEY_ZOOMIN), value 1 Event: time 1396640828.951618, -------------- SYN_REPORT ------------ Event: time 1396640829.143618, type 4 (EV_MSC), code 4 (MSC_SCAN), value c022d Event: time 1396640829.143618, type 1 (EV_KEY), code 418 (KEY_ZOOMIN), value 0 Event: time 1396640829.143618, -------------- SYN_REPORT ------------ Event: time 1396640830.231616, type 4 (EV_MSC), code 4 (MSC_SCAN), value c022e Event: time 1396640830.231616, type 1 (EV_KEY), code 419 (KEY_ZOOMOUT), value 1 Event: time 1396640830.231616, -------------- SYN_REPORT ------------ Event: time 1396640830.359616, type 4 (EV_MSC), code 4 (MSC_SCAN), value c022e Event: time 1396640830.359616, type 1 (EV_KEY), code 419 (KEY_ZOOMOUT), value 0 Event: time 1396640830.359616, -------------- SYN_REPORT ------------

Jak widzimy, część z klawiszy ma kod > 255, dlatego one nie działają. Problem w tym, że by przemapować kernelowskie KEYCODE, czyli zmienić ich numerki na niższe (te < 255), musimy znać SCANCODE klawisza na klawiaturze.

W uzyskaniu SCANCODE pomoże nam /lib/udev/keymap . By ustalić jakie urządzenie chcemy monitorować, możemy albo wyciągnąć jedno z evtest albo skorzystać z /lib/udev/findkeyboards . Choć to narzędzie też trochę ssie i nie zawsze potrafi wskazać to czego szukamy. Dla przykładu, u mnie nie wykrył urządzenia event1 :

/lib/udev/findkeyboards

USB keyboard: input/event0 Unknown type: input/event6

W każdym razie, w tym przypadku musimy zbadać urządzenie input/event1 :

/lib/udev/keymap -i input/event1

Press ESC to finish, or Control-C if this device is not your primary keyboard scan code: 0xC022D key code: zoomin scan code: 0xC022E key code: zoomout

Bingo! Mamy SCANCODE niedziałających klawiszy -- tych co mają KEYCODE > 255.

Teraz musimy przemapować te klawisze. Do tego celu wykorzystamy udev oraz narzędzie keymap. Musimy napisać regułkę dla naszej klawiatury. Jeśli ktoś jeszcze nie czytał mojego artykułu na temat udeva, znajdzie go pod tym linkiem.

Zanim jednak się weźmiemy do pisania reguły dla udeva, stwórzmy plik, którego zawartość składać się będzie z dwóch kolumn, w jednej będzie SCANCODE, a w drugiej nowy KEYCODE. W moim przypadku to wygląda tak:

/usr/include/linux/input.h

0xC01BC CHAT 0xC022D PROG3 0xC022E PROG4 0x90040 FINANCE 0xC0184 SPORT 0xC0186 SHOP 0xC0188 F14 0x90049 F15 0x9004A F16 0x9004B F17 0x9004C F18

Uzupełnienie pierwszej kolumny raczej nie powinno stanowić problemu. Dane, które trzeba wpisać do drugiej kolumny musimy odczytać z pliku /usr/include/linux/input.h . Dla przykładu:

define KEY_PROG3 202

define KEY_PROG4 203

KEYCODE dla PROG3 oraz PROG4, które zostały wykorzystane powyżej, posiadają numerki 202 oraz 203. Trzeba teraz wrócić do evtest i sprawdzić, które KEYCODE nie są zajęte. Z reguły te powyżej 200 są wolne.

W moim przypadku, kernel przypisał KEYCODE do paru nieistniejących klawiszy, także jeśli nie jesteśmy pewni jakie numerki wybrać, to najlepiej powciskać wszystkich klawisze na klawiaturze i pospisywać każdy KEYCODE.

Jeśli już wypełniliśmy plik z nowym mapowaniem, tworzymy regułę dla udeva w /etc/udev/rules.d/95-keymap-media-keyboard-elite.rules :

KERNEL=="event*", ACTION=="add", SUBSYSTEM=="input", SUBSYSTEMS=="usb", ENV{ID_VENDOR_ID}=="046d", ENV{ID_MODEL_ID}=="c30f", RUN+="/lib/udev/keymap $name /lib/udev/keymaps/logitech-media-keyboard-elite"

Większość opcji będzie taka sama, za wyjątkiem ścieżki do pliku z mapowaniem oraz zmiennych ENV{ID_VENDOR_ID} i ENV{ID_MODEL_ID} . By uzyskać wartości dla tych zmiennych, odpalamy udevadm :

udevadm info /dev/input/event0

P: /devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/input/input10/event0 N: input/event0 S: input/by-id/usb-Logitech_Logitech_USB_Keyboard-event-kbd S: input/by-path/pci-0000:00:1d.1-usb-0:1:1.0-event-kbd E: BACKSPACE=guess E: DEVLINKS=/dev/input/by-id/usb-Logitech_Logitech_USB_Keyboard-event-kbd /dev/input/by-path/pci-0000:00:1d.1-usb-0:1:1.0-event-kbd E: DEVNAME=/dev/input/event0 E: DEVPATH=/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/input/input10/event0 E: ID_BUS=usb E: ID_INPUT=1 E: ID_INPUT_KEY=1 E: ID_INPUT_KEYBOARD=1 E: ID_MODEL=Logitech_USB_Keyboard E: ID_MODEL_ENC=Logitech\x20USB\x20Keyboard E: ID_MODEL_ID=c30f E: ID_PATH=pci-0000:00:1d.1-usb-0:1:1.0 E: ID_PATH_TAG=pci-0000_00_1d_1-usb-0_1_1_0 E: ID_REVISION=2300 E: ID_SERIAL=Logitech_Logitech_USB_Keyboard E: ID_TYPE=hid E: ID_USB_DRIVER=usbhid E: ID_USB_INTERFACES=:030101:030000: E: ID_USB_INTERFACE_NUM=00 E: ID_VENDOR=Logitech E: ID_VENDOR_ENC=Logitech E: ID_VENDOR_ID=046d E: MAJOR=13 E: MINOR=64 E: SUBSYSTEM=input E: USEC_INITIALIZED=350329788 E: XKBLAYOUT=pl E: XKBMODEL=logimel E: XKBOPTIONS=lv3:ralt_switch,compose:rctrl,terminate:ctrl_alt_bksp

Zapisujemy regułę i testujemy ją:

udevadm test /devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/input/input10/event0

... read rules file: /etc/udev/rules.d/95-keymap-media-keyboard-elite.rules ... RUN '/lib/udev/keymap $name /lib/udev/keymaps/logitech-media-keyboard-elite' /etc/udev/rules.d/95-keymap-media-keyboard-elite.rules:1 ... run: '/lib/udev/keymap input/event0 /lib/udev/keymaps/logitech-media-keyboard-elite'

Jeśli z jakichś powodów coś nie działa jak należy, można spróbować posłużyć się udevd z opcją --debug . U mnie niby wszystko działa jak należy ale keymap zwraca szereg błędów:

/lib/udev/keymap /dev/input/by-id/usb-Logitech_Logitech_USB_Keyboard-event-kbd /lib/udev/keymaps/logitech-media-keyboard-elite

EVIOCGKEYCODE for scan code 0xc01bc: Invalid argument EVIOCGKEYCODE for scan code 0xc022d: Invalid argument EVIOCGKEYCODE for scan code 0xc022e: Invalid argument EVIOCGKEYCODE for scan code 0x90040: Invalid argument EVIOCGKEYCODE for scan code 0xc0184: Invalid argument EVIOCGKEYCODE for scan code 0xc0186: Invalid argument EVIOCGKEYCODE for scan code 0xc0188: Invalid argument EVIOCGKEYCODE for scan code 0x90049: Invalid argument EVIOCGKEYCODE for scan code 0x9004a: Invalid argument EVIOCGKEYCODE for scan code 0x9004b: Invalid argument EVIOCGKEYCODE for scan code 0x9004c: Invalid argument

KEYCODE precyzowane w /lib/udev/keymaps/logitech-media-keyboard-elite mogą mieć postać nazwy -- CHAT , mogą być także zapisane, albo w systemie dziesiętnym -- 216, albo szesnastkowym -- 0xD8 . Nie ważne co tam wpiszę i tak wyrzuca ten sam komunikat.

  1. Problemy z nowszą wersją udeva

Natknąłem się na informację, że w nowszych wersjach udeva, prawdopodobnie > 206 , /lib/udev/keymap nie będzie używany. Od teraz mapowanie klawiatury będzie trzymane w bazie danych udeva. Jeśli posiadamy udeva w wersji 206 lub nowszej, trzeba stworzyć plik /etc/udev/hwdb.d/60-keyboard.hwdb o treści podobnej do tej poniżej:

keyboard:usb:v046dpc30f* KEYBOARD_KEY_c01bc=chat KEYBOARD_KEY_c022d=prog3 KEYBOARD_KEY_c022e=prog4 KEYBOARD_KEY_90040=finance KEYBOARD_KEY_c0184=sport KEYBOARD_KEY_c0186=shop KEYBOARD_KEY_c0188=f14 KEYBOARD_KEY_90049=f15 KEYBOARD_KEY_9004a=f16 KEYBOARD_KEY_9004b=f17 KEYBOARD_KEY_9004c=f18

W pierwszej linijce zawsze występuje keyboard:usb: . Potem mamy dwa numerki zaczynające się od v oraz p czyli v046d oraz pc30f i na końcu * . Te dwa numerki są to: idVendor=046d oraz idProduct=c30f , które wyciągnęliśmy wcześniej. Mapowanie klawiszy sprowadza się do podania SCANCODE bez 0x , czyli zamiast 0xc01bc należy podać c01bc oraz KEYCODE, w tym przypadku jest to nazwa zapisana z małych liter -- chat .

Następnie trzeba przeładować bazę danych udeva przy pomocy:

udevadm hwdb --update

Klawisze powinny być widoczne po ponownym podłączeniu klawiatury.

Obecnie w debianie udev jest w wersji 204 i powyższe mapowanie klawiszy via pliki hwdb nie działa, przynajmniej u mnie. Być może jest to za sprawą systemd, bo jakby nie patrzeć udev został połączony z nim, a ja nie posiadam systemd. Inną przyczyną może być brak pliku /etc/udev/hwdb.bin , który to powinien zostać wygenerowany przy wydawaniu polecenia udevadm hwdb --update . Z tego co wyczytałem, ten plik jest na pewno dostępny w wersji udeva 208. Także może ten sposób z hwdb będzie działał gdy udev w debianie zostanie zaktualizowany do nowszej wersji.

Natknąłem się też na info, że po aktualizacji udeva z wersji 204, ten poprzedni sposób od mapowania klawiatury może zwyczajnie przestać działać i trzeba będzie przejść na pliki hwdb.

Jak zaktualizować Linux Mint Debian 201403? [aktualizacja 14.04]

$
0
0

Linux Mint Debian Edition korzysta z własnych repozytoriów oparty o Debian w wersji testowej. Tworząc tzw. update packi, czyli kopię repozytoriów z danego dnia. Są one wydawane średnio raz na 3 miesiące. Jako osoba związana dość bardzo z projektem Debian uważam, że jest to straszny błąd, ponieważ gałąź testowa jak przystało na nazwę może zawierać bądź zawiera błędy. Zablokowanie powoduje, że odcinamy się od poprawek pakietów. Gdy tworzyliśmy system w pierwszej wersji miał on korzystać z głównych repozytoriów, lecz później historia potoczyła się inaczej.

Oczywiście można obejść tą sytuacje.

Aktualizacja systemu w oparciu o repozytoria Debian Testing:

Jeśli chcemy mieć system taki jakie było do niego założenia należy go zaktualizować do wersji testowej. Zaczynamy jak wyżej od edycji repozytorium. Podam pełny zapis jak ma wyglądać, będzie prościej:

1/ Edytujemy plik z wpisami repozytorium np. tak:

sudo nano /etc/apt/sources.list.d/official-package-repositories.list

zastępujemy takie lub podobne wpisy (mogą się różnić serwerami lustrzanymi):

deb http://packages.linuxmint.com debian main upstream import

deb http://debian.linuxmint.com/latest/ testing main contrib non-free deb http://debian.linuxmint.com/latest/security testing/updates main contrib no$ deb http://debian.linuxmint.com/latest/multimedia testing main non-free

deb http://extra.linuxmint.com debian main

Dla edycji Mate na:

deb http://packages.linuxmint.com/ debian import main upstream backport romeo deb http://extra.linuxmint.com debian main deb http://http.debian.net/debian/ testing main contrib non-free deb http://security.debian.org/ testing/updates main contrib non-free deb http://www.deb-multimedia.org/ testing main non-free deb http://repo.mate-desktop.org/debian jessie main

Dla edycji Cinnamon na: deb http://packages.linuxmint.com/ debian import main upstream backport romeo deb http://extra.linuxmint.com debian main deb http://http.debian.net/debian/ testing main contrib non-free deb http://security.debian.org/ testing/updates main contrib non-free deb http://www.deb-multimedia.org/ testing main non-free deb http://repo.dug.net.pl/mint debian main

W przypadku nano zapisujemy plik kombinacją klawiszy Ctrl + o i wychodzi z programu Ctrl + x.

2/ Usuwamy preferencje dla repozytoriów: sudo rm /etc/apt/preferences.d/official-package-repositories.pref 3/ Aktualizujemy listę repozytoriów: sudo apt-get update

4/ Dla edycji Mate: Wgrywamy nowe klucze publiczne i aktualizujemy ponownie listę: sudo apt-get --yes --quiet --allow-unauthenticated install mate-archive-keyring sudo apt-get update

5/ Przeprowadzamy pełną aktualizacje systemu: sudo apt-get dist-upgrade

i od tego momentu mamy system ciągły, z aktualizacjami codziennymi oraz błędami naprawianymi na bieżąco.

Viewing all 160 articles
Browse latest View live