disabled on a "bind" line using "no-strict-sni". See the "crt" option for
more information. See "add ssl crt-list" command in the management guide.
+tcp-md5sig <password>
+ Enables the TCP MD5 signature (RFC 2385 Protection of BGP Sessions via the
+ TCP MD5 Signature Option) for all incoming connections instantiated from this
+ listening socket. This option is only available on Linux. When enabled,
+ <password> string is used to sign every TCP segments with a 16-byte MD5
+ digest. This will protect the TCP connection against spoofing. The primary
+ use case for this option is to allow BGP to protect itself against the
+ introduction of spoofed TCP segments into the connection stream. But it can
+ be useful for any very long-lived TCP connections.
+
tcp-ut <delay>
Sets the TCP User Timeout for all incoming connections instantiated from this
listening socket. This option is available on Linux since version 2.6.37. It
server. Using this option won't force the health check to go via socks4 by
default. You will have to use the keyword "check-via-socks4" to enable it.
+tcp-md5sig <password>
+ May be used in the following contexts: tcp, http, log, peers, ring
+
+ Enables the TCP MD5 signature (RFC 2385 Protection of BGP Sessions via the
+ TCP MD5 Signature Option) for all outgoing connections to this server. This
+ option is only available on Linux. When enabled, <password> string is used to
+ sign every TCP segments with a 16-byte MD5 digest. This will protect the TCP
+ connection against spoofing. The primary use case for this option is to allow
+ BGP to protect itself against the introduction of spoofed TCP segments into
+ the connection stream. But it can be useful for any very long-lived TCP
+ connections.
+
tcp-ut <delay>
May be used in the following contexts: tcp, http, log, peers, ring
unsigned int analysers; /* bitmap of required protocol analysers */
int maxseg; /* for TCP, advertised MSS */
int tcp_ut; /* for TCP, user timeout */
+ char *tcp_md5sig; /* TCP MD5 signature password (RFC2385) */
int idle_ping; /* MUX idle-ping interval in ms */
int maxaccept; /* if set, max number of connections accepted at once (-1 when disabled) */
unsigned int backlog; /* if set, listen backlog */
int puid; /* proxy-unique server ID, used for SNMP, and "first" LB algo */
int tcp_ut; /* for TCP, user timeout */
+ char *tcp_md5sig; /* TCP MD5 signature password (RFC2385) */
int do_check; /* temporary variable used during parsing to denote if health checks must be enabled */
int do_agent; /* temporary variable used during parsing to denote if an auxiliary agent check must be enabled */
--- /dev/null
+varnishtest "Test the support for tcp-md5sig option (linux only)"
+
+feature ignore_unknown_macro
+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(3.3-dev1)'"
+
+#EXCLUDE_TARGETS=solaris,freebsd,freebsd-glibc,dragonfly,openbsd,netbsd,cygwin,haiku,aix51,aix52,aix72-gcc,osx,generic,custom
+
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
+ timeout connect "${HAPROXY_TEST_TIMEOUT-100ms}"
+ retries 0
+ log global
+
+ listen internal
+ bind "fd@${md5_int}" tcp-md5sig mypass
+ bind "fd@${nomd5_int}"
+ http-request return status 200
+
+ listen fe
+ bind "fd@${fe}"
+
+ use-server s1 if { path /s1 }
+ use-server s2 if { path /s2 }
+ use-server s3 if { path /s3 }
+ use-server s4 if { path /s4 }
+
+ server s1 ${h1_md5_int_addr}:${h1_md5_int_port} tcp-md5sig mypass
+ server s2 ${h1_md5_int_addr}:${h1_md5_int_port} tcp-md5sig badpass
+ server s3 ${h1_nomd5_int_addr}:${h1_nomd5_int_port}
+ server s4 ${h1_nomd5_int_addr}:${h1_nomd5_int_port} tcp-md5sig mypass
+
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -req "GET" -url "/s1"
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c2 -connect ${h1_fe_sock} {
+ txreq -req "GET" -url "/s2"
+ rxresp
+ expect resp.status == 503
+} -run
+
+client c3 -connect ${h1_fe_sock} {
+ txreq -req "GET" -url "/s3"
+ rxresp
+ expect resp.status == 200
+} -run
+
+client c4 -connect ${h1_fe_sock} {
+ txreq -req "GET" -url "/s4"
+ rxresp
+ expect resp.status == 503
+} -run
}
#endif
+#if defined(__linux__) && defined(TCP_MD5SIG)
+/* parse the "tcp-md5sig" bind keyword */
+static int bind_parse_tcp_md5sig(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+ if (!*args[cur_arg + 1]) {
+ memprintf(err, "'%s' : missing TCP MD5 signature password", args[cur_arg]);
+ return ERR_ALERT | ERR_FATAL;
+ }
+
+ ha_free(&conf->tcp_md5sig);
+ if (strlen(args[cur_arg + 1]) > TCP_MD5SIG_MAXKEYLEN) {
+ memprintf(err, "'%s' : password too long (at most %d characters expected)",
+ args[cur_arg], TCP_MD5SIG_MAXKEYLEN);
+ return ERR_ALERT | ERR_ABORT;
+ }
+ conf->tcp_md5sig = strdup(args[cur_arg + 1]);
+ if (!conf->tcp_md5sig) {
+ memprintf(err, "'%s %s' : out of memory", args[cur_arg], args[cur_arg + 1]);
+ return ERR_ALERT | ERR_FATAL;
+ }
+
+ return 0;
+}
+#endif
+
#ifdef TCP_USER_TIMEOUT
/* parse the "tcp-ut" bind keyword */
static int bind_parse_tcp_ut(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
}
#endif
+#if defined(__linux__) && defined(TCP_MD5SIG)
+/* parse the "tcp-md5sig" server keyword */
+static int srv_parse_tcp_md5sig(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
+{
+ if (!*args[*cur_arg + 1]) {
+ memprintf(err, "'%s' : missing TCP MD5 signature password", args[*cur_arg]);
+ return ERR_ALERT | ERR_FATAL;
+ }
+
+ if (newsrv->addr.ss_family == AF_INET || newsrv->addr.ss_family == AF_INET6) {
+ ha_free(&newsrv->tcp_md5sig);
+ if (strlen(args[*cur_arg + 1]) > TCP_MD5SIG_MAXKEYLEN) {
+ memprintf(err, "'%s' : password too long (at most %d characters expected)",
+ args[*cur_arg], TCP_MD5SIG_MAXKEYLEN);
+ return ERR_ALERT | ERR_ABORT;
+ }
+ newsrv->tcp_md5sig = strdup(args[*cur_arg + 1]);
+ if (!newsrv->tcp_md5sig) {
+ memprintf(err, "'%s %s' : out of memory", args[*cur_arg], args[*cur_arg + 1]);
+ return ERR_ALERT | ERR_FATAL;
+ }
+ }
+ return 0;
+}
+#endif
+
#ifdef TCP_USER_TIMEOUT
/* parse the "tcp-ut" server keyword */
static int srv_parse_tcp_ut(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
#ifdef TCP_MAXSEG
{ "mss", bind_parse_mss, 1 }, /* set MSS of listening socket */
#endif
+#if defined(__linux__) && defined(TCP_MD5SIG)
+ { "tcp-md5sig", bind_parse_tcp_md5sig, 1 }, /* set TCP MD5 signature password */
+#endif
#ifdef TCP_USER_TIMEOUT
{ "tcp-ut", bind_parse_tcp_ut, 1 }, /* set User Timeout on listening socket */
#endif
INITCALL1(STG_REGISTER, bind_register_keywords, &bind_kws);
static struct srv_kw_list srv_kws = { "TCP", { }, {
+#if defined(__linux__) && defined(TCP_MD5SIG)
+ { "tcp-md5sig", srv_parse_tcp_md5sig, 1, 1, 0 }, /* set TCP MD5 signature password on server */
+#endif
#ifdef TCP_USER_TIMEOUT
{ "tcp-ut", srv_parse_tcp_ut, 1, 1, 0 }, /* set TCP user timeout on server */
#endif
bind_conf->rhttp_srvname = NULL;
+ bind_conf->tcp_md5sig = NULL;
+
return bind_conf;
err:
setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, &zero, sizeof(zero));
#endif
+#if defined(__linux__) && defined(TCP_MD5SIG)
+ /* if it fails, the connection will fail, so reported an error */
+ if (srv && srv->tcp_md5sig) {
+ struct tcp_md5sig md5;
+
+ if (conn->dst->ss_family == AF_INET)
+ memcpy(&md5.tcpm_addr, (struct sockaddr_in *)conn->dst, sizeof(struct sockaddr_in));
+ else
+ memcpy(&md5.tcpm_addr, (struct sockaddr_in6 *)conn->dst, sizeof(struct sockaddr_in6));
+
+ strlcpy2((char*)md5.tcpm_key, srv->tcp_md5sig, sizeof(md5.tcpm_key));
+ md5.tcpm_keylen = strlen(srv->tcp_md5sig);
+ if (setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, &md5, sizeof(md5)) < 0) {
+ conn->flags |= CO_FL_ERROR;
+ return SF_ERR_SRVCL;
+ }
+ }
+#endif
+
#ifdef TCP_USER_TIMEOUT
/* there is not much more we can do here when it fails, it's still minor */
if (srv && srv->tcp_ut)
}
}
#endif
+#if defined(__linux__) && defined(TCP_MD5SIG)
+ if (listener->bind_conf->tcp_md5sig) {
+ struct tcp_md5sig md5;
+
+ if (listener->rx.addr.ss_family == AF_INET)
+ memcpy(&md5.tcpm_addr, (struct sockaddr_in *)&listener->rx.addr, sizeof(struct sockaddr_in));
+ else
+ memcpy(&md5.tcpm_addr, (struct sockaddr_in6 *)&listener->rx.addr, sizeof(struct sockaddr_in6));
+
+ strlcpy2((char*)md5.tcpm_key, listener->bind_conf->tcp_md5sig, sizeof(md5.tcpm_key));
+ md5.tcpm_keylen = strlen(listener->bind_conf->tcp_md5sig);
+ if (setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, &md5, sizeof(md5)) < 0) {
+ chunk_appendf(msg, "%scannot set TCP MD5 signature, (%s)", msg->data ? ", " : "",
+ strerror(errno));
+ err = ERR_ALERT | ERR_ABORT;
+ }
+ }
+#endif
#if defined(TCP_USER_TIMEOUT)
if (listener->bind_conf->tcp_ut) {
if (setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT,
LIST_DELETE(&bind_conf->by_fe);
free(bind_conf->guid_prefix);
free(bind_conf->rhttp_srvname);
+ free(bind_conf->tcp_md5sig);
#ifdef USE_QUIC
free(bind_conf->quic_cc_algo);
#endif
#if defined(USE_OPENSSL)
srv_ssl_settings_cpy(srv, src);
#endif
+#ifdef TCP_MD5SIG
+ if (src->tcp_md5sig != NULL)
+ srv->tcp_md5sig = strdup(src->tcp_md5sig);
+#endif
#ifdef TCP_USER_TIMEOUT
srv->tcp_ut = src->tcp_ut;
#endif
free(srv->pool_conn_name);
release_sample_expr(srv->pool_conn_name_expr);
free(srv->resolvers_id);
+ free(srv->tcp_md5sig);
free(srv->addr_node.key);
free(srv->lb_nodes);
counters_be_shared_drop(srv->counters.shared);