From 72fa1ec24e96d37c66126918e3ce129da762803a Mon Sep 17 00:00:00 2001 From: Bertrand Jacquin Date: Tue, 12 Dec 2017 01:17:23 +0000 Subject: [PATCH] MEDIUM: netscaler: add support for standard NetScaler CIP protocol 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. --- ...netscaler-client-ip-insertion-protocol.txt | 28 ++++++++++++- src/connection.c | 40 +++++++++++-------- 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/doc/netscaler-client-ip-insertion-protocol.txt b/doc/netscaler-client-ip-insertion-protocol.txt index 6f77f6522c..559d98a82a 100644 --- a/doc/netscaler-client-ip-insertion-protocol.txt +++ b/doc/netscaler-client-ip-insertion-protocol.txt @@ -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. diff --git a/src/connection.c b/src/connection.c index 58bf4a5f85..0f8acb02db 100644 --- a/src/connection.c +++ b/src/connection.c @@ -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,24 +729,38 @@ 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; - /* Fail if buffer length is not large enough to contain - * CIP magic, CIP length, minimal IP header */ - if (trash.len < 28) - goto missing; + /* 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; + } - line += 8; + /* Fail if buffer length is not large enough to contain + * a minimal IP header */ + if (trash.len < 20) + goto missing; /* Get IP version from the first four bits */ ip_v = (*line & 0xf0) >> 4;