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: 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>
This commit is contained in:
parent
0f1ce02368
commit
aa1236cdfa
|
@ -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,
|
||||
},
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue