0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-23 02:01:55 +00:00

tcp ao: key change works

This commit is contained in:
Katerina Kubecova 2024-02-23 09:33:08 +01:00
parent e3dc32e064
commit 8ba3396989
7 changed files with 202 additions and 40 deletions

View File

@ -42,8 +42,7 @@ struct ao_key
int remote_id; int remote_id;
const char *cipher; const char *cipher;
const char *master_key; const char *master_key;
int requested; int required;
struct linpool *lp;
struct ao_key *next_key; struct ao_key *next_key;
}; };
@ -120,7 +119,9 @@ int sk_set_ttl(sock *s, int ttl); /* Set transmit TTL for given socket */
int sk_set_min_ttl(sock *s, int ttl); /* Set minimal accepted TTL for given socket */ int sk_set_min_ttl(sock *s, int ttl); /* Set minimal accepted TTL for given socket */
int sk_set_md5_auth(sock *s, ip_addr local, ip_addr remote, int pxlen, struct iface *ifa, const char *passwd, int setkey); int sk_set_md5_auth(sock *s, ip_addr local, ip_addr remote, int pxlen, struct iface *ifa, const char *passwd, int setkey);
int sk_set_ao_auth(sock *s, ip_addr local, ip_addr remote, int pxlen, struct iface *ifa, const char *passwd, int passwd_id_loc, int passwd_id_rem, const char *cipher); int get_current_key_id(int sock_fd);
int sk_set_ao_auth(sock *s, ip_addr local, ip_addr remote, int pxlen, struct iface *ifa, const char *passwd, int passwd_id_loc, int passwd_id_rem, const char *cipher, int set_current);
void ao_delete_key(sock *s, ip_addr remote, int pxlen, struct iface *ifa, int passwd_id_rem, int passwd_id_loc);
void log_tcp_ao_info(int sock_fd); void log_tcp_ao_info(int sock_fd);
void log_tcp_ao_get_key(int sock_fd); void log_tcp_ao_get_key(int sock_fd);
void ao_try_change_master(int sock_fd, int next_key_id); void ao_try_change_master(int sock_fd, int next_key_id);

View File

