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