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