diff options
Diffstat (limited to 'sysdep')
-rw-r--r-- | sysdep/autoconf.h.in | 1 | ||||
-rw-r--r-- | sysdep/bsd/setkey.h | 170 | ||||
-rw-r--r-- | sysdep/bsd/sysio.h | 28 | ||||
-rw-r--r-- | sysdep/config.h | 2 | ||||
-rw-r--r-- | sysdep/linux/netlink.c | 14 | ||||
-rw-r--r-- | sysdep/linux/sysio.h | 6 | ||||
-rw-r--r-- | sysdep/unix/io.c | 26 | ||||
-rw-r--r-- | sysdep/unix/log.c | 1 | ||||
-rw-r--r-- | sysdep/unix/main.c | 16 |
9 files changed, 231 insertions, 33 deletions
diff --git a/sysdep/autoconf.h.in b/sysdep/autoconf.h.in index a9e46e27..c73270c3 100644 --- a/sysdep/autoconf.h.in +++ b/sysdep/autoconf.h.in @@ -43,6 +43,7 @@ #undef CONFIG_BGP #undef CONFIG_OSPF #undef CONFIG_PIPE +#undef CONFIG_BABEL /* We use multithreading */ #undef USE_PTHREADS diff --git a/sysdep/bsd/setkey.h b/sysdep/bsd/setkey.h new file mode 100644 index 00000000..b417faca --- /dev/null +++ b/sysdep/bsd/setkey.h @@ -0,0 +1,170 @@ +/* + * BIRD -- Manipulation the IPsec SA/SP database using setkey(8) utility + * + * (c) 2016 CZ.NIC z.s.p.o. + */ + +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <net/pfkeyv2.h> +#include <netipsec/ipsec.h> + +#include "nest/bird.h" +#include "lib/unix.h" + + +/* + * Open a socket for manage the IPsec SA/SP database entries + */ +static int +setkey_open_socket(void) +{ + int s = socket(PF_KEY, SOCK_RAW, PF_KEY_V2); + if (s < 0) + { + log(L_ERR "SETKEY: socket: %m"); + return -1; + } + + return s; +} + +static int +setkey_send(struct sadb_msg *msg, uint len) +{ + int s = setkey_open_socket(); + if (s < 0) + return -1; + + if (msg->sadb_msg_type == SADB_ADD) + { + /* Delete possible current key in the IPsec SA/SP database */ + msg->sadb_msg_type = SADB_DELETE; + send(s, msg, len, 0); + msg->sadb_msg_type = SADB_ADD; + } + + if (send(s, msg, len, 0) < 0) + { + log(L_ERR "SETKEY: send: %m"); + close(s); + return -1; + } + + close(s); + return 0; +} + +/* + * Perform setkey(8)-like operation for set the password for TCP MD5 Signature. + * Could be called with SABD_ADD or SADB_DELETE argument. Note that SADB_ADD + * argument is internally processed as a pair of SADB_ADD and SADB_DELETE + * operations to implement replace. + */ +static int +setkey_md5(sockaddr *src, sockaddr *dst, char *passwd, uint type) +{ + uint passwd_len = passwd ? strlen(passwd) : 0; + + uint total = + sizeof(struct sadb_msg) + + sizeof(struct sadb_key) + PFKEY_ALIGN8(passwd_len) + + sizeof(struct sadb_sa) + + sizeof(struct sadb_x_sa2) + + sizeof(struct sadb_address) + PFKEY_ALIGN8(src->sa.sa_len) + + sizeof(struct sadb_address) + PFKEY_ALIGN8(dst->sa.sa_len); + + char *buf = alloca(total); + char *pos = buf; + uint len; + + memset(buf, 0, total); + + struct sadb_msg *msg = (void *) pos; + len = sizeof(struct sadb_msg); + msg->sadb_msg_version = PF_KEY_V2; + msg->sadb_msg_type = type; + msg->sadb_msg_satype = SADB_X_SATYPE_TCPSIGNATURE; + msg->sadb_msg_len = 0; /* Fix it later */ + msg->sadb_msg_pid = getpid(); + pos += len; + + /* Set authentication algorithm and password */ + struct sadb_key *key = (void *) pos; + len = sizeof(struct sadb_key) + PFKEY_ALIGN8(passwd_len); + key->sadb_key_len = PFKEY_UNIT64(len); + key->sadb_key_exttype = SADB_EXT_KEY_AUTH; + key->sadb_key_bits = passwd_len * 8; + memcpy(pos + sizeof(struct sadb_key), passwd, passwd_len); + pos += len; + + struct sadb_sa *sa = (void *) pos; + len = sizeof(struct sadb_sa); + sa->sadb_sa_len = PFKEY_UNIT64(len); + sa->sadb_sa_exttype = SADB_EXT_SA; + sa->sadb_sa_spi = htonl((u32) TCP_SIG_SPI); + sa->sadb_sa_auth = SADB_X_AALG_TCP_MD5; + sa->sadb_sa_encrypt = SADB_EALG_NONE; + sa->sadb_sa_flags = SADB_X_EXT_CYCSEQ; + pos += len; + + struct sadb_x_sa2 *sa2 = (void *) pos; + len = sizeof(struct sadb_x_sa2); + sa2->sadb_x_sa2_len = PFKEY_UNIT64(len); + sa2->sadb_x_sa2_exttype = SADB_X_EXT_SA2; + sa2->sadb_x_sa2_mode = IPSEC_MODE_ANY; + pos += len; + + /* Set source address */ + struct sadb_address *saddr = (void *) pos; + len = sizeof(struct sadb_address) + PFKEY_ALIGN8(src->sa.sa_len); + saddr->sadb_address_len = PFKEY_UNIT64(len); + saddr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + saddr->sadb_address_proto = IPSEC_ULPROTO_ANY; + saddr->sadb_address_prefixlen = MAX_PREFIX_LENGTH; + memcpy(pos + sizeof(struct sadb_address), &src->sa, src->sa.sa_len); + pos += len; + + /* Set destination address */ + struct sadb_address *daddr = (void *) pos; + len = sizeof(struct sadb_address) + PFKEY_ALIGN8(dst->sa.sa_len); + daddr->sadb_address_len = PFKEY_UNIT64(len); + daddr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; + daddr->sadb_address_proto = IPSEC_ULPROTO_ANY; + daddr->sadb_address_prefixlen = MAX_PREFIX_LENGTH; + memcpy(pos + sizeof(struct sadb_address), &dst->sa, dst->sa.sa_len); + pos += len; + + len = pos - buf; + msg->sadb_msg_len = PFKEY_UNIT64(len); + + return setkey_send(msg, len); +} + +/* + * Manipulation with the IPsec SA/SP database + */ +static int +sk_set_md5_in_sasp_db(sock *s, ip_addr local, ip_addr remote, struct iface *ifa, char *passwd) +{ + sockaddr src, dst; + sockaddr_fill(&src, s->af, local, ifa, 0); + sockaddr_fill(&dst, s->af, remote, ifa, 0); + + if (passwd && *passwd) + { + int len = strlen(passwd); + if (len > TCP_KEYLEN_MAX) + ERR_MSG("The password for TCP MD5 Signature is too long"); + + if (setkey_md5(&src, &dst, passwd, SADB_ADD) < 0) + ERR_MSG("Cannot add TCP-MD5 password into the IPsec SA/SP database"); + } + else + { + if (setkey_md5(&src, &dst, NULL, SADB_DELETE) < 0) + ERR_MSG("Cannot delete TCP-MD5 password from the IPsec SA/SP database"); + } + return 0; +} diff --git a/sysdep/bsd/sysio.h b/sysdep/bsd/sysio.h index c82d7a1e..6c20733f 100644 --- a/sysdep/bsd/sysio.h +++ b/sysdep/bsd/sysio.h @@ -189,30 +189,26 @@ sk_prepare_ip_header(sock *s, void *hdr, int dlen) #ifndef TCP_KEYLEN_MAX #define TCP_KEYLEN_MAX 80 #endif + #ifndef TCP_SIG_SPI #define TCP_SIG_SPI 0x1000 #endif -/* - * FIXME: Passwords has to be set by setkey(8) command. This is the same - * behaviour like Quagga. We need to add code for SA/SP entries - * management. - */ +#if defined(__FreeBSD__) +#define USE_MD5SIG_SETKEY +#include "lib/setkey.h" +#endif int -sk_set_md5_auth(sock *s, ip_addr a, struct iface *ifa, char *passwd) +sk_set_md5_auth(sock *s, ip_addr local, ip_addr remote, struct iface *ifa, char *passwd, int setkey UNUSED) { - int enable = 0; - - if (passwd && *passwd) - { - int len = strlen(passwd); - enable = TCP_SIG_SPI; - - if (len > TCP_KEYLEN_MAX) - ERR_MSG("MD5 password too long"); - } +#ifdef USE_MD5SIG_SETKEY + if (setkey) + if (sk_set_md5_in_sasp_db(s, local, remote, ifa, passwd) < 0) + return -1; +#endif + int enable = (passwd && *passwd) ? TCP_SIG_SPI : 0; if (setsockopt(s->fd, IPPROTO_TCP, TCP_MD5SIG, &enable, sizeof(enable)) < 0) { if (errno == ENOPROTOOPT) diff --git a/sysdep/config.h b/sysdep/config.h index 08c15fe9..a8d58349 100644 --- a/sysdep/config.h +++ b/sysdep/config.h @@ -7,7 +7,7 @@ #define _BIRD_CONFIG_H_ /* BIRD version */ -#define BIRD_VERSION "1.5.0" +#define BIRD_VERSION "1.6.0" /* Include parameters determined by configure script */ #include "sysdep/autoconf.h" diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 8166d5f5..8146072b 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -126,7 +126,12 @@ nl_get_reply(struct nl_sock *nl) { struct iovec iov = { nl->rx_buffer, NL_RX_SIZE }; struct sockaddr_nl sa; - struct msghdr m = { (struct sockaddr *) &sa, sizeof(sa), &iov, 1, NULL, 0, 0 }; + struct msghdr m = { + .msg_name = &sa, + .msg_namelen = sizeof(sa), + .msg_iov = &iov, + .msg_iovlen = 1, + }; int x = recvmsg(nl->fd, &m, 0); if (x < 0) die("nl_get_reply: %m"); @@ -1343,7 +1348,12 @@ nl_async_hook(sock *sk, int size UNUSED) { struct iovec iov = { nl_async_rx_buffer, NL_RX_SIZE }; struct sockaddr_nl sa; - struct msghdr m = { (struct sockaddr *) &sa, sizeof(sa), &iov, 1, NULL, 0, 0 }; + struct msghdr m = { + .msg_name = &sa, + .msg_namelen = sizeof(sa), + .msg_iov = &iov, + .msg_iovlen = 1, + }; struct nlmsghdr *h; int x; uint len; diff --git a/sysdep/linux/sysio.h b/sysdep/linux/sysio.h index 6386940f..3c07a3e7 100644 --- a/sysdep/linux/sysio.h +++ b/sysdep/linux/sysio.h @@ -179,19 +179,19 @@ sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) */ int -sk_set_md5_auth(sock *s, ip_addr a, struct iface *ifa, char *passwd) +sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote, struct iface *ifa, char *passwd, int setkey UNUSED) { struct tcp_md5sig md5; memset(&md5, 0, sizeof(md5)); - sockaddr_fill((sockaddr *) &md5.tcpm_addr, fam_to_af[s->fam], a, ifa, 0); + sockaddr_fill((sockaddr *) &md5.tcpm_addr, fam_to_af[s->fam], remote, ifa, 0); if (passwd) { int len = strlen(passwd); if (len > TCP_MD5SIG_MAXKEYLEN) - ERR_MSG("MD5 password too long"); + ERR_MSG("The password for TCP MD5 Signature is too long"); md5.tcpm_keylen = len; memcpy(&md5.tcpm_key, passwd, len); diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 08521d75..69c17d60 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -448,6 +448,7 @@ tm_format_reltime(char *x, struct tm *tm, bird_clock_t delta) /** * tm_format_datetime - convert date and time to textual representation * @x: destination buffer of size %TM_DATETIME_BUFFER_SIZE + * @fmt_spec: specification of resulting textual representation of the time * @t: time * * This function formats the given relative time value @t to a textual @@ -952,23 +953,32 @@ sk_set_min_ttl(sock *s, int ttl) /** * sk_set_md5_auth - add / remove MD5 security association for given socket * @s: socket - * @a: IP address of the other side + * @local: IP address of local side + * @remote: IP address of remote side * @ifa: Interface for link-local IP address - * @passwd: password used for MD5 authentication + * @passwd: Password used for MD5 authentication + * @setkey: Update also system SA/SP database * - * In TCP MD5 handling code in kernel, there is a set of pairs (address, - * password) used to choose password according to address of the other side. - * This function is useful for listening socket, for active sockets it is enough - * to set s->password field. + * In TCP MD5 handling code in kernel, there is a set of security associations + * used for choosing password and other authentication parameters according to + * the local and remote address. This function is useful for listening socket, + * for active sockets it may be enough to set s->password field. * * When called with passwd != NULL, the new pair is added, * When called with passwd == NULL, the existing pair is removed. * + * Note that while in Linux, the MD5 SAs are specific to socket, in BSD they are + * stored in global SA/SP database (but the behavior also must be enabled on + * per-socket basis). In case of multiple sockets to the same neighbor, the + * socket-specific state must be configured for each socket while global state + * just once per src-dst pair. The @setkey argument controls whether the global + * state (SA/SP database) is also updated. + * * Result: 0 for success, -1 for an error. */ int -sk_set_md5_auth(sock *s, ip_addr a, struct iface *ifa, char *passwd) +sk_set_md5_auth(sock *s, ip_addr local, ip_addr remote, struct iface *ifa, char *passwd, int setkey) { DUMMY; } #endif @@ -1436,7 +1446,7 @@ sk_open(sock *s) } if (s->password) - if (sk_set_md5_auth(s, s->daddr, s->iface, s->password) < 0) + if (sk_set_md5_auth(s, s->saddr, s->daddr, s->iface, s->password, 0) < 0) goto err; switch (s->type) diff --git a/sysdep/unix/log.c b/sysdep/unix/log.c index 43d98f7b..9c56eb24 100644 --- a/sysdep/unix/log.c +++ b/sysdep/unix/log.c @@ -89,6 +89,7 @@ static char *class_names[] = { /** * log_commit - commit a log message * @class: message class information (%L_DEBUG to %L_BUG, see |lib/birdlib.h|) + * @buf: message to write * * This function writes a message prepared in the log buffer to the * log file (as specified in the configuration). The log buffer is diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index 691fee2d..1f47680e 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -621,7 +621,7 @@ signal_init(void) * Parsing of command-line arguments */ -static char *opt_list = "c:dD:ps:P:u:g:fR"; +static char *opt_list = "c:dD:ps:P:u:g:flR"; static int parse_and_exit; char *bird_name; static char *use_user; @@ -631,7 +631,7 @@ static int run_in_foreground = 0; static void usage(void) { - fprintf(stderr, "Usage: %s [-c <config-file>] [-d] [-D <debug-file>] [-p] [-s <control-socket>] [-P <pid-file>] [-u <user>] [-g <group>] [-f] [-R]\n", bird_name); + fprintf(stderr, "Usage: %s [-c <config-file>] [-d] [-D <debug-file>] [-p] [-s <control-socket>] [-P <pid-file>] [-u <user>] [-g <group>] [-f] [-l] [-R]\n", bird_name); exit(1); } @@ -681,7 +681,7 @@ get_gid(const char *s) if (!s) return 0; - + errno = 0; rv = strtol(s, &endptr, 10); @@ -698,6 +698,8 @@ get_gid(const char *s) static void parse_args(int argc, char **argv) { + int config_changed = 0; + int socket_changed = 0; int c; bird_name = get_bird_name(argv[0], "bird"); @@ -716,6 +718,7 @@ parse_args(int argc, char **argv) { case 'c': config_name = optarg; + config_changed = 1; break; case 'd': debug_flag |= 1; @@ -729,6 +732,7 @@ parse_args(int argc, char **argv) break; case 's': path_control_socket = optarg; + socket_changed = 1; break; case 'P': pid_file = optarg; @@ -742,6 +746,12 @@ parse_args(int argc, char **argv) case 'f': run_in_foreground = 1; break; + case 'l': + if (!config_changed) + config_name = xbasename(config_name); + if (!socket_changed) + path_control_socket = xbasename(path_control_socket); + break; case 'R': graceful_restart_recovery(); break; |