Validieren einer Ip4-Addresse



  • Ich code im Moment meine eigene kleine Netzwerkbibliothek und möchte jetzt die Funktion is_ip() für das Validieren von Ip4-Adressen schreiben.
    Eigentlich könnte man sowas ja wunderschön mit Regex's lösen, aber die gibts ja leider nicht im C++ Standard. Und Boost will ich für meine Bibliothek nicht vorraussetzen.

    Im Moment sieht das ganze also so aus:
    (schnell in 5min hingekritzelt)

    bool is_ip(std::string ip)
    {
    	int numbers = 0;
    	int dots = 0;
    
    	for(std::string::iterator itor = ip.begin(); itor != ip.end(); itor++)
    	{
    		if((*itor)=='.')Ich bin über jetzten Ansatz dankbar.
    			dots++;
    		else if(std::isdigit(*itor))
    			numbers++;
    		else
    			return false;
    	}
    
    	return (numbers >= 4)
    		&& (numbers <= 12)
    		&& (dots == 3);
    }
    

    Soweit funktioniert auch alles, nur dass eben noch nicht auf die min/max Werte der einzelnen Werte geachtet wird, sowas hier passiert also problemlos:
    366.366.366.366 obwohl es keine gültige Ip4-Adresse ist.
    Hat jemand eine Idee wie man das ganze Problem elegant mit möglichst wenig Spaghetti-Code lösen könnte?
    Ich glaube kaum dass meine Lösung die eleganteste ist, vielleicht weiß jemand wie man sowas in Benutzung mit find() löst.
    Ich bin über jeden Ansatz dankbar.



  • Bist du dir sicher das man so eine Funktion überhaupt braucht? 🙄



  • in meine jetzigen design braucht man sie, ob nur mein design schlecht ist weiß ich nicht ^^.

    ich habe einen namespace ip4

    namespace ip4
    {
    		bool is_hostname(std::string hostname);
    		bool is_ip(std::string ip);
    		std::string ip_to_hostname(std::string ip);
    		std::string hostname_to_ip(std::string hostname);
    
    		class address
    }
    

    Jetzt erwarted der Konstruktor der Klasse address eine Zeichenkette die sowohl Ip-Addresse als auch Hostname sein kann (das wird mit ip4::is_ip() und ip4::is_hostname() geprüft). Ist es eine Ip wird es gleich in den privaten membere std::string ip gespeichert ansonsten erst mittels ip4::hostname_to_ip() konventiert und dann in ip gespeichert.

    address(std::string ip_or_hostname, int port)
    			{
    				set_ip(ip_or_hostname);
    				_port = port;
    			}
    
    			address(std::string ip_or_hostname)
    			{
    				set_ip(ip_or_hostname);
    			}
    
    			void set_ip(std::string ip_or_hostname)
    			{
    				if(is_hostname(ip_or_hostname))
    					_ip = hostname_to_ip(ip_or_hostname);
    				else
    					_ip = ip_or_hostname;
    
    				if(!is_ip(_ip))
    				{
    					//TODO: throw exception
    				}
    			}
    

    Designvorschläge nehme ich gerne an ^^.
    Zu perfekt muss es aber nicht sein, ist ja nur für den privaten Gebrauch gedacht.



  • Ich würde die Funktion getaddrinfo nehmen. Die kommt mit Hostname und IP klar und kann auch IPv6.
    Oder wenn du es so lassen willst gibt es noch die Funktion inet_addr, die man zum Überprüfunen benutzen könnte.



  • Versuch doch mal, die potentielle IP durch einen stringstream zu jagen und auszuwerten:

    bool check_ip(const string& ip)
    {
      stringstream sdat(ip);
      unsigned short nums[4];
      char dots[3];
      sdat>>nums[0]>>dots[0]
          >>nums[1]>>dots[1]
          >>nums[2]>>dots[2]
          >>nums[3];
      /*
        jetzt kannst du den Inhalt von nums (alle Felder sollen <256 sein),
        dots (soll nur '.' enthalten) und den Status von sdat (intakt) überprüfen
      */
    }
    

    (PS: Wenn du willst kannst du die einzelnen IP-Teile zur Weiterverarbeitung nutzen)



  • Sehr elegante Lösung CStoll, wusste garnicht dass stringstream das kann 🙂

    Habs jetzt aber trotzdem mal mit der von sc angesprochenen inet_addr gelöst, weil es kürzer ist. Man muss ja nicht immer das Rad neu erfinden.

    bool is_ip(const std::string& ip)
    {
    	return inet_addr(ip.c_str()) != INADDR_NONE;
    }
    


  • Wieso benutzt du iteratoren um durch den string zu gehen? Eine normale

    for(size_t i = 0; i < string.size(); ++i)
    

    Schleife tuts doch auch?
    Ansonsten würde ich stringstreams nehmen, immer bis zum Punkt suchen, ab in den Stringstream und ein int daraus machen, dann den Wertebereich prüfen.



  • also ich würd mir nen struct/class für sone adresse basteln. die 4 komponenten werden private member variablen und beim setzen gibs ne simple überprüfung, ob die jeweils in der richtigen range liegen. wenn nicht, schmeisste ne exception.

    so bleibts dem anwender überlassen, seine ips in dein struct zu drücken und eventuelle fehler abzufangen und auszubügeln.





  • xGhost schrieb:

    http://cplus.kompf.de/artikel/regex.html

    the_teedude schrieb:

    [...]
    Eigentlich könnte man sowas ja wunderschön mit Regex's lösen, aber die gibts ja leider nicht im C++ Standard. Und Boost will ich für meine Bibliothek nicht vorraussetzen.
    [...]

    Danke nochmal an alle, hab das Problem jetzt wie gesagt gelöst 🙂


Anmelden zum Antworten