/* NET.C net functions especially for bots Robey Pointer, robey@acolyte.slip.netcom.com */ #if HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #if HAVE_SYS_SELECT_H #include #endif #include #ifndef LINUX /* linux gets wacko if you include both */ #include #endif /* but virtually every other OS NEEDS both */ #include #include #if HAVE_UNISTD_H #include #endif #include /* almost every module needs some sort of time thingy, so... */ #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #if !HAVE_GETDTABLESIZE #ifdef FD_SETSIZE #define getdtablesize() FD_SETSIZE #else #define getdtablesize() 64 #endif #endif #define STDOUT 1 #define STDIN 0 #define EFORKKILLED 2323 void fatal(); /* 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 /* static buffer */ extern char SBUF[]; /* FreeBSD's atol() is supposed to be fixed now, but since I went to all that trouble, might as well keep it. */ #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; } /* i read somewhere that memcpy() is broken on some machines */ /* it's easy to replace, so i'm not gonna take any chances, because it's */ /* pretty important that it work correctly here */ void my_memcpy(dest,src,len) char *dest,*src; int len; { while (len--) *dest++=*src++; } /* bzero() is bsd-only, so here's one for non-bsd systems */ void my_bzero(dest,len) char *dest; int len; { while (len--) *dest++=0; } /* 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("Hostname self-lookup failed.",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,120); hp=gethostbyname(s); if (hp==NULL) fatal("Hostname self-lookup failed.",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 #ifdef EACCES case EACCES: strcpy(s,"Permission denied"); break; #endif /* only used by forked processes that are killed */ case EFORKKILLED: strcpy(s,"Killed"); break; 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; my_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; } my_memcpy((char *)&name.sin_addr,hp->h_addr,hp->h_length); name.sin_family=hp->h_addrtype; } if (connect(sock,(struct sockaddr *)&name,sizeof(struct sockaddr_in)) <0) { close(sock); return -1; } /* make it a non-blocking socket (whee) */ fcntl(sock,F_SETFL,O_NONBLOCK); return sock; } int getsock() { int sock; int parm; /* struct timeval tv; */ sock=socket(AF_INET,SOCK_STREAM,0); if (sock<0) fatal("Can't open a socket at all.",0); /* keepalive (ie, ping), NO linger (block on write to dead socket), */ /* don't allow block on write to living socket if >10ms */ parm=1; setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,(void *)&parm,sizeof(int)); parm=0; setsockopt(sock,SOL_SOCKET,SO_LINGER,(void *)&parm,sizeof(int)); /* tv.tv_sec=0; tv.tv_usec=10000; */ parm=1; setsockopt(sock,SOL_SOCKET,TCP_NODELAY,(void *)&parm,sizeof(int)); 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=getsock(); my_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; { struct hostent *hp; unsigned long addr=ip; unsigned char *p; static char s[121]; hp=gethostbyaddr((char *)&addr,sizeof(addr),AF_INET); if (hp==NULL) { p=(unsigned char *)&addr; sprintf(s,"%u.%u.%u.%u",p[0],p[1],p[2],p[3]); return s; } strcpy(s,hp->h_name); return s; } /* 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); /* no blocking on the new socket */ fcntl(new_sock,F_SETFL,O_NONBLOCK); 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(); #ifdef FD_SETSIZE if (i>FD_SETSIZE) i=FD_SETSIZE; /* fixes YET ANOTHER freebsd bug!!! */ #endif t.tv_sec=1; t.tv_usec=0; FD_ZERO(&fd); for (j=0; j0) { for (j=0; j510) 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); if (ret<=0) { s[0]=0; return ret; } for (i=0; i=510) { /* string is too long, so just insert fake \n */ strcpy(s,xx); xx[0]=0; } } context; /* anything left that needs to be saved? */ if (!xx[0]) { if (s[0]) return ret; else return 0; } context; /* prepend old data back */ for (i=0; i510) SBUF2[510]=0; /* server can only take so much */ tputs(sock,SBUF2); va_end(va); } void io_memory(in,out) unsigned int *in,*out; { int i; *in=*out=0; for (i=0; i