0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-11-08 12:18:42 +00:00

documentation, beautify

This commit is contained in:
Katerina Kubecova 2024-03-08 11:31:01 +01:00
parent 94a41cb6a0
commit 53ab4cb5b5
4 changed files with 100 additions and 49 deletions

View File

@ -2433,6 +2433,38 @@ protocol bfd [<name>] {
offers better resistance to replay attacks but may require more offers better resistance to replay attacks but may require more
computation. computation.
<tag>authentication keyed tcp AO</tag>
This authentication is similar to md5, but enables changing keys on living connection.
Key change is done via reconfiguring.
Key configuration of one key consists of two ids - one for local and one for remote machine.
The ids may, but does not have to be the same and must be in range 0 - 255. Among keys
on one protocol the local ids must be unique and the remote ids must be unique.
Used cryphtographic algorithm must be specified for each key.
Possible ciphers are "cmac(aes128)", "hmac(md5)" "hmac(sha1)", "hmac(sha224)",
"hmac(sha256)", "hmac(sha384)" and "hmac(sha512)". And, of course, there must
be specified a string password.
One key must be marked as "required". This key will be send as rnext key.
That means, if the other site know the required key, it uses the key for next packet.
In order to delete a currently used key (key which is required by the other site),
it is possible to mark the key as "deprecated". This key will be deleted first time
the other site requires another key.
Deleting a curently used key in config causes restart of the protocol.
The problem of directly deleting current key is, that we could treat such deleted key as deprecated,
but only until the protocol restarts. If it restarts, key is lost.
For example, connection is established. Then one side decides to remove current key and requires a newly added key.
The other side does not know the new key yet. For now, this is not problem, they still use the old key.
But, at this moment, some unexpected error occures at the first site.
It restarts, but it does not have the old key in config. One site does not have old key,
the other new key and triing other keys than required ones is not supported.
Editing existing keys (except of marking them "required" or "deprecated")
is not reccomended and leads to restarting protocol.
<tag>password "<M>text</M>"</tag> <tag>password "<M>text</M>"</tag>
Specifies a password used for authentication. See <ref id="proto-pass" Specifies a password used for authentication. See <ref id="proto-pass"
name="password"> common option for detailed description. Note that name="password"> common option for detailed description. Note that

View File

@ -1296,19 +1296,23 @@ bgp_incoming_connection(sock *sk, uint dummy UNUSED)
if (p->ao_key) if (p->ao_key)
{ {
if (check_ao_keys_id(sk->fd, p->ao_key) == 0) if (check_ao_keys_id(sk->fd, p->ao_key) == 0)
{ {
sk->use_ao = 1; sk->use_ao = 1;
for (struct bgp_ao_key *key = p->ao_key; key; key = key->next_key) for (struct bgp_ao_key *key = p->ao_key; key; key = key->next_key)
{ {
key->activ_alive = key->passiv_alive; key->activ_alive = key->passiv_alive;
if (key->key.required == 1) if (key->key.required == 1)
{ {
sk->desired_ao_key = key->key.remote_id; sk->desired_ao_key = key->key.remote_id;
ao_try_change_master(sk, key->key.local_id, key->key.remote_id); ao_try_change_master(sk, key->key.local_id, key->key.remote_id);
} }
} else if (key->key.required == -1)
} {
sk->proto_del_ao_key = p;
}
}
}
} }
if (p->cf->enable_extended_messages) if (p->cf->enable_extended_messages)
{ {
@ -2272,14 +2276,16 @@ int reconfigure_tcp_ao(struct bgp_proto *old_proto, struct bgp_config new)
if (compare_aos(&old_ao->key, &cf_ao->key)) if (compare_aos(&old_ao->key, &cf_ao->key))
return 0; return 0;
if (old_ao->activ_alive == 0 && cf_ao->key.required >= 0) if (old_ao->activ_alive == 0 && cf_ao->key.required >= 0)
{ {
if (sk_set_ao_auth(s_activ, old_proto->local_ip, old_proto->remote_ip, -1, s_activ->iface, old_ao->key.master_key, old_ao->key.local_id, old_ao->key.remote_id, old_ao->key.cipher, 0)) if (sk_set_ao_auth(s_activ, old_proto->local_ip, old_proto->remote_ip, -1, s_activ->iface,
old_ao->key.master_key, old_ao->key.local_id, old_ao->key.remote_id, old_ao->key.cipher, 0))
return 0; return 0;
old_ao->activ_alive = 1; old_ao->activ_alive = 1;
} }
if (old_ao->passiv_alive == 0 && cf_ao->key.required >= 0) if (old_ao->passiv_alive == 0 && cf_ao->key.required >= 0)
{ {
if (sk_set_ao_auth(s_passiv, old_proto->local_ip, old_proto->remote_ip, -1, s_passiv->iface, old_ao->key.master_key, old_ao->key.local_id, old_ao->key.remote_id, old_ao->key.cipher, 0)) if (sk_set_ao_auth(s_passiv, old_proto->local_ip, old_proto->remote_ip, -1, s_passiv->iface,
old_ao->key.master_key, old_ao->key.local_id, old_ao->key.remote_id, old_ao->key.cipher, 0))
return 0; return 0;
old_ao->passiv_alive = 1; old_ao->passiv_alive = 1;
} }
@ -2290,11 +2296,12 @@ int reconfigure_tcp_ao(struct bgp_proto *old_proto, struct bgp_config new)
s_passiv->desired_ao_key = old_ao->key.remote_id; s_passiv->desired_ao_key = old_ao->key.remote_id;
ao_try_change_master(s_activ, old_ao->key.local_id, old_ao->key.remote_id); ao_try_change_master(s_activ, old_ao->key.local_id, old_ao->key.remote_id);
if (old_proto->conn->hold_timer->expires != 0) if (old_proto->conn->hold_timer->expires != 0)
bgp_schedule_packet(old_proto->conn, NULL, PKT_KEEPALIVE); // We might send this keepalive shortly after another. RFC says we should wait, but since reconfiguration is rare, this is harmless. bgp_schedule_packet(old_proto->conn, NULL, PKT_KEEPALIVE); // We might send this keepalive shortly after another.
// RFC says we should wait, but since reconfiguration is rare, this is harmless.
} }
old_ao->key = cf_ao->key; old_ao->key = cf_ao->key;
old_ao->to_delete = 0; old_ao->to_delete = 0;
found = old_ao; found = old_ao;
} }
} }
if (!found) if (!found)
@ -2305,10 +2312,12 @@ int reconfigure_tcp_ao(struct bgp_proto *old_proto, struct bgp_config new)
key->passiv_alive = 0; key->passiv_alive = 0;
key->next_key = first; key->next_key = first;
old_proto->ao_key = key; old_proto->ao_key = key;
if (sk_set_ao_auth(s_passiv, old_proto->local_ip, old_proto->remote_ip, -1, s_passiv->iface, cf_ao->key.master_key, cf_ao->key.local_id, cf_ao->key.remote_id, cf_ao->key.cipher, 0)) if (sk_set_ao_auth(s_passiv, old_proto->local_ip, old_proto->remote_ip, -1, s_passiv->iface,
cf_ao->key.master_key, cf_ao->key.local_id, cf_ao->key.remote_id, cf_ao->key.cipher, 0))
return 0; return 0;
key->passiv_alive = 1; key->passiv_alive = 1;
if (sk_set_ao_auth(s_activ, old_proto->local_ip, old_proto->remote_ip, -1, s_passiv->iface, cf_ao->key.master_key, cf_ao->key.local_id, cf_ao->key.remote_id, cf_ao->key.cipher, 0)) if (sk_set_ao_auth(s_activ, old_proto->local_ip, old_proto->remote_ip, -1, s_passiv->iface,
cf_ao->key.master_key, cf_ao->key.local_id, cf_ao->key.remote_id, cf_ao->key.cipher, 0))
return 0; return 0;
key->activ_alive = 1; key->activ_alive = 1;
key->to_delete = 0; key->to_delete = 0;
@ -2320,7 +2329,8 @@ int reconfigure_tcp_ao(struct bgp_proto *old_proto, struct bgp_config new)
s_passiv->desired_ao_key = found->key.remote_id; s_passiv->desired_ao_key = found->key.remote_id;
ao_try_change_master(s_activ, found->key.local_id, found->key.remote_id); ao_try_change_master(s_activ, found->key.local_id, found->key.remote_id);
if (old_proto->conn->hold_timer->expires != 0) if (old_proto->conn->hold_timer->expires != 0)
bgp_schedule_packet(old_proto->conn, NULL, PKT_KEEPALIVE); // We might send this keepalive shortly after another. RFC says we should wait, but since reconfiguration is rare, this is harmless. bgp_schedule_packet(old_proto->conn, NULL, PKT_KEEPALIVE); // We might send this keepalive shortly after another.
// RFC says we should wait, but since reconfiguration is rare, this is harmless.
} }
} }
} }
@ -2334,7 +2344,7 @@ int reconfigure_tcp_ao(struct bgp_proto *old_proto, struct bgp_config new)
if (old_ao->key.remote_id == key_in_use_rem) if (old_ao->key.remote_id == key_in_use_rem)
{ {
log(L_WARN "TCP AO: deleting currently used key"); log(L_WARN "TCP AO: deleting currently used key");
return 0; return 0;
} }
if (ao_delete_key(s_activ, old_proto->remote_ip, -1, s_activ->iface, old_ao->key.local_id, old_ao->key.remote_id)) if (ao_delete_key(s_activ, old_proto->remote_ip, -1, s_activ->iface, old_ao->key.local_id, old_ao->key.remote_id))
return 0; return 0;

