]> the.earth.li Git - sersniff.git/blob - sersniff.c
f12faf44de92841c28e7e339912713f4be6b7eb0
[sersniff.git] / sersniff.c
1 /*
2         sersniff.c - A program to tunnel between 2 serial ports and
3         sniff the data that passes between them. Designed to aid
4         working out the protocol between a Nokia 9000i and NServer.
5         Written by Jonathan McDowell for Project Purple, 1999
6         Extra stuff by Cornelius Cook (cook@cpoint.net), 1999
7
8         This program is free software; you can redistribute it and/or
9         modify it under the terms of the GNU General Public License
10         as published by the Free Software Foundation; either version 2
11         of the License, or (at your option) any later version.
12
13         This program is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17
18         You should have received a copy of the GNU General Public License
19         along with this program; if not, write to the Free Software Foundation
20         Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21         http://www.gnu.org/copyleft/gpl.html
22
23         07/09/1999 - Started writing.
24         21Nov1999  - Cook: added command line support and extra error checking
25         27Nov1999  - Cook: added select, timer & changed output look
26 */
27
28 #define VERSION "0.0.4"
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <termios.h>
34 #include <unistd.h>
35 #include <stdlib.h>
36 #include <time.h>
37 #include <sys/time.h>
38 #include <errno.h>
39
40 #include "disp_basic.h"
41 #include "tcp.h"
42
43 char * speed_str[] = { "300", "1200", "2400", "4800", "9600", "19200", "38400",
44                 "57600", "115200", "230400", NULL };
45 speed_t speed_num[] = { B300, B1200, B2400, B4800, B9600, B19200, B38400,
46                 B57600, B115200, B230400, B0 };
47
48 int openport(const char *device, speed_t baud, int setup)
49 {
50         int filedes;
51         struct termios serparams;
52
53         if ((filedes=open(device, O_RDWR | O_NONBLOCK))==-1) {
54                 /* Can't open device */
55                 fprintf(stderr,"%s: ",device);
56                 perror(device);
57                 exit(1);
58         }
59
60         if (setup) {
61                 bzero(&serparams, sizeof(serparams));
62         
63                 serparams.c_cflag=baud | CLOCAL | CS8 | CREAD;
64
65                 if (tcflush(filedes, TCIFLUSH)) {
66                         fprintf(stderr,"%s: ",device);
67                         perror("tcflush");
68                         exit(1);
69                 }
70                 if (tcsetattr(filedes, TCSANOW, &serparams)) {
71                         fprintf(stderr,"%s: ",device);
72                         perror("tcsetattr");
73                         exit(1);
74                 }
75         }
76
77         return filedes;
78 }
79
80 int closeport(int filedes)
81 {
82         /* Should remove any locks at this point */
83         return close(filedes);
84 }
85
86 /*
87    this returns the string for the character passed to it
88    It could be expanded in the future to maybe to string recognitions?
89 */
90 char *chardecide(unsigned char c, int alpha, char *format) {
91         static char result[256];
92
93         /* everyone should take up 5 characters */
94         if (alpha) {
95            if ((c < 32) | (c > 126)) {
96                 switch (c) {
97                         case 10:
98                                 sprintf(result,"<LF>");
99                                 break;
100                         case 13:
101                                 sprintf(result,"<CR>");
102                                 break;
103                         case 27:
104                                 sprintf(result,"<ESC>");
105                                 break;
106                         default:
107                                 snprintf(result,256,"<%02hX>",c);
108                                 break;
109                 }
110            } else {
111                 snprintf(result,256,"%c",c);
112            }
113         } else {
114            snprintf(result,256,format,c);
115         }
116         return result;
117 }
118
119 void outputchar(unsigned char c, int port, int alpha,
120                 long usec_threshold, long usec_waited, char *name1, char *name2, char *format)
121 {
122         char *todisplay;
123
124         todisplay=chardecide(c,alpha,format);
125         disp_outputstr(port, todisplay, usec_threshold, usec_waited, name1, name2);
126 }
127
128 void mainloop(int port1, int port2, int silent, int alpha, long usec_threshold, char *name1, char *name2, char *format)
129 {
130         unsigned char c1, c2;
131         int last;
132         int rc;
133         fd_set rfds;
134         fd_set efds;
135         int biggestfd=0;
136         int fdret;
137         struct timeval before;
138         struct timeval after;
139         long timediff;
140         int quit=0;
141
142         /* need the largest fd for the select call */
143         biggestfd=port1 > port2 ? port1 : port2;
144         biggestfd++;
145         last=0;
146
147         while (!quit) {
148                 /* reset the select set */
149                 FD_ZERO(&rfds);
150                 FD_ZERO(&efds);
151                 FD_SET(port1,&rfds);
152                 FD_SET(port1,&efds);
153                 FD_SET(port2,&rfds);
154                 FD_SET(port2,&efds);
155
156                 if (gettimeofday(&before,NULL)) {
157                         perror("gettimeofday");
158                         exit(1);
159                 }
160                 if ((fdret=select(biggestfd, &rfds, NULL, &efds, NULL))<0) {
161                         perror("select");
162                         exit(1);
163                 }
164                 if (gettimeofday(&after,NULL)) {
165                         perror("gettimeofday");
166                         exit(1);
167                 }
168
169                 /* get seconds difference */
170                 timediff=after.tv_sec-before.tv_sec;
171                 /* convert to micro seconds */
172                 timediff*=USEC;
173                 /* add difference in usecs */
174                 timediff+=after.tv_usec-before.tv_usec;
175                 
176                 if (FD_ISSET(port1, &rfds)) {
177                         for (rc=read(port1, &c1, 1);
178                              rc>0; rc=read(port1, &c1, 1) ) {
179                                 outputchar(c1,1,alpha,usec_threshold,timediff,name1,name2,format);
180                                 timediff=0;
181                                 if (!silent) write(port2,&c1,1);
182                         }
183                         if (rc==0) {
184                                 /* EOF? */
185                                 quit=1;
186                         }
187                         if (rc<0 && errno!=EAGAIN) {
188                                 perror("read(port1)");
189                                 exit(1);
190                         }
191                 }
192                 
193                 if (FD_ISSET(port2, &rfds)) {
194                         for (rc=read(port2, &c2, 1);
195                              rc>0; rc=read(port2, &c2, 1) ) {
196                                 outputchar(c2,2,alpha,usec_threshold,timediff,name1,name2,format);
197                                 timediff=0;
198                                 if (!silent) write(port1,&c2,1);
199                         }       
200                         if (rc==0) {
201                                 /* EOF? */
202                                 quit=1;
203                         }
204                         if (rc<0 && errno!=EAGAIN) {
205                                 perror("read(port2)");
206                                 exit(1);
207                         }
208                 }
209
210                 /* check for exceptions (sockets closed, broken, etc) */
211                 if (FD_ISSET(port1, &efds)) {
212                         /* I can't remember right now what to actually
213                            check for on a fd exception, so we'll just quit */
214                         fprintf(stderr,"\nException on port1\n");
215                         quit=1;
216                 }
217                 if (FD_ISSET(port2, &efds)) {
218                         /* I can't remember right now what to actually
219                            check for on a fd exception, so we'll just quit */
220                         fprintf(stderr,"\nException on port2\n");
221                         quit=1;
222                 }
223         }
224
225         closeport(port2);
226         closeport(port1);
227 }
228
229 void usage()
230 {
231         fprintf(stderr,"sersniff v%s\n"
232
233 "Usage:\n"
234 "sersniff [-h] [-i DEV | -l PORT] [-o DEV | -c HOST:PORT] [-b BAUD] [-w USEC]\n"
235 "-h             This help\n"
236 "-x             Show hex characters instead of alpha\n"
237 "-f PRINTF_OPTS printf style options for printing hex characters\n"
238 "               when '-x' switch is given (default \"<%%02hX>\")\n"
239 "-i DEVICE      Port 1 device (defaults to /dev/ttyS0). Use host:port for\n"
240 "                TCP.\n"
241 "-1 PORT1_NAME  Port 1 name to be printed (defaults to 'Port1')\n"
242 "-o DEVICE      Port 2 device (defaults to /dev/ttyS1). Use :port for TCP.\n"
243 "-2 PORT2_NAME  Port 2 name to be printed (defaults to 'Port2')\n"
244 "-b BAUD                Baud rate (Defaults to 19200)\n"
245 "-n             No port configuration (do not set BAUD or change settings)\n"
246 "-w USECS       How many microsecs to wait before reporting a delay\n"
247 "                       (default is %d)\n"
248 "-s             Silent - don't pass data from port1 <=> port2,\n"
249 "                       just display what we see from them.\n"
250 ,VERSION,USEC);
251         exit(1);
252 }
253
254 int main(int argc, char *argv[])
255 {
256         int optret, speed;
257         int port1, port2;
258         char *dev1=NULL;
259         char *dev2=NULL;
260         char *name1=NULL;
261         char *name2=NULL;
262         int listenport=0;
263         int connectport;
264         char *connecthost=NULL, *tmpchr=NULL;
265         int show_alpha=1;
266         speed_t baud=B0;
267         int silent=0;
268         long usec_threshold=USEC;
269         int setup_port=1;
270         char *format=NULL;
271
272         while ((optret=getopt(argc,argv,"hxsni:l:o:c:b:w:1:2:f:"))!=EOF) {
273                 switch (optret) {
274                 case '?': case 'h': case ':':
275                         usage();
276                 case 's':
277                         silent=1;
278                         break;
279                 case 'w':
280                         usec_threshold=atoi(optarg);
281                         break;
282                 case 'i':
283                         if ((tmpchr=strchr(optarg, ':'))!=NULL &&
284                             (strchr(optarg, '/')==NULL)) {
285                                 *tmpchr='\0';
286                                 listenport=atoi(++tmpchr);
287                         } else {
288                                 dev1=strdup(optarg);
289                         }
290                         break;
291                 case 'o':
292                         if ((tmpchr=strchr(optarg, ':'))!=NULL &&
293                             (strchr(optarg, '/')==NULL)) {
294                                 *tmpchr='\0';
295                                 connectport=atoi(++tmpchr);
296                                 connecthost=strdup(optarg);
297                         } else {
298                                 dev2=strdup(optarg);
299                         }
300                         break;
301                 case 'x':
302                         show_alpha=0;
303                         break;
304                 case 'b':
305                         for (speed=0;
306                              speed_str[speed];
307                              speed++) {
308                                 if (strstr(optarg,speed_str[speed])==optarg) {
309                                         baud=speed_num[speed];
310                                         break;
311                                 }
312                         }
313                         if (baud==B0) {
314                                 fprintf(stderr,"Unsupported Baud: '%s'\n",
315                                         optarg);
316                                 exit(1);
317                         }
318                         break;
319                 case 'n':
320                         setup_port=0;
321                         break;
322                 case '1':
323                         name1=strdup(optarg);
324                         break;
325                 case '2':
326                         name2=strdup(optarg);
327                         break;
328                 case 'f':
329                         format=strdup(optarg);
330                         break;
331                 }
332         }
333
334         /* Default settings */
335         if (!dev1 && !listenport) dev1=strdup("/dev/ttyS0");
336         if (!name1 && !listenport) name1=strdup("Port1");
337         if (!dev2 && !connecthost) dev2=strdup("/dev/ttyS1");
338         if (!name2 && !connecthost) name2=strdup("Port2");
339         if (baud==B0) baud=B19200;
340         if (!format) format=strdup("0x%02hX");
341
342         disp_init();
343         if (dev1) {
344                 port1=openport(dev1, baud, setup_port);
345         } else {
346                 disp_outputstatus("Waiting for connection to TCP port.");
347                 port1=listensock(listenport);
348         }
349
350         if (dev2) {
351                 port2=openport(dev2, baud, setup_port);
352         } else {
353                 disp_outputstatus("Connecting to TCP port.");
354                 port2=opensock(connecthost, connectport);
355         }
356
357         if (port1 < 0 || port2 < 0) {
358                 fprintf(stderr,"Argh.  An open failed!\n");
359                 exit(1);
360         }
361
362         mainloop(port1, port2, silent, show_alpha, usec_threshold, name1, name2, format);
363
364         /* Clean up */
365         if (dev1) free(dev1);
366         if (dev2) free(dev2);
367         if (connecthost) free(connecthost);
368         disp_close();
369
370         return 0;
371 }