From e99416456afd4aa8bde42016826f9a345291cbf3 Mon Sep 17 00:00:00 2001 From: Matthew Poletiek Date: Tue, 8 Dec 2020 21:03:16 -0600 Subject: Initial Commit --- tools/serialsniff.c | 440 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 440 insertions(+) create mode 100644 tools/serialsniff.c (limited to 'tools/serialsniff.c') diff --git a/tools/serialsniff.c b/tools/serialsniff.c new file mode 100644 index 0000000..7a80ac4 --- /dev/null +++ b/tools/serialsniff.c @@ -0,0 +1,440 @@ +/* + * + * Copyright 2008 Dan Smith + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * + * Modifications made by: + * Stuart Blake Tener, N3GWG + * Email: + * Mobile phone: +1 (310) 358-0202 + * + * 02 MAR 2009 - Version 1.01 + * + * Logic was changed to use "ptsname" instead of "ptsname_r" + * in pursuance of provisioning greater compatibility with other + * Unix variants and Open Standards Unix flavors which have not + * otherwise implemented the "ptsname_r" system call. + * Changes developed and tested under MacOS 10.5.6 (Leopard) + * + * Added "--quiescent" switch, which when used on the command + * line prevents the printing of "Timeout" and count notices + * on the console. + * Changes developed and tested under MacOS 10.5.6 (Leopard) + * + * Added program title and version tagline, printed when the + * software is first started. + * + * 03 MAR 2009 - Version 1.02 + * + * Added "--digits" switch, which when used on the command + * line allows for setting the number of hex digits print per + * line. + * + * Added code to allow "-q" shorthand for "quiescent mode". + * + * Changes were made to add "#ifdef" statements so that only code + * appropriate to MacOS would be compiled if a "#define MACOS" is + * defined early within the source code. + * + * Cleaned up comments in the source for my new source code. + * + * Changes developed and tested under MacOS 10.5.6 (Leopard) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STREQ(a,b) (strcmp(a,b) == 0) + +char *version = "1.02 (03 MAR 2009)"; +int quiescent = 0; +int total_hex = 20; + +struct path { + int fd; + char path[1024]; + char name[1024]; + int rawlog_fd; +}; + +void hexdump(char *buf, int len, FILE *dest) +{ + /* + * In precedence to the modification of this procedure to support the + * variable size hexadecimal output, the total bytes output was fixed + * to be a length of 8. + * + * The amendment of this procedure to support the "total_hex" variable + * allows for the user to pass a command line argument instantiating a + * desired number of hexadecimal bytes (and their ASCII equivelent) to + * be displayed. + * + */ + + int i; + int j; + + for (i = 0; i < len; i += total_hex) { + for (j = i; j < i + total_hex; j++) { + if ((j % 4) == 0) + fprintf(dest, " "); + + if (j < len) + fprintf(dest, "%02x", buf[j] & 0xFF); + else + fprintf(dest, "--"); + } + + fprintf(dest, " "); + + for (j = i; j < i + total_hex; j++) { + if ((j % 4) == 0) + fprintf(dest, " "); + + if (j > len) + fprintf(dest, "."); + else if ((buf[j] > ' ') && (buf[j] < '~')) + fprintf(dest, "%c", buf[j]); + else + fprintf(dest, "."); + } + + fprintf(dest, "\n"); + } +} + +int saferead(int fd, char *buf, int len) +{ + struct itimerval val; + int ret; + int count = 0; + + memset(&val, 0, sizeof(val)); + val.it_value.tv_usec = 50000; + setitimer(ITIMER_REAL, &val, NULL); + + while (count < len) { + getitimer(ITIMER_REAL, &val); + if ((val.it_value.tv_sec == 0) && + (val.it_value.tv_usec == 0)) { + if (!quiescent) + printf("Timeout\n"); + break; + } + + ret = read(fd, &(buf[count]), len - count); + if (ret > 0) + count += ret; + } + + return count; +} + +void proxy(struct path *pathA, struct path *pathB) +{ + fd_set rfds; + int ret; + struct timeval tv; + + while (1) { + int count = 0; + int ret; + char buf[4096]; + + FD_ZERO(&rfds); + + FD_SET(pathA->fd, &rfds); + FD_SET(pathB->fd, &rfds); + + ret = select(30, &rfds, NULL, NULL, NULL); + if (ret == -1) { + perror("select"); + break; + } + + if (FD_ISSET(pathA->fd, &rfds)) { + count = saferead(pathA->fd, buf, sizeof(buf)); + if (count < 0) + break; + + ret = write(pathB->fd, buf, count); + if (ret != count) + printf("Failed to write %i (%i)\n", count, ret); + if (!quiescent) + printf("%s %i:\n", pathA->name, count); + hexdump(buf, count, stdout); + + if (pathA->rawlog_fd >= 0) { + ret = write(pathA->rawlog_fd, buf, count); + if (ret != count) + printf("Failed to write %i to %s log", + count, + pathA->name); + } + + } + + if (FD_ISSET(pathB->fd, &rfds)) { + count = saferead(pathB->fd, buf, sizeof(buf)); + if (count < 0) + break; + + ret = write(pathA->fd, buf, count); + if (ret != count) + printf("Failed to write %i (%i)\n", count, ret); + if (!quiescent) + printf("%s %i:\n", pathB->name, count); + hexdump(buf, count, stdout); + + if (pathB->rawlog_fd >= 0) { + ret = write(pathB->rawlog_fd, buf, count); + if (ret != count) + printf("Failed to write %i to %s log", + count, + pathB->name); + } + } + } +} + +static bool open_pty(struct path *path) +{ +#ifdef MACOS + char *ptsname_path; +#endif + + path->fd = posix_openpt(O_RDWR); + if (path->fd < 0) { + perror("posix_openpt"); + return false; + } + + grantpt(path->fd); + unlockpt(path->fd); + +#ifdef MACOS + ptsname_path = ptsname(path->fd); + strncpy(path->path,ptsname_path,sizeof(path->path) - 1); +#else + ptsname_r(path->fd, path->path, sizeof(path->path)); +#endif + + fprintf(stderr, "%s\n", path->path); + + return true; +} + +static bool open_serial(const char *serpath, struct path *path) +{ + path->fd = open(serpath, O_RDWR); + if (path->fd < 0) + perror(serpath); + + strncpy(path->path, serpath, sizeof(path->path)); + + return path->fd >= 0; +} + +static bool open_socket(const char *foo, struct path *path) +{ + int lfd; + struct sockaddr_in srv; + struct sockaddr_in cli; + unsigned int cli_len = sizeof(cli); + int optval = 1; + + lfd = socket(AF_INET, SOCK_STREAM, 0); + if (lfd < 0) { + perror("socket"); + return false; + } + + srv.sin_family = AF_INET; + srv.sin_port = htons(2000); + srv.sin_addr.s_addr = INADDR_ANY; + + setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + + if (bind(lfd, (struct sockaddr *)&srv, sizeof(srv)) < 0) { + perror("bind"); + return false; + } + + if (listen(lfd, 1) < 0) { + perror("listen"); + return false; + } + + printf("Waiting...\n"); + + path->fd = accept(lfd, (struct sockaddr *)&cli, &cli_len); + if (path->fd < 0) { + perror("accept"); + return false; + } + + printf("Accepted socket client\n"); + + strcpy(path->path, "SOCKET"); + + return true; +} + +static bool open_path(const char *opt, struct path *path) +{ + if (STREQ(opt, "pty")) + return open_pty(path); + else if (STREQ(opt, "listen")) + return open_socket(opt, path); + else + return open_serial(opt, path); +} + +static bool open_log(const char *filename, struct path *path) +{ + path->rawlog_fd = open(filename, O_WRONLY | O_CREAT, 0644); + if (path->rawlog_fd < 0) + perror(filename); + + return path->rawlog_fd >= 0; +} + +static void usage() +{ + printf("Usage:\n" + "serialsniff [OPTIONS]\n" + "Where OPTIONS are:\n" + "\n" + " -A,--pathA=DEV Path to device A (or 'pty')\n" + " -B,--pathB=DEV Path to device B (or 'pty')\n" + " --logA=FILE Log pathA (raw) to FILE\n" + " --logB=FILE Log pathB (raw) to FILE\n" + " --nameA=NAME Set pathA name to NAME\n" + " --nameB=NAME Set pathB name to NAME\n" + " --q,-q,--quiescent Run in quiescent mode\n" + " --d,-d,--digits Number of hex digits to print in one line\n\n" + " --d=nn or -d nn or --digits nn\n" + "\n" + ); +} + +int main(int argc, char **argv) +{ + + struct sigaction sa; + + struct path pathA; + struct path pathB; + + int c; + + strcpy(pathA.name, "A"); + strcpy(pathB.name, "B"); + pathA.fd = pathA.rawlog_fd = -1; + pathB.fd = pathB.rawlog_fd = -1; + + printf("\nserialsniff - Version %s\n\n",version); + + while (1) { + int optind; + static struct option lopts[] = { + {"pathA", 1, 0, 'A'}, + {"pathB", 1, 0, 'B'}, + {"logA", 1, 0, 1 }, + {"logB", 1, 0, 2 }, + {"nameA", 1, 0, 3 }, + {"nameB", 1, 0, 4 }, + {"quiescent", 0, 0, 'q' }, + {"digits", 1, 0, 'd'}, + {0, 0, 0, 0} + }; + + c = getopt_long(argc, argv, "A:B:d:l:q", + lopts, &optind); + if (c == -1) + break; + + switch (c) { + + case 'A': + if (!open_path(optarg, &pathA)) + return 1; + break; + + case 'B': + if (!open_path(optarg, &pathB)) + return 2; + break; + + case 1: + if (!open_log(optarg, &pathA)) + return 3; + break; + + case 2: + if (!open_log(optarg, &pathB)) + return 4; + break; + + case 3: + strncpy(pathA.name, optarg, sizeof(pathA.name)); + break; + + case 4: + strncpy(pathB.name, optarg, sizeof(pathB.name)); + break; + + case 'q': + quiescent = 1; + break; + + case 'd': + total_hex=atoi(optarg); + break; + + case '?': + return 3; + } + } + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_IGN; + sigaction(SIGALRM, &sa, NULL); + + if ((pathA.fd < 0) || (pathB.fd < 0)) { + usage(); + return -1; + } + + proxy(&pathA, &pathB); + + return 0; +} -- cgit v1.2.3