LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Networking (https://www.linuxquestions.org/questions/linux-networking-3/)
-   -   Making a serial snooper with a linux box? (https://www.linuxquestions.org/questions/linux-networking-3/making-a-serial-snooper-with-a-linux-box-831431/)

Daravon 09-10-2010 01:31 PM

Making a serial snooper with a linux box?
 
I have some industrial equipment I'm trying to reverse-engineer. It communicates from the main CPU to a controller via a serial connection. I want to hook into the serial connection and dump everything doing down that line to log file so that I can stare at the messages and try to figure out the protocol.

I could just plug the serial cable into my computer but I need the messages to continue going to the controller or else the rest of the system will error. So basically I need to tap into it.

My first thought is to use a laptop with two USB-Serial adapters. I could use a perl script to open both serial connections as files and send everything that comes in the one serial connection right back out the other serial connection, but also dump it to a log file. Will this even work? I can see that it will introduce some latency but I don't think that will be critical.

MS3FGX 09-10-2010 02:29 PM

The traditional method for this sort of thing is to make a serial sniffer cable, which is simply a serial cable that has third connector attached which allows another device to monitor the connection.

A quick search online seems to show these devices are not easily purchasable in the 21st century (not much of a surprise there), but building one doesn't really require any electronics skills. I suppose your idea with dual USB-to-serial adapters would probably work, but it would be more complicated and expensive than simply doing it the accepted way.

estabroo 09-10-2010 06:20 PM

Your method will work fine. I did the exact same thing, though I used C instead of perl and the computer actually had two serial ports, this was back in early 2000s when serial ports still existed. I might have the program laying around somewhere if you want it.

Daravon 09-11-2010 12:40 PM

If you can find the program, I would like it. I'm not a very good programmer and just seeing how you did it would be a big confidence booster.

TB0ne 09-11-2010 01:11 PM

Quote:

Originally Posted by Daravon (Post 4094520)
If you can find the program, I would like it. I'm not a very good programmer and just seeing how you did it would be a big confidence booster.

Don't even necessarily need a 'real' program to do it.

You could just run minicom, go into the menu, and hit "L", to capture the entire session to a file, then examine it later. You could probably also use "tail -f /dev/ttyXXXX > output.log", which MIGHT work too. Minicom is essentially a Linux version of the old ProCOMM program, and similar to Windows Hyperterm. If all you're looking for is just capturing serial data, that should do it.

estabroo 09-11-2010 10:53 PM

Code:

/*
 * siso
 * like a breakout box for serial connections
 * put the computer running siso in the data
 * flow of a serial connection
 * PC -> serial -> PC(siso) -> serial -> device
 *
 * selectable items are
 * -b baud_rate
 * -f logfile
 * -i input_serial_device
 * -o output_serial_device
 *
 * default connection is
 * 9600 8N1 ttyS0 to ttyS1
 *
 */

/* this is for snprintf (under debian) */
#define _ISOC99_SOURCE 1
#define _POSIX_SOURCE  1

#include <stdio.h>
#include <termios.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/poll.h>
#include <fcntl.h>
#include <unistd.h>
#include <getopt.h>
#include <syslog.h>

#define DEFAULT_SERIAL_IN_PORT "/dev/ttyS0"
#define DEFAULT_SERIAL_OUT_PORT "/dev/ttyS1"

int
set_baud(char* baud_s) {
  int b;
  int baud;

  b = atoi(baud_s);
  switch (b) {
  case 300 : baud = B300; break;
  case 1200 : baud = B1200; break;
  case 2400 : baud = B2400; break;
  case 9600 : baud = B9600; break;
  case 19200 : baud = B19200; break;
  case 38400 : baud = B38400; break;
  case 57600 : baud = B57600; break;
  case 115200 : baud = B115200; break;
  default : baud = 0;
  };
  return baud;
}

int main (int argc, char* argv[]) {
  int            err;
  int            fdi;
  int            fdo;
  int            fdl;
  int            opt;
  int            n;
  int            baud;
  char          buf[8];
  char          log[1024];
  char          s_in[128];
  char          s_out[128];
  char          buffer[2048];
  struct pollfd  poll_fd[2];
  struct termios info;

  openlog("SiSo", LOG_PID, LOG_USER);

  /* setup defaults */
  baud = B9600;
  snprintf(s_in, sizeof(s_in), "%s", DEFAULT_SERIAL_IN_PORT);
  snprintf(s_out, sizeof(s_out), "%s", DEFAULT_SERIAL_OUT_PORT);
  for(opt=getopt(argc, argv, "f:i:o:b:"); opt != -1;
      opt=getopt(argc, argv, "f:i:o:b:")) {
    switch (opt) {
    case 'b' : { /* set baud rate */
      n = snprintf(buf, sizeof(buf), "%s", optarg);
      if (n < 0 || n > sizeof(buf)) {
        syslog(LOG_ERR, "couldn't convert -b option into a baud rate");
        return n;
      }
      baud = set_baud(buf);
      if (baud == 0) {
        syslog(LOG_ERR, "baud rate [%s] not supported", buf);
        return 0;
      }
    }; break;
    case 'f' : { /* output file */
      n = snprintf(log, sizeof(log), "%s", optarg);
      if (n < 0 || n > sizeof(log)) {
        syslog(LOG_ERR, "output filename truncated, longer than %d bytes", sizeof(log));
        closelog();
        return n;
      }
    }; break;
    case 'i' : { /* serial input device */
      n = snprintf(s_in, sizeof(s_in), "%s", optarg);
      if (n < 0 || n > sizeof(s_in)) {
        syslog(LOG_ERR, "output filename truncated, longer than %d bytes",
              sizeof(s_in));
        closelog();
        return n;
      }
    }; break;
    case 'o' : { /* serial output device */
      n = snprintf(s_in, sizeof(s_out), "%s", optarg);
      if (n < 0 || n > sizeof(s_out)) {
        syslog(LOG_ERR, "output filename truncated, longer than %d bytes",
              sizeof(s_out));
        closelog();
        return n;
      }
    }; break;
    }; /* end switch */
  } /* end for */
  fdi = open (s_in, O_RDWR);
  if (fdi < 0) {
    syslog(LOG_ERR, "couldn't open %s : %m", s_in);
    exit(0);
  }
  fdo = open (s_out, O_RDWR);
  if (fdo < 0) {
    syslog(LOG_ERR, "couldn't open %s : %m", s_out);
    exit(0);
  }
  fdl = open(log, O_RDWR|O_CREAT);
  if (fdl < 0) {
    syslog(LOG_ERR, "couldn't open %s : %m", log);
    exit(0);
  }
 
  /* set up modem connection */
  err = tcgetattr(fdi, &info);
  info.c_cflag = (CS8 | CREAD) & ~PARENB; /* 8N1 */
  info.c_iflag |= IXON | IXOFF;
  info.c_lflag &= ~ICANON & ~ISIG;
  err = cfsetospeed(&info, baud);
  err = cfsetispeed(&info, baud);
  err = tcsetattr(fdi, TCSANOW, &info);

  /* set up serial connection */
  err = tcgetattr(fdo, &info);
  info.c_cflag = (CS8 | CREAD) & ~PARENB; /* 8N1 */
  info.c_iflag |= IXON | IXOFF;
  info.c_lflag &= ~ICANON & ~ISIG;
  err = cfsetospeed(&info, baud);
  err = cfsetispeed(&info, baud);
  err = tcsetattr(fdo, TCSANOW, &info);

  /* set up poll structure */
  poll_fd[0].fd = fdi;
  poll_fd[1].fd = fdo;
  poll_fd[0].events = POLLIN;
  poll_fd[1].events = POLLIN;
  poll_fd[0].revents = 0;
  poll_fd[1].revents = 0;

  /* main loop */
  while (1) {
    n = poll(poll_fd, 2, -1); /* wait here */
    if (n < 0) {
      break;
    }
    if (poll_fd[0].revents & POLLIN) {
      n = read(poll_fd[0].fd, buffer, sizeof(buffer));
      if (n > 0) {
        write(poll_fd[1].fd, buffer, n);
        write(fdl, buffer, n);
      }
      poll_fd[0].revents = 0;
    }
    if (poll_fd[1].revents & POLLIN) {
      n = read(poll_fd[1].fd, buffer, sizeof(buffer));
      if (n > 0) {
        write(poll_fd[0].fd, buffer, n);
        write(fdl, buffer, n);
      }
      poll_fd[1].revents = 0;
    }
  }
  close(fdl);
  close(fdi);
  close(fdo);
  exit(0);
}


Daravon 09-13-2010 10:51 AM

Quote:

Don't even necessarily need a 'real' program to do it.

You could just run minicom, go into the menu, and hit "L", to capture the entire session to a file, then examine it later.
If I use two serial ports, though, I need something to send the commands back out the second serial port so the equipment keeps running. That's why I'm liking the idea of making a y-cable. Then it seems easier.

MS3FGX 09-13-2010 11:11 AM

TB0ne's post seems to be written with the assumption that you are using the serial sniffer cable, or you are directly connected to the device you want to monitor. In either event, it assumes you are able to capture the serial data but not forward it along to the destination device.

If you don't have the physical sniffer cable and want to go the route with two serial adapters, then the script posted by estabroo is what you want.

TB0ne 09-13-2010 11:35 AM

Quote:

Originally Posted by MS3FGX (Post 4096170)
TB0ne's post seems to be written with the assumption that you are using the serial sniffer cable, or you are directly connected to the device you want to monitor. In either event, it assumes you are able to capture the serial data but not forward it along to the destination device.

If you don't have the physical sniffer cable and want to go the route with two serial adapters, then the script posted by estabroo is what you want.

I agree Estabroo's program is a nice piece of work. But you don't NEED a "Y" cable.

Just a tap from the TX and RX lines, going into a port. The data flows along the one cable, between computer and device, as it always does. You've just got a 'vampire tap' on the transmit/receive, shoveling that data into minicom, or whatever. The DSR/DTR/etc., lines aren't needed.

MS3FGX 09-13-2010 03:49 PM

Which is what I linked to in my first post: http://www.lammertbies.nl/comm/cable...y-monitor.html

Just RX, TX, and ground are broken off into another port.

TB0ne 09-13-2010 04:14 PM

Quote:

Originally Posted by MS3FGX (Post 4096415)
Which is what I linked to in my first post: http://www.lammertbies.nl/comm/cable...y-monitor.html

Just RX, TX, and ground are broken off into another port.

Nice..honestly, I didn't see that link in your first post, till you pointed it out.

However...I'm old school....I've made about a zillion serial cables in my life, and it would never occur to me to actually BUY one. :)

Daravon 09-13-2010 04:41 PM

Quote:

Just a tap from the TX and RX lines, going into a port. The data flows along the one cable, between computer and device, as it always does. You've just got a 'vampire tap' on the transmit/receive, shoveling that data into minicom, or whatever. The DSR/DTR/etc., lines aren't needed.
The given link (http://www.lammertbies.nl/comm/cable...y-monitor.html) says that it's a bit more complicated than that. They have a resistor and a diode involved, and just from reading the text, I'm not entirely sure why you can't just tap pins 2, 3, and 5 directly off and wire them to another plug.

TB0ne 09-13-2010 09:02 PM

Quote:

Originally Posted by Daravon (Post 4096452)
The given link (http://www.lammertbies.nl/comm/cable...y-monitor.html) says that it's a bit more complicated than that. They have a resistor and a diode involved, and just from reading the text, I'm not entirely sure why you can't just tap pins 2, 3, and 5 directly off and wire them to another plug.

I think you can, at least I used to back in the olden days....you kids today, with your fancy network doohickys...:)

It's been a long time, though, and there may be some particulars I didn't have to deal with back then, like USB voltages, sensitivity of the ports, etc. Could be merit to it, but I don't THINK (your mileage may vary), it would hurt to try

michaelk 09-13-2010 09:38 PM

In the half duplex cable both TX lines from the device and the computer need to be combined together and used as the RX input to the sniffer. The TX from the sniffer is obviously not used. The diode basically isolates the to TXs form each other.

As stated if both computer and device communicate at the same time the half duplex cable does not work.

Daravon 09-14-2010 10:24 AM

1 Attachment(s)
http://www.lammertbies.nl/comm/cable/RS-232-spy-monitor.html


In my hardware, the device connects to the computer through a null-modem cable. I'm not sure if the snooper cable shown above is designed as a drop-in replacement for a null-modem cable, or if I will need to use a null-modem adapter after it.

I'm having conceptual failure because I'm not sure whether pins 2D and 3D are Rx and Tx respectively, or the other way around.

In either case, I have some problems with the design of the cable.
The attached diagrams explain my current confusion.

In Possibility #2, it the cable would cause all transmitted commands to be echo'd back to the local Rx pin as well as the target Rx pin, and I don't understand why R1 is needed. It just sits in the way of the transmissions.

In Possibility #1, I don't see any problems except I don't understand why R1 isn't just another diode. It would make perfect sense to me if R1 was another diode.


All times are GMT -5. The time now is 01:07 PM.