Index: docs/nmap.usage.txt
===================================================================
--- docs/nmap.usage.txt	(revision 32886)
+++ docs/nmap.usage.txt	(working copy)
@@ -75,6 +75,8 @@
   -e <iface>: Use specified interface
   -g/--source-port <portnum>: Use given port number
   --proxies <url1,[url2],...>: Relay connections through HTTP/SOCKS4 proxies
+  --data <hex string>: Append a custom payload to sent packets
+  --data-string <string>: Append a custom ASCII string to sent packets
   --data-length <num>: Append random data to sent packets
   --ip-options <options>: Send packets with specified ip options
   --ttl <val>: Set IP time-to-live field
Index: nmap.cc
===================================================================
--- nmap.cc	(revision 32886)
+++ nmap.cc	(working copy)
@@ -302,6 +302,8 @@
          "  -e <iface>: Use specified interface\n"
          "  -g/--source-port <portnum>: Use given port number\n"
          "  --proxies <url1,[url2],...>: Relay connections through HTTP/SOCKS4 proxies\n"
+         "  --data <hex string>: Append a custom payload to sent packets\n"
+         "  --data-string <string>: Append a custom ASCII string to sent packets\n"
          "  --data-length <num>: Append random data to sent packets\n"
          "  --ip-options <options>: Send packets with specified ip options\n"
          "  --ttl <val>: Set IP time-to-live field\n"
@@ -582,6 +584,9 @@
     {"packet-trace", no_argument, 0, 0}, /* Display all packets sent/rcv */
     {"version_trace", no_argument, 0, 0}, /* Display -sV related activity */
     {"version-trace", no_argument, 0, 0}, /* Display -sV related activity */
+    {"data", required_argument, 0, 0},
+    {"data_string", required_argument, 0, 0},
+    {"data-string", required_argument, 0, 0},
     {"data_length", required_argument, 0, 0},
     {"data-length", required_argument, 0, 0},
     {"send_eth", no_argument, 0, 0},
@@ -816,7 +821,32 @@
         } else if (optcmp(long_options[option_index].name, "version-trace") == 0) {
           o.setVersionTrace(true);
           o.debugging++;
+        } else if (optcmp(long_options[option_index].name, "data") == 0) {
+          if (o.extra_payload)
+            fatal("Can't use the --data option(s) multiple times, or together.");
+          u8 *tempbuff=NULL;
+          size_t len=0;
+          if( (tempbuff=parse_hex_string(optarg, &len))==NULL)
+            fatal("Invalid hex string specified");
+          else {
+            o.extra_payload_length = len;
+            o.extra_payload = (char *) safe_malloc(o.extra_payload_length);
+            memcpy(o.extra_payload, tempbuff, len);
+          }
+          if (o.extra_payload_length > 1400) /* 1500 - IP with opts - TCP with opts. */
+            error("WARNING: Payloads bigger than 1400 bytes may not be sent successfully.");
+        } else if (optcmp(long_options[option_index].name, "data-string") == 0) {
+          if (o.extra_payload)
+            fatal("Can't use the --data option(s) multiple times, or together.");
+          o.extra_payload_length = strlen(optarg);
+          if (o.extra_payload_length < 0 || o.extra_payload_length > MAX_PAYLOAD_ALLOWED)
+            fatal("string length must be between 0 and %d", MAX_PAYLOAD_ALLOWED);
+          if (o.extra_payload_length > 1400) /* 1500 - IP with opts - TCP with opts. */
+            error("WARNING: Payloads bigger than 1400 bytes may not be sent successfully.");
+          o.extra_payload = strdup(optarg);
         } else if (optcmp(long_options[option_index].name, "data-length") == 0) {
+          if (o.extra_payload)
+            fatal("Can't use the --data option(s) multiple times, or together.");
           o.extra_payload_length = (int)strtol(optarg, NULL, 10);
           if (o.extra_payload_length < 0 || o.extra_payload_length > MAX_PAYLOAD_ALLOWED)
             fatal("data-length must be between 0 and %d", MAX_PAYLOAD_ALLOWED);
Index: utils.cc
===================================================================
--- utils.cc	(revision 32886)
+++ utils.cc	(working copy)
@@ -495,6 +495,77 @@
     bp += Snprintf(buf + bp, buflen - bp, "\n");
 }
 
+/** Returns a buffer that contains the binary equivalent to the supplied
+ *  hex spec or NULL in case of error.
+ *  @warning Returned pointer points to a static buffer that subsequent calls
+ *  will overwrite. */
+u8 *parse_hex_string(char *str, size_t *outlen) {
+  char auxbuff[4096];
+  static u8 dst[16384];
+  size_t dstlen=16384;
+  unsigned int i=0, j=0;
+  char *start=NULL;
+
+  if(str==NULL || outlen==NULL)
+    return NULL;
+  /* This catches the empty string possibility "" */
+  if(strlen(str) == 0)
+    return NULL;
+  else
+    memset(auxbuff,0,4096);
+
+  /* String should be treated as a hex number in this format: 0xAABBCCDDEE...
+   * We process it the way it is specified, we don't perform byte order
+   * conversions so if the users says 0x00AA we write dst[0]=0x00, dst[1]==0xAA
+   * no matter the endianness of the host system. */
+  if( !strncmp("0x", str, 2) ) {
+    /* This catches the case of an empty "0x" */
+    if(strlen(str) == 2)
+      return NULL;
+    start=str+2;
+  }
+  /* String should be treated as list of hex char in this format: \x00\xFF\x0A*/
+  else if( !strncmp("\\x", str, 2) ) {
+    /* This catches the case of an empty "\x" */
+    if(strlen(str) == 2)
+      return NULL;
+    /* Copy all interesting bytes to an aux array, discard "\x" */
+    for(i=0; i<strlen(str) && j<4095; i++) {
+      if( str[i]!='\\' && str[i]!='x' && str[i]!='X')
+        auxbuff[j++]=str[i];
+    }
+    auxbuff[j]='\0'; /* NULL terminate the string */
+    start=auxbuff;
+  }
+  /* It must be a hex number in this format: AABBCCDDEE (without 0x or \x) */
+  else {
+    start=str;
+  }
+
+  /*OK, here we should have "start" pointing to the beginning of a string
+   * in the format AABBCCDDEE... */
+  /* Check if all we've got are hex chars */
+  for(i=0; i<strlen(start); i++) {
+    if( !isxdigit(start[i]) )
+      return NULL;
+  }
+  /* Check if we have an even number of hex chars */
+  if( strlen(start)%2 != 0 )
+    return NULL;
+
+  /* We are ready to parse this string */
+  for(i=0, j=0; j<dstlen && i<strlen(start)-1; i+=2) {
+    char twobytes[3];
+    twobytes[0]=start[i];
+    twobytes[1]=start[i+1];
+    twobytes[2]='\0';
+    dst[j++]=(u8)strtol(twobytes, NULL, 16);
+  }
+  /* Store final length */
+  *outlen=j;
+  return dst;
+}
+
 /* Get the CPE part (first component of the URL, should be "a", "h", or "o") as
    a character: 'a', 'h', or 'o'. Returns -1 on error. */
 int cpe_get_part(const char *cpe) {
Index: utils.h
===================================================================
--- utils.h	(revision 32886)
+++ utils.h	(working copy)
@@ -214,6 +214,8 @@
 
 void bintohexstr(char *buf, int buflen, char *src, int srclen);
 
+u8 *parse_hex_string(char *str, size_t *outlen);
+
 #ifndef HAVE_STRERROR
 char *strerror(int errnum);
 #endif
