- h1-case-adjust-file
- h2-workaround-bogus-websocket-clients
- hard-stop-after
+ - harden.reject-privileged-ports.tcp
+ - harden.reject-privileged-ports.quic
- insecure-fork-wanted
- insecure-setuid-wanted
- issuers-chain-path
See also: grace
+harden.reject-privileged-ports.tcp { on | off }
+harden.reject-privileged-ports.quic { on | off }
+ Toggle per protocol protection which forbid communication with clients which
+ use privileged ports as their source port. This range of ports is defined
+ according to RFC 6335. Protection is inactive by default on both protocols.
+
http-err-codes [+-]<range>[,...] [...]
Replace, reduce or extend the list of status codes that define an error as
considered by the termination codes and the "http_err_cnt" counter in stick
int numa_cpu_mapping;
int thread_limit; /* hard limit on the number of threads */
int prealloc_fd;
+ uchar clt_privileged_ports; /* bitmask to allow client privileged ports exchanges per protocol */
+ /* 3-bytes hole */
int cfg_curr_line; /* line number currently being parsed */
const char *cfg_curr_file; /* config file currently being parsed or NULL */
char *cfg_curr_section; /* config section name currently being parsed or NULL */
struct list list; /* list of registered protocols (under proto_lock) */
};
+/* Transport protocol identifiers which can be used as masked values. */
+enum ha_proto {
+ HA_PROTO_NONE = 0x00,
+
+ HA_PROTO_TCP = 0x01,
+ HA_PROTO_UDP = 0x02,
+ HA_PROTO_QUIC = 0x04,
+
+ HA_PROTO_ANY = 0xff,
+};
+
#endif /* _HAPROXY_PROTOCOL_T_H */
/*
#include <haproxy/api.h>
#include <haproxy/chunk.h>
#include <haproxy/intops.h>
+#include <haproxy/global.h>
#include <haproxy/namespace-t.h>
#include <haproxy/protocol-t.h>
#include <haproxy/tools-t.h>
return 0;
}
+/* Returns true if <addr> port is forbidden as client source using <proto>. */
+static inline int port_is_restricted(const struct sockaddr_storage *addr,
+ enum ha_proto proto)
+{
+ const uint16_t port = get_host_port(addr);
+
+ BUG_ON_HOT(proto != HA_PROTO_TCP && proto != HA_PROTO_QUIC);
+
+ /* RFC 6335 6. Port Number Ranges */
+ if (unlikely(port < 1024 && port > 0))
+ return !(global.clt_privileged_ports & proto);
+
+ return 0;
+}
+
/* Convert mask from bit length form to in_addr form.
* This function never fails.
*/
return 0;
}
+/* Parser for harden.reject-privileged-ports.{tcp|quic}. */
+static int cfg_parse_reject_privileged_ports(char **args, int section_type,
+ struct proxy *curpx,
+ const struct proxy *defpx,
+ const char *file, int line, char **err)
+{
+ struct ist proto;
+ char onoff;
+
+ if (!*(args[1])) {
+ memprintf(err, "'%s' expects either 'on' or 'off'.", args[0]);
+ return -1;
+ }
+
+ proto = ist(args[0]);
+ while (istlen(istfind(proto, '.')))
+ proto = istadv(istfind(proto, '.'), 1);
+
+ if (strcmp(args[1], "on") == 0) {
+ onoff = 1;
+ }
+ else if (strcmp(args[1], "off") == 0) {
+ onoff = 0;
+ }
+ else {
+ memprintf(err, "'%s' expects either 'on' or 'off'.", args[0]);
+ return -1;
+ }
+
+ if (istmatch(proto, ist("tcp"))) {
+ if (!onoff)
+ global.clt_privileged_ports |= HA_PROTO_TCP;
+ else
+ global.clt_privileged_ports &= ~HA_PROTO_TCP;
+ }
+ else if (istmatch(proto, ist("quic"))) {
+ if (!onoff)
+ global.clt_privileged_ports |= HA_PROTO_QUIC;
+ else
+ global.clt_privileged_ports &= ~HA_PROTO_QUIC;
+ }
+ else {
+ memprintf(err, "invalid protocol for '%s'.", args[0]);
+ return -1;
+ }
+
+ return 0;
+}
+
static struct cfg_kw_list cfg_kws = {ILH, {
{ CFG_GLOBAL, "prealloc-fd", cfg_parse_prealloc_fd },
+ { CFG_GLOBAL, "harden.reject-privileged-ports.tcp", cfg_parse_reject_privileged_ports },
+ { CFG_GLOBAL, "harden.reject-privileged-ports.quic", cfg_parse_reject_privileged_ports },
{ 0, NULL, NULL },
}};
.maxsslconn = DEFAULT_MAXSSLCONN,
#endif
#endif
+ /* by default do not protect against clients using privileged port */
+ .clt_privileged_ports = HA_PROTO_ANY,
/* others NULL OK */
};
#include <haproxy/listener.h>
#include <haproxy/log.h>
#include <haproxy/pool.h>
+#include <haproxy/protocol-t.h>
#include <haproxy/proto_quic.h>
#include <haproxy/proxy-t.h>
#include <haproxy/quic_cid.h>
if (ret < 0)
goto end;
+ if (unlikely(port_is_restricted((struct sockaddr_storage *)from, HA_PROTO_QUIC))) {
+ ret = -1;
+ goto end;
+ }
+
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
switch (cmsg->cmsg_level) {
case IPPROTO_IP:
#include <haproxy/listener.h>
#include <haproxy/log.h>
#include <haproxy/namespace.h>
+#include <haproxy/protocol-t.h>
#include <haproxy/proto_sockpair.h>
#include <haproxy/sock.h>
#include <haproxy/sock_inet.h>
goto fail_conn;
}
+ if (unlikely(port_is_restricted(addr, HA_PROTO_TCP)))
+ goto fail_conn;
+
/* Perfect, the connection was accepted */
conn = conn_new(&l->obj_type);
if (!conn)