Wie sichere Programmstruktur hinsichtlich Netzwerk aufbauen?

In dieser Linux-Ecke dürfen nur Themen rund um Linux geschrieben werden.
Beiträge, die plattformübergreifend sind, gehören ins 'Allgemein'-Forum.
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Wie sichere Programmstruktur hinsichtlich Netzwerk aufbauen?

Beitrag von AND51 »

Hallo,

Sicherlich wisst ihr, dass unter Linux viele "wichtige" Programme sehr auf die Sicherheit des Systems bedacht sind. Sie laufen oftmals chrooted, mit möglichst wenig Rechten oder teilen sich sogar in verschiedene Daemons auf.

Gerade letzteres interessiert mich: Beispielsweise Postfix und Apache starten zig Daemons, aber wie können die sich alle an einen Port binden, sodass jeder Daemon einen Clienten bedienen kann? Nach allem was ich bisher weiß, kann doch nur ein Prozess sich mittels CreateNetworkServer() an einen Port binden...

Da ich für meinen Linux-Server gern auch mal das ein oder andere Programm schreiben möchte: Könnt ihr mir erklären, wie diese Programme das machen?
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
remi_meier
Beiträge: 1078
Registriert: 29.08.2004 20:11
Wohnort: Schweiz

Re: Wie sichere Programmstruktur hinsichtlich Netzwerk aufba

Beitrag von remi_meier »

Hier mal eine kompakte Antwort, im Falle von
missverstandener Frage :D

Das Teilen einer Verbindung geschieht mit mehreren
Sockets. Der Server (z. B. Apache) hat einen Server-
Socket, der an eine Adresse gebunden ist. Wenn ein
Client verbindet, wird ein neuer (Connected-)Socket
für diese eine Verbindung zum Client erstellt. Da Sockets
über File-Descriptors angesprochen werden, kann dieser
an einen anderen Prozess übergeben werden, oder
normalerweise wird der Server-Prozess einfach geforkt.
Da alle Clients auf denselben Port verbinden und ihre
Daten senden, teilt nun Linux die Pakete auf die
verschiedenen Sockets gemäss Absender-Adresse
(Client-Adresse) ein.

Hier findest du einige Beispiel zu Sockets:
http://www.linuxhowtos.org/C_C++/socket.htm
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Re: Wie sichere Programmstruktur hinsichtlich Netzwerk aufba

Beitrag von AND51 »

Hallo remi_meier,

Danke vielmals für deine 'kompakte' Antwort!

Das klingt ja furchtbar einfach! Für jede eingehende Verbindung wird also ein neuer Socket erstellt. Doch wie sähe das in PB aus? Hier muss ich ja mit einer ClientID arbeiten. Für jede Verbindung gibt es in PB ja eine ClientID, richtig? Kann man also sagen "ClientID = Socket"?

Um performante Anwendungen wie Apache zu schreiben, müsste also ein Master-Prozess jeden Socket einzeln an verschiedene vorher gestartete Child-Prozesse vergeben. Das macht man dann also via File-Descriptors. Ist das etwa der Dateiname zu einer *.sock-Datei oder wie muss ich mir das vorstellen? Ich habe bisher nur ein oder zwei *.sock-Dateien gesehen (von fail2ban und Dovecot). Daher weiß ich darüber noch nicht so viel.

Forken kann man den eigenen Prozess mit PB aber nicht — oder etwa doch? :lol: In Perl wüsste ich ja, wie das geht, aber in PB... Trotzdem, zum besseren Verständnis frage ich hier auch nochmal: Angenommen, in PB gäbe es den fork()-Befehl, dann müsste ich immer forken, wenn ich ein #PB_Network_EventClient-Ereignis erhalte, richtig? Wennich das richtig verstehe, hat dann der Kind-Prozess die ClientID des gerade neu verbundenen Client, während der Vater-Prozess einfach wieder bei NetworkEvent() wartet, bis eine Verbindung reinkommt.

So, ich arte erst mal wieder auf (deine) Antwort! :allright:
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
remi_meier
Beiträge: 1078
Registriert: 29.08.2004 20:11
Wohnort: Schweiz

