Hoe u de gebruikersmodus in Linux kunt gebruiken

Inleiding van de vertaler: Tegen de achtergrond van de massale intrede in ons leven van verschillende soorten containers, kan het heel interessant en nuttig zijn om erachter te komen met welke technologieën het ooit allemaal begon. Sommigen van hen kunnen tot op de dag van vandaag nuttig worden gebruikt, maar niet iedereen herinnert zich dergelijke methoden (of weet of ze niet zijn betrapt tijdens hun snelle ontwikkeling). Een van die technologieën is User Mode Linux. De auteur van het origineel heeft veel gegraven, uitzoeken welke van de oude ontwikkelingen nog steeds werken en welke niet, en stelde zoiets als een stapsgewijze instructie samen over hoe je in 2k19 een zelfgebouwde UML kunt krijgen. En ja, we hebben de auteur van het oorspronkelijke bericht uitgenodigd voor Habr Cadey, dus als je vragen hebt, stel ze dan in het Engels in de comments.

Hoe u de gebruikersmodus in Linux kunt gebruiken

Gebruikersmodus in Linux is in feite een poort van de Linux-kernel naar zichzelf. Deze modus stelt je in staat om een ​​volledige Linux-kernel als gebruikersproces uit te voeren en wordt vaak door ontwikkelaars gebruikt om stuurprogramma's te testen. Maar deze modus is ook nuttig als algemene isolatietool, waarvan het principe vergelijkbaar is met de werking van virtuele machines. Deze modus biedt meer isolatie dan Docker, maar minder dan een volwaardige virtuele machine zoals KVM of Virtual Box.

Over het algemeen lijkt de gebruikersmodus misschien een vreemd en moeilijk hulpmiddel om te gebruiken, maar het heeft nog steeds zijn toepassingen. Dit is tenslotte een volwaardige Linux-kernel die wordt uitgevoerd door een onbevoegde gebruiker. Met deze functie kan mogelijk niet-vertrouwde code worden uitgevoerd zonder enige bedreiging voor de hostcomputer. En aangezien dit een volwaardige kernel is, zijn de processen geïsoleerd van de hostmachine processen die in de gebruikersmodus worden uitgevoerd, zijn niet zichtbaar voor de host. Dit is niet zoals de gebruikelijke Docker-container, in welk geval de hostmachine altijd de processen in de repository ziet. Kijk naar dit stukje pstree van een van mijn servers:

containerd─┬─containerd-shim─┬─tini─┬─dnsd───19*[{dnsd}]
           │                 │      └─s6-svscan───s6-supervise
           │                 └─10*[{containerd-shim}]
           ├─containerd-shim─┬─tini─┬─aerial───21*[{aerial}]
           │                 │      └─s6-svscan───s6-supervise
           │                 └─10*[{containerd-shim}]
           ├─containerd-shim─┬─tini─┬─s6-svscan───s6-supervise
           │                 │      └─surl
           │                 └─9*[{containerd-shim}]
           ├─containerd-shim─┬─tini─┬─h───13*[{h}]
           │                 │      └─s6-svscan───s6-supervise
           │                 └─10*[{containerd-shim}]
           ├─containerd-shim─┬─goproxy───14*[{goproxy}]
           │                 └─9*[{containerd-shim}]
           └─32*[{containerd}]

En vergelijk dit met de pstree van de Linux-kernel in gebruikersmodus:

linux─┬─5*[linux]
      └─slirp

Wanneer ik met Docker-containers werk, kan ik van de host de namen zien van de processen die in de gast worden uitgevoerd. Met de Linux-gebruikersmodus is dit niet mogelijk. Wat betekent het? Dit betekent dat monitoringtools die door het auditing-subsysteem van Linux lopen niet kunnen zien processen die in het gastsysteem worden uitgevoerd. Maar in sommige situaties kan deze functie een tweesnijdend zwaard worden.

