CGIHTTPServer() einschränke auf IP Bereich...

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Dienstag 15. Februar 2005, 18:29

Wie kann ich den CGIHTTPServer() so modifizieren, das es nur von einer bestimmten IP-Range z.B. 192.168.x.x erreichbar ist...

Natürlich könnte ich das auch per Firewall Regeln, aber schön wäre es auch, wenn man es direkt mir Python machen kann...

Ich hab ein wenig in den Sourcen rumgewühlt, aber komme nicht so recht weiter...


Und gleich noch eine Frage... Wie kann ich die normalen print's in eine Datei schreiben lassen???
Meine Bisherige Lösung dazu ist sys.stdout zu verändern...
BlackJack

Donnerstag 17. Februar 2005, 00:04

Dazu ist die 'verify_request()' Methode vorgesehen. Die muss man nur geeignet überschreiben.

Code: Alles auswählen

from BaseHTTPServer import HTTPServer
from CGIHTTPServer import CGIHTTPRequestHandler

class LimitIPHTTPServer(HTTPServer):
    def __init__(self, server_address, request_handler, ip_masks):
        HTTPServer.__init__(self, server_address, request_handler)
        self.ip_masks = [mask.split('.') for mask in ip_masks]
        

    def verify_request(self, dummy, client_address):
        def check_ip(mask):
            for mask_part, ip_part in zip(mask, ip):
                if mask_part != ip_part and mask_part != '*':
                    return False
            return True

        ip = client_address[0].split('.')

        for mask in self.ip_masks:
            if check_ip(mask):
                return True
        return False

server = LimitIPHTTPServer((host, port),
                           CGIHTTPRequestHandler,
                           ('127.0.0.1', '192.168.*.*'))
server.serve_forever()
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Mittwoch 23. Februar 2005, 14:42

jens hat geschrieben:Und gleich noch eine Frage... Wie kann ich die normalen print's in eine Datei schreiben lassen???
Meine Bisherige Lösung dazu ist sys.stdout zu verändern...
So:

Code: Alles auswählen

print >> fileobj, "data"
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Donnerstag 24. Februar 2005, 19:58

Milan hat geschrieben:

Code: Alles auswählen

print >> fileobj, "data"
Auch nett zu wissen, was mit ">>" geht... Aber das meine ich nicht... Der Server printet doch LOG-Ausgaben direkt aus... Diese möchte ich noch in eine Datei umleiten und dafür verbiege ich sys.stdout
BlackJack

Donnerstag 24. Februar 2005, 23:36

Und das funktioniert? Der Server gibt seine Meldungen nämlich nach `sys.stderr` aus. Ansatzpunkt ist die Methode `log_message()` im Requesthandler. Da sollten alle Ausgaben mal vorbeikommen.
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Freitag 25. Februar 2005, 09:47

Jau! Hast recht, habe jetzt log_message() in MyHandler überschrieben bzw. erweitert... Jetzt brauche ich aber nochmal hilfe:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: ISO-8859-1 -*-

import CGIHTTPServer
import BaseHTTPServer
import os, sys, time


# Verz. in dem CGIs ausgeführt werden sollen. Leer lassen (="") für alle Verz.
cgiVerz = ""


class MyHandler(CGIHTTPServer.CGIHTTPRequestHandler):
    "Modifizieren des Ursprünglichen Servers"

    def __init__( self, LogFile ):
        CGIHTTPServer.CGIHTTPRequestHandler.__init__( self )

        self.LogFile = LogFile

        print "Lese Verzeichnisbaum für CGI-Ausführung...",
        # Liste aller Unetrverzeichnisse erzeugen, damit überall CGIs ausgeführt werden.
        cgi_directories = ["/"+i[0].replace("\\","/") for i in os.walk(cgiVerz)]
        print "OK",len(cgi_directories),"Verz. gefunden\n"

    def is_python(self, path):
        "Checkt, ob die Datei ein Python-Skript ist"
        head, tail = os.path.splitext(path)
        return tail.lower() in (".py", ".pyw", ".cgi")

    def is_cgi(self):
        "Ausführen eines Python-Skript"
        path = self.path
        print "self.path:",self.path
        print "self.cgi_directories:",self.cgi_directories
        for x in self.cgi_directories:
            i = len(x)
            if path[:i] == x and (path[i+1:] and path[i] == '/'):
                self.cgi_info = path[:i], path[i+1:]
                print "self.cgi_info:",self.cgi_info
                return True
        return False

    def log_message(self, format, *args):
        LogMessage = "%s - - [%s] %s\n" % (self.address_string(),
                          self.log_date_time_string(),
                          format%args)
        print LogMessage

        log = file( self.LogFile, "a" )
        log.write( LogMessage )
        log.close()





import SocketServer,socket
class MyThreadingServer(SocketServer.ThreadingTCPServer):
    "Verbesserung für den Server, damit er mehrere Anfragen parallel bearbeiten kann"
    allow_reuse_address = 1    # Seems to make sense in testing environment

    def __init__(self, server_address, request_handler, AllowIPs):
        SocketServer.ThreadingTCPServer.__init__(self, server_address, request_handler)
        self.AllowIPs = [mask.split('.') for mask in AllowIPs]

    def server_bind(self):
        """Override server_bind to store the server name."""
        SocketServer.ThreadingTCPServer.server_bind(self)
        host, port = self.socket.getsockname()[:2]
        self.server_name = socket.getfqdn(host)
        self.server_port = port

    def verify_request(self, dummy, client_address):
        """Checkt ob die IP-Adresse der Anfrage in 'AllowIPs' vorhanden ist"""
        def check_ip(mask):
            for mask_part, ip_part in zip(mask, ip):
                if mask_part != ip_part and mask_part != '*':
                    return False
            return True

        ip = client_address[0].split('.')

        for mask in self.AllowIPs:
            if check_ip(mask):
                return True

        print "IP [%s] not allowed!" % client_address

        # Beugt DOS Attacken vor, in dem die Rückmeldung verzögert und
        # somit CPU-Zeit freigegeben wird.
        time.sleep(1)

        return False





def ServerStart( ListenPort = 80, AllowIPs = ('127.0.0.1'), LogFile = "LogFile.txt" ):
    # Umgebungsvariablen setzten, die man in CGI-Skripten abfragen kann und normalerweise
    # von einem echten WebServer automatisch gesetzt werden
    # Evtl. selber erweitern ;)
    os.environ['DOCUMENT_ROOT']=os.getcwd()
    os.environ['HTTP_USER_AGENT']="Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0"
    os.environ['HTTP_HOST']="localhost"
    os.environ['REMOTE_ADDR']="localhost"

    print "ROOT-Pfad .......................:", os.getcwd()
    print "Log-Datei .......................:", os.path.join( os.getcwd(), LogFile )
    print "Starte CGI-HTTP-Server auf Port .:", ListenPort
    print "Zugelassener IP-Bereich .........:", AllowIPs
    print
    print "Seiten sind nun unter [http://localhost:%s] erreichbar!\n" % ListenPort

    server_address = ("", ListenPort)

    httpd = MyThreadingServer( server_address, MyHandler( LogFile ), AllowIPs )
    httpd.serve_forever()

if __name__=="__main__":
    LogFile = "logs\\LogFile.txt"
    ListenPort = 80
    AllowIPs = ('127.0.0.1', '192.168.*.*')

    ServerStart( ListenPort, AllowIPs, LogFile )
Ich versuche MyHandler mit einem eigenen __init__ zu versehen, um z.B. den Pfad zur Log-Datei (LogFile) mitzugeben...

Ich hab Probleme bei der Zeile CGIHTTPServer.CGIHTTPRequestHandler.__init__( self ) denn (self) reicht nicht aus, es werden noch andere Parameter benötigt:

Code: Alles auswählen

Traceback (most recent call last):
  File "W:\PyAdmin\PyAdminRoutines\PyAdminCGIHTTPServer.py", line 135, in ?
    ServerStart( ListenPort, AllowIPs, LogFile )
  File "W:\PyAdmin\PyAdminRoutines\PyAdminCGIHTTPServer.py", line 120, in ServerStart
    httpd = MyThreadingServer( server_address, MyHandler( LogFile ), AllowIPs )
  File "W:\PyAdmin\PyAdminRoutines\PyAdminCGIHTTPServer.py", line 17, in __init__
    CGIHTTPServer.CGIHTTPRequestHandler.__init__( self )
TypeError: __init__() takes exactly 4 arguments (1 given)

Aber welche???

Ich denke ich müßte die Parameter vom SocketServer.BaseRequestHandler nehmen, also:
(self, request, client_address, server) Nur die Variablen, hab ich ja in MyHandler() garnicht zu Verfügung...

denn
CGIHTTPServer.CGIHTTPRequestHandler
erbt von
SimpleHTTPServer.SimpleHTTPRequestHandler
erbt von
BaseHTTPServer.BaseHTTPRequestHandler
erbt von
SocketServer.StreamRequestHandler
erbt von
SocketServer.BaseRequestHandler


Ach, da hab ich noch eine zweite Frage: Ich habe bei verify_request() ein time.sleep() eingebaut, wenn die Anfrage auf einem nicht erleubten IP-Bereich kommt... Ob das bei DOS-Attacken was helfen würde? (Wobei das sowieso unwahrscheinlich ist, das es jemals dazu kommen könnte)
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Freitag 25. Februar 2005, 11:34

Autsch... Du kannst doch nicht einfach die __init__ des Handlers überschreiben ohne zu wissen welche Argumente vorher benötigt werden. Außerdem übergibst du eine Instanz MyHandler( LogFile ) statt einer Klasse. Du musst dir also einen anderen Weg suchen, um der Klasse den Pfad mitzuteilen. Vielleicht wäre eine globale Konstante angebracht, die dann von der Klasse verwendet wird.

Eine andere Möglichkeit wäre sys.stdout zu wrappen, also durch ein psydo-File ersetzen, welches die Ausgaben zwar an das ursprüngliche sys.stdout weiterleitet aber gleichzeitig in eine geöffnete Datei mitloggt. Dazu bietet sich Dookie Code hier sehr gut an:

Code: Alles auswählen

import sys
logfile=file("dateiname.txt","a")
Linebuffer=Line("",sys.stdout,logfile,encoding=sys.getfilesystemencoding())
old_stdout,sys.stdout=sys.stdout,Linebuffer
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Freitag 25. Februar 2005, 13:05

Also globale Variablen sind doch immer böse ;)
sys.stdout zu wrappen geht natürlich schon, aber schöner wäre es schon log_message() zu verändern...

Ich möchte auch nicht nur die Variable LogFile übermitteln, sondern auch cgi_directories...

Also irgendwie sollte es doch mit __init__ gehen...
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Freitag 25. Februar 2005, 13:32

Nein, das geht leider nicht über die __init__, da du auf die Instanzierung keinerlei Einfluss hast. Du kannst höchstens bei der Definition der Klasse das Attribut cgi_directories setzen, aber auf die Argumente der init hat man keinen Einfluss. Die init wird von der Serverklasse gerufen, wenn eine Anfrage reinkommt und erst dann hast du eine Instanz der Handlerclass (heißt deswegen so, weil sie eine Anfrage abhandelt). Probiers im zweifelsfall mal so:

Code: Alles auswählen

class MyHandler(CGIHTTPServer.CGIHTTPRequestHandler): 
    cgi_directories=["cgi-bin"]
    LogFile="balubb"

    def is_python(self, path): 
        "Checkt, ob die Datei ein Python-Skript ist" 
        head, tail = os.path.splitext(path) 
        return tail.lower() in (".py", ".pyw", ".cgi")
    #usw...
ps: der Text "Modifizieren des Ursprünglichen Servers" ist falsch, da der Server nur aus MyThreadingServer besteht, MyHandler ist für die Bearbeitung von Anfragen an den Server / Ausführung von CGI-Scripten zuständig.
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Freitag 25. Februar 2005, 13:45

OK, ich habe meine Variante etwas umgestrickt:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: ISO-8859-1 -*-

__version__ = "0.0.2"

import CGIHTTPServer, SocketServer
import os, sys, time, socket


def writeLogMessage( LogFile, LogMessage ):
    log = file( LogFile, "a" )
    log.write( LogMessage+"\n" )
    log.close()


class MyRequestHandler( CGIHTTPServer.CGIHTTPRequestHandler ):
    """
    Modifizieren des Standart RequestHandlers:
     - Dateiendung .cgi wird auch ausgeführt
     - Ausführung von CGIs in bestimmte Verzeichnissen erlaubt (cgi_directories)
     - Log-Ausgaben werden in Log-Datei geschrieben
    """
    def is_python(self, path):
        "Checkt, ob die Datei ein Python-Skript ist"
        head, tail = os.path.splitext(path)
        return tail.lower() in (".py", ".pyw", ".cgi")

    def is_cgi(self):
        "Testet ob sich eine CGI-Datei in einem erlaubten Pfad befindet"
        path = self.path
        for x in self.cgi_directories:
            i = len(x)
            if path[:i] == x and (path[i+1:] and path[i] == '/'):
                self.cgi_info = path[:i], path[i+1:]
                return True
        return False

    def log_message(self, format, *args):
        "Behandlung von Log-Nachrichten"
        LogMessage = "%s - - [%s] %s" % (self.address_string(), self.log_date_time_string(), format%args)
        print LogMessage
        writeLogMessage( self.LogFile, LogMessage )




class MyThreadingServer( SocketServer.ThreadingTCPServer ):
    """
    Verbesserung des Standart Servers:
     - ermöglicht das abarbeiten mehrere Anfragen parallel (z.B. Download mehrere Dateien gleichzeitig)
     - Ermöglicht das einschränken des IP-Bereiches aus denen der Server Anfragen behandelt
    """
    allow_reuse_address = 1    # Seems to make sense in testing environment

    def __init__(self, server_address, request_handler, AllowIPs):
        SocketServer.ThreadingTCPServer.__init__(self, server_address, request_handler)
        self.AllowIPs = [mask.split('.') for mask in AllowIPs]

    def server_bind(self):
        """Override server_bind to store the server name. (Parallele Anfragen)"""
        SocketServer.ThreadingTCPServer.server_bind(self)
        host, port = self.socket.getsockname()[:2]
        self.server_name = socket.getfqdn(host)
        self.server_port = port

    def verify_request(self, dummy, client_address):
        """Checkt ob die IP-Adresse der Anfrage in 'AllowIPs' vorhanden ist"""
        def check_ip(mask):
            for mask_part, ip_part in zip(mask, ip):
                if mask_part != ip_part and mask_part != '*':
                    return False
            return True

        ip = client_address[0].split('.')

        for mask in self.AllowIPs:
            if check_ip(mask):
                return True

        print "IP [%s] not allowed!" % client_address

        # Beugt DOS Attacken vor, in dem die Rückmeldung verzögert und
        # somit CPU-Zeit freigegeben wird.
        time.sleep(1)

        return False





def ServerStart( cgiVerz = "", ListenPort = 80, AllowIPs = ('127.0.0.1'), LogFile = "LogFile.txt" ):
    # Umgebungsvariablen setzten, die man in CGI-Skripten abfragen kann und normalerweise
    # von einem echten WebServer automatisch gesetzt werden
    os.environ['DOCUMENT_ROOT']     = os.getcwd()
    os.environ['HTTP_USER_AGENT']   = "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0"
    os.environ['HTTP_HOST']         = "localhost"
    os.environ['REMOTE_ADDR']       = "localhost"

    # Liste aller Unetrverzeichnisse erzeugen, damit überall CGIs ausgeführt werden.
    print "Lese Verzeichnisbaum für CGI-Ausführung...",
    cgi_directories = ["/"+i[0].replace("\\","/") for i in os.walk(cgiVerz)]
    print "OK",len(cgi_directories),"Verz. gefunden\n"

    print "ROOT-Pfad .......................:", os.getcwd()
    print "Log-Datei .......................:", os.path.join( os.getcwd(), LogFile )
    print "Starte CGI-HTTP-Server auf Port .:", ListenPort
    print "Zugelassener IP-Bereich .........:", AllowIPs
    print
    print "Seiten sind nun unter [http://localhost:%s] erreichbar!\n" % ListenPort

    # Variablen in MyRequestHandler setzten:
    MyRequestHandler.cgi_directories    = cgi_directories
    MyRequestHandler.LogFile            = LogFile

    httpd = MyThreadingServer( ("", ListenPort), MyRequestHandler, AllowIPs )

    writeLogMessage( LogFile, "*** Server gestartet ***" )

    httpd.serve_forever()





