Linux operatsioonisüsteemis töötab võrguühendus: erinevus redaktsioonide vahel

Allikas: Imre kasutab arvutit
Mine navigeerimisribaleMine otsikasti
568. rida: 568. rida:
   
 
* nö load balancing toimub kerneli poolt tehtud hash'ing vms abil (seda võiks saada üle kirjutada eBPF programmiga tõenäoliselt)
 
* nö load balancing toimub kerneli poolt tehtud hash'ing vms abil (seda võiks saada üle kirjutada eBPF programmiga tõenäoliselt)
  +
  +
====Turvalisus====
  +
  +
Väidetavalt ei ole reuseport realistlik ründevektor kuigi tal võiks teoreetiliselt olla potensiaali
  +
  +
* ta on populaarne interneti ühendatud infosüsteemi komponendi puhul (nginx, haproxy, apache, nsd, unbound)
  +
* ta võimaldab nö ausa teenust pakkuva pordi külge sokutada midagi, ja teenuse ees olev tulemüür laseb liikluse ilmselt läbi
   
 
===Kasulikud lisamaterjalid===
 
===Kasulikud lisamaterjalid===

Redaktsioon: 28. mai 2026, kell 17:56

Sissejuhatus

Käesolev tekst

  • ei juhenda arvuti ip aadressi ja ruutingu seadistamist
  • mõtiskleb, mis asi on võrguühendus
  • mõtiskleb, kuidas on arvutis töötav protsess seotud võrguühendusega (ja vastupidi)

Mõisted

  • berkeley sockets api - käesoleva teksti peamini sisu
  • streams api - berkeley sockets api peamini alternatiiv - solaris ja co kasutavad

Tööpõhimõte

