upped version number
[kai/samba.git] / source3 / sockspy.c
1 /*
2  USAGE
3    sockspy desthost destservice
4
5 You install this program in /etc/inetd.conf and /etc/services
6
7 For example I have used these entries:
8
9 /etc/services:
10 spy             8001/tcp        spy port
11
12 /etc/inetd.conf:
13 spy stream tcp nowait tridge /usr/local/smb/sockspy sockspy fjall netbios-ssn
14
15 This means any connection to port 8001 will be redirected to
16 netbios-ssn on fjall. By playing with these parameters you can easily
17 spy on most of the tcp protocols. All packets traversing the link will
18 be captured.
19
20 NOTE: This program is totally unsupported. I haven't used it for 2
21 years, and don't intend to fix the obvious bugs/limitations. I will,
22 however, accept contributed patches - or even a total rewrite :-)
23 */
24
25 #include <stdio.h>
26 #include <strings.h>
27 #include <sys/types.h>
28 #include <sys/dir.h>
29 #include <sys/socket.h>
30 #include <sys/ioctl.h>
31 #include <netinet/in.h>
32 #include <netdb.h>
33
34 #include <signal.h>
35
36 #include <errno.h>
37 #include <sysexits.h>
38
39 int trans_num = 0;
40
41 #ifndef LOGIN
42 #define LOGIN "/tmp/spy.in"
43 #endif
44
45 #ifndef LOGOUT
46 #define LOGOUT "/tmp/spy.out"
47 #endif
48
49 #ifndef LOGCMD
50 #define LOGCMD "/tmp/spy.cmd"
51 #endif
52
53 FILE *cmd = NULL;
54 FILE *login = NULL;
55 FILE *logout = NULL;
56
57 #define      STREQL(a, b)        (strcmp(a, b) == 0)
58 #define      NIL                 (0)
59
60 char      DestHost[256];    /* Remote system to connect to         */
61 char      DestObj[256];     /* Remote object/service to connect to */
62
63 /* Signal handler for SIGPIPE (write on a disconnected socket) */
64 abort()
65 {
66   if (cmd)
67     {
68       fprintf(cmd,"writing to disconnected socket!\n");
69       fflush(cmd);
70     }
71     exit(1);
72 }
73
74
75 main(argc, argv)
76 int    argc;           /* # of command line arguments */
77 char   *argv[];        /* the command line arguments  */
78 {
79   int      client,       /* Socket connected to client  */
80   server;       /* Socket to use for server    */
81
82   trans_num = 0;
83 #ifndef NOLOG
84   login = fopen(LOGIN,"w");
85   logout = fopen(LOGOUT,"w");
86   cmd = fopen(LOGCMD,"w");
87 #endif
88
89   if (cmd)
90     {
91       fprintf(cmd,"Started server\n");
92       fflush(cmd);
93     }
94
95   /* Check usage */
96   if(argc != 3)
97     return;
98
99   strcpy(DestHost,argv[1]);
100   strcpy(DestObj,argv[2]);
101   
102   /* Time to attempt the connection */
103   server = inet_conn(DestHost, DestObj);
104
105   if( server < 0 ) {
106     exit(EX_CANTCREAT);
107   }
108
109   /* Just to make the code more readable */
110   client = 0;
111   
112   /* We will abort gracefully when the client or remote system 
113      goes away */
114   signal(SIGPIPE, abort);
115   
116   /* Now just go and move raw data between client and 
117      remote system */
118   dowork(client, server);
119   /* ... NEVER RETURNS ... */
120 }
121
122 dowork(client, server)
123      int    client, server;      
124 {
125   
126   /* select(2) masks for client and remote */
127   int      ClientMask, ServerMask;
128   
129   /* Combined ClientMask and ServerMask */
130   int      ReadMask;
131
132   /* Initialize select(2) masks */
133   ClientMask = 1<<client;
134   ServerMask = 1<<server;
135   
136   ReadMask = ClientMask | ServerMask;
137   
138   /* Now move raw data for the rest of our life between 
139      client and remote */
140   for( ; ; ) {
141     /* Local Variables */
142     int  SelectReadMask;/* select(2) mask modifiable by select(2) */
143     int  nready;        /* status return from select(2)           */
144     
145     do {
146       /* Intialize select(2) mask everytime
147          as select(2) always modifies it */
148       SelectReadMask = ReadMask;
149       
150       /* Wait for data to be present to be moved */
151       errno = 0;
152       nready = select(32,&SelectReadMask,(int *)0,(int *)0,NIL);
153     } while( nready < 0  &&  errno == EINTR );
154
155     /* select(2) failed, shouldn't happen.  Exit abnormally */
156     if( nready < 0 )
157       exit(EX_SOFTWARE);
158     
159     /* Favor the client (for no particular reason) 
160        if s/he is has data */
161     if( SelectReadMask & ClientMask )      
162       {
163         if (cmd)
164           fprintf(cmd,"client %d\n",nready);
165         xfer(client, server,login);
166       }
167     
168     /* Then check on the other guy */
169     if( SelectReadMask & ServerMask )
170       {
171         if (cmd)
172           fprintf(cmd,"server %d\n",nready);
173         xfer(server, client,logout);
174       }
175   }
176
177     /* NEVER REACHED */
178 }
179
180 #define      BUFSIZE        20000 /* Max bytes to move at a time */
181
182 xfer(from, to,file)
183      int      from, to;        /* Move data from "from" to "to" */
184      FILE *file;
185 {
186   static char buf[BUFSIZE];      /* Buffer data to be moved      */
187   int      nready;               /* # bytes readable             */
188   int      got;                  /* # bytes actually being moved */
189   int ret;
190   
191   /* Query the system how many bytes are ready to be read */
192   ioctl(from, FIONREAD, &nready);
193   
194   if (cmd)
195     fprintf(cmd,"nready = %d\n",nready);
196   
197   /* Only try to get the smaller of nready and BUFSIZE */
198   got = read(from, buf, nready < BUFSIZE ? nready : BUFSIZE);
199
200   /* Zero bytes returned indicates end of stream, exit gracefully */
201   if( got == 0 )
202     {
203       if (cmd)
204         {
205           fprintf(cmd,"read 0 bytes exiting\n");
206           fflush(cmd);
207         }
208       if (login)
209         fclose(login);
210       if (logout)
211         fclose(logout);
212       if (cmd)
213         fclose(cmd);
214       exit(EX_OK);
215     }
216   
217   
218   if (file)
219     {
220       fprintf(file,"\nTransaction %d\n",trans_num);
221       fwrite(buf,got,1,file);
222       fflush(file);
223     }
224   trans_num++;
225   
226   /* Now send it accross to the other side */
227   ret = write(to, buf, got);
228   
229   if (cmd)
230     {
231       fprintf(cmd,"wrote %d\n",ret);
232       if (ret < 0)
233         fprintf(cmd,"error = %s\n",strerror(errno));
234     }
235 }
236
237 int
238 inet_conn(host, port)
239     char *host;
240     char *port;
241 {
242   /* Local Vars */
243   int                sock;      /* Socket to use for the connection */
244   struct hostent     *hostent;  /* Destination host entry           */
245   struct servent     *servent;  /* Destination service entry        */
246   struct sockaddr_in addr;      /* Formated destination for connect */
247   
248   /* Fetch the requested host and service entries */
249   hostent = gethostbyname(host);
250   if (isdigit(*port))
251     servent = getservbyport(80, "tcp");
252   else
253     servent = getservbyname(port, "tcp");
254
255   
256   if (cmd)
257     {
258       fprintf(cmd,"inet_conn %s %s\n",host,port);
259   
260       if (servent == NULL)
261         fprintf(cmd,"servent is NIL\n");
262       if (hostent == NULL)
263         fprintf(cmd,"hostent is NIL\n");
264       if (hostent->h_addrtype != AF_INET)
265         fprintf(cmd,"not inet type\n");
266       fflush(cmd);
267     }
268
269
270   /* No host entry, no service entry, or host is not 
271      Internet, error! */
272   if( servent == NIL || 
273      hostent == NIL || 
274      hostent->h_addrtype != AF_INET )
275     return -1;
276   
277   /* Get a socket from the system to use for the connection */
278   if( (sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
279     return -1;
280   
281   /* Make sure we start with a clean address structure ... */
282   bzero(&addr, sizeof(addr));
283   
284   /* ... then fill in the required fields */
285   addr.sin_family = AF_INET;
286   addr.sin_port   = servent->s_port;
287   bcopy(hostent->h_addr, &addr.sin_addr, hostent->h_length);
288   
289   /* Now try to connection to the destination */
290   if( connect(sock, &addr, sizeof(addr)) < 0 ) {
291     /* No go, release the socket, and then return error! */
292     close(sock);
293     return -1;
294   }
295   
296   /* Success.  Return the connected socket descriptor */
297   if (cmd)
298     fprintf(cmd,"returning %d\n",sock);
299   return sock;
300 }
301
302