Over het algemeen is het hele bericht hieronder een verzameling van onderzoek en ruwe pogingen om het gewenste resultaat te bereiken. Om dit te doen, moest ik verschillende oude tools gebruiken, de kernelbronnen lezen, intensief debuggen van code die was geschreven in de tijd dat ik nog op de basisschool zat, en ook sleutelen aan Heroku-builds met behulp van een speciaal binair bestand om de tools te vinden die ik nodig had . Door al dit werk noemden de jongens op mijn IRC me magie. Ik hoop dat dit bericht dient als betrouwbare documentatie voor iemand die hetzelfde probeert met nieuwere kernels en OS-versies.

afstelling

Het instellen van de Linux-gebruikersmodus gebeurt in verschillende stappen:

  • afhankelijkheden op de host installeren;
  • het downloaden van de Linux-kernel;
  • kernel build-configuratie;
  • kernel montage;
  • binaire installatie;
  • configureren van het gastbestandssysteem;
  • selectie van parameters voor het starten van de kernel;
  • opzetten van een gastnetwerk;
  • het starten van de gastkernel.

Ik neem aan dat als je besluit het zelf te doen, je hoogstwaarschijnlijk alles zult doen wat wordt beschreven in een Ubuntu- of Debian-achtig systeem. Ik heb geprobeerd al het bovenstaande te implementeren in mijn favoriete distributie - Alpine, maar er kwam niets van terecht, blijkbaar vanwege het feit dat de Linux-kernel een hardbindende glibc-ismen heeft voor stuurprogramma's in de gebruikersmodus. Ik ben van plan dit aan stroomopwaarts te melden nadat ik eindelijk het probleem begrijp.

Het installeren van afhankelijkheden op de host

Ubuntu vereist ten minste de volgende pakketten om de Linux-kernel te bouwen (uitgaande van een schone installatie):

- 'build-essential'
- 'flex'
- 'bison'
- 'xz-utils'
- 'wget'
- 'ca-certificates'
- 'bc'
- 'linux-headers'

Je kunt ze installeren met het volgende commando (als root of met sudo):

apt-get -y install build-essential flex bison xz-utils wget ca-certificates bc 
                   linux-headers-$(uname -r)

Merk op dat het uitvoeren van het installatieprogramma voor het Linux-kernelmenu de installatie vereist van libncurses-dev. Zorg ervoor dat het is geïnstalleerd met de volgende opdracht (als root of met sudo):

apt-get -y install libncurses-dev

Kernel downloaden

Bepaal waar u wilt downloaden en bouw vervolgens de kernel. Voor deze bewerking moet u ongeveer 1,3 GB ruimte op de harde schijf toewijzen, dus zorg ervoor dat u deze hebt.

Na ga naar kernel.org en haal de URL op om de nieuwste stabiele kernel te downloaden. Op het moment van schrijven is dit: https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.1.16.tar.xz

Download dit bestand met behulp van 'wget':

wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.1.16.tar.xz

En pak het uit met 'tar':

tar xJf linux-5.1.16.tar.xz

Nu gaan we naar de map die is gemaakt bij het uitpakken van de tarball:

cd linux-5.1.16

Installatie van kernelbuild

Het kernel-buildsysteem is een set Makefiles с veel aangepaste tools en scripts om het proces te automatiseren. Open eerst het interactieve setup-programma:

make ARCH=um menuconfig

Het zal gedeeltelijk een dialoogvenster voor u bouwen en weergeven. Wanneer '[Select]', kunt u configureren met behulp van de spatiebalk of Enter-toetsen. Navigeer zoals gewoonlijk door het venster met de toetsenbordpijlen "omhoog" en "omlaag" en selecteer elementen - "links" of "rechts".

De aanwijzer -> betekent dat u zich in een submenu bevindt, toegankelijk via de Enter-toets. De uitweg is duidelijk door '[Exit]'.

Neem de volgende opties op in '[Select]' en zorg ervoor dat er een '[*]' naast staat:

UML-specific Options:
  - Host filesystem
Networking support (enable this to get the submenu to show up):
  - Networking options:
    - TCP/IP Networking
UML Network devices:
  - Virtual network device
  - SLiRP transport

Dat is alles, u kunt dit venster verlaten door achtereenvolgens '[Exit]'. Zorg ervoor dat u aan het einde wordt gevraagd om de configuratie op te slaan en selecteer '[Yes]'.

Ik raad je aan om na het lezen van dit bericht met de opties voor het bouwen van de kernel te spelen. Door deze experimenten kun je veel leren over het begrijpen van het werk van low-level kernelmechanica en de impact van verschillende vlaggen op de montage ervan.

De kern bouwen

De Linux-kernel is een groot programma dat veel dingen doet. Zelfs met zo'n minimale configuratie op oude hardware kan het behoorlijk wat tijd kosten om te bouwen. Dus bouw de kernel met het volgende commando:

make ARCH=um -j$(nproc)

Waarvoor? Deze opdracht zal onze bouwer vertellen om alle beschikbare CPU-kernen en threads te gebruiken in het bouwproces. Team $(nproc) aan het einde van Build vervangt de uitvoer van de opdracht nproc, die er deel van uitmaakt coreutils in een standaard Ubuntu-build.

Na enige tijd zal onze kernel worden gecompileerd tot een uitvoerbaar bestand ./linux.

Het binaire bestand installeren

Omdat de gebruikersmodus in Linux een regulier binair bestand maakt, kunt u het installeren zoals elk ander hulpprogramma. Hier is hoe ik het deed:

mkdir -p ~/bin
cp linux ~/bin/linux

Het is ook de moeite waard om daar zeker van te zijn ~/bin zit in jouw $PATH:

export PATH=$PATH:$HOME/bin

Het gastbestandssysteem opzetten

Maak een map aan voor het gastbestandssysteem:

mkdir -p $HOME/prefix/uml-demo
cd $HOME/prefix

Open alpinelinux.org en in sectie downloaden zoek de daadwerkelijke downloadlink MINI ROOT FILESYSTEM. Op het moment van schrijven was dit:

http://dl-cdn.alpinelinux.org/alpine/v3.10/releases/x86_64/alpine-minirootfs-3.10.0-x86_64.tar.gz

Download deze tarball met wget:

wget -O alpine-rootfs.tgz http://dl-cdn.alpinelinux.org/alpine/v3.10/releases/x86_64/alpine-minirootfs-3.10.0-x86_64.tar.gz

Voer nu de map van het gastbestandssysteem in en pak het archief uit:

cd uml-demo
tar xf ../alpine-rootfs.tgz

De beschreven acties zullen een kleine sjabloon voor het bestandssysteem maken. Vanwege de aard van het systeem zal het buitengewoon moeilijk zijn om pakketten te installeren via de Alpine apk-manager. Maar deze FS zal voldoende zijn om het algemene idee te evalueren.

We hebben ook een hulpmiddel nodig Tini om het geheugenverbruik te beperken zombie processen onze gastkernel.

wget -O tini https://github.com/krallin/tini/releases/download/v0.18.0/tini-static
chmod +x tini

Een kernel-opdrachtregel maken

De Linux-kernel heeft, net als de meeste andere programma's, opdrachtregelargumenten waartoe toegang kan worden verkregen door de sleutel op te geven --help.

Zelf - help

linux --help
User Mode Linux v5.1.16
        available at http://user-mode-linux.sourceforge.net/

--showconfig
    Prints the config file that this UML binary was generated from.

iomem=<name>,<file>
    Configure <file> as an IO memory region named <name>.

mem=<Amount of desired ram>
    This controls how much "physical" memory the kernel allocates
    for the system. The size is specified as a number followed by
    one of 'k', 'K', 'm', 'M', which have the obvious meanings.
    This is not related to the amount of memory in the host.  It can
    be more, and the excess, if it's ever used, will just be swapped out.
        Example: mem=64M

--help
    Prints this message.

debug
    this flag is not needed to run gdb on UML in skas mode

root=<file containing the root fs>
    This is actually used by the generic kernel in exactly the same
    way as in any other kernel. If you configure a number of block
    devices and want to boot off something other than ubd0, you
    would use something like:
        root=/dev/ubd5

--version
    Prints the version number of the kernel.

umid=<name>
    This is used to assign a unique identity to this UML machine and
    is used for naming the pid file and management console socket.

con[0-9]*=<channel description>
    Attach a console or serial line to a host channel.  See
    http://user-mode-linux.sourceforge.net/old/input.html for a complete
    description of this switch.

eth[0-9]+=<transport>,<options>
    Configure a network device.
    
aio=2.4
    This is used to force UML to use 2.4-style AIO even when 2.6 AIO is
    available.  2.4 AIO is a single thread that handles one request at a
    time, synchronously.  2.6 AIO is a thread which uses the 2.6 AIO
    interface to handle an arbitrary number of pending requests.  2.6 AIO
    is not available in tt mode, on 2.4 hosts, or when UML is built with
    /usr/include/linux/aio_abi.h not available.  Many distributions don't
    include aio_abi.h, so you will need to copy it from a kernel tree to
    your /usr/include/linux in order to build an AIO-capable UML

nosysemu
    Turns off syscall emulation patch for ptrace (SYSEMU).
    SYSEMU is a performance-patch introduced by Laurent Vivier. It changes
    behaviour of ptrace() and helps reduce host context switch rates.
    To make it work, you need a kernel patch for your host, too.
    See http://perso.wanadoo.fr/laurent.vivier/UML/ for further
    information.

uml_dir=<directory>
    The location to place the pid and umid files.

quiet
    Turns off information messages during boot.

hostfs=<root dir>,<flags>,...
    This is used to set hostfs parameters.  The root directory argument
    is used to confine all hostfs mounts to within the specified directory
    tree on the host.  If this isn't specified, then a user inside UML can
    mount anything on the host that's accessible to the user that's running
    it.
    The only flag currently supported is 'append', which specifies that all
    files opened by hostfs will be opened in append mode.

Dit paneel belicht de belangrijkste parameters van de lancering. Laten we de kernel uitvoeren met de minimaal vereiste set opties:

linux 
  root=/dev/root 
  rootfstype=hostfs 
  rootflags=$HOME/prefix/uml-demo 
  rw 
  mem=64M 
  init=/bin/sh

De bovenstaande regels vertellen onze kernel het volgende:

  • Neem aan dat het rootbestandssysteem een ​​pseudo-apparaat is /dev/root.
  • Kiezen hostfs als een driver voor het rootbestandssysteem.
  • Koppel het gastbestandssysteem dat we hebben gemaakt op het root-apparaat.
  • En ja, in lees-schrijfmodus.
  • Gebruik slechts 64 MB RAM (u kunt veel minder gebruiken, afhankelijk van wat u van plan bent te doen, maar 64 MB lijkt de optimale hoeveelheid).
  • De kernel start automatisch /bin/sh hoe init-proces.

Voer deze opdracht uit en u zou zoiets als het volgende moeten krijgen:

Nog een blad

Core dump limits :
        soft - 0
        hard - NONE
