| Joined: Jun 2002 Posts: 207 Member | Member Joined: Jun 2002 Posts: 207 | i just began programming sockets in C. i decided for my first project to make a port scanner. everythign was working fine until i added the gethostbyname() fucntion to it. now everytime i run it i get a Segmentation Fault. I've tried to pinpoint it, but it's difficult. I only get the segmentation fault when I enter a valid ip address or domain. if the domain is invalid it sends back a custom error message. also if the user puts in the wrong number of arguments it calls a usage function. so i only have problems with the program when it doesn't encounter an error. In the code I set the first three variables to 5 to show that when the program runs, they are changed (or overwritten) to 0, 0, and 134519796 respectively. Also. I put a printf("hello"); followed by a fflush(stdout); followed by another printf("hello"); right after my declarations. when that happens, the only output is: helloSegmentation Fault does anyone know whats going on here??!
Output: bash2.05a# ./pscan validdomain.com
sockfd: 0 n: 0 ret: 134519796
Segmentation fault
gdb output: (gdb)run validdomain.com Starting program: /home/gollum/projects/portscanner/pscan validdomain.com
sockfd: 0 n: 0 ret: 134519796
Program received signal SIGSEV, Segmentation fault. __inet_aton (cp=0x2b6206d1 <Address 0x2b6206d1 out of bounds>, addr=0xbffff918) at inet_addr.c:130 130 inet_addr.c: No such file or directory. in inet_addr.c (gdb)bt #0 __inet_aton (cp=0x2b6206d1 <Address 0x2b6206d1 out of bounds>, addr=0xbffff918) at inet_addr.c:130 #1 0x40102bd6 in inet_addr (cp=0x2b6206d1 <Address 0x2b6206d1 out of bounds>, addr=0xbffff918) at inet_addr.c:96 #2 0x0804887a in main (argc=2, argv=0xbffff9d4) at portscanner.c:74 #3 0x4003e17d in __libc_start_main (main=0x80486cc <main>, argc=2 ubp_av=0xbffff9d4, init-0x8048494 <_init>, fini=0x8048980 <_fini>, at ../sysdeps/generic/libc-start.c:129
CODE:([LT] is < and [GT] is >) #include [LT]stdio.h[GT] #include [LT]stdlib.h[GT] #include [LT]errno.h[GT] #include [LT]string.h[GT] #include [LT]netdb.h[GT] #include [LT]sys/types.h[GT] #include [LT]netinet/in.h[GT] #include [LT]sys/socket.h[GT]
void usage(char *s) { printf("\nGollum's First Port Scanner\nUsage: %s [LT]ip address[GT] [begin port] [end port]\n\n",s); exit(1); }
int main(int argc, char *argv[]) { int sockfd = 5, n = 5, ret = 5; struct hostent *host; struct sockaddr_in targ_addr; int openprt = 0, begport, endport, strdprt;
printf("\nsockfd: %d\nn: %d\nret: %d\n\n"); fflush(stdout); if(argc [LT]= 1) usage(argv[0]); if(argc [GT] 4) usage(argv[0]);
if((host = gethostbyname(argv[1])) == NULL){ printf("%s: unknown host: %s\n",argv[0],argv[1]); exit(1); }
if(argc == 4){ begport = atoi(argv[2]); endport = atoi(argv[3]); } else{ begport = 1; endport = 1024; }
printf("Scanning [LT]%s[GT](%s) from port %d to %d...",host-[GT]h_name,inet_ntoa(*((struct in_addr *)host-[GT]h_addr)),begport,endport);
strdprt = endport - begport+1;
for(; begport [LT]= endport; begport++){
sockfd=socket(AF_INET,SOCK_STREAM,0); bzero((char*)&targ_addr,sizeof(targ_addr)); targ_addr.sin_family=AF_INET; targ_addr.sin_port=htons(begport); targ_addr.sin_addr.s_addr = inet_addr(*((struct in_addr *)host-[GT]h_addr)); if((ret=connect(sockfd,(struct sockaddr *)&targ_addr,sizeof(targ_addr)))!=-1) { printf("\n--[GT] %d is Open",begport); openprt++;} for(n = 0; n [LT]= 12000000; n++); } printf("\nScan Finished\n"); if(openprt == 0){ printf("No open ports were detected on %s.\n",host); } else{ printf("The other %d ports scanned were closed.\n",strdprt-openprt); } close(sockfd);
return 0; }
Unbodied unsouled unheard unseen Let the gift be grown in the time to call our own Truth is natural like a wind that blows Follow the direction no matter where it goes Let the truth blow like a hurricane through me
| | |
▼ Sponsored Links ▼
▲ Sponsored Links ▲
| | | Joined: Mar 2002 Posts: 1,273 DollarDNS Owner | DollarDNS Owner Joined: Mar 2002 Posts: 1,273 | I believe this line is a crash alert:
printf("Scanning <%s>(%s) from port %d to %d...", host->h_name, inet_ntoa(*((struct in_addr*)host->h_addr)), begport, endport);
untested solution - to remove pointer dereferencing
printf("Scanning <%s>(%s) from port %d to %d...", host->h_name, inet_ntoa((struct in_addr*)host->h_addr), begport, endport);
and
targ_addr.sin_addr.s_addr = inet_addr(*((struct in_addr *)host->h_addr));
untested solution - correct invalid assignment of string pointer to long
memcpy(&targ_addr.sin_addr.s_addr, host.h_addr, 4);
since I AM at my mother's house, I don't have access to my C compiler and cannot test this for myself. But you can try my suggested changes. | | | | Joined: Jun 2002 Posts: 207 Member | Member Joined: Jun 2002 Posts: 207 | i tried them, with unsuccessful results. however, i found out why i was getting erroneous results for the 3 variables i searched for. i never added the varialbes at the end of the printf statement. i fixed that and they printed out fine. however, i'm stilling getting a segmentation fault. i've tried allocating memory for *host, but to no avail.//
Unbodied unsouled unheard unseen Let the gift be grown in the time to call our own Truth is natural like a wind that blows Follow the direction no matter where it goes Let the truth blow like a hurricane through me
| | | | Joined: Mar 2002 Posts: 1,273 DollarDNS Owner | DollarDNS Owner Joined: Mar 2002 Posts: 1,273 | ok, I've started to test your code in LCC - for windows, so this is a bit difficult to test considering I think you're compiling under *nix. BEFORE printf("No open ports were detected on %s.\n",host); AFTER printf("No open ports were detected on %s.\n",host->h_name); invalid argument type. host is a structure, not a string pointer. BEFORE close(sockfd); AFTER closesocket(sockfd); This may be a windows specific function, but check to be sure you don't have a closesocket function. BEFORE targ_addr.sin_addr.s_addr = inet_addr(*((struct in_addr *)host-[GT]h_addr)); AFTER memcpy(&targ_addr.sin_addr.s_addr, &host->h_addr, 4); I noticed this error before, but I gave you the incorrect fix. I once again believe this to be your most likely crash error. DELETED bzero((char*)&targ_addr,sizeof(targ_addr)); I don't have bzero, so I deleted it. If by some wierd stroke of bad luck, this is your crash problem, then I suggest you delete it too for testing. With all the above changes (plus the inclusion of one windows specific function to initialize sockets) I successfully ran the program on Win2k. Course, there's a bug where it didn't properly detect open ports, but I'll leave that up to you - unless you should ask help on that too.  Once again, it could be a windows thing. | | | | Joined: Jun 2002 Posts: 207 Member | Member Joined: Jun 2002 Posts: 207 | ah, i got it to work. it had to do w/ one of the lines you wanted me to change:
targ_addr.sin_addr.s_addr = inet_addr(*((struct in_addr *)host- > h_addr)); it should have been: targ_addr.sin_addr = *((struct in_addr *)host- > h_addr);
that fixed it. but, btw...do you multithread a port scanner in c just by creating more than one socket? i changed sockfd to sockfd[x] and changed my code accordingly. i'd like to know what your opinion is on creating an array of sockets. as of right now i have a for loop at the end and instead of 120000000 or whateve,r i have 150, and i have a total of 500 different sockets that i use. i also changed bzero to memset.
targ_addr.sin_family=AF_INET; targ_addr.sin_port=htons(onport); targ_addr.sin_addr = *((struct in_addr *)host- > h_addr); memset(&(targ_addr.sin_zero), '\0', 8);
if((ret=connect(sockfd[x],(struct sockaddr *)&targ_addr,sizeof(targ_addr)))!=-1) { printf("\n-- > %d is Open",onport); openprt++; }
for(n = 0; n < = 150; n++); x++; if(onport-begport > 500) close(sockfd[x+1]); if(x == 500) x = 0;
at the end i have a for loop which closes all the sockets. and yes, speaking of closeing sockets, i believe in *nix, sockets are still considered the same as files, hence sockfd is socket file descriptor. so you're actually opening a file descriptor, which you just close, so it's the same command. this, to me, doesn't seem very efficient, but i don't know if there's another way to do this. i've checked online, but most of what i came up with has been how to do it with .NET, C#, or C++.//
Unbodied unsouled unheard unseen Let the gift be grown in the time to call our own Truth is natural like a wind that blows Follow the direction no matter where it goes Let the truth blow like a hurricane through me
| | | | Joined: Mar 2002 Posts: 1,273 DollarDNS Owner | DollarDNS Owner Joined: Mar 2002 Posts: 1,273 | yes, I'm familiar with pseudo file handles, so I knew it would work with close(), I just like being as specific as possible in my code. So if there was a closesocket function, that's what I would opt to use. Basically, just see of closesocket works if you want and if it doesn't, continue to use close.
as for an array of sockets... that's not your problem. I'll give ya a technical terms and definitions concerning this point:
syncronous tcp scan this is where you try to connect to a port one after another. Each time you successfully connect or fail, you close the socket and move to the next port. To coders, this is called BLOCKING sockets. In other words, the connect function will block (or not return) until the connection attempt failed or succeeded.
asyncronous tcp scan the most popular technique for scanning. This involves a SINGLE thread, but many ports are being scanned at one time, asyncronously. To coders this is called NON-BLOCKING sockets. In other words, the connect function will return immediately, meanwhile the connection attempt is still in progress.
multithreaded This is most popular for major server applications where the process spins off another thread for each client.
Now, the rules may be slightly different for *nix, but in windows, sockets are by default BLOCKING. If I were to create a tcp scanner in windows, I would set the socket to NON-BLOCKING and give the OS the handle to the window and message number I want associated with network events. Then I setup a loop to attempt to connect to a bunch of sockets, meanwhile, the OS will post a message to my window each time a connection attempt failed or succeeded.
Now for *nix, this is what I theorize. The general technique should be much the same. You need to set your sockets to NON-BLOCKING and give the OS a FUNCTION POINTER, so that it may notify your application whenever a connection attempt failed or succeeded. That function would be called a CALLBACK function by coders.
if that ISN'T how it works under *nix...
You MAY still have to set the sockets to NON-BLOCKING, then after you attempt to connect with a group of them, you start looping through them checking their current connection state. If they're still pending, ignore them. If they connected, close them, print. If they failed, close them. Whenever you decide that the loop has gone for long enough (timeout), then you close all and move to the next group of ports. | | | | Joined: Jun 2002 Posts: 207 Member | Member Joined: Jun 2002 Posts: 207 | ah, ok, i believe this would do the trick:
fcntl(sockfd, F_SETFL, O_NONBLOCK); but... "By setting a socket to non-blocking, you can effectively "poll" the socket for information. If you try to read from a non-blocking socket and there's no data there, it's not allowed to block--it will return -1 and errno will be set to EWOULDBLOCK.
Generally speaking, however, this type of polling is a bad idea. If you put your program in a busy-wait looking for data on the socket, you'll suck up CPU time like it was going out of style. A more elegant solution for checking to see if there's data waiting to be read comes in the following section on select()." (thank god for beej.)
so i dunno...i assume i could use that, but i'll try both that and select and see which one works better.
Unbodied unsouled unheard unseen Let the gift be grown in the time to call our own Truth is natural like a wind that blows Follow the direction no matter where it goes Let the truth blow like a hurricane through me
| | | | Joined: Jun 2002 Posts: 207 Member | Member Joined: Jun 2002 Posts: 207 | yea...after extensive search on non-blocking sockets...i've found the same conclusion almost everywhere...use select.//
Unbodied unsouled unheard unseen Let the gift be grown in the time to call our own Truth is natural like a wind that blows Follow the direction no matter where it goes Let the truth blow like a hurricane through me
| | | | Joined: Mar 2002 Posts: 1,273 DollarDNS Owner | DollarDNS Owner Joined: Mar 2002 Posts: 1,273 | well isn't that fascinating. Seems select() is available for windows as well. I just may rewrite my socket code to use select instead of a window's message queue. Both are equivilent in efficiency, but why create a window when I don't need one? Good to know this.
For sure, I agree the second technique outlined above does sux0r big balls. Do NOT do things that way. If you do, be sure to release time every loop for the CPU to catch up on things. Under windows the function is called Sleep(). It puts the process on idle for the duration you specify. | | |
Forums41 Topics33,840 Posts68,858 Members2,176 | Most Online3,253 Jan 13th, 2020 | | | |