Re: Wie sichere Programmstruktur hinsichtlich Netzwerk aufba

Beitrag von remi_meier »

AND51 hat geschrieben:Das klingt ja furchtbar einfach! Für jede eingehende Verbindung wird also ein neuer Socket erstellt. Doch wie sähe das in PB aus? Hier muss ich ja mit einer ClientID arbeiten. Für jede Verbindung gibt es in PB ja eine ClientID, richtig? Kann man also sagen "ClientID = Socket"?
Vielleicht, das macht PB ja intern. So auf die Schnelle sieht es so
aus, als gäbe es in PB nicht die Möglichkeit, den Connected-Socket
selbst zu verwalten. Man muss bei jedem Event nachfragen, welcher
Client es denn ausgelöst hat. Mit Connected-Sockets erhältst du nur
die Events von dem einen Client.
AND51 hat geschrieben:Um performante Anwendungen wie Apache zu schreiben, müsste also ein Master-Prozess jeden Socket einzeln an verschiedene vorher gestartete Child-Prozesse vergeben. Das macht man dann also via File-Descriptors. Ist das etwa der Dateiname zu einer *.sock-Datei oder wie muss ich mir das vorstellen? Ich habe bisher nur ein oder zwei *.sock-Dateien gesehen (von fail2ban und Dovecot). Daher weiß ich darüber noch nicht so viel.
Also eine Variante ist direkt nach einem "Client-Connected"-Event
den FileDescriptor (FD) dieses Connected-Sockets an einen Child-
Prozess weiterzugeben. FDs sind Handles, man kann also mehrere
FDs auf die gleiche Datei zeigen lassen. Wobei so ein Socket
nicht unbedingt an eine Datei im Dateisystem gebunden sein muss,
es ist normalerweise ein sogenannter "unnamed Socket". Also optional
kann man den Socket auch über das Dateisystem verfügbar machen,
dann siehst du solche .sock Dateien. Ansonsten sind Sockets einfach
"Streams", die über die FD angesprochen werden können.
An einen bestehenden (Child-)Prozess kannst du die FDs wie hier
beschrieben übergeben:
http://www.cs.nyu.edu/bacon/phd-thesis/diss/node21.html
Weshalb es einfacher ist, direkt nach Erhalt eines FDs zu forken,
dann nämlich erbt der Child-Prozess die FDs ohne, dass man sie
senden muss.
AND51 hat geschrieben:Forken kann man den eigenen Prozess mit PB aber nicht — oder etwa doch? :lol: In Perl wüsste ich ja, wie das geht, aber in PB... Trotzdem, zum besseren Verständnis frage ich hier auch nochmal: Angenommen, in PB gäbe es den fork()-Befehl, dann müsste ich immer forken, wenn ich ein #PB_Network_EventClient-Ereignis erhalte, richtig? Wennich das richtig verstehe, hat dann der Kind-Prozess die ClientID des gerade neu verbundenen Client, während der Vater-Prozess einfach wieder bei NetworkEvent() wartet, bis eine Verbindung reinkommt.

Code: Alles auswählen

fork_() ; sollte klappen, aber Achtung, der Debugger mag das IIRC nicht so
Das wäre prinzipiell richtig, aber wie ich feststellen musste, erlaubt
es PB soweit ich sehe nicht, die Client-Sockets selbst in die Hand
zu nehmen. Man muss leider selbst per ClientID feststellen, welcher
Child-Prozess diese Daten verarbeiten soll. Dann muss der Hauptprozess
selbst die Daten empfangen und zur Verarbeitung weitergeben. Das
ist ziemlich schlecht...
Ich würde daher vorschlagen, du schaust dir ein paar Socket-Beispiele
an und machst dir einen eigenen kleinen Network-Wrapper, der dann
das Forken möglich macht.

greetz
remi
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Re: Wie sichere Programmstruktur hinsichtlich Netzwerk aufba

Beitrag von AND51 »

remi_meier hat geschrieben:Weshalb es einfacher ist, direkt nach Erhalt eines FDs zu forken,
dann nämlich erbt der Child-Prozess die FDs ohne, dass man sie
senden muss.

