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.3"
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)
51 struct termios serparams;
53 if ((filedes=open(device, O_RDWR | O_NONBLOCK))==-1) {
54 /* Can't open device */
55 fprintf(stderr,"%s: ",device);
60 bzero(&serparams, sizeof(serparams));
62 serparams.c_cflag=baud | CLOCAL | CS8 | CREAD;
64 if (tcflush(filedes, TCIFLUSH)) {
65 fprintf(stderr,"%s: ",device);
69 if (tcsetattr(filedes, TCSANOW, &serparams)) {
70 fprintf(stderr,"%s: ",device);
78 int closeport(int filedes)
80 /* Should remove any locks at this point */
81 return close(filedes);
85 this returns the string for the character passed to it
86 It could be expanded in the future to maybe to string recognitions?
88 char *chardecide(unsigned char c, int alpha) {
89 static char result[256];
91 /* everyone should take up 5 characters */
93 if ((c < 32) | (c > 126)) {
96 sprintf(result,"<LF>");
99 sprintf(result,"<CR>");
102 sprintf(result,"<ESC>");
105 snprintf(result,256,"<%02hX>",c);
109 snprintf(result,256,"%c",c);
112 snprintf(result,256,"0x%02hX ",c);
117 void outputchar(unsigned char c, int port, int alpha,
118 long usec_threshold, long usec_waited)
122 todisplay=chardecide(c,alpha);
123 disp_outputstr(port, todisplay, usec_threshold, usec_waited);
126 void mainloop(int port1, int port2, int silent, int alpha, long usec_threshold)
128 unsigned char c1, c2;
135 struct timeval before;
136 struct timeval after;
140 /* need the largest fd for the select call */
141 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);
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);
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
232 sersniff [-h] [-i DEV | -l PORT] [-o DEV | -c HOST:PORT] [-b BAUD] [-w USEC]
234 -x Show hex characters instead of alpha
235 -i DEVICE Port 1 device (defaults to /dev/ttyS0)
236 -l PORT Port 1 port for TCP
237 -o DEVICE Port 2 device (defaults to /dev/ttyS1)
238 -c HOST:PORT Port 2 host & port to connect to
239 -b BAUD Baud rate (Defaults to 19200)
240 -w USECS How many microsecs to wait before reporting a delay
242 -s Silent - don't pass data from port1 <=> port2,
243 just display what we see from them.
248 int main(int argc, char *argv[])
256 char *connecthost=NULL, *tmpchr=NULL;
260 long usec_threshold=USEC;
262 while ((optret=getopt(argc,argv,"hxsi:l:o:c:b:w:"))!=EOF) {
264 case '?': case 'h': case ':':
270 usec_threshold=atoi(optarg);
279 listenport=atoi(optarg);
282 if ((tmpchr=strchr(optarg, ':'))==NULL) {
283 printf("Must specify -c option with host:port\n");
287 connectport=atoi(++tmpchr);
288 connecthost=strdup(optarg);
297 if (strstr(optarg,speed_str[speed])==optarg) {
298 baud=speed_num[speed];
303 fprintf(stderr,"Unsupported Baud: '%s'\n",
311 /* Default settings */
312 if (!dev1 && !listenport) dev1=strdup("/dev/ttyS0");
313 if (!dev2 && !connecthost) dev2=strdup("/dev/ttyS1");
314 if (baud==B0) baud=B19200;
318 port1=openport(dev1, baud);
320 disp_outputstatus("Waiting for connection to TCP port.");
321 port1=listensock(listenport);
325 port2=openport(dev2, baud);
327 disp_outputstatus("Connecting to TCP port.");
328 port2=opensock(connecthost, connectport);
331 if (port1 < 0 || port2 < 0) {
332 fprintf(stderr,"Argh. An open failed!\n");
336 mainloop(port1, port2, silent, show_alpha, usec_threshold);
339 if (dev1) free(dev1);
340 if (dev2) free(dev2);
341 if (connecthost) free(connecthost);