if __name__=="__main__":
    cgiVerz = ""
    ListenPort = 900
    AllowIPs = ('127.0.0.1', '192.168.*.*')
    LogFile = "logs\\LogFile.txt"

    ServerStart( cgiVerz, ListenPort, AllowIPs, LogFile )
Die Variablen werden jetzt in der Funktion ServerStart() übergeben mit:

Code: Alles auswählen

    MyRequestHandler.cgi_directories    = cgi_directories
    MyRequestHandler.LogFile            = LogFile
Die Beschreibung "Modifizieren des Standart RequestHandlers" trifft aber doch zu, oder?

Schön wäre ja eigentlich auch, wenn os.environ['HTTP_USER_AGENT'] & Co. nicht so doof gesetzt werden müßten...

Sonst noch verbesserungs Vorschläge???

Ach, noch eine Frage... Ich möchte den Server von der Console aus starten und von extern wieder beenden... Also sagen wir von einem 2ten Python Skript...
Oder ist es möglich das ich den Server durch ein CGI beende, welches er selber Ausführt???
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Freitag 25. Februar 2005, 14:34

jens hat geschrieben:Die Beschreibung "Modifizieren des Standart RequestHandlers" trifft aber doch zu, oder?
Ja, das trifft es auf jeden Fall...
Schön wäre ja eigentlich auch, wenn os.environ['HTTP_USER_AGENT'] & Co. nicht so doof gesetzt werden müßten...

Sonst noch verbesserungs Vorschläge???
Hi. Um diese Werte würde ich mich nun gar nicht kümmern. HTTP_USER_AGENT, REMOTE_ADDR und all die anderen Dinger sind Umgebungsvariablen die z.T. vom Server gesetzt werden und zwar abh. von der Anfrage des Clients. Der Server setzt z.B. den Useragenten, weil der bei der Anfrage als HTTP-Header mitgeschickt wird. Remote-Addr berechnet sich dagen aus der IP, von der der Client anfragt und wird deswegen vom Handler gesetzt (schau dir aml den Quelltext von CGIHTTPServer.py an, da vor allem die Methode run_cgi). Um zu sehen, was schon von Python gesetzt wird, kannst du dir ja nen CGI-Script schreiben und das mal abrufen:

Code: Alles auswählen

#!/usr/bin/python
import cgi
import cgitb; cgitb.enable()
print "Content-type: text/html\n\n"
form=cgi.FieldStorage()
print form,'<br><br><br>'
keys=cgi.os.environ.keys()
keys.sort()
for k in keys:
    print "%s : %s<br>"%(k,cgi.os.environ[k])
Den Rest würde ich als Dictionary an die init des Servers übergeben (auf die hast du Einfluss) und von da aus setzen lassen.
Ach, noch eine Frage... Ich möchte den Server von der Console aus starten und von extern wieder beenden... Also sagen wir von einem 2ten Python Skript...
Oder ist es möglich das ich den Server durch ein CGI beende, welches er selber Ausführt???
Laut Quelltext wird immer ein eigener Prozess zum ausführen von CGI-Scripten gestartet, es sei denn dies ist nicht möglich, weil keine möglichkeiten zum forken oder zum erstellen von Prozessen mit Pipes vorhanden sind. Dies ist aber eher die Ausnahme. Du musst also in jedem Fall eine OS-abhängige Lösung finden um den Serverprozess abzuschießen. Unter Linux sollte dies leicht möglich sein, du musst nur die PID rauskriegen und fertig. Unter win sollte es ebensoleicht gehen, wenn die win32all installiert sind.
Sonst wird es schon um einiges schwieriger. Du müsstest quasi einen 2. Server-Thread im Serverscript starten, der auf ein Signal von außen wartet. Dann muss er den eigentlichen Serverthread beenden (MyServer.serve_forever()) und dann ist das Script auch beendet. Aber das ist seeeehr aufwändig :wink:
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Freitag 25. Februar 2005, 23:19