@ -254,7 +254,7 @@ bgp_setup_auth(struct bgp_proto *p, int enable)
do { do {
rv = sk_set_ao_auth(p->sock->sk, rv = sk_set_ao_auth(p->sock->sk,
p->cf->local_ip, prefix, pxlen, p->cf->iface, p->cf->local_ip, prefix, pxlen, p->cf->iface,
key->master_key, key->local_id, key->remote_id, key->cipher); key->master_key, key->local_id, key->remote_id, key->cipher, 0);
key = key->next_key; key = key->next_key;
} while(key); } while(key);
@ -1117,10 +1117,9 @@ bgp_active(struct bgp_proto *p)
void void
log_ao(int fd) log_ao(int fd)
{ {
log("the two ao logs"); //log("the two ao logs");
log_tcp_ao_info(fd); log_tcp_ao_info(fd);
log_tcp_ao_get_key(fd); log_tcp_ao_get_key(fd);
ao_try_change_master(fd, 101);
} }
/** /**
@ -2155,6 +2154,89 @@ bgp_postconfig(struct proto_config *CF)
} }
} }
int compare_aos(struct ao_key *a, struct ao_key *b)
{
if (a->local_id != b->local_id)
return 1;
if (a->remote_id != b->local_id)
return 1;
if (strcmp(a->cipher, b->cipher))
return 1;
return strcmp(a->master_key, b->master_key);
}
int reconfigure_tcp_ao(struct bgp_proto old_proto, struct bgp_config new)
{
log("in reconf ao");
sock *s_passiv = old_proto.sock->sk;
sock *s_activ = old_proto.conn->sk;
int key_in_use = get_current_key_id(s_activ->fd);
if (key_in_use == -1)
{
log("Unable to detect currently used key");
return 0;
}
struct ao_key *old_aos[256];
memset(&old_aos, 0, sizeof(struct ao_key*)*256);
for(struct ao_key *ao_key = old_proto.cf->ao_key; ao_key; ao_key = ao_key->next_key)
{
old_aos[ao_key->local_id] = ao_key;
}
for(struct ao_key *ao_key = new.ao_key; ao_key; ao_key = ao_key->next_key)
{
if(old_aos[ao_key->local_id])
{
if(compare_aos(ao_key, old_aos[ao_key->local_id]))
{
struct ao_key *o = old_aos[ao_key->local_id];
log("%i %i %i %i %s %s %s %s", ao_key->local_id, o->local_id, ao_key->remote_id, o->remote_id, ao_key->cipher, o->cipher, ao_key->master_key, o->master_key);
if (ao_key->local_id == key_in_use)
{
//struct ao_key *o = old_aos[ao_key->local_id];
//log("%i %i %i %i %s %s %s %s", ao_key->local_id, o->local_id, ao_key->remote_id, o->remote_id, ao_key->cipher, o->cipher, ao_key->master_key, o->master_key);
log("Currently used master key part update. This is not allowed.");
return 0;
}
log("Reusing key id. Not nice. Lets try to update.");
struct ao_key *old_key = old_aos[ao_key->local_id];
ao_delete_key(s_activ, old_proto.remote_ip, -1, s_activ->iface, old_key->local_id, old_key->remote_id);
ao_delete_key(s_passiv, old_proto.remote_ip, -1, s_passiv->iface, old_key->local_id, old_key->remote_id);
sk_set_ao_auth(s_activ, old_proto.local_ip, old_proto.remote_ip, -1, s_activ->iface, ao_key->master_key, ao_key->local_id, ao_key->remote_id, ao_key->cipher, ao_key->required == 1);
sk_set_ao_auth(s_passiv, old_proto.local_ip, old_proto.remote_ip, -1, s_passiv->iface, ao_key->master_key, ao_key->local_id, ao_key->remote_id, ao_key->cipher, 0);
}
old_aos[ao_key->local_id] = 0;
}
else
{
sk_set_ao_auth(s_activ, old_proto.local_ip, old_proto.remote_ip, -1, s_activ->iface, ao_key->master_key, ao_key->local_id, ao_key->remote_id, ao_key->cipher, ao_key->required == 1);
sk_set_ao_auth(s_passiv, old_proto.local_ip, old_proto.remote_ip, -1, s_passiv->iface, ao_key->master_key, ao_key->local_id, ao_key->remote_id, ao_key->cipher, 0);
}
if (ao_key->required == 1)
{
ao_try_change_master(s_activ->fd, ao_key->local_id); // or remote id?
}
}
for(int i = 0; i<256; i++)
{
if (old_aos[i])
{
if (i == key_in_use)
{
log("Currently used key deletion. This is not allowed.");
return 0;
}
ao_delete_key(s_activ, old_proto.remote_ip, -1, s_activ->iface, old_aos[i]->local_id, old_aos[i]->remote_id);
ao_delete_key(s_passiv, old_proto.remote_ip, -1, s_passiv->iface, old_aos[i]->local_id, old_aos[i]->remote_id);
}
}
log("no changes in ao");
return 1;
}
static int static int
bgp_reconfigure(struct proto *P, struct proto_config *CF) bgp_reconfigure(struct proto *P, struct proto_config *CF)
{ {
@ -2170,6 +2252,7 @@ bgp_reconfigure(struct proto *P, struct proto_config *CF)
// password item is last and must be checked separately // password item is last and must be checked separately
OFFSETOF(struct bgp_config, password) - sizeof(struct proto_config)) OFFSETOF(struct bgp_config, password) - sizeof(struct proto_config))
&& !bstrcmp(old->password, new->password) && !bstrcmp(old->password, new->password)
&& reconfigure_tcp_ao(*p, *new)
&& ((!old->remote_range && !new->remote_range) && ((!old->remote_range && !new->remote_range)
|| (old->remote_range && new->remote_range && net_equal(old->remote_range, new->remote_range))) || (old->remote_range && new->remote_range && net_equal(old->remote_range, new->remote_range)))
&& !bstrcmp(old->dynamic_name, new->dynamic_name) && !bstrcmp(old->dynamic_name, new->dynamic_name)

View File

@ -134,7 +134,8 @@ struct bgp_config {
u32 disable_after_cease; /* Disable it when cease is received, bitfield */ u32 disable_after_cease; /* Disable it when cease is received, bitfield */
const char *password; /* Password used for MD5 authentication */ const char *password; /* Password used for MD5 authentication */
struct ao_key *ao_key; /* Keys for tcp ao authentication */ struct ao_key *ao_key; /* Keys for tcp ao authentication TODO: copy to protocol? */
struct linpool *ao_lp; /* Linpool for allocating ao keys */
net_addr *remote_range; /* Allowed neighbor range for dynamic BGP */ net_addr *remote_range; /* Allowed neighbor range for dynamic BGP */
const char *dynamic_name; /* Name pattern for dynamic BGP */ const char *dynamic_name; /* Name pattern for dynamic BGP */
int dynamic_name_digits; /* Minimum number of digits for dynamic names */ int dynamic_name_digits; /* Minimum number of digits for dynamic names */
@ -306,6 +307,7 @@ struct bgp_conn {
u8 last_channel_count; /* Number of times the last channel was used in succession */ u8 last_channel_count; /* Number of times the last channel was used in succession */
int notify_code, notify_subcode, notify_size; int notify_code, notify_subcode, notify_size;
byte *notify_data; byte *notify_data;
int last_used_ao_key; /* ID of last ao authentication key, which was used */
uint hold_time, keepalive_time; /* Times calculated from my and neighbor's requirements */ uint hold_time, keepalive_time; /* Times calculated from my and neighbor's requirements */
}; };

