Why is my program soooo slow in Windows
I wrote a simple port scanner and under linux it's lightning fast while on windows (After small modifications to port over) it's dog slow:
Usage is: portscan.exe [ip address]
What could cause it to be significantly slower?
Usage is: portscan.exe [ip address]
#include <winsock2.h> #include <ws2tcpip.h> #include <stdio.h> #include <stdlib.h> #define PORT_MIN 0x0000 #define PORT_MAX 0xFFFF void test_port(SOCKET, struct sockaddr_in *, unsigned short, char *); int main(int argc, char ** argv){ SOCKET client_socket; WSADATA wsaData; struct sockaddr_in target; unsigned short port = PORT_MIN; WSAStartup(MAKEWORD(2, 2), &wsaData); memset(&target, sizeof(target), 0); if((target.sin_addr.s_addr = inet_addr(argv[1])) != INADDR_NONE) while(port++ < PORT_MAX) test_port(client_socket, &target, port, "tcp"); return 0; } void test_port(SOCKET client_socket, struct sockaddr_in * target, unsigned short port, char * svc_proto){ struct servent * service; printf("Testing %s port %u\r", svc_proto, port); target->sin_family = AF_INET; target->sin_port = htons(port); if((client_socket = socket(AF_INET, SOCK_STREAM, 0)) != INVALID_SOCKET) if(connect(client_socket, (struct sockaddr *)target, sizeof(*target)) != SOCKET_ERROR){ closesocket(client_socket); if(service = getservbyport(port, svc_proto)) printf("Discovered open port %u (%s)/%s\n", port, service->s_name, svc_proto); else printf("Discovered open port %u/%s\n", port, svc_proto); } }
What could cause it to be significantly slower?
Currently reading: Network Warrior, Unix Network Programming by Richard Stevens
Comments
-
paul78 Member Posts: 3,016 ■■■■■■■■■■It because you are using a blocking connect(). Not sure if Windows supports using setsockopt() timeout options on connect() but that's one thing you can try.
I vaguely recall (its been a while) that in Windows to do what you want efficiently, you would use an async/nonblocking connect() and write your own handler with select().
Good luck - sounds like a fun project. -
newt.chapman Member Posts: 34 ■■□□□□□□□□(Anthony) wrote:most likely due to the connection recycling wait and tcp connection limit in windows.
Quoted from a programming friendly board that I took the liberty of posting this problem on. -
paul78 Member Posts: 3,016 ■■■■■■■■■■newt.chapman wrote: »connection recycling wait
-
CodeBlox Member Posts: 1,363 ■■■■□□□□□□Sooo, I revised the program to scan a whole subnet and it seems to work, only now under even Linux, it starts going at a snails pace after the second IP... Any thoughts?
usage: ./portscan [subnet] [mask]#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netdb.h> #define NET_MASK 0XFFFFFFFF #define PORT_LIMIT 65535 #define BASE_PORT 0 void get_addr_space(unsigned long int *, unsigned long int *, struct in_addr, struct in_addr); void scan_addr(unsigned long int, struct sockaddr_in *, unsigned short); int test_port(int, unsigned short, struct sockaddr_in *, char *); void port_info(unsigned short, char *); int main(int argc, char ** argv){ unsigned short port = BASE_PORT; unsigned long int curr_addr = 0, max_addr = 0; struct sockaddr_in target; struct in_addr mask; inet_pton(AF_INET, argv[1], &target.sin_addr); inet_pton(AF_INET, argv[2], &mask); get_addr_space(&curr_addr, &max_addr, target.sin_addr, mask); target.sin_family = AF_INET; curr_addr = ntohl(curr_addr); max_addr = ntohl(max_addr); while(curr_addr < max_addr - 1) scan_addr(curr_addr++, &target, port); return 0; } void get_addr_space(unsigned long int * min, unsigned long int * max, struct in_addr subnet, struct in_addr mask){ unsigned long int subnet_bits = subnet.s_addr & mask.s_addr; *min = subnet_bits; *max = subnet_bits; //*max = ((~*max + subnet_bits) & ~mask.s_addr) + *max; *max = NET_MASK & ~mask.s_addr + *max; } void scan_addr(unsigned long int dec_addr, struct sockaddr_in * target, unsigned short port){ int client_socket = 0; char ipv4[INET_ADDRSTRLEN]; target->sin_addr.s_addr = htonl(dec_addr); target->sin_port = port; printf("\nTrying IP %s\n", inet_ntop(AF_INET, &target->sin_addr, ipv4, INET_ADDRSTRLEN)); while(port < PORT_LIMIT) if(!test_port(client_socket, port++, target, "tcp")) port_info(port - 1, "tcp"); } int test_port(int client_socket, unsigned short port, struct sockaddr_in * target, char * svc_proto){ printf("\t - Trying %s port %u\r", svc_proto, port); target->sin_family = AF_INET; target->sin_port = htons(port); if((client_socket = socket(AF_INET, (svc_proto == "tcp" ? SOCK_STREAM : SOCK_DGRAM), 0)) > 0){ if(connect(client_socket, (struct sockaddr *)target, sizeof(*target))){ close(); return 1; } else return 0; }else perror(""); } void port_info(unsigned short port, char * svc_proto){ struct servent * service; if((service = getservbyport(htons(port), svc_proto))) printf("\t - %s port %u (%s) is open\n", svc_proto, port, service->s_name); else printf("\t - %s port %u is open\n", svc_proto, port); }
Currently reading: Network Warrior, Unix Network Programming by Richard Stevens -
paul78 Member Posts: 3,016 ■■■■■■■■■■I just tried it on Linux - it seems to work pretty quick for me. About 1000 tcp ports per second. Are you expecting something else?
-
CodeBlox Member Posts: 1,363 ■■■■□□□□□□Well, it works fine for the first IP, really fast but when it gets to 192.168.0.2 it goes at a snails pace... Come to think of it... I think I know why that is. There is no host at that address! :PCurrently reading: Network Warrior, Unix Network Programming by Richard Stevens
-
paul78 Member Posts: 3,016 ■■■■■■■■■■Opps - I was reading your note incorrectly - yes - in that situation - connect() will block while it waits for the SYN packet response.
[edit] - Actually - I'm not sure that my theory makes sense. The connect() will block even if there is a host at that address but the target host doesn't respond to the SYN. -
CodeBlox Member Posts: 1,363 ■■■■□□□□□□What I could do is assume some threshold of ports that I fail to connect on and test errno for ETIMEDOUT... Maybe this is a valid way of checking for now until I buckle down on raw sockets. As far as I know though, connect won't block forever, it'll eventuall return something and if failed set errno.Currently reading: Network Warrior, Unix Network Programming by Richard Stevens
-
paul78 Member Posts: 3,016 ■■■■■■■■■■Yeah - that could work. I looked a bit closer and it looks like my hosts are returning RST so getting ECPNNREFUSED - so that explains why I was seeing the faster connect() fails. It's the ETIMEDOUT that's the issue.
Sounds like you understand that the right way is to use SOCK_RAW. Big fun! -
CodeBlox Member Posts: 1,363 ■■■■□□□□□□Got it working as desired for now (continues past "offline" host) by checking if errno == EHOSTUNREACH. See below:
#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netdb.h> #include <errno.h> #define NET_MASK 0XFFFFFFFF #define PORT_LIMIT 0XFFFF #define BASE_PORT 0X0000 void get_addr_space(unsigned long int *, unsigned long int *, struct in_addr, struct in_addr); void scan_addr(unsigned long int, struct sockaddr_in *, unsigned short); int test_port(int, unsigned short, struct sockaddr_in *, char *); void port_info(unsigned short, char *); int main(int argc, char ** argv){ unsigned short port = BASE_PORT; unsigned long int curr_addr = 0, max_addr = 0; struct sockaddr_in target; struct in_addr mask; inet_pton(AF_INET, argv[1], &target.sin_addr); inet_pton(AF_INET, argv[2], &mask); get_addr_space(&curr_addr, &max_addr, target.sin_addr, mask); target.sin_family = AF_INET; curr_addr = ntohl(curr_addr); max_addr = ntohl(max_addr); //printf("Min: %u, Max: %u\n", curr_addr, max_addr + 1); while(curr_addr < max_addr - 1) scan_addr(++curr_addr, &target, port); return 0; } void get_addr_space(unsigned long int * min, unsigned long int * max, struct in_addr subnet, struct in_addr mask){ unsigned long int subnet_bits = subnet.s_addr & mask.s_addr; *min = subnet_bits; *max = subnet_bits; //*max = ((~*max + subnet_bits) & ~mask.s_addr) + *max; *max = NET_MASK & ~mask.s_addr + *max; } void scan_addr(unsigned long int dec_addr, struct sockaddr_in * target, unsigned short port){ int client_socket = 0; char ipv4[INET_ADDRSTRLEN]; target->sin_addr.s_addr = htonl(dec_addr); target->sin_port = htons(port); printf("Trying IP %s\n\n", inet_ntop(AF_INET, &target->sin_addr, ipv4, INET_ADDRSTRLEN)); while(port < PORT_LIMIT){ if(test_port(client_socket, port++, target, "tcp")) port_info(port - 1, "tcp"); else if(errno == EHOSTUNREACH) break; else continue; } } int test_port(int client_socket, unsigned short port, struct sockaddr_in * target, char * svc_proto){ printf("Trying %s port %u\r", svc_proto, port); target->sin_family = AF_INET; target->sin_port = htons(port); if((client_socket = socket(AF_INET, (svc_proto == "tcp" ? SOCK_STREAM : SOCK_DGRAM), 0)) > 0){ if(!connect(client_socket, (struct sockaddr *)target, sizeof(*target))){ close(client_socket); return 1; } else close(client_socket); return 0; }else perror(""); } void port_info(unsigned short port, char * svc_proto){ struct servent * service; if((service = getservbyport(htons(port), svc_proto))) printf("%s port %u (%s) is open\n", svc_proto, port, service->s_name); else printf("%s port %u is open\n", svc_proto, port); }
Currently reading: Network Warrior, Unix Network Programming by Richard Stevens -
paul78 Member Posts: 3,016 ■■■■■■■■■■Nice work CodeBlox!!! Now if you thread it, you can even make it more efficient What you can do is to create a separate threads as well - perhaps one thread per IP.