]> the.earth.li Git - sersniff.git/blob - sersniff.c
64e05767fbfa0a3813bc8e68d9015e230e983ef9
[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 rc;
132         fd_set rfds;
133         fd_set efds;
134         int biggestfd=0;
135         int fdret;
136         struct timeval before;
137         struct timeval after;
138         long timediff;
139         int quit=0;
140
141         /* need the largest fd for the select call */
142         biggestfd=port1 > port2 ? port1 : port2;
143         biggestfd++;
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,name1,name2,format);
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,name1,name2,format);
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\n"
230
231 "Usage:\n"
232 "sersniff [-h] [-i DEV | -l PORT] [-o DEV | -c HOST:PORT] [-b BAUD] [-w USEC]\n"
233 "-h             This help\n"
234 "-x             Show hex characters instead of alpha\n"
235 "-f PRINTF_OPTS printf style options for printing hex characters\n"
236 "               when '-x' switch is given (default \"<%%02hX>\")\n"
237 "-i DEVICE      Port 1 device (defaults to /dev/ttyS0). Use host:port for\n"
238 "                TCP.\n"
239 "-1 PORT1_NAME  Port 1 name to be printed (defaults to 'Port1')\n"
240 "-o DEVICE      Port 2 device (defaults to /dev/ttyS1). Use :port for TCP.\n"
241 "-2 PORT2_NAME  Port 2 name to be printed (defaults to 'Port2')\n"
242 "-b BAUD                Baud rate (Defaults to 19200)\n"
243 "-n             No port configuration (do not set BAUD or change settings)\n"
244 "-w USECS       How many microsecs to wait before reporting a delay\n"
245 "                       (default is %d)\n"
246 "-s             Silent - don't pass data from port1 <=> port2,\n"
247 "                       just display what we see from them.\n"
248 ,VERSION,USEC);
249         exit(1);
250 }
251
252 int main(int argc, char *argv[])
253 {
254         int optret, speed;
255         int port1, port2;
256         char *dev1=NULL;
257         char *dev2=NULL;
258         char *name1=NULL;
259         char *name2=NULL;
260         int listenport=0;
261         int connectport;
262         char *connecthost=NULL, *tmpchr=NULL;
263         int show_alpha=1;
264         speed_t baud=B0;
265         int silent=0;
266         long usec_threshold=USEC;
267         int setup_port=1;
268         char *format=NULL;
269
270         while ((optret=getopt(argc,argv,"hxsni:l:o:c:b:w:1:2:f:"))!=EOF) {
271                 switch (optret) {
272                 case '?': case 'h': case ':':
273                         usage();
274                 case 's':
275                         silent=1;
276                         break;
277                 case 'w':
278                         usec_threshold=atoi(optarg);
279                         break;
280                 case 'i':
281                         if ((tmpchr=strchr(optarg, ':'))!=NULL &&
282                             (strchr(optarg, '/')==NULL)) {
283                                 *tmpchr='\0';
284                                 listenport=atoi(++tmpchr);
285                         } else {
286                                 dev1=strdup(optarg);
287                         }
288                         break;
289                 case 'o':
290                         if ((tmpchr=strchr(optarg, ':'))!=NULL &&
291                             (strchr(optarg, '/')==NULL)) {
292                                 *tmpchr='\0';
293                                 connectport=atoi(++tmpchr);
294                                 connecthost=strdup(optarg);
295                         } else {
296                                 dev2=strdup(optarg);
297                         }
298                         break;
299                 case 'x':
300                         show_alpha=0;
301                         break;
302                 case 'b':
303                         for (speed=0;
304                              speed_str[speed];
305                              speed++) {
306                                 if (strstr(optarg,speed_str[speed])==optarg) {
307                                         baud=speed_num[speed];
308                                         break;
309                                 }
310                         }
311                         if (baud==B0) {
312                                 fprintf(stderr,"Unsupported Baud: '%s'\n",
313                                         optarg);
314                                 exit(1);
315                         }
316                         break;
317                 case 'n':
318                         setup_port=0;
319                         break;
320                 case '1':
321                         name1=strdup(optarg);
322                         break;
323                 case '2':
324                         name2=strdup(optarg);
325                         break;
326                 case 'f':
327                         format=strdup(optarg);
328                         break;
329                 }
330         }
331
332         /* Default settings */
333         if (!dev1 && !listenport) dev1=strdup("/dev/ttyS0");
334         if (!name1 && !listenport) name1=strdup("Port1");
335         if (!dev2 && !connecthost) dev2=strdup("/dev/ttyS1");
336         if (!name2 && !connecthost) name2=strdup("Port2");
337         if (baud==B0) baud=B19200;
338         if (!format) format=strdup("0x%02hX");
339
340         disp_init();
341         if (dev1) {
342                 port1=openport(dev1, baud, setup_port);
343         } else {
344                 disp_outputstatus("Waiting for connection to TCP port.");
345                 port1=listensock(listenport);
346         }
347
348         if (dev2) {
349                 port2=openport(dev2, baud, setup_port);
350         } else {
351                 disp_outputstatus("Connecting to TCP port.");
352                 port2=opensock(connecthost, connectport);
353         }
354
355         if (port1 < 0 || port2 < 0) {
356                 fprintf(stderr,"Argh.  An open failed!\n");
357                 exit(1);
358         }
359
360         mainloop(port1, port2, silent, show_alpha, usec_threshold, name1, name2, format);
361
362         /* Clean up */
363         if (dev1) free(dev1);
364         if (dev2) free(dev2);
365         if (connecthost) free(connecthost);
366         disp_close();
367
368         return 0;
369 }