Checking that ptrace can change system call numbers...OK
Checking syscall emulation patch for ptrace...OK
Checking advanced syscall emulation patch for ptrace...OK
Checking environment variables for a tempdir...none found
Checking if /dev/shm is on tmpfs...OK
Checking PROT_EXEC mmap in /dev/shm...OK
Adding 32137216 bytes to physical memory to account for exec-shield gap
Linux version 5.1.16 (cadey@kahless) (gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)) #30 Sun Jul 7 18:57:19 UTC 2019
Built 1 zonelists, mobility grouping on.  Total pages: 23898
Kernel command line: root=/dev/root rootflags=/home/cadey/dl/uml/alpine rootfstype=hostfs rw mem=64M init=/bin/sh
Dentry cache hash table entries: 16384 (order: 5, 131072 bytes)
Inode-cache hash table entries: 8192 (order: 4, 65536 bytes)
Memory: 59584K/96920K available (2692K kernel code, 708K rwdata, 588K rodata, 104K init, 244K bss, 37336K reserved, 0K cma-reserved)
SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
NR_IRQS: 15
clocksource: timer: mask: 0xffffffffffffffff max_cycles: 0x1cd42e205, max_idle_ns: 881590404426 ns
Calibrating delay loop... 7479.29 BogoMIPS (lpj=37396480)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 512 (order: 0, 4096 bytes)
Mountpoint-cache hash table entries: 512 (order: 0, 4096 bytes)
Checking that host ptys support output SIGIO...Yes
Checking that host ptys support SIGIO on close...No, enabling workaround
devtmpfs: initialized
random: get_random_bytes called from setup_net+0x48/0x1e0 with crng_init=0
Using 2.6 host AIO
clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
futex hash table entries: 256 (order: 0, 6144 bytes)
NET: Registered protocol family 16
clocksource: Switched to clocksource timer
NET: Registered protocol family 2
tcp_listen_portaddr_hash hash table entries: 256 (order: 0, 4096 bytes)
TCP established hash table entries: 1024 (order: 1, 8192 bytes)
TCP bind hash table entries: 1024 (order: 1, 8192 bytes)
TCP: Hash tables configured (established 1024 bind 1024)
UDP hash table entries: 256 (order: 1, 8192 bytes)
UDP-Lite hash table entries: 256 (order: 1, 8192 bytes)
NET: Registered protocol family 1
console [stderr0] disabled
mconsole (version 2) initialized on /home/cadey/.uml/tEwIjm/mconsole
Checking host MADV_REMOVE support...OK
workingset: timestamp_bits=62 max_order=14 bucket_order=0
Block layer SCSI generic (bsg) driver version 0.4 loaded (major 254)
io scheduler noop registered (default)
io scheduler bfq registered
loop: module loaded
NET: Registered protocol family 17
Initialized stdio console driver
Using a channel type which is configured out of UML
setup_one_line failed for device 1 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 2 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 3 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 4 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 5 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 6 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 7 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 8 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 9 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 10 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 11 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 12 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 13 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 14 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 15 : Configuration failed
Console initialized on /dev/tty0
console [tty0] enabled
console [mc-1] enabled
Failed to initialize ubd device 0 :Couldn't determine size of device's file
VFS: Mounted root (hostfs filesystem) on device 0:11.
devtmpfs: mounted
This architecture does not have kernel memory protection.
Run /bin/sh as init process
/bin/sh: can't access tty; job control turned off
random: fast init done
/ # 

De manipulaties hierboven zullen ons geven gastsysteem minimaal, zonder dingen als /proc of toegewezen hostnaam. Probeer bijvoorbeeld de volgende opdrachten:

- uname -av
- cat /proc/self/pid
- hostname

Typ om uit te loggen bij de gast exit of druk op control-d. Dit doodt de shell gevolgd door een kernel panic:

/ # exit
Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000
fish: “./linux root=/dev/root rootflag…” terminated by signal SIGABRT (Abort)

We hebben deze kernel panic omdat de Linux-kernel denkt dat het initialisatieproces altijd bezig is. Zonder dit kan het systeem niet meer functioneren en crasht het. Maar aangezien dit een gebruikersmodusproces is, stuurt de resulterende uitvoer zichzelf naar SIGABRT, wat resulteert in een uitvoer.

Gastnetwerk instellen

En hier begint het mis te gaan. Netwerken in gebruikersmodus Bij Linux begint het hele concept van beperkte "gebruikersmodus" uit elkaar te vallen. Meestal is het netwerk immers op systeemniveau beperkt bevoorrecht uitvoeringswijzen om voor ons allemaal begrijpelijke redenen.

