Home page logo
/

nmap-dev logo Nmap Development mailing list archives

[PATCH] Ncat and windows line endings
From: jah <jah () zadkiel plus com>
Date: Fri, 15 May 2009 01:51:53 +0100

On 09/05/2009 04:42, Fyodor wrote:
First of all, maybe -C should format all bare \n in the buffer to
\r\n.  Is there a good reason (other than ease of implementation) for
only handling bare \n which happens to appear at the end of the
buffer?  Of course it needs to make sure that the \n chars in the
buffer are bare (not preceeded by a \r already).  We don't want to end
up with \r\r\n.

Second, we should probably have an option which does the opposite and
converts \r\n in input to plain \n.  Maybe it could be -N/--newline or
-L/--lf or something.  It should check the whole buffer for \r\n too,
IMHO.

Does anyone have a different idea or should we just implement these
two changes?  Anyone want to write a patch?
Hi folks,

Attached is a patch which adds the -L/--lf option to Ncat.  The option
does the opposite of -C/--crlf and converts any \r\n read from STDIN to
plain \n.
The patch also enforces these options for the whole buffer and not just
the end of it.

The new option means that you can issue commands from a terminal which
uses \r\n for line endings (e.g. windows) to an ncat running on a
terminal which uses \n.  Which means that windows users can start
getting their own back.

I've tested the changes in connect, listen and broker modes and all
looks good.

Regards,

jah
diff -urNb ncat/ncat_broker.c ncat_opt_lf/ncat_broker.c
--- ncat/ncat_broker.c  2009-05-15 01:24:50.765625000 +0100
+++ ncat_opt_lf/ncat_broker.c   2009-05-15 00:30:52.750000000 +0100
@@ -189,12 +189,13 @@
 
 /* Read from recv_fd and broadcast whatever is read to all other descriptors in
    master, with the exception of stdin, listen_socket, and recv_fd itself.
-   Handles CRLF translation and chat mode. On read error or end of stream,
+   Handles EOL translation and chat mode. On read error or end of stream,
    closes the socket and removes it from the master list. */
 static void read_and_broadcast(int recv_fd)
 {
     char buf[DEFAULT_TCP_BUF_LEN];
     char *chatbuf, *outbuf;
+    char *tempbuf = NULL;
     struct fdinfo *fdn = get_fdinfo(&fdlist, recv_fd);
     ssize_t nbytes;
     fd_set fds;
@@ -209,7 +210,7 @@
 #endif
     if (recv_fd == STDIN_FILENO) {
         /* Behavior differs depending on whether this is stdin or a socket. */
-        nbytes = read(recv_fd, buf, sizeof(buf) - o.crlf);
+        nbytes = read(recv_fd, buf, sizeof(buf));
         if (nbytes <= 0) {
             if (nbytes < 0 && o.verbose)
                 logdebug("Error reading from stdin: %s\n", strerror(errno));
@@ -225,11 +226,8 @@
             return;
         }
 
-        /* We gave ourselves extra room in our special-case stdin read above */
-        if (o.crlf && buf[nbytes - 1] == '\n' && buf[nbytes - 2] != '\r') {
-            memcpy(&buf[nbytes - 1], "\r\n", 2);
-            nbytes++;
-        }
+        if (o.crlf || o.lf)
+            fix_line_endings((char *) buf, &nbytes, &tempbuf);
     } else {
         /* From a connected socket, not stdin. */
         nbytes = recv(recv_fd, buf, sizeof(buf), 0);
@@ -270,10 +268,14 @@
         logdebug("Handling data from client %d.\n", recv_fd);
 
     chatbuf = NULL;
+    /* tempbuf is in use if we read from STDIN and fixed EOL */
+    if (tempbuf == NULL)
     outbuf = buf;
+    else
+        outbuf = tempbuf;
 
     if (o.chat) {
-        chatbuf = chat_filter(buf, nbytes, recv_fd, &nbytes);
+        chatbuf = chat_filter(outbuf, nbytes, recv_fd, &nbytes);
         if (chatbuf == NULL) {
             if (o.verbose)
                 logdebug("Error formatting chat message from fd %d\n", recv_fd);
@@ -291,6 +293,8 @@
     broadcast(&fds, &fdlist, outbuf, nbytes);
 
     free(chatbuf);
+    free(tempbuf);
+    tempbuf = NULL;
 
 #ifdef HAVE_OPENSSL
     /* SSL can buffer our input, so doing another select()
diff -urNb ncat/ncat_connect.c ncat_opt_lf/ncat_connect.c
--- ncat/ncat_connect.c 2009-05-15 01:24:50.468750000 +0100
+++ ncat_opt_lf/ncat_connect.c  2009-05-15 00:41:11.531250000 +0100
@@ -341,12 +341,9 @@
                     if (o.recvonly == 0) {
                         char *tmp = NULL;
 
-                        if (o.crlf && buf[nbytes - 1] == '\n' && buf[nbytes - 2] != '\r') {
-                            tmp = (char *) safe_malloc(nbytes + 1);
-                            memcpy(tmp, buf, nbytes - 1);
-                            memcpy(tmp + nbytes - 1, "\r\n", 2);
+                        if (o.crlf || o.lf) {
+                            if (fix_line_endings(buf, &nbytes, &tmp))
                             buf = tmp;
-                            nbytes++;
                         }
 
                         nsock_write(nsp, cs->sock_nsi, connect_evt_handler,
diff -urNb ncat/ncat_core.c ncat_opt_lf/ncat_core.c
--- ncat/ncat_core.c    2009-05-15 01:24:50.781250000 +0100
+++ ncat_opt_lf/ncat_core.c     2009-05-14 15:24:18.156250000 +0100
@@ -50,6 +50,7 @@
     o.hexlogfd = -1;
     o.idletimeout = 0;
     o.crlf = 0;
+    o.lf = 0;
     o.allow = 0;
     o.deny = 0;
     addrset_init(&o.allowset);
diff -urNb ncat/ncat_core.h ncat_opt_lf/ncat_core.h
--- ncat/ncat_core.h    2009-05-15 01:24:50.546875000 +0100
+++ ncat_opt_lf/ncat_core.h     2009-05-14 15:24:18.062500000 +0100
@@ -33,6 +33,7 @@
     int hexlogfd;
     int idletimeout;
     int crlf;
+    int lf;
     /* Were any hosts specifically allowed? If so, deny all others. */
     int allow;
     int deny;
diff -urNb ncat/ncat_listen.c ncat_opt_lf/ncat_listen.c
--- ncat/ncat_listen.c  2009-05-15 01:24:50.562500000 +0100
+++ ncat_opt_lf/ncat_listen.c   2009-05-15 00:42:19.187500000 +0100
@@ -207,9 +207,10 @@
 {
     int nbytes;
     char buf[DEFAULT_TCP_BUF_LEN];
+    char* write_buf;
     fd_set fds;
 
-    nbytes = read(STDIN_FILENO, buf, sizeof(buf) - o.crlf);
+    nbytes = read(STDIN_FILENO, buf, sizeof(buf));
     if (nbytes <= 0) {
         if (nbytes < 0 && o.verbose)
             logdebug("Error reading from stdin: %s\n", strerror(errno));
@@ -225,10 +226,11 @@
         return;
     }
 
-    /* We gave ourselves extra room in our special-case stdin read above */
-    if (o.crlf && buf[nbytes - 1] == '\n' && buf[nbytes - 2] != '\r') {
-        memcpy(&buf[nbytes - 1], "\r\n", 2);
-        nbytes++;
+    if (o.crlf || o.lf) {
+        if (!fix_line_endings((char *) buf, &nbytes, &write_buf)) {
+            write_buf = (char *) safe_malloc(sizeof(buf));
+            memcpy(write_buf, &buf, sizeof(buf));
+        }
     }
 
     if(o.linedelay)
@@ -239,7 +241,9 @@
     fds = master;
     FD_CLR(STDIN_FILENO, &fds);
     FD_CLR(listen_socket, &fds);
-    broadcast(&fds, &fdlist, buf, nbytes);
+    broadcast(&fds, &fdlist, write_buf, nbytes);
+    if (write_buf)
+        free(write_buf);
 }
 
 /* Read from a client socket and write to stdout. */
diff -urNb ncat/ncat_main.c ncat_opt_lf/ncat_main.c
--- ncat/ncat_main.c    2009-05-15 01:24:50.687500000 +0100
+++ ncat_opt_lf/ncat_main.c     2009-05-14 22:32:05.531250000 +0100
@@ -144,6 +144,7 @@
     struct option long_options[] = {
         {"4",               no_argument,        NULL,         '4'},
         {"6",               no_argument,        NULL,         '6'},
+        {"lf",              no_argument,        NULL,         'L'},
         {"crlf",            no_argument,        NULL,         'C'},
         {"g",               required_argument,  NULL,         'g'},
         {"G",               required_argument,  NULL,         'G'},
@@ -193,7 +194,7 @@
     while (1) {
         /* handle command line arguments */
         int option_index;
-        int c = getopt_long(argc, argv, "46Cc:e:g:G:i:m:hp:d:lo:x:ts:uvw:n",
+        int c = getopt_long(argc, argv, "46CLc:e:g:G:i:m:hp:d:lo:x:ts:uvw:n",
                             long_options, &option_index);
 
         /* That's the end of the options. */
@@ -211,8 +212,11 @@
             bye("-6 chosen when IPv6 wasn't compiled in.");
 #endif
             break;
+        case 'L':
+            o.lf = 1;
+            break;
         case 'C':
-            o.crlf = 1; /* not an arbitrary number */
+            o.crlf = 1;
             break;
         case 'c':
             o.shellexec = 1;
@@ -371,6 +375,7 @@
             printf("(seconds), 'm' (minutes), or 'h' (hours) to the value (e.g. 30s)\n");
             printf("  -4                         Use IPv4 only\n");
             printf("  -6                         Use IPv6 only\n");
+            printf("  -L, --lf                   Use LF for EOL sequence\n");
             printf("  -C, --crlf                 Use CRLF for EOL sequence\n");
 #ifndef WIN32
             printf("  -c, --sh-exec <command>    Executes specified command via /bin/sh\n");
@@ -431,6 +436,9 @@
     targetss.ss_family = AF_UNSPEC;
     httpconnect = socksconnect = srcaddr = targetss;
 
+    if (o.lf && o.crlf)
+        bye("Invalid option combination: `-C' (--crlf) and `-L' (--lf).");
+    
     if (proxyaddr) {
       if (!o.proxytype)
           o.proxytype = Strdup("http");
diff -urNb ncat/util.c ncat_opt_lf/util.c
--- ncat/util.c 2009-05-15 01:24:50.640625000 +0100
+++ ncat_opt_lf/util.c  2009-05-15 01:37:48.921875000 +0100
@@ -442,3 +442,75 @@
     fdl->nfds = 0;
     fdl->fdmax = -1;
 }
+
+
+/*  If any changes need to be made to EOL sequences to comply with --crlf and
+ *  --lf then dst will be populated with the modified src, len will be
+ *  adjusted accordingly and the return will be non-zero.
+ *  Returns 0 if changes were not made and len and dst will remain untouched.
+ */
+int fix_line_endings(char *src, int *len, char **dst)
+{
+    char *tmp = NULL;
+    int fix_count;
+    int i,j;
+    int num_bytes = *len;
+
+    /* insert required carriage returns */
+    if (o.crlf)
+    {
+        /* get count of \n without matching \r */
+        fix_count = 0;
+        for (i = 0; i < num_bytes; i++) {
+            if (src[i] == '\n' && (i == 0 || src[i-1] != '\r'))
+                fix_count++;
+        }
+        if (fix_count <= 0 ) return 0;
+
+        /* now insert matching \r */
+               *dst = (char *) safe_malloc(num_bytes + fix_count);
+               j=0;
+
+               for (i = 0; i < num_bytes; i++) {
+                       if (src[i] == '\n' && (i == 0 || src[i-1] != '\r')) {
+                               memcpy(*dst+j, "\r\n", 2);
+                               j += 2;
+                       } else {
+                               memcpy(*dst+j, src+i, 1);
+                               j++;
+                       }
+               }
+               *len += fix_count;
+               return 1;
+    }
+
+    /* strip carriage returns from crlf sequence */
+    else if (o.lf)
+    {
+        /* get count of \r with matching \n */
+        fix_count = 0;
+        for (i = 0; i < num_bytes; i++) {
+            if (src[i] == '\r' && i < num_bytes-1 && src[i+1] == '\n')
+                fix_count++;
+        }
+        if (fix_count <= 0 ) return 0;
+
+               /* now remove matching \r */
+               *dst = (char *) safe_malloc(num_bytes - fix_count);
+               j=0;
+
+               for (i = 0; i < num_bytes; i++) {
+                       if (src[i] == '\r' && i < num_bytes-1 && src[i+1] == '\n') {
+                           /* not copying this '\r' */
+                       }
+                       else {
+                               memcpy(*dst+j, src+i, 1);
+                               j++;
+                       }
+               }
+               *len -= fix_count;
+               return 1;
+    }
+
+    return 0;
+}
diff -urNb ncat/util.h ncat_opt_lf/util.h
--- ncat/util.h 2009-05-15 01:24:50.671875000 +0100
+++ ncat_opt_lf/util.h  2009-05-15 01:37:32.171875000 +0100
@@ -85,3 +85,5 @@
 struct fdinfo *get_fdinfo(const fd_list_t *, int);
 
 #endif
+
+int fix_line_endings(char *src, int *len, char **dst);

_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://SecLists.Org

  By Date           By Thread  

Current thread:
[ Nmap | Sec Tools | Mailing Lists | Site News | About/Contact | Advertising | Privacy ]