Statistics
| Branch: | Revision:

iof-bird / bird-2.0.1 / sysdep / bsd / setkey.h @ 6b3f1a54

History | View | Annotate | Download (4.62 KB)

1
/*
2
 *        BIRD -- Manipulation the IPsec SA/SP database using setkey(8) utility
3
 *
4
 *         (c) 2016 CZ.NIC z.s.p.o.
5
 */
6

    
7
#include <unistd.h>
8
#include <sys/types.h>
9
#include <sys/socket.h>
10
#include <net/pfkeyv2.h>
11
#include <netipsec/ipsec.h>
12

    
13
#include "nest/bird.h"
14
#include "sysdep/unix/unix.h"
15

    
16

    
17
/*
18
 * Open a socket for manage the IPsec SA/SP database entries
19
 */
20
static int
21
setkey_open_socket(void)
22
{
23
  int s = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
24
  if (s < 0)
25
  {
26
    log(L_ERR "SETKEY: socket: %m");
27
    return -1;
28
  }
29

    
30
  return s;
31
}
32

    
33
static int
34
setkey_send(struct sadb_msg *msg, uint len)
35
{
36
  int s = setkey_open_socket();
37
  if (s < 0)
38
    return -1;
39

    
40
  if (msg->sadb_msg_type == SADB_ADD)
41
  {
42
    /* Delete possible current key in the IPsec SA/SP database */
43
    msg->sadb_msg_type = SADB_DELETE;
44
    send(s, msg, len, 0);
45
    msg->sadb_msg_type = SADB_ADD;
46
  }
47

    
48
  if (send(s, msg, len, 0) < 0)
49
  {
50
    log(L_ERR "SETKEY: send: %m");
51
    close(s);
52
    return -1;
53
  }
54

    
55
  close(s);
56
  return 0;
57
}
58

    
59
/*
60
 * Perform setkey(8)-like operation for set the password for TCP MD5 Signature.
61
 * Could be called with SABD_ADD or SADB_DELETE argument. Note that SADB_ADD
62
 * argument is internally processed as a pair of SADB_ADD and SADB_DELETE
63
 * operations to implement replace.
64
 */
65
static int
66
setkey_md5(sockaddr *src, sockaddr *dst, uint pxlen, char *passwd, uint type)
67
{
68
  uint passwd_len = passwd ? strlen(passwd) : 0;
69

    
70
  uint total =
71
    sizeof(struct sadb_msg) +
72
    sizeof(struct sadb_key) + PFKEY_ALIGN8(passwd_len) +
73
    sizeof(struct sadb_sa) +
74
    sizeof(struct sadb_x_sa2) +
75
    sizeof(struct sadb_address) + PFKEY_ALIGN8(src->sa.sa_len) +
76
    sizeof(struct sadb_address) + PFKEY_ALIGN8(dst->sa.sa_len);
77

    
78
  char *buf = alloca(total);
79
  char *pos = buf;
80
  uint len;
81

    
82
  memset(buf, 0, total);
83

    
84
  struct sadb_msg *msg = (void *) pos;
85
  len = sizeof(struct sadb_msg);
86
  msg->sadb_msg_version = PF_KEY_V2;
87
  msg->sadb_msg_type = type;
88
  msg->sadb_msg_satype = SADB_X_SATYPE_TCPSIGNATURE;
89
  msg->sadb_msg_len = 0;        /* Fix it later */
90
  msg->sadb_msg_pid = getpid();
91
  pos += len;
92

    
93
  /* Set authentication algorithm and password */
94
  struct sadb_key *key = (void *) pos;
95
  len = sizeof(struct sadb_key) + PFKEY_ALIGN8(passwd_len);
96
  key->sadb_key_len = PFKEY_UNIT64(len);
97
  key->sadb_key_exttype = SADB_EXT_KEY_AUTH;
98
  key->sadb_key_bits = passwd_len * 8;
99
  memcpy(pos + sizeof(struct sadb_key), passwd, passwd_len);
100
  pos += len;
101

    
102
  struct sadb_sa *sa = (void *) pos;
103
  len = sizeof(struct sadb_sa);
104
  sa->sadb_sa_len = PFKEY_UNIT64(len);
105
  sa->sadb_sa_exttype = SADB_EXT_SA;
106
  sa->sadb_sa_spi = htonl((u32) TCP_SIG_SPI);
107
  sa->sadb_sa_auth = SADB_X_AALG_TCP_MD5;
108
  sa->sadb_sa_encrypt = SADB_EALG_NONE;
109
  sa->sadb_sa_flags = SADB_X_EXT_CYCSEQ;
110
  pos += len;
111

    
112
  struct sadb_x_sa2 *sa2 = (void *) pos;
113
  len = sizeof(struct sadb_x_sa2);
114
  sa2->sadb_x_sa2_len = PFKEY_UNIT64(len);
115
  sa2->sadb_x_sa2_exttype = SADB_X_EXT_SA2;
116
  sa2->sadb_x_sa2_mode = IPSEC_MODE_ANY;
117
  pos += len;
118

    
119
  /* Set source address */
120
  struct sadb_address *saddr = (void *) pos;
121
  len = sizeof(struct sadb_address) + PFKEY_ALIGN8(src->sa.sa_len);
122
  saddr->sadb_address_len = PFKEY_UNIT64(len);
123
  saddr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
124
  saddr->sadb_address_proto = IPSEC_ULPROTO_ANY;
125
  saddr->sadb_address_prefixlen = pxlen;
126
  memcpy(pos + sizeof(struct sadb_address), &src->sa, src->sa.sa_len);
127
  pos += len;
128

    
129
  /* Set destination address */
130
  struct sadb_address *daddr = (void *) pos;
131
  len = sizeof(struct sadb_address) + PFKEY_ALIGN8(dst->sa.sa_len);
132
  daddr->sadb_address_len = PFKEY_UNIT64(len);
133
  daddr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
134
  daddr->sadb_address_proto = IPSEC_ULPROTO_ANY;
135
  daddr->sadb_address_prefixlen = pxlen;
136
  memcpy(pos + sizeof(struct sadb_address), &dst->sa, dst->sa.sa_len);
137
  pos += len;
138

    
139
  len = pos - buf;
140
  msg->sadb_msg_len = PFKEY_UNIT64(len);
141

    
142
  return setkey_send(msg, len);
143
}
144

    
145
/*
146
 * Manipulation with the IPsec SA/SP database
147
 */
148
static int
149
sk_set_md5_in_sasp_db(sock *s, ip_addr local, ip_addr remote, struct iface *ifa, char *passwd)
150
{
151
  sockaddr src, dst;
152
  sockaddr_fill(&src, s->af, local, ifa, 0);
153
  sockaddr_fill(&dst, s->af, remote, ifa, 0);
154

    
155
  uint pxlen = (s->af == AF_INET) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH;
156

    
157
  if (passwd && *passwd)
158
  {
159
    int len = strlen(passwd);
160
    if (len > TCP_KEYLEN_MAX)
161
      ERR_MSG("The password for TCP MD5 Signature is too long");
162

    
163
    if (setkey_md5(&src, &dst, pxlen, passwd, SADB_ADD) < 0)
164
      ERR_MSG("Cannot add TCP-MD5 password into the IPsec SA/SP database");
165
  }
166
  else
167
  {
168
    if (setkey_md5(&src, &dst, pxlen, NULL, SADB_DELETE) < 0)
169
      ERR_MSG("Cannot delete TCP-MD5 password from the IPsec SA/SP database");
170
  }
171
  return 0;
172
}