diff options
author | Markus Friedl <markus@cvs.openbsd.org> | 2004-01-27 14:09:37 +0000 |
---|---|---|
committer | Markus Friedl <markus@cvs.openbsd.org> | 2004-01-27 14:09:37 +0000 |
commit | 942f9a50d9183eaf295c97e8c25f8d6caba08fdf (patch) | |
tree | e383fd39eb289395fee5f6aab15ba58ceb79ae12 /usr.sbin | |
parent | e93dcf434b921ea06bc97f772c7c97677d59cd6e (diff) |
use SADB_GETSPI/UPDATE for setting tcpmd5 keys; ok henning
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/bgpd/bgpd.h | 4 | ||||
-rw-r--r-- | usr.sbin/bgpd/config.c | 4 | ||||
-rw-r--r-- | usr.sbin/bgpd/pfkey.c | 273 |
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); } |