segmentation fault

Posted by: Gollum

segmentation fault - 03/07/03 02:34 AM

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
, 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
, addr=0xbffff918) at inet_addr.c:130
#1 0x40102bd6 in inet_addr (cp=0x2b6206d1
, 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
, 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;
}
Posted by: SilentRage

Re: segmentation fault - 03/07/03 10:57 AM

gosh dang, well, I'm about to take a trip to see my mom. When I get there, I'll pour over your code and tell you what's wrong.

In the meantime, I have two C open source programs that use sockets that you can look at:

Uses both TCP and UDP to query DNS servers
http://serialcoders.sytes.net/Download/DNSLookup/DNS_v1.0.zip

Accepts and makes connections
http://serialcoders.sytes.net/Download/Router/TelnetRouter_v3.0.zip

Both use gethostbyname
Posted by: SilentRage

Re: segmentation fault - 03/08/03 05:43 AM

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.
Posted by: Gollum

Re: segmentation fault - 03/10/03 12:00 AM

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.//
Posted by: SilentRage

Re: segmentation fault - 03/10/03 12:03 PM

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.
Posted by: Gollum

Re: segmentation fault - 03/11/03 12:27 AM

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- &gt h_addr));
it should have been:
targ_addr.sin_addr = *((struct in_addr *)host- &gt 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- &gt h_addr);
memset(&(targ_addr.sin_zero), '\0', 8);

if((ret=connect(sockfd[x],(struct sockaddr *)&targ_addr,sizeof(targ_addr)))!=-1)
{
printf("\n-- &gt %d is Open",onport);
openprt++;
}

for(n = 0; n &lt = 150; n++);
x++;
if(onport-begport &gt 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++.//
Posted by: SilentRage

Re: segmentation fault - 03/11/03 10:14 AM

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.
Posted by: Gollum

Re: segmentation fault - 03/11/03 01:11 PM

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.
Posted by: Gollum

Re: segmentation fault - 03/11/03 02:25 PM

yea...after extensive search on non-blocking sockets...i've found the same conclusion almost everywhere...use select.//
Posted by: SilentRage

Re: segmentation fault - 03/11/03 05:55 PM

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.