]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
tcp ao works, but can not be closed
authorKaterina Kubecova <katerina.kubecova@nic.cz>
Mon, 26 Feb 2024 13:58:25 +0000 (14:58 +0100)
committerKaterina Kubecova <katerina.kubecova@nic.cz>
Mon, 26 Feb 2024 13:58:25 +0000 (14:58 +0100)
lib/socket.h
proto/bgp/bgp.c
proto/bgp/config.Y
proto/bgp/packets.c
sysdep/linux/sysio.h
sysdep/unix/io.c

index 8cae88ee734dc5a94d2e18b5b404b878a7b1ae3e..3772cb5ca6b583aa65332361d084030e5f2e956f 100644 (file)
@@ -120,6 +120,7 @@ int sk_set_min_ttl(sock *s, int ttl);       /* Set minimal accepted TTL for given sock
 int sk_set_md5_auth(sock *s, ip_addr local, ip_addr remote, int pxlen, struct iface *ifa, const char *passwd, int setkey);
 
 int get_current_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);
 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);
index 5bbc96c31dae52c3b096529761e59fda1ed4efb8..a79147de0a8978d5b3d06e619f68648584f3c9b9 100644 (file)
@@ -179,7 +179,6 @@ bgp_open(struct bgp_proto *p)
   sk->type = SK_TCP_PASSIVE;
   sk->ttl = 255;
   sk->saddr = addr;
- // sk->daddr = p->remote_ip;
   sk->sport = port;
   sk->iface = ifa;
   sk->vrf = p->p.vrf;
@@ -189,12 +188,11 @@ bgp_open(struct bgp_proto *p)
   sk->tbsize = BGP_TX_BUFFER_SIZE;
   sk->rx_hook = bgp_incoming_connection;
   sk->err_hook = bgp_listen_sock_err;
-  //sk->password = p->cf->password;
 
-  log("passive connect p %i, c cf %i %s", p, p->cf, p->cf->password ? p->cf->password : "no password");
   if (sk_open(sk) < 0)
     goto err;
-
+  
+  log("____________________________________________________________________________%i %i", sk->fd, sk->ao_key);
   bs = mb_allocz(proto_pool, sizeof(struct bgp_socket));
   bs->sk = sk;
   bs->uc = 1;
@@ -251,6 +249,7 @@ bgp_setup_auth(struct bgp_proto *p, int enable)
     {
       log("set ao auth [%s]", p->cf->ao_key->master_key);
       struct ao_key *key = p->cf->ao_key;
+      p->sock->sk->ao_key = key;
       do {
         rv = sk_set_ao_auth(p->sock->sk,
                             p->cf->local_ip, prefix, pxlen, p->cf->iface,
@@ -1085,6 +1084,7 @@ bgp_setup_conn(struct bgp_proto *p, struct bgp_conn *conn)
   conn->channels_to_send = 0;
   conn->last_channel = 0;
   conn->last_channel_count = 0;
+  conn->last_used_ao_key = -1;
 
   conn->connect_timer  = tm_new_init(p->p.pool, bgp_connect_timeout,    conn, 0, 0);
   conn->hold_timer     = tm_new_init(p->p.pool, bgp_hold_timeout,       conn, 0, 0);
@@ -1160,11 +1160,11 @@ bgp_connect(struct bgp_proto *p)        /* Enter Connect state and start establishing c
   bgp_setup_sk(conn, s);
   bgp_conn_set_state(conn, BS_CONNECT);
 
-  log("active open p %i, c cf %i %s ", p, p->cf, p->cf->password ? p->cf->password : "no password");
   if (sk_open(s) < 0)
     goto err;
 
-  //int rv = sk_set_ao_auth(s, p->local_ip, p->remote_ip, -1, s->iface, s->password ? s->password : "d3f4u1t", 1);
+  log("a..........................................................................................fd %i key %i %I", s->fd, s->ao_key, s->daddr);
+
   /* Set minimal receive TTL if needed */
   if (p->cf->ttl_security)
     if (sk_set_min_ttl(s, 256 - hops) < 0)
@@ -2170,9 +2170,9 @@ 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);
+  int key_in_use_rem = get_current_key_id(s_activ->fd);
 
