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 cfsetspeed(&serparams, baud);
64 serparams.c_cflag |= CLOCAL | CS8 | CREAD;
66 if (tcflush(filedes, TCIFLUSH)) {
67 fprintf(stderr,"%s: ",device);
71 if (tcsetattr(filedes, TCSANOW, &serparams)) {
72 fprintf(stderr,"%s: ",device);
81 int closeport(int filedes)
83 /* Should remove any locks at this point */
84 return close(filedes);
88 this returns the string for the character passed to it
89 It could be expanded in the future to maybe to string recognitions?
91 char *chardecide(unsigned char c, int alpha, char *format) {
92 static char result[256];
94 /* everyone should take up 5 characters */
96 if ((c < 32) | (c > 126)) {
99 sprintf(result,"<LF>");
102 sprintf(result,"<CR>");
105 sprintf(result,"<ESC>");
108 snprintf(result,256,"<%02hX>",c);
112 snprintf(result,256,"%c",c);
115 snprintf(result,256,format,c);
120 void outputchar(unsigned char c, int port, int alpha,
121 long usec_threshold, long usec_waited, char *name1, char *name2, char *format)
125 todisplay=chardecide(c,alpha,format);
126 disp_outputstr(port, todisplay, usec_threshold, usec_waited, name1, name2);
129 void mainloop(int port1, int port2, int silent, int alpha, long usec_threshold, char *name1, char *name2, char *format)
131 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;
147 /* reset the select set */
155 if (gettimeofday(&before,NULL)) {
156 perror("gettimeofday");
159 if ((fdret=select(biggestfd, &rfds, NULL, &efds, NULL))<0) {
163 if (gettimeofday(&after,NULL)) {
164 perror("gettimeofday");
168 /* get seconds difference */
169 timediff=after.tv_sec-before.tv_sec;
170 /* convert to micro seconds */
172 /* add difference in usecs */
173 timediff+=after.tv_usec-before.tv_usec;
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);
180 if (!silent) write(port2,&c1,1);
186 if (rc<0 && errno!=EAGAIN) {
187 perror("read(port1)");
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);
197 if (!silent) write(port1,&c2,1);
203 if (rc<0 && errno!=EAGAIN) {
204 perror("read(port2)");
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");
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");
230 fprintf(stderr,"sersniff v%s\n"
233 "sersniff [-h] [-i DEV | -l PORT] [-o DEV | -c HOST:PORT] [-b BAUD] [-w USEC]\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"
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"
247 "-s Silent - don't pass data from port1 <=> port2,\n"
248 " just display what we see from them.\n"
253 int main(int argc, char *argv[])
263 char *connecthost=NULL, *tmpchr=NULL;
267 long usec_threshold=USEC;
271 while ((optret=getopt(argc,argv,"hxsni:l:o:c:b:w:1:2:f:"))!=EOF) {
273 case '?': case 'h': case ':':
279 usec_threshold=atoi(optarg);
282 if ((tmpchr=strchr(optarg, ':'))!=NULL &&
283 (strchr(optarg, '/')==NULL)) {
285 listenport=atoi(++tmpchr);
291 if ((tmpchr=strchr(optarg, ':'))!=NULL &&
292 (strchr(optarg, '/')==NULL)) {
294 connectport=atoi(++tmpchr);
295 connecthost=strdup(optarg);
307 if (strstr(optarg,speed_str[speed])==optarg) {
308 baud=speed_num[speed];
313 fprintf(stderr,"Unsupported Baud: '%s'\n",
322 name1=strdup(optarg);
325 name2=strdup(optarg);
328 format=strdup(optarg);
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");
343 port1=openport(dev1, baud, setup_port);
345 disp_outputstatus("Waiting for connection to TCP port.");
346 port1=listensock(listenport);
350 port2=openport(dev2, baud, setup_port);
352 disp_outputstatus("Connecting to TCP port.");
353 port2=opensock(connecthost, connectport);
356 if (port1 < 0 || port2 < 0) {
357 fprintf(stderr,"Argh. An open failed!\n");
361 mainloop(port1, port2, silent, show_alpha, usec_threshold, name1, name2, format);
364 if (dev1) free(dev1);
365 if (dev2) free(dev2);
366 if (connecthost) free(connecthost);