Commit aa1236cd authored by Jason Baron's avatar Jason Baron Committed by David S. Miller

tcp: add support for optional TFO backup key to net.ipv4.tcp_fastopen_key

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: default avatarJason Baron <jbaron@akamai.com>
Signed-off-by: default avatarChristoph Paasch <cpaasch@apple.com>
Acked-by: default avatarYuchung Cheng <ycheng@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0f1ce023
...@@ -277,55 +277,97 @@ static int proc_allowed_congestion_control(struct ctl_table *ctl, ...@@ -277,55 +277,97 @@ static int proc_allowed_congestion_control(struct ctl_table *ctl,
return ret; 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, static int proc_tcp_fastopen_key(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, void __user *buffer, size_t *lenp,
loff_t *ppos) loff_t *ppos)
{ {
struct net *net = container_of(table->data, struct net, struct net *net = container_of(table->data, struct net,
ipv4.sysctl_tcp_fastopen); ipv4.sysctl_tcp_fastopen);
struct ctl_table tbl = { .maxlen = (TCP_FASTOPEN_KEY_LENGTH * 2 + 10) }; /* maxlen to print the list of keys in hex (*2), with dashes
struct tcp_fastopen_context *ctxt; * separating doublewords and a comma in between keys.
u32 user_key[4]; /* 16 bytes, matching TCP_FASTOPEN_KEY_LENGTH */ */
__le32 key[4]; struct ctl_table tbl = { .maxlen = ((TCP_FASTOPEN_KEY_LENGTH *
int ret, i; 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); tbl.data = kmalloc(tbl.maxlen, GFP_KERNEL);
if (!tbl.data) if (!tbl.data)
return -ENOMEM; return -ENOMEM;
rcu_read_lock(); rcu_read_lock();
ctxt = rcu_dereference(net->ipv4.tcp_fastopen_ctx); ctx = rcu_dereference(net->ipv4.tcp_fastopen_ctx);
if (ctxt) if (ctx) {
memcpy(key, ctxt->key, TCP_FASTOPEN_KEY_LENGTH); n_keys = tcp_fastopen_context_len(ctx);
else memcpy(&key[0], &ctx->key[0], TCP_FASTOPEN_KEY_LENGTH * n_keys);
memset(key, 0, sizeof(key)); }
rcu_read_unlock(); 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]); user_key[i] = le32_to_cpu(key[i]);
snprintf(tbl.data, tbl.maxlen, "%08x-%08x-%08x-%08x", for (i = 0; i < n_keys; i++) {
user_key[0], user_key[1], user_key[2], user_key[3]); 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); ret = proc_dostring(&tbl, write, buffer, lenp, ppos);
if (write && ret == 0) { if (write && ret == 0) {
if (sscanf(tbl.data, "%x-%x-%x-%x", user_key, user_key + 1, backup_data = strchr(tbl.data, ',');
user_key + 2, user_key + 3) != 4) { if (backup_data) {
*backup_data = '\0';
backup_data++;
}
if (sscanf_key(tbl.data, key)) {
ret = -EINVAL; ret = -EINVAL;
goto bad_key; goto bad_key;
} }
if (backup_data) {
for (i = 0; i < ARRAY_SIZE(user_key); i++) if (sscanf_key(backup_data, key + 4)) {
key[i] = cpu_to_le32(user_key[i]); ret = -EINVAL;
goto bad_key;
tcp_fastopen_reset_cipher(net, NULL, key, NULL, }
}
tcp_fastopen_reset_cipher(net, NULL, key,
backup_data ? key + 4 : NULL,
TCP_FASTOPEN_KEY_LENGTH); TCP_FASTOPEN_KEY_LENGTH);
} }
bad_key: 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); kfree(tbl.data);
return ret; return ret;
} }
...@@ -933,7 +975,12 @@ static struct ctl_table ipv4_net_table[] = { ...@@ -933,7 +975,12 @@ static struct ctl_table ipv4_net_table[] = {
.procname = "tcp_fastopen_key", .procname = "tcp_fastopen_key",
.mode = 0600, .mode = 0600,
.data = &init_net.ipv4.sysctl_tcp_fastopen, .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, .proc_handler = proc_tcp_fastopen_key,
}, },
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment