summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2004-01-27 14:09:37 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2004-01-27 14:09:37 +0000
commit942f9a50d9183eaf295c97e8c25f8d6caba08fdf (patch)
treee383fd39eb289395fee5f6aab15ba58ceb79ae12 /usr.sbin
parente93dcf434b921ea06bc97f772c7c97677d59cd6e (diff)
use SADB_GETSPI/UPDATE for setting tcpmd5 keys; ok henning
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/bgpd/bgpd.h4
-rw-r--r--usr.sbin/bgpd/config.c4
-rw-r--r--usr.sbin/bgpd/pfkey.c273
3 files changed, 187 insertions, 94 deletions
diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h
index 787d897790d..7e85cffff5c 100644
--- a/usr.sbin/bgpd/bgpd.h
+++ b/usr.sbin/bgpd/bgpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpd.h,v 1.80 2004/01/26 14:42:47 henning Exp $ */
+/* $OpenBSD: bgpd.h,v 1.81 2004/01/27 14:09:36 markus Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -325,6 +325,6 @@ void control_cleanup(void);
int control_imsg_relay(struct imsg *);
/* pfkey.c */
-int pfkey_signature(struct sockaddr *, struct sockaddr *, char *);
+int pfkey_setkey(struct sockaddr *, struct sockaddr *, char *);
#endif /* __BGPD_H__ */
diff --git a/usr.sbin/bgpd/config.c b/usr.sbin/bgpd/config.c
index e88b20eed1e..e2eb48ddb0d 100644
--- a/usr.sbin/bgpd/config.c
+++ b/usr.sbin/bgpd/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.20 2004/01/26 14:42:47 henning Exp $ */
+/* $OpenBSD: config.c,v 1.21 2004/01/27 14:09:36 markus Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -56,7 +56,7 @@ merge_config(struct bgpd_config *xconf, struct bgpd_config *conf,
if (!p->conf.id)
p->conf.id = get_id(p);
if (p->conf.tcp_sign_key[0] &&
- pfkey_signature((struct sockaddr *)&p->conf.local_addr,
+ pfkey_setkey((struct sockaddr *)&p->conf.local_addr,
(struct sockaddr *)&p->conf.remote_addr,
p->conf.tcp_sign_key) == -1)
return (1);
diff --git a/usr.sbin/bgpd/pfkey.c b/usr.sbin/bgpd/pfkey.c
index c8b15d98d5f..86bee599b2d 100644
--- a/usr.sbin/bgpd/pfkey.c
+++ b/usr.sbin/bgpd/pfkey.c
@@ -1,7 +1,8 @@
-/* $OpenBSD: pfkey.c,v 1.2 2004/01/26 17:50:53 henning Exp $ */
+/* $OpenBSD: pfkey.c,v 1.3 2004/01/27 14:09:36 markus Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ * Copyright (c) 2003, 2004 Markus Friedl <markus@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -29,65 +30,31 @@
#include "bgpd.h"
-#define ROUNDUP(x) (((x) + sizeof(u_int64_t) - 1) & ~(sizeof(u_int64_t) - 1))
+#define PFKEY2_CHUNK sizeof(u_int64_t)
+#define ROUNDUP(x) (((x) + (PFKEY2_CHUNK - 1)) & ~(PFKEY2_CHUNK - 1))
#define IOV_CNT 8
static u_int32_t sadb_msg_seq = 1;
-int send_sa_msg(struct iovec *, int, int);
+int pfkey_reply(int, u_int32_t *);
+int pfkey_send(int, uint8_t, struct sockaddr *, struct sockaddr *,
+ u_int32_t, char *);
int
-send_sa_msg(struct iovec *iov, int cnt, int len)
-{
- struct sadb_msg sm;
- int sd;
- ssize_t n;
-
- if ((sd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) == -1) {
- if (errno == EPROTONOSUPPORT)
- log_warnx("no kernel support for PF_KEY");
- else
- log_warn("socket");
- return (-1);
- }
-
- if ((n = writev(sd, iov, cnt)) == -1) {
- log_warn("write");
- close(sd);
- return (-1);
- }
-
- if (n != len) {
- log_warn("writev: should=%d has=%d", len, n);
- close(sd);
- return (-1);
- }
-
- if (read(sd, &sm, sizeof(sm)) != sizeof(sm)) {
- log_warn("read");
- close(sd);
- return (-1);
- }
- close(sd);
-
- if (sm.sadb_msg_errno != 0) {
- errno = sm.sadb_msg_errno;
- log_warn("pfkey");
- return (-1);
- }
- return (0);
-}
-
-int
-pfkey_signature(struct sockaddr *src, struct sockaddr *dst, char *key)
+pfkey_send(int sd, uint8_t mtype, struct sockaddr *src, struct sockaddr *dst,
+ u_int32_t spi, char *key)
{
struct sadb_msg smsg;
struct sadb_sa sa;
struct sadb_address sa_src, sa_dst;
struct sadb_key sa_key;
+ struct sadb_spirange sa_spirange;
struct iovec iov[IOV_CNT];
+ ssize_t n;
int klen = 0;
+ int len = 0;
int i;
+ int iov_cnt;
char realkey[TCP_SIGN_KEY_LEN];
char s[3];
struct sockaddr_storage ssrc, sdst;
@@ -126,15 +93,46 @@ pfkey_signature(struct sockaddr *src, struct sockaddr *dst, char *key)
smsg.sadb_msg_seq = sadb_msg_seq++;
smsg.sadb_msg_pid = getpid();
smsg.sadb_msg_len = sizeof(smsg) / 8;
- smsg.sadb_msg_type = SADB_ADD;
+ smsg.sadb_msg_type = mtype;
smsg.sadb_msg_satype = SADB_X_SATYPE_TCPSIGNATURE;
- bzero(&sa, sizeof(sa));
- sa.sadb_sa_exttype = SADB_EXT_SA;
- sa.sadb_sa_len = sizeof(sa) / 8;
- sa.sadb_sa_replay = 0;
- sa.sadb_sa_spi = 0;
- sa.sadb_sa_state = SADB_SASTATE_MATURE;
+ switch (mtype) {
+ case SADB_GETSPI:
+ bzero(&sa_spirange, sizeof(sa_spirange));
+ sa_spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE;
+ sa_spirange.sadb_spirange_len = sizeof(sa_spirange) / 8;
+ sa_spirange.sadb_spirange_min = 0x100;
+ sa_spirange.sadb_spirange_max = 0xffffffff;
+ sa_spirange.sadb_spirange_reserved = 0;
+ break;
+ case SADB_ADD:
+ case SADB_UPDATE:
+ bzero(&sa, sizeof(sa));
+ sa.sadb_sa_exttype = SADB_EXT_SA;
+ sa.sadb_sa_len = sizeof(sa) / 8;
+ sa.sadb_sa_replay = 0;
+ sa.sadb_sa_spi = spi;
+ sa.sadb_sa_state = SADB_SASTATE_MATURE;
+
+ bzero(&sa_key, sizeof(sa_key));
+ klen = strlen(key) / 2;
+ sa_key.sadb_key_exttype = SADB_EXT_KEY_AUTH;
+ sa_key.sadb_key_len = (sizeof(sa_key) +
+ ((klen + 7) / 8) * 8) / 8;
+ sa_key.sadb_key_bits = 8 * klen;
+
+ for (i = 0; i < klen; i++) {
+ s[0] = key[2*i];
+ s[1] = key[2*i + 1];
+ s[2] = 0;
+ if (!isxdigit(s[0]) || !isxdigit(s[1])) {
+ log_warnx("tcpmd5 must be specified in hex");
+ return (-1);
+ }
+ realkey[i] = strtoul(s, NULL, 16);
+ }
+ break;
+ }
bzero(&sa_src, sizeof(sa_src));
sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
@@ -144,52 +142,147 @@ pfkey_signature(struct sockaddr *src, struct sockaddr *dst, char *key)
sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8;
- bzero(&sa_key, sizeof(sa_key));
- klen = strlen(key) / 2;
- sa_key.sadb_key_exttype = SADB_EXT_KEY_AUTH;
- sa_key.sadb_key_len = (sizeof(sa_key) + ((klen + 7) / 8) * 8) / 8;
- sa_key.sadb_key_bits = 8 * klen;
-
- for (i = 0; i < klen; i++) {
- s[0] = key[2*i];
- s[1] = key[2*i + 1];
- s[2] = 0;
- if (!isxdigit(s[0]) || !isxdigit(s[1])) {
- log_warnx("espkey must be specified in hex");
- return (-1);
- }
- realkey[i] = strtoul(s, NULL, 16);
- }
+ iov_cnt = 0;
/* msghdr */
- iov[0].iov_base = &smsg;
- iov[0].iov_len = sizeof(smsg);
+ iov[iov_cnt].iov_base = &smsg;
+ iov[iov_cnt].iov_len = sizeof(smsg);
+ iov_cnt++;
- /* SA hdr */
- iov[1].iov_base = &sa;
- iov[1].iov_len = sizeof(sa);
- smsg.sadb_msg_len += sa.sadb_sa_len;
+ switch (mtype) {
+ case SADB_ADD:
+ case SADB_UPDATE:
+ /* SA hdr */
+ iov[iov_cnt].iov_base = &sa;
+ iov[iov_cnt].iov_len = sizeof(sa);
+ smsg.sadb_msg_len += sa.sadb_sa_len;
+ iov_cnt++;
+ break;
+ case SADB_GETSPI:
+ /* SPI range */
+ iov[iov_cnt].iov_base = &sa_spirange;
+ iov[iov_cnt].iov_len = sizeof(sa_spirange);
+ smsg.sadb_msg_len += sa_spirange.sadb_spirange_len;
+ iov_cnt++;
+ break;
+ }
/* dest addr */
- iov[2].iov_base = &sa_dst;
- iov[2].iov_len = sizeof(sa_dst);
- iov[3].iov_base = &sdst;
- iov[3].iov_len = ROUNDUP(sdst.ss_len);
+ iov[iov_cnt].iov_base = &sa_dst;
+ iov[iov_cnt].iov_len = sizeof(sa_dst);
+ iov_cnt++;
+ iov[iov_cnt].iov_base = &sdst;
+ iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len);
smsg.sadb_msg_len += sa_dst.sadb_address_len;
+ iov_cnt++;
/* src addr */
- iov[4].iov_base = &sa_src;
- iov[4].iov_len = sizeof(sa_src);
- iov[5].iov_base = &ssrc;
- iov[5].iov_len = ROUNDUP(ssrc.ss_len);
+ iov[iov_cnt].iov_base = &sa_src;
+ iov[iov_cnt].iov_len = sizeof(sa_src);
+ iov_cnt++;
+ iov[iov_cnt].iov_base = &ssrc;
+ iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len);
smsg.sadb_msg_len += sa_src.sadb_address_len;
+ iov_cnt++;
- /* auth key */
- iov[6].iov_base = &sa_key;
- iov[6].iov_len = sizeof(sa_key);
- iov[7].iov_base = realkey;
- iov[7].iov_len = ((klen + 7) / 8) * 8;
- smsg.sadb_msg_len += sa_key.sadb_key_len;
+ switch (mtype) {
+ case SADB_ADD:
+ case SADB_UPDATE:
+ /* auth key */
+ iov[iov_cnt].iov_base = &sa_key;
+ iov[iov_cnt].iov_len = sizeof(sa_key);
+ iov_cnt++;
+ iov[iov_cnt].iov_base = realkey;
+ iov[iov_cnt].iov_len = ((klen + 7) / 8) * 8;
+ smsg.sadb_msg_len += sa_key.sadb_key_len;
+ iov_cnt++;
+ break;
+ }
- return (send_sa_msg(iov, IOV_CNT, smsg.sadb_msg_len * 8));
+ len = smsg.sadb_msg_len * 8;
+ if ((n = writev(sd, iov, iov_cnt)) == -1) {
+ log_warn("writev (%d/%d)", iov_cnt, len);
+ return (-1);
+ }
+
+ if (n != len) {
+ log_warn("writev: should=%d has=%d", len, n);
+ return (-1);
+ }
+}
+
+int
+pfkey_reply(int sd, u_int32_t *spip)
+{
+ struct sadb_msg hdr, *msg;
+ struct sadb_ext *ext;
+ struct sadb_sa *sa;
+ u_int8_t *data;
+ ssize_t len;
+
+ if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) {
+ log_warn("pfkey peek");
+ return (-1);
+ }
+ if (hdr.sadb_msg_errno != 0) {
+ errno = hdr.sadb_msg_errno;
+ log_warn("pfkey");
+ return (-1);
+ }
+ if (spip == NULL)
+ return (0);
+ if (hdr.sadb_msg_type != SADB_GETSPI)
+ return (-1);
+ len = hdr.sadb_msg_len * PFKEY2_CHUNK;
+ if ((data = malloc(len)) == NULL) {
+ log_warn("pfkey malloc");
+ return (-1);
+ }
+ if (read(sd, data, len) != len) {
+ log_warn("pfkey read");
+ return (-1);
+ }
+ msg = (struct sadb_msg *)data;
+ for (ext = (struct sadb_ext *)(msg + 1);
+ (size_t)((u_int8_t *)ext - (u_int8_t *)msg) <
+ msg->sadb_msg_len * PFKEY2_CHUNK;
+ ext = (struct sadb_ext *)((u_int8_t *)ext +
+ ext->sadb_ext_len * PFKEY2_CHUNK)) {
+ if (ext->sadb_ext_type == SADB_EXT_SA) {
+ sa = (struct sadb_sa *) ext;
+ *spip = sa->sadb_sa_spi;
+ break;
+ }
+ }
+ memset(data, len, 0);
+ free(data);
+ return (0);
+}
+
+int
+pfkey_setkey(struct sockaddr *src, struct sockaddr *dst, char *key)
+{
+ u_int32_t spi = 0;
+ int sd;
+ int ret = -1;
+
+ if ((sd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) == -1) {
+ if (errno == EPROTONOSUPPORT)
+ log_warnx("no kernel support for PF_KEY");
+ else
+ log_warn("socket");
+ return (-1);
+ }
+ if (pfkey_send(sd, SADB_GETSPI, src, dst, 0, NULL) < 0)
+ goto done;
+ if (pfkey_reply(sd, &spi) < 0)
+ goto done;
+ if (pfkey_send(sd, SADB_UPDATE, src, dst, spi, key) < 0)
+ goto done;
+ if (pfkey_reply(sd, NULL) < 0)
+ goto done;
+ ret = 0;
+done:
+ close(sd);
+ return (ret);
}