View File

@ -193,7 +193,7 @@ bgp_proto:
| bgp_proto ADVERTISE HOSTNAME bool ';' { BGP_CFG->enable_hostname = $4; } | bgp_proto ADVERTISE HOSTNAME bool ';' { BGP_CFG->enable_hostname = $4; }
| bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; } | bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; }
| bgp_proto PASSWORD text ';' { log("%s", $3); BGP_CFG->password = $3; } | bgp_proto PASSWORD text ';' { log("%s", $3); BGP_CFG->password = $3; }
| bgp_proto AUTHENTICATE MANUAL '{' ao_keys '}' | bgp_proto AUTHENTICATE MANUAL '{' ao_keys '}' tcp_ao_end
| bgp_proto SETKEY bool ';' { BGP_CFG->setkey = $3; } | bgp_proto SETKEY bool ';' { BGP_CFG->setkey = $3; }
| bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; } | bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; }
| bgp_proto INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $4; } | bgp_proto INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $4; }
@ -245,35 +245,61 @@ ao_key:
ao_first_item: ao_first_item:
LOCAL ID expr ';' { LOCAL ID expr ';' {
struct linpool *lp; if (!BGP_CFG->ao_lp)
if (BGP_CFG->ao_key) BGP_CFG->ao_lp = lp_new(rp_new(&root_pool, "ao struct pool"));
lp = BGP_CFG->ao_key->lp; struct ao_key *new_key = lp_alloc(BGP_CFG->ao_lp, sizeof(struct ao_key));
else
lp = lp_new(rp_new(&root_pool, "ao struct pool"));
struct ao_key *new_key = lp_alloc(lp, sizeof(struct ao_key));
new_key->lp = lp;
new_key->next_key = BGP_CFG->ao_key; new_key->next_key = BGP_CFG->ao_key;
BGP_CFG->ao_key = new_key; BGP_CFG->ao_key = new_key;
BGP_CFG->ao_key->requested = 0; BGP_CFG->ao_key->required = 0;
BGP_CFG->ao_key->local_id = $3; BGP_CFG->ao_key->local_id = $3;
} }
; ;
ao_item: ao_item:
REMOTE ID expr ';' {log("remote id %i", $3); BGP_CFG->ao_key->remote_id = $3; } REMOTE ID expr ';' {log("remote id %i", $3); BGP_CFG->ao_key->remote_id = $3; }
| CIPHER text ';' { char *c = lp_alloc(BGP_CFG->ao_key->lp, strlen($2)); | CIPHER text ';' { char *c = lp_alloc(BGP_CFG->ao_lp, strlen($2)+1);
memcpy(c, $2, strlen($2)); memcpy(c, $2, strlen($2)+1);
BGP_CFG->ao_key->cipher = c; BGP_CFG->ao_key->cipher = c;
log("ciph[%s]", $2); } log("ciph[%s]", $2); }
| MASTER KEY text ';' { | MASTER KEY text ';' {
char *k = lp_alloc(BGP_CFG->ao_key->lp, strlen($3)); char *k = lp_alloc(BGP_CFG->ao_lp, strlen($3)+1);
memcpy(k, $3, strlen($3)); memcpy(k, $3, strlen($3)+1);
BGP_CFG->ao_key->master_key = k; BGP_CFG->ao_key->master_key = k;
log("key[%s]", BGP_CFG->ao_key->master_key);} log("key[%s]", BGP_CFG->ao_key->master_key);}
| DEPRECATED ';' { BGP_CFG->ao_key->requested = -1; } | DEPRECATED ';' { BGP_CFG->ao_key->required = -1; }
| REQUIRED ';' { BGP_CFG->ao_key->requested = 1; } | REQUIRED ';' { BGP_CFG->ao_key->required = 1; }
; ;
tcp_ao_end:
{ //TODO this is not all what we need to check - old current master same, cipher, key exist...
char used_aos_id_loc[256];
char used_aos_id_rem[256];
memset(used_aos_id_loc, 0, sizeof(char)*256);
memset(used_aos_id_rem, 0, sizeof(char)*256);
int required_found = 0;
struct ao_key *key = BGP_CFG->ao_key;
while (key)
{
if (used_aos_id_loc[key->local_id])
cf_error("Reused local key id");
used_aos_id_loc[key->local_id] = 1;
if (used_aos_id_rem[key->remote_id])
cf_error("Reused remote key id");
used_aos_id_rem[key->remote_id] = 1;
if (key->required == 1)
{
if (required_found)
cf_error("How do you want to use two keys at once? Check 'REQUIRED'");
required_found = 1;
}
key = key->next_key;
}
if (required_found == 0)
cf_error("Missing 'REQUIRED'. Which key should be used?");
}
bgp_channel_start: bgp_afi bgp_channel_start: bgp_afi
{ {
const struct bgp_af_desc *desc = bgp_get_af_desc($1); const struct bgp_af_desc *desc = bgp_get_af_desc($1);

View File

@ -3423,8 +3423,9 @@ bgp_rx_packet(struct bgp_conn *conn, byte *pkt, uint len)
int int
bgp_rx(sock *sk, uint size) bgp_rx(sock *sk, uint size)
{ {
log_ao(sk->fd);
struct bgp_conn *conn = sk->data; struct bgp_conn *conn = sk->data;
//if (get_current_key_id(sk->fd) == conn->last_used_ao_key) TODO: uncoment after debug
log_ao(sk->fd);
byte *pkt_start = sk->rbuf; byte *pkt_start = sk->rbuf;
byte *end = pkt_start + size; byte *end = pkt_start + size;
uint i, len; uint i, len;

View File

@ -238,6 +238,21 @@ void log_tcp_ao_info(int sock_fd)
tmp.current_key, tmp.rnext, tmp.set_current, tmp.ao_required, tmp.pkt_good, tmp.pkt_bad); 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)
{
struct tcp_ao_info_opt_ext tmp;
memset(&tmp, 0, sizeof(struct tcp_ao_info_opt_ext));
socklen_t len = sizeof(tmp);
if (getsockopt(sock_fd, IPPROTO_TCP, TCP_AO_INFO, &tmp, len))
{
log("get current ao key failed %i", errno);
return -1;
}
else
return tmp.current_key;
}
void void
log_tcp_ao_get_key(int sock_fd) log_tcp_ao_get_key(int sock_fd)
{ {
@ -252,27 +267,41 @@ log_tcp_ao_get_key(int sock_fd)
log("log tcp ao get keys failed with err code %i", errno); log("log tcp ao get keys failed with err code %i", errno);
return; return;
} }
else
log("cipher %s key %s num of keys %i", tmp.alg_name, tmp.key, tmp.nkeys);
int nkeys = tmp.nkeys;
struct tcp_ao_getsockopt_ext tm_all[nkeys];
memset(tm_all, 0, sizeof(struct tcp_ao_getsockopt_ext)*nkeys);
tm_all[0].nkeys = nkeys;
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
{
log("log tcp ao get keys failed with err code %i", errno);
return;
}
log("keys %i %i", nkeys, tm_all[0].nkeys);
for (int i = 0; i < nkeys; i++)
{
log("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);
}
} }
int int
sk_set_ao_auth(sock *s, ip_addr local, ip_addr remote, int pxlen, struct iface *ifa, const char *passwd, int passwd_id_loc, int passwd_id_rem, const char* cipher) sk_set_ao_auth(sock *s, ip_addr local, ip_addr remote, int pxlen, struct iface *ifa, const char *passwd, int passwd_id_loc, int passwd_id_rem, const char* cipher, int set_current)
{ {
struct tcp_ao_add_ext ao; struct tcp_ao_add_ext ao;
memset(&ao, 0, sizeof(struct tcp_ao_add_ext)); memset(&ao, 0, sizeof(struct tcp_ao_add_ext));
log("in sk set ao"); log("in sk set ao, pass %s", passwd);
log("%s %i %i", passwd, passwd_id_loc, passwd_id_rem);
log("af %i %I %I (%i or %i) %s %i", s->af, remote, local, AF_INET, AF_INET6, passwd, passwd[0]);
/* int af; /* int af;
if (ipa_is_ip4(remote)) if (ipa_is_ip4(remote))
af = AF_INET; af = AF_INET;
else else
af = AF_INET6;*/ a = AF_INET6;*/
sockaddr_fill((sockaddr *) &ao.addr, s->af, remote, ifa, 0); sockaddr_fill((sockaddr *) &ao.addr, s->af, remote, ifa, 0);
ao.set_current = 0; if (set_current)
ao.set_rnext = 0; {
ao.set_rnext = 1;
ao.set_current = 1;
}
if (pxlen >= 0) if (pxlen >= 0)
ao.prefix = pxlen; ao.prefix = pxlen;
else if(s->af == AF_INET) else if(s->af == AF_INET)
@ -294,22 +323,42 @@ sk_set_ao_auth(sock *s, ip_addr local, ip_addr remote, int pxlen, struct iface *
if (setsockopt(s->fd, IPPROTO_TCP, TCP_AO_ADD_KEY, &ao, sizeof(ao)) < 0) if (setsockopt(s->fd, IPPROTO_TCP, TCP_AO_ADD_KEY, &ao, sizeof(ao)) < 0)
bug("tcp ao err %i", errno); bug("tcp ao err %i", errno);
log_tcp_ao_info(s->fd); log_tcp_ao_get_key(s->fd);
return 0; return 0;
} }
void
ao_delete_key(sock *s, ip_addr remote, int pxlen, struct iface *ifa, int passwd_id_loc, int passwd_id_rem)
{
struct tcp_ao_del_ext del;
memset(&del, 0, sizeof(struct tcp_ao_del_ext));
sockaddr_fill((sockaddr *) &del.addr, s->af, remote, ifa, 0);
del.sndid = passwd_id_rem;
del.rcvid = passwd_id_loc;
if (pxlen >= 0)
del.prefix = pxlen;
else if(s->af == AF_INET)
del.prefix = 32;
else
del.prefix = 128;
int IPPROTO_TCP_ = 6;
if (setsockopt(s->fd, IPPROTO_TCP, TCP_AO_DEL_KEY, &del, sizeof(del)) < 0)
bug("tcp ao deletion err %i", errno);
log("tcp ao key %i %i deleted", passwd_id_loc, passwd_id_rem);
}
void void
ao_try_change_master(int sock_fd, int next_master_id ) ao_try_change_master(int sock_fd, int next_master_id )
{ {
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);
tmp.set_rnext = 1; tmp.set_rnext = 1;
tmp.rnext = next_master_id; tmp.rnext = next_master_id;
if (setsockopt(sock_fd, IPPROTO_TCP, TCP_AO_INFO, &tmp, &len)) if (setsockopt(sock_fd, IPPROTO_TCP, TCP_AO_INFO, &tmp, sizeof(tmp)))
{ {
log(" tcp ao change master key failed with err code %i", errno); log(" tcp ao change master key failed with err code %i", errno);
log_tcp_ao_get_key(sock_fd);
return; return;
} }
else else

View File

@ -1465,15 +1465,15 @@ sk_open(sock *s)
log("set ao, %s", s->ao_key->cipher); log("set ao, %s", s->ao_key->cipher);
struct ao_key *key = s->ao_key; struct ao_key *key = s->ao_key;
do { do {
if (sk_set_ao_auth(s, s->saddr, s->daddr, -1, s->iface, key->master_key, key->local_id, key->remote_id, key->cipher) < 0) if (sk_set_ao_auth(s, s->saddr, s->daddr, -1, s->iface, key->master_key, key->local_id, key->remote_id, key->cipher, key->required == 1) < 0)
goto err; goto err;
key = key->next_key; key = key->next_key;
} while (key); } while (key);
} }
if (s->password) else if (s->password)
{ {
log("set md5"); log("set md5");
if (sk_set_ao_auth(s, s->saddr, s->daddr, -1, s->iface, s->password, 123, 123, 0) < 0) if (sk_set_md5_auth(s, s->saddr, s->daddr, -1, s->iface, s->password, 0) < 0)
goto err; goto err;
} }
else else