different limits to different listening ports or addresses. See also the
"fe_conn" and "be_conn" fetches.
+dst_is_local : boolean
+ Returns true if the destination address of the incoming connection is local
+ to the system, or false if the address doesn't exist on the system, meaning
+ that it was intercepted in transparent mode. It can be useful to apply
+ certain rules by default to forwarded traffic and other rules to the traffic
+ targetting the real address of the machine. For example the stats page could
+ be delivered only on this address, or SSH access could be locally redirected.
+ Please note that the check involves a few system calls, so it's better to do
+ it only once per connection.
+
dst_port : integer
Returns an integer value corresponding to the destination TCP port of the
connection on the client side, which is the port the client connected to.
acl kill src_inc_gpc0 gt 0
tcp-request connection reject if abuse kill
+src_is_local : boolean
+ Returns true if the source address of the incoming connection is local to the
+ system, or false if the address doesn't exist on the system, meaning that it
+ comes from a remote machine. Note that UNIX addresses are considered local.
+ It can be useful to apply certain access restrictions based on where the
+ client comes from (eg: require auth or https for remote machines). Please
+ note that the check involves a few system calls, so it's better to do it only
+ once per connection.
+
src_kbytes_in([<table>]) : integer
Returns the total amount of data received from the incoming connection's
source address in the current proxy's stick-table or in the designated
#include <arpa/inet.h>
#include <common/chunk.h>
#include <common/config.h>
+#include <common/namespace.h>
#include <eb32tree.h>
#ifndef LLONG_MAX
*/
int port_to_str(struct sockaddr_storage *addr, char *str, int size);
+/* check if the given address is local to the system or not. It will return
+ * -1 when it's not possible to know, 0 when the address is not local, 1 when
+ * it is. We don't want to iterate over all interfaces for this (and it is not
+ * portable). So instead we try to bind in UDP to this address on a free non
+ * privileged port and to connect to the same address, port 0 (connect doesn't
+ * care). If it succeeds, we own the address. Note that non-inet addresses are
+ * considered local since they're most likely AF_UNIX.
+ */
+int addr_is_local(const struct netns_entry *ns,
+ const struct sockaddr_storage *orig);
+
/* will try to encode the string <string> replacing all characters tagged in
* <map> with the hexadecimal representation of their ASCII-code (2 digits)
* prefixed by <escape>, and will store the result between <start> (included)
return 1;
}
+/* check if the destination address of the front connection is local to the
+ * system or if it was intercepted.
+ */
+int smp_fetch_dst_is_local(const struct arg *args, struct sample *smp, const char *kw, void *private)
+{
+ struct connection *conn = objt_conn(smp->sess->origin);
+ struct listener *li = smp->sess->listener;
+
+ if (!conn)
+ return 0;
+
+ conn_get_to_addr(conn);
+ if (!(conn->flags & CO_FL_ADDR_TO_SET))
+ return 0;
+
+ smp->data.type = SMP_T_BOOL;
+ smp->flags = 0;
+ smp->data.u.sint = addr_is_local(li->netns, &conn->addr.to);
+ return smp->data.u.sint >= 0;
+}
+
+/* check if the source address of the front connection is local to the system
+ * or not.
+ */
+int smp_fetch_src_is_local(const struct arg *args, struct sample *smp, const char *kw, void *private)
+{
+ struct connection *conn = objt_conn(smp->sess->origin);
+ struct listener *li = smp->sess->listener;
+
+ if (!conn)
+ return 0;
+
+ conn_get_from_addr(conn);
+ if (!(conn->flags & CO_FL_ADDR_FROM_SET))
+ return 0;
+
+ smp->data.type = SMP_T_BOOL;
+ smp->flags = 0;
+ smp->data.u.sint = addr_is_local(li->netns, &conn->addr.from);
+ return smp->data.u.sint >= 0;
+}
+
/* set temp integer to the frontend connexion's destination port */
static int
smp_fetch_dport(const struct arg *args, struct sample *smp, const char *kw, void *private)
*/
static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
{ "dst", smp_fetch_dst, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI },
+ { "dst_is_local", smp_fetch_dst_is_local, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI },
{ "dst_port", smp_fetch_dport, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI },
{ "src", smp_fetch_src, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI },
+ { "src_is_local", smp_fetch_src_is_local, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI },
{ "src_port", smp_fetch_sport, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI },
#ifdef TCP_INFO
{ "fc_rtt", smp_fetch_fc_rtt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_L4CLI },
*/
#include <ctype.h>
+#include <errno.h>
#include <netdb.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
+#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
return addr->ss_family;
}
+/* check if the given address is local to the system or not. It will return
+ * -1 when it's not possible to know, 0 when the address is not local, 1 when
+ * it is. We don't want to iterate over all interfaces for this (and it is not
+ * portable). So instead we try to bind in UDP to this address on a free non
+ * privileged port and to connect to the same address, port 0 (connect doesn't
+ * care). If it succeeds, we own the address. Note that non-inet addresses are
+ * considered local since they're most likely AF_UNIX.
+ */
+int addr_is_local(const struct netns_entry *ns,
+ const struct sockaddr_storage *orig)
+{
+ struct sockaddr_storage addr;
+ int result;
+ int fd;
+
+ if (!is_inet_addr(orig))
+ return 1;
+
+ memcpy(&addr, orig, sizeof(addr));
+ set_host_port(&addr, 0);
+
+ fd = my_socketat(ns, addr.ss_family, SOCK_DGRAM, IPPROTO_UDP);
+ if (fd < 0)
+ return -1;
+
+ result = -1;
+ if (bind(fd, (struct sockaddr *)&addr, get_addr_len(&addr)) == 0) {
+ if (connect(fd, (struct sockaddr *)&addr, get_addr_len(&addr)) == -1)
+ result = 0; // fail, non-local address
+ else
+ result = 1; // success, local address
+ }
+ else {
+ if (errno == EADDRNOTAVAIL)
+ result = 0; // definitely not local :-)
+ }
+ close(fd);
+
+ return result;
+}
+
/* will try to encode the string <string> replacing all characters tagged in
* <map> with the hexadecimal representation of their ASCII-code (2 digits)
* prefixed by <escape>, and will store the result between <start> (included)