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;