Teenuse pakkumise poolelt vaadates toimub seoses võrguühenduse teenindamisega selline sündmuste käik (välja on kirjutatud nn syscall'id)

SOCKET() -> BIND() -> LISTEN() -> ACCEPT() -> READ/WRITE() -> CLOSE()

kus erinevad tarkvaralised lahendused saavad jagada seda järgnevust erinevalt lõikudeks, nt

  • üks netcat protsess tegeleb kõigi teemadega ise
  • postgres isand protsess tegeleb kuni accept juurde, edasi moodustatakse uus protsess ning see töötab lõpuks 'active connected socket' olukorraga
  • sshd/init (ubuntu 24.04) - esialgu kuulab võrgus init protsess port 22/tcp, st on listen olekus, kui saabub esimene pöördumine tuuakse juurde sshd protsess, listen antakse üle (sd_listen_fds tehnika abil)
  • võrguühenduse töötamine on seotud tavaliselt user-space protsessi töötamisega

Kliendi poolt vaadates

SOCKET() -> CONNECT() -> READ/WRITE() -> CLOSE()

Väited

  • toodud nähtusi saab omavahel kombineerida (nt nginx-reuseport režiimis kasutab lisaks 'sshd/init' lähenemise elemente)
  • kui toimub võrguühendus, siis serveri poolelt osaleb kaks erinevat socketit: 1. listening socket, 2. active connected socket
  • socket esineb kerneli mälu struktuuri üksusena (sinna on üles kirjutatud metaandmed, nt port number, aga ka andmetega seotud queue'd)

Selleks, et protsess saaks kasutada võrku ületab ta nö user-space -> kernel-space horisondi syscallide abil, ja neid ei ole palju, nt (mõni on ühine nii kliendile kui serverile, nt 'socket()', mõni iseloomulik serverile (nt listen()), mõni iseloomulik kliendile (nt connect())

  • socket()
  • bind()
  • listen()
  • accept()
  • connect()
  • read()
  • write()
  • epoll()
  • poll()
  • close()

Listening-socket ja active-connected-socket objektidega toimuv on sarnane protsessiga toimuvale forkimise (clone()) olukorras

  • pidavalt on süsteemis olemas nö parent nähtus: vastavalt 1. listen socket, 2. parent protsess
  • teatud olukorras toimub uue objekti tekkimine: 1. saabuva võrguühenduse teenindamisega moodustatakse listen socket alusel koopia; 2. uue protsessi vajadusel olemasolev protsess moodustab endast koopia ja täidab koodi osa mälus uue tarkvara st programmi sisuga)

Võrguühenduse vaatlemine - netcat

Serveri poolel on lähtepunktiks ainult nn 'listening socket', peale netcat protsessi käivitamist ütleb protsess kernelile kolm syscall'i

  • socket()
  • bind()
  • listen()
  • accept()

tulemusena paistab (reaalset grep väljundis accept4 ei ole paista)

terminal 1 - server-01# strace netcat -l 6001 2>&1 | egrep "socket|setsockopt|bind|listen|accept"
..
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
setsockopt(3, SOL_SOCKET, SO_REUSEPORT, [1], 4) = 0
bind(3, {sa_family=AF_INET, sin_port=htons(6001), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
listen(3, 1)                          = 0
accept4(...
...

terminal 2 - server-01# netstat -anpt | grep netcat
tcp        0      0 0.0.0.0:6001            0.0.0.0:*               LISTEN      21473/netcat

terminal 2 - server-01# lsof -n -P -p 21473
COMMAND   PID USER   FD   TYPE  DEVICE SIZE/OFF  NODE NAME
netcat  21473 root  cwd    DIR   252,2     4096  8193 /root
netcat  21473 root  rtd    DIR   252,2     4096     2 /
netcat  21473 root  txt    REG   252,2    39560   841 /usr/bin/nc.openbsd
netcat  21473 root  mem    REG   252,2  2125328  7621 /usr/lib/x86_64-linux-gnu/libc.so.6
netcat  21473 root  mem    REG   252,2    55536 15411 /usr/lib/x86_64-linux-gnu/libmd.so.0.1.0
netcat  21473 root  mem    REG   252,2    68104  8515 /usr/lib/x86_64-linux-gnu/libresolv.so.2
netcat  21473 root  mem    REG   252,2    80888 15290 /usr/lib/x86_64-linux-gnu/libbsd.so.0.12.1
netcat  21473 root  mem    REG   252,2   236616  7618 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
netcat  21473 root    0u   CHR   136,7      0t0    10 /dev/pts/7
netcat  21473 root    1u   CHR   136,7      0t0    10 /dev/pts/7
netcat  21473 root    2u   CHR   136,7      0t0    10 /dev/pts/7
netcat  21473 root    3u  IPv4 1514112      0t0   TCP *:6001 (LISTEN)

kus

  • lsof käsk esitab userspace protsessiga seotud avatud failide nimekirja (muu hulgas kuulub nimekirja võrgusoketiga seotud võrguühenduse inode 1514112
  • 1514112 on operatsioonisüsteemis unikaalne globaalne võrgusoketi inode number (ino)
  • fd 0u, 1u ja 2u on standardse tähendusega, vastavalt - stdin, stdout ja stderr
  • 3u on protsessi kontekstis unikaalne file descriptor väärus (3r või 4w oleksid põhimõtteliselt read ja write, u on universal st mõlemad)
  • tegu on listening soketiga, talle vastab mälueraldis jms
  • soket asub ise kernel space'is, aga userspace'i protsessil on temaga kontakt fd abil (selle suhtes teeb protess nt read() ja write() syscall'isid
  • accept() syscall on pooleldi täidetud, st ta ootab võrgust connect() syscall'ile vastavat pöördumist

Peale kliendi ühenduse alustamist st kui ühendus toimub, paistab kliendi arvutis syscallid

  • socket
  • setsockopt
  • connect
terminal 1 - klient-01# # strace netcat 192.168.10.193 6001 2>&1 | egrep "socket|setsockopt|connect"
..
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
setsockopt(3, SOL_SOCKET, SO_REUSEPORT, [1], 4) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(6001), sin_addr=inet_addr("192.168.10.193")}, 16) = 0
...

terminal 2 - klient-01# netstat -anpt | grep netcat
tcp        0      0 192.168.10.196:58384    192.168.10.193:6001     ESTABLISHED 345883/netcat

terminal 2 - klient-01# lsof -n -P -p 345883
COMMAND    PID USER  FD   TYPE   DEVICE SIZE/OFF   NODE NAME
netcat  345883 root cwd    DIR    253,2     4096     14 /root
netcat  345883 root rtd    DIR    253,2     4096      2 /
netcat  345883 root txt    REG    253,2    35032 419036 /usr/bin/nc.traditional
netcat  345883 root mem    REG    253,2  1999312 403434 /usr/lib/x86_64-linux-gnu/libc.so.6
netcat  345883 root mem    REG    253,2   225600 403431 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
netcat  345883 root   0u   CHR    136,2      0t0      5 /dev/pts/2
netcat  345883 root   1u   CHR    136,2      0t0      5 /dev/pts/2
netcat  345883 root   2u   CHR    136,2      0t0      5 /dev/pts/2
netcat  345883 root   3u  IPv4 29390854      0t0    TCP 192.168.10.196:58384->192.168.10.193:6001 (ESTABLISHED)

kus

  • üks active connected socket oma mälueraldisega kernelis
  • 29390854 on operatsioonisüsteemi jaoks globaalselt unikaalne inode väärtus (ino)

ja serveris kaks võrgusoketit nüüd, accept syscall sai valmis (tema tegevuse tulemusena ilmus file descriptor 4u

terminal 2 - server-01# netstat -anpt | grep netcat
tcp        0      0 0.0.0.0:6001            0.0.0.0:*               LISTEN      21473/netcat
tcp        0      0 192.168.10.193:6001     192.168.10.196:58384    ESTABLISHED 21473/netcat

terminal 2 - server-01# lsof -n -P -p 21473
COMMAND   PID USER   FD   TYPE  DEVICE SIZE/OFF  NODE NAME
netcat  21473 root  cwd    DIR   252,2     4096  8193 /root
netcat  21473 root  rtd    DIR   252,2     4096     2 /
netcat  21473 root  txt    REG   252,2    39560   841 /usr/bin/nc.openbsd
netcat  21473 root  mem    REG   252,2  2125328  7621 /usr/lib/x86_64-linux-gnu/libc.so.6
netcat  21473 root  mem    REG   252,2    55536 15411 /usr/lib/x86_64-linux-gnu/libmd.so.0.1.0
netcat  21473 root  mem    REG   252,2    68104  8515 /usr/lib/x86_64-linux-gnu/libresolv.so.2
netcat  21473 root  mem    REG   252,2    80888 15290 /usr/lib/x86_64-linux-gnu/libbsd.so.0.12.1
netcat  21473 root  mem    REG   252,2   236616  7618 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
netcat  21473 root    0u   CHR   136,7      0t0    10 /dev/pts/7
netcat  21473 root    1u   CHR   136,7      0t0    10 /dev/pts/7
netcat  21473 root    2u   CHR   136,7      0t0    10 /dev/pts/7
netcat  21473 root    3u  IPv4 1514112      0t0   TCP *:6001 (LISTEN)
netcat  21473 root    4u  IPv4 1514113      0t0   TCP 192.168.10.193:6001->192.168.10.196:58384 (ESTABLISHED)
  • listening socket oma mälueraldisega jms
  • active connected socket oma mälueraldisega
  • võrgusoketi inode numbrid on soketitel erinevad - 1514112 ja 1514113
  • lisaks tekkinud file descriptor 4u on read() ja write() syscallide poolt kasutatav
  • asjaolu, et võrguühendusega on seotud fd nii nagu tavalise failisüsteemi faili puhul kinnitab asjaolu, et in-unix-everything-is-a-file

Väited

  • serveri poolel olev listen-socket ülesseadmine on valmisoleku tekitamine sisenevate võrguühenduste teenindamiseks
  • kui accept syscall lõpetab, siis listen-socket on nagu ta ikka on edasi, lisaks on tekkinud juurde teine ühendusega tegelev soket
  • listen-socket ja active-connection-soket suhe on võrreldab protsessidega operatsioonisüsteemis: parent ja child kuid sellise täpsustusega, et parent sünnitab ainult nö poegi st kes edasi ise ei suuda sünnitada; parent protsessi poolt tekitatud child protsess reeglina saab omakorda tekitada child protsessi, st protsess tekitab tütreid
  • šovinist võiks võrrelda võrguühenduse klienti nö poeglapsega ja serverit tütarlapsega

Võrguühenduse vaatlemine - python skript

TODO

sd_listen_fds - sshd

sd_listen_fds (sd nagu systemd) nähtus võimaldab nt sellist asjakorraldust, mis toimub Ubuntu v. 24.04 operatsioonisüsteemis vaikimisi sshd serveriga

  • kui keegi pole sshd abil süsteemi sisse loginud, siis port 22 peal kuulab systemd komplekti kuuluvad programm 'init' (analoogne kunagise xinitd vms nn internet superserveriga)
  • kui keegi pole sshd kaudu süsteemi sisse loginud, siis sshd protsesse süsteemis ei töötagi veel (arvutusressusi kokkuhoiu eesmärgil)
  • kui toimub esimene pöördumine, siis systemd käivitab ssh.service unit abil sshd protsessi kusjuures andes üle listen tegevusega seotud faili deskriptori
root@zabbix-pub-01:/# netstat -anpt
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
..
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1/init
tcp6       0      0 :::22                   :::*                    LISTEN      1/init
...

tcp6       0      0 192.168.10.193:9999     192.168.10.156:59522    ESTABLISHED 1/init


root@zabbix-pub-01:/# ps -ef | egrep "init|ssh"
UID           PID    PPID  C STIME  TTY          TIME CMD
root           1       0   8 17:06  ?        00:00:01 /sbin/init

kus

  • nn bootshell viguriga (vt TODO) on nö kõrvalt neutraalselt sisse logitud

Peale sisselogimist

root@zabbix-pub-01:/# netstat -anpt
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1/init
tcp        0      0 192.168.10.193:22       192.168.10.156:60079    ESTABLISHED 1037/sshd: root@pts
tcp6       0      0 :::22                   :::*                    LISTEN      1/init
tcp6       0      0 :::9999                 :::*                    LISTEN      1/init
tcp6       0      0 192.168.10.193:9999     192.168.10.156:59522    ESTABLISHED 1/init


root@zabbix-pub-01:/# ps -ef | egrep "init|ssh"
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 17:06 ?        00:00:01 /sbin/init
root        1035       1  0 17:08 ?        00:00:00 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
root        1037    1035  0 17:08 ?        00:00:00 sshd: root@pts/0

kus

  • init protsess on "sshd -D ..." parent
  • "sshd -D ..." on "sshd: root@pts/0" parent
  • sisselogitud oleks on seotud protsessiga "sshd: root@pts/0"
  • kui toimub veel sisselogimisi, siis moodustub "sshd: root@pts/0" kõrvale nt "sshd: root@pts/1"

seejuures

root@zabbix-pub-01:~# lsof -n -P -p 1 | grep "TCP \*:22" | grep LISTE
COMMAND PID    USER   FD      TYPE             DEVICE     SIZE/OFF    NODE  NAME
systemd   1    root   94u     IPv4               6904      0t0        TCP   *:22 (LISTEN)
systemd   1    root   95u     IPv6               4076      0t0        TCP   *:22 (LISTEN)

root@zabbix-pub-01:~# lsof -n -P -p 1035 | grep TCP
COMMAND PID    USER   FD    TYPE         DEVICE     SIZE/OFF    NODE  NAME
sshd    1035   root   3u    IPv4           6904      0t0        TCP   *:22 (LISTEN)
sshd    1035   root   4u    IPv6           4076      0t0        TCP   *:22 (LISTEN)

st

  • init protsess ja "sshd -D .." protsess jagavad omavahel port 22 osas võrgusoketi globaalset inode'i - inet -> "sshd -D .." suunal toimus sd_listen_fds

systemd unitite poolelt töötavad selle nähtusega kaks unitit

  • ssh.socket
  • ssh.service

kus

root@zabbix-pub-01:~# systemctl status ssh.socket
● ssh.socket - OpenBSD Secure Shell server socket
     Loaded: loaded (/usr/lib/systemd/system/ssh.socket; enabled; preset: enabled)
    Drop-In: /etc/systemd/system/ssh.socket.d
             └─override.conf
     Active: active (running) since Thu 2026-05-28 17:06:29 EEST; 10min ago
   Triggers: ● ssh.service
     Listen: 0.0.0.0:22 (Stream)
             [::]:22 (Stream)
      Tasks: 0 (limit: 2115)
     Memory: 12.0K (peak: 512.0K)
        CPU: 1ms
     CGroup: /system.slice/ssh.socket

May 28 17:06:29 zabbix-pub-01 systemd[1]: Listening on ssh.socket - OpenBSD Secure Shell server socket.

root@zabbix-pub-01:~# cat /lib/systemd/system/ssh.socket
[Unit]
Description=OpenBSD Secure Shell server socket
Before=sockets.target ssh.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run

[Socket]
ListenStream=0.0.0.0:22
ListenStream=[::]:22
BindIPv6Only=ipv6-only
Accept=no
FreeBind=yes

[Install]
WantedBy=sockets.target
RequiredBy=ssh.service
root@zabbix-pub-01:~#

kus

  • BindIPv6Only=ipv6-only - port 22 jaoks on eraldatud kaks listen soketit st tehtud kaks mälueraldist: 1. ipv4 jaoks, 2. ipv6 jaoks

ning

root@zabbix-pub-01:~# systemctl status ssh.service
● ssh.service - OpenBSD Secure Shell server
     Loaded: loaded (/usr/lib/systemd/system/ssh.service; disabled; preset: enabled)
    Drop-In: /etc/systemd/system/ssh.service.d
             └─override.conf
     Active: active (running) since Thu 2026-05-28 17:08:45 EEST; 9min ago
TriggeredBy: ● ssh.socket
       Docs: man:sshd(8)
             man:sshd_config(5)
    Process: 1034 ExecStartPre=/usr/sbin/sshd -t (code=exited, status=0/SUCCESS)
   Main PID: 1035 (sshd)
      Tasks: 1 (limit: 2115)
     Memory: 5.3M (peak: 5.9M)
        CPU: 39ms
     CGroup: /system.slice/ssh.service
             └─1035 "sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups"

May 28 17:08:45 zabbix-pub-01 systemd[1]: Starting ssh.service - OpenBSD Secure Shell server...
May 28 17:08:45 zabbix-pub-01 sshd[1035]: Server listening on 0.0.0.0 port 22.
May 28 17:08:45 zabbix-pub-01 sshd[1035]: Server listening on :: port 22.
May 28 17:08:45 zabbix-pub-01 systemd[1]: Started ssh.service - OpenBSD Secure Shell server.
May 28 17:08:45 zabbix-pub-01 sshd[1037]: Accepted publickey for root from 192.168.10.156 port 60079 ssh2: ED25519 SHA256:3cj7QCk4leNOSQJlfeUeHr6Y>
May 28 17:08:45 zabbix-pub-01 sshd[1037]: pam_unix(sshd:session): session opened for user root(uid=0) by root(uid=0)


root@zabbix-pub-01:~# cat /lib/systemd/system/ssh.service
[Unit]
Description=OpenBSD Secure Shell server
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run

[Service]
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755

[Install]
WantedBy=multi-user.target
Alias=sshd.service

Väited

  • ssh.socket sisaldab rida 'Accept=no' - accept syscall juures annab systemd tegevused üle init protsessilt "sshd -D ..." protsessile
  • üleandmine toimub systemd poolt vastava xxx.service abil, st antud juhul ssh.service käivitamisega
  • ssh.socket on enabletud, ssh.service iseensest ei ole enabletud - seda triggerdab ssh.socket
  • selleks, et selline nähtus toimuks, peab nägema omajagu vaeva systemd osakond, ja sshd tarkvara peab olema ka omalt poolt ettevalmistatud sd_listen_fds abil tegevuse üleandmiseks

Reuseport

Osutub, et tcp/ip network stack Linux, Windows, BSD jt implementatsioonid võimaldavad teatud tingimustel mitmel protsessil korraga sama porti kasutada. Seda võimalust kontrollib 'so_reuseport' socket option ('so_').

Väited

  • haproxy - kasutatakse vaikimisi
  • nginx - vaikimisi ei kasutata, aga soovitatakse kasutada jõudluse suurendamise eesmärgil
  • zabbix-agent2 - ei ole võimalik kasutada

Python skript

Illustratsiooniks reuseport omadust kasutav python skript

# cat socket-01-server.py
import socket
import os
import sys

PORT = 8083
# Fetch the Process ID so we can easily tell which instance answers the client
PID = os.getpid()

# 1. Create a standard TCP IPv4 Socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 2. THE MAGIC OPTIONS: Enable Reuse Address and Reuse Port
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)

# 3. Bind and Listen (Standard blocking mode)
server_socket.bind(('0.0.0.0', PORT))
server_socket.listen(10)

print(f"[Worker PID: {PID}] Multi-core listening gate opened on port {PORT}...")

try:
    while True:
        # This call BLOCKS completely. The script sleeps right here in the kernel
        # until the Linux 4-tuple hash decides to route a client to THIS specific socket instance.
        client_socket, client_address = server_socket.accept()

        # Read the raw incoming HTTP request payload (up to 4KB)
        request = client_socket.recv(4096)

        if request:
            # Construct a basic HTTP response containing the answering process ID
            body = f"Hello from Worker Process ID: {PID}\n"
            response = (
                "HTTP/1.1 200 OK\r\n"
                "Content-Type: text/plain\r\n"
                f"Content-Length: {len(body)}\r\n"
                "Connection: close\r\n"
                "\r\n"
                f"{body}"
            ).encode('utf-8')

            # Fire the response back to the client
            client_socket.sendall(response)

        # Close the socket immediately to return the client line
        client_socket.close()

except KeyboardInterrupt:
    print(f"\n[Worker {PID}] Shutting down down gracefully.")
finally:
    server_socket.close()

kus

  • TODO

Väited

  • sellist skripti saab käivitada mitu eksemplari ühes arvutis - kõik kuulavad ja teenindavad samal pordil

Nginx ja haproxy

reuseport nähtust saab illustreerida käivitades samal pordil nginx ja haproxy protsessid, haproxy seadistus

root@zabbix-pub-01:~# cat /etc/haproxy/haproxy.cfg
global
    log /dev/log local0
    chroot /var/lib/haproxy
    user haproxy
    group haproxy
    daemon
#    no-reuseport
    nbthread 1

    # Modern HAProxy thread configuration:
    # This automatically spawns workers matching your CPU count.
    # To strictly witness the kernel routing traffic across different internal
    # buckets, HAProxy pairs this natively with SO_REUSEPORT by default.
    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners

defaults
    log     global
    mode    http
    option  httplog
    option  dontlognull
    timeout connect 5000
    timeout client  50000
    timeout server  50000

# =====================================================================
# THE EXPERIMENTAL REUSEPORT FRONTEND
# =====================================================================
frontend reuseport_experiment
    bind 0.0.0.0:80

    # We will use HAProxy's internal sample fetches to append the
    # handling Thread ID directly into a custom HTTP response header!
    http-after-response set-header X-Handling-Thread "%[thread]"

    default_backend echo_back

backend echo_back
    # A simple trick: We use HAProxy's internal stats app to act as an
    # instant mock HTTP responder, so you don't need a backend server running.
    http-request return status 200 content-type "text/plain" string "Hello from HAProxy! Connection processed successfully.\n"

ning nginx seadistus

root@zabbix-pub-01:~# cat /etc/nginx/sites-enabled/default
##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# https://www.nginx.com/resources/wiki/start/
# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
# https://wiki.debian.org/Nginx/DirectoryStructure
#
# In most cases, administrators will remove this file from sites-enabled/ and
# leave it as reference inside of sites-available where it will continue to be
# updated by the nginx packaging team.
#
# This file will automatically load configuration files provided by other
# applications, such as Drupal or Wordpress. These applications will be made
# available underneath a path with that package name, such as /drupal8.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##

# Default server configuration
#
server {
	listen 80 reuseport;
#	listen [::]:8082 reuseport;

	root /var/www/html;

	# Add index.php to the list if you are using PHP
	index index.html index.htm index.nginx-debian.html;

	server_name _;

	location / {
		# First attempt to serve request as file, then
		# as directory, then fall back to displaying a 404.
		try_files $uri $uri/ =404;
	}
}

tulemus paistab serveris välja

root@zabbix-pub-01:~# netstat -lnpt | grep :80
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1520/nginx: master
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1513/haproxy

root@zabbix-pub-01:~# lsof -n -P -p 1513 | grep TCP
haproxy 1513 haproxy    9u     IPv4              12976      0t0    TCP *:80 (LISTEN)

root@zabbix-pub-01:~# lsof -n -P -p 1520 | grep TCP
nginx   1520 root    5u  IPv4              16719      0t0    TCP *:80 (LISTEN)
  • erinevad listen socket inode numbrid
  • ei ole üksteisest põlvnevat suhet

ja kliendi poolt vaadates

root@zabbix-01:~# curl http://192.168.10.193/
Hello from HAProxy! Connection processed successfully.
root@zabbix-01:~# curl http://192.168.10.193/
Hello from HAProxy! Connection processed successfully.
root@zabbix-01:~# curl http://192.168.10.193/
Welcome to nginx!
root@zabbix-01:~# curl http://192.168.10.193/
Hello from HAProxy! Connection processed successfully.
root@zabbix-01:~# curl http://192.168.10.193/
Welcome to nginx!
root@zabbix-01:~# curl http://192.168.10.193/
Welcome to nginx!

Väited

  • nö load balancing toimub kerneli poolt tehtud hash'ing vms abil (seda võiks saada üle kirjutada eBPF programmiga tõenäoliselt)

Turvalisus

Väidetavalt ei ole reuseport realistlik ründevektor kuigi tal võiks teoreetiliselt olla potensiaali

  • ta on populaarne interneti ühendatud infosüsteemi komponendi puhul (nginx, haproxy, apache, nsd, unbound)
  • ta võimaldab nö ausa teenust pakkuva pordi külge sokutada midagi, ja teenuse ees olev tulemüür laseb liikluse ilmselt läbi

Kasulikud lisamaterjalid