#ident "@(#) aprelay.c 0.1 06/15/1998 " /********************************************************/ /* Copyright (C) 1998 ID NET - Nancy - FRANCE */ /* P.Toilon (zorthrax@id-net.fr) */ /* This relay is released into the Public Domain */ /* The original file 'apircrly.c' has 6901 bytes */ /********************************************************/ #include #include #include #include #include #define hd(h) ((h<'A')?(h-'0'):(((h&0xdf)-'A')+10)) /* Change it to #undef UNIX if under Windows */ #undef UNIX /* Max simultaneous users on the relay */ #define MAXUSERS 128 /* Local listener socket timeout in seconds */ #define LCTIMEOUT 120 /* Max length of negociation frame before connecting to remote */ #define MAXFRAME 128 struct usr { int fd; int fdo; } usr[MAXUSERS]; char oc; fd_set rfds,fds; struct sockaddr_in uin; int FIRST,mfd,maxfd,osz; short eoframe[MAXUSERS]; char *cpass,*cserv,*cport,*arg,*strchr(); char *fptr[MAXUSERS],frame[MAXUSERS][MAXFRAME]; void htod4(saddr,i1,i2,i3,i4) long saddr; int *i1,*i2,*i3,*i4; { char xsaddr[32]; sprintf(xsaddr,"%.8x",saddr); *i4=hd(xsaddr[0])*16+hd(xsaddr[1]); *i3=hd(xsaddr[2])*16+hd(xsaddr[3]); *i2=hd(xsaddr[4])*16+hd(xsaddr[5]); *i1=hd(xsaddr[6])*16+hd(xsaddr[7]); } /* ** addrcmp("194.206.115.0",0x0673cec2) -> 0 ** addrcmp("194.206.115.0",0x0673cec2) -> 0 ** (0x0673cec2 corresponding to 194.206.115.6) ** ** Allow to select incoming users on an accept(fd,&in,&sz). ** E.g.: addrcmp("194.206.115.0",in.sin_addr.s_addr) */ int addrcmp(faddr,saddr) char *faddr; long saddr; { int fi[4],si[4],cpt; char caddr[32],*cn2,*cn3,*cn4; strcpy(caddr,faddr); if(!isdigit(*caddr) || !(cn2=strchr(caddr,'.')) || !isdigit(*++cn2) || !(cn3=strchr(cn2,'.')) || !isdigit(*++cn3) || !(cn4=strchr(cn3,'.')) || !isdigit(*++cn4)) return(-1); *(cn2-1)=*(cn3-1)=*(cn4-1)='\0'; if((fi[0]=atoi(caddr))>255 || (fi[1]=atoi(cn2))>255 || (fi[2]=atoi(cn3))>255 || (fi[3]=atoi(cn4))>255) return(-1); htod4(saddr,&si[0],&si[1],&si[2],&si[3]); for(cpt=0;cpt<4;cpt++) if(fi[cpt] && si[cpt]!=fi[cpt]) return(-1); return(0); } int open_remote_server_socket(server,port) char *server; int port; { int fd; struct hostent *rmt; struct sockaddr_in out; if((fd=socket(AF_INET,SOCK_STREAM,0))<0) return(-1); if(!(rmt=gethostbyname(server))) { close(fd); return(-1); } memcpy(&out.sin_addr,rmt->h_addr,rmt->h_length); out.sin_family=AF_INET; out.sin_port=htons(port); if(connect(fd,(struct sockaddr *)&out,sizeof out)<0) { close(fd); return(-1); } return(fd); } int open_listener_socket(port,maxusers,timeout) int port,maxusers,timeout; { time_t tvey; struct sockaddr_in in; int fd,rt,sz=sizeof(struct sockaddr_in); if((fd=socket(AF_INET,SOCK_STREAM,0))<0) return(-1); memset(&in,0,sz); in.sin_family=AF_INET; in.sin_addr.s_addr=INADDR_ANY; in.sin_port=htons(port); time(&tvey); while((rt=bind(fd,(struct sockaddr *)&in,sz))<0 && (time(0)-tvey)j) j=usr[i].fd; if(usr[i].fdo>j) j=usr[i].fdo; } if(fd>j) j=fd; return(j); } /* ** accept sent a broken pipe (signal 13) ** We go back into accept_user() */ void b_accept() { FIRST=0; accept_user(); } accept_user() { int i,newfd; /* ** To avoid the accept() brokenpipe */ signal(13,b_accept); if(FIRST) { for(i=0;i=0) { if(arg && addrcmp(arg,uin.sin_addr.s_addr)==-1) { sd(newfd,"Sorry, your host is not allowed !\n\r"); close(newfd); } else if((i=getnewusernum())==-1) { sd(newfd,"Sorry, all relay sockets are busy !\n\r"); close(newfd); } else { usr[i].fd=newfd; usr[i].fdo=-1; fptr[i]=frame[i]; eoframe[i]=0; sd(usr[i].fd,"Apirc relay v1.0\r\n\n"); FD_SET(usr[i].fd,&fds); maxfd=getmaxfdvalue(mfd); } } } else for(i=0;i=MAXFRAME) { FD_CLR(usr[i].fd,&fds); close(usr[i].fd); usr[i].fd=-1; maxfd=getmaxfdvalue(mfd); } else if(oc=='§') { *(fptr[i]-1)='\0'; /* On the last ':' */ cpass=frame[i]; *(cserv=strchr(frame[i],':'))='\0'; *(cport=strchr(++cserv,':'))='\0'; cport++; eoframe[i]=1; } /* Still not § in "xUi.HjGF/g:irc.id-net.fr:6667:§" */ else if(oc>0) *(fptr[i])++ = oc; } else /* We just received the complete frame, let's connect */ { if((usr[i].fdo=open_remote_server_socket(cserv,atoi(cport)))<0) { sd(usr[i].fd,"Server unavailable\r\n"); FD_CLR(usr[i].fd,&fds); /* On libere */ close(usr[i].fd); usr[i].fd=-1; maxfd=getmaxfdvalue(mfd); } else { FD_SET(usr[i].fdo,&fds); maxfd=getmaxfdvalue(mfd); send(usr[i].fdo,&oc,1,0); /* 1st byte sent to th server */ } } } if(usr[i].fdo!=-1 && FD_ISSET(usr[i].fdo,&rfds)) { if(!recv(usr[i].fdo,&oc,1,0)) /* If disconnected */ { FD_CLR(usr[i].fd,&fds); FD_CLR(usr[i].fdo,&fds); close(usr[i].fd); close(usr[i].fdo); usr[i].fd=-1; usr[i].fdo=-1; maxfd=getmaxfdvalue(mfd); } else send(usr[i].fd,&oc,1,0); } } } } main(argc,argv) int argc; char **argv; { arg=(argc==2)?argv[1]:NULL; printf("Trying to open the listener socket ... "); fflush(stdout); if((mfd=open_listener_socket(8888,MAXUSERS,LCTIMEOUT))<0) { printf("\nSocket not openable. Daemon not ready\n"); exit(); } printf("\nListener socket ready\n"); fflush(stdout); #ifdef UNIX if(fork()) exit(); #endif osz=sizeof(struct sockaddr_in); FIRST=1; accept_user(); }