summaryrefslogtreecommitdiff
path: root/sysdep
diff options
context:
space:
mode:
Diffstat (limited to 'sysdep')
-rw-r--r--sysdep/autoconf.h.in1
-rw-r--r--sysdep/bsd/setkey.h170
-rw-r--r--sysdep/bsd/sysio.h28
-rw-r--r--sysdep/config.h2
-rw-r--r--sysdep/linux/netlink.c14
-rw-r--r--sysdep/linux/sysio.h6
-rw-r--r--sysdep/unix/io.c26
-rw-r--r--sysdep/unix/log.c1
-rw-r--r--sysdep/unix/main.c16
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;