Сканирование портов c++ метод TCP, бывает зависание функции на некоторых айпи
Сканирование портов c++ метод TCP, бывает зависание функции на некоторых айпи. Вот такая проблема, у меня есть основная функция где проходит отправка пакета, и обработка порта.
int send_tcp_packet(int sock, const struct sockaddr_in* target_address, int timeout_ms) {
int ret = connect(sock, (struct sockaddr*)target_address, sizeof(*target_address));
if (ret < 0 && errno != EINPROGRESS){
return PORT_CLOSED;
}
if (ret == -1) {
int error_code = 0;
#ifdef _WIN32
error_code = WSAGetLastError();
#else
error_code = errno;
#endif
if (error_code == EINPROGRESS || error_code == EINTR) {
fd_set read_fds, write_fds;
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_SET(sock, &read_fds);
FD_SET(sock, &write_fds);
struct timeval tv;
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
int result = select(sock + 1, &read_fds, &write_fds, NULL, &tv);
if (result == -1) {
perror("select");
return PORT_ERROR;
}
else if (result == 0) {
int err;
socklen_t err_len = sizeof(err);
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void *)&err, &err_len) != 0) {
perror("getsockopt");
return PORT_ERROR;
}
if (err == ECONNREFUSED || err == ETIMEDOUT) {
return PORT_CLOSED;
}
else if (err == EHOSTUNREACH || err == EADDRINUSE) {
return PORT_ERROR;
}
else {
char *errstr = strerror(err);
return PORT_FILTERED;
}
}
else {
if (FD_ISSET(sock, &write_fds) || FD_ISSET(sock, &read_fds)) {
return PORT_OPEN;
} else {
return PORT_CLOSED;
}
}
}
else {
char *errstr = strerror(error_code);
return PORT_ERROR;
}
}
else {
close(sock);
return PORT_OPEN;
}
}
Функция для включения неблокирующего режима:
void set_non_blocking(int sock) {
#ifdef _WIN32
u_long iMode = 1;
ioctlsocket(sock, FIONBIO, &iMode);
#else
int flags = fcntl(sock, F_GETFL, 0);
if (flags == -1) {
return;
}
if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) {
return;
}
#endif
}
И функция которая связывает её и другие, ну там открытие сокета, закрытие и включение неблокирующего режима:
int tcp_scan_port(const char* host, int port, int timeout_ms){
int sock = create_socket();
set_non_blocking(sock);
struct sockaddr_in target_address;
memset(&target_address, 0, sizeof(target_address));
target_address.sin_family = AF_INET;
target_address.sin_port = htons(port);
inet_pton(AF_INET, host, &target_address.sin_addr);
int result = send_tcp_packet(sock, &target_address, timeout_ms);
close_socket(sock);
return result;
}
Где может быть проблема? Вообще сканирование происходит в потоках, для работы с ними использую future.
Но через gdb я так понял что это не из за них, а именно зависание происходит на одной из этих функций, как это можно исправить, или хотя-бы почему это происходит. У меня нету объяснения.
Ответы (1 шт):
Я не доконца понял в чём была проблема, но у меня не работал таймаут, я просто переписал главную функцию, и добавил обработку уже в неё. Вот что вышло.
int tcp_scan_port(const std::string& ip, int port, int timeout_ms) {
const char* addr = ip.c_str();
struct sockaddr_in addr_s;
struct timeval tv;
int so_error;
int fd=-1;
struct timespec tstart={0,0}, tend={0,0};
fd_set read_fds, write_fds;
addr_s.sin_family = AF_INET;
addr_s.sin_addr.s_addr = inet_addr(addr);
addr_s.sin_port = htons(port);
clock_gettime(CLOCK_MONOTONIC, &tstart);
fd = create_socket();
set_non_blocking(fd);
int rc = connect(fd, (struct sockaddr *)&addr_s, sizeof(addr_s));
if (rc == 0) {
clock_gettime(CLOCK_MONOTONIC, &tend);
close_socket(fd);
return PORT_OPEN;
}
else if (rc == -1 && errno == EINPROGRESS) {
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_SET(fd, &read_fds);
FD_SET(fd, &write_fds);
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
rc = select(fd + 1, &read_fds, &write_fds, NULL, &tv);
if (rc > 0) {
socklen_t len = sizeof(so_error);
getsockopt(fd, SOL_SOCKET, SO_ERROR, &so_error, &len);
if (so_error == 0) {
clock_gettime(CLOCK_MONOTONIC, &tend);
close(fd);
return PORT_OPEN;
}
else {
close_socket(fd);
return PORT_FILTERED;
}
}
else if (rc == 0) {
close(fd);
return PORT_CLOSED;
}
}
close_socket(fd);
return PORT_ERROR;
}