]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: netscaler: add support for standard NetScaler CIP protocol
authorBertrand Jacquin <jacquinb@amazon.com>
Tue, 12 Dec 2017 01:17:23 +0000 (01:17 +0000)
committerWilly Tarreau <w@1wt.eu>
Wed, 20 Dec 2017 06:04:07 +0000 (07:04 +0100)
It looks like two version of the protocol exist as reported by
Andreas Mahnke. This patch add support for both legacy and standard CIP
protocol according to NetScaler specifications.

doc/netscaler-client-ip-insertion-protocol.txt
src/connection.c

index 6f77f6522c7f8d7d193f0c07fed047bbf027f299..559d98a82a92f2381485d741befb9ca5e414e8b9 100644 (file)
@@ -10,7 +10,9 @@ Specifications and documentations from NetScaler:
   https://www.citrix.com/blogs/2016/04/25/how-to-enable-client-ip-in-tcpip-option-of-netscaler/
 
 When CIP is enabled on the NetScaler, then a TCP packet is inserted just after
-the TCP handshake. This is composed as:
+the TCP handshake. Two versions of the CIP extension exist.
+
+Legacy (NetScaler < 10.5)
 
   - CIP magic number : 4 bytes
     Both sender and receiver have to agree on a magic number so that
@@ -27,3 +29,27 @@ the TCP handshake. This is composed as:
   - TCP header : >= 20 bytes
     Contains the header of the last TCP packet sent by the client during TCP
     handshake.
+
+Standard (NetScaler >= 10.5)
+
+  - CIP magic number : 4 bytes
+    Both sender and receiver have to agree on a magic number so that
+    they both handle the incoming data as a NetScaler Client IP insertion
+    packet.
+
+  - CIP length : 4 bytes
+    Defines the total length on the CIP header.
+
+  - CIP type: 2 bytes
+    Always set to 1.
+
+  - Header length : 2 bytes
+    Defines the length on the remaining data.
+
+  - IP header : >= 20 bytes if IPv4, 40 bytes if IPv6
+    Contains the header of the last IP packet sent by the client during TCP
+    handshake.
+
+  - TCP header : >= 20 bytes
+    Contains the header of the last TCP packet sent by the client during TCP
+    handshake.
index 58bf4a5f85f54bbae249fc6e2affd820d31e8324..0f8acb02dbdbc0a70cdd99830f8a0c9256f731e8 100644 (file)
@@ -678,14 +678,8 @@ int conn_recv_proxy(struct connection *conn, int flag)
 }
 
 /* This handshake handler waits a NetScaler Client IP insertion header
- * at the beginning of the raw data stream. The header looks like this:
- *
- *   4 bytes:   CIP magic number
- *   4 bytes:   Header length
- *   20+ bytes: Header of the last IP packet sent by the client during
- *              TCP handshake.
- *   20+ bytes: Header of the last TCP packet sent by the client during
- *              TCP handshake.
+ * at the beginning of the raw data stream. The header format is
+ * described in doc/netscaler-client-ip-insertion-protocol.txt
  *
  * This line MUST be at the beginning of the buffer and MUST NOT be
  * fragmented.
@@ -735,25 +729,39 @@ int conn_recv_netscaler_cip(struct connection *conn, int flag)
        }
 
        /* Fail if buffer length is not large enough to contain
-        * CIP magic, CIP length */
-       if (trash.len < 8)
+        * CIP magic, header length or
+        * CIP magic, CIP length, CIP type, header length */
+       if (trash.len < 12)
                goto missing;
 
        line = trash.str;
-       hdr_len = ntohl(*(uint32_t *)(line+4));
 
        /* Decode a possible NetScaler Client IP request, fail early if
         * it does not match */
        if (ntohl(*(uint32_t *)line) != objt_listener(conn->target)->bind_conf->ns_cip_magic)
                goto bad_magic;
 
+       /* Legacy CIP protocol */
+       if ((trash.str[8] & 0xD0) == 0x40) {
+               hdr_len = ntohl(*(uint32_t *)(line+4));
+               line += 8;
+       }
+       /* Standard CIP protocol */
+       else if (trash.str[8] == 0x00) {
+               hdr_len = ntohs(*(uint32_t *)(line+10));
+               line += 12;
+       }
+       /* Unknown CIP protocol */
+       else {
+               conn->err_code = CO_ER_CIP_BAD_PROTO;
+               goto fail;
+       }
+
        /* Fail if buffer length is not large enough to contain
-        * CIP magic, CIP length, minimal IP header */
-       if (trash.len < 28)
+        * a minimal IP header */
+       if (trash.len < 20)
                goto missing;
 
-       line += 8;
-
        /* Get IP version from the first four bits */
        ip_v = (*line & 0xf0) >> 4;