return 1;
}
+/* Return the version of the SSL protocol in the request. It supports both
+ * SSLv3 (TLSv1) header format for any message, and SSLv2 header format for
+ * the hello message. The SSLv3 format is described in RFC 2246 p49, and the
+ * SSLv2 format is described here, and completed p67 of RFC 2246 :
+ * http://wp.netscape.com/eng/security/SSL_2.html
+ *
+ * Note: this decoder only works with non-wrapping data.
+ */
+static int
+acl_fetch_req_ssl_ver(struct proxy *px, struct session *l4, void *l7, int dir,
+ struct acl_expr *expr, struct acl_test *test)
+{
+ int version, bleft, msg_len;
+ const unsigned char *data;
+
+ if (!l4 || !l4->req)
+ return 0;
+
+ msg_len = 0;
+ bleft = l4->req->l;
+ if (!bleft)
+ goto too_short;
+
+ data = l4->req->w;
+ if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
+ /* SSLv3 header format */
+ if (bleft < 5)
+ goto too_short;
+
+ version = (data[1] << 16) + data[2]; /* version: major, minor */
+ msg_len = (data[3] << 8) + data[4]; /* record length */
+
+ /* format introduced with SSLv3 */
+ if (version < 0x00030000)
+ goto not_ssl;
+
+ /* message length between 1 and 2^14 + 2048 */
+ if (msg_len < 1 || msg_len > ((1<<14) + 2048))
+ goto not_ssl;
+
+ bleft -= 5; data += 5;
+ } else {
+ /* SSLv2 header format, only supported for hello (msg type 1) */
+ int rlen, plen, cilen, silen, chlen;
+
+ if (*data & 0x80) {
+ if (bleft < 3)
+ goto too_short;
+ /* short header format : 15 bits for length */
+ rlen = ((data[0] & 0x7F) << 8) | data[1];
+ plen = 0;
+ bleft -= 2; data += 2;
+ } else {
+ if (bleft < 4)
+ goto too_short;
+ /* long header format : 14 bits for length + pad length */
+ rlen = ((data[0] & 0x3F) << 8) | data[1];
+ plen = data[2];
+ bleft -= 3; data += 2;
+ }
+
+ if (*data != 0x01)
+ goto not_ssl;
+ bleft--; data++;
+
+ if (bleft < 8)
+ goto too_short;
+ version = (data[0] << 16) + data[1]; /* version: major, minor */
+ cilen = (data[2] << 8) + data[3]; /* cipher len, multiple of 3 */
+ silen = (data[4] << 8) + data[5]; /* session_id_len: 0 or 16 */
+ chlen = (data[6] << 8) + data[7]; /* 16<=challenge length<=32 */
+
+ bleft -= 8; data += 8;
+ if (cilen % 3 != 0)
+ goto not_ssl;
+ if (silen && silen != 16)
+ goto not_ssl;
+ if (chlen < 16 || chlen > 32)
+ goto not_ssl;
+ if (rlen != 9 + cilen + silen + chlen)
+ goto not_ssl;
+
+ /* focus on the remaining data length */
+ msg_len = cilen + silen + chlen + plen;
+ }
+ /* We could recursively check that the buffer ends exactly on an SSL
+ * fragment boundary and that a possible next segment is still SSL,
+ * but that's a bit pointless. However, we could still check that
+ * all the part of the request which fits in a buffer is already
+ * there.
+ */
+ if (msg_len > l4->req->rlim - l4->req->w)
+ msg_len = l4->req->rlim - l4->req->w;
+
+ if (bleft < msg_len)
+ goto too_short;
+
+ /* OK that's enough. We have at least the whole message, and we have
+ * the protocol version.
+ */
+ test->i = version;
+ test->flags = ACL_TEST_F_VOLATILE;
+ return 1;
+
+ too_short:
+ test->flags = ACL_TEST_F_MAY_CHANGE;
+ not_ssl:
+ return 0;
+}
+
static struct cfg_kw_list cfg_kws = {{ },{
{ CFG_LISTEN, "tcp-request", tcp_parse_tcp_req },
}};
static struct acl_kw_list acl_kws = {{ },{
- { "req_len", acl_parse_int, acl_fetch_req_len, acl_match_int },
+ { "req_len", acl_parse_int, acl_fetch_req_len, acl_match_int },
+ { "req_ssl_ver", acl_parse_dotted_ver, acl_fetch_req_ssl_ver, acl_match_int },
{ NULL, NULL, NULL, NULL },
}};
--- /dev/null
+# This is a test configuration. It listens on port 8443, waits for an incoming
+# connection, and applies the following rules :
+# - if the address is in the white list, then accept it and forward the
+# connection to the server (local port 443)
+# - if the address is in the black list, then immediately drop it
+# - otherwise, wait up to 3 seconds for valid SSL data to come in. If those
+# data are identified as SSL, the connection is immediately accepted, and
+# if they are definitely identified as non-SSL, the connection is rejected,
+# which will happen upon timeout if they still don't match SSL.
+
+listen block-non-ssl
+ log 127.0.0.1:514 local0
+ option tcplog
+
+ mode tcp
+ bind :8443
+ timeout client 6s
+ timeout server 6s
+ timeout connect 6s
+
+ tcp-request inspect-delay 4s
+
+ acl white_list src 127.0.0.2
+ acl black_list src 127.0.0.3
+
+ # note: SSLv2 is not used anymore, SSLv3.1 is TLSv1.
+ acl obsolete_ssl req_ssl_ver lt 3
+ acl correct_ssl req_ssl_ver 3.0-3.1
+ acl invalid_ssl req_ssl_ver gt 3.1
+
+ tcp-request content accept if white_list
+ tcp-request content reject if black_list
+ tcp-request content reject if !correct_ssl
+
+ balance roundrobin
+ server srv1 127.0.0.1:443
+