Also ich hab mich noch mit den Log-Ausgaben in einer Datei-verbiegen rum geschlagen... Ich bin doch wieder bei dem Umbiegen von stdout und stderr gelandet... Es gibt zwar log_message() und log_error() vom CGIHTTPServer.py aber das ist nicht ganz so Praktikabel... Wenn üble Tracheback beim Ausführen entstehen, hatte ich diese nicht in meiner Log-Datei :(

Das Überschreiben von is_python() hab ich wieder raus genommen, denn die Skripte müßen ja nicht .cgi heißen... Hat man sich das auch gespart...

Hab aber nun was anderes entdeckt... Ich möchte, das die Skripte als root Ausgeführt werden bzw. mit dem User, mit dem der Server gestartet wurde. Dazu hab ich in MyRequestHandler() fork und popen "ausgeschaltet"...

So hier meine aktuelle Version:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: ISO-8859-1 -*-

__version__ = "0.0.4"


import CGIHTTPServer, SocketServer
import os, sys, time, socket


class RedirectStdOut:
    def __init__( self, File, stdoutObj ):
        self.MyStdOut = stdoutObj
        self.File = File

    def write( self, *txt ):
        txt = " ".join([str(i) for i in txt])
        # Auf Konsole Ausgeben
        self.MyStdOut.write( txt )
        # In Log-Datei schreiben
        FileHandle = file( self.File, "a" )
        FileHandle.write( txt )
        FileHandle.close()


class MyRequestHandler( CGIHTTPServer.CGIHTTPRequestHandler ):
    "Modifizieren des Standart RequestHandlers"

    # Damit auch unter Linux, welches fork unterstützt, das Python-CGI-Skript
    # unter dem User ausgeführt wird, mit dem der CGIHTTPServer gestartet wurde
    # und nicht mit User nobody...
    have_fork = False
    have_popen2 = False
    have_popen3 = False

    def is_cgi(self):
        "Modifikation, sodas man im CGI-Verzeichnis ein Dir-Listing bekommt"
        path = self.path
        for x in self.cgi_directories:
            i = len(x)
            if path[:i] == x and (path[i+1:] and path[i] == '/'):
                self.cgi_info = path[:i], path[i+1:]
                return True
        return False






class MyThreadingServer( SocketServer.ThreadingTCPServer ):
    """
    Verbesserung des Standart Servers:
     - ermöglicht das abarbeiten mehrere Anfragen parallel (z.B. Download mehrere Dateien gleichzeitig)
     - Ermöglicht das einschränken des IP-Bereiches aus denen der Server Anfragen behandelt
    """
    allow_reuse_address = 1    # Seems to make sense in testing environment

    def __init__(self, server_address, request_handler, AllowIPs):
        SocketServer.ThreadingTCPServer.__init__(self, server_address, request_handler)
        self.AllowIPs = [mask.split('.') for mask in AllowIPs]

    def server_bind(self):
        """Override server_bind to store the server name. (Parallele Anfragen)"""
        SocketServer.ThreadingTCPServer.server_bind(self)
        host, port = self.socket.getsockname()[:2]
        self.server_name = socket.getfqdn(host)
        self.server_port = port

    def verify_request(self, dummy, client_address):
        """Checkt ob die IP-Adresse der Anfrage in 'AllowIPs' vorhanden ist"""
        def check_ip(mask):
            for mask_part, ip_part in zip(mask, ip):
                if mask_part != ip_part and mask_part != '*':
                    return False
            return True

        ip = client_address[0].split('.')

        for mask in self.AllowIPs:
            if check_ip(mask):
                return True

        print "IP [%s] not allowed!" % client_address

        # Beugt DOS Attacken vor, in dem die Rückmeldung verzögert und
        # somit CPU-Zeit freigegeben wird.
        time.sleep(1)

        return False




def ServerStart( cgiVerz, ListenPort, AllowIPs, LogFile ):
    # Ausgaben in Datei mitloggen:
    sys.stdout = RedirectStdOut( LogFile, sys.stdout )
    sys.stderr = RedirectStdOut( LogFile, sys.stderr )

    print "="*80

    # Umgebungsvariablen setzten, die man in CGI-Skripten abfragen kann und normalerweise
    # von einem echten WebServer automatisch gesetzt werden
    os.environ['DOCUMENT_ROOT']     = os.getcwd()

    # Liste aller Unetrverzeichnisse erzeugen, damit überall CGIs ausgeführt werden.
    print "Lese Verzeichnisbaum für CGI-Ausführung...",
    cgi_directories = [os.path.normpath( os.sep + i[0] ) for i in os.walk(cgiVerz)]
    print "OK",len(cgi_directories),"Verz. gefunden\n"
    #~ for i in cgi_directories: print i

    print "ROOT-Pfad .......................:", os.getcwd()
    print "Log-Datei .......................:", os.path.join( os.getcwd(), LogFile )
    print "Starte CGI-HTTP-Server auf Port .:", ListenPort
    print "Zugelassener IP-Bereich .........:", AllowIPs
    print
    print "Seiten sind nun unter [http://localhost:%s] erreichbar!\n" % ListenPort

    # Variablen in MyRequestHandler setzten:
    MyRequestHandler.cgi_directories    = cgi_directories

    httpd = MyThreadingServer( ("", ListenPort), MyRequestHandler, AllowIPs )

    print "*** Server gestartet ***"

    httpd.serve_forever()


if __name__=="__main__":
    cgiVerz = "." # CGI's in jedem Pfad erlauben
    ListenPort = 9000
    AllowIPs = ('127.0.0.1', '192.168.*.*')
    LogFile = "logs\\LogFile.txt"

    ServerStart( cgiVerz, ListenPort, AllowIPs, LogFile )
Komischerweise wird unter Windows .py nicht ausgeführt, sondern ich sehe den Quellentext im Browser :evil:

So, jetzt kann ich mich mal um die os.environ Dinge kümmern... Wie ich sehe hast du recht, es wird schon jede Menge vom Server selber gesetzt...

EDIT: Allerdings nicht alle... u.a. ist os.environ['DOCUMENT_ROOT'] nicht gesetzt... :? Naja, dann mache ich das halt noch per Hand...
BlackJack

Samstag 26. Februar 2005, 00:21

Zu der Logging-Geschichte: Wie wär's mit dem Modul 'logging'. Das ist doch genau für solche Fälle gedacht.

Was das beenden angeht: Kannst Du Dir nicht eine geeignete Stelle/Methode suchen in der Du testest ob ein bestimmtes Dokument angefordert wurde, z.B. "/kill.me" und dann 'sys.exit()' aufrufen?
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Samstag 26. Februar 2005, 09:22

BlackJack hat geschrieben:Zu der Logging-Geschichte: Wie wär's mit dem Modul 'logging'. Das ist doch genau für solche Fälle gedacht.
Das kenne ich noch garnicht... Muß ich mir mal anschauen...
BlackJack hat geschrieben:Was das beenden angeht: Kannst Du Dir nicht eine geeignete Stelle/Methode suchen in der Du testest ob ein bestimmtes Dokument angefordert wurde, z.B. "/kill.me" und dann 'sys.exit()' aufrufen?
Stimmt das könnte ich in MyRequestHandler.is_cgi() machen!
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Samstag 26. Februar 2005, 15:24

jens hat geschrieben:
BlackJack hat geschrieben:Zu der Logging-Geschichte: Wie wär's mit dem Modul 'logging'. Das ist doch genau für solche Fälle gedacht.
Das kenne ich noch garnicht... Muß ich mir mal anschauen...
Sehr cool. Kennst du log4j oder log4r? Das muss sich nicht dahinter verstecken. Allerdings ist es erst richtig mächtig, wenn du es richtig kennenlernst. Ist in Python 2.3 neu hinzugekommen, wir haben dazu sogar schon Snippets im Forum.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Antworten