]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: stick-table: fix IPv4-to-IPv6 conversion in src_* fetches
authorThierry FOURNIER <tfournier@exceliance.fr>
Mon, 14 Apr 2014 12:35:40 +0000 (14:35 +0200)
committerWilly Tarreau <w@1wt.eu>
Mon, 14 Apr 2014 16:22:57 +0000 (18:22 +0200)
The function addr_to_stktable_key doesn't consider the expected
type of key. If the stick table key is based on IPv6 addresses
and the input is IPv4, the returned key is IPv4 adddress and his
length is 4 bytes, while is expected 16 bytes key.

This patch considers the expected key and try to convert IPv4 to
IPv6 and IPv6 to IPv4 according with the expected key.

This fixes the bug reported by Apollon Oikonomopoulos.

This bug was introduced somewhere in the 1.5-dev process.

include/proto/proto_tcp.h
src/session.c

index af7e28a90f199f1c795c41817f2dbb759323bf0d..4adf4d2fa4b18897513a5408b3e1f96b9dd63267 100644 (file)
@@ -40,19 +40,43 @@ int tcp_inspect_response(struct session *s, struct channel *rep, int an_bit);
 int tcp_exec_req_rules(struct session *s);
 
 /* Converts the INET/INET6 source address to a stick_table key usable for table
- * lookups. Returns either NULL if the source cannot be converted (eg: not
- * IPv4) or a pointer to the converted result in static_table_key in the
- * appropriate format (IP).
+ * lookups. <type> can be STKTABLE_TYPE_IP or STKTABLE_TYPE_IPV6. The function
+ * try to convert the incoming IP to the type expected by the sticktable.
+ * Returns either NULL if the source cannot be converted (eg: not IPv4) or a
+ * pointer to the converted result in static_table_key in the appropriate format
+ * (IP).
  */
-static inline struct stktable_key *addr_to_stktable_key(struct sockaddr_storage *addr)
+static inline struct stktable_key *addr_to_stktable_key(struct sockaddr_storage *addr, long type)
 {
        switch (addr->ss_family) {
        case AF_INET:
-               static_table_key->key = (void *)&((struct sockaddr_in *)addr)->sin_addr;
-               break;
+               /* Convert IPv4 to IPv4 key. */
+               if (type == STKTABLE_TYPE_IP) {
+                       static_table_key->key = (void *)&((struct sockaddr_in *)addr)->sin_addr;
+                       break;
+               }
+               /* Convert IPv4 to IPv6 key. */
+               if (type == STKTABLE_TYPE_IPV6) {
+                       v4tov6(&static_table_key->data.ipv6, &((struct sockaddr_in *)addr)->sin_addr);
+                       static_table_key->key = &static_table_key->data.ipv6;
+                       break;
+               }
+               return NULL;
+
        case AF_INET6:
-               static_table_key->key = (void *)&((struct sockaddr_in6 *)addr)->sin6_addr;
-               break;
+               /* Convert IPv6 to IPv4 key. This conversion can be failed. */
+               if (type == STKTABLE_TYPE_IP) {
+                       if (!v6tov4(&static_table_key->data.ip, &((struct sockaddr_in6 *)addr)->sin6_addr))
+                               return NULL;
+                       static_table_key->key = &static_table_key->data.ip;
+                       break;
+               }
+               /* Convert IPv6 to IPv6 key. */
+               if (type == STKTABLE_TYPE_IPV6) {
+                       static_table_key->key = (void *)&((struct sockaddr_in6 *)addr)->sin6_addr;
+                       break;
+               }
+               return NULL;
        default:
                return NULL;
        }
index cada0ab99fe96d49372538d36d211a0658883e9f..99f7558ae88ccfac2ed416dfaf652c703904d956 100644 (file)
@@ -2656,7 +2656,7 @@ smp_fetch_sc_stkctr(struct session *l4, const struct arg *args, const char *kw)
                if (!conn)
                        return NULL;
 
-               key = addr_to_stktable_key(&conn->addr.from);
+               key = addr_to_stktable_key(&conn->addr.from, args->data.prx->table.type);
                if (!key)
                        return NULL;
 
@@ -2880,7 +2880,7 @@ smp_fetch_src_updt_conn_cnt(struct proxy *px, struct session *l4, void *l7, unsi
        if (!conn)
                return 0;
 
-       key = addr_to_stktable_key(&conn->addr.from);
+       key = addr_to_stktable_key(&conn->addr.from, px->table.type);
        if (!key)
                return 0;