Add a cache of recently seen addresses.
authorGuus Sliepen <guus@tinc-vpn.org>
Fri, 5 Jan 2018 21:49:30 +0000 (22:49 +0100)
committerGuus Sliepen <guus@tinc-vpn.org>
Sat, 6 Jan 2018 22:35:51 +0000 (23:35 +0100)
This maintains a cache file for each host we have communicated with, either
via TCP or UDP. The cache is used when trying to make outgoing connections,
and is updated whenever a successful TCP or UDP connection is established.
Up to 8 addresses are stored in the cache.

Currently, the cache is stored in /etc/tinc/NETNAME/cache. The directory
has to be manually created to opt in to this feature for now.

src/Makefile.am
src/address_cache.c [new file with mode: 0644]
src/address_cache.h [new file with mode: 0644]
src/autoconnect.c
src/net.h
src/net_packet.c
src/net_socket.c
src/node.c
src/node.h
src/protocol_misc.c

index 253e02a..ebf8f71 100644 (file)
@@ -42,6 +42,7 @@ chacha_poly1305_SOURCES = \
        chacha-poly1305/poly1305.c chacha-poly1305/poly1305.h
 
 tincd_SOURCES = \
+       address_cache.c address_cache.h \
        autoconnect.c autoconnect.h \
        buffer.c buffer.h \
        cipher.h \