-  if (key_in_use == -1)
+  if (key_in_use_rem == -1)
     {
       log("Unable to detect currently used key");
       return 0;
@@ -2180,10 +2180,15 @@ int reconfigure_tcp_ao(struct bgp_proto old_proto, struct bgp_config new)
 
   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)
   {
      if(old_aos[ao_key->local_id])
@@ -2191,15 +2196,13 @@ int reconfigure_tcp_ao(struct bgp_proto old_proto, struct bgp_config new)
        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);
+        log("%i %i (master %i) %i %i %s %s %s %s", ao_key->local_id, o->local_id, key_in_use, 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.");
+           cf_warn("TCP AO reconfiguration: Currently used master key (%i) part update. This is not allowed.", ao_key->local_id);
           return 0;
         }
-         log("Reusing key id. Not nice. Lets try to update.");
+         cf_warn("TCP AO reconfiguration: Reusing or manipulating key with id %i. This might break connection.", ao_key->local_id);
 
         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);
@@ -2211,13 +2214,19 @@ int reconfigure_tcp_ao(struct bgp_proto old_proto, struct bgp_config new)
      }
      else
      {
+       if (old_rem_id[ao_key->remote_id])
+         cf_warn("TCP AO reconfiguration: Reusing remote id %i with new local id %i. This might break your connection.", ao_key->remote_id, ao_key->local_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);
      }
+     s_activ->ao_key = new.ao_key; 
+     s_passiv->ao_key = new.ao_key;
 
-    if (ao_key->required == 1)
+    if (ao_key->required == 1 && (ao_key->local_id != get_rnext_key_id(s_activ->fd)))
     {
-      ao_try_change_master(s_activ->fd, ao_key->local_id); // or remote id?
+      ao_try_change_master(s_activ->fd, ao_key->local_id);
+      if (old_proto.conn->hold_timer->expires != 0)
+        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
     }
   }
   for(int i = 0; i<256; i++)
@@ -2226,14 +2235,14 @@ int reconfigure_tcp_ao(struct bgp_proto old_proto, struct bgp_config new)
      {
        if (i == key_in_use)
        {
-         log("Currently used key deletion. This is not allowed.");
+         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 changes in ao");
+  log("no big changes in ao");
   return 1;
 }
 
index f3cac9391a1425519a739f01a39f8f520fa61f4a..e0fc6aefc486bff4311a95f76c9160d3b79a16d1 100644 (file)
@@ -245,6 +245,8 @@ ao_key:
 
 ao_first_item:
     LOCAL ID expr ';' {
+      if($3 >= 256)
+        cf_error("Key ids ust be in range 0 - 255");
       if (!BGP_CFG->ao_lp)
         BGP_CFG->ao_lp = lp_new(rp_new(&root_pool, "ao struct pool"));
       struct ao_key *new_key = lp_alloc(BGP_CFG->ao_lp, sizeof(struct ao_key));
@@ -252,20 +254,27 @@ ao_first_item:
       BGP_CFG->ao_key = new_key;
       BGP_CFG->ao_key->required = 0;
       BGP_CFG->ao_key->local_id = $3;
+      BGP_CFG->ao_key->remote_id = -1;
     }
 ;
 
 ao_item:
-      REMOTE ID expr ';' {log("remote id %i", $3); BGP_CFG->ao_key->remote_id = $3; }
-    | CIPHER text ';' { char *c = lp_alloc(BGP_CFG->ao_lp, strlen($2));
+      REMOTE ID expr ';' {
+        if ($3 > 255)
+          cf_error("TCP AO: Key id must be in range 0 - 255");
+        BGP_CFG->ao_key->remote_id = $3; }
+    | 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)"))
+         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));
        memcpy(c, $2, strlen($2));
        BGP_CFG->ao_key->cipher = c;
-       log("ciph[%s]", $2); }
+       }
     | MASTER KEY text ';' {
        char *k = lp_alloc(BGP_CFG->ao_lp, strlen($3));
        memcpy(k, $3, strlen($3));
        BGP_CFG->ao_key->master_key = k;
-       log("key[%s]", BGP_CFG->ao_key->master_key);}
+       }
     | DEPRECATED ';' { BGP_CFG->ao_key->required = -1; }
     | REQUIRED ';' { BGP_CFG->ao_key->required = 1; }
  ;
