Ergebnis 1 bis 13 von 13

[Python] IP im Netzwerk?

  1. #1 Zitieren
    Tieftöner Avatar von Lookbehind
    Registriert seit
    Dec 2007
    Beiträge
    15.176
    Hi,

    ich suche grade eine Funktion in Python, der ich ein Netzwerk übergebe (z.b. 192.168.123.0/26) und eine IP-Adresse (z.B. 192.168.123.254) und die mir dann zurück gibt, ob diese IP in dem Netzwerk liegt, oder nicht (in diesem Beispiel also False).

    Sowas gibts doch bestimmt schon in fertig, oder muss ich das doch selbst coden?


    Gruß

    Look
    Lookbehind ist offline

  2. #2 Zitieren
    Retro Micky Avatar von Blue Force
    Registriert seit
    May 2009
    Beiträge
    26.192
    In Python 3.3+, you can use ipaddress module:
    >>> import ipaddress
    >>> ipaddress.ip_address('192.0.43.10') in ipaddress.ip_network('192.0.0.0/16')
    True

    Quelle: https://stackoverflow.com/questions/...p-subnet-match
    Blue Force ist offline

  3. #3 Zitieren
    Tieftöner Avatar von Lookbehind
    Registriert seit
    Dec 2007
    Beiträge
    15.176
    Zitat Zitat von Blue Force Beitrag anzeigen
    In Python 3.3+, you can use ipaddress module:
    >>> import ipaddress
    >>> ipaddress.ip_address('192.0.43.10') in ipaddress.ip_network('192.0.0.0/16')
    True

    Quelle: https://stackoverflow.com/questions/...p-subnet-match
    Danke

    Darf ich fragen wonach du gegoogelt hast? Ich war nämlich anscheinend zu blöd dafür. (Oder wusstest du das so?)
    Lookbehind ist offline

  4. #4 Zitieren
    Retro Micky Avatar von Blue Force
    Registriert seit
    May 2009
    Beiträge
    26.192
    Zitat Zitat von Lookbehind Beitrag anzeigen
    Danke

    Darf ich fragen wonach du gegoogelt hast? Ich war nämlich anscheinend zu blöd dafür. (Oder wusstest du das so?)
    ich habe in Google gesucht nach python check ip in network. Dann wars die zweite Fundstelle. Vorher hatte ich noch gesucht nach Seiten mit Python Netzwerk Funktionen, da aber nichts gefunden.
    Von Python habe ich keine Ahnung
    Blue Force ist offline

  5. #5 Zitieren
    Dea
    Registriert seit
    Jul 2007
    Beiträge
    10.446
    Blue Force hat ja nun schon eine Lösung gepostet, aber spricht denn irgendetwas dagegen, das einfach selbst zu machen? Oder gibt's da noch irgendwelche Fettnäpfchen, die machen beachten sollte?

    Code:
    int checkIPinSubnet(int32 subnet, int32 subnetmask, int32 ip) {
        /* Ggf. die Subnetmask aus der Range (dem /x Teil) selber berechnen:
            int32 subnetmask = ~((1<<(32-subnetrange))-1);
        */
    
        return (subnet & subnetmask) == (ip & subnetmask);
    }
    Lehona ist offline

  6. #6 Zitieren
    Knight Commander Avatar von Kellendil
    Registriert seit
    Jul 2009
    Beiträge
    2.093
    Zitat Zitat von Lehona Beitrag anzeigen
    Blue Force hat ja nun schon eine Lösung gepostet, aber spricht denn irgendetwas dagegen, das einfach selbst zu machen? Oder gibt's da noch irgendwelche Fettnäpfchen, die machen beachten sollte?
    Dagegen spricht, dass die Bibliothek auch mit ipv6 Schreibweisen umgehen kann, die Funktionen gut dokumentiert und (hoffentlich) auch getestet sind, und außerdem bei Falscheingaben entsprechende Fehler geworfen werden.

    Kommt halt drauf an, ob das wichtiger ist als Geschwindigkeit... auf Stackoverflow wird ja auch deine Lösung als schnelle Alternative angegeben.
    Kellendil ist offline

  7. #7 Zitieren
    Tieftöner Avatar von Lookbehind
    Registriert seit
    Dec 2007
    Beiträge
    15.176
    Zitat Zitat von Lehona Beitrag anzeigen
    Blue Force hat ja nun schon eine Lösung gepostet, aber spricht denn irgendetwas dagegen, das einfach selbst zu machen? Oder gibt's da noch irgendwelche Fettnäpfchen, die machen beachten sollte?

    Code:
    int checkIPinSubnet(int32 subnet, int32 subnetmask, int32 ip) {
        /* Ggf. die Subnetmask aus der Range (dem /x Teil) selber berechnen:
            int32 subnetmask = ~((1<<(32-subnetrange))-1);
        */
    
        return (subnet & subnetmask) == (ip & subnetmask);
    }
    Das reicht halt nicht. Ich müsste zusätzlich noch n Parser schreiben, der erst mal die übliche Schreibweise "192.168.16.0/29" sauber in 2 Int-Werte für IP und Subnetz-Maske zerlegt. Ja, ist machbar.... natürlich. Aber, muss ich denn das Rad immer erst neu erfinden?
    Lookbehind ist offline

  8. #8 Zitieren
    Dea
    Registriert seit
    Jul 2007
    Beiträge
    10.446
    Zitat Zitat von Lookbehind Beitrag anzeigen
    Das reicht halt nicht. Ich müsste zusätzlich noch n Parser schreiben, der erst mal die übliche Schreibweise "192.168.16.0/29" sauber in 2 Int-Werte für IP und Subnetz-Maske zerlegt. Ja, ist machbar.... natürlich. Aber, muss ich denn das Rad immer erst neu erfinden?
    Nein, natürlich nicht. Aber wenn ich schon so "verzweifelt" bin, dass ich hier nachfrage...
    Da es ja tatsächlich eine fertige Lösung gibt (wofür gibt es die nicht in Python?), nimmt man natürlich die.
    Lehona ist offline

  9. #9 Zitieren
    Tieftöner Avatar von Lookbehind
    Registriert seit
    Dec 2007
    Beiträge
    15.176
    Zitat Zitat von Lehona Beitrag anzeigen
    Nein, natürlich nicht. Aber wenn ich schon so "verzweifelt" bin, dass ich hier nachfrage...
    ...
    Verzweifelt würd ich das nicht nennen. Aber ich mach bestimmte Dinge eben gern vernünftig, und meistens sind in solche "fertigen" Lösungen schon bedeutend mehr Hirnschmalz geflossen, als in meine Quick n' Dirty Implementierung. Daher bevorzuge ich einfach die fertige Version und such erst mal danach. Wenn es die nicht gibt, muss ich eben doch selbst ran.
    In diesem Fall konnt ich mir aber nicht vorstellen, dass es dazu noch nix fertiges gibt, obwohl ich nix gefunden hab. Darum hab ich gefragt.
    Ist jetzt nicht so, dass ich ohne diese Lösung nicht weiter gekommen wäre. Das in Python zu gießen war ohnehin schon der bessere Ansatz... der erste Entwurf war in Bash geschrieben ... hat das mit den IP-Adressen allerdings auch etwas... öhhh... anders gelöst (cut + grep)
    Lookbehind ist offline

  10. #10 Zitieren
    Legende Avatar von jabu
    Registriert seit
    Jul 2011
    Beiträge
    7.328
    War von falschen Voraussetzungen ausgegangen, weshalb ich den Mist mal weggemacht habe, sorry!
    jabu ist offline Geändert von jabu (19.05.2016 um 19:00 Uhr)

  11. #11 Zitieren
    Dea
    Registriert seit
    Jul 2007
    Beiträge
    10.446
    Vielleicht habe ich deine Kritik nicht richtig verstanden (und hätte vielleicht explizit erwähnen sollen, dass ich von wohlgeformten Eingaben ausgehe), aber das sagt der C99-Standard dazu:

    The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with
    zeros. If E1 has an unsigned type, the value of the result is E1 × 2E2, reduced modulo
    one more than the maximum value representable in the result type. If E1 has a signed
    type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is
    the resulting value; otherwise, the behavior is undefined.
    Das einzige Problem, das ich sehe, ist also, dass "1" vermutlich nicht uint32 ist und somit das Subnetz 0.0.0.0/0 (falls das überhaupt gültig ist?) ein undefiniertes Verhalten mit sich bringt.*


    *Vermutlich wäre das Verhalten selbst mit uint32 als Typ undefiniert, zumindest gehe ich mal davon aus, dass 0-1 für unsigned types implementation-defined/undefined ist.
    Lehona ist offline Geändert von Lehona (19.05.2016 um 19:09 Uhr)

  12. #12 Zitieren
    Legende Avatar von jabu
    Registriert seit
    Jul 2011
    Beiträge
    7.328
    Zitat Zitat von Lehona Beitrag anzeigen
    [...]
    Nein, das sollte keine Kritik an dir sein, sondern an deinem Ausgangsmaterial! Ich hatte, was mich jetzt sehr verwundert, den linken und den rechten Operanden der Verschiebeoperation miteinander verwechselt. Anscheinend war ich echt übermüdet, sorry. Dann ist dein Einwand absolut angebracht. Den Mist mache ich mal lieber weg, bevor er für weitere Konfusion sorgt. Danke für deinen freundlichen Hinweis! Und danke auch für das Zitat aus dem C99-Standard.

    Edit:
    Ich glaube aber, dass unter C sowie C++ bei vorzeichenlosen Typen (wenn sie es nach den Promotions noch sind, s.u.) Overflows sicher sind (in dem Sinne, dass definierte Werte herauskommen, was nicht heißen soll, dass man solche Situationen nicht manchmal abfangen müsste). Jedenfalls kenne ich einigen Code, welcher darauf aufbaut und habe, auch bei mir selbst, noch nie erlebt, dass es nicht klappt (was natürlich nichts heißen muss). Kann das gerne später mal aus dem Standard heraussuchen, aber den hast du wohl selbst, wie es aussieht. Bei vorzeichenbehafteten Typen habe ich beim Refactoring in ähnlichen Situationen immer vorsichtshalber auf unsigned abgeändert.

    C99 §6.2.5 Absatz 9:
    The range of nonnegative values of a signed integer type is a subrange of the corresponding unsigned integer type, and the representation of the same value in each type is the same.31)
    A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.
    31) The same representation and alignment requirements are meant to imply interchangeability as arguments to functions, return values from functions, and members of unions.
    Für mich ist das bei unsigned das natürliche Verhalten von üblicher Hardware, indem die nicht darstellbaren Stellen fehlen und alles andere bleibt (wer schon mal mit Flipflops Register gebastelt hat, weiß, was ich meine). So kann ich es mir am besten merken. Aber der Standard ist korrekt, indem er sich von der technischen Repräsentation unabhängig macht und das rein numerisch fasst, weshalb das "natürliche Verhalten" nur als eine Eselsbrücke gelten darf, denn theoretisch könnte jemand auf die Idee kommen und UINT_MAX auf einen unnatürlichen Wert legen. Dann greift die Definition immer noch, und meine ist falsch. Sicher wurde die Definition so gewählt, damit sie dem natürlichen Verhalten real existierender Hardware bestmöglich entgegenkommt, aber sie setzt solche nicht voraus.

    Um auf deine Frage zurückzukommen: Ich wüsste jedoch nicht, dass der Standard sagt, dass 0u-1u unbedingt ein Muster der Art ...1111111 ergeben müsste, weshalb das zwar nicht portabel, aber trotzdem nicht weniger definiert sein sollte. Aus dem starren Korsett des Standards sollte sich jedoch ergeben, dass alles andere ziemlich schwer darstellbar ist. Dass etwas anderes herauskommt, habe ich noch nicht gesehen, aber wenn wir schon bei Standard-Pedanterie sind, wird es langsam schwierig, die verstreuten Stellen aufzufinden, um einen einzigen logischen Ausdruck daraus zu fabrizieren, um ihn auf seine Lücken abzuklopfen, denn man sieht immer nur, was man schon gefunden hat.

    Wenn die 1 in deiner Subtraktion ein int ist und der andere Operand ein unsigned(!), dürfte sich deswegen kein Problem ergeben, da zu erwarten ist, dass bei der 1 ein impliziter Cast zu unsigned erfolgt. Irgendwo sollte auch das im Standard stehen, ich weiß gerade nur nicht, wo...*1

    Letztendlich ist hundertprozentig portabler Code, so erstrebenswert er auch ist, in der realen Welt ein Mythos. Wenn man sich hier dem Ideal etwas annähern möchte, dann könnte man z.B. versuchen, mehr mit den gewöhnlichen Operationen als mit Bitmasken zu arbeiten, Subtraktion, Modulo-Operator usw.

    *1: Also weiter:
    C99 §6.3.1.8 Absatz 1
    [...]
    Otherwise, the integer promotions are performed on both operands. Then the following rules are applied to the promoted operands:
    If both operands have the same type, then no further conversion is needed. Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.
    Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.
    Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the operand with signed integer type.
    Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type.
    Der grün markierte Satz sollte belegen, was ich oben schrieb, dass z.B. implizit von int nach unsigned umgewandelt wird, wenn ein Operand int und der andere unsigned int ist.

    Im roten Satz ist der Integer-Typ aber so groß, dass er auch alle Werte des Unsigned-Typs innerhalb seines vorzeichenlosen Teils abbilden kann, weshalb letzterer zum Integer-Typ umgewandelt wird, was den Erhalt des Vorzeichens garantiert.

    Nun gibt es manchmal noch eine weitere Sache zu berücksichtigen, indem, wie der Standard weiter oben sagt (gelb markiert, das "Otherwise" meint, dass es sich nicht um Fließkommatypen handelt), zuvor die Integer Promotions vorgenommen werden, wozu unter §6.3.1.1 u.a. Folgendes ausgeführt ist:
    The following may be used in an expression wherever an int or unsigned int may be used:
    — An object or expression with an integer type whose integer conversion rank is less than the rank of int and unsigned int.
    — A bit-field of type _Bool, int, signed int, or unsigned int.
    If an int can represent all values of the original type, the value is converted to an int;
    otherwise, it is converted to an unsigned int. These are called the integer promotions.
    All other types are unchanged by the integer promotions.
    The integer promotions preserve value including sign. As discussed earlier, whether a "plain" char is treated as signed is implementation-defined.
    Die Integer Promotions ergeben sich schon ganz pragmatisch aus der Breite eines Registers, obwohl man das aus Sicht des Standards so nicht formulieren sollte, aber daher stammt es. Deswegen werden kleinere Typen auf diese Breite geweitet und auf dieser Ebene verrechnet, was allerdings zu Fehlern führen kann, wenn man es unberücksichtigt lässt, siehe z.B. hier. Nur mal angenommen, es ginge: Wäre in dem verlinkten Beispiel ein int so klein wie ein char, dann würde zu unsigned umgewandelt! Ein unsigned char passt aber problemlos in den vorzeichenlosen Teil von int hinein, weshalb er in einen int umgewandelt wird. Größere Typen als int unterliegen nicht den Integer Promotions, wie der zitierte Abschnitt impliziert. Aber es greifen, wie sonst auch, die allgemeinen Regeln für arithmetische Ausdrücke, siehe §6.3.1.8.

    In der Praxis würde man sich zuerst geeignete Typen aussuchen, was hier gewiss keine vorzeichenbehafteten sind, damit es erst gar nicht zu solchen oder ähnlichen Schwierigkeiten kommt. Beipielsweise ist eine IP-Nr. natürlicherweise immer vorzeichenlos, ebenso wie Bitmasken und Bitshifting-Kram. Dann kommt man auch gar nicht erst in Versuchung, wegen eines tatsächlich oder vermeintlich benötigten Vorzeichens Operationen mit gleich großen Integers durchzuführen, wo dann irgendwo obskure Nebenwirkungen auftreten. Stellen, an denen solche Umwandlungen erfolgen, sollten besonders gut durchdacht und wohldokumentiert sein. Wenn sie über den Code verstreut sind, bekommt man das später kaum noch entflochten, weil der Code gerade systematisch darauf aufbaut, Vorzeichen an der Hand zu haben, was neben den zu erwartenden Bugs auch noch Unwartbarkeit mit sich bringt.
    jabu ist offline Geändert von jabu (22.05.2016 um 02:29 Uhr) Grund: 22.05.2016: Bezug zum verlinkten Beispiel klarer formuliert

  13. #13 Zitieren
    Legende Avatar von jabu
    Registriert seit
    Jul 2011
    Beiträge
    7.328
    Zitat Zitat von Lehona Beitrag anzeigen
    [...]
    Das einzige Problem, das ich sehe, ist also, dass "1" vermutlich nicht uint32 ist und somit das Subnetz 0.0.0.0/0 (falls das überhaupt gültig ist?) ein undefiniertes Verhalten mit sich bringt.*
    Auf 0.0.0.0 kommt es hier nicht an, der /0-Teil genügt.

    Vom Fabrizieren von Corner Cases, in realem Code ist dringend abzuraten. Denn dieser Umstand wäre nicht durch den Code selbst an der Stelle, wo man ihn verstehen muss, dokumentiert und damit außerordentlich fehlerträchtig. Was du woanders abfängst, wirst du beim späteren Lesen nicht erfassen können. Selbst wenn dir Wartbarkeit egal ist, kannst du nicht voraussehen, was auf einer höheren Schicht damit gemacht werden wird. Gutgemeinte Dokus über komplizierte Corner Cases wird man mit ungefähr derselben Wahrscheinlichkeit wie lange AGBs lesen. Am besten lässt man es also und schreibt gleich die Typen hin, die man meint und macht das sozusagen wasserdicht.

    Deine Annahme, dass die nackte 1 ein int sei, ist zutreffend. Du kannst aber nicht garantieren, dass ein int den von dir gewünschten Wertebereich habe, sondern lediglich, dass er unter C99 mindestens -32767 bis 32767 umfassen muss (was auf üblicher Hardware 16 Bit erfordert, wobei eigentlich -32768 bis 32767 möglich wäre), weshalb sich implementierungsabhängiges sowie implementierungsabhängiges undefiniertes Verhalten ergibt.

    Eine Implementierung kann anstelle des Zweierkomplementes das Einerkomplement verwenden, wobei die Bitmaske nicht mehr zu den IP-Nummern passt, es sei denn, man konstruiert die IP-Nummern derart, dass ihre binäre Repräsentation exakt der des Zweierkomplementes entspricht, was schwierig werden kann und bei Berechnungen auf dieser Basis falsche Ergebnisse liefern würde.

    Desweiteren sind Padding-Bits möglich. Eine IP-Nr. oder eine Bitmaske selbst muss also, da es der Standard erlaubt, auf 32-bittigen int-Typen nicht notwendigerweise mit jedem möglichen Wert definiert sein.

    Was ist überhaupt ein int? Da lässt der Standard also einiges offen. Meistens mus man aber nicht portabel programmieren, weshalb man sich z.B. darauf stützen kann, dass es kein Padding gibt und dass Zweierkomplement gegeben ist, wie es bei gängigen PC-Plattformen üblich ist. Für solche Garantien gibt es Typen wie z.B. int32_t, wie der weitere Verlauf zeigen wird.

    Nochmal zu C99 §6.5.7 Absatz 4:
    [...] If E1 has a signed type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.
    Daraus lese ich, dass E1 × 2E2 im Ergebnistyp darstellbar sein muss. Das ist er aber bereits nicht mehr, sobald er den positiven Wertebereich von int verlässt. Für mich ist er nur dann "representable", wenn sein Wert erhalten bleibt, denn sonst handelt es sich nicht mehr um E1 × 2E2. Ich bin mir zwar nicht ganz sicher, dass es tatsächlich so gemeint ist, aber der sonstige Gebrauch der Begriffe representable sowie result type lassen darauf schließen. Also könnte bzw. sollte sich dein Corner Case leider auf eine weitere Stelle erweitern.

    Integers mit fester Breite sind im Standard folgendermaßen definiert (int32 bzw. uint32 gehören nicht zum Standard), nachzulesen unter C99 §7.18.1.1:
    1 The typedef name intN_t designates a signed integer type with width N, no padding bits, and a two’s complement representation. Thus, int8_t denotes a signed integer type with a width of exactly 8 bits.
    2 The typedef name uintN_t designates an unsigned integer type with width N. Thus, uint24_t denotes an unsigned integer type with a width of exactly 24 bits.
    3 These types are optional. However, if an implementation provides integer types with widths of 8, 16, 32, or 64 bits, no padding bits, and (for the signed types) that have a two’s complement representation, it shall de?ne the corresponding typedef names.
    Welche dieser Typen es gibt, ist also implementierungsabhängig, wobei Satz 3 ihre Existenz schon sehr wahrscheinlich macht, aber eben nicht überall oder nur teilweise. Beispielsweise kommt eine Implementierung für ein 8-Bit-System ganz gut mit int8_t und uint8_t aus.

    Gucken wir mal in ein typisches stdint.h, welches natürlich implementierungsabhängig ist, hinein:
    typedef signed char int8_t;
    typedef unsigned char uint8_t;
    typedef short int16_t;
    typedef unsigned short uint16_t;
    typedef int int32_t;
    typedef unsigned uint32_t;
    Leider sind diese Typen optional, also implementierungsabhängig vorhanden oder nicht vorhanden. Aber das ist nicht weiter schlimm, weil die Kompilierung fehlschlägt, wo sie fehlen.

    Zitat Zitat von Lehona Beitrag anzeigen
    [...]
    *Vermutlich wäre das Verhalten selbst mit uint32 als Typ undefiniert, zumindest gehe ich mal davon aus, dass 0-1 für unsigned types implementation-defined/undefined ist.
    0u-1u ist glücklicherweise wohldefiniert, wie bei anderen vorzeichenlosen Typen auch. Es wäre bedauerlich, wenn nicht, weil man sonst grottenschlechte Performance hätte und gleich die meisten Controller wegschmeißen könnte. C ist dicht am natürlichen Verhalten von Hardware definiert, also wie Register und Operationen auf diesen funktionieren und wie der Stack funktioniert, ohne eine solche Hardware vorauszusetzen.

    Allerdings ist es trotzdem nicht ratsam, genauso viele (oder noch mehr) Stellen aus dem Register zu schieben, wie es selber umfasst, siehe C99 §6.5.7 Absatz 3:
    The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand. If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined.
    Es geht darum, ein möglichst breites Spektrum an Hardware zu unterstützen. Nebenbei ergeben sich über solche Garantien für den Compiler mögliche Performanceoptimierungen.
    jabu ist offline Geändert von jabu (22.05.2016 um 07:35 Uhr)

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •