mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 09:41:54 +00:00
bgp.c - tcp ao rewrited so ao_key is basic and bgp_ao_key and config_ao uses ao_key. bgp_ao_key keeps living info, config_ao just make it linked list
This commit is contained in:
parent
026d89bd93
commit
94a41cb6a0
25
lib/socket.h
25
lib/socket.h
@ -43,7 +43,20 @@ struct ao_key
|
|||||||
const char *cipher;
|
const char *cipher;
|
||||||
const char *master_key;
|
const char *master_key;
|
||||||
int required;
|
int required;
|
||||||
struct ao_key *next_key;
|
};
|
||||||
|
|
||||||
|
struct ao_config
|
||||||
|
{
|
||||||
|
struct ao_key key;
|
||||||
|
struct ao_config *next_key;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bgp_ao_key {
|
||||||
|
struct ao_key key;
|
||||||
|
int activ_alive; /* this ao key is in activ socket */
|
||||||
|
int passiv_alive; /* this ao key is in passiv socket */
|
||||||
|
int to_delete; /* flag for reconfig */
|
||||||
|
struct bgp_ao_key *next_key;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct birdsock {
|
typedef struct birdsock {
|
||||||
@ -87,8 +100,9 @@ typedef struct birdsock {
|
|||||||
node n;
|
node n;
|
||||||
void *rbuf_alloc, *tbuf_alloc;
|
void *rbuf_alloc, *tbuf_alloc;
|
||||||
const char *password; /* Password for MD5 authentication */
|
const char *password; /* Password for MD5 authentication */
|
||||||
struct ao_key *ao_key_init; /* Key for tcp ao authentication icialization. */
|
struct bgp_ao_key *ao_key_init; /* Key for tcp ao authentication icialization. */
|
||||||
char use_ao;
|
struct bgp_proto *proto_del_ao_key; /* For deletion of the currently used deprecated ao key */
|
||||||
|
char use_ao; /* This is the only reliable flag saying if the socket use ao or not */
|
||||||
int last_used_ao_key; /* Last ID the other site requested */
|
int last_used_ao_key; /* Last ID the other site requested */
|
||||||
int desired_ao_key; /* ID of requested ao key */
|
int desired_ao_key; /* ID of requested ao key */
|
||||||
const char *err; /* Error message */
|
const char *err; /* Error message */
|
||||||
@ -125,10 +139,11 @@ int sk_set_md5_auth(sock *s, ip_addr local, ip_addr remote, int pxlen, struct if
|
|||||||
int get_current_key_id(int sock_fd);
|
int get_current_key_id(int sock_fd);
|
||||||
int get_rnext_key_id(int sock_fd);
|
int get_rnext_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);
|
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);
|
int 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);
|
||||||
int check_ao_keys_id(int sock_fd, struct ao_key *key);
|
void tcp_ao_get_info(int sock_fd, int key_info[4]);
|
||||||
|
int check_ao_keys_id(int sock_fd, struct bgp_ao_key *key);
|
||||||
void ao_try_change_master(sock *s, int next_key_id_loc, int next_id_rem);
|
void ao_try_change_master(sock *s, int next_key_id_loc, int next_id_rem);
|
||||||
int sk_set_ipv6_checksum(sock *s, int offset);
|
int sk_set_ipv6_checksum(sock *s, int offset);
|
||||||
int sk_set_icmp6_filter(sock *s, int p1, int p2);
|
int sk_set_icmp6_filter(sock *s, int p1, int p2);
|
||||||
|
258
proto/bgp/bgp.c
258
proto/bgp/bgp.c
@ -191,8 +191,7 @@ bgp_open(struct bgp_proto *p)
|
|||||||
|
|
||||||
if (sk_open(sk) < 0)
|
if (sk_open(sk) < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
log("____________________________________________________________________________%i %i", sk->fd, sk->ao_key_init);
|
|
||||||
bs = mb_allocz(proto_pool, sizeof(struct bgp_socket));
|
bs = mb_allocz(proto_pool, sizeof(struct bgp_socket));
|
||||||
bs->sk = sk;
|
bs->sk = sk;
|
||||||
bs->uc = 1;
|
bs->uc = 1;
|
||||||
@ -249,24 +248,24 @@ bgp_setup_auth(struct bgp_proto *p, int enable)
|
|||||||
{
|
{
|
||||||
if (enable)
|
if (enable)
|
||||||
{
|
{
|
||||||
log("set ao auth [%s]", p->cf->ao_key->master_key);
|
struct bgp_ao_key *key = p->ao_key;
|
||||||
struct ao_key *key = p->cf->ao_key;
|
|
||||||
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, 0);
|
key->key.master_key, key->key.local_id, key->key.remote_id, key->key.cipher, 0);
|
||||||
|
if (rv == 0)
|
||||||
|
key->passiv_alive = 1;
|
||||||
key = key->next_key;
|
key = key->next_key;
|
||||||
|
|
||||||
} while(key);
|
} while(key);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log("in bgp close");
|
struct bgp_ao_key *key = p->ao_key;
|
||||||
struct ao_key *key = p->cf->ao_key;
|
|
||||||
while (key)
|
while (key)
|
||||||
{
|
{
|
||||||
log("delete %i", key->local_id);
|
if (key->passiv_alive)
|
||||||
ao_delete_key(p->sock->sk, p->remote_ip, -1, p->sock->sk->iface, key->local_id, key->remote_id);
|
ao_delete_key(p->sock->sk, p->remote_ip, -1, p->sock->sk->iface, key->key.local_id, key->key.remote_id);
|
||||||
key = key->next_key;
|
key = key->next_key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1126,14 +1125,6 @@ bgp_active(struct bgp_proto *p)
|
|||||||
bgp_start_timer(conn->connect_timer, delay);
|
bgp_start_timer(conn->connect_timer, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
log_ao(int fd)
|
|
||||||
{
|
|
||||||
//log("the two ao logs");
|
|
||||||
log_tcp_ao_info(fd);
|
|
||||||
log_tcp_ao_get_key(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bgp_connect - initiate an outgoing connection
|
* bgp_connect - initiate an outgoing connection
|
||||||
* @p: BGP instance
|
* @p: BGP instance
|
||||||
@ -1161,7 +1152,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c
|
|||||||
s->tbsize = p->cf->enable_extended_messages ? BGP_TX_BUFFER_EXT_SIZE : BGP_TX_BUFFER_SIZE;
|
s->tbsize = p->cf->enable_extended_messages ? BGP_TX_BUFFER_EXT_SIZE : BGP_TX_BUFFER_SIZE;
|
||||||
s->tos = IP_PREC_INTERNET_CONTROL;
|
s->tos = IP_PREC_INTERNET_CONTROL;
|
||||||
s->password = p->cf->password;
|
s->password = p->cf->password;
|
||||||
s->ao_key_init = p->cf->ao_key;
|
s->ao_key_init = p->ao_key;
|
||||||
s->tx_hook = bgp_connected;
|
s->tx_hook = bgp_connected;
|
||||||
s->flags = p->cf->free_bind ? SKF_FREEBIND : 0;
|
s->flags = p->cf->free_bind ? SKF_FREEBIND : 0;
|
||||||
BGP_TRACE(D_EVENTS, "Connecting to %I%J from local address %I%J",
|
BGP_TRACE(D_EVENTS, "Connecting to %I%J from local address %I%J",
|
||||||
@ -1174,8 +1165,6 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c
|
|||||||
if (sk_open(s) < 0)
|
if (sk_open(s) < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
log("a..........................................................................................fd %i %I", s->fd, s->daddr);
|
|
||||||
|
|
||||||
/* Set minimal receive TTL if needed */
|
/* Set minimal receive TTL if needed */
|
||||||
if (p->cf->ttl_security)
|
if (p->cf->ttl_security)
|
||||||
if (sk_set_min_ttl(s, 256 - hops) < 0)
|
if (sk_set_min_ttl(s, 256 - hops) < 0)
|
||||||
@ -1305,10 +1294,21 @@ bgp_incoming_connection(sock *sk, uint dummy UNUSED)
|
|||||||
if (sk_set_min_ttl(sk, 256 - hops) < 0)
|
if (sk_set_min_ttl(sk, 256 - hops) < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (p->cf->ao_key)
|
if (p->ao_key)
|
||||||
{
|
{
|
||||||
if (check_ao_keys_id(sk->fd, p->cf->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)
|
||||||
|
{
|
||||||
|
key->activ_alive = key->passiv_alive;
|
||||||
|
if (key->key.required == 1)
|
||||||
|
{
|
||||||
|
sk->desired_ao_key = key->key.remote_id;
|
||||||
|
ao_try_change_master(sk, key->key.local_id, key->key.remote_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (p->cf->enable_extended_messages)
|
if (p->cf->enable_extended_messages)
|
||||||
{
|
{
|
||||||
@ -1779,6 +1779,20 @@ bgp_init(struct proto_config *CF)
|
|||||||
p->remote_ip = cf->remote_ip;
|
p->remote_ip = cf->remote_ip;
|
||||||
p->remote_as = cf->remote_as;
|
p->remote_as = cf->remote_as;
|
||||||
|
|
||||||
|
if (cf->ao_key)
|
||||||
|
{
|
||||||
|
struct ao_config *cf_key = cf->ao_key;
|
||||||
|
do {
|
||||||
|
struct bgp_ao_key *key = mb_alloc(proto_pool, sizeof(struct bgp_ao_key));
|
||||||
|
key->key = cf_key->key;
|
||||||
|
key->activ_alive = 0;
|
||||||
|
key->passiv_alive = 0;
|
||||||
|
key->next_key = p->ao_key;
|
||||||
|
p->ao_key = key;
|
||||||
|
cf_key = cf_key->next_key;
|
||||||
|
} while (cf_key);
|
||||||
|
}
|
||||||
|
|
||||||
/* Hack: We use cf->remote_ip just to pass remote_ip from bgp_spawn() */
|
/* Hack: We use cf->remote_ip just to pass remote_ip from bgp_spawn() */
|
||||||
if (cf->c.parent)
|
if (cf->c.parent)
|
||||||
cf->remote_ip = IPA_NONE;
|
cf->remote_ip = IPA_NONE;
|
||||||
@ -2191,85 +2205,37 @@ int compare_aos(struct ao_key *a, struct ao_key *b)
|
|||||||
return strcmp(a->master_key, b->master_key);
|
return strcmp(a->master_key, b->master_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
int reconfigure_ao_without_conn(struct bgp_proto old_proto, struct bgp_config new)
|
int reconfigure_tcp_ao(struct bgp_proto *old_proto, struct bgp_config new)
|
||||||
{
|
{
|
||||||
log("in reconf dead ao");
|
if (old_proto->cf->ao_key == NULL && new.ao_key == NULL)
|
||||||
|
return 1; // tcp ao not used
|
||||||
|
if (old_proto->cf->ao_key == NULL || new.ao_key == NULL)
|
||||||
|
return 0; // connection is changing from ao to no ao or no ao to ao
|
||||||
|
|
||||||
sock *s_passiv = old_proto.sock->sk;
|
if (!old_proto->conn)
|
||||||
|
|
||||||
struct ao_key *old_aos[256];
|
|
||||||
memset(&old_aos, 0, sizeof(struct ao_key*)*256);
|
|
||||||
struct ao_key *old_aos_rem[256];
|
|
||||||
memset(&old_aos_rem, 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;
|
log("tcp ao: reconfigure nonestablished connection");
|
||||||
old_aos_rem[ao_key->remote_id] = ao_key;
|
return 0; // Connection was not (re)established, so we can not change it.
|
||||||
}
|
}
|
||||||
|
sock *s_passiv = old_proto->sock->sk;
|
||||||
for(struct ao_key *ao_key = new.ao_key; ao_key; ao_key = ao_key->next_key)
|
sock *s_activ = old_proto->conn->sk;
|
||||||
{
|
|
||||||
if(old_aos[ao_key->local_id])
|
|
||||||
{
|
|
||||||
if(compare_aos(ao_key, old_aos[ao_key->local_id]))
|
|
||||||
{
|
|
||||||
struct ao_key *old_key = old_aos[ao_key->local_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_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, ao_key->required == 1);
|
|
||||||
}
|
|
||||||
old_aos[ao_key->local_id] = 0;
|
|
||||||
}
|
|
||||||
else if(old_aos_rem[ao_key->remote_id])
|
|
||||||
{
|
|
||||||
struct ao_key *old_key = old_aos_rem[ao_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_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, ao_key->required == 1);
|
|
||||||
old_aos[old_key->local_id] = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
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, ao_key->required == 1);
|
|
||||||
}
|
|
||||||
for(int i = 0; i<256; i++)
|
|
||||||
{
|
|
||||||
if (old_aos[i])
|
|
||||||
ao_delete_key(s_passiv, old_proto.remote_ip, -1, s_passiv->iface, old_aos[i]->local_id, old_aos[i]->remote_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int reconfigure_tcp_ao(struct bgp_proto old_proto, struct bgp_config new)
|
|
||||||
{
|
|
||||||
log("in reconf ao");
|
|
||||||
if (!old_proto.conn)
|
|
||||||
return reconfigure_ao_without_conn(old_proto, new); // Connection was not (re)established, so we can not change it.
|
|
||||||
sock *s_passiv = old_proto.sock->sk;
|
|
||||||
sock *s_activ = old_proto.conn->sk;
|
|
||||||
|
|
||||||
int key_in_use_rem = get_current_key_id(s_activ->fd);
|
int key_in_use_rem = get_current_key_id(s_activ->fd);
|
||||||
|
|
||||||
if (key_in_use_rem == -1)
|
if (key_in_use_rem == -1)
|
||||||
{
|
{
|
||||||
log("Unable to detect currently used key");
|
log(L_WARN "TCP AO: Unable to detect currently used key");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
int rnext_id = get_rnext_key_id(s_activ->fd);
|
|
||||||
log("old rnext %i", rnext_id);
|
|
||||||
|
|
||||||
struct ao_key *old_aos[256];
|
|
||||||
memset(&old_aos, 0, sizeof(struct ao_key*)*256);
|
|
||||||
struct ao_key *old_rem_id[256];
|
|
||||||
memset(&old_rem_id, 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;
|
|
||||||
old_rem_id[ao_key->remote_id] = ao_key;
|
|
||||||
}
|
}
|
||||||
int key_in_use = old_rem_id[key_in_use_rem]->local_id;
|
|
||||||
for(struct ao_key *ao_key = new.ao_key; ao_key; ao_key = ao_key->next_key)
|
for (struct bgp_ao_key *ao_key = old_proto->ao_key; ao_key; ao_key = ao_key->next_key)
|
||||||
|
ao_key->to_delete = 1;
|
||||||
|
|
||||||
|
struct bgp_ao_key *first = old_proto->ao_key;
|
||||||
|
for (struct ao_config *cf_ao = new.ao_key; cf_ao; cf_ao = cf_ao->next_key)
|
||||||
{
|
{
|
||||||
|
if (cf_ao->key.required == -1 && cf_ao->key.remote_id != key_in_use_rem)
|
||||||
|
continue;
|
||||||
if(old_aos[ao_key->local_id])
|
if(old_aos[ao_key->local_id])
|
||||||
{
|
{
|
||||||
if(compare_aos(ao_key, old_aos[ao_key->local_id]))
|
if(compare_aos(ao_key, old_aos[ao_key->local_id]))
|
||||||
@ -2299,28 +2265,92 @@ int reconfigure_tcp_ao(struct bgp_proto old_proto, struct bgp_config new)
|
|||||||
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);
|
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_key->local_id != rnext_id))
|
struct bgp_ao_key *found = NULL;
|
||||||
|
for (struct bgp_ao_key *old_ao = first; old_ao && !found; old_ao = old_ao->next_key) {
|
||||||
|
if (old_ao->key.local_id == cf_ao->key.local_id || old_ao->key.remote_id == cf_ao->key.remote_id)
|
||||||
|
{
|
||||||
|
if (compare_aos(&old_ao->key, &cf_ao->key))
|
||||||
|
return 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))
|
||||||
|
return 0;
|
||||||
|
old_ao->activ_alive = 1;
|
||||||
|
}
|
||||||
|
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))
|
||||||
|
return 0;
|
||||||
|
old_ao->passiv_alive = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cf_ao->key.required == 1 && old_ao->key.required != 1)
|
||||||
|
{
|
||||||
|
s_activ->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);
|
||||||
|
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.
|
||||||
|
}
|
||||||
|
old_ao->key = cf_ao->key;
|
||||||
|
old_ao->to_delete = 0;
|
||||||
|
found = old_ao;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
{
|
{
|
||||||
ao_try_change_master(s_activ, ao_key->local_id, ao_key->remote_id);
|
struct bgp_ao_key *key = mb_alloc(old_proto->p.pool, sizeof(struct bgp_ao_key));
|
||||||
if (old_proto.conn->hold_timer->expires != 0)
|
key->key = cf_ao->key;
|
||||||
bgp_schedule_packet(old_proto.conn, NULL, PKT_KEEPALIVE); // According to RFC we should not send keepalive shortly after another, but since reconfiguration is rare, this is harmless
|
key->activ_alive = 0;
|
||||||
|
key->passiv_alive = 0;
|
||||||
|
key->next_key = first;
|
||||||
|
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))
|
||||||
|
return 0;
|
||||||
|
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))
|
||||||
|
return 0;
|
||||||
|
key->activ_alive = 1;
|
||||||
|
key->to_delete = 0;
|
||||||
|
found = key;
|
||||||
|
|
||||||
|
if (found->key.required == 1)
|
||||||
|
{
|
||||||
|
s_activ->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);
|
||||||
|
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.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(int i = 0; i<256; i++)
|
|
||||||
{
|
|
||||||
if (old_aos[i])
|
|
||||||
{
|
|
||||||
if (i == key_in_use)
|
|
||||||
{
|
|
||||||
cf_warn("TCP AO reconfiguration: Currently used key (id %i) deletion. This is not allowed.", i);
|
|
||||||
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 big changes in ao");
|
key_in_use_rem = get_current_key_id(s_activ->fd);
|
||||||
|
struct bgp_ao_key *previous = NULL;
|
||||||
|
for (struct bgp_ao_key *old_ao = old_proto->ao_key; old_ao; old_ao = old_ao->next_key)
|
||||||
|
{
|
||||||
|
if (old_ao->to_delete)
|
||||||
|
{
|
||||||
|
if (old_ao->key.remote_id == key_in_use_rem)
|
||||||
|
{
|
||||||
|
log(L_WARN "TCP AO: deleting currently used key");
|
||||||
|
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))
|
||||||
|
return 0;
|
||||||
|
old_ao->activ_alive = 0;
|
||||||
|
|
||||||
|
if (ao_delete_key(s_passiv, old_proto->remote_ip, -1, s_passiv->iface, old_ao->key.local_id, old_ao->key.remote_id))
|
||||||
|
return 0;
|
||||||
|
old_ao->passiv_alive = 0;
|
||||||
|
if (previous)
|
||||||
|
previous->next_key = old_ao->next_key;
|
||||||
|
else
|
||||||
|
old_proto->ao_key = old_ao->next_key;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
previous = old_ao;
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2339,7 +2369,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)
|
&& 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)
|
||||||
@ -2780,6 +2810,16 @@ bgp_show_proto_info(struct proto *P)
|
|||||||
tm_remains(p->conn->hold_timer), p->conn->hold_time);
|
tm_remains(p->conn->hold_timer), p->conn->hold_time);
|
||||||
cli_msg(-1006, " Keepalive timer: %t/%u",
|
cli_msg(-1006, " Keepalive timer: %t/%u",
|
||||||
tm_remains(p->conn->keepalive_timer), p->conn->keepalive_time);
|
tm_remains(p->conn->keepalive_timer), p->conn->keepalive_time);
|
||||||
|
if (p->cf->ao_key)
|
||||||
|
{
|
||||||
|
int tmp[4];
|
||||||
|
tcp_ao_get_info(p->conn->sk->fd, tmp);
|
||||||
|
cli_msg(-1006, " TCP AO:");
|
||||||
|
cli_msg(-1006, " current key remote id %i", tmp[0]);
|
||||||
|
cli_msg(-1006, " rnext key local id %i", tmp[1]);
|
||||||
|
cli_msg(-1006, " good packets %i", tmp[2]);
|
||||||
|
cli_msg(-1006, " bad packets %i", tmp[3]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -134,8 +134,7 @@ 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 TODO: copy to protocol? */
|
struct ao_config *ao_key; /* Keys for tcp ao authentication */
|
||||||
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 */
|
||||||
@ -343,6 +342,7 @@ struct bgp_proto {
|
|||||||
struct object_lock *lock; /* Lock for neighbor connection */
|
struct object_lock *lock; /* Lock for neighbor connection */
|
||||||
struct neighbor *neigh; /* Neighbor entry corresponding to remote ip, NULL if multihop */
|
struct neighbor *neigh; /* Neighbor entry corresponding to remote ip, NULL if multihop */
|
||||||
struct bgp_socket *sock; /* Shared listening socket */
|
struct bgp_socket *sock; /* Shared listening socket */
|
||||||
|
struct bgp_ao_key *ao_key; /* Linked list for ao keys */
|
||||||
struct bfd_request *bfd_req; /* BFD request, if BFD is used */
|
struct bfd_request *bfd_req; /* BFD request, if BFD is used */
|
||||||
struct birdsock *postponed_sk; /* Postponed incoming socket for dynamic BGP */
|
struct birdsock *postponed_sk; /* Postponed incoming socket for dynamic BGP */
|
||||||
struct bgp_stats stats; /* BGP statistics */
|
struct bgp_stats stats; /* BGP statistics */
|
||||||
@ -541,8 +541,6 @@ bgp_parse_error(struct bgp_parse_state *s, uint subcode)
|
|||||||
longjmp(s->err_jmpbuf, 1);
|
longjmp(s->err_jmpbuf, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_ao(int fd);
|
|
||||||
|
|
||||||
|
|
||||||
void bgp_start_timer(timer *t, uint value);
|
void bgp_start_timer(timer *t, uint value);
|
||||||
void bgp_check_config(struct bgp_config *c);
|
void bgp_check_config(struct bgp_config *c);
|
||||||
|
@ -234,76 +234,83 @@ bgp_afi:
|
|||||||
;
|
;
|
||||||
|
|
||||||
ao_keys:
|
ao_keys:
|
||||||
KEY '{' ao_first_item ao_key '}'
|
KEY '{' ao_first_item ao_key '}'
|
||||||
| KEY '{' ao_first_item ao_key '}' ao_keys
|
| KEY '{' ao_first_item ao_key '}' ao_keys
|
||||||
;
|
;
|
||||||
|
|
||||||
ao_key:
|
ao_key:
|
||||||
ao_item
|
ao_item
|
||||||
| ao_item ao_key
|
| ao_item ao_key
|
||||||
;
|
;
|
||||||
|
|
||||||
ao_first_item:
|
ao_first_item:
|
||||||
LOCAL ID expr ';' {
|
LOCAL ID expr ';' {
|
||||||
if($3 >= 256)
|
if ($3 >= 256)
|
||||||
cf_error("Key ids ust be in range 0 - 255");
|
cf_error("Key ids ust be in range 0 - 255");
|
||||||
if (!BGP_CFG->ao_lp)
|
struct ao_config *new_key = cfg_alloc(sizeof(struct ao_config));
|
||||||
BGP_CFG->ao_lp = lp_new(rp_new(&root_pool, "ao struct pool"));
|
new_key->next_key = BGP_CFG->ao_key;
|
||||||
struct ao_key *new_key = lp_alloc(BGP_CFG->ao_lp, sizeof(struct ao_key));
|
BGP_CFG->ao_key = new_key;
|
||||||
new_key->next_key = BGP_CFG->ao_key;
|
BGP_CFG->ao_key->key.required = 0;
|
||||||
BGP_CFG->ao_key = new_key;
|
BGP_CFG->ao_key->key.local_id = $3;
|
||||||
BGP_CFG->ao_key->required = 0;
|
BGP_CFG->ao_key->key.remote_id = -1;
|
||||||
BGP_CFG->ao_key->local_id = $3;
|
}
|
||||||
BGP_CFG->ao_key->remote_id = -1;
|
|
||||||
}
|
|
||||||
;
|
;
|
||||||
|
|
||||||
ao_item:
|
ao_item:
|
||||||
REMOTE ID expr ';' {
|
REMOTE ID expr ';' {
|
||||||
if ($3 > 255)
|
if ($3 > 255)
|
||||||
cf_error("TCP AO: Key id must be in range 0 - 255");
|
cf_error("TCP AO: Key id must be in range 0 - 255");
|
||||||
BGP_CFG->ao_key->remote_id = $3; }
|
BGP_CFG->ao_key->key.remote_id = $3; }
|
||||||
| CIPHER text ';' {
|
| CIPHER text ';' {
|
||||||
if (strcmp($2, "cmac(aes128)") & strcmp($2, "hmac(sha1)") & strcmp($2, "hmac(sha224)") & strcmp($2, "hmac(sha256)") & strcmp($2, "hmac(sha384)") & strcmp($2, "hmac(sha512)")& strcmp($2, "hmac(md5)"))
|
if (strcmp($2, "cmac(aes128)") & strcmp($2, "hmac(sha1)") & strcmp($2, "hmac(sha224)") & strcmp($2, "hmac(sha256)") & strcmp($2, "hmac(sha384)") & strcmp($2, "hmac(sha512)")& strcmp($2, "hmac(md5)"))
|
||||||
cf_error("TCP AO: Here are ciphers 'cmac(aes128)', 'hmac(md5)', 'hmac(sha1)', 'hmac(sha224)', 'hmac(sha256)', 'hmac(sha384)' and 'hmac(sha512)' hardcoded. If there is another cipher available in kernel, please contact BIRD developers.");
|
cf_error("TCP AO: Here are ciphers 'cmac(aes128)', 'hmac(md5)', 'hmac(sha1)', 'hmac(sha224)', 'hmac(sha256)', 'hmac(sha384)' and 'hmac(sha512)' hardcoded. If there is another cipher available in kernel, please contact BIRD developers.");
|
||||||
char *c = lp_alloc(BGP_CFG->ao_lp, strlen($2));
|
char *c = cfg_alloc(strlen($2)+1);
|
||||||
memcpy(c, $2, strlen($2));
|
memcpy(c, $2, strlen($2)+1);
|
||||||
BGP_CFG->ao_key->cipher = c;
|
BGP_CFG->ao_key->key.cipher = c;
|
||||||
}
|
}
|
||||||
| MASTER KEY text ';' {
|
| MASTER KEY text ';' {
|
||||||
char *k = lp_alloc(BGP_CFG->ao_lp, strlen($3));
|
char *k = cfg_alloc(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->key.master_key = k;
|
||||||
}
|
}
|
||||||
| DEPRECATED ';' { BGP_CFG->ao_key->required = -1; }
|
| DEPRECATED ';' {
|
||||||
| REQUIRED ';' { BGP_CFG->ao_key->required = 1; }
|
if (BGP_CFG->ao_key->key.required == 0)
|
||||||
|
BGP_CFG->ao_key->key.required = -1;
|
||||||
|
else
|
||||||
|
cf_error("TCP AO: Key can be only once deprecated or once required, key id %i", BGP_CFG->ao_key->key.local_id);
|
||||||
|
}
|
||||||
|
| REQUIRED ';' {
|
||||||
|
if (BGP_CFG->ao_key->key.required == 0)
|
||||||
|
BGP_CFG->ao_key->key.required = 1;
|
||||||
|
else
|
||||||
|
cf_error("TCP AO: Key can be only once deprecated or once required, key id %i", BGP_CFG->ao_key->key.local_id);
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
tcp_ao_end:
|
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_loc[256];
|
||||||
char used_aos_id_rem[256];
|
char used_aos_id_rem[256];
|
||||||
memset(used_aos_id_loc, 0, sizeof(char)*256);
|
memset(used_aos_id_loc, 0, sizeof(char)*256);
|
||||||
memset(used_aos_id_rem, 0, sizeof(char)*256);
|
memset(used_aos_id_rem, 0, sizeof(char)*256);
|
||||||
|
|
||||||
int required_found = 0;
|
int required_found = 0;
|
||||||
|
|
||||||
struct ao_key *key = BGP_CFG->ao_key;
|
struct ao_config *key = BGP_CFG->ao_key;
|
||||||
while (key)
|
while (key)
|
||||||
{
|
{
|
||||||
if (used_aos_id_loc[key->local_id])
|
if (used_aos_id_loc[key->key.local_id])
|
||||||
cf_error("TCP AO: Reused local key id %i", key->local_id);
|
cf_error("TCP AO: Reused local key id %i", key->key.local_id);
|
||||||
used_aos_id_loc[key->local_id] = 1;
|
used_aos_id_loc[key->key.local_id] = 1;
|
||||||
if (key->remote_id == -1)
|
if (key->key.remote_id == -1)
|
||||||
cf_error("TCP AO: No remote key id for local id %i", key->local_id);
|
cf_error("TCP AO: No remote key id for local id %i", key->key.local_id);
|
||||||
if (used_aos_id_rem[key->remote_id])
|
if (used_aos_id_rem[key->key.remote_id])
|
||||||
cf_error("TCP AO: Reused remote key id %i", key->remote_id);
|
cf_error("TCP AO: Reused remote key id %i", key->key.remote_id);
|
||||||
used_aos_id_rem[key->remote_id] = 1;
|
used_aos_id_rem[key->key.remote_id] = 1;
|
||||||
if (!key->cipher)
|
if (!key->key.cipher)
|
||||||
cf_error("TCP AO: No cipher given for key id %i.", key->local_id);
|
cf_error("TCP AO: No cipher given for key id %i.", key->key.local_id);
|
||||||
if (!key->master_key)
|
if (!key->key.master_key)
|
||||||
cf_error("TCP AO: No master key given for key id %i.", key->local_id);
|
cf_error("TCP AO: No master key given for key id %i.", key->key.local_id);
|
||||||
if (key->required == 1)
|
if (key->key.required == 1)
|
||||||
{
|
{
|
||||||
if (required_found)
|
if (required_found)
|
||||||
cf_error("TCP AO: How do you want to use two keys at once? Check 'REQUIRED'");
|
cf_error("TCP AO: How do you want to use two keys at once? Check 'REQUIRED'");
|
||||||
|
@ -3410,6 +3410,24 @@ bgp_rx_packet(struct bgp_conn *conn, byte *pkt, uint len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
delete_deprecated_key(sock *sk, struct bgp_proto *p, int key_rem_id)
|
||||||
|
{
|
||||||
|
struct bgp_ao_key *key = p->ao_key;
|
||||||
|
while (key->key.remote_id != key_rem_id)
|
||||||
|
{
|
||||||
|
key = key->next_key;
|
||||||
|
}
|
||||||
|
if (key->key.required != -1)
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bgp_rx - handle received data
|
* bgp_rx - handle received data
|
||||||
* @sk: socket
|
* @sk: socket
|
||||||
@ -3424,29 +3442,25 @@ int
|
|||||||
bgp_rx(sock *sk, uint size)
|
bgp_rx(sock *sk, uint size)
|
||||||
{
|
{
|
||||||
struct bgp_conn *conn = sk->data;
|
struct bgp_conn *conn = sk->data;
|
||||||
|
|
||||||
if (sk->use_ao && sk->desired_ao_key != sk->last_used_ao_key)
|
if (sk->use_ao && sk->desired_ao_key != sk->last_used_ao_key)
|
||||||
{
|
{
|
||||||
int new_rnext = get_current_key_id(sk->fd);
|
int new_rnext = get_current_key_id(sk->fd);
|
||||||
if (new_rnext != sk->last_used_ao_key)
|
if (new_rnext != sk->last_used_ao_key)
|
||||||
{
|
{
|
||||||
if (conn->hold_timer->expires != 0)
|
if (conn->hold_timer->expires != 0)
|
||||||
bgp_schedule_packet(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(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.
|
||||||
|
log(L_INFO "TCP AO: Expected key rotation: desired rnext %i, received %i", sk->desired_ao_key, new_rnext);
|
||||||
|
log_tcp_ao_info(sk->fd);
|
||||||
|
|
||||||
|
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);
|
||||||
|
sk->proto_del_ao_key = NULL;
|
||||||
|
}
|
||||||
sk->last_used_ao_key = new_rnext;
|
sk->last_used_ao_key = new_rnext;
|
||||||
log("Expected desired rnext %i, arrived %i", sk->desired_ao_key, new_rnext);
|
|
||||||
log_ao(sk->fd);
|
|
||||||
}
|
|
||||||
else //todo delete after debug
|
|
||||||
{
|
|
||||||
log("Nothing happend %i %i", get_current_key_id(sk->fd), sk->last_used_ao_key);
|
|
||||||
log_ao(sk->fd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
log("No ao or not expecting changes %i %i", get_current_key_id(sk->fd), sk->last_used_ao_key);
|
|
||||||
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;
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#include "sysdep/linux/tcp-ao.h"
|
#include "sysdep/linux/tcp-ao.h"
|
||||||
|
|
||||||
|
|
||||||
#ifndef IPV6_MINHOPCOUNT
|
#ifndef IPV6_MINHOPCOUNT
|
||||||
#define IPV6_MINHOPCOUNT 73
|
#define IPV6_MINHOPCOUNT 73
|
||||||
#endif
|
#endif
|
||||||
@ -25,14 +24,6 @@
|
|||||||
#define TCP_MD5SIG_FLAG_PREFIX 1
|
#define TCP_MD5SIG_FLAG_PREFIX 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TCP_AO_ADD_KEY
|
|
||||||
#define TCP_AO_ADD_KEY 38 /* Add/Set MKT */
|
|
||||||
#define TCP_AO_DEL_KEY 39 /* Delete MKT */
|
|
||||||
#define TCP_AO_INFO 40 /* Set/list TCP-AO per-socket options */
|
|
||||||
#define TCP_AO_GET_KEYS 41 /* List MKT(s) */
|
|
||||||
#define TCP_AO_REPAIR 42 /* Get/Set SNEs and ISNs */
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* We redefine the tcp_md5sig structure with different name to avoid collision with older headers */
|
/* We redefine the tcp_md5sig structure with different name to avoid collision with older headers */
|
||||||
struct tcp_md5sig_ext {
|
struct tcp_md5sig_ext {
|
||||||
@ -176,11 +167,11 @@ sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
|
|||||||
/*
|
/*
|
||||||
* Miscellaneous Linux socket syscalls
|
* Miscellaneous Linux socket syscalls
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote, int pxlen, struct iface *ifa, const char *passwd, int setkey UNUSED)
|
sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote, int pxlen, struct iface *ifa, const char *passwd, int setkey UNUSED)
|
||||||
{
|
{
|
||||||
struct tcp_md5sig_ext md5;
|
struct tcp_md5sig_ext md5;
|
||||||
log("md5 password is %i, socket fd %i", passwd, s->fd);
|
|
||||||
|
|
||||||
memset(&md5, 0, sizeof(md5));
|
memset(&md5, 0, sizeof(md5));
|
||||||
sockaddr_fill((sockaddr *) &md5.tcpm_addr, s->af, remote, ifa, 0);
|
sockaddr_fill((sockaddr *) &md5.tcpm_addr, s->af, remote, ifa, 0);
|
||||||
@ -198,7 +189,7 @@ sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote, int pxlen, struct
|
|||||||
|
|
||||||
if (pxlen < 0)
|
if (pxlen < 0)
|
||||||
{
|
{
|
||||||
if (setsockopt(s->fd, SOL_TCP, TCP_MD5SIG_EXT, &md5, sizeof(md5)) < 0)
|
if (setsockopt(s->fd, SOL_TCP, TCP_MD5SIG, &md5, sizeof(md5)) < 0)
|
||||||
if (errno == ENOPROTOOPT)
|
if (errno == ENOPROTOOPT)
|
||||||
ERR_MSG("Kernel does not support TCP MD5 signatures");
|
ERR_MSG("Kernel does not support TCP MD5 signatures");
|
||||||
else
|
else
|
||||||
@ -230,11 +221,11 @@ void log_tcp_ao_info(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("log tcp ao info failed with err code %i", errno);
|
log(L_WARN "TCP AO: log tcp ao info failed with err code %i", errno);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
log("current key id %i (rem), next key %i (loc),\n set current %i, ao required %i\n good packets %i, bad packets %i",
|
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",
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,7 +237,7 @@ 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("get current ao key failed %i", 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
|
||||||
@ -261,8 +252,8 @@ int get_rnext_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("get rnext ao key failed %i", errno);
|
log(L_WARN "TCP AO: Getting rnext ao key for socket file descriptor %i failed with errno %i", sock_fd, errno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return tmp.rnext;
|
return tmp.rnext;
|
||||||
@ -278,7 +269,7 @@ 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("tcp ao get keys failed with err code %i", 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;
|
||||||
@ -286,7 +277,7 @@ int get_num_ao_keys(int sock_fd)
|
|||||||
|
|
||||||
void
|
void
|
||||||
log_tcp_ao_get_key(int sock_fd)
|
log_tcp_ao_get_key(int sock_fd)
|
||||||
{
|
{
|
||||||
int nkeys = get_num_ao_keys(sock_fd);
|
int nkeys = get_num_ao_keys(sock_fd);
|
||||||
if (nkeys < 0)
|
if (nkeys < 0)
|
||||||
return;
|
return;
|
||||||
@ -297,27 +288,41 @@ 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("log tcp ao get keys failed with err code %i", errno);
|
log(L_WARN "TCP AO: getting keys on socket fd %i failed with err code %i", sock_fd, errno);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log("keys %i %i", nkeys, 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("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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tcp_ao_get_info(int sock_fd, int key_info[4])
|
||||||
|
{
|
||||||
|
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(L_WARN "TCP AO: log tcp ao info failed with err code %i", errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
key_info[0] = tmp.current_key;
|
||||||
|
key_info[1] = tmp.rnext;
|
||||||
|
key_info[2] = tmp.pkt_good;
|
||||||
|
key_info[3] = tmp.pkt_bad;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
sk_set_ao_auth(sock *s, ip_addr local UNUSED, 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)
|
sk_set_ao_auth(sock *s, ip_addr local UNUSED, 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, pass %s fd %i sk %i %i", passwd, s->fd, s);
|
log(L_DEBUG "tcp ao: socket sets ao, password %s socket fd %i", passwd, s->fd);
|
||||||
/* int af;
|
|
||||||
if (ipa_is_ip4(remote))
|
|
||||||
af = AF_INET;
|
|
||||||
else
|
|
||||||
a = AF_INET6;*/
|
|
||||||
sockaddr_fill((sockaddr *) &ao.addr, s->af, remote, ifa, 0);
|
sockaddr_fill((sockaddr *) &ao.addr, s->af, remote, ifa, 0);
|
||||||
if (set_current)
|
if (set_current)
|
||||||
{
|
{
|
||||||
@ -337,18 +342,16 @@ sk_set_ao_auth(sock *s, ip_addr local UNUSED, ip_addr remote, int pxlen, struct
|
|||||||
ao.ifindex = 0;
|
ao.ifindex = 0;
|
||||||
|
|
||||||
strncpy(ao.alg_name, (cipher) ? cipher : DEFAULT_TEST_ALGO, 64);
|
strncpy(ao.alg_name, (cipher) ? cipher : DEFAULT_TEST_ALGO, 64);
|
||||||
|
ao.keylen = strlen(passwd);
|
||||||
ao.keylen = strlen(passwd);
|
|
||||||
memcpy(ao.key, passwd, (strlen(passwd) > TCP_AO_MAXKEYLEN_) ? TCP_AO_MAXKEYLEN_ : strlen(passwd));
|
memcpy(ao.key, passwd, (strlen(passwd) > TCP_AO_MAXKEYLEN_) ? TCP_AO_MAXKEYLEN_ : strlen(passwd));
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
if (errno == ENOPROTOOPT)
|
if (errno == ENOPROTOOPT)
|
||||||
ERR_MSG("Kernel does not support extended TCP AO signatures");
|
ERR_MSG("Kernel does not support extended TCP AO signatures");
|
||||||
else
|
else
|
||||||
ERR("TCP_AOSIG_EXT");
|
ERR("TCP_AOSIG_EXT");
|
||||||
}
|
}
|
||||||
|
|
||||||
s->use_ao = 1;
|
s->use_ao = 1;
|
||||||
if (set_current)
|
if (set_current)
|
||||||
s->desired_ao_key = passwd_id_rem;
|
s->desired_ao_key = passwd_id_rem;
|
||||||
@ -356,7 +359,7 @@ sk_set_ao_auth(sock *s, ip_addr local UNUSED, ip_addr remote, int pxlen, struct
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
ao_delete_key(sock *s, ip_addr remote, int pxlen, struct iface *ifa, int passwd_id_loc, int passwd_id_rem)
|
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;
|
struct tcp_ao_del_ext del;
|
||||||
@ -373,11 +376,11 @@ ao_delete_key(sock *s, ip_addr remote, int pxlen, struct iface *ifa, int passwd_
|
|||||||
|
|
||||||
if (setsockopt(s->fd, IPPROTO_TCP, TCP_AO_DEL_KEY, &del, sizeof(del)) < 0)
|
if (setsockopt(s->fd, IPPROTO_TCP, TCP_AO_DEL_KEY, &del, sizeof(del)) < 0)
|
||||||
{
|
{
|
||||||
log("log keys for debug delete error key %i %i", passwd_id_loc, passwd_id_rem);
|
log(L_WARN "TCP AO: deletion of key %i %i on socket fd %i failed with err %i", passwd_id_loc, passwd_id_rem, s->fd, errno);
|
||||||
log_tcp_ao_get_key(s->fd);
|
return errno;
|
||||||
bug("tcp ao deletion err %i", errno);
|
|
||||||
}
|
}
|
||||||
log("tcp ao key %i %i deleted", passwd_id_loc, passwd_id_rem);
|
log(L_DEBUG "tcp ao: key %i %i deleted", passwd_id_loc, passwd_id_rem);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -390,27 +393,27 @@ ao_try_change_master(sock *s, int next_master_id_loc, int next_master_id_rem)
|
|||||||
|
|
||||||
if (setsockopt(s->fd, IPPROTO_TCP, TCP_AO_INFO, &tmp, sizeof(tmp)))
|
if (setsockopt(s->fd, IPPROTO_TCP, TCP_AO_INFO, &tmp, sizeof(tmp)))
|
||||||
{
|
{
|
||||||
log(" tcp ao change master key failed with err code %i", errno);
|
log(L_WARN "TCP AO: change master key failed with err code %i", errno);
|
||||||
log_tcp_ao_get_key(s->fd);
|
log_tcp_ao_get_key(s->fd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
log("tried to change master");
|
log(L_DEBUG "tcp ao: tried to change master to %i %i", next_master_id_loc, next_master_id_rem);
|
||||||
s->desired_ao_key = next_master_id_rem;
|
s->desired_ao_key = next_master_id_rem;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int check_ao_keys_id(int sock_fd, struct ao_key *keys)
|
int check_ao_keys_id(int sock_fd, struct bgp_ao_key *keys)
|
||||||
{
|
{
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
int expected_keys[256]; //can not have char, because we must support 0 key id
|
int expected_keys[256]; //can not have char, because we must support 0 key id
|
||||||
memset(expected_keys, 0, sizeof(int)*256);
|
memset(expected_keys, 0, sizeof(int)*256);
|
||||||
for (struct ao_key *key = keys; key; key = key->next_key)
|
for (struct bgp_ao_key *key = keys; key; key = key->next_key)
|
||||||
expected_keys[key->local_id] = 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)
|
||||||
{
|
{
|
||||||
cf_warn("TCP AO: unable to get num of keys");
|
log(L_WARN "TCP AO: unable to get num of keys");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
struct tcp_ao_getsockopt_ext tm_all[nkeys];
|
struct tcp_ao_getsockopt_ext tm_all[nkeys];
|
||||||
@ -420,27 +423,27 @@ int check_ao_keys_id(int sock_fd, struct ao_key *keys)
|
|||||||
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
|
||||||
{
|
{
|
||||||
cf_warn("log tcp ao get keys failed with err code %i", errno);
|
log(L_WARN "TCP AO: log tcp ao get keys failed with err code %i", errno);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
for (int i = 0; i< nkeys; i++)
|
for (int i = 0; i< nkeys; i++)
|
||||||
{
|
{
|
||||||
struct tcp_ao_getsockopt_ext sock_key = tm_all[i];
|
struct tcp_ao_getsockopt_ext sock_key = tm_all[i];
|
||||||
if (expected_keys[sock_key.rcvid] - 1 != sock_key.sndid)
|
if (expected_keys[sock_key.rcvid] - 1 != sock_key.sndid)
|
||||||
{
|
{
|
||||||
if (expected_keys[sock_key.rcvid] == 0)
|
if (expected_keys[sock_key.rcvid] == 0)
|
||||||
cf_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
|
||||||
cf_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;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 256; i++)
|
for (int i = 0; i < 256; i++)
|
||||||
{
|
{
|
||||||
if (expected_keys[i] != 0)
|
if (expected_keys[i] != 0)
|
||||||
{
|
{
|
||||||
cf_warn("TCP AO: key %i %i is not in socket", i, expected_keys - 1);
|
log(L_WARN "TCP AO: key %i %i is not in socket", i, expected_keys - 1);
|
||||||
errors++;
|
errors++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
|
|
||||||
|
#ifndef TCP_AO_ADD_KEY
|
||||||
|
#define TCP_AO_ADD_KEY 38 /* Add/Set MKT */
|
||||||
|
#define TCP_AO_DEL_KEY 39 /* Delete MKT */
|
||||||
|
#define TCP_AO_INFO 40 /* Set/list TCP-AO per-socket options */
|
||||||
|
#define TCP_AO_GET_KEYS 41 /* List MKT(s) */
|
||||||
|
#define TCP_AO_REPAIR 42 /* Get/Set SNEs and ISNs */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifndef TCP_AO_STRUCTS
|
#ifndef TCP_AO_STRUCTS
|
||||||
#define TCP_AO_STRUCTS
|
#define TCP_AO_STRUCTS
|
||||||
|
|
||||||
|
@ -1097,7 +1097,7 @@ sk_passive_connected(sock *s, int type)
|
|||||||
t->tos = s->tos;
|
t->tos = s->tos;
|
||||||
t->vrf = s->vrf;
|
t->vrf = s->vrf;
|
||||||
t->rbsize = s->rbsize;
|
t->rbsize = s->rbsize;
|
||||||
t->tbsize = s->tbsize;
|
t->tbsize = s->tbsize;
|
||||||
|
|
||||||
if (type == SK_TCP)
|
if (type == SK_TCP)
|
||||||
{
|
{
|
||||||
@ -1341,7 +1341,6 @@ sk_open(sock *s)
|
|||||||
int bind_port = 0;
|
int bind_port = 0;
|
||||||
ip_addr bind_addr = IPA_NONE;
|
ip_addr bind_addr = IPA_NONE;
|
||||||
sockaddr sa;
|
sockaddr sa;
|
||||||
log("opening sock");
|
|
||||||
|
|
||||||
if (s->type <= SK_IP)
|
if (s->type <= SK_IP)
|
||||||
{
|
{
|
||||||
@ -1461,21 +1460,23 @@ sk_open(sock *s)
|
|||||||
|
|
||||||
if (s->ao_key_init)
|
if (s->ao_key_init)
|
||||||
{
|
{
|
||||||
struct ao_key *key = s->ao_key_init;
|
struct bgp_ao_key *key = s->ao_key_init;
|
||||||
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, key->required == 1) < 0)
|
if (sk_set_ao_auth(s, s->saddr, s->daddr, -1, s->iface, key->key.master_key, key->key.local_id, key->key.remote_id, key->key.cipher, key->key.required == 1) < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
if (s->type == SK_TCP_ACTIVE)
|
||||||
|
key->activ_alive = 1;
|
||||||
|
else
|
||||||
|
key->passiv_alive = 1;
|
||||||
key = key->next_key;
|
key = key->next_key;
|
||||||
} while (key);
|
} while (key);
|
||||||
}
|
}
|
||||||
else if (s->password)
|
else if (s->password)
|
||||||
{
|
{
|
||||||
log("set md5");
|
|
||||||
if (sk_set_md5_auth(s, s->saddr, s->daddr, -1, s->iface, s->password, 0) < 0)
|
if (sk_set_md5_auth(s, s->saddr, s->daddr, -1, s->iface, s->password, 0) < 0)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
log("no password given");
|
|
||||||
switch (s->type)
|
switch (s->type)
|
||||||
{
|
{
|
||||||
case SK_TCP_ACTIVE:
|
case SK_TCP_ACTIVE:
|
||||||
|
Loading…
Reference in New Issue
Block a user