@@ -283,21 +292,27 @@ tcp_ao_end:
   while (key)
   {
     if (used_aos_id_loc[key->local_id])
-      cf_error("Reused local key id");
+      cf_error("TCP AO: Reused local key id %i", key->local_id);
     used_aos_id_loc[key->local_id] = 1;
+    if (key->remote_id == -1)
+      cf_error("TCP AO: No remote key id for local id %i", key->local_id);
     if (used_aos_id_rem[key->remote_id])
-      cf_error("Reused remote key id");
+      cf_error("TCP AO: Reused remote key id %i", key->remote_id);
     used_aos_id_rem[key->remote_id] = 1;
+    if (!key->cipher)
+      cf_error("TCP AO: No cipher given for key id %i.", key->local_id);
+    if (!key->master_key)
+      cf_error("TCP AO: No master key given for key id %i.", key->local_id);
     if (key->required == 1)
     {
       if (required_found)
-        cf_error("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'");
       required_found = 1;
     }
     key = key->next_key;
   }
   if (required_found == 0)
-    cf_error("Missing 'REQUIRED'. Which key should be used?");
+    cf_error("TCP AO: Missing 'REQUIRED'. Which key should be used?");
 }
 
 bgp_channel_start: bgp_afi
index 97c1102e2a7c9fdf80a7d854bd045aa0dfa3c01f..eae6f87412ad6ff033f6f24fe9b1c4ef38b971b9 100644 (file)
@@ -3424,8 +3424,25 @@ int
 bgp_rx(sock *sk, uint size)
 {
   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);
+  
+  if (sk->ao_key)
+  {
+    if (get_current_key_id(sk->fd) != conn->last_used_ao_key)
+    {
+      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.
+      conn->last_used_ao_key = get_current_key_id(sk->fd);
+      log_ao(sk->fd);
+      log("%i", sk->ao_key);
+    }
+    else //todo delete after debug
+    {
+      log_ao(sk->fd);
+      log("%i %i", get_current_key_id(sk->fd), conn->last_used_ao_key);
+      log("fd %i sk %i key %i", sk->fd, sk, sk->ao_key);
+    }
+  }
+  
   byte *pkt_start = sk->rbuf;
   byte *end = pkt_start + size;
   uint i, len;
index a2e4318246b4c14f96296d65d514072f1d8e8039..4252623d795d059b065d5358bea7d119dcb7a84a 100644 (file)
@@ -253,6 +253,21 @@ int get_current_key_id(int sock_fd)
     return tmp.current_key;
 }
 
+int get_rnext_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 rnext ao key failed %i", errno);
+     return -1;
+  }
+  else
+    return tmp.rnext;
+}
+
 void
 log_tcp_ao_get_key(int sock_fd)
 {
@@ -290,7 +305,9 @@ sk_set_ao_auth(sock *s, ip_addr local, ip_addr remote, int pxlen, struct iface *
 {
   struct tcp_ao_add_ext ao;
   memset(&ao, 0, sizeof(struct tcp_ao_add_ext));
-  log("in sk set ao, pass %s", passwd);
+  if (!s->ao_key)
+    bug("no ao key");
+  log(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>in sk set ao, pass %s fd %i sk %i %i", passwd, s->fd, s, s->ao_key);
  /* int af;
   if (ipa_is_ip4(remote))
     af = AF_INET;
@@ -318,8 +335,7 @@ sk_set_ao_auth(sock *s, ip_addr local, ip_addr remote, int pxlen, struct iface *
 
   ao.keylen    = strlen(passwd);
   memcpy(ao.key, passwd, (strlen(passwd) > TCP_AO_MAXKEYLEN_) ? TCP_AO_MAXKEYLEN_ : strlen(passwd));
-    
-  int IPPROTO_TCP_ = 6;
+
   if (setsockopt(s->fd, IPPROTO_TCP, TCP_AO_ADD_KEY, &ao, sizeof(ao)) < 0)
     bug("tcp ao err %i", errno);
   
@@ -341,7 +357,7 @@ ao_delete_key(sock *s, ip_addr remote, int pxlen, struct iface *ifa, int passwd_
     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);
index 12986ee8a2fb570ffa638ac1951b93d6363fde1a..6057b6e1813fc0da031c60bcfa7b7aaf9d32ea9e 100644 (file)
@@ -1098,6 +1098,7 @@ sk_passive_connected(sock *s, int type)
   t->vrf = s->vrf;
   t->rbsize = s->rbsize;
   t->tbsize = s->tbsize;
+  t->ao_key = s->ao_key;
 
   if (type == SK_TCP)
   {