Reputation: 31
Port scanning c++ method TCP, sometimes function hangs on some IPs. Here is the problem, I have the main function where the packet is sent, and port handling.
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;
}
}
** Function for enabling non-blocking mode:**
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
}
** And the function that binds it and others, such as opening a socket, closing and enabling non-blocking mode:**
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;
}
Where can the problem be? Generally, the scanning occurs in the threads, to work with them I use future.
But through gdb I understand that it is not because of them, but hangs on one of these functions, how can it be fixed, or at least why it happens. I have no explanation.
Scanning random ip. And then it just stops and the function hangs. The IPs are not connected to this in any way.
Upvotes: 1
Views: 60
Reputation: 31
I did not fully understand what the problem was, but my timeout did not work, I just rewrote the main function, and added processing already in it. This is what came out.
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;
}
Upvotes: 0