diff --git a/src/address_cache.c b/src/address_cache.c
new file mode 100644 (file)
index 0000000..552e1f2
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+    address_cache.c -- Manage cache of recently seen addresses
+    Copyright (C) 2018 Guus Sliepen <guus@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "system.h"
+
+#include "address_cache.h"
+#include "conf.h"
+#include "names.h"
+#include "netutl.h"
+#include "xalloc.h"
+
+static const unsigned int NOT_CACHED = -1;
+
+// Find edges pointing to this node, and use them to build a list of unique, known addresses.
+static struct addrinfo *get_known_addresses(node_t *n) {
+       struct addrinfo *ai = NULL;
+       struct addrinfo *oai = NULL;
+
+       for splay_each(edge_t, e, n->edge_tree) {
+               if(!e->reverse) {
+                       continue;
+               }
+
+               bool found = false;
+
+               for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) {
+                       if(!sockaddrcmp(&e->reverse->address, (sockaddr_t *)aip->ai_addr)) {
+                               found = true;
+                               break;
+                       }
+               }
+
+               if(found) {
+                       continue;
+               }
+
+               oai = ai;
+               ai = xzalloc(sizeof(*ai));
+               ai->ai_family = e->reverse->address.sa.sa_family;
+               ai->ai_socktype = SOCK_STREAM;
+               ai->ai_protocol = IPPROTO_TCP;
+               ai->ai_addrlen = SALEN(e->reverse->address.sa);
+               ai->ai_addr = xmalloc(ai->ai_addrlen);
+               memcpy(ai->ai_addr, &e->reverse->address, ai->ai_addrlen);
+               ai->ai_next = oai;
+       }
+
+       return ai;
+}
+
+static void free_known_addresses(struct addrinfo *ai) {
+       for(struct addrinfo *aip = ai, *next; aip; aip = next) {
+               next = aip->ai_next;
+               free(aip);
+       }
+}
+
+static unsigned int find_cached(address_cache_t *cache, const sockaddr_t *sa) {
+       for(unsigned int i = 0; i < cache->data.used; i++)
+               if(!sockaddrcmp(&cache->data.address[i], sa)) {
+                       return i;
+               }
+
+       return NOT_CACHED;
+}
+
+void add_recent_address(address_cache_t *cache, const sockaddr_t *sa) {
+       // Check if it's already cached
+       unsigned int pos = find_cached(cache, sa);
+
+       // It's in the first spot, so nothing to do
+       if (pos == 0) {
+               return;
+       }
+
+       // Shift everything, move/add the address to the first slot
+       if(pos == NOT_CACHED) {
+               if(cache->data.used < MAX_CACHED_ADDRESSES)
+                       cache->data.used++;
+               pos = cache->data.used - 1;
+       }
+
+       memmove(&cache->data.address[1], &cache->data.address[0], pos * sizeof(cache->data.address[0]));
+
+       cache->data.address[0] = *sa;
+
+       // Write the cache
+       char fname[PATH_MAX];
+       snprintf(fname, sizeof(fname), "%s" SLASH "cache" SLASH "%s", confbase, cache->node->name);
+       FILE *fp = fopen(fname, "wb");
+
+       if(fp) {
+               fprintf(stderr, "Writing cache to %s\n", fname);
+               fwrite(&cache->data, sizeof(cache->data), 1, fp);
+               fclose(fp);
+       }
+}
+
+const sockaddr_t *get_recent_address(address_cache_t *cache) {
+       // Check if there is an address in our cache of recently seen addresses
+       if(cache->tried < cache->data.used) {
+               return &cache->data.address[cache->tried++];
+       }
+
+       // Next, check any recently seen addresses not in our cache
+       while(cache->tried == cache->data.used) {
+               if(!cache->ai) {
+                       cache->aip = cache->ai = get_known_addresses(cache->node);
+               }
+
+               if(cache->ai) {
+                       if(cache->aip) {
+                               sockaddr_t *sa = (sockaddr_t *)cache->aip;
+
+                               if(find_cached(cache, sa) != NOT_CACHED) {
+                                       continue;
+                               }
+
+                               cache->aip = cache->aip->ai_next;
+                               return sa;
+                       } else {
+                               free_known_addresses(cache->ai);
+                               cache->ai = NULL;
+                       }
+               }
+
+               cache->tried++;
+       }
+
+       // Otherwise, check if there are any known Address statements
+       if(!cache->config_tree) {
+               init_configuration(&cache->config_tree);
+               read_host_config(cache->config_tree, cache->node->name, false);
+               cache->cfg = lookup_config(cache->config_tree, "Address");
+       }
+
+       while(cache->cfg && !cache->ai) {
+               char *address, *port;
+
+               get_config_string(cache->cfg, &address);
+
+               char *space = strchr(address, ' ');
+
+               if(space) {
+                       port = xstrdup(space + 1);
+                       *space = 0;
+               } else {
+                       if(!get_config_string(lookup_config(cache->config_tree, "Port"), &port)) {
+                               port = xstrdup("655");
+                       }
+               }
+
+               cache->aip = cache->ai = str2addrinfo(address, port, SOCK_STREAM);
+               free(address);
+               free(port);
+
+               cache->cfg = lookup_config_next(cache->config_tree, cache->cfg);
+       }
+
+       if(cache->aip) {
+               sockaddr_t *sa = (sockaddr_t *)cache->aip->ai_addr;
+               cache->aip = cache->aip->ai_next;
+
+               if(!cache->aip) {
+                       freeaddrinfo(cache->aip);
+                       cache->aip = NULL;
+               }
+
+               return sa;
+       }
+
+       // We're all out of addresses.
+       exit_configuration(&cache->config_tree);
+       return false;
+}
+
+address_cache_t *open_address_cache(node_t *node) {
+       address_cache_t *cache = xmalloc(sizeof(*cache));
+       cache->node = node;
+
+       // Try to open an existing address cache
+       char fname[PATH_MAX];
+       snprintf(fname, sizeof(fname), "%s" SLASH "cache" SLASH "%s", confbase, node->name);
+       FILE *fp = fopen(fname, "rb");
+
+       if(!fp || fread(&cache->data, sizeof(cache->data), 1, fp) != 1 || cache->data.version != ADDRESS_CACHE_VERSION) {
+               memset(&cache->data, 0, sizeof(cache->data));
+       }
+
+       if(fp) {
+               fclose(fp);
+       }
+
+       // Ensure we have a valid state
+       cache->config_tree = NULL;
+       cache->cfg = NULL;
+       cache->ai = NULL;
+       cache->aip = NULL;
+       cache->tried = 0;
+       cache->data.version = ADDRESS_CACHE_VERSION;
+
+       if(cache->data.used > MAX_CACHED_ADDRESSES) {
+               cache->data.used = 0;
+       }
+
+       return cache;
+}
+
+void reset_address_cache(address_cache_t *cache, const sockaddr_t *sa) {
+       if(sa) {
+               add_recent_address(cache, sa);
+       }
+
+       if(cache->config_tree) {
+               exit_configuration(&cache->config_tree);
+       }
+
+       if(cache->ai) {
+               if(cache->tried == cache->data.used) {
+                       free_known_addresses(cache->ai);
+               } else {
+                       freeaddrinfo(cache->ai);
+               }
+       }
+
+       cache->config_tree = NULL;
+       cache->cfg = NULL;
+       cache->ai = NULL;
+       cache->aip = NULL;
+       cache->tried = 0;
+}
+
+void close_address_cache(address_cache_t *cache) {
+       if(cache->config_tree) {
+               exit_configuration(&cache->config_tree);
+       }
+
+       if(cache->ai) {
+               if(cache->tried == cache->data.used) {
+                       free_known_addresses(cache->ai);
+               } else {
+                       freeaddrinfo(cache->ai);
+               }
+       }
+
+       free(cache);
+}
diff --git a/src/address_cache.h b/src/address_cache.h
new file mode 100644 (file)
index 0000000..4ce6ec5
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef TINC_ADDRESS_CACHE_H
+#define TINC_ADDRESS_CACHE_H
+
+/*
+    address_cache.h -- header for address_cache.c
+    Copyright (C) 2018 Guus Sliepen <guus@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "net.h"
+
+#define MAX_CACHED_ADDRESSES 8
+#define ADDRESS_CACHE_VERSION 1
+
+typedef struct address_cache_t {
+       struct node_t *node;
+       struct splay_tree_t *config_tree;
+       struct config_t *cfg;
+       struct addrinfo *ai;
+       struct addrinfo *aip;
+       unsigned int tried;
+
+       struct {
+               unsigned int version;
+               unsigned int used;
+               sockaddr_t address[MAX_CACHED_ADDRESSES];
+       } data;
+} address_cache_t;
+
+void add_recent_address(address_cache_t *cache, const sockaddr_t *sa);
+const sockaddr_t *get_recent_address(address_cache_t *cache);
+
+address_cache_t *open_address_cache(struct node_t *node);
+void reset_address_cache(address_cache_t *cache, const sockaddr_t *sa);
+void close_address_cache(address_cache_t *cache);
+
+#endif
index 132467e..0fa6f4e 100644 (file)
@@ -54,7 +54,7 @@ static void make_new_connection() {
                bool found = false;
 
                for list_each(outgoing_t, outgoing, outgoing_list) {
-                       if(!strcmp(outgoing->name, n->name)) {
+                       if(outgoing->node == n) {
                                found = true;
                                break;
                        }
@@ -63,7 +63,7 @@ static void make_new_connection() {
                if(!found) {
                        logger(DEBUG_CONNECTIONS, LOG_INFO, "Autoconnecting to %s", n->name);
                        outgoing_t *outgoing = xzalloc(sizeof(*outgoing));
-                       outgoing->name = xstrdup(n->name);
+                       outgoing->node = n;
                        list_insert_tail(outgoing_list, outgoing);
                        setup_outgoing_connection(outgoing, false);
                }
@@ -92,15 +92,16 @@ static void connect_to_unreachable() {
                        return;
                }
 
-               /* Are we already trying to make an outgoing connection to it? If not, return. */
-               for list_each(outgoing_t, outgoing, outgoing_list)
-                       if(!strcmp(outgoing->name, n->name)) {
+               /* Are we already trying to make an outgoing connection to it? If so, return. */
+               for list_each(outgoing_t, outgoing, outgoing_list) {
+                       if(outgoing->node == n) {
                                return;
                        }
+               }
 
                logger(DEBUG_CONNECTIONS, LOG_INFO, "Autoconnecting to %s", n->name);
                outgoing_t *outgoing = xzalloc(sizeof(*outgoing));
-               outgoing->name = xstrdup(n->name);
+               outgoing->node = n;
                list_insert_tail(outgoing_list, outgoing);
                setup_outgoing_connection(outgoing, false);
 
@@ -159,7 +160,7 @@ static void drop_superfluous_pending_connections() {
                        continue;
                }
 
-               logger(DEBUG_CONNECTIONS, LOG_INFO, "Cancelled outgoing connection to %s", o->name);
+               logger(DEBUG_CONNECTIONS, LOG_INFO, "Cancelled outgoing connection to %s", o->node->name);
                list_delete_node(outgoing_list, node);
        }
 }
