/* NET.C net functions especially for bots Robey Pointer, rpointe@eng.clemson.edu */ #include #include #include #include #include #include #include #include #include #include #include #include #ifndef FORGET_UNISTD #include #endif #include #ifdef AIX #include #endif #ifdef HPUX #define getdtablesize() 64 #endif #ifdef SVR4 #define getdtablesize() OPEN_MAX #endif #define STDOUT 1 #define STDIN 0 /* context support */ extern int cx_line; extern char cx_file[]; #define context { strcpy(cx_file,__FILE__); cx_line=__LINE__; } /* this is used by mtgets to store up data from various sockets until a \n is received -- set this relatively high so it won't have to throw away any data -- making this greater than or equal to the number of open sockets you expect to have at any given time is the smart way to go */ #define TABLESIZE 50 /* some BSD machines can't do atol -- i don't understand why not -- sounds like a major bug that should be fixed sometime */ #undef atol #define atol my_atol unsigned long my_atol(x) char *x; { unsigned long l=0; while ((*x>='0') && (*x<='9')) l=(l*10)+(*x++)-'0'; return l; } /* puts full hostname in s */ void getmyhostname(s) char *s; { struct hostent *hp; char *p; p=getenv("HOSTNAME"); if (p!=NULL) { strcpy(s,p); if (strchr(s,'.')!=NULL) return; } gethostname(s,80); if (strchr(s,'.')!=NULL) return; hp=gethostbyname(s); if (hp==NULL) fatal("Can't find your hostname.",0); strcpy(s,hp->h_name); if (strchr(s,'.')!=NULL) return; if (hp->h_aliases[0] == NULL) fatal("Can't determine your hostname!",0); strcpy(s,hp->h_aliases[0]); if (strchr(s,'.')==NULL) fatal("Can't determine your hostname!",0); } /* get my ip number */ unsigned long getmyip() { struct hostent *hp; char s[121]; unsigned long ip; struct in_addr *in; gethostname(s,80); hp=gethostbyname(s); if (hp==NULL) fatal("Can't find your hostname.",0); in=(struct in_addr *)(hp->h_addr_list[0]); ip=(unsigned long)(in->s_addr); ip=htonl(ip); return ip; } void neterror(s) char *s; { switch(errno) { case EADDRINUSE: strcpy(s,"Address already in use"); break; case EADDRNOTAVAIL: strcpy(s,"Address invalid on remote machine"); break; case EAFNOSUPPORT: strcpy(s,"Address family not supported"); break; case EALREADY: strcpy(s,"Socket already in use"); break; case EBADF: strcpy(s,"Socket descriptor is bad"); break; case ECONNREFUSED: strcpy(s,"Connection refused"); break; case EFAULT: strcpy(s,"Namespace segment violation"); break; case EINPROGRESS: strcpy(s,"Operation in progress"); break; case EINTR: strcpy(s,"Timeout"); break; case EINVAL: strcpy(s,"Invalid namespace"); break; case EISCONN: strcpy(s,"Socket already connected"); break; case ENETUNREACH: strcpy(s,"Network unreachable"); break; case ENOTSOCK: strcpy(s,"File descriptor, not a socket"); break; case ETIMEDOUT: strcpy(s,"Connection timed out"); break; case ENOTCONN: strcpy(s,"Socket is not connected"); break; case EHOSTUNREACH: strcpy(s,"Host is unreachable"); break; #ifdef ECONNRESET case ECONNRESET: strcpy(s,"Connection reset by peer"); break; #endif case 0: strcpy(s,"Error 0"); break; default: sprintf(s,"Unforseen error %d",errno); break; } } /* connects to socket & returns file descriptor */ /* returns <0 if connection refused: */ /* -1 connection refused */ /* -2 can't resolve hostname */ int open_telnet_raw(sock,server,port) int sock; char *server; int port; { int number,i; struct sockaddr_in name; struct hostent *hp; bzero((char *)&name,sizeof(struct sockaddr_in)); name.sin_family=AF_INET; name.sin_port=htons(port); number=1; i=strlen(server)-1; while ((server[i]!='.') && (i!=0)) { if ((server[i]<'0') || (server[i]>'9')) number=0; i--; } if (number) { unsigned char *p,*p1; unsigned long a; p1=(unsigned char *)&a; p1[0]=atoi(server); p=(unsigned char *)strchr(server,'.'); if (p!=NULL) p1[1]=atoi((char *)(p+1)); if (p!=NULL) { p=(unsigned char *)strchr((char *)(p+1),'.'); if (p!=NULL) p1[2]=atoi((char *)(p+1)); } if (p!=NULL) { p=(unsigned char *)strchr((char *)(p+1),'.'); if (p!=NULL) p1[3]=atoi((char *)(p+1)); } if (p!=NULL) name.sin_addr.s_addr=htonl(a); else { close(sock); return -2; } } else { hp=gethostbyname(server); if (hp==NULL) { close(sock); return -2; } bcopy(hp->h_addr,(char *)&name.sin_addr /*.s_addr*/ ,hp->h_length); name.sin_family=hp->h_addrtype; } if (connect(sock,(struct sockaddr *)&name,sizeof(struct sockaddr_in)) <0) { close(sock); sock=-1; } return sock; } int getsock() { int sock; sock=socket(AF_INET,SOCK_STREAM,0); if (sock<0) fatal("Can't open a socket at all.",0); return sock; } int open_telnet(server,port) char *server; int port; { return open_telnet_raw(getsock(),server,port); } /* returns a socket number for a listening socket that will accept any */ /* connection -- port # is returned in port */ int open_listen(port) int *port; { int sock,addrlen; struct sockaddr_in name; sock=socket(AF_INET,SOCK_STREAM,0); if (sock<0) fatal("Can't open a socket at all.",0); bzero((char *)&name,sizeof(struct sockaddr_in)); name.sin_family=AF_INET; name.sin_port=htons(*port); /* 0 = just assign us a port */ name.sin_addr.s_addr=INADDR_ANY; if (bind(sock,(struct sockaddr *)&name,sizeof(name))<0) { close(sock); return -1; } /* what port are we on? */ addrlen=sizeof(name); if (getsockname(sock,(struct sockaddr *)&name,&addrlen)<0) { close(sock); return -1; } *port=ntohs(name.sin_port); if (listen(sock,1)<0) { close(sock); return -1; } return sock; } /* given network-style IP address, return hostname */ /* hostname will be "##.##.##.##" format if there was an error */ char *hostnamefromip(ip) unsigned long ip; { static char name[121]; struct hostent *hp; unsigned long addr=ip; unsigned char *p; hp=gethostbyaddr((char *)&addr,sizeof(addr),AF_INET); if (hp==NULL) { p=(unsigned char *)&addr; sprintf(name,"%u.%u.%u.%u",p[0],p[1],p[2],p[3]); } else strcpy(name,hp->h_name); return name; } /* short routine to answer a connect received on a socket made previously */ /* by open_listen ... returns hostname of the caller & the new socket */ /* does NOT dispose of old "public" socket! */ int answer(sock,caller,ip) int sock; char *caller; unsigned long *ip; { int new_sock,addrlen; struct sockaddr_in from; addrlen=sizeof(struct sockaddr); new_sock=accept(sock,(struct sockaddr *)&from,&addrlen); if (new_sock<0) return -1; *ip=from.sin_addr.s_addr; strcpy(caller,hostnamefromip(*ip)); *ip=ntohl(*ip); return new_sock; } /* like open_telnet, but uses server & port specifications of dcc */ int open_telnet_dcc(sock,server,port) int sock; char *server,*port; { int p; unsigned long addr; char sv[121]; unsigned char *c; if (port!=NULL) p=atoi(port); else p=2000; if (server!=NULL) addr=atol(server); else addr=0L; if (addr<(1<<24)) return -3; /* fake address */ c=(unsigned char *)&addr; sprintf(sv,"%u.%u.%u.%u",c[0],c[1],c[2],c[3]); /* strcpy(sv,hostnamefromip(addr)); */ return open_telnet_raw(sock,sv,p); } #define SOCK_BINARY 1 #define SOCK_LISTEN 2 /* mtread: uh... see mtgets for info. this is just part of that. */ int mtread(socks,sockl,flagl,s,len) int socks,sockl[],flagl[]; char *s; int *len; { fd_set fd; int i,j,x; struct timeval t; i=getdtablesize(); t.tv_sec=1; t.tv_usec=0; FD_ZERO(&fd); for (j=0; j0) { for (j=0; j 0) { i=read(sock,s,511); s[i]=0; if (i==0) return -1; else return i; } else { s[0]=0; return 0; } } /* mtgets: a strange and complex function with five parameters: socks - number of items in sockl sockl - array of integers, these are the sockets to attempt reading from flagl - array of integers, these are the flags for each socket s - (char *) where mtgets puts the string len - (int *) attempts to read from all the sockets listed up to one second. if after one second, no complete data has been received from any of the sockets, s will be empty, len will be 0, and mtgets will return 0. if there is returnable data received from any socket in the sockl array, the data will be in s (null-terminated if ascii), the length will be returned in len, and the socket number (positive) will be returned. if an EOF is detected from any of the sockets, that socket number will be put in len, and -1 will be returned. mtgets will only return data from a socket when it gets an entire line terminated with a '\n', unless the socket has a flag set in flagl[]. if the socket is marked SOCK_BINARY, then it will return data as soon as it comes in, without processing it. if the socket is marked with SOCK_LISTEN, it will return with a null string when activity occurs at all (without attempting to read). YOU MUST initialize the function first by calling it like so: mtgets(0,NULL,NULL,NULL,NULL); * the maximum length of the string returned is 512 (including null) * mtgets stores pent-up data in static buffers that it mallocs as it needs them (does not waste memory) -- see the #define at the top of this file to set the number of buffers available */ int mtgets(socks,sockl,flagl,s,len) int socks,sockl[],flagl[]; char *s; int *len; { static char *bf[TABLESIZE]; static int bfs[TABLESIZE]; char xx[512]; char *p,*px; int ret,i,j; if (socks==0) { /* initialize socket buffer table */ for (i=0; i510) bf[i][510]=0; strcpy(s,bf[i]); px=(char *)malloc(strlen(p+1)+1); strcpy(px,p+1); free(bf[i]); if (px[0]) bf[i]=px; else { bf[i]=NULL; bfs[i]=0; free(px); } if (s[strlen(s)-1]=='\r') s[strlen(s)-1]=0; *len = strlen(s); /* <-- oh that looks so cute robey! :) */ return j; } } /* no pent-up data of any worth -- down to business */ context; *len=0; ret=mtread(socks,sockl,flagl,xx,len); context; if (ret<=0) { s[0]=0; return ret; } context; for (i=0; i