]> the.earth.li Git - sersniff.git/blob - sersniff.c
Initial import of sersniff 0.0.3
[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.3"
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)
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         bzero(&serparams, sizeof(serparams));
61         
62         serparams.c_cflag=baud | CLOCAL | CS8 | CREAD;
63
64         if (tcflush(filedes, TCIFLUSH)) {
65                 fprintf(stderr,"%s: ",device);
66                 perror("tcflush");
67                 exit(1);
68         }
69         if (tcsetattr(filedes, TCSANOW, &serparams)) {
70                 fprintf(stderr,"%s: ",device);
71                 perror("tcsetattr");
72                 exit(1);
73         }
74
75         return filedes;
76 }
77
78 int closeport(int filedes)
79 {
80         /* Should remove any locks at this point */
81         return close(filedes);
82 }
83
84 /*
85    this returns the string for the character passed to it
86    It could be expanded in the future to maybe to string recognitions?
87 */
88 char *chardecide(unsigned char c, int alpha) {
89         static char result[256];
90
91         /* everyone should take up 5 characters */
92         if (alpha) {
93            if ((c < 32) | (c > 126)) {
94                 switch (c) {
95                         case 10:
96                                 sprintf(result,"<LF>");
97                                 break;
98                         case 13:
99                                 sprintf(result,"<CR>");
100                                 break;
101                         case 27:
102                                 sprintf(result,"<ESC>");
103                                 break;
104                         default:
105                                 snprintf(result,256,"<%02hX>",c);
106                                 break;
107                 }
108            } else {
109                 snprintf(result,256,"%c",c);
110            }
111         } else {
112            snprintf(result,256,"0x%02hX ",c);
113         }
114         return result;
115 }
116
117 void outputchar(unsigned char c, int port, int alpha,
118                 long usec_threshold, long usec_waited)
119 {
120         char *todisplay;
121
122         todisplay=chardecide(c,alpha);
123         disp_outputstr(port, todisplay, usec_threshold, usec_waited);
124 }
125
126 void mainloop(int port1, int port2, int silent, int alpha, long usec_threshold)
127 {
128         unsigned char c1, c2;
129         int last;
130         int rc;
131         fd_set rfds;
132         fd_set efds;
133         int biggestfd=0;
134         int fdret;
135         struct timeval before;
136         struct timeval after;
137         long timediff;
138         int quit=0;
139
140         /* need the largest fd for the select call */
141         biggestfd=port1 > port2 ? port1 : port2;
142         biggestfd++;
143         last=0;
144
145         while (!quit) {
146                 /* reset the select set */
147                 FD_ZERO(&rfds);
148                 FD_ZERO(&efds);
149                 FD_SET(port1,&rfds);
150                 FD_SET(port1,&efds);
151                 FD_SET(port2,&rfds);
152                 FD_SET(port2,&efds);
153
154                 if (gettimeofday(&before,NULL)) {
155                         perror("gettimeofday");
156                         exit(1);
157                 }
158                 if ((fdret=select(biggestfd, &rfds, NULL, &efds, NULL))<0) {
159                         perror("select");
160                         exit(1);
161                 }
162                 if (gettimeofday(&after,NULL)) {
163                         perror("gettimeofday");
164                         exit(1);
165                 }
166
167                 /* get seconds difference */
168                 timediff=after.tv_sec-before.tv_sec;
169                 /* convert to micro seconds */
170                 timediff*=USEC;
171                 /* add difference in usecs */
172                 timediff+=after.tv_usec-before.tv_usec;
173                 
174                 if (FD_ISSET(port1, &rfds)) {
175                         for (rc=read(port1, &c1, 1);
176                              rc>0; rc=read(port1, &c1, 1) ) {
177                                 outputchar(c1,1,alpha,usec_threshold,timediff);
178                                 timediff=0;
179                                 if (!silent) write(port2,&c1,1);
180                         }
181                         if (rc==0) {
182                                 /* EOF? */
183                                 quit=1;
184                         }
185                         if (rc<0 && errno!=EAGAIN) {
186                                 perror("read(port1)");
187                                 exit(1);
188                         }
189                 }
190                 
191                 if (FD_ISSET(port2, &rfds)) {
192                         for (rc=read(port2, &c2, 1);
193                              rc>0; rc=read(port2, &c2, 1) ) {
194                                 outputchar(c2,2,alpha,usec_threshold,timediff);
195                                 timediff=0;
196                                 if (!silent) write(port1,&c2,1);
197                         }       
198                         if (rc==0) {
199                                 /* EOF? */
200                                 quit=1;
201                         }
202                         if (rc<0 && errno!=EAGAIN) {
203                                 perror("read(port2)");
204                                 exit(1);
205                         }
206                 }
207
208                 /* check for exceptions (sockets closed, broken, etc) */
209                 if (FD_ISSET(port1, &efds)) {
210                         /* I can't remember right now what to actually
211                            check for on a fd exception, so we'll just quit */
212                         fprintf(stderr,"\nException on port1\n");
213                         quit=1;
214                 }
215                 if (FD_ISSET(port2, &efds)) {
216                         /* I can't remember right now what to actually
217                            check for on a fd exception, so we'll just quit */
218                         fprintf(stderr,"\nException on port2\n");
219                         quit=1;
220                 }
221         }
222
223         closeport(port2);
224         closeport(port1);
225 }
226
227 void usage()
228 {
229         fprintf(stderr,"sersniff v%s
230
231 Usage:
232 sersniff [-h] [-i DEV | -l PORT] [-o DEV | -c HOST:PORT] [-b BAUD] [-w USEC]
233 -h              This help
234 -x              Show hex characters instead of alpha
235 -i DEVICE       Port 1 device (defaults to /dev/ttyS0)
236 -l PORT         Port 1 port for TCP
237 -o DEVICE       Port 2 device (defaults to /dev/ttyS1)
238 -c HOST:PORT    Port 2 host & port to connect to
239 -b BAUD         Baud rate (Defaults to 19200)
240 -w USECS        How many microsecs to wait before reporting a delay
241                         (default is %d)
242 -s              Silent - don't pass data from port1 <=> port2,
243                         just display what we see from them.
244 ",VERSION,USEC);
245         exit(1);
246 }
247
248 int main(int argc, char *argv[])
249 {
250         int optret, speed;
251         int port1, port2;
252         char *dev1=NULL;
253         char *dev2=NULL;
254         int listenport=0;
255         int connectport;
256         char *connecthost=NULL, *tmpchr=NULL;
257         int show_alpha=1;
258         speed_t baud=B0;
259         int silent=0;
260         long usec_threshold=USEC;
261
262         while ((optret=getopt(argc,argv,"hxsi:l:o:c:b:w:"))!=EOF) {
263                 switch (optret) {
264                 case '?': case 'h': case ':':
265                         usage();
266                 case 's':
267                         silent=1;
268                         break;
269                 case 'w':
270                         usec_threshold=atoi(optarg);
271                         break;
272                 case 'i':
273                         dev1=strdup(optarg);
274                         break;
275                 case 'o':
276                         dev2=strdup(optarg);
277                         break;
278                 case 'l':
279                         listenport=atoi(optarg);
280                         break;
281                 case 'c':
282                         if ((tmpchr=strchr(optarg, ':'))==NULL) {
283                             printf("Must specify -c option with host:port\n");
284                             exit(1);
285                         }
286                         *tmpchr='\0';
287                         connectport=atoi(++tmpchr);
288                         connecthost=strdup(optarg);
289                         break;
290                 case 'x':
291                         show_alpha=0;
292                         break;
293                 case 'b':
294                         for (speed=0;
295                              speed_str[speed];
296                              speed++) {
297                                 if (strstr(optarg,speed_str[speed])==optarg) {
298                                         baud=speed_num[speed];
299                                         break;
300                                 }
301                         }
302                         if (baud==B0) {
303                                 fprintf(stderr,"Unsupported Baud: '%s'\n",
304                                         optarg);
305                                 exit(1);
306                         }
307                         break;
308                 }
309         }
310
311         /* Default settings */
312         if (!dev1 && !listenport) dev1=strdup("/dev/ttyS0");
313         if (!dev2 && !connecthost) dev2=strdup("/dev/ttyS1");
314         if (baud==B0) baud=B19200;
315
316         disp_init();
317         if (dev1) {
318                 port1=openport(dev1, baud);
319         } else {
320                 disp_outputstatus("Waiting for connection to TCP port.");
321                 port1=listensock(listenport);
322         }
323
324         if (dev2) {
325                 port2=openport(dev2, baud);
326         } else {
327                 disp_outputstatus("Connecting to TCP port.");
328                 port2=opensock(connecthost, connectport);
329         }
330
331         if (port1 < 0 || port2 < 0) {
332                 fprintf(stderr,"Argh.  An open failed!\n");
333                 exit(1);
334         }
335
336         mainloop(port1, port2, silent, show_alpha, usec_threshold);
337
338         /* Clean up */
339         if (dev1) free(dev1);
340         if (dev2) free(dev2);
341         if (connecthost) free(connecthost);
342         disp_close();
343
344         return 0;
345 }