allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (10/01/89)
Posting-number: Volume 8, Issue 64 Submitted-by: matthew@CS.UCLA.EDU (Matthew Merzbacher) Archive-name: bug #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # README # bug.1 # bug.c # This archive created: Fri Sep 29 18:29:52 1989 export PATH; PATH=/bin:$PATH if test -f 'README' then echo shar: will not over-write existing file "'README'" else cat << \SHAR_EOF > 'README' Bug is used to tap a stream socket. It is useful for tracing communication between a server and its clients. The communication between server and client is maintained while transcripts of all communication lines are taken. There is a man page (bug.1), a source file (bug.c) and this file (README) included in this archive. No Makefile is necessary, since to "make" it, all you do is: cc -o bug bug.c You need to be running a BSD or BSD-derived system (since it examines sockets). It has been tested under SunOS 4.0.3 If you don't like my MARK, you can change it by changing the lines #define MARK and #define MARKLEN to your own values. I'd be interested in hearing what people have to say and what they use 'bug' for. I hope I haven't re-invented the wheel. Bugs/Comments/Questions/Hate Mail to me, Matthew Merzbacher ARPA: matthew@CS.UCLA.EDU UUCP: ...!{uunet|rutgers|ucbvax}!cs.ucla.edu!matthew SHAR_EOF fi # end of overwriting check if test -f 'bug.1' then echo shar: will not over-write existing file "'bug.1'" else cat << \SHAR_EOF > 'bug.1' .TH BUG 1 \" Copyright (C) 1989 by Matthew Merzbacher. All Rights Reserved. .SH NAME bug \- listen and transcribe communication on a socket .SH SYNOPSIS .B bug .nh input_port output_port machine client_file server_file .hy .SH DESCRIPTION .I bug is used to listen on a specified \fIinput_port\fR and write an exact duplicate out to the \fIoutput_port\fR on a specified \fImachine\fR. It also writes a transcript of everything that is said on either port to seperate files. Each piece of communication is seperated by a MARK, which is #defined in the code as "<MARK>". .PP The naming scheme for the output files is \fIclient_file\fR (for communication received from the \fIinput_port\fR) or \fIserver_file\fR (for communication received from the \fIoutput_port\fR) followed by a period ('.') followed by the process id of the bug program followed by a period ('.') followed by the process id of the child of bug which actually does the monitoring. Thus, for every connection made to the input_port, there will be two (unique) files created. .PP The output files are probably best read by using \fIod\fR(1) with the "-c" or "-cx" options. .SH EXAMPLE \fIbug\fR 3000 2999 moosebreath cl se .PP This invocation will create, for every connection to port 3000 on the current machine, two files (cl.pid.cpid and se.pid.cpid). Every communication to port 3000 is repeated verbatim to port 2999 on machine "moosebreath" and written to the first file. All responses are written to the second file. .SH FILES .br creates files based on \fIclient_file\fR and \fIserver_file\fR .SH "SEE ALSO" od(1), socket(2) [and friends], fork(2). .SH AUTHOR Matthew Merzbacher, bugs/comments - matthew@cs.ucla.edu .SH BUGS .PP Goodness knows what systems this will actually run on. Any BSD or BSD-derived system SHOULD work. There should be an option to change the MARK. SHAR_EOF fi # end of overwriting check if test -f 'bug.c' then echo shar: will not over-write existing file "'bug.c'" else cat << \SHAR_EOF > 'bug.c' /* Copyright (C) 1989 by Matthew Merzbacher. All Rights Reserved. Bug is provided as is, without express or implied warranty. In no event shall Matthew Merzbacher become liable for any loss or damages, consequential or otherwise, arising from the use or possession of this software. */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #include <fcntl.h> #define MARK "<MARK>" #define MARKLEN 6 /* * Brief Description: * Bug is used to tap a stream socket. It is useful for tracing communication * between a server and its clients. The communication between server and * client is maintained while transcripts of all communication lines are taken. * It has six required (and no optional) arguments. * * Usage: * bug <in port> <out port> <machine> <client file> <server file> * * <in port> - the port (on the machine on which bug runs) to which to * clients will connect (the pseudo-port) * <out port> - the true server port * <machine> - the server machine * <client file> - transcript file of what each client says * <server file> - transcript file of what the server responds * * Example: * Suppose a server listens on port 3000 of machine "xyz". The user must * artificially make the clients talk to some other port (on any machine - * it could be the server machine, the client machine, or a third machine). * That port is called the pseudo-port. Bug runs on the machine of the * pseudo-port. To run it, type: * * bug 2999 3000 xyz client server * * This assumes that the pseudo-port is 2999. The output files will all start * with "client" or "server" followed by the process number of the bug process * and the process number of each seperate listening session. That way, you * can follow the connection order. Typically, the output files created by bug * may be read by using 'od -c'. * */ main(argc, argv) int argc; char *argv[]; { struct sockaddr_in server; struct hostent *hp, *gethostbyname(); char buf[1024]; int rval; int outfile1, outfile2; int insock, outsock, msgsock; int insocknum, outsocknum; fd_set fdset; /* Check Arguments */ if (argc < 6) { printf("usage: %s <in port> <out port> <machine> <client file> <server file>\n",argv[0]); exit(1); } insocknum = atoi(argv[1]); outsocknum = atoi(argv[2]); /* Create listening post on pseudo-port */ insock = socket(AF_INET, SOCK_STREAM, 0); if (insock < 0) { perror("opening pseudo-port stream socket"); exit(1); } /* Name socket using user supplied port number */ server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = insocknum; if (bind(insock, &server, sizeof(server))) { perror("binding pseudo-port stream socket"); exit(1); } /* Start accepting connections */ listen(insock, SOMAXCONN); /* Every connection spawns a child to handle the communication */ do { msgsock = accept(insock, 0, 0); if (msgsock == -1) perror("accept"); } while (fork() != 0); /* Close listening post - it's now called "msgsock" */ close(insock); /* Create output socket to server */ outsock = socket(AF_INET, SOCK_STREAM, 0); if (outsock < 0) { perror("opening server stream socket"); exit(1); } /* Connect socket using machine & port specified on command line. */ server.sin_family = AF_INET; hp = gethostbyname(argv[3]); if (hp == 0) { fprintf(stderr, "%s: unknown machine\n", argv[3]); exit(2); } bcopy(hp->h_addr, &server.sin_addr, hp->h_length); server.sin_port = htons(outsocknum); if (connect(outsock, &server, sizeof(server)) < 0) { perror("connecting server stream socket"); exit(1); } /* Open the output files */ sprintf(buf,"%s.%d.%d",argv[4],getppid(),getpid()); if ((outfile1 = open(buf, O_TRUNC|O_WRONLY|O_CREAT, 0644)) == -1) { fprintf(stderr,"cannot open file: %s\n",buf); exit(1); } sprintf(buf,"%s.%d.%d",argv[5],getppid(),getpid()); if ((outfile2 = open(buf, O_TRUNC|O_WRONLY|O_CREAT, 0644)) == -1) { fprintf(stderr,"cannot open file: %s\n",buf); exit(1); } do { /* find out who's talking */ FD_ZERO(&fdset); FD_SET(msgsock, &fdset); FD_SET(outsock, &fdset); if (select(getdtablesize(), &fdset, 0, 0, 0) == -1) { perror("select"); exit(1); } bzero(buf, 1024); if (FD_ISSET(msgsock, &fdset) && FD_ISSET(outsock, &fdset)) fprintf(stderr,"Two talkers - no listeners\n"); /* Client is talking to server */ if (FD_ISSET(msgsock, &fdset)) { if ((rval = read(msgsock, buf, 1024)) < 0) perror("reading stream message"); if (rval == 0) fprintf(stderr,"Ending client connection\n"); else { write(outfile1, buf, rval); write(outfile1, MARK, 6); if (write(outsock, buf, rval) < 0) perror("writing on output stream socket"); } } /* Server is talking to client */ else { if (! FD_ISSET(outsock, &fdset)) { perror("weird behavior"); exit(1); } if ((rval = read(outsock, buf, 1024)) < 0) perror("reading stream message"); if (rval == 0) fprintf(stderr,"Ending server connection\n"); else { write(outfile2, buf, rval); write(outfile2, MARK, 6); if (write(msgsock, buf, rval) < 0) perror("writing on output stream socket"); } } } while (rval != 0); /* Close up shop */ fprintf(stderr, "Closing Connections\n"); close(msgsock); close(outsock); close(outfile1); close(outfile2); } SHAR_EOF fi # end of overwriting check # End of shell archive exit 0