home *** CD-ROM | disk | FTP | other *** search
- /*
-
- faucet.c, part of
- faucet and hose: network pipe utilities
- Copyright (C) 1992 Robert Forsman
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- */
-
- static char info[] = "faucet: a network utility for sockets\nWritten 1992 by Robert Forsman <thoth@ufl.edu>\n";
- #include <stdio.h>
- #include <fcntl.h>
- #include <errno.h>
- #ifdef hpux
- #include <signal.h>
- #include <sgtty.h>
- #endif
- #include <sys/wait.h>
- #include <sys/param.h>
- #include <sys/file.h>
- #include <sys/ioctl.h>
- #include <sys/socket.h>
- #include <sys/un.h>
- #include <netinet/in.h>
- #include <netdb.h>
-
- int mastersocket;
- #define DOSTDOUT (1<<0)
- #define DOSTDIN (1<<1)
- #define DOSTDERR (1<<2)
- #define DOONCE (1<<3)
- #define DOVERBOSE (1<<4)
- #define DOUNIX (1<<5)
- long doflags=0;
- int running=1;
-
- char *foreignhost=NULL,*foreignport=NULL;
- int foreignPORT;
- struct in_addr foreignHOST;
-
- char *programname;
- extern int errno;
- extern char *sys_errlist[];
-
-
- int name_to_inet_port();
-
- void nice_shutdown()
- /* This procedure gets called when we are killed with one of the reasonable
- signals (TERM, HUP, that kind of thing). The main while loop then
- terminates and we get a chance to clean up. */
- {
- running = 0;
- }
-
-
- /* print an internet host address prettily */
- printhost(addr)
- struct in_addr *addr;
- {
- struct hostent *h;
- char *s,**p;
- int i;
-
- h = gethostbyaddr(addr, sizeof(*addr),AF_INET);
- s = (h==NULL) ? NULL : h->h_name;
-
- printf("%d", ((u_char*)addr)[0]);
- for (i=1; i<sizeof(*addr); i++)
- printf(".%d",((u_char*)addr)[i]);
-
- printf("(%s",s?s:"name unknown");
- if (s)
- for (p=h->h_aliases; *p; p++)
- printf(",%s",*p);
- printf(")");
- }
-
- int setup_socket(name)
- char *name;
- /* This procedure creates a socket and handles retries on the inet domain.
- Sockets seem to "stick" on my system (SunOS [43].x) */
- {
- int sock;
-
- sock = socket((doflags&DOUNIX)?AF_UNIX:AF_INET, SOCK_STREAM, 0);
- /* I need a real value for the protocol eventually. IPPROTO_TCP sounds
- like a good value, but what about AF_UNIX sockets? It seems to have
- worked so far... */
-
- if (sock <0) {
- perror("opening stream socket");
- exit(1);
- }
-
- if (!bindlocal(sock, name, (doflags&DOUNIX)?AF_UNIX:AF_INET)) {
- fprintf(stderr,"%s: error binding stream socket %s (%s)",
- programname,name,sys_errlist[errno]);
- exit(1);
- }
-
- listen(sock,NOFILE);
-
- return(sock);
- }
-
-
- void waitonchild()
-
- {
- union wait status;
- #if 0
- unsigned char reason,signal,rval;
- char buf[32];
- #endif
- int childpid;
-
- childpid = wait3(&status,WNOHANG,NULL);
- /* What a pity I can't easily print out child statuses */
- #if 0
- if (childpid==-1) {
- fputs(stderr,programname);
- fputs(stderr,": error in wait3 while handling SIGCHLD (");
- fputs(stderr,sys_errlist[errno]);
- fputs(stderr,")\n");
- return;
- }
- reason = status.w_status & 0xff;
- if (reason==0) {
- rval = reason >> 8;
- if (rval!=0) {
- fputs(stderr,programname);
- fputs(stderr,": Child ");
- sprintf(buf,"%d",childpid); fputs(stderr,buf);
- fputs(stderr," gave abnormal exit code ");
- sprintf(buf,"%d",rval); fputs(stderr,buf);
- fputs(stderr,"\n");
- }
- } else if (reason!=0177) {
- signal = reason & 0x7f;
- fputs(stderr,programname);
- fputs(stderr,": Child ");
- sprintf(buf,"%d",childpid); fputs(stderr,buf);
- fputs(stderr," killed by signal ");
- sprintf(buf,"%d",signal); fputs(stderr,buf);
- fputs(stderr," (");
- fputs(stderr,(signal<=SIGUSR2)?signames[signal]:"bogus signal number");
- fputs(stderr,")\n");
- }
- #endif
- }
-
-
- int
- authorize_address(sin)
- struct sockaddr *sin;
- {
- if (doflags&DOUNIX) {
- struct sockaddr_un *srv = (struct sockaddr_un*)sin;
-
- if (foreignport != NULL && 0!=strcmp(foreignport, srv->sun_path)) {
- if (doflags&DOVERBOSE) {
- printf("%s: refusing connection from port %s\n",
- programname, srv->sun_path);
- }
- return 0;
- }
- } else {
- struct sockaddr_in *srv = (struct sockaddr_in*)sin;
-
- if (foreignhost!=NULL &&
- 0!=bcmp(&srv->sin_addr,
- &foreignHOST, sizeof(foreignHOST))) {
- if (doflags&DOVERBOSE) {
- printf("refusing connection from host ");
- printhost(&srv->sin_addr);
- printf(".\n");
- }
- return 0;
- }
-
- if (foreignport!=NULL && foreignPORT != srv->sin_port) {
- if (doflags&DOVERBOSE) {
- printf("refusing connection from port %d.\n",
- ntohs(srv->sin_port));
- }
- return 0;
- }
- }
-
- return 1;
- }
-
-
- main (argc,argv)
- int argc;
- char ** argv;
-
- {
- int rval,length;
- struct sockaddr saddr;
- struct sockaddr_in *sinp = (struct sockaddr_in*)&saddr;
- struct sockaddr_un *sunp = (struct sockaddr_un*)&saddr;
-
- programname = argv[0];
-
- if (argc<3) {
- fprintf(stderr,"Usage : %s <port> <command> (in|out|err)+ [once] [verb(|ose)] [quiet] [unix] [foreignport <port>] [foreignhost <host>]\n", programname);
- exit(1);
- }
-
- /* parse trailing args */
- for (length=3; length<argc; length++) {
- if (strcmp(argv[length],"in")==0)
- doflags |= DOSTDIN;
- else if (strcmp(argv[length],"out")==0)
- doflags |= DOSTDOUT;
- else if (strcmp(argv[length],"err")==0)
- doflags |= DOSTDERR;
- else if (strcmp(argv[length],"once")==0)
- doflags |= DOONCE;
- else if (strcmp(argv[length],"verbose")==0
- || strcmp(argv[length],"verb")==0)
- doflags |= DOVERBOSE;
- else if (strcmp(argv[length],"quiet")==0)
- doflags &= ~DOVERBOSE;
- else if (strcmp(argv[length],"unix")==0)
- doflags |= DOUNIX;
- else if (strcmp(argv[length],"foreignport")==0) {
- if (length+1<argc)
- foreignport=argv[++length];
- else
- fprintf(stderr,"%s: foreignport requires port name or number.\n",
- programname);
- } else if (strcmp(argv[length],"foreignhost")==0) {
- if (length+1<argc)
- foreignhost=argv[++length];
- else
- fprintf(stderr,"%s: foreignhost requires host name or number.\n",
- programname);
- } else
- fprintf(stderr,"%s: Bogus extra command line flag \"%s\".\n",
- programname,argv[length]);
- }
-
- if ( ! (doflags&(DOSTDIN|DOSTDERR|DOSTDOUT)) ) {
- fprintf(stderr,"%s: Need at least one {in|out|err}.\n",programname);
- exit(1);
- }
-
- if ( (doflags&DOUNIX) && foreignhost!=NULL ) {
- fprintf(stderr, "%s: foreignhost parameter makes no sense with UNIX domain sockets, ignoring.\n", programname);
- foreignhost = NULL;
- }
-
- signal(SIGCHLD,waitonchild);
-
- mastersocket = setup_socket(argv[1]);
-
- signal(SIGHUP, nice_shutdown);
- signal(SIGINT, nice_shutdown);
- signal(SIGPIPE, nice_shutdown);
- signal(SIGALRM, nice_shutdown);
- signal(SIGTERM, nice_shutdown);
-
- if (foreignhost != NULL && !convert_hostname(foreignhost, &foreignHOST)) {
- fprintf(stderr, "%s: could not translate %s to a host address\n",
- programname, foreignhost);
- exit(1);
- }
-
- if (foreignport!=NULL && !(doflags&DOUNIX) &&
- 0 == (foreignPORT = name_to_inet_port(foreignport)) ) {
- fprintf(stderr,"%s: port %s unknown.\n",programname,foreignport);
- exit(1);
- }
-
- while (running) {
-
- length = sizeof(saddr);
-
- rval = accept(mastersocket,&saddr,&length);
-
- if (rval<0) {
- if (errno==EWOULDBLOCK) {
- printf("%s: No more connections to talk to.\n",programname);
- } else if (errno!=EINTR) {
- fprintf(stderr,"%s: error in accept (%s).",
- programname,sys_errlist[errno]);
- exit(1);
- }
- continue;
- }
-
- if (!authorize_address(&saddr)) {
- close(rval);
- continue;
- }
-
- if ( doflags&DOVERBOSE ) {
- printf("%s: Got connection from ",programname);
- if ( doflags&DOUNIX ) {
- printf("%s\n", sunp->sun_path);
- } else {
- printhost(&sinp->sin_addr);
- printf(" port %d\n",ntohs(sinp->sin_port));
- }
- }
-
- fflush(stdout);
-
- if ( doflags&DOONCE || fork()==0 ) {
- /* child process: frob descriptors and exec */
- char *s;
-
- if ( (doflags&(DOONCE|DOUNIX)) == (DOONCE|DOUNIX) )
- unlink(argv[1]);
- /* We don't want the unix domain socket anymore */
-
- dup2(fileno(stderr),mastersocket);
- ioctl(mastersocket,FIOCLEX,NULL);
- /* We don't need old stderr hanging around after an exec.
- The mastersocket has been closed by the dup2 */
-
- if (doflags & DOSTDIN)
- dup2(rval,fileno(stdin));
- if (doflags & DOSTDOUT)
- dup2(rval,fileno(stdout));
- if (doflags & DOSTDERR)
- dup2(rval,fileno(stderr));
-
- close(rval); /* rval has been properly duplicated */
-
- execl("/bin/csh","csh","-c",argv[2],NULL);
- s ="exec failed\n";
- write(mastersocket,s,strlen(s));
- exit(0);
- } else {
- /* parent: close socket.
- Signal will arrive upon death of child. */
- close(rval);
- }
- }
-
- /* clean up the socket when we're done */
- if (doflags&DOUNIX)
- unlink(argv[1]);
- close(mastersocket);
-
- }
-