Quel serait un bon moyen de déterminer si une chaîne contient une adresse IPv4? Devrais-je utiliser isdigit()
?
J'ai demandé une question similaire pour C++ . Vous devriez pouvoir utiliser une version légèrement modifiée (pour le C) de ce que j'ai créé à l'époque.
bool isValidIpAddress(char *ipAddress)
{
struct sockaddr_in sa;
int result = inet_pton(AF_INET, ipAddress, &(sa.sin_addr));
return result != 0;
}
Vous devrez utiliser #include <arpa/inet.h>
pour utiliser la fonction inet_pton () .
Mise à jour en fonction des commentaires à la question: Si vous voulez savoir si une chaîne de style C contient une adresse IP, vous devez combiner les deux réponses données jusqu'à présent. Utilisez une expression régulière pour rechercher des modèles qui correspondent approximativement à une adresse IP, puis utilisez la fonction ci-dessus pour vérifier la correspondance et voir si c'est la vraie affaire.
C’est une routine que j’écrivais il ya quelque temps pour un système intégré qui générait divers modèles suspects sur un réseau. En tant que tel, il utilise absolument no des éléments fantaisistes tels que des bibliothèques réseau ou même les bibliothèques C standard, préférant éviter tout ce qui est moderne, comme les bibliothèques de symboles de chaîne et de (frémissement) expressions régulières: adapté à à peu près n'importe quel environnement dans lequel vous pourriez vous trouver, et c'était incroyablement rapide.
Cependant, si vous êtes dans un environnement qui a quelque chose comme checkIp4Addess()
, je vous suggérerais de l’utiliser plutôt. C'est une indication des choses que vous devez parfois supporter lorsque vous faites des choses incorporées (bien que ce soit soit une vraie solution).
int isValidIp4 (char *str) {
int segs = 0; /* Segment count. */
int chcnt = 0; /* Character count within segment. */
int accum = 0; /* Accumulator for segment. */
/* Catch NULL pointer. */
if (str == NULL)
return 0;
/* Process every character in string. */
while (*str != '\0') {
/* Segment changeover. */
if (*str == '.') {
/* Must have some digits in segment. */
if (chcnt == 0)
return 0;
/* Limit number of segments. */
if (++segs == 4)
return 0;
/* Reset segment values and restart loop. */
chcnt = accum = 0;
str++;
continue;
}
/* Check numeric. */
if ((*str < '0') || (*str > '9'))
return 0;
/* Accumulate and check segment. */
if ((accum = accum * 10 + *str - '0') > 255)
return 0;
/* Advance other segment specific stuff and continue loop. */
chcnt++;
str++;
}
/* Check enough segments and enough characters in last segment. */
if (segs != 3)
return 0;
if (chcnt == 0)
return 0;
/* Address okay. */
return 1;
}
int validateIP4Dotted(const char *s)
{
int len = strlen(s);
if (len < 7 || len > 15)
return 0;
char tail[16];
tail[0] = 0;
unsigned int d[4];
int c = sscanf(s, "%3u.%3u.%3u.%3u%s", &d[0], &d[1], &d[2], &d[3], tail);
if (c != 4 || tail[0])
return 0;
for (int i = 0; i < 4; i++)
if (d[i] > 255)
return 0;
return 1;
}
C’est mon essai avec une programmation C de très faible niveau (actuellement utilisée dans l’un de mes programmes pour un microcontrôleur PIC) . Elle n’utilise pas la bibliothèque string.h . Elle n’utilise pas de pointeurs, car ce compilateur J'utilise ne fonctionne pas bien avec eux, de toute façon vous pourriez les utiliser . En tenant compte de cela et en définissant une variable pour gérer le tampon de données entrant comme ceci:
#define isdigit(x) isamong(x,"0123456789")
char IPACK_Buff[IPACK_SIZE];
// Check if string is a valid IP
int IPACK_is_valid_ip(int len)
{
int i = 0;
int j = 0;
int NumDots = 0;
char number[4] = "000\0";
// Check first char is numeric
if (!isdigit(IPACK_Buff[0]))
return 0;
for (i = 0 ; i< len; i++)
{
if (isdigit(IPACK_Buff[i]))
{
number[j] = IPACK_Buff[i];
j++;
if (j>3)
return 0;
}
else if (IPACK_Buff[i] == '.')
{
if (atof(number)> 255) return 0;
memset(number, '\0', 4);
j = 0;
NumDots++;
if(NumDots>3)
return 0;
}
}
if (NumDots == 3)
{
return 1;
}
else
return 0;
}//
J'espère que cette fonction vous aidera tous ... Encore une fois, tenez compte du faible niveau de programmation de cette fonction avant de le critiquer.
J'utiliserais cette expression régulière (courtoisie de Exemples d'expressions régulières ):
`\b(?:\d{1,3}\.){3}\d{1,3}\b`
Je vais donner la solution "ne veulent pas deux problèmes":
#include <string.h>
int isIp_v4( char* ip){
int num;
int flag = 1;
int counter=0;
char* p = strtok(ip,".");
while (p && flag ){
num = atoi(p);
if (num>=0 && num<=255 && (counter++<4)){
flag=1;
p=strtok(NULL,".");
}
else{
flag=0;
break;
}
}
return flag && (counter==3);
}
EDIT: strtok peut ne pas être thread-safe (crédit à Adam Rosenfield)
// you can even use the v value array to return the unsigned int
// version of the IP if desired in an unsigned int reference.
bool isvalidip(const char * s)
{
char t[8];
int p = 0;
int v[8];
int numnum = 0;
for (int i = 0; i < (int) strlen(s); i++) {
char c = s[i];
int cgood = 0;
if (c >= '0' && c <= '9' && p < 4) {
t[p++] = c;
t[p] = 0;
cgood++;
continue;
}
if (p == 4) return false;
if (c == '.') {
if (!p) return false;
v[numnum++] = atoi(t);
p = 0;
cgood++;
continue;
}
if (!cgood) return false; // not a valid character
if (numnum > 4) return false; // we have a lot of dots....
}
v[numnum++] = atoi(t); // we did not have a dot, we had a NULL.....
if (numnum != 4) return false; // we must have had 4 valid numbers....
for (int i = 0; i < 4; i++)
{
if (v[i] < 0 || v[i] > 255) return false; // octet values out-of-range
}
return true; //we good..
}
Dans l’URL/URI RFC 3986, l’adresse ipv4 de la forme de Backus-Naur augmentée (ABNF) est définie comme suit:
IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
dec-octet = DIGIT ; 0-9
/ %x31-39 DIGIT ; 10-99
/ "1" 2DIGIT ; 100-199
/ "2" %x30-34 DIGIT ; 200-249
/ "25" %x30-35 ; 250-255
J'ai implémenté le contrôle avec l'expression rationnelle sous la forme suivante:
// Although the RFC says ipv6 octects like 001 are not valid, it would be risky
// not to accept those
#define decoct "([01]?[0-9]?[0-9]|2[0-4][0-0]|25[0-5])"
#define ipv4 "(" decoct "\\." decoct "\\." decoct "\\." decoct ")"
Faites-le à partir de zéro comme ça. Ce code contient des outils pour vérifier si la chaîne contient une adresse IP IPv4.
#define MAX_HEX_NUMBER_COUNT 8
int ishexdigit(char ch)
{
if((ch>='0'&&ch<='9')||(ch>='a'&&ch<='f')||(ch>='A'&&ch<='F'))
return(1);
return(0);
}
int IsIp6str(char *str)
{
int hdcount=0;
int hncount=0;
int err=0;
int packed=0;
if(*str==':')
{
str++;
if(*str!=':')
return(0);
else
{
packed=1;
hncount=1;
str++;
if(*str==0)
return(1);
}
}
if(ishexdigit(*str)==0)
{
return(0);
}
hdcount=1;
hncount=1;
str++;
while(err==0&&*str!=0)
{
if(*str==':')
{
str++;
if(*str==':')
{
if(packed==1)
err=1;
else
{
str++;
if(ishexdigit(*str)||*str==0&&hncount<MAX_HEX_NUMBER_COUNT)
{
packed=1;
hncount++;
if(ishexdigit(*str))
{
if(hncount==MAX_HEX_NUMBER_COUNT)
{
err=1;
} else
{
hdcount=1;
hncount++;
str++;
}
}
} else
{
err=1;
}
}
} else
{
if(!ishexdigit(*str))
{
err=1;
} else
{
if(hncount==MAX_HEX_NUMBER_COUNT)
{
err=1;
} else
{
hdcount=1;
hncount++;
str++;
}
}
}
} else
{
if(ishexdigit(*str))
{
if(hdcount==4)
err=1;
else
{
hdcount++;
str++;
}
} else
err=1;
}
}
if(hncount<MAX_HEX_NUMBER_COUNT&&packed==0)
err=1;
return(err==0);
}
int IsIp4str(char *str)
{
int nnumber=0;
int value=0;
int err=0;
if(*str>='0'&&*str<='9')
{
value=*str-'0';
str++;
} else
return(0);
nnumber=1;
while(err==0&&*str!=0)
{
if(*str>='0'&&*str<='9')
{
if(255/value>=10)
{
value*=10;
if(255-value>=(*str-'0'))
{
value+=(*str-'0');
str++;
} else
err=1;
} else
err=1;
} else
{
if(*str=='.')
{
str++;
if(*str>='0'&&*str<='9')
{
if(nnumber==4)
err=1;
else
{
if(*str=='0')
{
*str++;
if(*str!='.'&&*str!=0)
err=1;
else
{
nnumber++;
value=0;
}
} else
{
nnumber++;
value=*str-'0';
str++;
}
}
} else
{
err=1;
}
} else
if(*str!=0)
err=1;
}
}
if(nnumber!=4)
err=1;
return(err==0);
}
Fonction IsIp4str (char * str) teste si la chaîne contient le format d'adresse à quatre adresses IP. IsIp6str (char * str) test de la fonction si la chaîne contient le format d'adresse à six adresses IP.
Fonctions IsIp4str (char * str) et IsIp6str (char * str) renvoie true si la chaîne str contient l'adresse IP ou false si la chaîne str ne contient pas l'adresse IP.
Si vous avez besoin de vérifier si la chaîne contient le format d'adresse IP IPv6, vous pouvez utiliser la fonction IsIp6str (char * str). Cela fonctionne de la même manière que
Je modifie une des réponses pour la rendre plus complète et attache tout le code (inclure test)
#include <stdio.h>
#include <assert.h>
#include <string.h>
int validateIP4Dotted(char *str, unsigned int pIPAddress[])
{
int segs = 0; /* Segment count. */
int chcnt = 0; /* Character count within segment. */
int accum = 0; /* Accumulator for segment. */
/* Catch NULL pointer. */
if (str == NULL)
return 0;
/* Process every character in string. */
while (*str != '\0')
{
/* Segment changeover. */
if (*str == '.')
{
pIPAddress[segs] = accum;
/* Must have some digits in segment. */
if (chcnt == 0 || chcnt > 3)
return 0;
/* Limit number of segments. */
if (++segs == 4)
return 0;
/* Reset segment values and restart loop. */
chcnt = accum = 0;
str++;
continue;
}
/* Check numeric. */
if ((*str < '0') || (*str > '9'))
return 0;
/* Accumulate and check segment. */
if ((accum = accum * 10 + *str - '0') > 255)
return 0;
/* Advance other segment specific stuff and continue loop. */
chcnt++;
str++;
}
/* Check enough segments and enough characters in last segment. */
pIPAddress[segs] = accum;
if (segs != 3)
return 0;
if (chcnt == 0 || chcnt > 3)
return 0;
if (pIPAddress[0] >=224)
return 0;
/* Address okay. */
return 1;
}
int main()
{
unsigned int IpAddress[4];
char str_ip[128];
strcpy(str_ip, "192.168.1.10");
assert(validateIP4Dotted(str_ip, IpAddress));
assert(
IpAddress[0] == 192 && IpAddress[1] == 168 && IpAddress[2] == 1
&& IpAddress[3] == 10);
strcpy(str_ip, "0.0.0.0");
assert(validateIP4Dotted(str_ip, IpAddress));
assert(
IpAddress[0] == 0 && IpAddress[1] == 0 && IpAddress[2] == 0
&& IpAddress[3] == 0);
strcpy(str_ip, "/192.168.1.10");
assert(!validateIP4Dotted(str_ip, IpAddress));
strcpy(str_ip, "192..168.1.10");
assert(!validateIP4Dotted(str_ip, IpAddress));
strcpy(str_ip, ".192.168.1.10");
assert(!validateIP4Dotted(str_ip, IpAddress));
strcpy(str_ip, "192.168.1.10.");
assert(!validateIP4Dotted(str_ip, IpAddress));
strcpy(str_ip, "192.168.1.10.10");
assert(!validateIP4Dotted(str_ip, IpAddress));
strcpy(str_ip, "192.168.1.");
assert(!validateIP4Dotted(str_ip, IpAddress));
strcpy(str_ip, "192.168.1");
assert(!validateIP4Dotted(str_ip, IpAddress));
strcpy(str_ip, "255.168.1.10");
assert(!validateIP4Dotted(str_ip, IpAddress));
strcpy(str_ip, "10.260.1.10");
assert(!validateIP4Dotted(str_ip, IpAddress));
strcpy(str_ip, "10.200.0001.10");
assert(!validateIP4Dotted(str_ip, IpAddress));
return 0;
}
J'avais besoin de savoir si la chaîne entrante "contient" une adresse IP valide et de renvoyer un pointeur sur la partie de la chaîne entrante qui correspond à l'adresse IP valide, le cas échéant. Sinon, retourne un pointeur nul.
Voici du code qui semble fonctionner, bien que pas encore testé, je l’ai écrit et j’ai essayé rapidement. Je n'ai pas encore ajouté de contrôle pour limiter les nombres à des valeurs sur un octet, mais assurez-vous qu'ils sont limités à trois chiffres.
int IsDigit(char ch)
{
int is_digit = 0;
if ( ch >= '0' && ch <= '9' )
{
is_digit = 1;
}
return is_digit;
}
#define FIND_IP_START 0
#define FIND_IP_DIGIT 1
#define FIND_IP_Dig_OR_DEC 2
#define FIND_IP_DECIMAL 3
#define FIND_IP_Dig_OR_END 4
#define FIND_IP_END 5
#define FIND_IP_DONE 6
char * StringContainsValidIpAddress(char * input_buf_pointer)
{
char * pos = input_buf_pointer;
int octets = 0;
int digits = 0;
int state = FIND_IP_START;
char * ip_string = 0;
char ch = *pos;
while ( (ch != NULL) && (state != FIND_IP_DONE) )
{
switch ( state )
{
case FIND_IP_START:
if ( IsDigit(ch) )
{
ip_string = pos; //potential start of ip string
digits = 1; // first digit
octets = 1; // of first octet
state = FIND_IP_Dig_OR_DEC;
}
break;
case FIND_IP_DIGIT:
if ( IsDigit(ch) )
{
digits = 1; // first digit
octets++; // of next octet
if ( octets == 4 )
{
state = FIND_IP_Dig_OR_END;
}
else
{
state = FIND_IP_Dig_OR_DEC;
}
}
else
{
// Start over
state = FIND_IP_START;
}
break;
case FIND_IP_Dig_OR_DEC:
// Here we are looking for another digit
// of the same octet or the decimal between
// octets.
if (ch == '.')
{
state = FIND_IP_DIGIT;
}
else if ( IsDigit(ch) )
{
digits++; // next digit
if ( digits == 3 )
{
state = FIND_IP_DECIMAL;
}
}
else
{
// Start over
state = FIND_IP_START;
}
break;
case FIND_IP_DECIMAL:
if (ch == '.')
{
state = FIND_IP_DIGIT;
}
break;
case FIND_IP_Dig_OR_END:
// Here we are looking for another digit
// of the same octet or the end (which could
// be a space or CR or LF or really any
// non-digit).
if ( IsDigit(ch) )
{
digits++; // next digit
if ( digits == 3 )
{
state = FIND_IP_END;
}
}
else
{
*pos = 0; // Null terminate the IP address string
state = FIND_IP_DONE;
}
break;
case FIND_IP_END:
if ( !IsDigit(ch) )
{
*pos = 0; // Null terminate the IP address string
state = FIND_IP_DONE;
}
break;
case FIND_IP_DONE:
break;
default:
break;
}
// Fetch the next character
ch = *++pos;
}
if (state == FIND_IP_DONE)
{
return ip_string;
}
else
{
return 0;
}
}
Voici le début d’une fonction sur laquelle j’ai travaillé, même si elle n’est pas complète, elle peut susciter des idées ou des commentaires. La pensée derrière la fonction est;
Je pense que cela dépend de la profondeur avec laquelle vous voulez aborder le problème, de la profondeur avec laquelle vous voulez comprendre les problèmes qui pourraient survenir.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>
int isIP(char *ip)
{
char *data_ptr = ip; // Create a pointer to passed data
int orig_str_size = 0; // Create an int to hold passed data size
int str_index = 0; // Create an int to iterate individual ip characters
int dot_count = 0; // Create an int to check for the number of dots
// Count the number of characters in data_ptr
while (*data_ptr++ != '\0'){ orig_str_size++; }
if(orig_str_size <= 0) // If nothing
{
printf("Get a grip, ip is empty\n\n");
exit(0);
}
else // If within IPv4 size range
if(orig_str_size >= 7 && orig_str_size <= INET_ADDRSTRLEN)
{
char *data1_ptr = ip; // Create a pointer to passed data
printf("Within IPv4 range, %i characters in length\n\n", orig_str_size);
// Count the number of dots in the string, 3 for IPv4
for(str_index; str_index < orig_str_size; str_index++)
{
if(data1_ptr[str_index] == '.'){ dot_count++; }
}
// If theres 3 dots, while ignoring dots, check each char is a digit
if(dot_count == 3)
{
printf("There's three dots in the string\n\n");
data1_ptr = ip;
str_index = 0;
// Iterate the string char by char
for(str_index; str_index < orig_str_size; str_index++)
{
// Ignoring dots
if(data1_ptr[str_index] != '.')
{
// If isdigit() is happy its a digit and isalpha() happy not alphabetic
if(isdigit(data1_ptr[str_index]) && !isalpha(data1_ptr[str_index]))
{
printf("Digit found and is not alphabetic\n\n");
continue;
}
else
if(!isdigit(data1_ptr[str_index]) && isalpha(data1_ptr[str_index]))
{
printf("Not a recognised IPv4 address, character detected in string\n\n");
exit(0);
}
}
}
return 0;
}
}
else // If IPv6
if(orig_str_size > 0 && orig_str_size > INET_ADDRSTRLEN && orig_str_size <= INET6_ADDRSTRLEN)
{
printf("Within IPv6 range %i\n\n", orig_str_size);
return 0;
}
else
{
printf("Unknown target format, the format you provided as a target is not implemented\n\n");
exit(0);
}
}
Interconnexion TCP/IP
RFC791 - Protocole Internet - https://tools.ietf.org/html/rfc791
Le manuel Cisco Internetworking http://docwiki.Cisco.com/wiki/Internetworking_Technology_Handbook
Modèle de référence de l'interconnexion de systèmes ouverts http://docwiki.Cisco.com/wiki/Internetworking_Basics#Open_Systems_Interconnection_Reference_Model
Dépannage de Cisco sur les réseaux TCP/IP https://www.Cisco.com/en/US/docs/internetworking/troubleshooting/guide/tr1907.pdf
Quel est le plus grand numéro de port réseau TCP/IP autorisé pour IPv4?