1 /* $OpenBSD$ */
2
3 /*
4 * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <netinet/tcp.h>
22 #include <errno.h>
23 #include <string.h>
24
25 #include "bgpd.h"
26 #include "session.h"
27 #include "log.h"
28
29 int
pfkey_read(int sd,struct sadb_msg * h)30 pfkey_read(int sd, struct sadb_msg *h)
31 {
32 log_warnx("pfkey read disabled");
33 return (-1);
34 }
35
36 int
pfkey_establish(struct peer * p)37 pfkey_establish(struct peer *p)
38 {
39 if (!p->auth.method)
40 return (0);
41 else
42 return (-1);
43 }
44
45 int
pfkey_remove(struct peer * p)46 pfkey_remove(struct peer *p)
47 {
48 if (!p->auth.established)
49 return (0);
50 else
51 return (-1);
52 }
53
54 int
pfkey_init(void)55 pfkey_init(void)
56 {
57 log_warnx("PF_KEY not available, disabling ipsec");
58 return (-1);
59 }
60
61 int
tcp_md5_check(int fd,struct peer * p)62 tcp_md5_check(int fd, struct peer *p)
63 {
64 /*
65 * No need to do the check on Linux.
66 * Only two options get us here:
67 * - the session has no md5 and the SYN had no md5 option
68 * - the session has md5 and the SYN had a valid md5 hash
69 */
70 return (0);
71 }
72
73 /*
74 * Add the TCP MD5SUM key to the kernel to enable TCP MD5SUM.
75 */
76 static int
install_tcp_md5(int fd,struct bgpd_addr * addr,char * key,u_int8_t key_len)77 install_tcp_md5(int fd, struct bgpd_addr *addr, char *key, u_int8_t key_len)
78 {
79 struct tcp_md5sig md5;
80 struct sockaddr *sa;
81 socklen_t sa_len;
82
83 if (key_len > TCP_MD5SIG_MAXKEYLEN) {
84 /* not be possible unless TCP_MD5_KEY_LEN changes */
85 errno = EINVAL;
86 return -1;
87 }
88
89 memset(&md5, 0, sizeof(md5));
90 if (key_len != 0) {
91 md5.tcpm_keylen = key_len;
92 memcpy(&md5.tcpm_key, key, md5.tcpm_keylen);
93 }
94
95 sa = addr2sa(addr, 0, &sa_len);
96 memcpy(&md5.tcpm_addr, sa, sa_len);
97
98 if (setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, &md5, sizeof(md5)) == -1) {
99 /* ignore removals that fail because addr is not present */
100 if (errno == ENOENT && key_len == 0)
101 return 0;
102 return -1;
103 }
104 return 0;
105 }
106
107 int
tcp_md5_set(int fd,struct peer * p)108 tcp_md5_set(int fd, struct peer *p)
109 {
110
111 if (p->conf.auth.method == AUTH_MD5SIG) {
112 if (install_tcp_md5(fd, &p->conf.remote_addr,
113 p->conf.auth.md5key, p->conf.auth.md5key_len) == -1) {
114 log_peer_warn(&p->conf, "setsockopt md5sig");
115 return -1;
116 }
117 }
118 return 0;
119 }
120
121 static int
listener_match_peer(struct listen_addr * la,struct peer * p)122 listener_match_peer(struct listen_addr *la, struct peer *p)
123 {
124 struct sockaddr *sa, *la_sa;
125 socklen_t sa_len;
126
127 la_sa = (struct sockaddr *)&la->sa;
128
129 /* first check remote_addr to be in same address family as socket */
130 if (aid2af(p->conf.remote_addr.aid) != la_sa->sa_family)
131 return 0;
132
133 switch (p->conf.remote_addr.aid) {
134 case AID_INET:
135 sa = addr2sa(&p->conf.local_addr_v4, BGP_PORT, &sa_len);
136 case AID_INET6:
137 sa = addr2sa(&p->conf.local_addr_v6, BGP_PORT, &sa_len);
138 default:
139 return 0;
140 }
141 if (sa == NULL)
142 /* undefined bind address will match any listener */
143 return 1;
144
145 if (sa_len == la->sa_len &&
146 memcmp(&sa->sa_data, &la_sa->sa_data, sa_len - 2) == 0)
147 return 1;
148 return 0;
149 }
150
151 int
tcp_md5_prep_listener(struct listen_addr * la,struct peer_head * peers)152 tcp_md5_prep_listener(struct listen_addr *la, struct peer_head *peers)
153 {
154 struct peer *p;
155
156 RB_FOREACH(p, peer_head, peers) {
157 if (p->conf.auth.method == AUTH_MD5SIG) {
158 if (listener_match_peer(la, p) == 0)
159 continue;
160
161 if (install_tcp_md5(la->fd, &p->conf.remote_addr,
162 p->conf.auth.md5key,
163 p->conf.auth.md5key_len) == -1) {
164 log_peer_warn(&p->conf,
165 "setsockopt md5sig on listening socket");
166 return -1;
167 }
168 }
169 }
170 return 0;
171 }
172
173 void
tcp_md5_add_listener(struct bgpd_config * conf,struct peer * p)174 tcp_md5_add_listener(struct bgpd_config *conf, struct peer *p)
175 {
176 struct listen_addr *la;
177
178 TAILQ_FOREACH(la, conf->listen_addrs, entry) {
179 if (listener_match_peer(la, p) == 0)
180 continue;
181
182 if (install_tcp_md5(la->fd, &p->conf.remote_addr,
183 p->conf.auth.md5key, p->conf.auth.md5key_len) == -1)
184 log_peer_warn(&p->conf,
185 "failed deletion of md5sig on listening socket");
186 }
187 }
188
189 void
tcp_md5_del_listener(struct bgpd_config * conf,struct peer * p)190 tcp_md5_del_listener(struct bgpd_config *conf, struct peer *p)
191 {
192 struct listen_addr *la;
193
194 TAILQ_FOREACH(la, conf->listen_addrs, entry) {
195 if (listener_match_peer(la, p) == 0)
196 continue;
197
198 if (install_tcp_md5(la->fd, &p->conf.remote_addr,
199 NULL, 0) == -1)
200 log_peer_warn(&p->conf,
201 "failed deletion of md5sig on listening socket");
202 }
203 }
204