So I made a port scanner in C++ this morning and it seems to work alright, just having one rather annoying issue with it- whenever I use it to scan an IP over the network, it takes a good 10-20 seconds PER port.
It seems like the connect() method is what's taking it so long.
Now aside from multi-threading, which I'm sure will speed up the process but not by much, how could I make this faster? Here is the section of code that does the scanning:
for (i = 0; i < a_size(port_no); i++)
{
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
target.sin_family = AF_INET;
target.sin_port = htons(port_no[i]);
target.sin_addr.s_addr = inet_addr(argv[1]);
if (connect(sock, (SOCKADDR *)&target, sizeof(target)) != SOCKET_ERROR)
cout << "Port: " << port_no[i] << " - open" << endl;
else
cout << "Port: " << port_no[i] << " - closed" << endl;
closesocket(sock);
}
If you need more let me know.
Oh also, I am using the winsock2.h file. Is it because of this that its so slow?
When you call connect(2), the OS initiates the three-way handshake by sending a SYN packet to the other peer. If no response is received, it waits a little bit and sends a few more SYN packets. If no response is still received after a given timeout, then the operation fails, and connect(2) returns with the error code ETIMEODOUT.
Ordinarily, if a peer is up but not accepting TCP connections on a given port, it will reply to any SYN packets with a RST packet. This will cause connect(2) to fail much more quickly (one network round-trip time) with the error ECONNREFUSED. However, if the peer has a firewall set up, it'll just ignore your SYN packets and won't send those RST packets, which will cause connect(2) to take a long time to fail.
So, if you want to avoid waiting for that timeout for every port, you need to do multiple connections in parallel. You can do this multithreading (one synchronous connect(2) call per thread), but this doesn't scale well since threads take up a fair amount of resources.
The better method would be to use non-blocking sockets. To make a socket non-blocking, call fcntl(2) with the F_SETFL option and the O_NONBLOCK option. Then, connect(2) will return immediately with either EWOULDBLOCK or EAGAIN, at which point you can use either select(2) or poll(2) and friends to monitor a large number of sockets at once.
Try creating an array of non-blocking sockets to queue up a bunch of connection attempts at once.
Read about it here
I figured out a solution that works on windows. First I added:
u_long on = 1;
timeval tv = {0, 1000}; //timeout value in microseconds
fd_set fds;
FD_ZERO(&fds);
then i changed this code to look like this:
for (i = 0; i < a_size(port_no); i++)
{
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
FD_SET(sock, &fds);
ioctlsocket(sock, FIONBIO, &on);
target.sin_family = AF_INET;
target.sin_port = htons(port_no[i]);
target.sin_addr.s_addr = inet_addr(argv[1]);
connect(sock, (SOCKADDR *)&target, sizeof(target));
err = select(sock, &fds, &fds, &fds, &tv);
if (err != SOCKET_ERROR && err != 0)
cout << "Port: " << port_no[i] << " - open" << endl;
else
cout << "Port: " << port_no[i] << " - closed" << endl;
closesocket(sock);
}
and it seems to function much faster now! I will do some work to optimize it & clean it up a bit, but thank you for all your input everyone who responded! :)
Related
Right now, I am trying to specify options with setsockopt() using the following code:
// bind socket
// Use setsockopt() function to make sure the port is not in use
int yes = 1;
setsockopt(TCPSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
setsockopt(TCPSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
status = bind(TCPSocket, host_info_list->ai_addr, host_info_list->ai_addrlen);
if (status == -1) std::cout << "bind error" << std::endl ;
// listen for connections
status = listen(TCPSocket, 5);
if (status == -1) std::cout << "listen error" << std::endl ;
int new_sd;
struct sockaddr_storage their_addr;
socklen_t addr_size = sizeof(their_addr);
new_sd = accept(TCPSocket, (struct sockaddr *)&their_addr, &addr_size);
if (new_sd == -1) std::cout << "listen error" << std::endl ;
Note tv is an already-specified timeval.
When I make only the first setsockopt() call, everything works fine. However, with the addition of the second (which does not return any errors), I encounter the second "listen error" specified in the code. I'm not sure why setting the timeout value affect this, can someone explain?
I do not take credit for the code specified; it is modified from the code presented in the tutorial here: http://codebase.eu/tutorial/linux-socket-programming-c/
If you see a TCP state diagram like this one you see there's a state called TIME_WAIT when actively closing a socket. This state can take some time before it ends, up to four minutes according to RFC793.
While the socket is in the TIME_WAIT you can not bind to an interface using the same address-port pair as the socket that is in the wait state. Setting the SO_REUSEADDR flag om a socket enables other sockets to bind to the address when the current socket (with the flag set) is in the TIME_WAIT state.
The SO_REUSEADDR option is most useful for server (passive, listening) sockets.
As for your problem, after each call to setsockopt check what it returns, and if it's -1 then you check errno to see what went wrong. You can use perror or strerror to print or get a printable string for the error, like
if (setsockopt(TCPSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) < 0)
{
std::cerr << "Error setting the SO_REUSEADDR: " << strerror(errno) << '\n';
// Do something appropriate
}
Joachim's solution did a great job of answering my intial question and explaining setsockopt(). To answer my own question after realizing the issue was further down in the code, the timeout affects the server being able to listen to a port. Say the timeout is only 10ms, the server must be started, then the client, and a connection must be established in that time. This wasn't happening in my case, thus the resulting error.
I'm attempting to create a method that listens for a connection request to a specific port using a TCP protocol, with no libraries other than those that come with the Windows OS. The method seems to work fine with creating a socket and binding to a port; the problem seems to be with the listen() function. Even with no connection request to any port, it continually returns the value of zero, meaning, straight off of Microsoft's website -
If no error occurs, listen returns zero.
The strange part is that this happens with all port values; it seems to find a connection request for randomly attempted ports, ranging from 1234, to 8000, to -154326. For each of these, it's returning a value of zero.
What it should be doing is continually running until a connection request is found (this is what SOMAXCONN apparently indicates); once again, straight off of Microsoft's website -
If there are no available socket descriptors, listen attempts to continue to function.
Here is the method itself -
bool listenOnPort(SOCKET networkSocket, int portNumber) {
WSADATA wsadata;
int error = WSAStartup(0x0202, &wsadata);
if(error) {
cout << "Failed to start up Windows Sockets API." << endl;
return false;
}
if(wsadata.wVersion != 0x0202) {
WSACleanup();
cout << "Failed to find a valid Windows Sockets API." << endl;
return false;
}
SOCKADDR_IN address;
address.sin_family = AF_INET;
address.sin_port = htons(portNumber);
address.sin_addr.s_addr = htonl(INADDR_ANY);
networkSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(networkSocket == INVALID_SOCKET) {
cout << "Failed to create a network socket." << endl;
return false;
}
if(bind(networkSocket, (LPSOCKADDR)&address, sizeof(address)) == SOCKET_ERROR) {
cout << "Failed to bind to the port." << endl;
return false;
}
cout << "Listening for a connection to port " << portNumber <<"..." << endl;
listen(networkSocket, SOMAXCONN);
cout << "Found a connection!" << endl;
}
Any explanation/word of advice is appreciated - thank you ahead of time!
You've confused listen with accept. listen reserves the port for your application, and queues incoming connections. accept waits for an incoming connection (if one isn't already queued).
listen will succeed when there is no incoming connection attempt.
http://linux.die.net/man/2/listen
listen() marks the socket referred to by sockfd as a passive socket, that is, as a socket that will be used to accept incoming connection requests using accept(2).
You must call "listen()" before you can call "accept()"; but "accept()" is the call that accepts new connections (and gives you a new socket for each new connection).
Here's the man page for "accept()":
http://linux.die.net/man/2/accept
Better, look at Beej's Guide for an excellent introduction to sockets programming:
http://beej.us/guide/bgnet/output/html/multipage/
PS:
And don't forget to call WSAStartup() if you're using Windows sockets :)
Rant: I really dislike boost::asio, So I've been looking at alternatives and came across libev. Which seems simple enough for me, but is doing a few things I cannot understand. If those are too many questions in one thread, please let me know.
1) I set the listening socket to NON_BLOCK, I also set each accepted incoming connection as NON_BLOCK, yet somewhere in the code the socket(s) turns into BLOCK.
Ex:
bool Server::Start()
{
// Setup event loop
loop = ev_default_loop(EVBACKEND_SELECT); //EVFLAG_AUTO ?
// Create Socket
sockfd = socket(PF_INET, SOCK_STREAM, 0);
addr_len = sizeof(addr)
// Set Socket to non blocking
fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK);
if (fcntl(sockfd, F_GETFL) & O_NONBLOCK) std::cout << "Socket is NONBLOCK" << std::endl;
else std::cout << "Socket is BLOCK" << std::endl;
if (sockfd < 0) {
std::cout << "ERROR opening socket" << std::endl;
return false;
}
bzero((char *)&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
// Bind port to socket
if (bind(sockfd,(struct sockaddr*)&addr, sizeof(addr))!=0) {
std::cout << "bind error" << std::endl;
return false;
}
// Listen
if (listen(sockfd, 2) < 0) {
std::cout << "listen error" << std::endl;
return false;
}
// Initialize and start a watcher to accepts client requests
ev_io_init(&w_accept, accept_cb, sockfd, EV_READ);
ev_io_start(loop, &w_accept);
return true;
}
I have tried to make the main loop also not to block:
void Server::MainLoop()
{
// Start infinite loop
while (1) {
ev_loop(loop, EVLOOP_NONBLOCK);
}
}
But it doesnt seem to have made a different. PLEASE DO NOT redirect me to the documentation (the only available source of documentation on the internet) I have read it.
I do this for the client socket that has been accepted:
void accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
....
c->client_sd = accept(watcher->fd, (struct sockaddr *)&c->client_addr, &c->client_len);
....
ev_io *w_client = (struct ev_io*) malloc (sizeof(struct ev_io));
ev_io_init(w_client, read_cb, c->client_sd, EV_READ);
ev_io_start(loop, w_client);
fcntl(watcher->fd, F_SETFL, fcntl(watcher->fd, F_GETFL) | O_NONBLOCK);
Yet every time my read callback is executed, the socket is magically set to BLOCK
2) I have tried setting a timeout for the socket:
struct timeval timeout;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
sizeof(timeout)) < 0)
error("setsockopt failed\n");
if (setsockopt (sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,
sizeof(timeout)) < 0)
error("setsockopt failed\n");
(Taken from here: this question)
It simply doesn't work. Is this because the sockets are reset to BLOCKing mode ?
3) I have seen a C++ wrapper for libev. I absolutely hate the fact I have to make the callbacks static functions, it ruins everything for me. Yet all the examples I have seen use:
signal.loop.break_loop();
and
loop.run(0);
which, funnily enough produces:
error: ‘struct ev::loop_ref’ has no member named ‘break_loop’ error:
‘struct ev::default_loop’ has no member named ‘run’
on Debian Squeeze.
So, what I am asking is:
What, who, where is the socket changed from NON_BLOCK to BLOCK ?
How (if) can I set a timeout for the socket (blocking or non-blocking)
What is wrong with ev++.h and why are those nice people using the wrappers I can't use?
Please, bear in mind that I can use the sockets to read and send data, but in a blocking manner, without timeouts. Furthermore, as this is a server, I NEED to keep the code in classes, as I have to save messages per connected clients. Making this static or non-class methods simply ruins it, or forces me to take a very different approach.
PS: Any alternatives to libev ?
You aren't setting the client FD to non-blocking mode. You are setting the listening socket FD.
In my C++ application, I am using ::bind() for a UDP socket, but on rare occasions, after reconnection due to lost connection, I get errno EADDRINUSE, even after many retries. The other side of the UDP connection which will receive the data reconnected fine and is waiting for select() to indicate there is something to read.
I presume this means the local port is in use. If true, how might I be leaking the local port such that the other side connects to it fine? The real issue here is that other side connected fine and is waiting but this side is stuck on EADDRINUSE.
--Edit--
Here is a code snippet showing that I am already doing SO_REUSEADDR on my TCP socket, not on this UDP socket for which I am having issue:
// According to "Linux Socket Programming by Example" p. 319, we must call
// setsockopt w/ SO_REUSEADDR option BEFORE calling bind.
// Make the address is reuseable so we don't get the nasty message.
int so_reuseaddr = 1; // Enabled.
int reuseAddrResult
= ::setsockopt(getTCPSocket(), SOL_SOCKET, SO_REUSEADDR, &so_reuseaddr,
sizeof(so_reuseaddr));
Here is my code to close the UDP socket when done:
void
disconnectUDP()
{
if (::shutdown(getUDPSocket(), 2) < 0) {
clog << "Warning: error during shutdown of data socket("
<< getUDPSocket() << "): " << strerror(errno) << '\n';
}
if (::close(getUDPSocket()) < 0 && !seenWarn) {
clog << "Warning: error while closing data socket("
<< getUDPSocket() << "): " << strerror(errno) << '\n';
}
}
Yes, that's normal. You need to set the socket SO_REUSEADDR before you bind, eg on *nix:
int sock = socket(...);
int yes = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
If you have separate code that reconnects by creating a new socket, set it on that one too. This is just to do with the default behaviour of the OS -- the port on a broken socket is kept defunct for a while.
[EDIT] This shouldn't apply to UDP connections. Maybe you should post the code you use to set up the socket.
In UDP there's no such thing as lost connection, because there's no connection. You can lose sent packets, that's all.
Don't reconnect, simply reuse the existing fd.
Ok first of all I like to mention what im doing is completely ethical and yes I am port scanning.
The program runs fine when the port is open but when I get to a closed socket the program halts for a very long time because there is no time-out clause. Below is the following code
int main(){
int err, net;
struct hostent *host;
struct sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_port = htons(xxxx);
sa.sin_addr.s_addr = inet_addr("xxx.xxx.xxx.xxx");
net = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
err = connect(net, (struct sockaddr *)&sa, sizeof(sa));
if(err >= 0){ cout << "Port is Open"; }
else { cout << "Port is Closed"; }
}
I found this on stack overflow but it just doesn't make sense to me using a select() command.
Question is can we make the connect() function timeout so we dont wait a year for it to come back with an error?
The easiest is to setup an alarm and have connect be interrupted with a signal (see UNP 14.2):
signal( SIGALRM, connect_alarm ); /* connect_alarm is you signal handler */
alarm( secs ); /* secs is your timeout in seconds */
if ( connect( fs, addr, addrlen ) < 0 )
{
if ( errno == EINTR ) /* timeout */
...
}
alarm( 0 ); /* cancel alarm */
Though using select is not much harder :)
You might want to learn about raw sockets too.
If you're dead-set on using blocking IO to get this done, you should investigate the setsockopt() call, specifically the SO_SNDTIMEO flag (or other flags, depending on your OS).
Be forewarned these flags are not reliable/portable and may be implemented differently on different platforms or different versions of a given platform.
The traditional/best way to do this is via the nonblocking approach which uses select(). In the event you're new to sockets, one of the very best books is TCP/IP Illustrated, Volume 1: The Protocols. It's at Amazon at: http://www.amazon.com/TCP-Illustrated-Protocols-Addison-Wesley-Professional/dp/0201633469
RudeSocket Solved the Problem
I found a lib file that is tested in linux Fedora (Not Sure about Windows) that gives me the option of timeout. Below you can find a very simple Example.
#include <rude/socket.h>
#include <iostream>
using namespace std;
using namespace rude;
Socket soc;
soc.setTimeout(30, 5);
//Try connecting
if (soc.connect("xxx.xxx.xxx.xxx", 80)){
cout << "Connected to xxx.xxx.xxx.xxx on Port " << 80 << "\n";
}
//connections Failed
else{
cout << "Timeout to xxx.xxx.xxx.xxx on Port " << 80 << "\n";
}
soc.close();
Here is a link to the DevSite