View File

@ -3410,22 +3410,30 @@ bgp_rx_packet(struct bgp_conn *conn, byte *pkt, uint len)
} }
} }
void int
delete_deprecated_key(sock *sk, struct bgp_proto *p, int key_rem_id) delete_deprecated_keys(sock *sk, struct bgp_proto *p, int new_rnext)
{ {
struct bgp_ao_key *key = p->ao_key; struct bgp_ao_key *key = p->ao_key;
while (key->key.remote_id != key_rem_id) int ret = 1;
while (key)
{ {
if (key->key.required == -1)
{
if (new_rnext == key->key.remote_id)
ret = 0;
else
{
if (ao_delete_key(sk, p->remote_ip, -1, sk->iface, key->key.local_id, key->key.remote_id))
bug("TCP AO: Can not delete deprecated key %i %i on socket %i", key->key.local_id, key->key.remote_id, sk->fd);
key->activ_alive = 0;
if (ao_delete_key(p->sock->sk, p->remote_ip, -1, p->sock->sk->iface, key->key.local_id, key->key.remote_id))
bug("TCP AO: Can not delete deprecated key %i %i on socket %i", key->key.local_id, key->key.remote_id, p->sock->sk->fd);
key->passiv_alive = 0;
}
}
key = key->next_key; key = key->next_key;
} }
if (key->key.required != -1) return ret;
bug("TCP AO: unexpected key management error");
if (ao_delete_key(sk, p->remote_ip, -1, sk->iface, key->key.local_id, key->key.remote_id))
bug("TCP AO: Can not delete deprecated key %i %i on socket %i", key->key.local_id, key->key.remote_id, sk->fd);
key->activ_alive = 0;
if (ao_delete_key(p->sock->sk, p->remote_ip, -1, p->sock->sk->iface, key->key.local_id, key->key.remote_id))
bug("TCP AO: Can not delete deprecated key %i %i on socket %i", key->key.local_id, key->key.remote_id, p->sock->sk->fd);
key->passiv_alive = 0;
} }
/** /**
@ -3454,8 +3462,8 @@ bgp_rx(sock *sk, uint size)
if (sk->proto_del_ao_key && sk->desired_ao_key == new_rnext) if (sk->proto_del_ao_key && sk->desired_ao_key == new_rnext)
{ {
delete_deprecated_key(sk, sk->proto_del_ao_key, sk->last_used_ao_key); if (delete_deprecated_keys(sk, sk->proto_del_ao_key, new_rnext))
sk->proto_del_ao_key = NULL; sk->proto_del_ao_key = NULL;
} }
sk->last_used_ao_key = new_rnext; sk->last_used_ao_key = new_rnext;
} }

View File

@ -217,7 +217,6 @@ void log_tcp_ao_info(int sock_fd)
struct tcp_ao_info_opt_ext tmp; struct tcp_ao_info_opt_ext tmp;
memset(&tmp, 0, sizeof(struct tcp_ao_info_opt_ext)); memset(&tmp, 0, sizeof(struct tcp_ao_info_opt_ext));
socklen_t len = sizeof(tmp); socklen_t len = sizeof(tmp);
log("socket: fd %i", sock_fd);
if (getsockopt(sock_fd, IPPROTO_TCP, TCP_AO_INFO, &tmp, &len)) if (getsockopt(sock_fd, IPPROTO_TCP, TCP_AO_INFO, &tmp, &len))
{ {
@ -225,8 +224,8 @@ void log_tcp_ao_info(int sock_fd)
return; return;
} }
else else
log(L_INFO "TCP AO:\ncurrent key id %i (rem), next key %i (loc),\n set current %i, is ao required %i\n good packets %i, bad packets %i", log(L_INFO "TCP AO on socket %i:\ncurrent key id %i (rem), next key %i (loc),\n set current %i, is ao required %i\n good packets %i, bad packets %i",
tmp.current_key, tmp.rnext, tmp.set_current, tmp.ao_required, tmp.pkt_good, tmp.pkt_bad); sock_fd, tmp.current_key, tmp.rnext, tmp.set_current, tmp.ao_required, tmp.pkt_good, tmp.pkt_bad);
} }
int get_current_key_id(int sock_fd) int get_current_key_id(int sock_fd)
@ -237,8 +236,8 @@ int get_current_key_id(int sock_fd)
if (getsockopt(sock_fd, IPPROTO_TCP, TCP_AO_INFO, &tmp, &len)) if (getsockopt(sock_fd, IPPROTO_TCP, TCP_AO_INFO, &tmp, &len))
{ {
log(L_WARN "TCP AO: Getting current ao key for socket file descriptor %i failed with errno %i", sock_fd, errno); log(L_WARN "TCP AO: Getting current ao key for socket file descriptor %i failed with errno %i", sock_fd, errno);
return -1; return -1;
} }
else else
return tmp.current_key; return tmp.current_key;
@ -269,8 +268,8 @@ int get_num_ao_keys(int sock_fd)
if (getsockopt(sock_fd, IPPROTO_TCP, TCP_AO_GET_KEYS, &tmp, &len)) if (getsockopt(sock_fd, IPPROTO_TCP, TCP_AO_GET_KEYS, &tmp, &len))
{ {
log(L_WARN "TCP AO: get keys on socket fd %i failed with err code %i", sock_fd, errno); log(L_WARN "TCP AO: get keys on socket fd %i failed with err code %i", sock_fd, errno);
return -1; return -1;
} }
return tmp.nkeys; return tmp.nkeys;
} }
@ -288,13 +287,15 @@ log_tcp_ao_get_key(int sock_fd)
tm_all[0].get_all = 1; tm_all[0].get_all = 1;
if (getsockopt(sock_fd, IPPROTO_TCP, TCP_AO_GET_KEYS, tm_all, &len)) // len should be still size of one struct. Because kernel net/ipv4/tcp_ao.c line 2165 if (getsockopt(sock_fd, IPPROTO_TCP, TCP_AO_GET_KEYS, tm_all, &len)) // len should be still size of one struct. Because kernel net/ipv4/tcp_ao.c line 2165
{ {
log(L_WARN "TCP AO: getting keys on socket fd %i failed with err code %i", sock_fd, errno); log(L_WARN "TCP AO: getting keys on socket fd %i failed with err code %i", sock_fd, errno);
return; return;
} }
log(L_INFO "TCP AO on socket fd %i has %i keys", tm_all[0].nkeys); log(L_INFO "TCP AO on socket fd %i has %i keys", tm_all[0].nkeys);
for (int i = 0; i < nkeys; i++) for (int i = 0; i < nkeys; i++)
{ {
log(L_INFO "sndid %i rcvid %i, %s %s, cipher %s key %s (%i/%i)", tm_all[i].sndid, tm_all[i].rcvid, tm_all[i].is_current ? "current" : "", tm_all[i].is_rnext ? "rnext" : "", tm_all[i].alg_name, tm_all[i].key, i+1, tm_all[0].nkeys); log(L_INFO "sndid %i rcvid %i, %s %s, cipher %s key %s (%i/%i)",
tm_all[i].sndid, tm_all[i].rcvid, tm_all[i].is_current ? "current" : "",
tm_all[i].is_rnext ? "rnext" : "", tm_all[i].alg_name, tm_all[i].key, i+1, tm_all[0].nkeys);
} }
} }
@ -411,7 +412,7 @@ int check_ao_keys_id(int sock_fd, struct bgp_ao_key *keys)
for (struct bgp_ao_key *key = keys; key; key = key->next_key) for (struct bgp_ao_key *key = keys; key; key = key->next_key)
expected_keys[key->key.local_id] = key->key.remote_id + 1; // the + 1 because we do not want 0 id be 0 expected_keys[key->key.local_id] = key->key.remote_id + 1; // the + 1 because we do not want 0 id be 0
int nkeys = get_num_ao_keys(sock_fd); int nkeys = get_num_ao_keys(sock_fd);
if(nkeys == -1) if (nkeys == -1)
{ {
log(L_WARN "TCP AO: unable to get num of keys"); log(L_WARN "TCP AO: unable to get num of keys");
return 1; return 1;
@ -434,7 +435,7 @@ int check_ao_keys_id(int sock_fd, struct bgp_ao_key *keys)
if (expected_keys[sock_key.rcvid] == 0) if (expected_keys[sock_key.rcvid] == 0)
log(L_WARN "TCP AO: unexpected ao key %i %i", sock_key.rcvid, sock_key.sndid); log(L_WARN "TCP AO: unexpected ao key %i %i", sock_key.rcvid, sock_key.sndid);
else else
log(L_WARN "TCP AO: expected key local id %i has different remote id than expected (%i vs %i)", sock_key.rcvid, expected_keys[sock_key.rcvid] - 1, sock_key.sndid); log(L_WARN "TCP AO: expected key local id %i has different remote id than expected (%i vs %i)", sock_key.rcvid, expected_keys[sock_key.rcvid] - 1, sock_key.sndid);
errors++; errors++;
} }
expected_keys[sock_key.rcvid] = 0; expected_keys[sock_key.rcvid] = 0;