MAJOR: stream-int: stop using si->conn and use si->end instead

The connection will only remain there as a pre-allocated entity whose
goal is to be placed in ->end when establishing an outgoing connection.
All connection initialization can be made on this connection, but all
information retrieved should be applied to the end point only.

This change is huge because there were many users of si->conn. Now the
only users are those who initialize the new connection. The difficulty
appears in a few places such as backend.c, proto_http.c, peers.c where
si->conn is used to hold the connection's target address before assigning
the connection to the stream interface. This is why we have to keep
si->conn for now. A future improvement might consist in dynamically
allocating the connection when it is needed.
This commit is contained in:
Willy Tarreau 2013-10-01 10:45:07 +02:00
parent 691b1f429e
commit b363a1f469
12 changed files with 687 additions and 357 deletions

View File

@ -53,18 +53,30 @@ static inline void si_prepare_none(struct stream_interface *si)
si->appctx.applet = NULL; si->appctx.applet = NULL;
} }
/* Assign the stream interface's pre-allocated connection to the end point,
* and initialize the connection's context. This is used for outgoing
* connections.
*/
static inline void si_prepare_conn(struct stream_interface *si, const struct protocol *ctrl, const struct xprt_ops *xprt) static inline void si_prepare_conn(struct stream_interface *si, const struct protocol *ctrl, const struct xprt_ops *xprt)
{ {
struct connection *conn = si->conn;
si->ops = &si_conn_ops; si->ops = &si_conn_ops;
si->end = &si->conn->obj_type; si->end = &conn->obj_type;
conn_prepare(si->conn, &si_conn_cb, ctrl, xprt, si); conn_prepare(conn, &si_conn_cb, ctrl, xprt, si);
} }
/* Assign the stream interface's pre-allocated connection to the end point,
* and leave the connection's context untouched. This is used for incoming
* connections.
*/
static inline void si_takeover_conn(struct stream_interface *si, const struct protocol *ctrl, const struct xprt_ops *xprt) static inline void si_takeover_conn(struct stream_interface *si, const struct protocol *ctrl, const struct xprt_ops *xprt)
{ {
struct connection *conn = si->conn;
si->ops = &si_conn_ops; si->ops = &si_conn_ops;
si->end = &si->conn->obj_type; si->end = &conn->obj_type;
conn_assign(si->conn, &si_conn_cb, ctrl, xprt, si); conn_assign(conn, &si_conn_cb, ctrl, xprt, si);
} }
static inline void si_prepare_applet(struct stream_interface *si, struct si_applet *applet) static inline void si_prepare_applet(struct stream_interface *si, struct si_applet *applet)
@ -141,25 +153,26 @@ static inline void si_chk_snd(struct stream_interface *si)
/* Calls chk_snd on the connection using the ctrl layer */ /* Calls chk_snd on the connection using the ctrl layer */
static inline int si_connect(struct stream_interface *si) static inline int si_connect(struct stream_interface *si)
{ {
struct connection *conn = objt_conn(si->end);
int ret; int ret;
if (unlikely(!si->conn->ctrl || !si->conn->ctrl->connect)) if (unlikely(!conn || !conn->ctrl || !conn->ctrl->connect))
return SN_ERR_INTERNAL; return SN_ERR_INTERNAL;
ret = si->conn->ctrl->connect(si->conn, !channel_is_empty(si->ob), !!si->send_proxy_ofs); ret = conn->ctrl->connect(conn, !channel_is_empty(si->ob), !!si->send_proxy_ofs);
if (ret != SN_ERR_NONE) if (ret != SN_ERR_NONE)
return ret; return ret;
/* needs src ip/port for logging */ /* needs src ip/port for logging */
if (si->flags & SI_FL_SRC_ADDR) if (si->flags & SI_FL_SRC_ADDR)
conn_get_from_addr(si->conn); conn_get_from_addr(conn);
/* Prepare to send a few handshakes related to the on-wire protocol. */ /* Prepare to send a few handshakes related to the on-wire protocol. */
if (si->send_proxy_ofs) if (si->send_proxy_ofs)
si->conn->flags |= CO_FL_SI_SEND_PROXY; conn->flags |= CO_FL_SI_SEND_PROXY;
/* we need to be notified about connection establishment */ /* we need to be notified about connection establishment */
si->conn->flags |= CO_FL_WAKE_DATA; conn->flags |= CO_FL_WAKE_DATA;
/* we're in the process of establishing a connection */ /* we're in the process of establishing a connection */
si->state = SI_ST_CON; si->state = SI_ST_CON;

View File

@ -164,7 +164,7 @@ struct stream_interface {
unsigned int err_type; /* first error detected, one of SI_ET_* */ unsigned int err_type; /* first error detected, one of SI_ET_* */
enum obj_type *end; /* points to the end point (connection or appctx) */ enum obj_type *end; /* points to the end point (connection or appctx) */
struct connection *conn; /* descriptor for a connection */ struct connection *conn; /* pre-allocated connection */
struct si_ops *ops; /* general operations at the stream interface layer */ struct si_ops *ops; /* general operations at the stream interface layer */
/* struct members below are the "remote" part, as seen from the buffer side */ /* struct members below are the "remote" part, as seen from the buffer side */

View File

@ -505,7 +505,7 @@ struct server *get_server_rch(struct session *s)
int assign_server(struct session *s) int assign_server(struct session *s)
{ {
struct connection *conn;
struct server *conn_slot; struct server *conn_slot;
struct server *srv, *prev_srv; struct server *srv, *prev_srv;
int err; int err;
@ -574,14 +574,15 @@ int assign_server(struct session *s)
switch (s->be->lbprm.algo & BE_LB_PARM) { switch (s->be->lbprm.algo & BE_LB_PARM) {
case BE_LB_HASH_SRC: case BE_LB_HASH_SRC:
if (s->req->prod->conn->addr.from.ss_family == AF_INET) { conn = objt_conn(s->req->prod->end);
if (conn && conn->addr.from.ss_family == AF_INET) {
srv = get_server_sh(s->be, srv = get_server_sh(s->be,
(void *)&((struct sockaddr_in *)&s->req->prod->conn->addr.from)->sin_addr, (void *)&((struct sockaddr_in *)&conn->addr.from)->sin_addr,
4); 4);
} }
else if (s->req->prod->conn->addr.from.ss_family == AF_INET6) { else if (conn && conn->addr.from.ss_family == AF_INET6) {
srv = get_server_sh(s->be, srv = get_server_sh(s->be,
(void *)&((struct sockaddr_in6 *)&s->req->prod->conn->addr.from)->sin6_addr, (void *)&((struct sockaddr_in6 *)&conn->addr.from)->sin6_addr,
16); 16);
} }
else { else {
@ -664,7 +665,8 @@ int assign_server(struct session *s)
s->target = &s->be->obj_type; s->target = &s->be->obj_type;
} }
else if ((s->be->options & PR_O_HTTP_PROXY) && else if ((s->be->options & PR_O_HTTP_PROXY) &&
is_addr(&s->req->cons->conn->addr.to)) { (conn = objt_conn(s->req->cons->end)) &&
is_addr(&conn->addr.to)) {
/* in proxy mode, we need a valid destination address */ /* in proxy mode, we need a valid destination address */
s->target = &s->be->obj_type; s->target = &s->be->obj_type;
} }
@ -706,9 +708,15 @@ int assign_server(struct session *s)
* Upon successful return, the session flag SN_ADDR_SET is set. This flag is * Upon successful return, the session flag SN_ADDR_SET is set. This flag is
* not cleared, so it's to the caller to clear it if required. * not cleared, so it's to the caller to clear it if required.
* *
* The address is set on si->conn only. This connection is expected to be
* already allocated and initialized.
*
*/ */
int assign_server_address(struct session *s) int assign_server_address(struct session *s)
{ {
struct connection *cli_conn = objt_conn(s->req->prod->end);
struct connection *srv_conn = s->req->cons->conn;
#ifdef DEBUG_FULL #ifdef DEBUG_FULL
fprintf(stderr,"assign_server_address : s=%p\n",s); fprintf(stderr,"assign_server_address : s=%p\n",s);
#endif #endif
@ -718,51 +726,47 @@ int assign_server_address(struct session *s)
if (!(s->flags & SN_ASSIGNED)) if (!(s->flags & SN_ASSIGNED))
return SRV_STATUS_INTERNAL; return SRV_STATUS_INTERNAL;
s->req->cons->conn->addr.to = objt_server(s->target)->addr; srv_conn->addr.to = objt_server(s->target)->addr;
if (!is_addr(&s->req->cons->conn->addr.to)) { if (!is_addr(&srv_conn->addr.to) && cli_conn) {
/* if the server has no address, we use the same address /* if the server has no address, we use the same address
* the client asked, which is handy for remapping ports * the client asked, which is handy for remapping ports
* locally on multiple addresses at once. * locally on multiple addresses at once.
*/ */
conn_get_to_addr(s->req->prod->conn); conn_get_to_addr(cli_conn);
if (s->req->prod->conn->addr.to.ss_family == AF_INET) { if (cli_conn->addr.to.ss_family == AF_INET) {
((struct sockaddr_in *)&s->req->cons->conn->addr.to)->sin_addr = ((struct sockaddr_in *)&s->req->prod->conn->addr.to)->sin_addr; ((struct sockaddr_in *)&srv_conn->addr.to)->sin_addr = ((struct sockaddr_in *)&cli_conn->addr.to)->sin_addr;
} else if (s->req->prod->conn->addr.to.ss_family == AF_INET6) { } else if (cli_conn->addr.to.ss_family == AF_INET6) {
((struct sockaddr_in6 *)&s->req->cons->conn->addr.to)->sin6_addr = ((struct sockaddr_in6 *)&s->req->prod->conn->addr.to)->sin6_addr; ((struct sockaddr_in6 *)&srv_conn->addr.to)->sin6_addr = ((struct sockaddr_in6 *)&cli_conn->addr.to)->sin6_addr;
} }
} }
/* if this server remaps proxied ports, we'll use /* if this server remaps proxied ports, we'll use
* the port the client connected to with an offset. */ * the port the client connected to with an offset. */
if (objt_server(s->target)->state & SRV_MAPPORTS) { if ((objt_server(s->target)->state & SRV_MAPPORTS) && cli_conn) {
int base_port; int base_port;
conn_get_to_addr(s->req->prod->conn); conn_get_to_addr(cli_conn);
/* First, retrieve the port from the incoming connection */ /* First, retrieve the port from the incoming connection */
base_port = get_host_port(&s->req->prod->conn->addr.to); base_port = get_host_port(&cli_conn->addr.to);
/* Second, assign the outgoing connection's port */ /* Second, assign the outgoing connection's port */
base_port += get_host_port(&s->req->cons->conn->addr.to); base_port += get_host_port(&srv_conn->addr.to);
set_host_port(&s->req->cons->conn->addr.to, base_port); set_host_port(&srv_conn->addr.to, base_port);
} }
} }
else if (s->be->options & PR_O_DISPATCH) { else if (s->be->options & PR_O_DISPATCH) {
/* connect to the defined dispatch addr */ /* connect to the defined dispatch addr */
s->req->cons->conn->addr.to = s->be->dispatch_addr; srv_conn->addr.to = s->be->dispatch_addr;
} }
else if (s->be->options & PR_O_TRANSP) { else if ((s->be->options & PR_O_TRANSP) && cli_conn) {
/* in transparent mode, use the original dest addr if no dispatch specified */ /* in transparent mode, use the original dest addr if no dispatch specified */
conn_get_to_addr(s->req->prod->conn); conn_get_to_addr(cli_conn);
if (s->req->prod->conn->addr.to.ss_family == AF_INET || s->req->prod->conn->addr.to.ss_family == AF_INET6) { if (cli_conn->addr.to.ss_family == AF_INET || cli_conn->addr.to.ss_family == AF_INET6)
memcpy(&s->req->cons->conn->addr.to, &s->req->prod->conn->addr.to, MIN(sizeof(s->req->cons->conn->addr.to), sizeof(s->req->prod->conn->addr.to))); srv_conn->addr.to = cli_conn->addr.to;
}
/* when we support IPv6 on the backend, we may add other tests */
//qfprintf(stderr, "Cannot get original server address.\n");
//return SRV_STATUS_INTERNAL;
} }
else if (s->be->options & PR_O_HTTP_PROXY) { else if (s->be->options & PR_O_HTTP_PROXY) {
/* If HTTP PROXY option is set, then server is already assigned /* If HTTP PROXY option is set, then server is already assigned
@ -902,13 +906,16 @@ int assign_server_and_queue(struct session *s)
/* If an explicit source binding is specified on the server and/or backend, and /* If an explicit source binding is specified on the server and/or backend, and
* this source makes use of the transparent proxy, then it is extracted now and * this source makes use of the transparent proxy, then it is extracted now and
* assigned to the session's req->cons->addr.from entry. * assigned to the session's pending connection. This function assumes that an
* outgoing connection has already been allocated into s->req->cons->conn.
*/ */
static void assign_tproxy_address(struct session *s) static void assign_tproxy_address(struct session *s)
{ {
#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_TRANSPARENT) #if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_TRANSPARENT)
struct server *srv = objt_server(s->target); struct server *srv = objt_server(s->target);
struct conn_src *src; struct conn_src *src;
struct connection *cli_conn;
struct connection *srv_conn = s->req->cons->conn;
if (srv && srv->conn_src.opts & CO_SRC_BIND) if (srv && srv->conn_src.opts & CO_SRC_BIND)
src = &srv->conn_src; src = &srv->conn_src;
@ -919,12 +926,16 @@ static void assign_tproxy_address(struct session *s)
switch (src->opts & CO_SRC_TPROXY_MASK) { switch (src->opts & CO_SRC_TPROXY_MASK) {
case CO_SRC_TPROXY_ADDR: case CO_SRC_TPROXY_ADDR:
s->req->cons->conn->addr.from = src->tproxy_addr; srv_conn->addr.from = src->tproxy_addr;
break; break;
case CO_SRC_TPROXY_CLI: case CO_SRC_TPROXY_CLI:
case CO_SRC_TPROXY_CIP: case CO_SRC_TPROXY_CIP:
/* FIXME: what can we do if the client connects in IPv6 or unix socket ? */ /* FIXME: what can we do if the client connects in IPv6 or unix socket ? */
s->req->cons->conn->addr.from = s->req->prod->conn->addr.from; cli_conn = objt_conn(s->req->prod->end);
if (cli_conn)
srv_conn->addr.from = cli_conn->addr.from;
else
memset(&srv_conn->addr.from, 0, sizeof(srv_conn->addr.from));
break; break;
case CO_SRC_TPROXY_DYN: case CO_SRC_TPROXY_DYN:
if (src->bind_hdr_occ) { if (src->bind_hdr_occ) {
@ -933,21 +944,21 @@ static void assign_tproxy_address(struct session *s)
int rewind; int rewind;
/* bind to the IP in a header */ /* bind to the IP in a header */
((struct sockaddr_in *)&s->req->cons->conn->addr.from)->sin_family = AF_INET; ((struct sockaddr_in *)&srv_conn->addr.from)->sin_family = AF_INET;
((struct sockaddr_in *)&s->req->cons->conn->addr.from)->sin_port = 0; ((struct sockaddr_in *)&srv_conn->addr.from)->sin_port = 0;
((struct sockaddr_in *)&s->req->cons->conn->addr.from)->sin_addr.s_addr = 0; ((struct sockaddr_in *)&srv_conn->addr.from)->sin_addr.s_addr = 0;
b_rew(s->req->buf, rewind = s->req->buf->o); b_rew(s->req->buf, rewind = s->req->buf->o);
if (http_get_hdr(&s->txn.req, src->bind_hdr_name, src->bind_hdr_len, if (http_get_hdr(&s->txn.req, src->bind_hdr_name, src->bind_hdr_len,
&s->txn.hdr_idx, src->bind_hdr_occ, NULL, &vptr, &vlen)) { &s->txn.hdr_idx, src->bind_hdr_occ, NULL, &vptr, &vlen)) {
((struct sockaddr_in *)&s->req->cons->conn->addr.from)->sin_addr.s_addr = ((struct sockaddr_in *)&srv_conn->addr.from)->sin_addr.s_addr =
htonl(inetaddr_host_lim(vptr, vptr + vlen)); htonl(inetaddr_host_lim(vptr, vptr + vlen));
} }
b_adv(s->req->buf, rewind); b_adv(s->req->buf, rewind);
} }
break; break;
default: default:
memset(&s->req->cons->conn->addr.from, 0, sizeof(s->req->cons->conn->addr.from)); memset(&srv_conn->addr.from, 0, sizeof(srv_conn->addr.from));
} }
#endif #endif
} }
@ -965,9 +976,13 @@ static void assign_tproxy_address(struct session *s)
* - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...) * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
* - SN_ERR_INTERNAL for any other purely internal errors * - SN_ERR_INTERNAL for any other purely internal errors
* Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted. * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
* The server-facing stream interface is expected to hold a pre-allocated connection
* in s->req->cons->conn.
*/ */
int connect_server(struct session *s) int connect_server(struct session *s)
{ {
struct connection *cli_conn;
struct connection *srv_conn = s->req->cons->conn;
struct server *srv; struct server *srv;
int err; int err;
@ -978,7 +993,7 @@ int connect_server(struct session *s)
} }
/* the target was only on the session, assign it to the SI now */ /* the target was only on the session, assign it to the SI now */
s->req->cons->conn->target = s->target; srv_conn->target = s->target;
/* set the correct protocol on the output stream interface */ /* set the correct protocol on the output stream interface */
if (objt_server(s->target)) { if (objt_server(s->target)) {
@ -986,8 +1001,8 @@ int connect_server(struct session *s)
} }
else if (obj_type(s->target) == OBJ_TYPE_PROXY) { else if (obj_type(s->target) == OBJ_TYPE_PROXY) {
/* proxies exclusively run on raw_sock right now */ /* proxies exclusively run on raw_sock right now */
si_prepare_conn(s->req->cons, protocol_by_family(s->req->cons->conn->addr.to.ss_family), &raw_sock); si_prepare_conn(s->req->cons, protocol_by_family(srv_conn->addr.to.ss_family), &raw_sock);
if (!s->req->cons->conn->ctrl) if (!objt_conn(s->req->cons->end) || !objt_conn(s->req->cons->end)->ctrl)
return SN_ERR_INTERNAL; return SN_ERR_INTERNAL;
} }
else else
@ -997,7 +1012,9 @@ int connect_server(struct session *s)
s->req->cons->send_proxy_ofs = 0; s->req->cons->send_proxy_ofs = 0;
if (objt_server(s->target) && (objt_server(s->target)->state & SRV_SEND_PROXY)) { if (objt_server(s->target) && (objt_server(s->target)->state & SRV_SEND_PROXY)) {
s->req->cons->send_proxy_ofs = 1; /* must compute size */ s->req->cons->send_proxy_ofs = 1; /* must compute size */
conn_get_to_addr(s->req->prod->conn); cli_conn = objt_conn(s->req->prod->end);
if (cli_conn)
conn_get_to_addr(cli_conn);
} }
assign_tproxy_address(s); assign_tproxy_address(s);

View File

@ -151,7 +151,7 @@ enum {
extern const char *stat_status_codes[]; extern const char *stat_status_codes[];
/* This function is called from the session-level accept() in order to instanciate /* This function is called from the session-level accept() in order to instanciate
* a new stats socket. It returns a positive value upon success, 0 if the connection * a new stats socket. It returns a positive value upon success, 0 if the session
* needs to be closed and ignored, or a negative value upon critical failure. * needs to be closed and ignored, or a negative value upon critical failure.
*/ */
static int stats_accept(struct session *s) static int stats_accept(struct session *s)
@ -3881,6 +3881,7 @@ static int stats_dump_full_sess_to_buffer(struct stream_interface *si, struct se
struct tm tm; struct tm tm;
extern const char *monthname[12]; extern const char *monthname[12];
char pn[INET6_ADDRSTRLEN]; char pn[INET6_ADDRSTRLEN];
struct connection *conn;
chunk_reset(&trash); chunk_reset(&trash);
@ -3910,12 +3911,12 @@ static int stats_dump_full_sess_to_buffer(struct stream_interface *si, struct se
sess->uniq_id, sess->uniq_id,
sess->listener && sess->listener->proto->name ? sess->listener->proto->name : "?"); sess->listener && sess->listener->proto->name ? sess->listener->proto->name : "?");
switch ((obj_type(sess->si[0].end) == OBJ_TYPE_CONN) ? conn = objt_conn(sess->si[0].end);
addr_to_str(&sess->si[0].conn->addr.from, pn, sizeof(pn)) : AF_UNSPEC) { switch (conn ? addr_to_str(&conn->addr.from, pn, sizeof(pn)) : AF_UNSPEC) {
case AF_INET: case AF_INET:
case AF_INET6: case AF_INET6:
chunk_appendf(&trash, " source=%s:%d\n", chunk_appendf(&trash, " source=%s:%d\n",
pn, get_host_port(&sess->si[0].conn->addr.from)); pn, get_host_port(&conn->addr.from));
break; break;
case AF_UNIX: case AF_UNIX:
chunk_appendf(&trash, " source=unix:%d\n", sess->listener->luid); chunk_appendf(&trash, " source=unix:%d\n", sess->listener->luid);
@ -3936,15 +3937,14 @@ static int stats_dump_full_sess_to_buffer(struct stream_interface *si, struct se
sess->listener ? sess->listener->name ? sess->listener->name : "?" : "?", sess->listener ? sess->listener->name ? sess->listener->name : "?" : "?",
sess->listener ? sess->listener->luid : 0); sess->listener ? sess->listener->luid : 0);
if (obj_type(sess->si[0].end) == OBJ_TYPE_CONN) if (conn)
conn_get_to_addr(sess->si[0].conn); conn_get_to_addr(conn);
switch ((obj_type(sess->si[0].end) == OBJ_TYPE_CONN) ? switch (conn ? addr_to_str(&conn->addr.to, pn, sizeof(pn)) : AF_UNSPEC) {
addr_to_str(&sess->si[0].conn->addr.to, pn, sizeof(pn)) : AF_UNSPEC) {
case AF_INET: case AF_INET:
case AF_INET6: case AF_INET6:
chunk_appendf(&trash, " addr=%s:%d\n", chunk_appendf(&trash, " addr=%s:%d\n",
pn, get_host_port(&sess->si[0].conn->addr.to)); pn, get_host_port(&conn->addr.to));
break; break;
case AF_UNIX: case AF_UNIX:
chunk_appendf(&trash, " addr=unix:%d\n", sess->listener->luid); chunk_appendf(&trash, " addr=unix:%d\n", sess->listener->luid);
@ -3963,15 +3963,15 @@ static int stats_dump_full_sess_to_buffer(struct stream_interface *si, struct se
else else
chunk_appendf(&trash, " backend=<NONE> (id=-1 mode=-)"); chunk_appendf(&trash, " backend=<NONE> (id=-1 mode=-)");
if (obj_type(sess->si[1].end) == OBJ_TYPE_CONN) conn = objt_conn(sess->si[1].end);
conn_get_from_addr(sess->si[1].conn); if (conn)
conn_get_from_addr(conn);
switch ((obj_type(sess->si[1].end) == OBJ_TYPE_CONN) ? switch (conn ? addr_to_str(&conn->addr.from, pn, sizeof(pn)) : AF_UNSPEC) {
addr_to_str(&sess->si[1].conn->addr.from, pn, sizeof(pn)) : AF_UNSPEC) {
case AF_INET: case AF_INET:
case AF_INET6: case AF_INET6:
chunk_appendf(&trash, " addr=%s:%d\n", chunk_appendf(&trash, " addr=%s:%d\n",
pn, get_host_port(&sess->si[1].conn->addr.from)); pn, get_host_port(&conn->addr.from));
break; break;
case AF_UNIX: case AF_UNIX:
chunk_appendf(&trash, " addr=unix\n"); chunk_appendf(&trash, " addr=unix\n");
@ -3990,15 +3990,14 @@ static int stats_dump_full_sess_to_buffer(struct stream_interface *si, struct se
else else
chunk_appendf(&trash, " server=<NONE> (id=-1)"); chunk_appendf(&trash, " server=<NONE> (id=-1)");
if (obj_type(sess->si[1].end) == OBJ_TYPE_CONN) if (conn)
conn_get_to_addr(sess->si[1].conn); conn_get_to_addr(conn);
switch ((obj_type(sess->si[1].end) == OBJ_TYPE_CONN) ? switch (conn ? addr_to_str(&conn->addr.to, pn, sizeof(pn)) : AF_UNSPEC) {
addr_to_str(&sess->si[1].conn->addr.to, pn, sizeof(pn)) : AF_UNSPEC) {
case AF_INET: case AF_INET:
case AF_INET6: case AF_INET6:
chunk_appendf(&trash, " addr=%s:%d\n", chunk_appendf(&trash, " addr=%s:%d\n",
pn, get_host_port(&sess->si[1].conn->addr.to)); pn, get_host_port(&conn->addr.to));
break; break;
case AF_UNIX: case AF_UNIX:
chunk_appendf(&trash, " addr=unix\n"); chunk_appendf(&trash, " addr=unix\n");
@ -4057,42 +4056,44 @@ static int stats_dump_full_sess_to_buffer(struct stream_interface *si, struct se
TICKS_TO_MS(1000)) : "<NEVER>", TICKS_TO_MS(1000)) : "<NEVER>",
sess->si[1].err_type); sess->si[1].err_type);
if (obj_type(sess->si[0].end) == OBJ_TYPE_CONN) { conn = objt_conn(sess->si[0].end);
if (conn) {
chunk_appendf(&trash, chunk_appendf(&trash,
" co0=%p ctrl=%s xprt=%s data=%s target=%s:%p\n", " co0=%p ctrl=%s xprt=%s data=%s target=%s:%p\n",
sess->si[0].conn, conn,
get_conn_ctrl_name(sess->si[0].conn), get_conn_ctrl_name(conn),
get_conn_xprt_name(sess->si[0].conn), get_conn_xprt_name(conn),
get_conn_data_name(sess->si[0].conn), get_conn_data_name(conn),
obj_type_name(sess->si[0].conn->target), obj_type_name(conn->target),
obj_base_ptr(sess->si[0].conn->target)); obj_base_ptr(conn->target));
chunk_appendf(&trash, chunk_appendf(&trash,
" flags=0x%08x fd=%d fd_spec_e=%02x fd_spec_p=%d updt=%d\n", " flags=0x%08x fd=%d fd_spec_e=%02x fd_spec_p=%d updt=%d\n",
sess->si[0].conn->flags, conn->flags,
sess->si[0].conn->t.sock.fd, conn->t.sock.fd,
sess->si[0].conn->t.sock.fd >= 0 ? fdtab[sess->si[0].conn->t.sock.fd].spec_e : 0, conn->t.sock.fd >= 0 ? fdtab[conn->t.sock.fd].spec_e : 0,
sess->si[0].conn->t.sock.fd >= 0 ? fdtab[sess->si[0].conn->t.sock.fd].spec_p : 0, conn->t.sock.fd >= 0 ? fdtab[conn->t.sock.fd].spec_p : 0,
sess->si[0].conn->t.sock.fd >= 0 ? fdtab[sess->si[0].conn->t.sock.fd].updated : 0); conn->t.sock.fd >= 0 ? fdtab[conn->t.sock.fd].updated : 0);
} }
if (obj_type(sess->si[1].end) == OBJ_TYPE_CONN) { conn = objt_conn(sess->si[1].end);
if (conn) {
chunk_appendf(&trash, chunk_appendf(&trash,
" co1=%p ctrl=%s xprt=%s data=%s target=%s:%p\n", " co1=%p ctrl=%s xprt=%s data=%s target=%s:%p\n",
sess->si[1].conn, conn,
get_conn_ctrl_name(sess->si[1].conn), get_conn_ctrl_name(conn),
get_conn_xprt_name(sess->si[1].conn), get_conn_xprt_name(conn),
get_conn_data_name(sess->si[1].conn), get_conn_data_name(conn),
obj_type_name(sess->si[1].conn->target), obj_type_name(conn->target),
obj_base_ptr(sess->si[1].conn->target)); obj_base_ptr(conn->target));
chunk_appendf(&trash, chunk_appendf(&trash,
" flags=0x%08x fd=%d fd_spec_e=%02x fd_spec_p=%d updt=%d\n", " flags=0x%08x fd=%d fd_spec_e=%02x fd_spec_p=%d updt=%d\n",
sess->si[1].conn->flags, conn->flags,
sess->si[1].conn->t.sock.fd, conn->t.sock.fd,
sess->si[1].conn->t.sock.fd >= 0 ? fdtab[sess->si[1].conn->t.sock.fd].spec_e : 0, conn->t.sock.fd >= 0 ? fdtab[conn->t.sock.fd].spec_e : 0,
sess->si[1].conn->t.sock.fd >= 0 ? fdtab[sess->si[1].conn->t.sock.fd].spec_p : 0, conn->t.sock.fd >= 0 ? fdtab[conn->t.sock.fd].spec_p : 0,
sess->si[1].conn->t.sock.fd >= 0 ? fdtab[sess->si[1].conn->t.sock.fd].updated : 0); conn->t.sock.fd >= 0 ? fdtab[conn->t.sock.fd].updated : 0);
} }
chunk_appendf(&trash, chunk_appendf(&trash,
@ -4171,6 +4172,8 @@ static int stats_dump_full_sess_to_buffer(struct stream_interface *si, struct se
*/ */
static int stats_dump_sess_to_buffer(struct stream_interface *si) static int stats_dump_sess_to_buffer(struct stream_interface *si)
{ {
struct connection *conn;
if (unlikely(si->ib->flags & (CF_WRITE_ERROR|CF_SHUTW))) { if (unlikely(si->ib->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
/* If we're forced to shut down, we might have to remove our /* If we're forced to shut down, we might have to remove our
* reference to the last session being dumped. * reference to the last session being dumped.
@ -4240,14 +4243,14 @@ static int stats_dump_sess_to_buffer(struct stream_interface *si)
curr_sess->listener->proto->name); curr_sess->listener->proto->name);
switch ((obj_type(curr_sess->si[0].end) == OBJ_TYPE_CONN) ? conn = objt_conn(curr_sess->si[0].end);
addr_to_str(&curr_sess->si[0].conn->addr.from, pn, sizeof(pn)) : AF_UNSPEC) { switch (conn ? addr_to_str(&conn->addr.from, pn, sizeof(pn)) : AF_UNSPEC) {
case AF_INET: case AF_INET:
case AF_INET6: case AF_INET6:
chunk_appendf(&trash, chunk_appendf(&trash,
" src=%s:%d fe=%s be=%s srv=%s", " src=%s:%d fe=%s be=%s srv=%s",
pn, pn,
get_host_port(&curr_sess->si[0].conn->addr.from), get_host_port(&conn->addr.from),
curr_sess->fe->id, curr_sess->fe->id,
(curr_sess->be->cap & PR_CAP_BE) ? curr_sess->be->id : "<NONE>", (curr_sess->be->cap & PR_CAP_BE) ? curr_sess->be->id : "<NONE>",
objt_server(curr_sess->target) ? objt_server(curr_sess->target)->id : "<none>" objt_server(curr_sess->target) ? objt_server(curr_sess->target)->id : "<none>"
@ -4312,22 +4315,22 @@ static int stats_dump_sess_to_buffer(struct stream_interface *si)
human_time(TICKS_TO_MS(curr_sess->rep->analyse_exp - now_ms), human_time(TICKS_TO_MS(curr_sess->rep->analyse_exp - now_ms),
TICKS_TO_MS(1000)) : ""); TICKS_TO_MS(1000)) : "");
conn = objt_conn(curr_sess->si[0].end);
chunk_appendf(&trash, chunk_appendf(&trash,
" s0=[%d,%1xh,fd=%d,ex=%s]", " s0=[%d,%1xh,fd=%d,ex=%s]",
curr_sess->si[0].state, curr_sess->si[0].state,
curr_sess->si[0].flags, curr_sess->si[0].flags,
(obj_type(curr_sess->si[0].end) == OBJ_TYPE_CONN) ? conn ? conn->t.sock.fd : -1,
curr_sess->si[0].conn->t.sock.fd : -1,
curr_sess->si[0].exp ? curr_sess->si[0].exp ?
human_time(TICKS_TO_MS(curr_sess->si[0].exp - now_ms), human_time(TICKS_TO_MS(curr_sess->si[0].exp - now_ms),
TICKS_TO_MS(1000)) : ""); TICKS_TO_MS(1000)) : "");
conn = objt_conn(curr_sess->si[1].end);
chunk_appendf(&trash, chunk_appendf(&trash,
" s1=[%d,%1xh,fd=%d,ex=%s]", " s1=[%d,%1xh,fd=%d,ex=%s]",
curr_sess->si[1].state, curr_sess->si[1].state,
curr_sess->si[1].flags, curr_sess->si[1].flags,
(obj_type(curr_sess->si[1].end) == OBJ_TYPE_CONN) ? conn ? conn->t.sock.fd : -1,
curr_sess->si[1].conn->t.sock.fd : -1,
curr_sess->si[1].exp ? curr_sess->si[1].exp ?
human_time(TICKS_TO_MS(curr_sess->si[1].exp - now_ms), human_time(TICKS_TO_MS(curr_sess->si[1].exp - now_ms),
TICKS_TO_MS(1000)) : ""); TICKS_TO_MS(1000)) : "");

View File

@ -49,11 +49,13 @@
/* Finish a session accept() for a proxy (TCP or HTTP). It returns a negative /* Finish a session accept() for a proxy (TCP or HTTP). It returns a negative
* value in case of a critical failure which must cause the listener to be * value in case of a critical failure which must cause the listener to be
* disabled, a positive value in case of success, or zero if it is a success * disabled, a positive value in case of success, or zero if it is a success
* but the session must be closed ASAP (eg: monitoring). * but the session must be closed ASAP (eg: monitoring). It only supports
* sessions with a connection in si[0].
*/ */
int frontend_accept(struct session *s) int frontend_accept(struct session *s)
{ {
int cfd = s->si[0].conn->t.sock.fd; struct connection *conn = __objt_conn(s->si[0].end);
int cfd = conn->t.sock.fd;
tv_zero(&s->logs.tv_request); tv_zero(&s->logs.tv_request);
s->logs.t_queue = -1; s->logs.t_queue = -1;
@ -140,16 +142,16 @@ int frontend_accept(struct session *s)
else { else {
char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN]; char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
conn_get_from_addr(s->req->prod->conn); conn_get_from_addr(conn);
conn_get_to_addr(s->req->prod->conn); conn_get_to_addr(conn);
switch (addr_to_str(&s->req->prod->conn->addr.from, pn, sizeof(pn))) { switch (addr_to_str(&conn->addr.from, pn, sizeof(pn))) {
case AF_INET: case AF_INET:
case AF_INET6: case AF_INET6:
addr_to_str(&s->req->prod->conn->addr.to, sn, sizeof(sn)); addr_to_str(&conn->addr.to, sn, sizeof(sn));
send_log(s->fe, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n", send_log(s->fe, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
pn, get_host_port(&s->req->prod->conn->addr.from), pn, get_host_port(&conn->addr.from),
sn, get_host_port(&s->req->prod->conn->addr.to), sn, get_host_port(&conn->addr.to),
s->fe->id, (s->fe->mode == PR_MODE_HTTP) ? "HTTP" : "TCP"); s->fe->id, (s->fe->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
break; break;
case AF_UNIX: case AF_UNIX:
@ -165,14 +167,14 @@ int frontend_accept(struct session *s)
if (unlikely((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) { if (unlikely((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
char pn[INET6_ADDRSTRLEN]; char pn[INET6_ADDRSTRLEN];
conn_get_from_addr(s->req->prod->conn); conn_get_from_addr(conn);
switch (addr_to_str(&s->req->prod->conn->addr.from, pn, sizeof(pn))) { switch (addr_to_str(&conn->addr.from, pn, sizeof(pn))) {
case AF_INET: case AF_INET:
case AF_INET6: case AF_INET6:
chunk_printf(&trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n", chunk_printf(&trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
s->uniq_id, s->fe->id, (unsigned short)s->listener->fd, (unsigned short)cfd, s->uniq_id, s->fe->id, (unsigned short)s->listener->fd, (unsigned short)cfd,
pn, get_host_port(&s->req->prod->conn->addr.from)); pn, get_host_port(&conn->addr.from));
break; break;
case AF_UNIX: case AF_UNIX:
/* UNIX socket, only the destination is known */ /* UNIX socket, only the destination is known */

View File

@ -935,6 +935,7 @@ int build_logline(struct session *s, char *dst, size_t maxsize, struct list *lis
return 0; return 0;
list_for_each_entry(tmp, list_format, list) { list_for_each_entry(tmp, list_format, list) {
struct connection *conn;
const char *src = NULL; const char *src = NULL;
struct sample *key; struct sample *key;
@ -969,8 +970,11 @@ int build_logline(struct session *s, char *dst, size_t maxsize, struct list *lis
break; break;
case LOG_FMT_CLIENTIP: // %ci case LOG_FMT_CLIENTIP: // %ci
ret = lf_ip(tmplog, (struct sockaddr *)&s->req->prod->conn->addr.from, conn = objt_conn(s->req->prod->end);
dst + maxsize - tmplog, tmp); if (conn)
ret = lf_ip(tmplog, (struct sockaddr *)&conn->addr.from, dst + maxsize - tmplog, tmp);
else
ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
if (ret == NULL) if (ret == NULL)
goto out; goto out;
tmplog = ret; tmplog = ret;
@ -978,12 +982,18 @@ int build_logline(struct session *s, char *dst, size_t maxsize, struct list *lis
break; break;
case LOG_FMT_CLIENTPORT: // %cp case LOG_FMT_CLIENTPORT: // %cp
if (s->req->prod->conn->addr.from.ss_family == AF_UNIX) { conn = objt_conn(s->req->prod->end);
if (conn) {
if (conn->addr.from.ss_family == AF_UNIX) {
ret = ltoa_o(s->listener->luid, tmplog, dst + maxsize - tmplog); ret = ltoa_o(s->listener->luid, tmplog, dst + maxsize - tmplog);
} else { } else {
ret = lf_port(tmplog, (struct sockaddr *)&s->req->prod->conn->addr.from, ret = lf_port(tmplog, (struct sockaddr *)&conn->addr.from,
dst + maxsize - tmplog, tmp); dst + maxsize - tmplog, tmp);
} }
}
else
ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
if (ret == NULL) if (ret == NULL)
goto out; goto out;
tmplog = ret; tmplog = ret;
@ -991,9 +1001,14 @@ int build_logline(struct session *s, char *dst, size_t maxsize, struct list *lis
break; break;
case LOG_FMT_FRONTENDIP: // %fi case LOG_FMT_FRONTENDIP: // %fi
conn_get_to_addr(s->req->prod->conn); conn = objt_conn(s->req->prod->end);
ret = lf_ip(tmplog, (struct sockaddr *)&s->req->prod->conn->addr.to, if (conn) {
dst + maxsize - tmplog, tmp); conn_get_to_addr(conn);
ret = lf_ip(tmplog, (struct sockaddr *)&conn->addr.to, dst + maxsize - tmplog, tmp);
}
else
ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
if (ret == NULL) if (ret == NULL)
goto out; goto out;
tmplog = ret; tmplog = ret;
@ -1001,14 +1016,17 @@ int build_logline(struct session *s, char *dst, size_t maxsize, struct list *lis
break; break;
case LOG_FMT_FRONTENDPORT: // %fp case LOG_FMT_FRONTENDPORT: // %fp
conn_get_to_addr(s->req->prod->conn); conn = objt_conn(s->req->prod->end);
if (s->req->prod->conn->addr.to.ss_family == AF_UNIX) { if (conn) {
ret = ltoa_o(s->listener->luid, conn_get_to_addr(conn);
tmplog, dst + maxsize - tmplog); if (conn->addr.to.ss_family == AF_UNIX)
} else { ret = ltoa_o(s->listener->luid, tmplog, dst + maxsize - tmplog);
ret = lf_port(tmplog, (struct sockaddr *)&s->req->prod->conn->addr.to, else
dst + maxsize - tmplog, tmp); ret = lf_port(tmplog, (struct sockaddr *)&conn->addr.to, dst + maxsize - tmplog, tmp);
} }
else
ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
if (ret == NULL) if (ret == NULL)
goto out; goto out;
tmplog = ret; tmplog = ret;
@ -1016,8 +1034,12 @@ int build_logline(struct session *s, char *dst, size_t maxsize, struct list *lis
break; break;
case LOG_FMT_BACKENDIP: // %bi case LOG_FMT_BACKENDIP: // %bi
ret = lf_ip(tmplog, (struct sockaddr *)&s->req->cons->conn->addr.from, conn = objt_conn(s->req->cons->end);
dst + maxsize - tmplog, tmp); if (conn)
ret = lf_ip(tmplog, (struct sockaddr *)&conn->addr.from, dst + maxsize - tmplog, tmp);
else
ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
if (ret == NULL) if (ret == NULL)
goto out; goto out;
tmplog = ret; tmplog = ret;
@ -1025,8 +1047,12 @@ int build_logline(struct session *s, char *dst, size_t maxsize, struct list *lis
break; break;
case LOG_FMT_BACKENDPORT: // %bp case LOG_FMT_BACKENDPORT: // %bp
ret = lf_port(tmplog, (struct sockaddr *)&s->req->cons->conn->addr.from, conn = objt_conn(s->req->cons->end);
dst + maxsize - tmplog, tmp); if (conn)
ret = lf_port(tmplog, (struct sockaddr *)&conn->addr.from, dst + maxsize - tmplog, tmp);
else
ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
if (ret == NULL) if (ret == NULL)
goto out; goto out;
tmplog = ret; tmplog = ret;
@ -1034,8 +1060,12 @@ int build_logline(struct session *s, char *dst, size_t maxsize, struct list *lis
break; break;
case LOG_FMT_SERVERIP: // %si case LOG_FMT_SERVERIP: // %si
ret = lf_ip(tmplog, (struct sockaddr *)&s->req->cons->conn->addr.to, conn = objt_conn(s->req->cons->end);
dst + maxsize - tmplog, tmp); if (conn)
ret = lf_ip(tmplog, (struct sockaddr *)&conn->addr.to, dst + maxsize - tmplog, tmp);
else
ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
if (ret == NULL) if (ret == NULL)
goto out; goto out;
tmplog = ret; tmplog = ret;
@ -1043,8 +1073,12 @@ int build_logline(struct session *s, char *dst, size_t maxsize, struct list *lis
break; break;
case LOG_FMT_SERVERPORT: // %sp case LOG_FMT_SERVERPORT: // %sp
ret = lf_port(tmplog, (struct sockaddr *)&s->req->cons->conn->addr.to, conn = objt_conn(s->req->cons->end);
dst + maxsize - tmplog, tmp); if (conn)
ret = lf_port(tmplog, (struct sockaddr *)&conn->addr.to, dst + maxsize - tmplog, tmp);
else
ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
if (ret == NULL) if (ret == NULL)
goto out; goto out;
tmplog = ret; tmplog = ret;
@ -1143,8 +1177,11 @@ int build_logline(struct session *s, char *dst, size_t maxsize, struct list *lis
#ifdef USE_OPENSSL #ifdef USE_OPENSSL
case LOG_FMT_SSL_CIPHER: // %sslc case LOG_FMT_SSL_CIPHER: // %sslc
src = NULL; src = NULL;
conn = objt_conn(s->si[0].end);
if (conn) {
if (s->listener->xprt == &ssl_sock) if (s->listener->xprt == &ssl_sock)
src = ssl_sock_get_cipher_name(s->si[0].conn); src = ssl_sock_get_cipher_name(conn);
}
ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp); ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
if (ret == NULL) if (ret == NULL)
goto out; goto out;
@ -1154,8 +1191,11 @@ int build_logline(struct session *s, char *dst, size_t maxsize, struct list *lis
case LOG_FMT_SSL_VERSION: // %sslv case LOG_FMT_SSL_VERSION: // %sslv
src = NULL; src = NULL;
conn = objt_conn(s->si[0].end);
if (conn) {
if (s->listener->xprt == &ssl_sock) if (s->listener->xprt == &ssl_sock)
src = ssl_sock_get_proto_version(s->si[0].conn); src = ssl_sock_get_proto_version(conn);
}
ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp); ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
if (ret == NULL) if (ret == NULL)
goto out; goto out;

View File

@ -1076,11 +1076,10 @@ static void peer_session_forceshutdown(struct session * session)
task_wakeup(session->task, TASK_WOKEN_MSG); task_wakeup(session->task, TASK_WOKEN_MSG);
} }
/* /* Finish a session accept() for a peer. It returns a negative value in case of
* this function is called on a read event from a listen socket, corresponding * a critical failure which must cause the listener to be disabled, a positive
* to an accept. It tries to accept as many connections as possible. * value in case of success, or zero if it is a success but the session must be
* It returns a positive value upon success, 0 if the connection needs to be * closed ASAP and ignored.
* closed and ignored, or a negative value upon critical failure.
*/ */
int peer_accept(struct session *s) int peer_accept(struct session *s)
{ {
@ -1162,15 +1161,17 @@ static struct session *peer_session_create(struct peer *peer, struct peer_sessio
s->req = s->rep = NULL; /* will be allocated later */ s->req = s->rep = NULL; /* will be allocated later */
/* si[0] is the applet, we should not need s->si[0].conn anymore soon */
s->si[0].conn->obj_type = OBJ_TYPE_CONN; s->si[0].conn->obj_type = OBJ_TYPE_CONN;
s->si[0].conn->t.sock.fd = -1; s->si[0].conn->t.sock.fd = -1;
s->si[0].conn->flags = CO_FL_NONE; s->si[0].conn->flags = CO_FL_NONE;
s->si[0].conn->err_code = CO_ER_NONE; s->si[0].conn->err_code = CO_ER_NONE;
s->si[0].conn->target = &l->obj_type;
s->si[0].owner = t; s->si[0].owner = t;
s->si[0].state = s->si[0].prev_state = SI_ST_EST; s->si[0].state = s->si[0].prev_state = SI_ST_EST;
s->si[0].err_type = SI_ET_NONE; s->si[0].err_type = SI_ET_NONE;
s->si[0].send_proxy_ofs = 0; s->si[0].send_proxy_ofs = 0;
s->si[0].conn->target = &l->obj_type;
s->si[0].exp = TICK_ETERNITY; s->si[0].exp = TICK_ETERNITY;
s->si[0].flags = SI_FL_NONE; s->si[0].flags = SI_FL_NONE;
if (s->fe->options2 & PR_O2_INDEPSTR) if (s->fe->options2 & PR_O2_INDEPSTR)
@ -1184,18 +1185,23 @@ static struct session *peer_session_create(struct peer *peer, struct peer_sessio
s->si[1].conn->t.sock.fd = -1; /* just to help with debugging */ s->si[1].conn->t.sock.fd = -1; /* just to help with debugging */
s->si[1].conn->flags = CO_FL_NONE; s->si[1].conn->flags = CO_FL_NONE;
s->si[1].conn->err_code = CO_ER_NONE; s->si[1].conn->err_code = CO_ER_NONE;
s->si[1].conn->target = &s->be->obj_type;
s->si[1].owner = t; s->si[1].owner = t;
s->si[1].state = s->si[1].prev_state = SI_ST_ASS; s->si[1].state = s->si[1].prev_state = SI_ST_ASS;
s->si[1].conn_retries = p->conn_retries; s->si[1].conn_retries = p->conn_retries;
s->si[1].err_type = SI_ET_NONE; s->si[1].err_type = SI_ET_NONE;
s->si[1].send_proxy_ofs = 0; s->si[1].send_proxy_ofs = 0;
s->si[1].conn->target = &s->be->obj_type;
si_prepare_conn(&s->si[1], peer->proto, peer->xprt);
s->si[1].exp = TICK_ETERNITY; s->si[1].exp = TICK_ETERNITY;
s->si[1].flags = SI_FL_NONE; s->si[1].flags = SI_FL_NONE;
if (s->be->options2 & PR_O2_INDEPSTR) if (s->be->options2 & PR_O2_INDEPSTR)
s->si[1].flags |= SI_FL_INDEP_STR; s->si[1].flags |= SI_FL_INDEP_STR;
/* will automatically prepare the stream interface to connect to the
* pre-initialized connection in si->conn.
*/
si_prepare_conn(&s->si[1], peer->proto, peer->xprt);
session_init_srv_conn(s); session_init_srv_conn(s);
s->target = &s->be->obj_type; s->target = &s->be->obj_type;
s->pend_pos = NULL; s->pend_pos = NULL;

View File

@ -2488,12 +2488,12 @@ int http_wait_for_request(struct session *s, struct channel *req, int an_bit)
req->flags |= CF_READ_DONTWAIT; /* try to get back here ASAP */ req->flags |= CF_READ_DONTWAIT; /* try to get back here ASAP */
s->rep->flags &= ~CF_EXPECT_MORE; /* speed up sending a previous response */ s->rep->flags &= ~CF_EXPECT_MORE; /* speed up sending a previous response */
#ifdef TCP_QUICKACK #ifdef TCP_QUICKACK
if (s->listener->options & LI_O_NOQUICKACK && req->buf->i) { if (s->listener->options & LI_O_NOQUICKACK && req->buf->i && objt_conn(s->req->prod->end)) {
/* We need more data, we have to re-enable quick-ack in case we /* We need more data, we have to re-enable quick-ack in case we
* previously disabled it, otherwise we might cause the client * previously disabled it, otherwise we might cause the client
* to delay next data. * to delay next data.
*/ */
setsockopt(s->si[0].conn->t.sock.fd, IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one)); setsockopt(__objt_conn(s->req->prod->end)->t.sock.fd, IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
} }
#endif #endif
@ -2969,6 +2969,7 @@ static inline void inet_set_tos(int fd, struct sockaddr_storage from, int tos)
static struct http_req_rule * static struct http_req_rule *
http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct session *s, struct http_txn *txn) http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct session *s, struct http_txn *txn)
{ {
struct connection *cli_conn;
struct http_req_rule *rule; struct http_req_rule *rule;
struct hdr_ctx ctx; struct hdr_ctx ctx;
@ -3014,12 +3015,14 @@ http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct session
break; break;
case HTTP_REQ_ACT_SET_TOS: case HTTP_REQ_ACT_SET_TOS:
inet_set_tos(s->req->prod->conn->t.sock.fd, s->req->prod->conn->addr.from, rule->arg.tos); if ((cli_conn = objt_conn(s->req->prod->end)))
inet_set_tos(cli_conn->t.sock.fd, cli_conn->addr.from, rule->arg.tos);
break; break;
case HTTP_REQ_ACT_SET_MARK: case HTTP_REQ_ACT_SET_MARK:
#ifdef SO_MARK #ifdef SO_MARK
setsockopt(s->req->prod->conn->t.sock.fd, SOL_SOCKET, SO_MARK, &rule->arg.mark, sizeof(rule->arg.mark)); if ((cli_conn = objt_conn(s->req->prod->end)))
setsockopt(cli_conn->t.sock.fd, SOL_SOCKET, SO_MARK, &rule->arg.mark, sizeof(rule->arg.mark));
#endif #endif
break; break;
@ -3062,6 +3065,7 @@ http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct session
static struct http_res_rule * static struct http_res_rule *
http_res_get_intercept_rule(struct proxy *px, struct list *rules, struct session *s, struct http_txn *txn) http_res_get_intercept_rule(struct proxy *px, struct list *rules, struct session *s, struct http_txn *txn)
{ {
struct connection *cli_conn;
struct http_res_rule *rule; struct http_res_rule *rule;
struct hdr_ctx ctx; struct hdr_ctx ctx;
@ -3097,12 +3101,14 @@ http_res_get_intercept_rule(struct proxy *px, struct list *rules, struct session
break; break;
case HTTP_RES_ACT_SET_TOS: case HTTP_RES_ACT_SET_TOS:
inet_set_tos(s->req->prod->conn->t.sock.fd, s->req->prod->conn->addr.from, rule->arg.tos); if ((cli_conn = objt_conn(s->req->prod->end)))
inet_set_tos(cli_conn->t.sock.fd, cli_conn->addr.from, rule->arg.tos);
break; break;
case HTTP_RES_ACT_SET_MARK: case HTTP_RES_ACT_SET_MARK:
#ifdef SO_MARK #ifdef SO_MARK
setsockopt(s->req->prod->conn->t.sock.fd, SOL_SOCKET, SO_MARK, &rule->arg.mark, sizeof(rule->arg.mark)); if ((cli_conn = objt_conn(s->req->prod->end)))
setsockopt(cli_conn->t.sock.fd, SOL_SOCKET, SO_MARK, &rule->arg.mark, sizeof(rule->arg.mark));
#endif #endif
break; break;
@ -3684,6 +3690,7 @@ int http_process_request(struct session *s, struct channel *req, int an_bit)
{ {
struct http_txn *txn = &s->txn; struct http_txn *txn = &s->txn;
struct http_msg *msg = &txn->req; struct http_msg *msg = &txn->req;
struct connection *cli_conn = objt_conn(req->prod->end);
if (unlikely(msg->msg_state < HTTP_MSG_BODY)) { if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
/* we need more data */ /* we need more data */
@ -3711,8 +3718,9 @@ int http_process_request(struct session *s, struct channel *req, int an_bit)
*/ */
/* /*
* If HTTP PROXY is set we simply get remote server address * If HTTP PROXY is set we simply get remote server address parsing
* parsing incoming request. * incoming request. Note that this requires that a connection is
* allocated on the server side.
*/ */
if ((s->be->options & PR_O_HTTP_PROXY) && !(s->flags & SN_ADDR_SET)) { if ((s->be->options & PR_O_HTTP_PROXY) && !(s->flags & SN_ADDR_SET)) {
url2sa(req->buf->p + msg->sl.rq.u, msg->sl.rq.u_l, &s->req->cons->conn->addr.to); url2sa(req->buf->p + msg->sl.rq.u, msg->sl.rq.u_l, &s->req->cons->conn->addr.to);
@ -3769,19 +3777,19 @@ int http_process_request(struct session *s, struct channel *req, int an_bit)
* and we found it, so don't do anything. * and we found it, so don't do anything.
*/ */
} }
else if (s->req->prod->conn->addr.from.ss_family == AF_INET) { else if (cli_conn && cli_conn->addr.from.ss_family == AF_INET) {
/* Add an X-Forwarded-For header unless the source IP is /* Add an X-Forwarded-For header unless the source IP is
* in the 'except' network range. * in the 'except' network range.
*/ */
if ((!s->fe->except_mask.s_addr || if ((!s->fe->except_mask.s_addr ||
(((struct sockaddr_in *)&s->req->prod->conn->addr.from)->sin_addr.s_addr & s->fe->except_mask.s_addr) (((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr.s_addr & s->fe->except_mask.s_addr)
!= s->fe->except_net.s_addr) && != s->fe->except_net.s_addr) &&
(!s->be->except_mask.s_addr || (!s->be->except_mask.s_addr ||
(((struct sockaddr_in *)&s->req->prod->conn->addr.from)->sin_addr.s_addr & s->be->except_mask.s_addr) (((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr.s_addr & s->be->except_mask.s_addr)
!= s->be->except_net.s_addr)) { != s->be->except_net.s_addr)) {
int len; int len;
unsigned char *pn; unsigned char *pn;
pn = (unsigned char *)&((struct sockaddr_in *)&s->req->prod->conn->addr.from)->sin_addr; pn = (unsigned char *)&((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr;
/* Note: we rely on the backend to get the header name to be used for /* Note: we rely on the backend to get the header name to be used for
* x-forwarded-for, because the header is really meant for the backends. * x-forwarded-for, because the header is really meant for the backends.
@ -3801,14 +3809,14 @@ int http_process_request(struct session *s, struct channel *req, int an_bit)
goto return_bad_req; goto return_bad_req;
} }
} }
else if (s->req->prod->conn->addr.from.ss_family == AF_INET6) { else if (cli_conn && cli_conn->addr.from.ss_family == AF_INET6) {
/* FIXME: for the sake of completeness, we should also support /* FIXME: for the sake of completeness, we should also support
* 'except' here, although it is mostly useless in this case. * 'except' here, although it is mostly useless in this case.
*/ */
int len; int len;
char pn[INET6_ADDRSTRLEN]; char pn[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, inet_ntop(AF_INET6,
(const void *)&((struct sockaddr_in6 *)(&s->req->prod->conn->addr.from))->sin6_addr, (const void *)&((struct sockaddr_in6 *)(&cli_conn->addr.from))->sin6_addr,
pn, sizeof(pn)); pn, sizeof(pn));
/* Note: we rely on the backend to get the header name to be used for /* Note: we rely on the backend to get the header name to be used for
@ -3837,22 +3845,22 @@ int http_process_request(struct session *s, struct channel *req, int an_bit)
if ((s->fe->options | s->be->options) & PR_O_ORGTO) { if ((s->fe->options | s->be->options) & PR_O_ORGTO) {
/* FIXME: don't know if IPv6 can handle that case too. */ /* FIXME: don't know if IPv6 can handle that case too. */
if (s->req->prod->conn->addr.from.ss_family == AF_INET) { if (cli_conn && cli_conn->addr.from.ss_family == AF_INET) {
/* Add an X-Original-To header unless the destination IP is /* Add an X-Original-To header unless the destination IP is
* in the 'except' network range. * in the 'except' network range.
*/ */
conn_get_to_addr(s->req->prod->conn); conn_get_to_addr(cli_conn);
if (s->req->prod->conn->addr.to.ss_family == AF_INET && if (cli_conn->addr.to.ss_family == AF_INET &&
((!s->fe->except_mask_to.s_addr || ((!s->fe->except_mask_to.s_addr ||
(((struct sockaddr_in *)&s->req->prod->conn->addr.to)->sin_addr.s_addr & s->fe->except_mask_to.s_addr) (((struct sockaddr_in *)&cli_conn->addr.to)->sin_addr.s_addr & s->fe->except_mask_to.s_addr)
!= s->fe->except_to.s_addr) && != s->fe->except_to.s_addr) &&
(!s->be->except_mask_to.s_addr || (!s->be->except_mask_to.s_addr ||
(((struct sockaddr_in *)&s->req->prod->conn->addr.to)->sin_addr.s_addr & s->be->except_mask_to.s_addr) (((struct sockaddr_in *)&cli_conn->addr.to)->sin_addr.s_addr & s->be->except_mask_to.s_addr)
!= s->be->except_to.s_addr))) { != s->be->except_to.s_addr))) {
int len; int len;
unsigned char *pn; unsigned char *pn;
pn = (unsigned char *)&((struct sockaddr_in *)&s->req->prod->conn->addr.to)->sin_addr; pn = (unsigned char *)&((struct sockaddr_in *)&cli_conn->addr.to)->sin_addr;
/* Note: we rely on the backend to get the header name to be used for /* Note: we rely on the backend to get the header name to be used for
* x-original-to, because the header is really meant for the backends. * x-original-to, because the header is really meant for the backends.
@ -3922,9 +3930,10 @@ int http_process_request(struct session *s, struct channel *req, int an_bit)
* the client to delay further data. * the client to delay further data.
*/ */
if ((s->listener->options & LI_O_NOQUICKACK) && if ((s->listener->options & LI_O_NOQUICKACK) &&
cli_conn &&
((msg->flags & HTTP_MSGF_TE_CHNK) || ((msg->flags & HTTP_MSGF_TE_CHNK) ||
(msg->body_len > req->buf->i - txn->req.eoh - 2))) (msg->body_len > req->buf->i - txn->req.eoh - 2)))
setsockopt(s->si[0].conn->t.sock.fd, IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one)); setsockopt(cli_conn->t.sock.fd, IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
#endif #endif
} }
@ -4282,7 +4291,9 @@ void http_end_txn_clean_session(struct session *s)
s->target = NULL; s->target = NULL;
/* reinitialize the connection to the server */
s->req->cons->state = s->req->cons->prev_state = SI_ST_INI; s->req->cons->state = s->req->cons->prev_state = SI_ST_INI;
s->req->cons->end = NULL;
s->req->cons->conn->obj_type = OBJ_TYPE_CONN; s->req->cons->conn->obj_type = OBJ_TYPE_CONN;
s->req->cons->conn->t.sock.fd = -1; /* just to help with debugging */ s->req->cons->conn->t.sock.fd = -1; /* just to help with debugging */
s->req->cons->conn->flags = CO_FL_NONE; s->req->cons->conn->flags = CO_FL_NONE;
@ -7786,7 +7797,11 @@ void http_capture_bad_message(struct error_snapshot *es, struct session *s,
es->sid = s->uniq_id; es->sid = s->uniq_id;
es->srv = objt_server(s->target); es->srv = objt_server(s->target);
es->oe = other_end; es->oe = other_end;
es->src = s->req->prod->conn->addr.from; if (objt_conn(s->req->prod->end))
es->src = __objt_conn(s->req->prod->end)->addr.from;
else
memset(&es->src, 0, sizeof(es->src));
es->state = state; es->state = state;
es->ev_id = error_snapshot_id++; es->ev_id = error_snapshot_id++;
es->b_flags = chn->flags; es->b_flags = chn->flags;
@ -7939,8 +7954,9 @@ void debug_hdr(const char *dir, struct session *t, const char *start, const char
{ {
int max; int max;
chunk_printf(&trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id, chunk_printf(&trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
dir, (unsigned short)t->req->prod->conn->t.sock.fd, dir,
(unsigned short)t->req->cons->conn->t.sock.fd); objt_conn(t->req->prod->end) ? (unsigned short)objt_conn(t->req->prod->end)->t.sock.fd : -1,
objt_conn(t->req->cons->end) ? (unsigned short)objt_conn(t->req->cons->end)->t.sock.fd : -1);
for (max = 0; start + max < end; max++) for (max = 0; start + max < end; max++)
if (start[max] == '\r' || start[max] == '\n') if (start[max] == '\r' || start[max] == '\n')
@ -9264,6 +9280,10 @@ smp_fetch_base32_src(struct proxy *px, struct session *l4, void *l7, unsigned in
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
struct chunk *temp; struct chunk *temp;
struct connection *cli_conn = objt_conn(l4->si[0].end);
if (!cli_conn)
return 0;
if (!smp_fetch_base32(px, l4, l7, opt, args, smp, kw)) if (!smp_fetch_base32(px, l4, l7, opt, args, smp, kw))
return 0; return 0;
@ -9272,13 +9292,13 @@ smp_fetch_base32_src(struct proxy *px, struct session *l4, void *l7, unsigned in
memcpy(temp->str + temp->len, &smp->data.uint, sizeof(smp->data.uint)); memcpy(temp->str + temp->len, &smp->data.uint, sizeof(smp->data.uint));
temp->len += sizeof(smp->data.uint); temp->len += sizeof(smp->data.uint);
switch (l4->si[0].conn->addr.from.ss_family) { switch (cli_conn->addr.from.ss_family) {
case AF_INET: case AF_INET:
memcpy(temp->str + temp->len, &((struct sockaddr_in *)&l4->si[0].conn->addr.from)->sin_addr, 4); memcpy(temp->str + temp->len, &((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr, 4);
temp->len += 4; temp->len += 4;
break; break;
case AF_INET6: case AF_INET6:
memcpy(temp->str + temp->len, &((struct sockaddr_in6 *)(&l4->si[0].conn->addr.from))->sin6_addr, 16); memcpy(temp->str + temp->len, &((struct sockaddr_in6 *)&cli_conn->addr.from)->sin6_addr, 16);
temp->len += 16; temp->len += 16;
break; break;
default: default:
@ -9848,6 +9868,7 @@ smp_fetch_url32_src(struct proxy *px, struct session *l4, void *l7, unsigned int
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
struct chunk *temp; struct chunk *temp;
struct connection *cli_conn = objt_conn(l4->si[0].end);
if (!smp_fetch_url32(px, l4, l7, opt, args, smp, kw)) if (!smp_fetch_url32(px, l4, l7, opt, args, smp, kw))
return 0; return 0;
@ -9856,13 +9877,13 @@ smp_fetch_url32_src(struct proxy *px, struct session *l4, void *l7, unsigned int
memcpy(temp->str + temp->len, &smp->data.uint, sizeof(smp->data.uint)); memcpy(temp->str + temp->len, &smp->data.uint, sizeof(smp->data.uint));
temp->len += sizeof(smp->data.uint); temp->len += sizeof(smp->data.uint);
switch (l4->si[0].conn->addr.from.ss_family) { switch (cli_conn->addr.from.ss_family) {
case AF_INET: case AF_INET:
memcpy(temp->str + temp->len, &((struct sockaddr_in *)&l4->si[0].conn->addr.from)->sin_addr, 4); memcpy(temp->str + temp->len, &((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr, 4);
temp->len += 4; temp->len += 4;
break; break;
case AF_INET6: case AF_INET6:
memcpy(temp->str + temp->len, &((struct sockaddr_in6 *)(&l4->si[0].conn->addr.from))->sin6_addr, 16); memcpy(temp->str + temp->len, &((struct sockaddr_in6 *)&cli_conn->addr.from)->sin6_addr, 16);
temp->len += 16; temp->len += 16;
break; break;
default: default:

View File

@ -1086,16 +1086,20 @@ int tcp_inspect_response(struct session *s, struct channel *rep, int an_bit)
/* This function performs the TCP layer4 analysis on the current request. It /* This function performs the TCP layer4 analysis on the current request. It
* returns 0 if a reject rule matches, otherwise 1 if either an accept rule * returns 0 if a reject rule matches, otherwise 1 if either an accept rule
* matches or if no more rule matches. It can only use rules which don't need * matches or if no more rule matches. It can only use rules which don't need
* any data. * any data. This only works on connection-based client-facing stream interfaces.
*/ */
int tcp_exec_req_rules(struct session *s) int tcp_exec_req_rules(struct session *s)
{ {
struct tcp_rule *rule; struct tcp_rule *rule;
struct stksess *ts; struct stksess *ts;
struct stktable *t = NULL; struct stktable *t = NULL;
struct connection *conn = objt_conn(s->si[0].end);
int result = 1; int result = 1;
enum acl_test_res ret; enum acl_test_res ret;
if (!conn)
return result;
list_for_each_entry(rule, &s->fe->tcp_req.l4_rules, list) { list_for_each_entry(rule, &s->fe->tcp_req.l4_rules, list) {
ret = ACL_TEST_PASS; ret = ACL_TEST_PASS;
@ -1136,8 +1140,8 @@ int tcp_exec_req_rules(struct session *s)
session_track_stkctr(&s->stkctr[tcp_trk_idx(rule->action)], t, ts); session_track_stkctr(&s->stkctr[tcp_trk_idx(rule->action)], t, ts);
} }
else if (rule->action == TCP_ACT_EXPECT_PX) { else if (rule->action == TCP_ACT_EXPECT_PX) {
s->si[0].conn->flags |= CO_FL_ACCEPT_PROXY; conn->flags |= CO_FL_ACCEPT_PROXY;
conn_sock_want_recv(s->si[0].conn); conn_sock_want_recv(conn);
} }
else { else {
/* otherwise it's an accept */ /* otherwise it's an accept */
@ -1577,13 +1581,18 @@ static int
smp_fetch_src(struct proxy *px, struct session *l4, void *l7, unsigned int opt, smp_fetch_src(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
switch (l4->si[0].conn->addr.from.ss_family) { struct connection *cli_conn = objt_conn(l4->si[0].end);
if (!cli_conn)
return 0;
switch (cli_conn->addr.from.ss_family) {
case AF_INET: case AF_INET:
smp->data.ipv4 = ((struct sockaddr_in *)&l4->si[0].conn->addr.from)->sin_addr; smp->data.ipv4 = ((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr;
smp->type = SMP_T_IPV4; smp->type = SMP_T_IPV4;
break; break;
case AF_INET6: case AF_INET6:
smp->data.ipv6 = ((struct sockaddr_in6 *)(&l4->si[0].conn->addr.from))->sin6_addr; smp->data.ipv6 = ((struct sockaddr_in6 *)&cli_conn->addr.from)->sin6_addr;
smp->type = SMP_T_IPV6; smp->type = SMP_T_IPV6;
break; break;
default: default:
@ -1599,8 +1608,13 @@ static int
smp_fetch_sport(struct proxy *px, struct session *l4, void *l7, unsigned int opt, smp_fetch_sport(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
struct connection *cli_conn = objt_conn(l4->si[0].end);
if (!cli_conn)
return 0;
smp->type = SMP_T_UINT; smp->type = SMP_T_UINT;
if (!(smp->data.uint = get_host_port(&l4->si[0].conn->addr.from))) if (!(smp->data.uint = get_host_port(&cli_conn->addr.from)))
return 0; return 0;
smp->flags = 0; smp->flags = 0;
@ -1612,15 +1626,20 @@ static int
smp_fetch_dst(struct proxy *px, struct session *l4, void *l7, unsigned int opt, smp_fetch_dst(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
conn_get_to_addr(l4->si[0].conn); struct connection *cli_conn = objt_conn(l4->si[0].end);
switch (l4->si[0].conn->addr.to.ss_family) { if (!cli_conn)
return 0;
conn_get_to_addr(cli_conn);
switch (cli_conn->addr.to.ss_family) {
case AF_INET: case AF_INET:
smp->data.ipv4 = ((struct sockaddr_in *)&l4->si[0].conn->addr.to)->sin_addr; smp->data.ipv4 = ((struct sockaddr_in *)&cli_conn->addr.to)->sin_addr;
smp->type = SMP_T_IPV4; smp->type = SMP_T_IPV4;
break; break;
case AF_INET6: case AF_INET6:
smp->data.ipv6 = ((struct sockaddr_in6 *)(&l4->si[0].conn->addr.to))->sin6_addr; smp->data.ipv6 = ((struct sockaddr_in6 *)&cli_conn->addr.to)->sin6_addr;
smp->type = SMP_T_IPV6; smp->type = SMP_T_IPV6;
break; break;
default: default:
@ -1636,10 +1655,15 @@ static int
smp_fetch_dport(struct proxy *px, struct session *l4, void *l7, unsigned int opt, smp_fetch_dport(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
conn_get_to_addr(l4->si[0].conn); struct connection *cli_conn = objt_conn(l4->si[0].end);
if (!cli_conn)
return 0;
conn_get_to_addr(cli_conn);
smp->type = SMP_T_UINT; smp->type = SMP_T_UINT;
if (!(smp->data.uint = get_host_port(&l4->si[0].conn->addr.to))) if (!(smp->data.uint = get_host_port(&cli_conn->addr.to)))
return 0; return 0;
smp->flags = 0; smp->flags = 0;

View File

@ -72,6 +72,7 @@ struct data_cb sess_conn_cb = {
*/ */
int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr) int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr)
{ {
struct connection *cli_conn;
struct proxy *p = l->frontend; struct proxy *p = l->frontend;
struct session *s; struct session *s;
struct task *t; struct task *t;
@ -83,7 +84,7 @@ int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr)
if (unlikely((s = pool_alloc2(pool2_session)) == NULL)) if (unlikely((s = pool_alloc2(pool2_session)) == NULL))
goto out_close; goto out_close;
if (unlikely((s->si[0].conn = pool_alloc2(pool2_connection)) == NULL)) if (unlikely((cli_conn = s->si[0].conn = pool_alloc2(pool2_connection)) == NULL))
goto out_fail_conn0; goto out_fail_conn0;
if (unlikely((s->si[1].conn = pool_alloc2(pool2_connection)) == NULL)) if (unlikely((s->si[1].conn = pool_alloc2(pool2_connection)) == NULL))
@ -104,19 +105,21 @@ int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr)
s->listener = l; s->listener = l;
s->fe = p; s->fe = p;
/* OK, we're keeping the session, so let's properly initialize the session */ /* OK, we're keeping the session, so let's properly initialize the session.
s->si[0].conn->obj_type = OBJ_TYPE_CONN; * We first have to initialize the client-side connection.
s->si[0].conn->t.sock.fd = cfd;
s->si[0].conn->ctrl = l->proto;
s->si[0].conn->flags = CO_FL_NONE | CO_FL_ADDR_FROM_SET;
s->si[0].conn->err_code = CO_ER_NONE;
s->si[0].conn->addr.from = *addr;
s->si[0].conn->target = &l->obj_type;
/* FIXME: this should be replaced with OBJ_TYPE_NONE once all users check the
* object type before dereferencing the connection pointer.
*/ */
s->si[1].conn->obj_type = OBJ_TYPE_CONN; cli_conn->obj_type = OBJ_TYPE_CONN;
cli_conn->t.sock.fd = cfd;
cli_conn->ctrl = l->proto;
cli_conn->flags = CO_FL_NONE | CO_FL_ADDR_FROM_SET;
cli_conn->err_code = CO_ER_NONE;
cli_conn->addr.from = *addr;
cli_conn->target = &l->obj_type;
/* The server side is not used yet, but just initialize it to avoid
* confusing some debugging or "show sess" for example.
*/
s->si[1].conn->obj_type = OBJ_TYPE_NONE;
s->logs.accept_date = date; /* user-visible date for logging */ s->logs.accept_date = date; /* user-visible date for logging */
s->logs.tv_accept = now; /* corrected date for internal use */ s->logs.tv_accept = now; /* corrected date for internal use */
@ -178,8 +181,8 @@ int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr)
/* wait for a PROXY protocol header */ /* wait for a PROXY protocol header */
if (l->options & LI_O_ACC_PROXY) { if (l->options & LI_O_ACC_PROXY) {
s->si[0].conn->flags |= CO_FL_ACCEPT_PROXY; cli_conn->flags |= CO_FL_ACCEPT_PROXY;
conn_sock_want_recv(s->si[0].conn); conn_sock_want_recv(cli_conn);
} }
if (unlikely((t = task_new()) == NULL)) if (unlikely((t = task_new()) == NULL))
@ -193,14 +196,14 @@ int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr)
* but not initialized. Also note we need to be careful as the stream * but not initialized. Also note we need to be careful as the stream
* int is not initialized yet. * int is not initialized yet.
*/ */
conn_prepare(s->si[0].conn, &sess_conn_cb, l->proto, l->xprt, s); conn_prepare(cli_conn, &sess_conn_cb, l->proto, l->xprt, s);
/* finish initialization of the accepted file descriptor */ /* finish initialization of the accepted file descriptor */
fd_insert(cfd); fd_insert(cfd);
fdtab[cfd].owner = s->si[0].conn; fdtab[cfd].owner = cli_conn;
fdtab[cfd].iocb = conn_fd_handler; fdtab[cfd].iocb = conn_fd_handler;
conn_data_want_recv(s->si[0].conn); conn_data_want_recv(cli_conn);
if (conn_xprt_init(s->si[0].conn) < 0) if (conn_xprt_init(cli_conn) < 0)
goto out_free_task; goto out_free_task;
/* OK, now either we have a pending handshake to execute with and /* OK, now either we have a pending handshake to execute with and
@ -209,16 +212,16 @@ int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr)
* set the I/O timeout to the frontend's client timeout. * set the I/O timeout to the frontend's client timeout.
*/ */
if (s->si[0].conn->flags & CO_FL_HANDSHAKE) { if (cli_conn->flags & CO_FL_HANDSHAKE) {
t->process = expire_mini_session; t->process = expire_mini_session;
t->expire = tick_add_ifset(now_ms, p->timeout.client); t->expire = tick_add_ifset(now_ms, p->timeout.client);
task_queue(t); task_queue(t);
s->si[0].conn->flags |= CO_FL_INIT_DATA | CO_FL_WAKE_DATA; cli_conn->flags |= CO_FL_INIT_DATA | CO_FL_WAKE_DATA;
return 1; return 1;
} }
/* OK let's complete session initialization since there is no handshake */ /* OK let's complete session initialization since there is no handshake */
s->si[0].conn->flags |= CO_FL_CONNECTED; cli_conn->flags |= CO_FL_CONNECTED;
ret = session_complete(s); ret = session_complete(s);
if (ret > 0) if (ret > 0)
return ret; return ret;
@ -252,21 +255,24 @@ int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr)
} }
/* prepare the trash with a log prefix for session <s> */ /* prepare the trash with a log prefix for session <s>. It only works with
* embryonic sessions based on a real connection.
*/
static void prepare_mini_sess_log_prefix(struct session *s) static void prepare_mini_sess_log_prefix(struct session *s)
{ {
struct tm tm; struct tm tm;
char pn[INET6_ADDRSTRLEN]; char pn[INET6_ADDRSTRLEN];
int ret; int ret;
char *end; char *end;
struct connection *cli_conn = s->si[0].conn;
ret = addr_to_str(&s->si[0].conn->addr.from, pn, sizeof(pn)); ret = addr_to_str(&cli_conn->addr.from, pn, sizeof(pn));
if (ret <= 0) if (ret <= 0)
chunk_printf(&trash, "unknown ["); chunk_printf(&trash, "unknown [");
else if (ret == AF_UNIX) else if (ret == AF_UNIX)
chunk_printf(&trash, "%s:%d [", pn, s->listener->luid); chunk_printf(&trash, "%s:%d [", pn, s->listener->luid);
else else
chunk_printf(&trash, "%s:%d [", pn, get_host_port(&s->si[0].conn->addr.from)); chunk_printf(&trash, "%s:%d [", pn, get_host_port(&cli_conn->addr.from));
get_localtime(s->logs.accept_date.tv_sec, &tm); get_localtime(s->logs.accept_date.tv_sec, &tm);
end = date2str_log(trash.str + trash.len, &tm, &(s->logs.accept_date), trash.size - trash.len); end = date2str_log(trash.str + trash.len, &tm, &(s->logs.accept_date), trash.size - trash.len);
@ -317,7 +323,7 @@ static void kill_mini_session(struct session *s)
} }
/* kill the connection now */ /* kill the connection now */
conn_full_close(s->si[0].conn); conn_full_close(conn);
s->fe->feconn--; s->fe->feconn--;
session_store_counters(s); session_store_counters(s);
@ -393,6 +399,7 @@ static struct task *expire_mini_session(struct task *t)
* be called with an embryonic session. It returns a positive value upon * be called with an embryonic session. It returns a positive value upon
* success, 0 if the connection can be ignored, or a negative value upon * success, 0 if the connection can be ignored, or a negative value upon
* critical failure. The accepted file descriptor is closed if we return <= 0. * critical failure. The accepted file descriptor is closed if we return <= 0.
* The client-side end point is assumed to be a connection.
*/ */
int session_complete(struct session *s) int session_complete(struct session *s)
{ {
@ -462,15 +469,17 @@ int session_complete(struct session *s)
s->si[1].conn->t.sock.fd = -1; /* just to help with debugging */ s->si[1].conn->t.sock.fd = -1; /* just to help with debugging */
s->si[1].conn->flags = CO_FL_NONE; s->si[1].conn->flags = CO_FL_NONE;
s->si[1].conn->err_code = CO_ER_NONE; s->si[1].conn->err_code = CO_ER_NONE;
s->si[1].conn->target = NULL;
s->si[1].owner = t; s->si[1].owner = t;
s->si[1].state = s->si[1].prev_state = SI_ST_INI; s->si[1].state = s->si[1].prev_state = SI_ST_INI;
s->si[1].err_type = SI_ET_NONE; s->si[1].err_type = SI_ET_NONE;
s->si[1].conn_retries = 0; /* used for logging too */ s->si[1].conn_retries = 0; /* used for logging too */
s->si[1].send_proxy_ofs = 0; s->si[1].send_proxy_ofs = 0;
si_prepare_none(&s->si[1]);
s->si[1].exp = TICK_ETERNITY; s->si[1].exp = TICK_ETERNITY;
s->si[1].flags = SI_FL_NONE; s->si[1].flags = SI_FL_NONE;
si_prepare_none(&s->si[1]);
if (likely(s->fe->options2 & PR_O2_INDEPSTR)) if (likely(s->fe->options2 & PR_O2_INDEPSTR))
s->si[1].flags |= SI_FL_INDEP_STR; s->si[1].flags |= SI_FL_INDEP_STR;
@ -549,7 +558,7 @@ int session_complete(struct session *s)
txn->rsp.chn = s->rep; txn->rsp.chn = s->rep;
/* finish initialization of the accepted file descriptor */ /* finish initialization of the accepted file descriptor */
conn_data_want_recv(s->si[0].conn); conn_data_want_recv(__objt_conn(s->si[0].end));
if (p->accept && (ret = p->accept(s)) <= 0) { if (p->accept && (ret = p->accept(s)) <= 0) {
/* Either we had an unrecoverable error (<0) or work is /* Either we had an unrecoverable error (<0) or work is
@ -561,10 +570,10 @@ int session_complete(struct session *s)
/* if logs require transport layer information, note it on the connection */ /* if logs require transport layer information, note it on the connection */
if (s->logs.logwait & LW_XPRT) if (s->logs.logwait & LW_XPRT)
s->si[0].conn->flags |= CO_FL_XPRT_TRACKED; __objt_conn(s->si[0].end)->flags |= CO_FL_XPRT_TRACKED;
/* we want the connection handler to notify the stream interface about updates. */ /* we want the connection handler to notify the stream interface about updates. */
s->si[0].conn->flags |= CO_FL_WAKE_DATA; __objt_conn(s->si[0].end)->flags |= CO_FL_WAKE_DATA;
/* it is important not to call the wakeup function directly but to /* it is important not to call the wakeup function directly but to
* pass through task_wakeup(), because this one knows how to apply * pass through task_wakeup(), because this one knows how to apply
@ -594,6 +603,7 @@ static void session_free(struct session *s)
struct http_txn *txn = &s->txn; struct http_txn *txn = &s->txn;
struct proxy *fe = s->fe; struct proxy *fe = s->fe;
struct bref *bref, *back; struct bref *bref, *back;
struct connection *cli_conn = objt_conn(s->si[0].end);
int i; int i;
if (s->pend_pos) if (s->pend_pos)
@ -636,8 +646,10 @@ static void session_free(struct session *s)
http_end_txn(s); http_end_txn(s);
/* ensure the client-side transport layer is destroyed */ /* ensure the client-side transport layer is destroyed */
s->si[0].conn->flags &= ~CO_FL_XPRT_TRACKED; if (cli_conn) {
conn_full_close(s->si[0].conn); cli_conn->flags &= ~CO_FL_XPRT_TRACKED;
conn_full_close(cli_conn);
}
for (i = 0; i < s->store_count; i++) { for (i = 0; i < s->store_count; i++) {
if (!s->store[i].ts) if (!s->store[i].ts)
@ -771,12 +783,13 @@ void session_process_counters(struct session *s)
* We must check for establishment, error and abort. Possible output states * We must check for establishment, error and abort. Possible output states
* are SI_ST_EST (established), SI_ST_CER (error), SI_ST_DIS (abort), and * are SI_ST_EST (established), SI_ST_CER (error), SI_ST_DIS (abort), and
* SI_ST_CON (no change). The function returns 0 if it switches to SI_ST_CER, * SI_ST_CON (no change). The function returns 0 if it switches to SI_ST_CER,
* otherwise 1. * otherwise 1. This only works with connection-based sessions.
*/ */
static int sess_update_st_con_tcp(struct session *s, struct stream_interface *si) static int sess_update_st_con_tcp(struct session *s, struct stream_interface *si)
{ {
struct channel *req = si->ob; struct channel *req = si->ob;
struct channel *rep = si->ib; struct channel *rep = si->ib;
struct connection *srv_conn = __objt_conn(si->end);
/* If we got an error, or if nothing happened and the connection timed /* If we got an error, or if nothing happened and the connection timed
* out, we must give up. The CER state handler will take care of retry * out, we must give up. The CER state handler will take care of retry
@ -798,8 +811,8 @@ static int sess_update_st_con_tcp(struct session *s, struct stream_interface *si
si->exp = TICK_ETERNITY; si->exp = TICK_ETERNITY;
si->state = SI_ST_CER; si->state = SI_ST_CER;
si->conn->flags &= ~CO_FL_XPRT_TRACKED; srv_conn->flags &= ~CO_FL_XPRT_TRACKED;
conn_full_close(si->conn); conn_full_close(srv_conn);
if (si->err_type) if (si->err_type)
return 0; return 0;
@ -954,7 +967,7 @@ static void sess_establish(struct session *s, struct stream_interface *si)
rep->analysers |= s->fe->fe_rsp_ana | s->be->be_rsp_ana; rep->analysers |= s->fe->fe_rsp_ana | s->be->be_rsp_ana;
rep->flags |= CF_READ_ATTACHED; /* producer is now attached */ rep->flags |= CF_READ_ATTACHED; /* producer is now attached */
if (si->conn->ctrl) { if (objt_conn(si->end)) {
/* real connections have timeouts */ /* real connections have timeouts */
req->wto = s->be->timeout.server; req->wto = s->be->timeout.server;
rep->rto = s->be->timeout.server; rep->rto = s->be->timeout.server;
@ -2130,8 +2143,8 @@ struct task *process_session(struct task *t)
if (!(s->req->flags & (CF_KERN_SPLICING|CF_SHUTR)) && if (!(s->req->flags & (CF_KERN_SPLICING|CF_SHUTR)) &&
s->req->to_forward && s->req->to_forward &&
(global.tune.options & GTUNE_USE_SPLICE) && (global.tune.options & GTUNE_USE_SPLICE) &&
(s->si[0].conn->xprt && s->si[0].conn->xprt->rcv_pipe && s->si[0].conn->xprt->snd_pipe) && (objt_conn(s->si[0].end) && __objt_conn(s->si[0].end)->xprt && __objt_conn(s->si[0].end)->xprt->rcv_pipe) &&
(s->si[1].conn->xprt && s->si[1].conn->xprt->rcv_pipe && s->si[1].conn->xprt->snd_pipe) && (objt_conn(s->si[1].end) && __objt_conn(s->si[1].end)->xprt && __objt_conn(s->si[1].end)->xprt->snd_pipe) &&
(pipes_used < global.maxpipes) && (pipes_used < global.maxpipes) &&
(((s->fe->options2|s->be->options2) & PR_O2_SPLIC_REQ) || (((s->fe->options2|s->be->options2) & PR_O2_SPLIC_REQ) ||
(((s->fe->options2|s->be->options2) & PR_O2_SPLIC_AUT) && (((s->fe->options2|s->be->options2) & PR_O2_SPLIC_AUT) &&
@ -2278,8 +2291,8 @@ struct task *process_session(struct task *t)
if (!(s->rep->flags & (CF_KERN_SPLICING|CF_SHUTR)) && if (!(s->rep->flags & (CF_KERN_SPLICING|CF_SHUTR)) &&
s->rep->to_forward && s->rep->to_forward &&
(global.tune.options & GTUNE_USE_SPLICE) && (global.tune.options & GTUNE_USE_SPLICE) &&
(s->si[0].conn->xprt && s->si[0].conn->xprt->rcv_pipe && s->si[0].conn->xprt->snd_pipe) && (objt_conn(s->si[0].end) && __objt_conn(s->si[0].end)->xprt && __objt_conn(s->si[0].end)->xprt->snd_pipe) &&
(s->si[1].conn->xprt && s->si[1].conn->xprt->rcv_pipe && s->si[1].conn->xprt->snd_pipe) && (objt_conn(s->si[1].end) && __objt_conn(s->si[1].end)->xprt && __objt_conn(s->si[1].end)->xprt->rcv_pipe) &&
(pipes_used < global.maxpipes) && (pipes_used < global.maxpipes) &&
(((s->fe->options2|s->be->options2) & PR_O2_SPLIC_RTR) || (((s->fe->options2|s->be->options2) & PR_O2_SPLIC_RTR) ||
(((s->fe->options2|s->be->options2) & PR_O2_SPLIC_AUT) && (((s->fe->options2|s->be->options2) & PR_O2_SPLIC_AUT) &&
@ -2345,8 +2358,8 @@ struct task *process_session(struct task *t)
s->si[1].prev_state == SI_ST_EST) { s->si[1].prev_state == SI_ST_EST) {
chunk_printf(&trash, "%08x:%s.srvcls[%04x:%04x]\n", chunk_printf(&trash, "%08x:%s.srvcls[%04x:%04x]\n",
s->uniq_id, s->be->id, s->uniq_id, s->be->id,
(unsigned short)s->si[0].conn->t.sock.fd, objt_conn(s->si[0].end) ? (unsigned short)objt_conn(s->si[0].end)->t.sock.fd : -1,
(unsigned short)s->si[1].conn->t.sock.fd); objt_conn(s->si[1].end) ? (unsigned short)objt_conn(s->si[1].end)->t.sock.fd : -1);
if (write(1, trash.str, trash.len) < 0) /* shut gcc warning */; if (write(1, trash.str, trash.len) < 0) /* shut gcc warning */;
} }
@ -2354,8 +2367,8 @@ struct task *process_session(struct task *t)
s->si[0].prev_state == SI_ST_EST) { s->si[0].prev_state == SI_ST_EST) {
chunk_printf(&trash, "%08x:%s.clicls[%04x:%04x]\n", chunk_printf(&trash, "%08x:%s.clicls[%04x:%04x]\n",
s->uniq_id, s->be->id, s->uniq_id, s->be->id,
(unsigned short)s->si[0].conn->t.sock.fd, objt_conn(s->si[0].end) ? (unsigned short)objt_conn(s->si[0].end)->t.sock.fd : -1,
(unsigned short)s->si[1].conn->t.sock.fd); objt_conn(s->si[1].end) ? (unsigned short)objt_conn(s->si[1].end)->t.sock.fd : -1);
if (write(1, trash.str, trash.len) < 0) /* shut gcc warning */; if (write(1, trash.str, trash.len) < 0) /* shut gcc warning */;
} }
} }
@ -2459,8 +2472,8 @@ struct task *process_session(struct task *t)
(!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) { (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
chunk_printf(&trash, "%08x:%s.closed[%04x:%04x]\n", chunk_printf(&trash, "%08x:%s.closed[%04x:%04x]\n",
s->uniq_id, s->be->id, s->uniq_id, s->be->id,
(unsigned short)s->req->prod->conn->t.sock.fd, objt_conn(s->si[0].end) ? (unsigned short)objt_conn(s->si[0].end)->t.sock.fd : -1,
(unsigned short)s->req->cons->conn->t.sock.fd); objt_conn(s->si[1].end) ? (unsigned short)objt_conn(s->si[1].end)->t.sock.fd : -1);
if (write(1, trash.str, trash.len) < 0) /* shut gcc warning */; if (write(1, trash.str, trash.len) < 0) /* shut gcc warning */;
} }
@ -2619,10 +2632,16 @@ smp_fetch_sc_stkctr(struct session *l4, const struct arg *args, const char *kw)
return NULL; return NULL;
} }
else if (num > 9) { /* src_* variant, args[0] = table */ else if (num > 9) { /* src_* variant, args[0] = table */
struct stktable_key *key = addr_to_stktable_key(&l4->si[0].conn->addr.from); struct stktable_key *key;
struct connection *conn = objt_conn(l4->si[0].end);
if (!conn)
return NULL;
key = addr_to_stktable_key(&conn->addr.from);
if (!key) if (!key)
return NULL; return NULL;
stkctr.table = &args->data.prx->table; stkctr.table = &args->data.prx->table;
stkctr.entry = stktable_lookup_key(stkctr.table, key); stkctr.entry = stktable_lookup_key(stkctr.table, key);
return &stkctr; return &stkctr;
@ -2831,11 +2850,15 @@ static int
smp_fetch_src_updt_conn_cnt(struct proxy *px, struct session *l4, void *l7, unsigned int opt, smp_fetch_src_updt_conn_cnt(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
struct connection *conn = objt_conn(l4->si[0].end);
struct stksess *ts; struct stksess *ts;
struct stktable_key *key; struct stktable_key *key;
void *ptr; void *ptr;
key = addr_to_stktable_key(&l4->si[0].conn->addr.from); if (!conn)
return 0;
key = addr_to_stktable_key(&conn->addr.from);
if (!key) if (!key)
return 0; return 0;

View File

@ -1704,17 +1704,23 @@ static int
smp_fetch_ssl_fc_has_crt(struct proxy *px, struct session *l4, void *l7, unsigned int opt, smp_fetch_ssl_fc_has_crt(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) struct connection *conn;
if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE; smp->flags |= SMP_F_MAY_CHANGE;
return 0; return 0;
} }
smp->flags = 0; smp->flags = 0;
smp->type = SMP_T_BOOL; smp->type = SMP_T_BOOL;
smp->data.uint = SSL_SOCK_ST_FL_VERIFY_DONE & l4->si[0].conn->xprt_st ? 1 : 0; smp->data.uint = SSL_SOCK_ST_FL_VERIFY_DONE & conn->xprt_st ? 1 : 0;
return 1; return 1;
} }
@ -1727,17 +1733,22 @@ smp_fetch_ssl_c_serial(struct proxy *px, struct session *l4, void *l7, unsigned
X509 *crt = NULL; X509 *crt = NULL;
int ret = 0; int ret = 0;
struct chunk *smp_trash; struct chunk *smp_trash;
struct connection *conn;
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE; smp->flags |= SMP_F_MAY_CHANGE;
return 0; return 0;
} }
/* SSL_get_peer_certificate, it increase X509 * ref count */ /* SSL_get_peer_certificate, it increase X509 * ref count */
crt = SSL_get_peer_certificate(l4->si[0].conn->xprt_ctx); crt = SSL_get_peer_certificate(conn->xprt_ctx);
if (!crt) if (!crt)
goto out; goto out;
@ -1763,17 +1774,22 @@ smp_fetch_ssl_c_sha1(struct proxy *px, struct session *l4, void *l7, unsigned in
const EVP_MD *digest; const EVP_MD *digest;
int ret = 0; int ret = 0;
struct chunk *smp_trash; struct chunk *smp_trash;
struct connection *conn;
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE; smp->flags |= SMP_F_MAY_CHANGE;
return 0; return 0;
} }
/* SSL_get_peer_certificate, it increase X509 * ref count */ /* SSL_get_peer_certificate, it increase X509 * ref count */
crt = SSL_get_peer_certificate(l4->si[0].conn->xprt_ctx); crt = SSL_get_peer_certificate(conn->xprt_ctx);
if (!crt) if (!crt)
goto out; goto out;
@ -1798,17 +1814,22 @@ smp_fetch_ssl_c_notafter(struct proxy *px, struct session *l4, void *l7, unsigne
X509 *crt = NULL; X509 *crt = NULL;
int ret = 0; int ret = 0;
struct chunk *smp_trash; struct chunk *smp_trash;
struct connection *conn;
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE; smp->flags |= SMP_F_MAY_CHANGE;
return 0; return 0;
} }
/* SSL_get_peer_certificate, it increase X509 * ref count */ /* SSL_get_peer_certificate, it increase X509 * ref count */
crt = SSL_get_peer_certificate(l4->si[0].conn->xprt_ctx); crt = SSL_get_peer_certificate(conn->xprt_ctx);
if (!crt) if (!crt)
goto out; goto out;
@ -1834,17 +1855,22 @@ smp_fetch_ssl_c_i_dn(struct proxy *px, struct session *l4, void *l7, unsigned in
X509_NAME *name; X509_NAME *name;
int ret = 0; int ret = 0;
struct chunk *smp_trash; struct chunk *smp_trash;
struct connection *conn;
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE; smp->flags |= SMP_F_MAY_CHANGE;
return 0; return 0;
} }
/* SSL_get_peer_certificate, it increase X509 * ref count */ /* SSL_get_peer_certificate, it increase X509 * ref count */
crt = SSL_get_peer_certificate(l4->si[0].conn->xprt_ctx); crt = SSL_get_peer_certificate(conn->xprt_ctx);
if (!crt) if (!crt)
goto out; goto out;
@ -1884,17 +1910,22 @@ smp_fetch_ssl_c_notbefore(struct proxy *px, struct session *l4, void *l7, unsign
X509 *crt = NULL; X509 *crt = NULL;
int ret = 0; int ret = 0;
struct chunk *smp_trash; struct chunk *smp_trash;
struct connection *conn;
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE; smp->flags |= SMP_F_MAY_CHANGE;
return 0; return 0;
} }
/* SSL_get_peer_certificate, it increase X509 * ref count */ /* SSL_get_peer_certificate, it increase X509 * ref count */
crt = SSL_get_peer_certificate(l4->si[0].conn->xprt_ctx); crt = SSL_get_peer_certificate(conn->xprt_ctx);
if (!crt) if (!crt)
goto out; goto out;
@ -1920,17 +1951,22 @@ smp_fetch_ssl_c_s_dn(struct proxy *px, struct session *l4, void *l7, unsigned in
X509_NAME *name; X509_NAME *name;
int ret = 0; int ret = 0;
struct chunk *smp_trash; struct chunk *smp_trash;
struct connection *conn;
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE; smp->flags |= SMP_F_MAY_CHANGE;
return 0; return 0;
} }
/* SSL_get_peer_certificate, it increase X509 * ref count */ /* SSL_get_peer_certificate, it increase X509 * ref count */
crt = SSL_get_peer_certificate(l4->si[0].conn->xprt_ctx); crt = SSL_get_peer_certificate(conn->xprt_ctx);
if (!crt) if (!crt)
goto out; goto out;
@ -1968,17 +2004,22 @@ smp_fetch_ssl_c_used(struct proxy *px, struct session *l4, void *l7, unsigned in
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
X509 *crt; X509 *crt;
struct connection *conn;
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE; smp->flags |= SMP_F_MAY_CHANGE;
return 0; return 0;
} }
/* SSL_get_peer_certificate returns a ptr on allocated X509 struct */ /* SSL_get_peer_certificate returns a ptr on allocated X509 struct */
crt = SSL_get_peer_certificate(l4->si[0].conn->xprt_ctx); crt = SSL_get_peer_certificate(conn->xprt_ctx);
if (crt) { if (crt) {
X509_free(crt); X509_free(crt);
} }
@ -1994,17 +2035,22 @@ smp_fetch_ssl_c_version(struct proxy *px, struct session *l4, void *l7, unsigned
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
X509 *crt; X509 *crt;
struct connection *conn;
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE; smp->flags |= SMP_F_MAY_CHANGE;
return 0; return 0;
} }
/* SSL_get_peer_certificate returns a ptr on allocated X509 struct */ /* SSL_get_peer_certificate returns a ptr on allocated X509 struct */
crt = SSL_get_peer_certificate(l4->si[0].conn->xprt_ctx); crt = SSL_get_peer_certificate(conn->xprt_ctx);
if (!crt) if (!crt)
return 0; return 0;
@ -2022,17 +2068,22 @@ smp_fetch_ssl_c_sig_alg(struct proxy *px, struct session *l4, void *l7, unsigned
{ {
X509 *crt; X509 *crt;
int nid; int nid;
struct connection *conn;
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE; smp->flags |= SMP_F_MAY_CHANGE;
return 0; return 0;
} }
/* SSL_get_peer_certificate increase X509 * ref count */ /* SSL_get_peer_certificate increase X509 * ref count */
crt = SSL_get_peer_certificate(l4->si[0].conn->xprt_ctx); crt = SSL_get_peer_certificate(conn->xprt_ctx);
if (!crt) if (!crt)
return 0; return 0;
@ -2058,17 +2109,22 @@ smp_fetch_ssl_c_key_alg(struct proxy *px, struct session *l4, void *l7, unsigned
{ {
X509 *crt; X509 *crt;
int nid; int nid;
struct connection *conn;
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE; smp->flags |= SMP_F_MAY_CHANGE;
return 0; return 0;
} }
/* SSL_get_peer_certificate increase X509 * ref count */ /* SSL_get_peer_certificate increase X509 * ref count */
crt = SSL_get_peer_certificate(l4->si[0].conn->xprt_ctx); crt = SSL_get_peer_certificate(conn->xprt_ctx);
if (!crt) if (!crt)
return 0; return 0;
@ -2092,8 +2148,10 @@ static int
smp_fetch_ssl_fc(struct proxy *px, struct session *l4, void *l7, unsigned int opt, smp_fetch_ssl_fc(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
struct connection *conn = objt_conn(l4->si[0].end);
smp->type = SMP_T_BOOL; smp->type = SMP_T_BOOL;
smp->data.uint = (l4->si[0].conn->xprt == &ssl_sock); smp->data.uint = (conn && conn->xprt == &ssl_sock);
return 1; return 1;
} }
@ -2103,10 +2161,12 @@ smp_fetch_ssl_fc_has_sni(struct proxy *px, struct session *l4, void *l7, unsigne
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
struct connection *conn = objt_conn(l4->si[0].end);
smp->type = SMP_T_BOOL; smp->type = SMP_T_BOOL;
smp->data.uint = (l4->si[0].conn->xprt == &ssl_sock) && smp->data.uint = (conn && conn->xprt == &ssl_sock) &&
l4->si[0].conn->xprt_ctx && conn->xprt_ctx &&
SSL_get_servername(l4->si[0].conn->xprt_ctx, TLSEXT_NAMETYPE_host_name) != NULL; SSL_get_servername(conn->xprt_ctx, TLSEXT_NAMETYPE_host_name) != NULL;
return 1; return 1;
#else #else
return 0; return 0;
@ -2121,16 +2181,21 @@ smp_fetch_ssl_f_serial(struct proxy *px, struct session *l4, void *l7, unsigned
X509 *crt = NULL; X509 *crt = NULL;
int ret = 0; int ret = 0;
struct chunk *smp_trash; struct chunk *smp_trash;
struct connection *conn;
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE; smp->flags |= SMP_F_MAY_CHANGE;
return 0; return 0;
} }
crt = SSL_get_certificate(l4->si[0].conn->xprt_ctx); crt = SSL_get_certificate(conn->xprt_ctx);
if (!crt) if (!crt)
goto out; goto out;
@ -2152,16 +2217,21 @@ smp_fetch_ssl_f_notafter(struct proxy *px, struct session *l4, void *l7, unsigne
X509 *crt = NULL; X509 *crt = NULL;
int ret = 0; int ret = 0;
struct chunk *smp_trash; struct chunk *smp_trash;
struct connection *conn;
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE; smp->flags |= SMP_F_MAY_CHANGE;
return 0; return 0;
} }
crt = SSL_get_certificate(l4->si[0].conn->xprt_ctx); crt = SSL_get_certificate(conn->xprt_ctx);
if (!crt) if (!crt)
goto out; goto out;
@ -2184,16 +2254,21 @@ smp_fetch_ssl_f_notbefore(struct proxy *px, struct session *l4, void *l7, unsign
X509 *crt = NULL; X509 *crt = NULL;
int ret = 0; int ret = 0;
struct chunk *smp_trash; struct chunk *smp_trash;
struct connection *conn;
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE; smp->flags |= SMP_F_MAY_CHANGE;
return 0; return 0;
} }
crt = SSL_get_certificate(l4->si[0].conn->xprt_ctx); crt = SSL_get_certificate(conn->xprt_ctx);
if (!crt) if (!crt)
goto out; goto out;
@ -2214,17 +2289,22 @@ smp_fetch_ssl_f_version(struct proxy *px, struct session *l4, void *l7, unsigned
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
X509 *crt; X509 *crt;
struct connection *conn;
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE; smp->flags |= SMP_F_MAY_CHANGE;
return 0; return 0;
} }
/* SSL_get_certificate returns a ptr on an SSL * internal sub struct */ /* SSL_get_certificate returns a ptr on an SSL * internal sub struct */
crt = SSL_get_certificate(l4->si[0].conn->xprt_ctx); crt = SSL_get_certificate(conn->xprt_ctx);
if (!crt) if (!crt)
return 0; return 0;
@ -2241,16 +2321,21 @@ smp_fetch_ssl_f_sig_alg(struct proxy *px, struct session *l4, void *l7, unsigned
{ {
X509 *crt; X509 *crt;
int nid; int nid;
struct connection *conn;
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE; smp->flags |= SMP_F_MAY_CHANGE;
return 0; return 0;
} }
crt = SSL_get_certificate(l4->si[0].conn->xprt_ctx); crt = SSL_get_certificate(conn->xprt_ctx);
if (!crt) if (!crt)
return 0; return 0;
@ -2273,16 +2358,21 @@ smp_fetch_ssl_f_key_alg(struct proxy *px, struct session *l4, void *l7, unsigned
{ {
X509 *crt; X509 *crt;
int nid; int nid;
struct connection *conn;
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE; smp->flags |= SMP_F_MAY_CHANGE;
return 0; return 0;
} }
crt = SSL_get_certificate(l4->si[0].conn->xprt_ctx); crt = SSL_get_certificate(conn->xprt_ctx);
if (!crt) if (!crt)
return 0; return 0;
@ -2307,16 +2397,21 @@ smp_fetch_ssl_f_i_dn(struct proxy *px, struct session *l4, void *l7, unsigned in
X509_NAME *name; X509_NAME *name;
int ret = 0; int ret = 0;
struct chunk *smp_trash; struct chunk *smp_trash;
struct connection *conn;
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE; smp->flags |= SMP_F_MAY_CHANGE;
return 0; return 0;
} }
crt = SSL_get_certificate(l4->si[0].conn->xprt_ctx); crt = SSL_get_certificate(conn->xprt_ctx);
if (!crt) if (!crt)
goto out; goto out;
@ -2355,16 +2450,21 @@ smp_fetch_ssl_f_s_dn(struct proxy *px, struct session *l4, void *l7, unsigned in
X509_NAME *name; X509_NAME *name;
int ret = 0; int ret = 0;
struct chunk *smp_trash; struct chunk *smp_trash;
struct connection *conn;
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags |= SMP_F_MAY_CHANGE; smp->flags |= SMP_F_MAY_CHANGE;
return 0; return 0;
} }
crt = SSL_get_certificate(l4->si[0].conn->xprt_ctx); crt = SSL_get_certificate(conn->xprt_ctx);
if (!crt) if (!crt)
goto out; goto out;
@ -2398,12 +2498,18 @@ static int
smp_fetch_ssl_fc_cipher(struct proxy *px, struct session *l4, void *l7, unsigned int opt, smp_fetch_ssl_fc_cipher(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
struct connection *conn;
smp->flags = 0; smp->flags = 0;
if (!l4 || !l4->si[0].conn->xprt_ctx || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
smp->data.str.str = (char *)SSL_get_cipher_name(l4->si[0].conn->xprt_ctx); conn = objt_conn(l4->si[0].end);
if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock)
return 0;
smp->data.str.str = (char *)SSL_get_cipher_name(conn->xprt_ctx);
if (!smp->data.str.str) if (!smp->data.str.str)
return 0; return 0;
@ -2417,12 +2523,18 @@ static int
smp_fetch_ssl_fc_alg_keysize(struct proxy *px, struct session *l4, void *l7, unsigned int opt, smp_fetch_ssl_fc_alg_keysize(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
struct connection *conn;
smp->flags = 0; smp->flags = 0;
if (!l4 || !l4->si[0].conn->xprt_ctx || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
if (!SSL_get_cipher_bits(l4->si[0].conn->xprt_ctx, (int *)&smp->data.uint)) conn = objt_conn(l4->si[0].end);
if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock)
return 0;
if (!SSL_get_cipher_bits(conn->xprt_ctx, (int *)&smp->data.uint))
return 0; return 0;
smp->type = SMP_T_UINT; smp->type = SMP_T_UINT;
@ -2434,12 +2546,18 @@ static int
smp_fetch_ssl_fc_use_keysize(struct proxy *px, struct session *l4, void *l7, unsigned int opt, smp_fetch_ssl_fc_use_keysize(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
struct connection *conn;
smp->flags = 0; smp->flags = 0;
if (!l4 || !l4->si[0].conn->xprt_ctx || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
smp->data.uint = (unsigned int)SSL_get_cipher_bits(l4->si[0].conn->xprt_ctx, NULL); conn = objt_conn(l4->si[0].end);
if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock)
return 0;
smp->data.uint = (unsigned int)SSL_get_cipher_bits(conn->xprt_ctx, NULL);
if (!smp->data.uint) if (!smp->data.uint)
return 0; return 0;
@ -2453,14 +2571,20 @@ static int
smp_fetch_ssl_fc_npn(struct proxy *px, struct session *l4, void *l7, unsigned int opt, smp_fetch_ssl_fc_npn(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
struct connection *conn;
smp->flags = 0; smp->flags = 0;
smp->type = SMP_T_CSTR; smp->type = SMP_T_CSTR;
if (!l4 || !l4->si[0].conn->xprt_ctx || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0;
conn = objt_conn(l4->si[0].end);
if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock)
return 0; return 0;
smp->data.str.str = NULL; smp->data.str.str = NULL;
SSL_get0_next_proto_negotiated(l4->si[0].conn->xprt_ctx, SSL_get0_next_proto_negotiated(conn->xprt_ctx,
(const unsigned char **)&smp->data.str.str, (unsigned *)&smp->data.str.len); (const unsigned char **)&smp->data.str.str, (unsigned *)&smp->data.str.len);
if (!smp->data.str.str) if (!smp->data.str.str)
@ -2475,14 +2599,20 @@ static int
smp_fetch_ssl_fc_alpn(struct proxy *px, struct session *l4, void *l7, unsigned int opt, smp_fetch_ssl_fc_alpn(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
struct connection *conn;
smp->flags = 0; smp->flags = 0;
smp->type = SMP_T_CSTR; smp->type = SMP_T_CSTR;
if (!l4 || !l4->si[0].conn->xprt_ctx || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0;
conn = objt_conn(l4->si[0].end);
if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock)
return 0; return 0;
smp->data.str.str = NULL; smp->data.str.str = NULL;
SSL_get0_alpn_negotiated(l4->si[0].conn->xprt_ctx, SSL_get0_alpn_negotiated(conn->xprt_ctx,
(const unsigned char **)&smp->data.str.str, (unsigned *)&smp->data.str.len); (const unsigned char **)&smp->data.str.str, (unsigned *)&smp->data.str.len);
if (!smp->data.str.str) if (!smp->data.str.str)
@ -2496,12 +2626,18 @@ static int
smp_fetch_ssl_fc_protocol(struct proxy *px, struct session *l4, void *l7, unsigned int opt, smp_fetch_ssl_fc_protocol(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
struct connection *conn;
smp->flags = 0; smp->flags = 0;
if (!l4 || !l4->si[0].conn->xprt_ctx || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
smp->data.str.str = (char *)SSL_get_version(l4->si[0].conn->xprt_ctx); conn = objt_conn(l4->si[0].end);
if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock)
return 0;
smp->data.str.str = (char *)SSL_get_version(conn->xprt_ctx);
if (!smp->data.str.str) if (!smp->data.str.str)
return 0; return 0;
@ -2517,14 +2653,19 @@ smp_fetch_ssl_fc_session_id(struct proxy *px, struct session *l4, void *l7, unsi
{ {
#if OPENSSL_VERSION_NUMBER > 0x0090800fL #if OPENSSL_VERSION_NUMBER > 0x0090800fL
SSL_SESSION *sess; SSL_SESSION *sess;
struct connection *conn;
smp->flags = 0; smp->flags = 0;
smp->type = SMP_T_CBIN; smp->type = SMP_T_CBIN;
if (!l4 || !l4->si[0].conn->xprt_ctx || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
sess = SSL_get_session(l4->si[0].conn->xprt_ctx); conn = objt_conn(l4->si[0].end);
if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock)
return 0;
sess = SSL_get_session(conn->xprt_ctx);
if (!sess) if (!sess)
return 0; return 0;
@ -2543,13 +2684,19 @@ smp_fetch_ssl_fc_sni(struct proxy *px, struct session *l4, void *l7, unsigned in
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
struct connection *conn;
smp->flags = 0; smp->flags = 0;
smp->type = SMP_T_CSTR; smp->type = SMP_T_CSTR;
if (!l4 || !l4->si[0].conn->xprt_ctx || l4->si[0].conn->xprt != &ssl_sock) if (!l4)
return 0; return 0;
smp->data.str.str = (char *)SSL_get_servername(l4->si[0].conn->xprt_ctx, TLSEXT_NAMETYPE_host_name); conn = objt_conn(l4->si[0].end);
if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock)
return 0;
smp->data.str.str = (char *)SSL_get_servername(conn->xprt_ctx, TLSEXT_NAMETYPE_host_name);
if (!smp->data.str.str) if (!smp->data.str.str)
return 0; return 0;
@ -2565,16 +2712,22 @@ static int
smp_fetch_ssl_c_ca_err(struct proxy *px, struct session *l4, void *l7, unsigned int opt, smp_fetch_ssl_c_ca_err(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) struct connection *conn;
if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags = SMP_F_MAY_CHANGE; smp->flags = SMP_F_MAY_CHANGE;
return 0; return 0;
} }
smp->type = SMP_T_UINT; smp->type = SMP_T_UINT;
smp->data.uint = (unsigned int)SSL_SOCK_ST_TO_CA_ERROR(l4->si[0].conn->xprt_st); smp->data.uint = (unsigned int)SSL_SOCK_ST_TO_CA_ERROR(conn->xprt_st);
smp->flags = 0; smp->flags = 0;
return 1; return 1;
@ -2585,16 +2738,22 @@ static int
smp_fetch_ssl_c_ca_err_depth(struct proxy *px, struct session *l4, void *l7, unsigned int opt, smp_fetch_ssl_c_ca_err_depth(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) struct connection *conn;
if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags = SMP_F_MAY_CHANGE; smp->flags = SMP_F_MAY_CHANGE;
return 0; return 0;
} }
smp->type = SMP_T_UINT; smp->type = SMP_T_UINT;
smp->data.uint = (unsigned int)SSL_SOCK_ST_TO_CAEDEPTH(l4->si[0].conn->xprt_st); smp->data.uint = (unsigned int)SSL_SOCK_ST_TO_CAEDEPTH(conn->xprt_st);
smp->flags = 0; smp->flags = 0;
return 1; return 1;
@ -2605,16 +2764,22 @@ static int
smp_fetch_ssl_c_err(struct proxy *px, struct session *l4, void *l7, unsigned int opt, smp_fetch_ssl_c_err(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) struct connection *conn;
if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags = SMP_F_MAY_CHANGE; smp->flags = SMP_F_MAY_CHANGE;
return 0; return 0;
} }
smp->type = SMP_T_UINT; smp->type = SMP_T_UINT;
smp->data.uint = (unsigned int)SSL_SOCK_ST_TO_CRTERROR(l4->si[0].conn->xprt_st); smp->data.uint = (unsigned int)SSL_SOCK_ST_TO_CRTERROR(conn->xprt_st);
smp->flags = 0; smp->flags = 0;
return 1; return 1;
@ -2625,19 +2790,25 @@ static int
smp_fetch_ssl_c_verify(struct proxy *px, struct session *l4, void *l7, unsigned int opt, smp_fetch_ssl_c_verify(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
const struct arg *args, struct sample *smp, const char *kw) const struct arg *args, struct sample *smp, const char *kw)
{ {
if (!l4 || l4->si[0].conn->xprt != &ssl_sock) struct connection *conn;
if (!l4)
return 0; return 0;
if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) { conn = objt_conn(l4->si[0].end);
if (!conn || conn->xprt != &ssl_sock)
return 0;
if (!(conn->flags & CO_FL_CONNECTED)) {
smp->flags = SMP_F_MAY_CHANGE; smp->flags = SMP_F_MAY_CHANGE;
return 0; return 0;
} }
if (!l4->si[0].conn->xprt_ctx) if (!conn->xprt_ctx)
return 0; return 0;
smp->type = SMP_T_UINT; smp->type = SMP_T_UINT;
smp->data.uint = (unsigned int)SSL_get_verify_result(l4->si[0].conn->xprt_ctx); smp->data.uint = (unsigned int)SSL_get_verify_result(conn->xprt_ctx);
smp->flags = 0; smp->flags = 0;
return 1; return 1;

View File

@ -395,7 +395,12 @@ int conn_si_send_proxy(struct connection *conn, unsigned int flag)
* (which is recomputed every time since it's constant). If * (which is recomputed every time since it's constant). If
* it is positive, it means we have to send from the start. * it is positive, it means we have to send from the start.
*/ */
ret = make_proxy_line(trash.str, trash.size, &si->ob->prod->conn->addr.from, &si->ob->prod->conn->addr.to); struct connection *remote = objt_conn(si->ob->prod->end);
if (remote)
ret = make_proxy_line(trash.str, trash.size, &remote->addr.from, &remote->addr.to);
else
ret = make_proxy_line(trash.str, trash.size, NULL, NULL);
if (!ret) if (!ret)
goto out_error; goto out_error;
@ -638,6 +643,7 @@ void stream_int_update_conn(struct stream_interface *si)
{ {
struct channel *ib = si->ib; struct channel *ib = si->ib;
struct channel *ob = si->ob; struct channel *ob = si->ob;
struct connection *conn = __objt_conn(si->end);
/* Check if we need to close the read side */ /* Check if we need to close the read side */
if (!(ib->flags & CF_SHUTR)) { if (!(ib->flags & CF_SHUTR)) {
@ -647,7 +653,7 @@ void stream_int_update_conn(struct stream_interface *si)
if (!(si->flags & SI_FL_WAIT_ROOM)) { if (!(si->flags & SI_FL_WAIT_ROOM)) {
if (!(ib->flags & CF_DONT_READ)) /* full */ if (!(ib->flags & CF_DONT_READ)) /* full */
si->flags |= SI_FL_WAIT_ROOM; si->flags |= SI_FL_WAIT_ROOM;
conn_data_stop_recv(si->conn); conn_data_stop_recv(conn);
ib->rex = TICK_ETERNITY; ib->rex = TICK_ETERNITY;
} }
} }
@ -658,7 +664,7 @@ void stream_int_update_conn(struct stream_interface *si)
* have updated it if there has been a completed I/O. * have updated it if there has been a completed I/O.
*/ */
si->flags &= ~SI_FL_WAIT_ROOM; si->flags &= ~SI_FL_WAIT_ROOM;
conn_data_want_recv(si->conn); conn_data_want_recv(conn);
if (!(ib->flags & (CF_READ_NOEXP|CF_DONT_READ)) && !tick_isset(ib->rex)) if (!(ib->flags & (CF_READ_NOEXP|CF_DONT_READ)) && !tick_isset(ib->rex))
ib->rex = tick_add_ifset(now_ms, ib->rto); ib->rex = tick_add_ifset(now_ms, ib->rto);
} }
@ -672,7 +678,7 @@ void stream_int_update_conn(struct stream_interface *si)
if (!(si->flags & SI_FL_WAIT_DATA)) { if (!(si->flags & SI_FL_WAIT_DATA)) {
if ((ob->flags & CF_SHUTW_NOW) == 0) if ((ob->flags & CF_SHUTW_NOW) == 0)
si->flags |= SI_FL_WAIT_DATA; si->flags |= SI_FL_WAIT_DATA;
conn_data_stop_send(si->conn); conn_data_stop_send(conn);
ob->wex = TICK_ETERNITY; ob->wex = TICK_ETERNITY;
} }
} }
@ -683,7 +689,7 @@ void stream_int_update_conn(struct stream_interface *si)
* have updated it if there has been a completed I/O. * have updated it if there has been a completed I/O.
*/ */
si->flags &= ~SI_FL_WAIT_DATA; si->flags &= ~SI_FL_WAIT_DATA;
conn_data_want_send(si->conn); conn_data_want_send(conn);
if (!tick_isset(ob->wex)) { if (!tick_isset(ob->wex)) {
ob->wex = tick_add_ifset(now_ms, ob->wto); ob->wex = tick_add_ifset(now_ms, ob->wto);
if (tick_isset(ib->rex) && !(si->flags & SI_FL_INDEP_STR)) { if (tick_isset(ib->rex) && !(si->flags & SI_FL_INDEP_STR)) {
@ -712,7 +718,7 @@ void stream_int_update_conn(struct stream_interface *si)
*/ */
static void stream_int_shutr_conn(struct stream_interface *si) static void stream_int_shutr_conn(struct stream_interface *si)
{ {
struct connection *conn = si->conn; struct connection *conn = __objt_conn(si->end);
si->ib->flags &= ~CF_SHUTR_NOW; si->ib->flags &= ~CF_SHUTR_NOW;
if (si->ib->flags & CF_SHUTR) if (si->ib->flags & CF_SHUTR)
@ -754,7 +760,7 @@ static void stream_int_shutr_conn(struct stream_interface *si)
*/ */
static void stream_int_shutw_conn(struct stream_interface *si) static void stream_int_shutw_conn(struct stream_interface *si)
{ {
struct connection *conn = si->conn; struct connection *conn = __objt_conn(si->end);
si->ob->flags &= ~CF_SHUTW_NOW; si->ob->flags &= ~CF_SHUTW_NOW;
if (si->ob->flags & CF_SHUTW) if (si->ob->flags & CF_SHUTW)
@ -840,24 +846,25 @@ static void stream_int_shutw_conn(struct stream_interface *si)
static void stream_int_chk_rcv_conn(struct stream_interface *si) static void stream_int_chk_rcv_conn(struct stream_interface *si)
{ {
struct channel *ib = si->ib; struct channel *ib = si->ib;
struct connection *conn = __objt_conn(si->end);
if (unlikely(si->state > SI_ST_EST || (ib->flags & CF_SHUTR))) if (unlikely(si->state > SI_ST_EST || (ib->flags & CF_SHUTR)))
return; return;
conn_refresh_polling_flags(si->conn); conn_refresh_polling_flags(conn);
if ((ib->flags & CF_DONT_READ) || channel_full(ib)) { if ((ib->flags & CF_DONT_READ) || channel_full(ib)) {
/* stop reading */ /* stop reading */
if (!(ib->flags & CF_DONT_READ)) /* full */ if (!(ib->flags & CF_DONT_READ)) /* full */
si->flags |= SI_FL_WAIT_ROOM; si->flags |= SI_FL_WAIT_ROOM;
__conn_data_stop_recv(si->conn); __conn_data_stop_recv(conn);
} }
else { else {
/* (re)start reading */ /* (re)start reading */
si->flags &= ~SI_FL_WAIT_ROOM; si->flags &= ~SI_FL_WAIT_ROOM;
__conn_data_want_recv(si->conn); __conn_data_want_recv(conn);
} }
conn_cond_update_data_polling(si->conn); conn_cond_update_data_polling(conn);
} }
@ -869,6 +876,7 @@ static void stream_int_chk_rcv_conn(struct stream_interface *si)
static void stream_int_chk_snd_conn(struct stream_interface *si) static void stream_int_chk_snd_conn(struct stream_interface *si)
{ {
struct channel *ob = si->ob; struct channel *ob = si->ob;
struct connection *conn = __objt_conn(si->end);
if (unlikely(si->state > SI_ST_EST || (ob->flags & CF_SHUTW))) if (unlikely(si->state > SI_ST_EST || (ob->flags & CF_SHUTW)))
return; return;
@ -880,7 +888,7 @@ static void stream_int_chk_snd_conn(struct stream_interface *si)
!(si->flags & SI_FL_WAIT_DATA)) /* not waiting for data */ !(si->flags & SI_FL_WAIT_DATA)) /* not waiting for data */
return; return;
if (si->conn->flags & (CO_FL_DATA_WR_ENA|CO_FL_CURR_WR_ENA)) { if (conn->flags & (CO_FL_DATA_WR_ENA|CO_FL_CURR_WR_ENA)) {
/* already subscribed to write notifications, will be called /* already subscribed to write notifications, will be called
* anyway, so let's avoid calling it especially if the reader * anyway, so let's avoid calling it especially if the reader
* is not ready. * is not ready.
@ -888,20 +896,20 @@ static void stream_int_chk_snd_conn(struct stream_interface *si)
return; return;
} }
if (!(si->conn->flags & (CO_FL_HANDSHAKE|CO_FL_WAIT_L4_CONN|CO_FL_WAIT_L6_CONN))) { if (!(conn->flags & (CO_FL_HANDSHAKE|CO_FL_WAIT_L4_CONN|CO_FL_WAIT_L6_CONN))) {
/* Before calling the data-level operations, we have to prepare /* Before calling the data-level operations, we have to prepare
* the polling flags to ensure we properly detect changes. * the polling flags to ensure we properly detect changes.
*/ */
if (si->conn->ctrl) if (conn->ctrl)
fd_want_send(si->conn->t.sock.fd); fd_want_send(conn->t.sock.fd);
conn_refresh_polling_flags(si->conn); conn_refresh_polling_flags(conn);
si_conn_send(si->conn); si_conn_send(conn);
if (si->conn->flags & CO_FL_ERROR) { if (conn->flags & CO_FL_ERROR) {
/* Write error on the file descriptor */ /* Write error on the file descriptor */
fd_stop_both(si->conn->t.sock.fd); fd_stop_both(conn->t.sock.fd);
__conn_data_stop_both(si->conn); __conn_data_stop_both(conn);
si->flags |= SI_FL_ERR; si->flags |= SI_FL_ERR;
goto out_wakeup; goto out_wakeup;
} }
@ -916,7 +924,7 @@ static void stream_int_chk_snd_conn(struct stream_interface *si)
* ->o limit was reached. Maybe we just wrote the last * ->o limit was reached. Maybe we just wrote the last
* chunk and need to close. * chunk and need to close.
*/ */
__conn_data_stop_send(si->conn); __conn_data_stop_send(conn);
if (((ob->flags & (CF_SHUTW|CF_AUTO_CLOSE|CF_SHUTW_NOW)) == if (((ob->flags & (CF_SHUTW|CF_AUTO_CLOSE|CF_SHUTW_NOW)) ==
(CF_AUTO_CLOSE|CF_SHUTW_NOW)) && (CF_AUTO_CLOSE|CF_SHUTW_NOW)) &&
(si->state == SI_ST_EST)) { (si->state == SI_ST_EST)) {
@ -932,7 +940,7 @@ static void stream_int_chk_snd_conn(struct stream_interface *si)
/* Otherwise there are remaining data to be sent in the buffer, /* Otherwise there are remaining data to be sent in the buffer,
* which means we have to poll before doing so. * which means we have to poll before doing so.
*/ */
__conn_data_want_send(si->conn); __conn_data_want_send(conn);
si->flags &= ~SI_FL_WAIT_DATA; si->flags &= ~SI_FL_WAIT_DATA;
if (!tick_isset(ob->wex)) if (!tick_isset(ob->wex))
ob->wex = tick_add_ifset(now_ms, ob->wto); ob->wex = tick_add_ifset(now_ms, ob->wto);
@ -969,7 +977,7 @@ static void stream_int_chk_snd_conn(struct stream_interface *si)
} }
/* commit possible polling changes */ /* commit possible polling changes */
conn_cond_update_polling(si->conn); conn_cond_update_polling(conn);
} }
/* /*
@ -1205,7 +1213,7 @@ static void si_conn_send_cb(struct connection *conn)
if (conn->flags & CO_FL_ERROR) if (conn->flags & CO_FL_ERROR)
return; return;
if (si->conn->flags & CO_FL_HANDSHAKE) if (conn->flags & CO_FL_HANDSHAKE)
/* a handshake was requested */ /* a handshake was requested */
return; return;
@ -1229,6 +1237,8 @@ static void si_conn_send_cb(struct connection *conn)
*/ */
void stream_sock_read0(struct stream_interface *si) void stream_sock_read0(struct stream_interface *si)
{ {
struct connection *conn = __objt_conn(si->end);
si->ib->flags &= ~CF_SHUTR_NOW; si->ib->flags &= ~CF_SHUTR_NOW;
if (si->ib->flags & CF_SHUTR) if (si->ib->flags & CF_SHUTR)
return; return;
@ -1246,22 +1256,22 @@ void stream_sock_read0(struct stream_interface *si)
/* we want to immediately forward this close to the write side */ /* we want to immediately forward this close to the write side */
if (si->flags & SI_FL_NOLINGER) { if (si->flags & SI_FL_NOLINGER) {
si->flags &= ~SI_FL_NOLINGER; si->flags &= ~SI_FL_NOLINGER;
setsockopt(si->conn->t.sock.fd, SOL_SOCKET, SO_LINGER, setsockopt(conn->t.sock.fd, SOL_SOCKET, SO_LINGER,
(struct linger *) &nolinger, sizeof(struct linger)); (struct linger *) &nolinger, sizeof(struct linger));
} }
/* force flag on ssl to keep session in cache */ /* force flag on ssl to keep session in cache */
if (si->conn->xprt->shutw) if (conn->xprt->shutw)
si->conn->xprt->shutw(si->conn, 0); conn->xprt->shutw(conn, 0);
goto do_close; goto do_close;
} }
/* otherwise that's just a normal read shutdown */ /* otherwise that's just a normal read shutdown */
__conn_data_stop_recv(si->conn); __conn_data_stop_recv(conn);
return; return;
do_close: do_close:
/* OK we completely close the socket here just as if we went through si_shut[rw]() */ /* OK we completely close the socket here just as if we went through si_shut[rw]() */
conn_full_close(si->conn); conn_full_close(conn);
si->ib->flags &= ~CF_SHUTR_NOW; si->ib->flags &= ~CF_SHUTR_NOW;
si->ib->flags |= CF_SHUTR; si->ib->flags |= CF_SHUTR;