Opmerking. per .: lees je meer over de verschillende mogelijkheden om met een netwerk in UML te werken hier.

Reis naar Slurp

Er is echter een oude en bijna niet-ondersteunde tool genaamd Slip, waarmee Gebruikersmodus Linux kan communiceren met het netwerk. Het werkt ongeveer als een TCP/IP-stack op gebruikersniveau en vereist geen systeemrechten om te worden uitgevoerd. Dit hulpmiddel was uitgebracht in 1995, en de laatste update is gedateerd 2006 jaar. Slirp is erg oud. Gedurende de tijd zonder ondersteuning en updates zijn compilers zo ver gegaan dat deze tool nu alleen kan worden omschreven als code rot.

Dus laten we Slirp downloaden van de Ubuntu-repositories en proberen het uit te voeren:

sudo apt-get install slirp
/usr/bin/slirp
Slirp v1.0.17 (BETA)

Copyright (c) 1995,1996 Danny Gasparovski and others.
All rights reserved.
This program is copyrighted, free software.
Please read the file COPYRIGHT that came with the Slirp
package for the terms and conditions of the copyright.

IP address of Slirp host: 127.0.0.1
IP address of your DNS(s): 1.1.1.1, 10.77.0.7
Your address is 10.0.2.15
(or anything else you want)

Type five zeroes (0) to exit.

[autodetect SLIP/CSLIP, MTU 1500, MRU 1500, 115200 baud]

SLiRP Ready ...
fish: “/usr/bin/slirp” terminated by signal SIGSEGV (Address boundary error)

Oh goden. Laten we de debugger van Slirp installeren en kijken of we erachter kunnen komen wat hier aan de hand is:

sudo apt-get install gdb slirp-dbgsym
gdb /usr/bin/slirp
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /usr/bin/slirp...Reading symbols from /usr/lib/debug/.build-id/c6/2e75b69581a1ad85f72ac32c0d7af913d4861f.debug...done.
done.
(gdb) run
Starting program: /usr/bin/slirp
Slirp v1.0.17 (BETA)

Copyright (c) 1995,1996 Danny Gasparovski and others.
All rights reserved.
This program is copyrighted, free software.
Please read the file COPYRIGHT that came with the Slirp
package for the terms and conditions of the copyright.

IP address of Slirp host: 127.0.0.1
IP address of your DNS(s): 1.1.1.1, 10.77.0.7
Your address is 10.0.2.15
(or anything else you want)

Type five zeroes (0) to exit.

[autodetect SLIP/CSLIP, MTU 1500, MRU 1500, 115200 baud]

SLiRP Ready ...

Program received signal SIGSEGV, Segmentation fault.
                                                    ip_slowtimo () at ip_input.c:457
457     ip_input.c: No such file or directory.

De fout slaat in ons deze lijn. Laten we eens kijken naar de stacktrace, misschien kan iets ons daar helpen:

(gdb) bt full
#0  ip_slowtimo () at ip_input.c:457
        fp = 0x55784a40
#1  0x000055555556a57c in main_loop () at ./main.c:980
        so = <optimized out>
        so_next = <optimized out>
        timeout = {tv_sec = 0, tv_usec = 0}
        ret = 0
        nfds = 0
        ttyp = <optimized out>
        ttyp2 = <optimized out>
        best_time = <optimized out>
        tmp_time = <optimized out>
#2  0x000055555555b116 in main (argc=1, argv=0x7fffffffdc58) at ./main.c:95
No locals.

Hier zien we dat de crash optreedt tijdens het starten van de hoofdlus wanneer slirp probeert te controleren op time-outs. Op dit punt moest ik het proberen om te debuggen opgeven. Maar laten we eens kijken of Slirp gebouwd van soorten werkt. Ik heb het archief opnieuw rechtstreeks van de site gedownload Sourceforge, omdat het lastig is om iets vanaf daar via de opdrachtregel te slepen:

