1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
|
/*
* 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 "sysdep/unix/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, uint slen, sockaddr *dst, uint dlen, const 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 = slen;
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 = dlen;
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, int pxlen, struct iface *ifa, const char *passwd)
{
sockaddr src, dst;
sockaddr_fill(&src, s->af, local, ifa, 0);
sockaddr_fill(&dst, s->af, remote, ifa, 0);
uint maxlen = (s->af == AF_INET) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH;
uint slen = maxlen;
uint dlen = (pxlen < 0) ? maxlen : pxlen;
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, slen, &dst, dlen, passwd, SADB_ADD) < 0) ||
(setkey_md5(&dst, dlen, &src, slen, passwd, SADB_ADD) < 0))
ERR_MSG("Cannot add TCP-MD5 password into the IPsec SA/SP database");
}
else
{
if ((setkey_md5(&src, slen, &dst, dlen, NULL, SADB_DELETE) < 0) ||
(setkey_md5(&dst, dlen, &src, slen, NULL, SADB_DELETE) < 0))
ERR_MSG("Cannot delete TCP-MD5 password from the IPsec SA/SP database");
}
return 0;
}
|