From fbcf51f81bd01fbb5174cd88e69da778076a7a12 Mon Sep 17 00:00:00 2001 From: Conrad Pankoff Date: Thu, 8 Aug 2019 12:25:21 +1000 Subject: Userland: Implement nc command This is a very simple version of the nc (netcat) command. It only supports outgoing TCP connections, and has no options aside from the target host and port. --- Userland/nc.cpp | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 Userland/nc.cpp (limited to 'Userland') diff --git a/Userland/nc.cpp b/Userland/nc.cpp new file mode 100644 index 0000000000..cb597a2811 --- /dev/null +++ b/Userland/nc.cpp @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define max(a, b) ((a > b) ? a : b) + +int main(int argc, char** argv) +{ + if (argc < 3) { + fprintf(stderr, "Usage: nc \n"); + return -1; + } + + const char* addr_str = argv[1]; + int port = atoi(argv[2]); + + int fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + perror("socket"); + return 1; + } + + struct timeval timeout { + 3, 0 + }; + int rc = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + if (rc < 0) { + perror("setsockopt"); + return 1; + } + rc = setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); + if (rc < 0) { + perror("setsockopt"); + return 1; + } + + struct sockaddr_in dst_addr; + memset(&dst_addr, 0, sizeof(dst_addr)); + + dst_addr.sin_family = AF_INET; + dst_addr.sin_port = htons(port); + rc = inet_pton(AF_INET, addr_str, &dst_addr.sin_addr); + if (rc <= 0) { + perror("inet_pton"); + return 1; + } + + rc = connect(fd, (struct sockaddr*)&dst_addr, sizeof(dst_addr)); + if (rc < 0) { + perror("connect"); + return 1; + } + + fd_set readfds, writefds, exceptfds; + + for (;;) { + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&exceptfds); + + int highest_fd = 0; + + FD_SET(STDIN_FILENO, &readfds); + FD_SET(STDIN_FILENO, &exceptfds); + highest_fd = max(highest_fd, STDIN_FILENO); + FD_SET(fd, &readfds); + FD_SET(fd, &exceptfds); + highest_fd = max(highest_fd, fd); + + int ready = select(highest_fd + 1, &readfds, &writefds, &exceptfds, NULL); + if (ready == -1) { + if (errno == EINTR) + continue; + + perror("select"); + return 1; + } + + if (FD_ISSET(STDIN_FILENO, &readfds)) { + char buf[1024]; + int nread = read(STDIN_FILENO, buf, sizeof(buf)); + if (nread < 0) { + perror("read(STDIN_FILENO)"); + return 1; + } + + // stdin closed + if (nread == 0) { + return 0; + } + + if (write(fd, buf, nread) < 0) { + perror("write(fd)"); + return 1; + } + } + + if (FD_ISSET(fd, &readfds)) { + char buf[1024]; + int nread = read(fd, buf, sizeof(buf)); + if (nread < 0) { + perror("read(fd)"); + return 1; + } + + // remote end closed + if (nread == 0) { + return 0; + } + + if (write(STDOUT_FILENO, buf, nread) < 0) { + perror("write(STDOUT_FILENO)"); + return 1; + } + } + } + + return 0; +} -- cgit v1.2.3