1 /*
2  * Copyright (C) 2013-2018 Nikos Mavrogiannopoulos
3  * Copyright (C) 2015-2016 Red Hat, Inc.
4  *
5  * This file is part of ocserv.
6  *
7  * ocserv is free software: you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * ocserv is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <config.h>
22 
23 #include <gnutls/gnutls.h>
24 #include <gnutls/crypto.h>
25 #include <gnutls/x509.h>
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/uio.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <limits.h>
37 
38 #include <sys/ioctl.h>
39 #include <sys/socket.h>
40 #include <net/if.h>
41 
42 #include <vpn.h>
43 #include <worker.h>
44 #include <tlslib.h>
45 
46 #ifdef HAVE_SIGALTSTACK
47 # include <signal.h>
48 # include <sys/mman.h>
49 #endif
50 
51 /* recv from the new file descriptor and make sure we have a valid packet */
recv_from_new_fd(struct worker_st * ws,struct dtls_st * dtls,int fd,UdpFdMsg ** tmsg)52 static unsigned recv_from_new_fd(struct worker_st * ws, struct dtls_st *dtls, int fd, UdpFdMsg **tmsg)
53 {
54 	int saved_fd, ret;
55 	UdpFdMsg *saved_tmsg;
56 
57 	/* don't bother with anything if we are on uninitialized state */
58 	if (dtls->dtls_session == NULL || dtls->udp_state != UP_ACTIVE)
59 		return 1;
60 
61 	saved_fd = dtls->dtls_tptr.fd;
62 	saved_tmsg = dtls->dtls_tptr.msg;
63 
64 	dtls->dtls_tptr.msg = *tmsg;
65 	dtls->dtls_tptr.fd = fd;
66 
67 	ret = gnutls_record_recv(dtls->dtls_session, ws->buffer, ws->buffer_size);
68 	/* we receive GNUTLS_E_AGAIN in case the packet was discarded */
69 	if (ret > 0) {
70 		ret = 1;
71 		goto revert;
72 	}
73 
74 	ret = 0;
75  revert:
76  	*tmsg = dtls->dtls_tptr.msg;
77  	dtls->dtls_tptr.fd = saved_fd;
78  	dtls->dtls_tptr.msg = saved_tmsg;
79  	return ret;
80 }
81 
handle_commands_from_main(struct worker_st * ws)82 int handle_commands_from_main(struct worker_st *ws)
83 {
84 	uint8_t cmd;
85 	size_t length;
86 	UdpFdMsg *tmsg = NULL;
87 	int ret;
88 	int fd = -1;
89 	struct dtls_st * dtls = NULL;
90 	/*int cmd_data_len;*/
91 
92 	memset(&ws->buffer, 0, sizeof(ws->buffer));
93 
94 	ret = recv_msg_data(ws->cmd_fd, &cmd, ws->buffer, sizeof(ws->buffer), &fd);
95 	if (ret < 0) {
96 		oclog(ws, LOG_DEBUG, "cannot obtain data from command socket");
97 		exit_worker_reason(ws, REASON_SERVER_DISCONNECT);
98 	}
99 
100 	if (ret == 0) {
101 		oclog(ws, LOG_ERR, "parent terminated");
102 		return ERR_NO_CMD_FD;
103 	}
104 
105 	length = ret;
106 
107 	oclog(ws, LOG_DEBUG, "worker received message %s of %u bytes\n", cmd_request_to_str(cmd), (unsigned)length);
108 
109 	/*cmd_data_len = ret - 1;*/
110 
111 	switch(cmd) {
112 		case CMD_TERMINATE:
113 			exit_worker_reason(ws, REASON_SERVER_DISCONNECT);
114 		case CMD_UDP_FD: {
115 			unsigned has_hello = 1;
116 
117 			if (DTLS_ACTIVE(ws)->udp_state != UP_WAIT_FD) {
118 				oclog(ws, LOG_DEBUG, "received another a UDP fd!");
119 			}
120 
121 			tmsg = udp_fd_msg__unpack(NULL, length, ws->buffer);
122 			if (tmsg) {
123 				has_hello = tmsg->hello;
124 			}
125 
126 			if (fd == -1) {
127 				oclog(ws, LOG_ERR, "received UDP fd message of wrong type");
128 
129 				if (tmsg)
130 					udp_fd_msg__free_unpacked(tmsg, NULL);
131 
132 				if (DTLS_ACTIVE(ws)->udp_state == UP_WAIT_FD)
133 					DTLS_ACTIVE(ws)->udp_state = UP_DISABLED;
134 				return -1;
135 			}
136 
137 			set_non_block(fd);
138 			if (has_hello == 0) {
139 				/* check if the first packet received is a valid one -
140 				 * if not discard the new fd */
141 				if (!recv_from_new_fd(ws, DTLS_ACTIVE(ws), fd, &tmsg)) {
142 					oclog(ws, LOG_INFO, "received UDP fd message but its session has invalid data!");
143 					if (tmsg)
144 						udp_fd_msg__free_unpacked(tmsg, NULL);
145 					close(fd);
146 					return 0;
147 				}
148 				dtls = DTLS_ACTIVE(ws);
149 			} else { /* received client hello */
150 				dtls = DTLS_INACTIVE(ws);
151 				dtls->udp_state = UP_SETUP;
152 				oclog(ws, LOG_DEBUG, "Starting DTLS session %d", ws->dtls_active_session ^ 1);
153 			}
154 
155 			if (dtls->dtls_tptr.fd != -1)
156 				close(dtls->dtls_tptr.fd);
157 			if (dtls->dtls_tptr.msg != NULL)
158 				udp_fd_msg__free_unpacked(dtls->dtls_tptr.msg, NULL);
159 
160 			dtls->dtls_tptr.msg = tmsg;
161 			dtls->dtls_tptr.fd = fd;
162 
163 			if (WSCONFIG(ws)->try_mtu == 0)
164 				set_mtu_disc(fd, ws->proto, 0);
165 
166 			oclog(ws, LOG_DEBUG, "received new UDP fd and connected to peer");
167 			ws->udp_recv_time = time(0);
168 
169 			return 0;
170 
171 			}
172 			break;
173 		default:
174 			oclog(ws, LOG_ERR, "unknown CMD 0x%x", (unsigned)cmd);
175 			exit_worker_reason(ws, REASON_ERROR);
176 	}
177 
178 	return 0;
179 
180 }
181 
182 /* Completes the VPN device information.
183  *
184  * Returns 0 on success.
185  */
complete_vpn_info(worker_st * ws,struct vpn_st * vinfo)186 int complete_vpn_info(worker_st * ws, struct vpn_st *vinfo)
187 {
188 	int ret, fd;
189 	struct ifreq ifr;
190 
191 	if (vinfo->ipv4 == NULL && vinfo->ipv6 == NULL) {
192 		return -1;
193 	}
194 
195 	if (WSCONFIG(ws)->default_mtu != 0) {
196 		vinfo->mtu = WSCONFIG(ws)->default_mtu;
197 	} else {
198 		fd = socket(AF_INET, SOCK_STREAM, 0);
199 		if (fd == -1)
200 			return -1;
201 
202 		memset(&ifr, 0, sizeof(ifr));
203 		ifr.ifr_addr.sa_family = AF_INET;
204 		snprintf(ifr.ifr_name, IFNAMSIZ, "%s", vinfo->name);
205 		ret = ioctl(fd, SIOCGIFMTU, (caddr_t) & ifr);
206 		if (ret < 0) {
207 			oclog(ws, LOG_INFO,
208 			      "cannot obtain MTU for %s. Assuming 1500",
209 			      vinfo->name);
210 			vinfo->mtu = 1500;
211 		} else {
212 			vinfo->mtu = ifr.ifr_mtu;
213 		}
214 		close(fd);
215 	}
216 
217 	return 0;
218 }
219 
ocsigaltstack(struct worker_st * ws)220 void ocsigaltstack(struct worker_st *ws)
221 {
222 #if defined(HAVE_SIGALTSTACK) && defined(HAVE_POSIX_MEMALIGN)
223 	stack_t ss;
224 	int e;
225 
226 	/* setup the stack for signal handlers */
227 	if (posix_memalign((void**)&ss.ss_sp, getpagesize(), SIGSTKSZ) != 0) {
228 		oclog(ws, LOG_ERR,
229 		      "could not allocate memory for signal stack");
230 		exit(1);
231 	}
232 	if (mprotect(ss.ss_sp, SIGSTKSZ, PROT_READ|PROT_WRITE) == -1) {
233 		e = errno;
234 		oclog(ws, LOG_ERR, "mprotect: %s\n", strerror(e));
235 		exit(1);
236 	}
237 	ss.ss_size = SIGSTKSZ;
238 	ss.ss_flags = 0;
239 	if (sigaltstack(&ss, NULL) == -1) {
240 		e = errno;
241 		oclog(ws, LOG_ERR, "sigaltstack: %s\n", strerror(e));
242 		exit(1);
243 	}
244 #endif
245 }
246