index a434644..827194e 100644 (file)
--- a/src/net.h
+++ b/src/net.h
@@ -122,13 +122,9 @@ typedef struct listen_socket_t {
 #include "list.h"
 
 typedef struct outgoing_t {
-       char *name;
+       struct node_t *node;
        int timeout;
-       splay_tree_t *config_tree;
-       struct config_t *cfg;
-       struct addrinfo *ai;  // addresses from config files
-       struct addrinfo *aip;
-       struct addrinfo *kai; // addresses known via other online nodes (use free_known_addresses())
+       struct address_cache_t *address_cache;
        timeout_t ev;
 } outgoing_t;
 
index 2175180..7bd619f 100644 (file)
@@ -30,6 +30,7 @@
 #include LZO1X_H
 #endif
 
+#include "address_cache.h"
 #include "cipher.h"
 #include "conf.h"
 #include "connection.h"
@@ -153,7 +154,13 @@ static void udp_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
        /* It's a valid reply: now we know bidirectional communication
           is possible using the address and socket that the reply
           packet used. */
-       n->status.udp_confirmed = true;
+       if(!n->status.udp_confirmed) {
+               n->status.udp_confirmed = true;
+               fprintf(stderr, "Updating address cache...\n");
+               if (!n->address_cache)
+                       n->address_cache = open_address_cache(n);
+               reset_address_cache(n->address_cache, &n->address);
+       }
 
        // Reset the UDP ping timer.
        n->udp_ping_sent = now;
index 979e84b..30ab79e 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "system.h"
 
+#include "address_cache.h"
 #include "conf.h"
 #include "connection.h"
 #include "control_common.h"
@@ -491,73 +492,26 @@ static void handle_meta_io(void *data, int flags) {
        }
 }
 
