mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 15:47:01 +02:00
MINOR: proto_reverse_connect: parse rev@ addresses for bind
Implement parsing for "rev@" addresses on bind line. On config parsing, server name is stored on the bind_conf. Several new callbacks are defined on reverse_connect protocol to complete parsing. listen callback is used to retrieve the server instance from the bind_conf server name. If found, the server instance is stored on the receiver. Checks are implemented to ensure HTTP/2 protocol only is used by the server.
This commit is contained in:
parent
008e8f67ee
commit
0747e493a0
@ -4993,6 +4993,10 @@ bind /<path> [, ...] [param*]
|
|||||||
- 'quic6@' -> address is resolved as IPv6 and protocol UDP
|
- 'quic6@' -> address is resolved as IPv6 and protocol UDP
|
||||||
is used. The performance note for QUIC over IPv4 applies
|
is used. The performance note for QUIC over IPv4 applies
|
||||||
as well.
|
as well.
|
||||||
|
- 'rev@' -> used for reverse HTTP. Address must be a server
|
||||||
|
with the format '<backend>/<server>'. The server will be
|
||||||
|
used to instantiate connections to a remote address. The
|
||||||
|
listener will try to maintain 'maxconn' connections.
|
||||||
|
|
||||||
You may want to reference some environment variables in the
|
You may want to reference some environment variables in the
|
||||||
address parameter, see section 2.3 about environment
|
address parameter, see section 2.3 about environment
|
||||||
|
@ -205,6 +205,7 @@ struct bind_conf {
|
|||||||
char *arg; /* argument passed to "bind" for better error reporting */
|
char *arg; /* argument passed to "bind" for better error reporting */
|
||||||
char *file; /* file where the section appears */
|
char *file; /* file where the section appears */
|
||||||
int line; /* line where the section appears */
|
int line; /* line where the section appears */
|
||||||
|
char *reverse_srvname; /* name of server when using "rev@" address */
|
||||||
__decl_thread(HA_RWLOCK_T sni_lock); /* lock the SNI trees during add/del operations */
|
__decl_thread(HA_RWLOCK_T sni_lock); /* lock the SNI trees during add/del operations */
|
||||||
struct thread_set thread_set; /* entire set of the allowed threads (0=no restriction) */
|
struct thread_set thread_set; /* entire set of the allowed threads (0=no restriction) */
|
||||||
struct rx_settings settings; /* all the settings needed for the listening socket */
|
struct rx_settings settings; /* all the settings needed for the listening socket */
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
int rev_bind_receiver(struct receiver *rx, char **errmsg);
|
int rev_bind_receiver(struct receiver *rx, char **errmsg);
|
||||||
|
|
||||||
int rev_bind_listener(struct listener *listener, char *errmsg, int errlen);
|
int rev_bind_listener(struct listener *listener, char *errmsg, int errlen);
|
||||||
|
void rev_unbind_receiver(struct listener *l);
|
||||||
|
|
||||||
int rev_accepting_conn(const struct receiver *rx);
|
int rev_accepting_conn(const struct receiver *rx);
|
||||||
|
|
||||||
|
@ -79,6 +79,10 @@ struct receiver {
|
|||||||
#ifdef USE_QUIC
|
#ifdef USE_QUIC
|
||||||
struct mt_list rxbuf_list; /* list of buffers to receive and dispatch QUIC datagrams. */
|
struct mt_list rxbuf_list; /* list of buffers to receive and dispatch QUIC datagrams. */
|
||||||
#endif
|
#endif
|
||||||
|
struct {
|
||||||
|
struct server *srv; /* Underlying server used to initiate reverse pre-connect. */
|
||||||
|
} reverse_connect;
|
||||||
|
|
||||||
/* warning: this struct is huge, keep it at the bottom */
|
/* warning: this struct is huge, keep it at the bottom */
|
||||||
struct sockaddr_storage addr; /* the address the socket is bound to */
|
struct sockaddr_storage addr; /* the address the socket is bound to */
|
||||||
};
|
};
|
||||||
|
@ -173,6 +173,10 @@ int str2listener(char *str, struct proxy *curproxy, struct bind_conf *bind_conf,
|
|||||||
else
|
else
|
||||||
bind_conf->options |= BC_O_USE_XPRT_STREAM;
|
bind_conf->options |= BC_O_USE_XPRT_STREAM;
|
||||||
|
|
||||||
|
if (ss2->ss_family == AF_CUST_REV_SRV) {
|
||||||
|
bind_conf->reverse_srvname = strdup(str + strlen("rev@"));
|
||||||
|
}
|
||||||
|
|
||||||
if (!create_listeners(bind_conf, ss2, port, end, fd, proto, err)) {
|
if (!create_listeners(bind_conf, ss2, port, end, fd, proto, err)) {
|
||||||
memprintf(err, "%s for address '%s'.\n", *err, str);
|
memprintf(err, "%s for address '%s'.\n", *err, str);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -799,6 +799,8 @@ int create_listeners(struct bind_conf *bc, const struct sockaddr_storage *ss,
|
|||||||
l->rx.iocb = proto->default_iocb;
|
l->rx.iocb = proto->default_iocb;
|
||||||
l->rx.fd = fd;
|
l->rx.fd = fd;
|
||||||
|
|
||||||
|
l->rx.reverse_connect.srv = NULL;
|
||||||
|
|
||||||
memcpy(&l->rx.addr, ss, sizeof(*ss));
|
memcpy(&l->rx.addr, ss, sizeof(*ss));
|
||||||
if (proto->fam->set_port)
|
if (proto->fam->set_port)
|
||||||
proto->fam->set_port(&l->rx.addr, port);
|
proto->fam->set_port(&l->rx.addr, port);
|
||||||
@ -1945,6 +1947,9 @@ struct bind_conf *bind_conf_alloc(struct proxy *fe, const char *file,
|
|||||||
bind_conf->sni_w_ctx = EB_ROOT;
|
bind_conf->sni_w_ctx = EB_ROOT;
|
||||||
#endif
|
#endif
|
||||||
LIST_INIT(&bind_conf->listeners);
|
LIST_INIT(&bind_conf->listeners);
|
||||||
|
|
||||||
|
bind_conf->reverse_srvname = NULL;
|
||||||
|
|
||||||
return bind_conf;
|
return bind_conf;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <haproxy/api.h>
|
#include <haproxy/api.h>
|
||||||
#include <haproxy/errors.h>
|
#include <haproxy/errors.h>
|
||||||
#include <haproxy/list.h>
|
#include <haproxy/list.h>
|
||||||
#include <haproxy/listener.h>
|
#include <haproxy/listener.h>
|
||||||
#include <haproxy/protocol.h>
|
#include <haproxy/protocol.h>
|
||||||
|
#include <haproxy/proxy.h>
|
||||||
|
#include <haproxy/server.h>
|
||||||
|
|
||||||
#include <haproxy/proto_reverse_connect.h>
|
#include <haproxy/proto_reverse_connect.h>
|
||||||
|
|
||||||
@ -17,8 +22,10 @@ struct protocol proto_reverse_connect = {
|
|||||||
.name = "rev",
|
.name = "rev",
|
||||||
|
|
||||||
/* connection layer */
|
/* connection layer */
|
||||||
.listen = rev_bind_listener,
|
.listen = rev_bind_listener,
|
||||||
.add = default_add_listener,
|
.unbind = rev_unbind_receiver,
|
||||||
|
.add = default_add_listener,
|
||||||
|
.resume = default_resume_listener,
|
||||||
|
|
||||||
/* address family */
|
/* address family */
|
||||||
.fam = &proto_fam_reverse_connect,
|
.fam = &proto_fam_reverse_connect,
|
||||||
@ -33,12 +40,65 @@ struct protocol proto_reverse_connect = {
|
|||||||
|
|
||||||
int rev_bind_receiver(struct receiver *rx, char **errmsg)
|
int rev_bind_receiver(struct receiver *rx, char **errmsg)
|
||||||
{
|
{
|
||||||
|
rx->flags |= RX_F_BOUND;
|
||||||
return ERR_NONE;
|
return ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rev_bind_listener(struct listener *listener, char *errmsg, int errlen)
|
int rev_bind_listener(struct listener *listener, char *errmsg, int errlen)
|
||||||
{
|
{
|
||||||
|
struct proxy *be;
|
||||||
|
struct server *srv;
|
||||||
|
struct ist be_name, sv_name;
|
||||||
|
char *name = NULL;
|
||||||
|
|
||||||
|
name = strdup(listener->bind_conf->reverse_srvname);
|
||||||
|
if (!name) {
|
||||||
|
snprintf(errmsg, errlen, "Out of memory.");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
sv_name = ist(name);
|
||||||
|
be_name = istsplit(&sv_name, '/');
|
||||||
|
if (!istlen(sv_name)) {
|
||||||
|
snprintf(errmsg, errlen, "Invalid server name: '%s'.", name);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(be = proxy_be_by_name(ist0(be_name)))) {
|
||||||
|
snprintf(errmsg, errlen, "No such backend: '%s'.", name);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if (!(srv = server_find_by_name(be, ist0(sv_name)))) {
|
||||||
|
snprintf(errmsg, errlen, "No such server: '%s/%s'.", ist0(be_name), ist0(sv_name));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO check que on utilise pas un serveur @reverse */
|
||||||
|
if (srv->flags & SRV_F_REVERSE) {
|
||||||
|
snprintf(errmsg, errlen, "Cannot use reverse server '%s/%s' as target to a reverse bind.", ist0(be_name), ist0(sv_name));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that server uses HTTP/2 either with proto or ALPN. */
|
||||||
|
if ((!srv->mux_proto || !isteqi(srv->mux_proto->token, ist("h2"))) &&
|
||||||
|
(!srv->use_ssl || !isteqi(ist(srv->ssl_ctx.alpn_str), ist("\x02h2")))) {
|
||||||
|
snprintf(errmsg, errlen, "Cannot reverse connect with server '%s/%s' unless HTTP/2 is activated on it with either proto or alpn keyword.", name, ist0(sv_name));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
ha_free(&name);
|
||||||
|
|
||||||
|
listener->rx.reverse_connect.srv = srv;
|
||||||
|
|
||||||
return ERR_NONE;
|
return ERR_NONE;
|
||||||
|
|
||||||
|
err:
|
||||||
|
ha_free(&name);
|
||||||
|
return ERR_ALERT | ERR_FATAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rev_unbind_receiver(struct listener *l)
|
||||||
|
{
|
||||||
|
l->rx.flags &= ~RX_F_BOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rev_accepting_conn(const struct receiver *rx)
|
int rev_accepting_conn(const struct receiver *rx)
|
||||||
|
@ -334,6 +334,7 @@ void free_proxy(struct proxy *p)
|
|||||||
free(bind_conf->arg);
|
free(bind_conf->arg);
|
||||||
free(bind_conf->settings.interface);
|
free(bind_conf->settings.interface);
|
||||||
LIST_DELETE(&bind_conf->by_fe);
|
LIST_DELETE(&bind_conf->by_fe);
|
||||||
|
free(bind_conf->reverse_srvname);
|
||||||
free(bind_conf);
|
free(bind_conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user