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
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.
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.
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
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
28 #define VERSION "0.0.4"
40 #include "disp_basic.h"
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 };
48 int openport(const char *device, speed_t baud, int setup)
51 struct termios serparams;
53 if ((filedes=open(device, O_RDWR | O_NONBLOCK))==-1) {
54 /* Can't open device */
55 fprintf(stderr,"%s: ",device);
61 bzero(&serparams, sizeof(serparams));
63 serparams.c_cflag=baud | CLOCAL | CS8 | CREAD;
65 if (tcflush(filedes, TCIFLUSH)) {
66 fprintf(stderr,"%s: ",device);
70 if (tcsetattr(filedes, TCSANOW, &serparams)) {
71 fprintf(stderr,"%s: ",device);
80 int closeport(int filedes)
82 /* Should remove any locks at this point */
83 return close(filedes);
87 this returns the string for the character passed to it
88 It could be expanded in the future to maybe to string recognitions?
90 char *chardecide(unsigned char c, int alpha, char *format) {
91 static char result[256];
93 /* everyone should take up 5 characters */
95 if ((c < 32) | (c > 126)) {
98 sprintf(result,"<LF>");
101 sprintf(result,"<CR>");
104 sprintf(result,"<ESC>");
107 snprintf(result,256,"<%02hX>",c);
111 snprintf(result,256,"%c",c);
114 snprintf(result,256,format,c);
119 void outputchar(unsigned char c, int port, int alpha,
120 long usec_threshold, long usec_waited, char *name1, char *name2, char *format)
124 todisplay=chardecide(c,alpha,format);
125 disp_outputstr(port, todisplay, usec_threshold, usec_waited, name1, name2);
128 void mainloop(int port1, int port2, int silent, int alpha, long usec_threshold, char *name1, char *name2, char *format)
130 unsigned char c1, c2;
136 struct timeval before;
137 struct timeval after;
141 /* need the largest fd for the select call */
142 biggestfd=port1 > port2 ? port1 : port2;
146 /* reset the select set */
154 if (gettimeofday(&before,NULL)) {
155 perror("gettimeofday");
158 if ((fdret=select(biggestfd, &rfds, NULL, &efds, NULL))<0) {
162 if (gettimeofday(&after,NULL)) {
163 perror("gettimeofday");
167 /* get seconds difference */
168 timediff=after.tv_sec-before.tv_sec;
169 /* convert to micro seconds */
171 /* add difference in usecs */
172 timediff+=after.tv_usec-before.tv_usec;
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);
179 if (!silent) write(port2,&c1,1);
185 if (rc<0 && errno!=EAGAIN) {
186 perror("read(port1)");
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);
196 if (!silent) write(port1,&c2,1);
202 if (rc<0 && errno!=EAGAIN) {
203 perror("read(port2)");
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");
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");
229 fprintf(stderr,"sersniff v%s\n"
232 "sersniff [-h] [-i DEV | -l PORT] [-o DEV | -c HOST:PORT] [-b BAUD] [-w USEC]\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"
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"
246 "-s Silent - don't pass data from port1 <=> port2,\n"
247 " just display what we see from them.\n"
252 int main(int argc, char *argv[])
262 char *connecthost=NULL, *tmpchr=NULL;
266 long usec_threshold=USEC;
270 while ((optret=getopt(argc,argv,"hxsni:l:o:c:b:w:1:2:f:"))!=EOF) {
272 case '?': case 'h': case ':':
278 usec_threshold=atoi(optarg);
281 if ((tmpchr=strchr(optarg, ':'))!=NULL &&
282 (strchr(optarg, '/')==NULL)) {
284 listenport=atoi(++tmpchr);
290 if ((tmpchr=strchr(optarg, ':'))!=NULL &&
291 (strchr(optarg, '/')==NULL)) {
293 connectport=atoi(++tmpchr);
294 connecthost=strdup(optarg);
306 if (strstr(optarg,speed_str[speed])==optarg) {
307 baud=speed_num[speed];
312 fprintf(stderr,"Unsupported Baud: '%s'\n",
321 name1=strdup(optarg);
324 name2=strdup(optarg);
327 format=strdup(optarg);
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");
342 port1=openport(dev1, baud, setup_port);
344 disp_outputstatus("Waiting for connection to TCP port.");
345 port1=listensock(listenport);
349 port2=openport(dev2, baud, setup_port);
351 disp_outputstatus("Connecting to TCP port.");
352 port2=opensock(connecthost, connectport);
355 if (port1 < 0 || port2 < 0) {
356 fprintf(stderr,"Argh. An open failed!\n");
360 mainloop(port1, port2, silent, show_alpha, usec_threshold, name1, name2, format);
363 if (dev1) free(dev1);
364 if (dev2) free(dev2);
365 if (connecthost) free(connecthost);