summaryrefslogtreecommitdiff
path: root/Userland/nc.cpp
diff options
context:
space:
mode:
authorConrad Pankoff <deoxxa@fknsrs.biz>2019-08-08 12:25:21 +1000
committerAndreas Kling <awesomekling@gmail.com>2019-08-08 06:47:30 +0200
commitfbcf51f81bd01fbb5174cd88e69da778076a7a12 (patch)
tree6044018da51f5028194cb54b3ae54d53bf4a9714 /Userland/nc.cpp
parent7ed54d86d50e0419f4854e4d331a9acd20493050 (diff)
downloadserenity-fbcf51f81bd01fbb5174cd88e69da778076a7a12.zip
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.
Diffstat (limited to 'Userland/nc.cpp')
-rw-r--r--Userland/nc.cpp126
1 files changed, 126 insertions, 0 deletions
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 <arpa/inet.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define max(a, b) ((a > b) ? a : b)
+
+int main(int argc, char** argv)
+{
+ if (argc < 3) {
+ fprintf(stderr, "Usage: nc <host> <port>\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;
+}