cd ~/dl
wget https://xena.greedo.xeserv.us/files/slirp-1.0.16.tar.gz
tar xf slirp-1.0.16.tar.gz
cd slirp-1.0.16/src
./configure --prefix=$HOME/prefix/slirp
make

Hier zien we waarschuwingen over ongedefinieerde ingebouwde functies, dat wil zeggen over het onvermogen om het resulterende binaire bestand te koppelen. Het lijkt erop dat gcc tussen 2006 en nu is gestopt met het produceren van symbolen die worden gebruikt in ingebouwde functies van tussentijdse gecompileerde bestanden. Laten we proberen het trefwoord te vervangen inline op een lege opmerking en kijk naar het resultaat:

vi slirp.h
:6
a
<enter>
#define inline /**/
<escape>
:wq
make

Nee. Dit werkt ook niet. Kan nog steeds geen symbolen voor deze functies vinden.

Op dit punt gaf ik het op en begon ik op Github te kijken Heroku bouwpakketten. Mijn theorie was dat een of ander Heroku-buildpakket de binaire bestanden zou bevatten die ik nodig had. Uiteindelijk leidde de zoektocht mij hier. Ik heb gedownload en uitgepakt uml.tar.gz en vond het volgende:

total 6136
-rwxr-xr-x 1 cadey cadey   79744 Dec 10  2017 ifconfig*
-rwxr-xr-x 1 cadey cadey     373 Dec 13  2017 init*
-rwxr-xr-x 1 cadey cadey  149688 Dec 10  2017 insmod*
-rwxr-xr-x 1 cadey cadey   66600 Dec 10  2017 route*
-rwxr-xr-x 1 cadey cadey  181056 Jun 26  2015 slirp*
-rwxr-xr-x 1 cadey cadey 5786592 Dec 15  2017 uml*
-rwxr-xr-x 1 cadey cadey     211 Dec 13  2017 uml_run*

Dit is het slirp-binaire bestand! Werkt hij?

./slirp
Slirp v1.0.17 (BETA) FULL_BOLT

Copyright (c) 1995,1996 Danny Gasparovski and others.
All rights reserved.
This program is copyrighted, free software.
Please read the file COPYRIGHT that came with the Slirp
package for the terms and conditions of the copyright.

IP address of Slirp host: 127.0.0.1
IP address of your DNS(s): 1.1.1.1, 10.77.0.7
Your address is 10.0.2.15
(or anything else you want)

Type five zeroes (0) to exit.

[autodetect SLIP/CSLIP, MTU 1500, MRU 1500]

SLiRP Ready ...

Crasht niet - dus het zou moeten werken! Laten we dit binaire bestand erin planten ~/bin/slirp:

cp slirp ~/bin/slirp

In het geval dat de maker van het pakket het verwijdert, I een spiegel gemaakt.

Netwerk configuratie

Laten we nu het netwerk instellen op onze gastkernel. Startopties bijwerken:

linux 
  root=/dev/root 
  rootfstype=hostfs 
  rootflags=$HOME/prefix/uml-demo 
  rw 
  mem=64M 
  eth0=slirp,,$HOME/bin/slirp 
  init=/bin/sh

Laten we nu het netwerk inschakelen:

mount -t proc proc proc/
mount -t sysfs sys sys/

ifconfig eth0 10.0.2.14 netmask 255.255.255.240 broadcast 10.0.2.15
route add default gw 10.0.2.2

De eerste twee configuratieopdrachten /proc и /sys nodig voor werk ifconfig, waarmee de netwerkinterface wordt ingesteld om te communiceren met Slirp. Team route stelt de kernelrouteringstabel in om te forceren dat al het verkeer door de Slirp-tunnel wordt gestuurd. Laten we dit controleren met een DNS-query:

nslookup google.com 8.8.8.8
Server:    8.8.8.8
Address 1: 8.8.8.8 dns.google