-static void free_known_addresses(struct addrinfo *ai) {
-       for(struct addrinfo *aip = ai, *next; aip; aip = next) {
-               next = aip->ai_next;
-               free(aip);
-       }
-}
-
 bool do_outgoing_connection(outgoing_t *outgoing) {
-       char *address, *port, *space;
+       const sockaddr_t *sa;
        struct addrinfo *proxyai = NULL;
        int result;
 
 begin:
+       sa = get_recent_address(outgoing->address_cache);
 
-       if(!outgoing->ai && !outgoing->kai) {
-               if(!outgoing->cfg) {
-                       logger(DEBUG_CONNECTIONS, LOG_ERR, "Could not set up a meta connection to %s", outgoing->name);
-                       retry_outgoing(outgoing);
-                       return false;
-               }
-
-               get_config_string(outgoing->cfg, &address);
-
-               space = strchr(address, ' ');
-
-               if(space) {
-                       port = xstrdup(space + 1);
-                       *space = 0;
-               } else {
-                       if(!get_config_string(lookup_config(outgoing->config_tree, "Port"), &port)) {
-                               port = xstrdup("655");
-                       }
-               }
-
-               outgoing->ai = str2addrinfo(address, port, SOCK_STREAM);
-               free(address);
-               free(port);
-
-               outgoing->aip = outgoing->ai;
-               outgoing->cfg = lookup_config_next(outgoing->config_tree, outgoing->cfg);
-       }
-
-       if(!outgoing->aip) {
-               if(outgoing->ai) {
-                       freeaddrinfo(outgoing->ai);
-               }
-
-               outgoing->ai = NULL;
-
-               if(outgoing->kai) {
-                       free_known_addresses(outgoing->kai);
-               }
-
-               outgoing->kai = NULL;
-
-               goto begin;
+       if(!sa) {
+               logger(DEBUG_CONNECTIONS, LOG_ERR, "Could not set up a meta connection to %s", outgoing->node->name);
+               retry_outgoing(outgoing);
+               return false;
        }
 
        connection_t *c = new_connection();
        c->outgoing = outgoing;
-
-       memcpy(&c->address, outgoing->aip->ai_addr, outgoing->aip->ai_addrlen);
-       outgoing->aip = outgoing->aip->ai_next;
-
+       c->address = *sa;
        c->hostname = sockaddr2hostname(&c->address);
 
-       logger(DEBUG_CONNECTIONS, LOG_INFO, "Trying to connect to %s (%s)", outgoing->name, c->hostname);
+       logger(DEBUG_CONNECTIONS, LOG_INFO, "Trying to connect to %s (%s)", outgoing->node->name, c->hostname);
 
        if(!proxytype) {
                c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
@@ -617,7 +571,7 @@ begin:
        }
 
        if(result == -1 && !sockinprogress(sockerrno)) {
-               logger(DEBUG_CONNECTIONS, LOG_ERR, "Could not connect to %s (%s): %s", outgoing->name, c->hostname, sockstrerror(sockerrno));
+               logger(DEBUG_CONNECTIONS, LOG_ERR, "Could not connect to %s (%s): %s", outgoing->node->name, c->hostname, sockstrerror(sockerrno));
                free_connection(c);
 
                goto begin;
@@ -627,7 +581,7 @@ begin:
 
        c->last_ping_time = time(NULL);
        c->status.connecting = true;
-       c->name = xstrdup(outgoing->name);
+       c->name = xstrdup(outgoing->node->name);
 #ifndef DISABLE_LEGACY
        c->outcipher = myself->connection->outcipher;
        c->outdigest = myself->connection->outdigest;
@@ -643,50 +597,13 @@ begin:
        return true;
 }
 
-// Find edges pointing to this node, and use them to build a list of unique, known addresses.
-static struct addrinfo *get_known_addresses(node_t *n) {
-       struct addrinfo *ai = NULL;
-       struct addrinfo *oai = NULL;
-
-       for splay_each(edge_t, e, n->edge_tree) {
-               if(!e->reverse) {
-                       continue;
-               }
-
-               bool found = false;
-
-               for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) {
-                       if(!sockaddrcmp(&e->reverse->address, (sockaddr_t *)aip->ai_addr)) {
-                               found = true;
-                               break;
-                       }
-               }
-
-               if(found) {
-                       continue;
-               }
-
-               oai = ai;
-               ai = xzalloc(sizeof(*ai));
-               ai->ai_family = e->reverse->address.sa.sa_family;
-               ai->ai_socktype = SOCK_STREAM;
-               ai->ai_protocol = IPPROTO_TCP;
-               ai->ai_addrlen = SALEN(e->reverse->address.sa);
-               ai->ai_addr = xmalloc(ai->ai_addrlen);
-               memcpy(ai->ai_addr, &e->reverse->address, ai->ai_addrlen);
-               ai->ai_next = oai;
-       }
-
-       return ai;
-}
-
 void setup_outgoing_connection(outgoing_t *outgoing, bool verbose) {
        timeout_del(&outgoing->ev);
 
-       node_t *n = lookup_node(outgoing->name);
+       node_t *n = outgoing->node;
 
-       if(n && n->connection) {
-               logger(DEBUG_CONNECTIONS, LOG_INFO, "Already connected to %s", outgoing->name);
+       if(n->connection) {
+               logger(DEBUG_CONNECTIONS, LOG_INFO, "Already connected to %s", n->name);
 
                if(!n->connection->outgoing) {
                        n->connection->outgoing = outgoing;
@@ -696,19 +613,8 @@ void setup_outgoing_connection(outgoing_t *outgoing, bool verbose) {
                }
        }
 
-       init_configuration(&outgoing->config_tree);
-       read_host_config(outgoing->config_tree, outgoing->name, verbose);
-       outgoing->cfg = lookup_config(outgoing->config_tree, "Address");
-
-       if(!outgoing->cfg) {
-               if(n) {
-                       outgoing->aip = outgoing->kai = get_known_addresses(n);
-               }
-
-               if(!outgoing->kai) {
-                       logger(verbose ? DEBUG_ALWAYS : DEBUG_CONNECTIONS, LOG_DEBUG, "No address known for %s", outgoing->name);
-                       goto remove;
-               }
+       if(!outgoing->address_cache) {
+               outgoing->address_cache = open_address_cache(n);
        }
 
        do_outgoing_connection(outgoing);
@@ -859,20 +765,8 @@ void handle_new_unix_connection(void *data, int flags) {
 static void free_outgoing(outgoing_t *outgoing) {
        timeout_del(&outgoing->ev);
 
-       if(outgoing->ai) {
-               freeaddrinfo(outgoing->ai);
-       }
-
-       if(outgoing->kai) {
-               free_known_addresses(outgoing->kai);
-       }
-
-       if(outgoing->config_tree) {
-               exit_configuration(&outgoing->config_tree);
-       }
-
-       if(outgoing->name) {
-               free(outgoing->name);
+       if(outgoing->address_cache) {
+               close_address_cache(outgoing->address_cache);
        }
 
        free(outgoing);
@@ -911,7 +805,7 @@ void try_outgoing_connections(void) {
                bool found = false;
 
                for list_each(outgoing_t, outgoing, outgoing_list) {
-                       if(!strcmp(outgoing->name, name)) {
+                       if(!strcmp(outgoing->node->name, name)) {
                                found = true;
                                outgoing->timeout = 0;
                                break;
@@ -920,7 +814,13 @@ void try_outgoing_connections(void) {
 
                if(!found) {
                        outgoing_t *outgoing = xzalloc(sizeof(*outgoing));
-                       outgoing->name = name;
+                       node_t *n = lookup_node(name);
+                       if(!n) {
+                               n = new_node();
+                               n->name = xstrdup(name);
+                               node_add(n);
+                       }
+                       outgoing->node = n;
                        list_insert_tail(outgoing_list, outgoing);
                        setup_outgoing_connection(outgoing, true);
                }
index c00124d..bea23c7 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "system.h"
 
+#include "address_cache.h"
 #include "control_common.h"
 #include "hash.h"
 #include "logger.h"
@@ -118,6 +119,10 @@ void free_node(node_t *n) {
                free(n->late);
        }
 
+       if(n->address_cache) {
+               close_address_cache(n->address_cache);
+       }
+
        free(n);
 }
 
index daa0830..496880f 100644 (file)
@@ -110,6 +110,8 @@ typedef struct node_t {
        uint64_t in_bytes;
        uint64_t out_packets;
        uint64_t out_bytes;
+
+       struct address_cache_t *address_cache;
 } node_t;
 
 extern struct node_t *myself;
index d4a45e8..d808d73 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "system.h"
 
+#include "address_cache.h"
 #include "conf.h"
 #include "connection.h"
 #include "logger.h"
@@ -68,14 +69,7 @@ bool pong_h(connection_t *c, const char *request) {
 
        if(c->outgoing) {
                c->outgoing->timeout = 0;
-               c->outgoing->cfg = NULL;
-
-               if(c->outgoing->ai) {
-                       freeaddrinfo(c->outgoing->ai);
-               }
-
-               c->outgoing->ai = NULL;
-               c->outgoing->aip = NULL;
+               reset_address_cache(c->outgoing->address_cache, &c->address);
        }
 
        return true;