Only remove entries to the VPN server on exit.

We might have other IPSec users, and flushing everything causes problems.

Bug: 4171459
Change-Id: Icebd4a04f9b88890ac1cfd587673fcf906a00aa5
diff --git a/setup.c b/setup.c
index b56c503..8bbbf81 100644
--- a/setup.c
+++ b/setup.c
@@ -49,6 +49,7 @@
 static struct remoteconf remoteconf;
 static struct sainfo sainfo;
 static char *pre_shared_key;
+static struct sockaddr target;
 
 struct localconf *lcconf = &localconf;
 char *script_names[SCRIPT_MAX + 1];
@@ -178,15 +179,51 @@
     }
 }
 
+static int match(struct sadb_address *address)
+{
+    if (address) {
+        struct sockaddr *source = PFKEY_ADDR_SADDR(address);
+        return !cmpsaddrwop(source, &target);
+    }
+    return 0;
+}
+
 /* flush; spdflush; */
 static void flush()
 {
+    struct sadb_msg *p;
+    int replies = 0;
     int key = pfkey_open();
-    if (key != -1) {
-        pfkey_send_flush(key, SADB_SATYPE_UNSPEC);
-        pfkey_send_spdflush(key);
-        pfkey_close(key);
+
+    if (pfkey_send_dump(key, SADB_SATYPE_UNSPEC) <= 0 ||
+        pfkey_send_spddump(key) <= 0) {
+        do_plog(LLV_ERROR, "Cannot dump SAD and SPD");
+        exit(1);
     }
+
+    for (p = NULL; replies < 2 && (p = pfkey_recv(key)) != NULL; free(p)) {
+        caddr_t q[SADB_EXT_MAX + 1];
+
+        if (p->sadb_msg_type != SADB_DUMP &&
+            p->sadb_msg_type != SADB_X_SPDDUMP) {
+            continue;
+        }
+        replies += !p->sadb_msg_seq;
+
+        if (p->sadb_msg_errno || pfkey_align(p, q) || pfkey_check(q)) {
+            continue;
+        }
+        if (match((struct sadb_address *)q[SADB_EXT_ADDRESS_SRC]) ||
+            match((struct sadb_address *)q[SADB_EXT_ADDRESS_DST])) {
+            p->sadb_msg_type = (p->sadb_msg_type == SADB_DUMP) ?
+                               SADB_DELETE : SADB_X_SPDDELETE;
+            p->sadb_msg_reserved = 0;
+            p->sadb_msg_seq = 0;
+            pfkey_send(key, p, PFKEY_UNUNIT64(p->sadb_msg_len));
+        }
+    }
+
+    pfkey_close(key);
 }
 
 /* flush; spdflush;
@@ -197,13 +234,9 @@
         struct sadb_x_policy p;
         struct sadb_x_ipsecrequest q;
     } policy;
-    int mask = (local->sa_family == AF_INET) ? sizeof(struct in_addr) * 8 :
+    int prefix = (local->sa_family == AF_INET) ? sizeof(struct in_addr) * 8 :
                sizeof(struct in6_addr) * 8;
     int key = pfkey_open();
-    if (key == -1) {
-        do_plog(LLV_ERROR, "Cannot create KEY socket\n");
-        exit(1);
-    }
 
     memset(&policy, 0, sizeof(policy));
     policy.p.sadb_x_policy_len = PFKEY_UNIT64(sizeof(policy));
@@ -218,11 +251,11 @@
     policy.q.sadb_x_ipsecrequest_mode = IPSEC_MODE_TRANSPORT;
     policy.q.sadb_x_ipsecrequest_level = IPSEC_LEVEL_REQUIRE;
 
-    if (pfkey_send_flush(key, SADB_SATYPE_UNSPEC) <= 0 ||
-        pfkey_send_spdflush(key) <= 0 ||
-        pfkey_send_spdadd(key, local, mask, remote, mask, IPPROTO_UDP,
+    target = *remote;
+    flush();
+    if (pfkey_send_spdadd(key, local, prefix, remote, prefix, IPPROTO_UDP,
                           (caddr_t)&policy, sizeof(policy), 0) <= 0) {
-        do_plog(LLV_ERROR, "Cannot initialize SA and SPD\n");
+        do_plog(LLV_ERROR, "Cannot initialize SAD and SPD\n");
         exit(1);
     }
     pfkey_close(key);
@@ -243,7 +276,7 @@
     /* Set local address and remote address. */
     set_address(argv[1], argv[2]);
 
-    /* Initialize SA and SPD. */
+    /* Initialize SAD and SPD. */
     spdadd(myaddrs[0].addr, remoteconf.remote);
 
     /* Set local port and remote port. */