Name:      google.com
Address 1: 172.217.12.206 lga25s63-in-f14.1e100.net
Address 2: 2607:f8b0:4006:81b::200e lga25s63-in-x0e.1e100.net

Работает!

Opmerking per .: Blijkbaar is het oorspronkelijke bericht geschreven op een desktop met een bekabelde netwerkkaart of een andere configuratie waarvoor geen extra stuurprogramma's nodig waren. Op een laptop met WiFi 8265 van Intel treedt er een fout op bij het verhogen van het netwerk

/ # ifconfig eth0 10.0.2.14 netmask 255.255.255.240 broadcast 10.0.2.15
slirp_tramp failed - errno = 2
ifconfig: ioctl 0x8914 failed: No such file or directory
/ #

Blijkbaar kan de kernel niet communiceren met het stuurprogramma van de netwerkkaart. Een poging om de firmware in de kernel te compileren heeft de situatie helaas niet verholpen. Op het moment van publicatie was het niet mogelijk om in deze configuratie een oplossing te vinden. Op eenvoudigere configuraties (bijvoorbeeld in Virtualbox) stijgt de interface correct.

Laten we de omleiding automatiseren met het volgende shellscript:

#!/bin/sh
# init.sh

mount -t proc proc proc/
mount -t sysfs sys sys/
ifconfig eth0 10.0.2.14 netmask 255.255.255.240 broadcast 10.0.2.15
route add default gw 10.0.2.2

echo "networking set up"

exec /tini /bin/sh

En markeer het uitvoerbaar:

chmod +x init.sh

En dan zullen we wijzigingen aanbrengen in de kernel-opdrachtregel:

linux 
  root=/dev/root 
  rootfstype=hostfs 
  rootflags=$HOME/prefix/uml-demo 
  rw 
  mem=64M 
  eth0=slirp,,$HOME/bin/slirp 
  init=/init.sh

En laten we herhalen:

SLiRP Ready ...
networking set up
/bin/sh: can't access tty; job control turned off

nslookup google.com 8.8.8.8
Server:    8.8.8.8
Address 1: 8.8.8.8 dns.google

Name:      google.com
Address 1: 172.217.12.206 lga25s63-in-f14.1e100.net
Address 2: 2607:f8b0:4004:800::200e iad30s09-in-x0e.1e100.net

Het netwerk is stabiel!

docker-bestand

Om het u gemakkelijker te maken dit allemaal te controleren, heb ik verzameld Dockerfile, die de meeste beschreven stappen automatiseert en u een werkende configuratie zou moeten geven. ik heb ook voorgeconfigureerde kernel, die alles bevat wat in de post wordt beschreven. Maar het is belangrijk om te begrijpen dat ik hier alleen de minimale instelling heb geschetst.

Ik hoop dat dit bericht je heeft geholpen te begrijpen hoe je een gastkernel kunt verhogen. Het bleek een soort monster te zijn, maar de publicatie was opgevat als een uitgebreide gids over het bouwen, installeren en configureren van de gebruikersmodus in Linux onder moderne versies van besturingssystemen van deze familie. De volgende stappen omvatten het installeren van services en andere software die zich al in het gastsysteem bevinden. Aangezien Docker-containerafbeeldingen slechts gepubliceerde tarballs zijn, zou u de afbeelding moeten kunnen extraheren via docker export, en bepaal vervolgens het installatiepad in de hoofdmap van het bestandssysteem van de gastkernel. Voer dan het shell-script uit.

Speciale dank aan Rkeene van #lobsters op Freenode. Zonder zijn hulp bij het debuggen van Slirp was ik niet zo ver gekomen. Ik heb geen idee hoe zijn Slackware-systeem correct werkt met slirp, maar mijn Ubuntu- en Alpine-systemen accepteerden slirp niet en de binaire Rkeene stelde me voor. Maar het is genoeg voor mij dat er tenminste iets voor mij werkt.

Bron: www.habr.com

Voeg een reactie