]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
tcp: add support for optional TFO backup key to net.ipv4.tcp_fastopen_key
authorJason Baron <jbaron@akamai.com>
Wed, 29 May 2019 16:33:59 +0000 (12:33 -0400)
committerDavid S. Miller <davem@davemloft.net>
Thu, 30 May 2019 20:41:26 +0000 (13:41 -0700)
Add the ability to add a backup TFO key as:

# echo "x-x-x-x,x-x-x-x" > /proc/sys/net/ipv4/tcp_fastopen_key

The key before the comma acks as the primary TFO key and the key after the
comma is the backup TFO key. This change is intended to be backwards
compatible since if only one key is set, userspace will simply read back
that single key as follows:

# echo "x-x-x-x" > /proc/sys/net/ipv4/tcp_fastopen_key
# cat /proc/sys/net/ipv4/tcp_fastopen_key
x-x-x-x

Signed-off-by: Jason Baron <jbaron@akamai.com>
Signed-off-by: Christoph Paasch <cpaasch@apple.com>
Acked-by: Yuchung Cheng <ycheng@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/sysctl_net_ipv4.c

index 72dc8ca98d43cb005ed52dfec39b5e1f2657cae3..90f09e47198bff9fdf2d42ff43e8dba11fb7f2df 100644 (file)
@@ -277,55 +277,97 @@ static int proc_allowed_congestion_control(struct ctl_table *ctl,
        return ret;
 }
 
+static int sscanf_key(char *buf, __le32 *key)
+{
+       u32 user_key[4];
+       int i, ret = 0;
+
+       if (sscanf(buf, "%x-%x-%x-%x", user_key, user_key + 1,
+                  user_key + 2, user_key + 3) != 4) {
+               ret = -EINVAL;
+       } else {
+               for (i = 0; i < ARRAY_SIZE(user_key); i++)
+                       key[i] = cpu_to_le32(user_key[i]);
+       }
+       pr_debug("proc TFO key set 0x%x-%x-%x-%x <- 0x%s: %u\n",
+                user_key[0], user_key[1], user_key[2], user_key[3], buf, ret);
+
+       return ret;
+}
+
 static int proc_tcp_fastopen_key(struct ctl_table *table, int write,
                                 void __user *buffer, size_t *lenp,
                                 loff_t *ppos)
 {
        struct net *net = container_of(table->data, struct net,
            ipv4.sysctl_tcp_fastopen);
-       struct ctl_table tbl = { .maxlen = (TCP_FASTOPEN_KEY_LENGTH * 2 + 10) };
-       struct tcp_fastopen_context *ctxt;
-       u32  user_key[4]; /* 16 bytes, matching TCP_FASTOPEN_KEY_LENGTH */
-       __le32 key[4];
-       int ret, i;
+       /* maxlen to print the list of keys in hex (*2), with dashes
+        * separating doublewords and a comma in between keys.
+        */
+       struct ctl_table tbl = { .maxlen = ((TCP_FASTOPEN_KEY_LENGTH *
+                                           2 * TCP_FASTOPEN_KEY_MAX) +
+                                           (TCP_FASTOPEN_KEY_MAX * 5)) };
+       struct tcp_fastopen_context *ctx;
+       u32 user_key[TCP_FASTOPEN_KEY_MAX * 4];
+       __le32 key[TCP_FASTOPEN_KEY_MAX * 4];
+       char *backup_data;
+       int ret, i = 0, off = 0, n_keys = 0;
 
        tbl.data = kmalloc(tbl.maxlen, GFP_KERNEL);
        if (!tbl.data)
                return -ENOMEM;
 
        rcu_read_lock();
-       ctxt = rcu_dereference(net->ipv4.tcp_fastopen_ctx);
-       if (ctxt)
-               memcpy(key, ctxt->key, TCP_FASTOPEN_KEY_LENGTH);
-       else
-               memset(key, 0, sizeof(key));
+       ctx = rcu_dereference(net->ipv4.tcp_fastopen_ctx);
+       if (ctx) {
+               n_keys = tcp_fastopen_context_len(ctx);
+               memcpy(&key[0], &ctx->key[0], TCP_FASTOPEN_KEY_LENGTH * n_keys);
+       }
        rcu_read_unlock();
 
-       for (i = 0; i < ARRAY_SIZE(key); i++)
+       if (!n_keys) {
+               memset(&key[0], 0, TCP_FASTOPEN_KEY_LENGTH);
+               n_keys = 1;
+       }
+
+       for (i = 0; i < n_keys * 4; i++)
                user_key[i] = le32_to_cpu(key[i]);
 
-       snprintf(tbl.data, tbl.maxlen, "%08x-%08x-%08x-%08x",
-               user_key[0], user_key[1], user_key[2], user_key[3]);
+       for (i = 0; i < n_keys; i++) {
+               off += snprintf(tbl.data + off, tbl.maxlen - off,
+                               "%08x-%08x-%08x-%08x",
+                               user_key[i * 4],
+                               user_key[i * 4 + 1],
+                               user_key[i * 4 + 2],
+                               user_key[i * 4 + 3]);
+               if (i + 1 < n_keys)
+                       off += snprintf(tbl.data + off, tbl.maxlen - off, ",");
+       }
+
        ret = proc_dostring(&tbl, write, buffer, lenp, ppos);
 
        if (write && ret == 0) {
-               if (sscanf(tbl.data, "%x-%x-%x-%x", user_key, user_key + 1,
-                          user_key + 2, user_key + 3) != 4) {
+               backup_data = strchr(tbl.data, ',');
+               if (backup_data) {
+                       *backup_data = '\0';
+                       backup_data++;
+               }
+               if (sscanf_key(tbl.data, key)) {
                        ret = -EINVAL;
                        goto bad_key;
                }
-
-               for (i = 0; i < ARRAY_SIZE(user_key); i++)
-                       key[i] = cpu_to_le32(user_key[i]);
-
-               tcp_fastopen_reset_cipher(net, NULL, key, NULL,
+               if (backup_data) {
+                       if (sscanf_key(backup_data, key + 4)) {
+                               ret = -EINVAL;
+                               goto bad_key;
+                       }
+               }
+               tcp_fastopen_reset_cipher(net, NULL, key,
+                                         backup_data ? key + 4 : NULL,
                                          TCP_FASTOPEN_KEY_LENGTH);
        }
 
 bad_key:
-       pr_debug("proc FO key set 0x%x-%x-%x-%x <- 0x%s: %u\n",
-               user_key[0], user_key[1], user_key[2], user_key[3],
-              (char *)tbl.data, ret);
        kfree(tbl.data);
        return ret;
 }
@@ -933,7 +975,12 @@ static struct ctl_table ipv4_net_table[] = {
                .procname       = "tcp_fastopen_key",
                .mode           = 0600,
                .data           = &init_net.ipv4.sysctl_tcp_fastopen,
-               .maxlen         = ((TCP_FASTOPEN_KEY_LENGTH * 2) + 10),
+               /* maxlen to print the list of keys in hex (*2), with dashes
+                * separating doublewords and a comma in between keys.
+                */
+               .maxlen         = ((TCP_FASTOPEN_KEY_LENGTH *
+                                  2 * TCP_FASTOPEN_KEY_MAX) +
+                                  (TCP_FASTOPEN_KEY_MAX * 5)),
                .proc_handler   = proc_tcp_fastopen_key,
        },
        {