У меня есть интересная проблема с обнаружением IP-адреса в C++. Я использовал функцию inet_pton и структуру sockaddr_in. Если строка действительна IPv4 или IPv6, функция вернет AF_INET или AF_INET6. В противном случае возвращается ноль.
Код ниже не работает. SIGSEGV в состоянии обнаружения IPv6 при правильном вводе адреса IPv6 (адрес IPv4 и неверный адрес в порядке). Такая же проблема возникает после удаления условия IPv4.
#include <string>
#include <iostream>
#include <arpa/inet.h>
using namespace std;
int isIP(string);
int main(int argc, char *argv[]){
string s = "::1";
int test = isIP(s);
return 0;
}
int isIP(string addr){
struct sockaddr_in sa;
if((inet_pton(AF_INET, addr.c_str(), &(sa.sin_addr))))
return AF_INET;
if((inet_pton(AF_INET6, addr.c_str(), &(sa.sin_addr))))
return AF_INET6;
return 0;
}
Но когда функция IsIP изменена, как коды ниже, все в порядке.
int isIP(string addr){
struct sockaddr_in sa;
cout << addr + "\n";
if(inet_pton(AF_INET, addr.c_str(), &(sa.sin_addr)))
return AF_INET;
if(inet_pton(AF_INET6, addr.c_str(), &(sa.sin_addr)))
return AF_INET6;
return 0;
}
или
int isIP(string addr){
struct sockaddr_in sa, sa2;
if((inet_pton(AF_INET, addr.c_str(), &(sa.sin_addr))))
return AF_INET;
if((inet_pton(AF_INET6, addr.c_str(), &(sa2.sin_addr))))
return AF_INET6;
return 0;
}
или
int isIP(string addr){
struct sockaddr_in sa;
int r1 = inet_pton(AF_INET, addr.c_str(), &(sa.sin_addr));
int r2 = inet_pton(AF_INET6, addr.c_str(), &(sa.sin_addr));
if(r1)
return AF_INET;
if(r2)
return AF_INET6;
return 0;
}
Какова эта проблема при первой реализации функции isIP?
struct sockaddr_in sa;
Это структура для IPv4; у него недостаточно места для адресов IPv6, поэтому в этих случаях вы выходите за рамки.
Добавление большего количества кода к вашей функции, так что это делает доступной больше памяти для функции - либо путем объявления другой переменной, либо путем запуска некоторых произвольных конструкций, определенных для реализации, о которых мы не можем рационализировать, - так что, когда вы переполняете sa
, вы "переполняется в память, принадлежащую процессу, и поэтому не вызывает ошибку нарушения прав доступа. Однако это все еще очень неправильно.
Адреса IPv6 должны быть прочитаны в struct in6_addr
; один содержится внутри struct sockaddr_in6
так, например:
bool isIPv6(const string& addr)
{
struct sockaddr_in6 sa;
if (inet_pton(AF_INET6, addr.c_str(), &(sa.sin_addr)))
return true;
return false;
}
Вы должны передать указатель на struct in6_addr в случае теста ipv6.