[...]

Das wäre prinzipiell richtig, aber wie ich feststellen musste, erlaubt
es PB soweit ich sehe nicht, die Client-Sockets selbst in die Hand
zu nehmen. Man muss leider selbst per ClientID feststellen, welcher
Child-Prozess diese Daten verarbeiten soll. Dann muss der Hauptprozess
selbst die Daten empfangen und zur Verarbeitung weitergeben. Das
ist ziemlich schlecht...
Ich würde daher vorschlagen, du schaust dir ein paar Socket-Beispiele
an und machst dir einen eigenen kleinen Network-Wrapper, der dann
das Forken möglich macht.
Erst mal vielen Dank, remi_meier, für deine gute Hilfe!
Das was du so von dir gibst ergibt recht viel Sinn, finde ich. Damit kann ich was anfangen!

Ich würde, wie hoffentlich schon erwähnt, gerne Anwendungen für meinen Linux-Server schreiben und ich finde diese Art und Weise, Master- und Child-Prozesse zu haben einfach genial. Natürlich kann man das auch mit Threads machen (habe ich sogar schon versuchsweise, als ich einen HTTP-Server schreiben anfing zu schreiben), aber das ist nicht so... "cool" wie separate Prozesse.

Jedenfalls halte ich es für die beste Vorgehensweise, wenn man mit PB arbeitet, mehrere separate Child-Prozesse ("Spare-Processes") im Vorfeld zu erstellen, sodass diese berets zur Verfügung stehen, wenn Verbindungen an den Master-Prozess rein kommen. Bloß, die Verbindung steht dann ja schon und wurde bereits vom Master angenommen. Der müsste dann also die Verbindung annehmen, halten und schlcihtweg durchscleusen zu den Client-Prozessen. Er kann die Verbindung ja nicht gänzlich abgeben. Hm... Somit fällt also die Möglichkeit weg, beispielsweise einen "graceful restart" machen zu können, bei dem ein Programm/Dienst neu startet, während alte Verbindungen noch zuende bedient werden können.

remi_meier, weißt du vielleicht möglichkeiten, unter Linux den eigenen Prozess zu forken? Ich vermute mal der fork_()-Befehl ist aus der Windows-API-Kiste?
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
RSBasic
Admin
Beiträge: 8047
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: Wie sichere Programmstruktur hinsichtlich Netzwerk aufba

Beitrag von RSBasic »

AND51 hat geschrieben:Ich vermute mal der fork_()-Befehl ist aus der Windows-API-Kiste?
Nein, aber vielleicht hilft dir diese Seite weiter: http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
Benutzeravatar
remi_meier
Beiträge: 1078
Registriert: 29.08.2004 20:11
Wohnort: Schweiz

Re: Wie sichere Programmstruktur hinsichtlich Netzwerk aufba

Beitrag von remi_meier »

AND51 hat geschrieben:remi_meier, weißt du vielleicht möglichkeiten, unter Linux den eigenen Prozess zu forken? Ich vermute mal der fork_()-Befehl ist aus der Windows-API-Kiste?
Wie RSBasic schon sagt, das ist ein Linux-API-Befehl. Genauer
ein Befehl aus der LibC. Da findest du sonst noch massenweise
spannende Befehle :D
http://www.gnu.org/software/libtool/man ... -a-Process
Falls er in PB nicht zur Verfügung steht:

Code: Alles auswählen

ImportC "" : fork() : EndImportC
sollte klappen.

Also ich sehe leider mit PBs Netzwerk-Befehlen auch keine einfache
Möglichkeit die Robustheit deines Servers per Child-Prozesse zu
erhöhen :|
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Re: Wie sichere Programmstruktur hinsichtlich Netzwerk aufba

Beitrag von AND51 »

OK, anke Leute.

Das sind alles ja schon mal ein paar sehr gute Grundlagen, die einem hilfreich sind wenn man eine 'vernünftige' Programmstruktur aufbauen möchte.

Danke auch noch mal für den Link, werde ich mir anschauen!
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Antworten