Make it possible to configure tcp md5 and ipsec on rtr as well
authorclaudio <claudio@openbsd.org>
Wed, 9 Oct 2024 10:01:29 +0000 (10:01 +0000)
committerclaudio <claudio@openbsd.org>
Wed, 9 Oct 2024 10:01:29 +0000 (10:01 +0000)
Single out the auth_config yacc rules. Even though this requires an
extra merge_auth_conf() function to handle manual IPsec setups but
even with that this seems like a net gain.

There is no rtr cache that does tcp md5 on OpenBSD so those bits remain
untested for now.
OK tb@

usr.sbin/bgpd/parse.y
usr.sbin/bgpd/printconf.c

index 166c0e7..954bc5c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: parse.y,v 1.469 2024/10/01 11:49:24 claudio Exp $ */
+/*     $OpenBSD: parse.y,v 1.470 2024/10/09 10:01:29 claudio Exp $ */
 
 /*
  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -187,6 +187,7 @@ static int   push_unary_numop(enum comp_ops, long long);
 static int      push_binary_numop(enum comp_ops, long long, long long);
 static int      geticmptypebyname(char *, uint8_t);
 static int      geticmpcodebyname(u_long, char *, uint8_t);
+static int      merge_auth_conf(struct auth_config *, struct auth_config *);
 
 static struct bgpd_config      *conf;
 static struct network_head     *netconf;
@@ -228,6 +229,7 @@ typedef struct {
                }                       prefix;
                struct filter_prefixlen prefixlen;
                struct prefixset_item   *prefixset_item;
+               struct auth_config      authconf;
                struct {
                        enum auth_enc_alg       enc_alg;
                        uint8_t                 enc_key_len;
@@ -293,6 +295,7 @@ typedef struct {
 %type  <v.filter_prefix>       filter_prefix filter_prefix_l filter_prefix_h
 %type  <v.filter_prefix>       filter_prefix_m
 %type  <v.u8>                  unaryop equalityop binaryop filter_as_type
+%type  <v.authconf>            authconf
 %type  <v.encspec>             encspec
 %type  <v.aspa_elm>            aspa_tas aspa_tas_l
 %%
@@ -732,6 +735,10 @@ rtropt             : DESCR STRING          {
                        }
                        currtr->min_version = $2;
                }
+               | authconf {
+                       if (merge_auth_conf(&currtr->auth, &$1) == 0)
+                               YYERROR;
+               }
                ;
 
 conf_main      : AS as4number          {
@@ -2075,142 +2082,9 @@ peeropts        : REMOTEAS as4number    {
                        curpeer->conf.max_out_prefix = $2;
                        curpeer->conf.max_out_prefix_restart = $4;
                }
-               | TCP MD5SIG PASSWORD string {
-                       if (curpeer->auth_conf.method) {
-                               yyerror("auth method cannot be redefined");
-                               free($4);
-                               YYERROR;
-                       }
-                       if (strlcpy(curpeer->auth_conf.md5key, $4,
-                           sizeof(curpeer->auth_conf.md5key)) >=
-                           sizeof(curpeer->auth_conf.md5key)) {
-                               yyerror("tcp md5sig password too long: max %zu",
-                                   sizeof(curpeer->auth_conf.md5key) - 1);
-                               free($4);
-                               YYERROR;
-                       }
-                       curpeer->auth_conf.method = AUTH_MD5SIG;
-                       curpeer->auth_conf.md5key_len = strlen($4);
-                       free($4);
-               }
-               | TCP MD5SIG KEY string {
-                       if (curpeer->auth_conf.method) {
-                               yyerror("auth method cannot be redefined");
-                               free($4);
-                               YYERROR;
-                       }
-
-                       if (str2key($4, curpeer->auth_conf.md5key,
-                           sizeof(curpeer->auth_conf.md5key)) == -1) {
-                               free($4);
-                               YYERROR;
-                       }
-                       curpeer->auth_conf.method = AUTH_MD5SIG;
-                       curpeer->auth_conf.md5key_len = strlen($4) / 2;
-                       free($4);
-               }
-               | IPSEC espah IKE {
-                       if (curpeer->auth_conf.method) {
-                               yyerror("auth method cannot be redefined");
-                               YYERROR;
-                       }
-                       if ($2)
-                               curpeer->auth_conf.method = AUTH_IPSEC_IKE_ESP;
-                       else
-                               curpeer->auth_conf.method = AUTH_IPSEC_IKE_AH;
-               }
-               | IPSEC espah inout SPI NUMBER STRING STRING encspec {
-                       enum auth_alg   auth_alg;
-                       uint8_t         keylen;
-
-                       if (curpeer->auth_conf.method &&
-                           (((curpeer->auth_conf.spi_in && $3 == 1) ||
-                           (curpeer->auth_conf.spi_out && $3 == 0)) ||
-                           ($2 == 1 && curpeer->auth_conf.method !=
-                           AUTH_IPSEC_MANUAL_ESP) ||
-                           ($2 == 0 && curpeer->auth_conf.method !=
-                           AUTH_IPSEC_MANUAL_AH))) {
-                               yyerror("auth method cannot be redefined");
-                               free($6);
-                               free($7);
-                               YYERROR;
-                       }
-
-                       if (!strcmp($6, "sha1")) {
-                               auth_alg = AUTH_AALG_SHA1HMAC;
-                               keylen = 20;
-                       } else if (!strcmp($6, "md5")) {
-                               auth_alg = AUTH_AALG_MD5HMAC;
-                               keylen = 16;
-                       } else {
-                               yyerror("unknown auth algorithm \"%s\"", $6);
-                               free($6);
-                               free($7);
+               | authconf {
+                       if (merge_auth_conf(&curpeer->auth_conf, &$1) == 0)
                                YYERROR;
-                       }
-                       free($6);
-
-                       if (strlen($7) / 2 != keylen) {
-                               yyerror("auth key len: must be %u bytes, "
-                                   "is %zu bytes", keylen, strlen($7) / 2);
-                               free($7);
-                               YYERROR;
-                       }
-
-                       if ($2)
-                               curpeer->auth_conf.method =
-                                   AUTH_IPSEC_MANUAL_ESP;
-                       else {
-                               if ($8.enc_alg) {
-                                       yyerror("\"ipsec ah\" doesn't take "
-                                           "encryption keys");
-                                       free($7);
-                                       YYERROR;
-                               }
-                               curpeer->auth_conf.method =
-                                   AUTH_IPSEC_MANUAL_AH;
-                       }
-
-                       if ($5 <= SPI_RESERVED_MAX || $5 > UINT_MAX) {
-                               yyerror("bad spi number %lld", $5);
-                               free($7);
-                               YYERROR;
-                       }
-
-                       if ($3 == 1) {
-                               if (str2key($7, curpeer->auth_conf.auth_key_in,
-                                   sizeof(curpeer->auth_conf.auth_key_in)) ==
-                                   -1) {
-                                       free($7);
-                                       YYERROR;
-                               }
-                               curpeer->auth_conf.spi_in = $5;
-                               curpeer->auth_conf.auth_alg_in = auth_alg;
-                               curpeer->auth_conf.enc_alg_in = $8.enc_alg;
-                               memcpy(&curpeer->auth_conf.enc_key_in,
-                                   &$8.enc_key,
-                                   sizeof(curpeer->auth_conf.enc_key_in));
-                               curpeer->auth_conf.enc_keylen_in =
-                                   $8.enc_key_len;
-                               curpeer->auth_conf.auth_keylen_in = keylen;
-                       } else {
-                               if (str2key($7, curpeer->auth_conf.auth_key_out,
-                                   sizeof(curpeer->auth_conf.auth_key_out)) ==
-                                   -1) {
-                                       free($7);
-                                       YYERROR;
-                               }
-                               curpeer->auth_conf.spi_out = $5;
-                               curpeer->auth_conf.auth_alg_out = auth_alg;
-                               curpeer->auth_conf.enc_alg_out = $8.enc_alg;
-                               memcpy(&curpeer->auth_conf.enc_key_out,
-                                   &$8.enc_key,
-                                   sizeof(curpeer->auth_conf.enc_key_out));
-                               curpeer->auth_conf.enc_keylen_out =
-                                   $8.enc_key_len;
-                               curpeer->auth_conf.auth_keylen_out = keylen;
-                       }
-                       free($7);
                }
                | TTLSECURITY yesno     {
                        curpeer->conf.ttlsec = $2;
@@ -2357,6 +2231,111 @@ nettype         : STATIC { $$ = 1; }
                | CONNECTED { $$ = 0; }
                ;
 
+authconf       : TCP MD5SIG PASSWORD string {
+                       memset(&$$, 0, sizeof($$));
+                       if (strlcpy($$.md5key, $4, sizeof($$.md5key)) >=
+                           sizeof($$.md5key)) {
+                               yyerror("tcp md5sig password too long: max %zu",
+                                   sizeof($$.md5key) - 1);
+                               free($4);
+                               YYERROR;
+                       }
+                       $$.method = AUTH_MD5SIG;
+                       $$.md5key_len = strlen($4);
+                       free($4);
+               }
+               | TCP MD5SIG KEY string {
+                       memset(&$$, 0, sizeof($$));
+                       if (str2key($4, $$.md5key, sizeof($$.md5key)) == -1) {
+                               free($4);
+                               YYERROR;
+                       }
+                       $$.method = AUTH_MD5SIG;
+                       $$.md5key_len = strlen($4) / 2;
+                       free($4);
+               }
+               | IPSEC espah IKE {
+                       memset(&$$, 0, sizeof($$));
+                       if ($2)
+                               $$.method = AUTH_IPSEC_IKE_ESP;
+                       else
+                               $$.method = AUTH_IPSEC_IKE_AH;
+               }
+               | IPSEC espah inout SPI NUMBER STRING STRING encspec {
+                       enum auth_alg   auth_alg;
+                       uint8_t         keylen;
+
+                       memset(&$$, 0, sizeof($$));
+                       if (!strcmp($6, "sha1")) {
+                               auth_alg = AUTH_AALG_SHA1HMAC;
+                               keylen = 20;
+                       } else if (!strcmp($6, "md5")) {
+                               auth_alg = AUTH_AALG_MD5HMAC;
+                               keylen = 16;
+                       } else {
+                               yyerror("unknown auth algorithm \"%s\"", $6);
+                               free($6);
+                               free($7);
+                               YYERROR;
+                       }
+                       free($6);
+
+                       if (strlen($7) / 2 != keylen) {
+                               yyerror("auth key len: must be %u bytes, "
+                                   "is %zu bytes", keylen, strlen($7) / 2);
+                               free($7);
+                               YYERROR;
+                       }
+
+                       if ($2)
+                               $$.method = AUTH_IPSEC_MANUAL_ESP;
+                       else {
+                               if ($8.enc_alg) {
+                                       yyerror("\"ipsec ah\" doesn't take "
+                                           "encryption keys");
+                                       free($7);
+                                       YYERROR;
+                               }
+                               $$.method = AUTH_IPSEC_MANUAL_AH;
+                       }
+
+                       if ($5 <= SPI_RESERVED_MAX || $5 > UINT_MAX) {
+                               yyerror("bad spi number %lld", $5);
+                               free($7);
+                               YYERROR;
+                       }
+
+                       if ($3 == 1) {
+                               if (str2key($7, $$.auth_key_in,
+                                   sizeof($$.auth_key_in)) == -1) {
+                                       free($7);
+                                       YYERROR;
+                               }
+                               $$.spi_in = $5;
+                               $$.auth_alg_in = auth_alg;
+                               $$.enc_alg_in = $8.enc_alg;
+                               memcpy(&$$.enc_key_in, &$8.enc_key,
+                                   sizeof($$.enc_key_in));
+                               $$.enc_keylen_in = $8.enc_key_len;
+                               $$.auth_keylen_in = keylen;
+                       } else {
+                               if (str2key($7, $$.auth_key_out,
+                                   sizeof($$.auth_key_out)) == -1) {
+                                       free($7);
+                                       YYERROR;
+                               }
+                               $$.spi_out = $5;
+                               $$.auth_alg_out = auth_alg;
+                               $$.enc_alg_out = $8.enc_alg;
+                               memcpy(&$$.enc_key_out, &$8.enc_key,
+                                   sizeof($$.enc_key_out));
+                               $$.enc_keylen_out = $8.enc_key_len;
+                               $$.auth_keylen_out = keylen;
+                       }
+                       free($7);
+               }
+               ;
+
 espah          : ESP           { $$ = 1; }
                | AH            { $$ = 0; }
                ;
@@ -6033,3 +6012,39 @@ geticmpcodebyname(u_long type, char *w, uint8_t aid)
        }
        return -1;
 }
+
+static int
+merge_auth_conf(struct auth_config *to, struct auth_config *from)
+{
+       if (to->method != 0) {
+               /* extra magic for manual ipsec rules */
+               if (to->method == from->method &&
+                   (to->method == AUTH_IPSEC_MANUAL_ESP ||
+                   to->method == AUTH_IPSEC_MANUAL_AH)) {
+                       if (to->spi_in == 0 && from->spi_in != 0) {
+                               to->spi_in = from->spi_in;
+                               to->auth_alg_in = from->auth_alg_in;
+                               to->enc_alg_in = from->enc_alg_in;
+                               memcpy(to->enc_key_in, from->enc_key_in,
+                                   sizeof(to->enc_key_in));
+                               to->enc_keylen_in = from->enc_keylen_in;
+                               to->auth_keylen_in = from->auth_keylen_in;
+                               return 1;
+                       } else if (to->spi_out == 0 && from->spi_out != 0) {
+                               to->spi_out = from->spi_out;
+                               to->auth_alg_out = from->auth_alg_out;
+                               to->enc_alg_out = from->enc_alg_out;
+                               memcpy(to->enc_key_out, from->enc_key_out,
+                                   sizeof(to->enc_key_out));
+                               to->enc_keylen_out = from->enc_keylen_out;
+                               to->auth_keylen_out = from->auth_keylen_out;
+                               return 1;
+                       }
+               }
+               yyerror("auth method cannot be redefined");
+               return 0;
+       }
+       *to = *from;
+       return 1;
+}
+
index e34380f..a62311e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: printconf.c,v 1.175 2024/10/01 11:49:24 claudio Exp $ */
+/*     $OpenBSD: printconf.c,v 1.176 2024/10/09 10:01:29 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -712,6 +712,39 @@ print_aspa(struct aspa_tree *a)
        printf("\n}\n\n");
 }
 
+static void
+print_auth(struct auth_config *auth, const char *c)
+{
+       char *method;
+
+       if (auth->method == AUTH_MD5SIG)
+               printf("%s\ttcp md5sig\n", c);
+       else if (auth->method == AUTH_IPSEC_MANUAL_ESP ||
+           auth->method == AUTH_IPSEC_MANUAL_AH) {
+               if (auth->method == AUTH_IPSEC_MANUAL_ESP)
+                       method = "esp";
+               else
+                       method = "ah";
+
+               printf("%s\tipsec %s in spi %u %s XXXXXX", c, method,
+                   auth->spi_in, print_auth_alg(auth->auth_alg_in));
+               if (auth->enc_alg_in)
+                       printf(" %s XXXXXX", print_enc_alg(auth->enc_alg_in));
+               printf("\n");
+
+               printf("%s\tipsec %s out spi %u %s XXXXXX", c, method,
+                   auth->spi_out, print_auth_alg(auth->auth_alg_out));
+               if (auth->enc_alg_out)
+                       printf(" %s XXXXXX",
+                           print_enc_alg(auth->enc_alg_out));
+               printf("\n");
+       } else if (auth->method == AUTH_IPSEC_IKE_AH)
+               printf("%s\tipsec ah ike\n", c);
+       else if (auth->method == AUTH_IPSEC_IKE_ESP)
+               printf("%s\tipsec esp ike\n", c);
+
+}
+
 void
 print_rtrs(struct rtr_config_head *rh)
 {
@@ -723,6 +756,7 @@ print_rtrs(struct rtr_config_head *rh)
                printf("\tport %u\n", r->remote_port);
                if (r->local_addr.aid != AID_UNSPEC)
                        printf("local-addr %s\n", log_addr(&r->local_addr));
+               print_auth(&r->auth, "");
                printf("}\n\n");
        }
 }
@@ -731,9 +765,7 @@ void
 print_peer(struct peer *peer, struct bgpd_config *conf, const char *c)
 {
        struct in_addr           ina;
-       char                    *method;
        struct peer_config      *p = &peer->conf;
-       struct auth_config      *auth = &peer->auth_conf;
 
        if ((p->remote_addr.aid == AID_INET && p->remote_masklen != 32) ||
            (p->remote_addr.aid == AID_INET6 && p->remote_masklen != 128))
@@ -832,31 +864,7 @@ print_peer(struct peer *peer, struct bgpd_config *conf, const char *c)
        if (p->flags & PEERFLAG_LOG_UPDATES)
                printf("%s\tlog updates\n", c);
 
-       if (auth->method == AUTH_MD5SIG)
-               printf("%s\ttcp md5sig\n", c);
-       else if (auth->method == AUTH_IPSEC_MANUAL_ESP ||
-           auth->method == AUTH_IPSEC_MANUAL_AH) {
-               if (auth->method == AUTH_IPSEC_MANUAL_ESP)
-                       method = "esp";
-               else
-                       method = "ah";
-
-               printf("%s\tipsec %s in spi %u %s XXXXXX", c, method,
-                   auth->spi_in, print_auth_alg(auth->auth_alg_in));
-               if (auth->enc_alg_in)
-                       printf(" %s XXXXXX", print_enc_alg(auth->enc_alg_in));
-               printf("\n");
-
-               printf("%s\tipsec %s out spi %u %s XXXXXX", c, method,
-                   auth->spi_out, print_auth_alg(auth->auth_alg_out));
-               if (auth->enc_alg_out)
-                       printf(" %s XXXXXX",
-                           print_enc_alg(auth->enc_alg_out));
-               printf("\n");
-       } else if (auth->method == AUTH_IPSEC_IKE_AH)
-               printf("%s\tipsec ah ike\n", c);
-       else if (auth->method == AUTH_IPSEC_IKE_ESP)
-               printf("%s\tipsec esp ike\n", c);
+       print_auth(&peer->auth_conf, c);
 
        if (p->ttlsec)
                printf("%s\tttl-security yes\n", c);