/* vi: set ts=4 sw=4 ai: */ /* * s_net.c * * Lotos v1.2.3 : (c) 1999-2003 Pavol Hluchy (Lopo) * last update : 30.1.2003 * email : lotos@losys.sk * homepage : lotos.losys.sk */ #ifndef __S_NET_C__ #define __S_NET_C__ 1 #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <ctype.h> #include <netdb.h> #include <netinet/in.h> #include <sys/socket.h> #include <arpa/inet.h> #include <sys/time.h> #include <arpa/telnet.h> #include "define.h" #include "prototypes.h" #include "obj_sys.h" #include "s_net.h" /*** Get host structure, using hostsfile info ( written by Mituc <BlackBlue@DeathsDoor.Com>) ***/ struct hostent *fgethostbyname(char *hostname) { FILE *fp; char siteaddr[SITE_NAME_LEN+1],sitename[SITE_NAME_LEN+1]; char int_h_addr_seq,*temp; struct hostent *host; int i,found=0; set_crash(); if (!use_hostsfile) return NULL; if ((temp=(char *)malloc(SITE_NAME_LEN))==NULL) return NULL; if(!(fp=fopen(HOSTSFILE, "r"))) return NULL; fscanf(fp, "%s %s", siteaddr, sitename); while (!feof(fp)) { if(!strcmp(hostname,sitename)) { /* found */ found=1; break; } fscanf(fp,"%s %s",siteaddr,sitename); } fclose(fp); if (!found) return NULL; if ((host=(struct hostent *)malloc(sizeof(struct hostent)))==NULL) return NULL; if ((host->h_addr_list=(char **)malloc(2))==NULL) return NULL; if ((host->h_addr_list[0]=(char *)malloc(10))==NULL) return NULL; if ((host->h_name=(char *)malloc(strlen(sitename)+1))==NULL) return NULL; strcpy(temp,siteaddr); temp=(char *)strtok(temp,"."); i=0; /* get IP components */ while (temp!=NULL && strlen(temp)>0) { int_h_addr_seq=atoi(temp); host->h_addr_list[0][i]=int_h_addr_seq; i++; temp=(char *)strtok(NULL,"."); } host->h_addrtype=AF_INET; host->h_length=strlen(host->h_addr_list[0]); return host; } /*** Get user account, using ident daemon of remote site (written by Mituc <BlackBlue@DeathsDoor.Com>) ***/ int ident_request(struct hostent *rhost, int rport, int lport, char *accname) { int sockid,i,n_msgs,nbread,partial_nbread,read_count; struct sockaddr_in forident; char *inbuf,outbuf[ID_BUFFLEN+1],*temp,*msgs[4],mask; struct timeval read_timeout; fd_set readfds; set_crash(); if ((temp=(char *)malloc(ID_BUFFLEN+1))==NULL) return ID_NOMEM; if ((inbuf=(char *)malloc(ID_BUFFLEN+1))==NULL) return ID_NOMEM; if ((sockid=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==-1) /* open a socket for ident */ return ID_CONNERR; forident.sin_family=rhost->h_addrtype; forident.sin_addr.s_addr=*((long *)rhost->h_addr_list[0]); forident.sin_port=htons(113); if (connect(sockid, (struct sockaddr *)&forident, sizeof(forident))) { /* ident is not running */ close(sockid); return ID_NOFOUND; } /* begin interogation... */ sprintf(outbuf,"%d,%d\n",rport,lport); if (write(sockid,outbuf,strlen(outbuf))==-1) { close(sockid); return ID_WRITEERR; } resetbuff(inbuf); read_timeout.tv_sec=ID_READTIMEOUT; read_timeout.tv_usec=0; FD_ZERO(&readfds); FD_SET(sockid,&readfds); nbread=0; read_count=0; partial_nbread=0; while (partial_nbread<2 && read_count<3) { if (select(FD_SETSIZE, &readfds, NULL, NULL, &read_timeout)==-1) return ID_TIMEOUT; /* There is no need to see if FD_ISSET(sockid,&readfds) is true because we have only one file descriptor in readfds, and a select error will refere only this file descriptor (sockid). */ read_count++; if ((partial_nbread=read(sockid,&inbuf[nbread],ID_BUFFLEN-nbread))==-1) { close(sockid); return ID_CLOSED; } nbread+=partial_nbread; } close(sockid); /* end interogation */ temp=strtok(inbuf,":"); n_msgs=0; /* We'll restrict the numbers of items read here to 4 just in case a lasy ident daemon runs on a given host... and who can give us gigabytes of auth infos... */ while (temp && (n_msgs<4)) { if (!(msgs[n_msgs]=(char *)malloc(ID_BUFFLEN+1))) return ID_NOMEM; strcpy(msgs[n_msgs],temp); /* We'll clean the return ident messages... We wasted a lot of CPU time already...:-| */ while ((strlen(msgs[n_msgs])>0) && !isalnum(msgs[n_msgs][0])) (msgs[n_msgs])++; i=strlen(msgs[n_msgs])-1; while ((i>0) && !isalnum(msgs[n_msgs][i])) msgs[n_msgs][i--]='\0'; if (msgs[n_msgs] && (strlen(msgs[n_msgs])>2)) n_msgs++; temp=strtok(NULL,":"); } /* The returned value should be like: "item1 : item2 : item3" in case of an error or "item1 : item2 : item3 :item4" on success. */ if (n_msgs<2) return ID_READERR; /* Or this should be ID_CRAP...? */ /* Conforming to the RFC 1413 document, the second item (n_msgs=1) should contain the keyword "ERROR" or "USERID"... */ if (!stricmp(msgs[1],"ERROR")) { mask= 2*(!stricmp(msgs[2],"NO-USER"))+ 4*(!stricmp(msgs[2],"INVALID-PORT"))+ 8*(!stricmp(msgs[2],"HIDDEN-USER"))+ 16*(!stricmp(msgs[2],"UNKNOWN-ERROR")); switch (mask) { case 2: return ID_NOUSER; case 4: return ID_INVPORT; case 8: return ID_HIDDENUSER; case 16: return ID_UNKNOWNERR; default: return ID_CRAP; } } else if(stricmp(msgs[1],"USERID")) return ID_READERR; /* strcmp() can be used succesfuly too, but a case insensitive comparation seems better to me... */ /* It's ok now... all tests where succesfuly passed. */ strcpy(accname,msgs[n_msgs-1]); return ID_OK; /* Here we go... */ } /*** Get user's Real name via mail daemon (written by Mituc <BlackBlue@DeathsDoor.Com>) ***/ int mail_id_request(struct hostent *rhost, char *accname, char *email) { struct hostent *lhost; struct sockaddr_in forident; char *inbuf,outbuf[ID_BUFFLEN+1],localhostname[SITE_NAME_LEN+1]; char *temp,*msgs[10]; int sockmail,i; int nbread,read_count,partial_nbread,n_msgs; struct timeval read_timeout; fd_set readfds; set_crash(); if (!(inbuf=(char *)malloc(ID_BUFFLEN+1))) return ID_NOMEM; if ((sockmail=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==-1) /* open a socket for mail ident */ return ID_CONNERR; forident.sin_family=rhost->h_addrtype; forident.sin_addr.s_addr=*((long *)rhost->h_addr_list[0]); forident.sin_port=htons(25); if ((connect(sockmail,(struct sockaddr *)&forident,sizeof(forident)))==-1) { /* mail daemon is not running or another error occured */ close(sockmail); return ID_NOFOUND; } /* preparing to interogate mail daemon... */ strncpy(localhostname,(char *)getenv("HOSTNAME"),SITE_NAME_LEN); /* On missconfigurated systems we may have the unpleasant surprise to see that the HOSTNAME variable is not set or there is no host entry for the value it is set to. */ if ((lhost=gethostbyname(localhostname))==NULL) strcpy(localhostname,"localhost"); /* Some problems with "helo" may occure now...!:-/ */ else strncpy(localhostname,lhost->h_name,SITE_NAME_LEN); /* begin interogation... */ resetbuff(inbuf); read_timeout.tv_sec=ID_READTIMEOUT; read_timeout.tv_usec=0; FD_ZERO(&readfds); FD_SET(sockmail,&readfds); nbread=0; read_count=0; partial_nbread=0; while (partial_nbread<2 && read_count<3) { if (select(FD_SETSIZE,&readfds,NULL,NULL,&read_timeout)==-1) return ID_TIMEOUT; /* There is no need to see if FD_ISSET(sockmail,&readfds) is true because we have only one file descriptor in readfds, and a select error will refere only this file descriptor (sockmail). This comment is for the select()s below, too. */ read_count++; if ((partial_nbread=read(sockmail,&inbuf[nbread],ID_BUFFLEN-nbread))==-1) { close(sockmail); return ID_CLOSED; } nbread+=partial_nbread; } /* send 'questions'... */ resetbuff(inbuf); resetbuff(outbuf); sprintf(outbuf,"helo %s\n",localhostname); if (write(sockmail,outbuf,strlen(outbuf))==-1) { close(sockmail); return ID_WRITEERR; } read_timeout.tv_sec=ID_READTIMEOUT; read_timeout.tv_usec=0; FD_ZERO(&readfds); FD_SET(sockmail,&readfds); nbread=0; read_count=0; partial_nbread=0; while (partial_nbread<2 && read_count<3) { if(select(FD_SETSIZE,&readfds,NULL,NULL,&read_timeout)==-1) return ID_TIMEOUT; read_count++; if ((partial_nbread=read(sockmail,&inbuf[nbread],ID_BUFFLEN-nbread))==-1) { close(sockmail); return ID_CLOSED; } nbread+=partial_nbread; } resetbuff(inbuf); resetbuff(outbuf); sprintf(outbuf,"vrfy %s\n",accname); if (write(sockmail,outbuf,strlen(outbuf))==-1) { close(sockmail); return ID_WRITEERR; } read_timeout.tv_sec=ID_READTIMEOUT; read_timeout.tv_usec=0; FD_ZERO(&readfds); FD_SET(sockmail,&readfds); nbread=0; read_count=0; partial_nbread=0; while (partial_nbread<2 && read_count<3) { if(select(FD_SETSIZE,&readfds,NULL,NULL,&read_timeout)==-1) return ID_TIMEOUT; read_count++; if ((partial_nbread=read(sockmail,&inbuf[nbread],ID_BUFFLEN-nbread))==-1) { close(sockmail); return ID_READERR; } nbread+=partial_nbread; } sprintf(outbuf,"quit\n"); write(sockmail,outbuf,strlen(outbuf)); /* it isn't interesting here if write fails...*/ close(sockmail); /* end interogation */ temp=strtok(inbuf," "); n_msgs=0; /* We will restrict the number of items read here just like in ident_request(), not to 4, but 10, 'cause there are some lasy people over the world ( Like me, yeah !:) ) whom name can contain a lot of initials, father's initial(s), mother's ( why not ?), and another one bilion of names. */ while (temp!=NULL && n_msgs<10) { if((msgs[n_msgs]=(char *)malloc(ID_BUFFLEN+1))==NULL) return ID_NOMEM; strcpy(msgs[n_msgs],temp); /* We'll clean this messages right now! We wasted a lot of CPU time already and this is not all...:-| */ while (strlen(msgs[n_msgs]) >0 && !isalnum(msgs[n_msgs][0])) (msgs[n_msgs])++; i=strlen(msgs[n_msgs])-1; while (i>0 && !isalnum(msgs[n_msgs][i])) msgs[n_msgs][i--]='\0'; if (msgs[n_msgs]!=NULL && strlen(msgs[n_msgs])>0) n_msgs++; temp=strtok(NULL," "); } if (n_msgs<1) return ID_READERR; i=atoi(msgs[0]); switch (i) { case 500: return ID_COMERR; case 550: return ID_UNKNOWN; /* I should add more values here, so the return messages will be mode comprehensible... */ case 250: if (!strchr(msgs[n_msgs-1],'@')) return ID_CRAP; strcpy(email,""); for (i=1;i<n_msgs-1;i++) sprintf(email,"%s %s",email,msgs[i]); sprintf(email,"%s <%s>",email,msgs[n_msgs-1]); return ID_OK; default: return ID_CRAP; } } /*** Check if a host is in hosts file ***/ int check_host(char *ip_site, char *named_site) { FILE *fp; char siteaddr[82], sitename[82]; set_crash(); if (!use_hostsfile) return 0; if ((fp=fopen(HOSTSFILE, "r"))==NULL) return 0; fscanf(fp, "%s %s", siteaddr, sitename); while (!feof(fp)) { if (!strcmp(ip_site, siteaddr)) { fclose(fp); strcpy(named_site, sitename); return 1; } fscanf(fp, "%s %s", siteaddr, sitename); } fclose(fp); return 0; } /*** Init the hosts file ***/ void init_hostsfile(void) { FILE *fp; set_crash(); if (!use_hostsfile) return; if ((fp=fopen(HOSTSFILE, "r"))==NULL) { if((fp=fopen(HOSTSFILE, "w"))==NULL) { write_syslog(ERRLOG, 1, "Cannot read file in add_host().\n"); return; } fprintf(fp, "127.0.0.1 localhost\n"); fclose(fp); return; } } /*** Add a site in hosts file ***/ void add_host(char *siteaddr, char *sitename) { FILE *fp; char asite[80], aname[80]; set_crash(); if (!use_hostsfile) return; if ((fp=fopen(HOSTSFILE,"r"))==NULL) { write_syslog(ERRLOG, 1, "Cannot read file in add_host().\n"); return; } fscanf(fp, "%s %s", asite, aname); while (!feof(fp)) { if (!strcmp(asite, siteaddr)) { fclose(fp); /* found, so don't want to write in file */ return; } fscanf(fp, "%s %s", asite, aname); } fclose(fp); if ((fp=fopen(HOSTSFILE,"a"))==NULL) { write_syslog(ERRLOG, 1, "Cannot append file in add_host().\n"); return; } fprintf(fp, "%s %s\n", siteaddr, sitename); fclose(fp); } /*** Get net address of accepted connection ***/ void get_net_addresses(struct sockaddr_in acc_addr, char *ip_site, char *named_site) { struct hostent *host; set_crash(); /* Get number addr */ strcpy(ip_site,(char *)inet_ntoa(acc_addr.sin_addr)); /* Get named site Hanging usually happens on BSD systems when using gethostbyaddr. If this happens to you then alter the resolve_ip setting in the config file. */ switch (amsys->resolve_ip) { case 0: /* don't resolve */ strcpy(named_site,ip_site); return; case 1: /* resolve automatically */ if (!check_host(ip_site, named_site)) { if ((host=gethostbyaddr((char *)&acc_addr.sin_addr,sizeof(acc_addr.sin_addr),AF_INET))!=NULL) { strcpy(named_site, host->h_name); strtolower(named_site); add_host(ip_site, named_site); } else strcpy(named_site,ip_site); } return; case 2: /* resolve with function by tref */ strcpy(named_site,((char *)resolve_ip(ip_site))); return; } } void ping(UR_OBJECT user) { char cmd[]={IAC, DO, TELOPT_STATUS}; if (user->type==CLONE_TYPE || user->type==BOT_TYPE) return; write_sock(user->socket, cmd); gettimeofday(&(user->ping_timer), NULL); } void ping_respond(UR_OBJECT user) { struct timeval endtv; long pt; if (user->type==CLONE_TYPE || user->type==BOT_TYPE) return; memset(&endtv, 0, sizeof(struct timeval)); gettimeofday(&endtv, NULL); pt=((endtv.tv_sec-user->ping_timer.tv_sec)*1000000)+(endtv.tv_usec-user->ping_timer.tv_usec); if (user->last_ping==-1) { user->last_ping=pt; user->next_ping=PINGINTERVAL; return; } vwrite_user(user, "~CW- ~FTYou have about %ld.%.2ld seconds of lag. ~CB(~CR%s~CB)\n", pt/1000000, (pt/10000)%1000000, ping_string(user)); } void ping_timed(UR_OBJECT user) { if (user->type==CLONE_TYPE || user->type==BOT_TYPE) return; user->last_ping=-1; ping(user); } char * ping_string(UR_OBJECT user) { int i; if (user->type==CLONE_TYPE || user->type==BOT_TYPE) return("Spanked!"); for (i=0; speeds[i].text[0]; i++) if ((user->last_ping/10000)<=speeds[i].lag) return speeds[i].text; return("Spanked!"); } #endif /* __S_NET_C__ */