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;
137 struct timeval before;
138 struct timeval after;
142 /* need the largest fd for the select call */
143 biggestfd=port1 > port2 ? port1 : port2;
148 /* reset the select set */
156 if (gettimeofday(&before,NULL)) {
157 perror("gettimeofday");
160 if ((fdret=select(biggestfd, &rfds, NULL, &efds, NULL))<0) {
164 if (gettimeofday(&after,NULL)) {
165 perror("gettimeofday");
169 /* get seconds difference */
170 timediff=after.tv_sec-before.tv_sec;
171 /* convert to micro seconds */
173 /* add difference in usecs */
174 timediff+=after.tv_usec-before.tv_usec;
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);
181 if (!silent) write(port2,&c1,1);
187 if (rc<0 && errno!=EAGAIN) {
188 perror("read(port1)");
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);
198 if (!silent) write(port1,&c2,1);
204 if (rc<0 && errno!=EAGAIN) {
205 perror("read(port2)");
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");
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");
231 fprintf(stderr,"sersniff v%s
234 sersniff [-h] [-i DEV | -l PORT] [-o DEV | -c HOST:PORT] [-b BAUD] [-w USEC]
236 -x Show hex characters instead of alpha
237 -f PRINTF_OPTS printf style options for printing hex characters
238 when '-x' switch is given (default \"<%%02hX>\")
239 -i DEVICE Port 1 device (defaults to /dev/ttyS0). Use host:port for
241 -1 PORT1_NAME Port 1 name to be printed (defaults to 'Port1')
242 -o DEVICE Port 2 device (defaults to /dev/ttyS1). Use :port for TCP.
243 -2 PORT2_NAME Port 2 name to be printed (defaults to 'Port2')
244 -b BAUD Baud rate (Defaults to 19200)
245 -n No port configuration (do not set BAUD or change settings)
246 -w USECS How many microsecs to wait before reporting a delay
248 -s Silent - don't pass data from port1 <=> port2,
249 just display what we see from them.
254 int main(int argc, char *argv[])
264 char *connecthost=NULL, *tmpchr=NULL;
268 long usec_threshold=USEC;
272 while ((optret=getopt(argc,argv,"hxsni:l:o:c:b:w:1:2:f:"))!=EOF) {
274 case '?': case 'h': case ':':
280 usec_threshold=atoi(optarg);
283 if ((tmpchr=strchr(optarg, ':'))!=NULL &&
284 (strchr(optarg, '/')==NULL)) {
286 listenport=atoi(++tmpchr);
292 if ((tmpchr=strchr(optarg, ':'))!=NULL &&
293 (strchr(optarg, '/')==NULL)) {
295 connectport=atoi(++tmpchr);
296 connecthost=strdup(optarg);
308 if (strstr(optarg,speed_str[speed])==optarg) {
309 baud=speed_num[speed];
314 fprintf(stderr,"Unsupported Baud: '%s'\n",
323 name1=strdup(optarg);
326 name2=strdup(optarg);
329 format=strdup(optarg);
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");
344 port1=openport(dev1, baud, setup_port);
346 disp_outputstatus("Waiting for connection to TCP port.");
347 port1=listensock(listenport);
351 port2=openport(dev2, baud, setup_port);
353 disp_outputstatus("Connecting to TCP port.");
354 port2=opensock(connecthost, connectport);
357 if (port1 < 0 || port2 < 0) {
358 fprintf(stderr,"Argh. An open failed!\n");
362 mainloop(port1, port2, silent, show_alpha, usec_threshold, name1, name2, format);
365 if (dev1) free(dev1);
366 if (dev2) free(dev2);
367 if (connecthost) free(connecthost);