File: | src/usr.sbin/npppd/npppd/../pptp/pptpd.c |
Warning: | line 639, column 5 Value stored to 'reason' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: pptpd.c,v 1.33 2021/03/29 03:54:40 yasuoka Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2009 Internet Initiative Japan Inc. |
5 | * All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | * SUCH DAMAGE. |
27 | */ |
28 | /* $Id: pptpd.c,v 1.33 2021/03/29 03:54:40 yasuoka Exp $ */ |
29 | |
30 | /**@file |
31 | * This file provides a implementation of PPTP daemon. Currently it |
32 | * provides functions for PAC (PPTP Access Concentrator) only. |
33 | * $Id: pptpd.c,v 1.33 2021/03/29 03:54:40 yasuoka Exp $ |
34 | */ |
35 | #include <sys/types.h> |
36 | #include <sys/socket.h> |
37 | #include <sys/sysctl.h> |
38 | #include <net/if.h> |
39 | #include <netinet/in.h> |
40 | #include <netinet/ip.h> |
41 | #include <netinet/ip_gre.h> |
42 | #include <arpa/inet.h> |
43 | #include <netdb.h> |
44 | #include <stdio.h> |
45 | #include <stdarg.h> |
46 | #include <signal.h> |
47 | #include <syslog.h> |
48 | #include <fcntl.h> |
49 | #include <unistd.h> |
50 | #include <stdlib.h> |
51 | #include <errno(*__errno()).h> |
52 | #include <string.h> |
53 | #include <event.h> |
54 | |
55 | #ifdef USE_LIBSOCKUTIL |
56 | #include <seil/sockfromto.h> |
57 | #endif |
58 | |
59 | #include "net_utils.h" |
60 | #include "bytebuf.h" |
61 | #include "debugutil.h" |
62 | #include "hash.h" |
63 | #include "slist.h" |
64 | #include "addr_range.h" |
65 | |
66 | #include "pptp.h" |
67 | #include "pptp_local.h" |
68 | #include "privsep.h" |
69 | #include "accept.h" |
70 | |
71 | #define MINIMUM(a, b)(((a) < (b)) ? (a) : (b)) (((a) < (b)) ? (a) : (b)) |
72 | |
73 | static int pptpd_seqno = 0; |
74 | |
75 | #ifdef PPTPD_DEBUG |
76 | #define PPTPD_ASSERT(x) ASSERT(x)((void)0); |
77 | #define PPTPD_DBG(x) pptpd_log x |
78 | #else |
79 | #define PPTPD_ASSERT(x) |
80 | #define PPTPD_DBG(x) |
81 | #endif |
82 | |
83 | static void pptpd_log (pptpd *, int, const char *, ...) __printflike(3,4)__attribute__((__format__ (__printf__, 3, 4))); |
84 | static void pptpd_close_gre (pptpd *); |
85 | static void pptpd_close_1723 (pptpd *); |
86 | static void pptpd_io_event (int, short, void *); |
87 | static void pptpd_gre_io_event (int, short, void *); |
88 | static void pptpd_gre_input (pptpd_listener *, struct sockaddr *, u_char *, int); |
89 | static void pptp_ctrl_start_by_pptpd (pptpd *, int, int, struct sockaddr *); |
90 | static int pptp_call_cmp (const void *, const void *); |
91 | static uint32_t pptp_call_hash (const void *, int); |
92 | static void pptp_gre_header_string (struct pptp_gre_header *, char *, int); |
93 | |
94 | #define PPTPD_SHUFFLE_MARK-1 -1 |
95 | |
96 | /* initialize pptp daemon */ |
97 | int |
98 | pptpd_init(pptpd *_this) |
99 | { |
100 | int i, m; |
101 | uint16_t call0, call[UINT16_MAX0xffff - 1]; |
102 | |
103 | int mib[] = { CTL_NET4, PF_INET2, IPPROTO_GRE47, GRECTL_ALLOW1 }; |
104 | int value; |
105 | size_t size; |
106 | size = sizeof(value); |
107 | |
108 | if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL((void *)0), 0) == 0) { |
109 | if(value == 0) { |
110 | pptpd_log(_this, LOG_WARNING4, "GRE protocol not allowed"); |
111 | } |
112 | } |
113 | |
114 | memset(_this, 0, sizeof(pptpd)); |
115 | _this->id = pptpd_seqno++; |
116 | |
117 | slist_init(&_this->ctrl_list); |
118 | slist_init(&_this->call_free_list); |
119 | |
120 | /* randomize call id */ |
121 | for (i = 0; i < countof(call)(sizeof(call) / sizeof((call)[0])) ; i++) |
122 | call[i] = i + 1; |
123 | for (i = countof(call)(sizeof(call) / sizeof((call)[0])); i > 1; i--) { |
124 | m = arc4random_uniform(i); |
125 | call0 = call[m]; |
126 | call[m] = call[i - 1]; |
127 | call[i - 1] = call0; |
128 | } |
129 | |
130 | for (i = 0; i < MINIMUM(PPTP_MAX_CALL, countof(call))(((8192) < ((sizeof(call) / sizeof((call)[0])))) ? (8192) : ((sizeof(call) / sizeof((call)[0])))); i++) |
131 | slist_add(&_this->call_free_list, (void *)(uintptr_t)call[i]); |
132 | slist_add(&_this->call_free_list, (void *)PPTPD_SHUFFLE_MARK-1); |
133 | |
134 | if (_this->call_id_map == NULL((void *)0)) |
135 | _this->call_id_map = hash_create(pptp_call_cmp, pptp_call_hash, |
136 | 0); |
137 | |
138 | return 0; |
139 | } |
140 | |
141 | /* add a listener to pptpd daemon context */ |
142 | int |
143 | pptpd_add_listener(pptpd *_this, int idx, struct pptp_conf *conf, |
144 | struct sockaddr *addr) |
145 | { |
146 | int inaddr_any; |
147 | pptpd_listener *plistener, *plstn; |
148 | |
149 | plistener = NULL((void *)0); |
150 | if (idx == 0 && slist_length(&_this->listener) > 0) { |
151 | slist_itr_first(&_this->listener); |
152 | while (slist_itr_has_next(&_this->listener)) { |
153 | slist_itr_next(&_this->listener); |
154 | plstn = slist_itr_remove(&_this->listener); |
155 | PPTPD_ASSERT(plstn != NULL); |
156 | PPTPD_ASSERT(plstn->sock == -1); |
157 | PPTPD_ASSERT(plstn->sock_gre == -1); |
158 | free(plstn); |
159 | } |
160 | } |
161 | PPTPD_ASSERT(slist_length(&_this->listener) == idx); |
162 | if (slist_length(&_this->listener) != idx) { |
163 | pptpd_log(_this, LOG_ERR3, |
164 | "Invalid argument error on %s(): idx must be %d but %d", |
165 | __func__, slist_length(&_this->listener), idx); |
166 | goto fail; |
167 | } |
168 | if ((plistener = calloc(1, sizeof(pptpd_listener))) == NULL((void *)0)) { |
169 | pptpd_log(_this, LOG_ERR3, "calloc() failed in %s: %m", |
170 | __func__); |
171 | goto fail; |
172 | } |
173 | |
174 | PPTPD_ASSERT(sizeof(plistener->bind_sin) >= addr->sa_len); |
175 | memcpy(&plistener->bind_sin, addr, addr->sa_len); |
176 | memcpy(&plistener->bind_sin_gre, addr, addr->sa_len); |
177 | |
178 | if (plistener->bind_sin.sin_port == 0) |
179 | plistener->bind_sin.sin_port = htons(PPTPD_DEFAULT_TCP_PORT)(__uint16_t)(__builtin_constant_p(1723) ? (__uint16_t)(((__uint16_t )(1723) & 0xffU) << 8 | ((__uint16_t)(1723) & 0xff00U ) >> 8) : __swap16md(1723)); |
180 | |
181 | /* When a raw socket binds both of an INADDR_ANY and specific IP |
182 | * address sockets, packets will be received by those sockets |
183 | * simultaneously. To avoid this duplicate receives, not |
184 | * permit such kind of configuration */ |
185 | inaddr_any = 0; |
186 | slist_itr_first(&_this->listener); |
187 | while (slist_itr_has_next(&_this->listener)) { |
188 | plstn = slist_itr_next(&_this->listener); |
189 | if (plstn->bind_sin_gre.sin_addr.s_addr == INADDR_ANY((u_int32_t)(0x00000000))) |
190 | inaddr_any++; |
191 | } |
192 | if (plistener->bind_sin_gre.sin_addr.s_addr == INADDR_ANY((u_int32_t)(0x00000000))) |
193 | inaddr_any++; |
194 | if (inaddr_any > 0 && idx > 0) { |
195 | log_printf(LOG_ERR3, "configuration error at pptpd.listener_in: " |
196 | "combination 0.0.0.0 and other address is not allowed."); |
197 | goto fail; |
198 | } |
199 | |
200 | plistener->bind_sin_gre.sin_port = 0; |
201 | plistener->sock = -1; |
202 | plistener->sock_gre = -1; |
203 | plistener->self = _this; |
204 | plistener->index = idx; |
205 | plistener->conf = conf; |
206 | strlcpy(plistener->tun_name, conf->name, sizeof(plistener->tun_name)); |
207 | |
208 | if (slist_add(&_this->listener, plistener) == NULL((void *)0)) { |
209 | pptpd_log(_this, LOG_ERR3, "slist_add() failed in %s: %m", |
210 | __func__); |
211 | goto fail; |
212 | } |
213 | return 0; |
214 | fail: |
215 | free(plistener); |
216 | return 1; |
217 | } |
218 | |
219 | void |
220 | pptpd_uninit(pptpd *_this) |
221 | { |
222 | pptpd_listener *plstn; |
223 | |
224 | slist_fini(&_this->ctrl_list); |
225 | slist_fini(&_this->call_free_list); |
226 | |
227 | slist_itr_first(&_this->listener); |
228 | while (slist_itr_has_next(&_this->listener)) { |
229 | plstn = slist_itr_next(&_this->listener); |
230 | PPTPD_ASSERT(plstn != NULL); |
231 | PPTPD_ASSERT(plstn->sock == -1); |
232 | PPTPD_ASSERT(plstn->sock_gre == -1); |
233 | free(plstn); |
234 | } |
235 | slist_fini(&_this->listener); |
236 | if (_this->call_id_map != NULL((void *)0)) |
237 | hash_free(_this->call_id_map); |
238 | _this->call_id_map = NULL((void *)0); |
239 | } |
240 | |
241 | #define CALL_ID_KEY(call_id, listener_idx)((void *)((uintptr_t)(call_id) | (listener_idx) << 16)) \ |
242 | ((void *)((uintptr_t)(call_id) | (listener_idx) << 16)) |
243 | #define CALL_KEY(call)((void *)((uintptr_t)((call)->id) | ((call)->ctrl->listener_index ) << 16)) \ |
244 | CALL_ID_KEY((call)->id, (call)->ctrl->listener_index)((void *)((uintptr_t)((call)->id) | ((call)->ctrl->listener_index ) << 16)) |
245 | int |
246 | pptpd_assign_call(pptpd *_this, pptp_call *call) |
247 | { |
248 | int shuffle_cnt = 0; |
249 | u_int call_id; |
250 | |
251 | shuffle_cnt = 0; |
252 | slist_itr_first(&_this->call_free_list); |
253 | while (slist_length(&_this->call_free_list) > 1 && |
254 | slist_itr_has_next(&_this->call_free_list)) { |
255 | call_id = (uintptr_t)slist_itr_next(&_this->call_free_list); |
256 | if (call_id == 0) |
257 | break; |
258 | slist_itr_remove(&_this->call_free_list); |
259 | if (call_id == PPTPD_SHUFFLE_MARK-1) { |
260 | if (shuffle_cnt++ > 0) |
261 | break; |
262 | slist_shuffle(&_this->call_free_list); |
263 | slist_add(&_this->call_free_list, |
264 | (void *)PPTPD_SHUFFLE_MARK-1); |
265 | slist_itr_first(&_this->call_free_list); |
266 | continue; |
267 | } |
268 | call->id = call_id; |
269 | hash_insert(_this->call_id_map, CALL_KEY(call)((void *)((uintptr_t)((call)->id) | ((call)->ctrl->listener_index ) << 16)), call); |
270 | |
271 | return 0; |
272 | } |
273 | errno(*__errno()) = EBUSY16; |
274 | pptpd_log(_this, LOG_ERR3, "call request reached limit=%d", |
275 | PPTP_MAX_CALL8192); |
276 | return -1; |
277 | } |
278 | |
279 | void |
280 | pptpd_release_call(pptpd *_this, pptp_call *call) |
281 | { |
282 | if (call->id != 0) |
283 | slist_add(&_this->call_free_list, (void *)(uintptr_t)call->id); |
284 | hash_delete(_this->call_id_map, CALL_KEY(call)((void *)((uintptr_t)((call)->id) | ((call)->ctrl->listener_index ) << 16)), 0); |
285 | call->id = 0; |
286 | } |
287 | |
288 | static int |
289 | pptpd_listener_start(pptpd_listener *_this) |
290 | { |
291 | int sock, ival, sock_gre; |
292 | struct sockaddr_in bind_sin, bind_sin_gre; |
293 | int wildcardbinding; |
294 | |
295 | wildcardbinding = |
296 | (_this->bind_sin.sin_addr.s_addr == INADDR_ANY((u_int32_t)(0x00000000)))? 1 : 0; |
297 | sock = -1; |
298 | sock_gre = -1; |
299 | memcpy(&bind_sin, &_this->bind_sin, sizeof(bind_sin)); |
300 | memcpy(&bind_sin_gre, &_this->bind_sin_gre, sizeof(bind_sin_gre)); |
301 | |
302 | if ((sock = socket(AF_INET2, SOCK_STREAM1 | SOCK_NONBLOCK0x4000, IPPROTO_TCP6)) |
303 | < 0) { |
304 | pptpd_log(_this->self, LOG_ERR3, "socket() failed at %s(): %m", |
305 | __func__); |
306 | goto fail; |
307 | } |
308 | ival = 1; |
309 | if(setsockopt(sock, SOL_SOCKET0xffff, SO_REUSEPORT0x0200, &ival, sizeof(ival)) < 0){ |
310 | pptpd_log(_this->self, LOG_WARNING4, |
311 | "setsockopt(SO_REUSEPORT) failed at %s(): %m", __func__); |
312 | } |
313 | #if defined(IP_STRICT_RCVIF) && defined(USE_STRICT_RCVIF) |
314 | ival = 1; |
315 | if (setsockopt(sock, IPPROTO_IP0, IP_STRICT_RCVIF, &ival, sizeof(ival)) |
316 | != 0) |
317 | pptpd_log(_this->self, LOG_WARNING4, |
318 | "%s(): setsockopt(IP_STRICT_RCVIF) failed: %m", __func__); |
319 | #endif |
320 | if (bind(sock, (struct sockaddr *)&_this->bind_sin, |
321 | _this->bind_sin.sin_len) != 0) { |
322 | pptpd_log(_this->self, LOG_ERR3, |
323 | "bind(%s:%u) failed at %s(): %m", |
324 | inet_ntoa(_this->bind_sin.sin_addr), |
325 | ntohs(_this->bind_sin.sin_port)(__uint16_t)(__builtin_constant_p(_this->bind_sin.sin_port ) ? (__uint16_t)(((__uint16_t)(_this->bind_sin.sin_port) & 0xffU) << 8 | ((__uint16_t)(_this->bind_sin.sin_port ) & 0xff00U) >> 8) : __swap16md(_this->bind_sin. sin_port)), __func__); |
326 | goto fail; |
327 | } |
328 | if (listen(sock, PPTP_BACKLOG32) != 0) { |
329 | pptpd_log(_this->self, LOG_ERR3, |
330 | "listen(%s:%u) failed at %s(): %m", |
331 | inet_ntoa(_this->bind_sin.sin_addr), |
332 | ntohs(_this->bind_sin.sin_port)(__uint16_t)(__builtin_constant_p(_this->bind_sin.sin_port ) ? (__uint16_t)(((__uint16_t)(_this->bind_sin.sin_port) & 0xffU) << 8 | ((__uint16_t)(_this->bind_sin.sin_port ) & 0xff00U) >> 8) : __swap16md(_this->bind_sin. sin_port)), __func__); |
333 | goto fail; |
334 | } |
335 | pptpd_log(_this->self, LOG_INFO6, "Listening %s:%u/tcp (PPTP PAC) [%s]", |
336 | inet_ntoa(_this->bind_sin.sin_addr), |
337 | ntohs(_this->bind_sin.sin_port)(__uint16_t)(__builtin_constant_p(_this->bind_sin.sin_port ) ? (__uint16_t)(((__uint16_t)(_this->bind_sin.sin_port) & 0xffU) << 8 | ((__uint16_t)(_this->bind_sin.sin_port ) & 0xff00U) >> 8) : __swap16md(_this->bind_sin. sin_port)), _this->tun_name); |
338 | |
339 | /* GRE */ |
340 | bind_sin_gre.sin_port = 0; |
341 | if ((sock_gre = priv_socket(AF_INET2, SOCK_RAW3, IPPROTO_GRE47)) < 0) { |
342 | pptpd_log(_this->self, LOG_ERR3, "socket() failed at %s(): %m", |
343 | __func__); |
344 | goto fail; |
345 | } |
346 | #if defined(IP_STRICT_RCVIF) && defined(USE_STRICT_RCVIF) |
347 | ival = 1; |
348 | if (setsockopt(sock_gre, IPPROTO_IP0, IP_STRICT_RCVIF, &ival, |
349 | sizeof(ival)) != 0) |
350 | pptpd_log(_this->self, LOG_WARNING4, |
351 | "%s(): setsockopt(IP_STRICT_RCVIF) failed: %m", __func__); |
352 | #endif |
353 | #ifdef IP_PIPEX34 |
354 | ival = 1; |
355 | if (setsockopt(sock_gre, IPPROTO_IP0, IP_PIPEX34, &ival, sizeof(ival)) |
356 | != 0) |
357 | pptpd_log(_this->self, LOG_WARNING4, |
358 | "%s(): setsockopt(IP_PIPEX) failed: %m", __func__); |
359 | #endif |
360 | if ((ival = fcntl(sock_gre, F_GETFL3)) < 0) { |
361 | pptpd_log(_this->self, LOG_ERR3, |
362 | "fcntl(F_GET_FL) failed at %s(): %m", __func__); |
363 | goto fail; |
364 | } else if (fcntl(sock_gre, F_SETFL4, ival | O_NONBLOCK0x0004) < 0) { |
365 | pptpd_log(_this->self, LOG_ERR3, |
366 | "fcntl(F_SET_FL) failed at %s(): %m", __func__); |
367 | goto fail; |
368 | } |
369 | if (bind(sock_gre, (struct sockaddr *)&bind_sin_gre, |
370 | bind_sin_gre.sin_len) != 0) { |
371 | pptpd_log(_this->self, LOG_ERR3, |
372 | "bind(%s:%u) failed at %s(): %m", |
373 | inet_ntoa(bind_sin_gre.sin_addr), |
374 | ntohs(bind_sin_gre.sin_port)(__uint16_t)(__builtin_constant_p(bind_sin_gre.sin_port) ? (__uint16_t )(((__uint16_t)(bind_sin_gre.sin_port) & 0xffU) << 8 | ((__uint16_t)(bind_sin_gre.sin_port) & 0xff00U) >> 8) : __swap16md(bind_sin_gre.sin_port)), __func__); |
375 | goto fail; |
376 | } |
377 | if (wildcardbinding) { |
378 | #ifdef USE_LIBSOCKUTIL |
379 | if (setsockoptfromto(sock) != 0) { |
380 | pptpd_log(_this->self, LOG_ERR3, |
381 | "setsockoptfromto() failed in %s(): %m", __func__); |
382 | goto fail; |
383 | } |
384 | #else |
385 | /* nothing to do */ |
386 | #endif |
387 | } |
388 | pptpd_log(_this->self, LOG_INFO6, "Listening %s:gre (PPTP PAC)", |
389 | inet_ntoa(bind_sin_gre.sin_addr)); |
390 | |
391 | _this->sock = sock; |
392 | _this->sock_gre = sock_gre; |
393 | |
394 | if (accept_add(_this->sock, pptpd_io_event, _this) != 0) { |
395 | pptpd_log(_this->self, LOG_ERR3, |
396 | "accept_add() failed in %s(): %m", __func__); |
397 | goto fail; |
398 | } |
399 | |
400 | event_set(&_this->ev_sock_gre, _this->sock_gre, EV_READ0x02 | EV_PERSIST0x10, |
401 | pptpd_gre_io_event, _this); |
402 | event_add(&_this->ev_sock_gre, NULL((void *)0)); |
403 | |
404 | return 0; |
405 | fail: |
406 | if (sock >= 0) |
407 | close(sock); |
408 | if (sock_gre >= 0) |
409 | close(sock_gre); |
410 | |
411 | _this->sock = -1; |
412 | _this->sock_gre = -1; |
413 | |
414 | return 1; |
415 | } |
416 | |
417 | int |
418 | pptpd_start(pptpd *_this) |
419 | { |
420 | int rval = 0; |
421 | pptpd_listener *plistener; |
422 | |
423 | slist_itr_first(&_this->listener); |
424 | while (slist_itr_has_next(&_this->listener)) { |
425 | plistener = slist_itr_next(&_this->listener); |
426 | PPTPD_ASSERT(plistener != NULL); |
427 | rval |= pptpd_listener_start(plistener); |
428 | } |
429 | if (rval == 0) |
430 | _this->state = PPTPD_STATE_RUNNING1; |
431 | |
432 | return rval; |
433 | } |
434 | |
435 | static void |
436 | pptpd_listener_close_gre(pptpd_listener *_this) |
437 | { |
438 | if (_this->sock_gre >= 0) { |
439 | event_del(&_this->ev_sock_gre); |
440 | close(_this->sock_gre); |
441 | pptpd_log(_this->self, LOG_INFO6, "Shutdown %s/gre", |
442 | inet_ntoa(_this->bind_sin_gre.sin_addr)); |
443 | } |
444 | _this->sock_gre = -1; |
445 | } |
446 | |
447 | static void |
448 | pptpd_close_gre(pptpd *_this) |
449 | { |
450 | pptpd_listener *plistener; |
451 | |
452 | slist_itr_first(&_this->listener); |
453 | while (slist_itr_has_next(&_this->listener)) { |
454 | plistener = slist_itr_next(&_this->listener); |
455 | pptpd_listener_close_gre(plistener); |
456 | } |
457 | } |
458 | |
459 | static void |
460 | pptpd_listener_close_1723(pptpd_listener *_this) |
461 | { |
462 | if (_this->sock >= 0) { |
463 | accept_del(_this->sock); |
464 | close(_this->sock); |
465 | pptpd_log(_this->self, LOG_INFO6, "Shutdown %s:%u/tcp", |
466 | inet_ntoa(_this->bind_sin.sin_addr), |
467 | ntohs(_this->bind_sin.sin_port)(__uint16_t)(__builtin_constant_p(_this->bind_sin.sin_port ) ? (__uint16_t)(((__uint16_t)(_this->bind_sin.sin_port) & 0xffU) << 8 | ((__uint16_t)(_this->bind_sin.sin_port ) & 0xff00U) >> 8) : __swap16md(_this->bind_sin. sin_port))); |
468 | } |
469 | _this->sock = -1; |
470 | } |
471 | |
472 | static void |
473 | pptpd_close_1723(pptpd *_this) |
474 | { |
475 | pptpd_listener *plistener; |
476 | |
477 | slist_itr_first(&_this->listener); |
478 | while (slist_itr_has_next(&_this->listener)) { |
479 | plistener = slist_itr_next(&_this->listener); |
480 | pptpd_listener_close_1723(plistener); |
481 | } |
482 | } |
483 | |
484 | void |
485 | pptpd_stop_immediatly(pptpd *_this) |
486 | { |
487 | pptp_ctrl *ctrl; |
488 | |
489 | if (event_initialized(&_this->ev_timer)((&_this->ev_timer)->ev_flags & 0x80)) |
490 | evtimer_del(&_this->ev_timer)event_del(&_this->ev_timer); |
491 | if (_this->state != PPTPD_STATE_STOPPED3) { |
492 | /* lock, to avoid multiple call from pptp_ctrl_stop() */ |
493 | _this->state = PPTPD_STATE_STOPPED3; |
494 | |
495 | pptpd_close_1723(_this); |
496 | for (slist_itr_first(&_this->ctrl_list); |
497 | (ctrl = slist_itr_next(&_this->ctrl_list)) != NULL((void *)0);) { |
498 | pptp_ctrl_stop(ctrl, 0); |
499 | } |
500 | pptpd_close_gre(_this); |
501 | slist_fini(&_this->ctrl_list); |
502 | slist_fini(&_this->call_free_list); |
503 | PPTPD_DBG((_this, LOG_DEBUG, "Stopped")); |
504 | } else { |
505 | PPTPD_DBG((_this, LOG_DEBUG, "(Already) Stopped")); |
506 | } |
507 | } |
508 | |
509 | static void |
510 | pptpd_stop_timeout(int fd, short event, void *ctx) |
511 | { |
512 | pptpd *_this; |
513 | |
514 | _this = ctx; |
515 | pptpd_stop_immediatly(_this); |
516 | } |
517 | |
518 | void |
519 | pptpd_stop(pptpd *_this) |
520 | { |
521 | int nctrl; |
522 | pptp_ctrl *ctrl; |
523 | struct timeval tv; |
524 | |
525 | if (event_initialized(&_this->ev_timer)((&_this->ev_timer)->ev_flags & 0x80)) |
526 | evtimer_del(&_this->ev_timer)event_del(&_this->ev_timer); |
527 | pptpd_close_1723(_this); |
528 | |
529 | /* XXX: use common procedure with l2tpd_stop */ |
530 | |
531 | if (pptpd_is_stopped(_this)(((_this)->state != 2 && (_this)->state != 1)? 1 : 0)) |
532 | return; |
533 | if (pptpd_is_shutting_down(_this)(((_this)->state == 2)? 1 : 0)) { |
534 | pptpd_stop_immediatly(_this); |
535 | return; |
536 | } |
537 | _this->state = PPTPD_STATE_SHUTTING_DOWN2; |
538 | nctrl = 0; |
539 | for (slist_itr_first(&_this->ctrl_list); |
540 | (ctrl = slist_itr_next(&_this->ctrl_list)) != NULL((void *)0);) { |
541 | pptp_ctrl_stop(ctrl, PPTP_CDN_RESULT_ADMIN_SHUTDOWN3); |
542 | nctrl++; |
543 | } |
544 | if (nctrl > 0) { |
545 | tv.tv_sec = PPTPD_SHUTDOWN_TIMEOUT5; |
546 | tv.tv_usec = 0; |
547 | |
548 | evtimer_set(&_this->ev_timer, pptpd_stop_timeout, _this)event_set(&_this->ev_timer, -1, 0, pptpd_stop_timeout, _this); |
549 | evtimer_add(&_this->ev_timer, &tv)event_add(&_this->ev_timer, &tv); |
550 | |
551 | return; |
552 | } |
553 | pptpd_stop_immediatly(_this); |
554 | } |
555 | |
556 | /* |
557 | * PPTP Configuration |
558 | */ |
559 | int |
560 | pptpd_reload(pptpd *_this, struct pptp_confs *pptp_conf) |
561 | { |
562 | int i; |
563 | struct pptp_conf *conf; |
564 | pptpd_listener *listener; |
565 | struct pptp_listen_addr *addr; |
566 | |
567 | if (slist_length(&_this->listener) > 0) { |
568 | /* |
569 | * TODO: add / remove / restart listener. |
570 | */ |
571 | slist_itr_first(&_this->listener); |
572 | while (slist_itr_has_next(&_this->listener)) { |
573 | listener = slist_itr_next(&_this->listener); |
574 | TAILQ_FOREACH(conf, pptp_conf, entry)for((conf) = ((pptp_conf)->tqh_first); (conf) != ((void *) 0); (conf) = ((conf)->entry.tqe_next)) { |
575 | if (strcmp(listener->tun_name, |
576 | conf->name) == 0) { |
577 | listener->conf = conf; |
578 | break; |
579 | } |
580 | } |
581 | } |
582 | |
583 | return 0; |
584 | } |
585 | |
586 | i = 0; |
587 | TAILQ_FOREACH(conf, pptp_conf, entry)for((conf) = ((pptp_conf)->tqh_first); (conf) != ((void *) 0); (conf) = ((conf)->entry.tqe_next)) { |
588 | TAILQ_FOREACH(addr, &conf->listen, entry)for((addr) = ((&conf->listen)->tqh_first); (addr) != ((void *)0); (addr) = ((addr)->entry.tqe_next)) |
589 | pptpd_add_listener(_this, i++, conf, |
590 | (struct sockaddr *)&addr->addr); |
591 | } |
592 | if (pptpd_start(_this) != 0) |
593 | return -1; |
594 | |
595 | return 0; |
596 | } |
597 | |
598 | /* |
599 | * I/O functions |
600 | */ |
601 | /* I/O event handler of 1723/tcp */ |
602 | static void |
603 | pptpd_io_event(int fd, short evmask, void *ctx) |
604 | { |
605 | int newsock; |
606 | const char *reason; |
607 | socklen_t peerlen; |
608 | struct sockaddr_storage peer; |
609 | pptpd *_this; |
610 | pptpd_listener *listener; |
611 | |
612 | listener = ctx; |
613 | PPTPD_ASSERT(listener != NULL); |
614 | _this = listener->self; |
615 | PPTPD_ASSERT(_this != NULL); |
616 | |
617 | if ((evmask & EV_READ0x02) != 0) { |
618 | for (;;) { /* accept till EAGAIN occurred */ |
619 | peerlen = sizeof(peer); |
620 | if ((newsock = accept(listener->sock, |
621 | (struct sockaddr *)&peer, &peerlen)) < 0) { |
622 | if (errno(*__errno()) != EAGAIN35 && errno(*__errno()) == EINTR4 && |
623 | errno(*__errno()) != ECONNABORTED53) { |
624 | if (errno(*__errno()) == EMFILE24 || errno(*__errno()) == ENFILE23) |
625 | accept_pause(); |
626 | pptpd_log(_this, LOG_ERR3, |
627 | "accept() failed at %s(): %m", |
628 | __func__); |
629 | } |
630 | break; |
631 | } |
632 | /* check peer */ |
633 | switch (peer.ss_family) { |
634 | case AF_INET2: |
635 | pptp_ctrl_start_by_pptpd(_this, newsock, |
636 | listener->index, (struct sockaddr *)&peer); |
637 | break; |
638 | default: |
639 | reason = "address family is not supported."; |
Value stored to 'reason' is never read | |
640 | break; |
641 | } |
642 | } |
643 | } |
644 | } |
645 | |
646 | /* I/O event handler of GRE */ |
647 | static void |
648 | pptpd_gre_io_event(int fd, short evmask, void *ctx) |
649 | { |
650 | int sz; |
651 | u_char pkt[65535]; |
652 | socklen_t peerlen; |
653 | struct sockaddr_storage peer; |
654 | pptpd *_this; |
655 | pptpd_listener *listener; |
656 | |
657 | listener = ctx; |
658 | PPTPD_ASSERT(listener != NULL); |
659 | _this = listener->self; |
660 | PPTPD_ASSERT(_this != NULL); |
661 | |
662 | if (evmask & EV_READ0x02) { |
663 | for (;;) { |
664 | /* read till bloked */ |
665 | peerlen = sizeof(peer); |
666 | if ((sz = recvfrom(listener->sock_gre, pkt, sizeof(pkt), |
667 | 0, (struct sockaddr *)&peer, &peerlen)) == -1) { |
668 | if (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4) |
669 | break; |
670 | pptpd_log(_this, LOG_INFO6, |
671 | "read(GRE) failed: %m"); |
672 | pptpd_stop(_this); |
673 | return; |
674 | } |
675 | pptpd_gre_input(listener, (struct sockaddr *)&peer, pkt, |
676 | sz); |
677 | } |
678 | } |
679 | } |
680 | |
681 | /* receive GRE then route to pptp_call */ |
682 | static void |
683 | pptpd_gre_input(pptpd_listener *listener, struct sockaddr *peer, u_char *pkt, |
684 | int lpkt) |
685 | { |
686 | int hlen, input_flags; |
687 | uint32_t seq, ack, call_id; |
688 | struct ip *iphdr; |
689 | struct pptp_gre_header *grehdr; |
690 | char hbuf0[NI_MAXHOST256], logbuf[512]; |
691 | const char *reason; |
692 | pptp_call *call; |
693 | hash_link *hl; |
694 | pptpd *_this; |
695 | |
696 | seq = 0; |
697 | ack = 0; |
698 | input_flags = 0; |
699 | reason = "No error"; |
700 | _this = listener->self; |
701 | |
702 | PPTPD_ASSERT(peer->sa_family == AF_INET); |
703 | |
704 | strlcpy(hbuf0, "<unknown>", sizeof(hbuf0)); |
705 | if (getnameinfo(peer, peer->sa_len, hbuf0, sizeof(hbuf0), NULL((void *)0), 0, |
706 | NI_NUMERICHOST1 | NI_NUMERICSERV2) != 0) { |
707 | pptpd_log(_this, LOG_ERR3, |
708 | "getnameinfo() failed at %s(): %m", __func__); |
709 | goto fail; |
710 | } |
711 | if (listener->conf->data_in_pktdump != 0) { |
712 | pptpd_log(_this, LOG_DEBUG7, "PPTP Data input packet dump"); |
713 | show_hd(debug_get_debugfp(), pkt, lpkt); |
714 | } |
715 | if (peer->sa_family != AF_INET2) { |
716 | pptpd_log(_this, LOG_ERR3, |
717 | "Received malformed GRE packet: address family is not " |
718 | "supported: peer=%s af=%d", hbuf0, peer->sa_family); |
719 | goto fail; |
720 | } |
721 | |
722 | if (lpkt < sizeof(struct ip)) { |
723 | pptpd_log(_this, LOG_ERR3, |
724 | "Received a short length packet length=%d, from %s", lpkt, |
725 | hbuf0); |
726 | goto fail; |
727 | } |
728 | iphdr = (struct ip *)pkt; |
729 | |
730 | iphdr->ip_len = ntohs(iphdr->ip_len)(__uint16_t)(__builtin_constant_p(iphdr->ip_len) ? (__uint16_t )(((__uint16_t)(iphdr->ip_len) & 0xffU) << 8 | ( (__uint16_t)(iphdr->ip_len) & 0xff00U) >> 8) : __swap16md (iphdr->ip_len)); |
731 | hlen = iphdr->ip_hl * 4; |
732 | |
733 | if (iphdr->ip_len > lpkt || |
734 | iphdr->ip_len < hlen + sizeof(struct pptp_gre_header)) { |
735 | pptpd_log(_this, LOG_ERR3, |
736 | "Received a broken packet: ip_hl=%d iplen=%d lpkt=%d", hlen, |
737 | iphdr->ip_len, lpkt); |
738 | show_hd(debug_get_debugfp(), pkt, lpkt); |
739 | goto fail; |
740 | } |
741 | pkt += hlen; |
742 | lpkt -= hlen; |
743 | grehdr = (struct pptp_gre_header *)pkt; |
744 | pkt += sizeof(struct pptp_gre_header); |
745 | lpkt -= sizeof(struct pptp_gre_header); |
746 | |
747 | grehdr->protocol_type = htons(grehdr->protocol_type)(__uint16_t)(__builtin_constant_p(grehdr->protocol_type) ? (__uint16_t)(((__uint16_t)(grehdr->protocol_type) & 0xffU ) << 8 | ((__uint16_t)(grehdr->protocol_type) & 0xff00U ) >> 8) : __swap16md(grehdr->protocol_type)); |
748 | grehdr->payload_length = htons(grehdr->payload_length)(__uint16_t)(__builtin_constant_p(grehdr->payload_length) ? (__uint16_t)(((__uint16_t)(grehdr->payload_length) & 0xffU ) << 8 | ((__uint16_t)(grehdr->payload_length) & 0xff00U) >> 8) : __swap16md(grehdr->payload_length) ); |
749 | grehdr->call_id = htons(grehdr->call_id)(__uint16_t)(__builtin_constant_p(grehdr->call_id) ? (__uint16_t )(((__uint16_t)(grehdr->call_id) & 0xffU) << 8 | ((__uint16_t)(grehdr->call_id) & 0xff00U) >> 8) : __swap16md(grehdr->call_id)); |
750 | |
751 | if (!(grehdr->protocol_type == PPTP_GRE_PROTOCOL_TYPE0x880b && |
752 | grehdr->C == 0 && grehdr->R == 0 && grehdr->K != 0 && |
753 | grehdr->recur == 0 && grehdr->s == 0 && grehdr->flags == 0 && |
754 | grehdr->ver == PPTP_GRE_VERSION1)) { |
755 | reason = "GRE header is broken"; |
756 | goto bad_gre; |
757 | } |
758 | if (grehdr->S != 0) { |
759 | if (lpkt < 2) { |
760 | reason = "No enough space for seq number"; |
761 | goto bad_gre; |
762 | } |
763 | input_flags |= PPTP_GRE_PKT_SEQ_PRESENT0x0001; |
764 | seq = ntohl(*(uint32_t *)pkt)(__uint32_t)(__builtin_constant_p(*(uint32_t *)pkt) ? (__uint32_t )(((__uint32_t)(*(uint32_t *)pkt) & 0xff) << 24 | ( (__uint32_t)(*(uint32_t *)pkt) & 0xff00) << 8 | ((__uint32_t )(*(uint32_t *)pkt) & 0xff0000) >> 8 | ((__uint32_t )(*(uint32_t *)pkt) & 0xff000000) >> 24) : __swap32md (*(uint32_t *)pkt)); |
765 | pkt += 4; |
766 | lpkt -= 4; |
767 | } |
768 | |
769 | if (grehdr->A != 0) { |
770 | if (lpkt < 2) { |
771 | reason = "No enough space for ack number"; |
772 | goto bad_gre; |
773 | } |
774 | input_flags |= PPTP_GRE_PKT_ACK_PRESENT0x0002; |
775 | ack = ntohl(*(uint32_t *)pkt)(__uint32_t)(__builtin_constant_p(*(uint32_t *)pkt) ? (__uint32_t )(((__uint32_t)(*(uint32_t *)pkt) & 0xff) << 24 | ( (__uint32_t)(*(uint32_t *)pkt) & 0xff00) << 8 | ((__uint32_t )(*(uint32_t *)pkt) & 0xff0000) >> 8 | ((__uint32_t )(*(uint32_t *)pkt) & 0xff000000) >> 24) : __swap32md (*(uint32_t *)pkt)); |
776 | pkt += 4; |
777 | lpkt -= 4; |
778 | } |
779 | |
780 | if (grehdr->payload_length > lpkt) { |
781 | reason = "'Payload Length' is mismatch from actual length"; |
782 | goto bad_gre; |
783 | } |
784 | |
785 | |
786 | /* route to pptp_call */ |
787 | call_id = grehdr->call_id; |
788 | |
789 | hl = hash_lookup(_this->call_id_map, CALL_ID_KEY(call_id, listener->index)((void *)((uintptr_t)(call_id) | (listener->index) << 16))); |
790 | if (hl == NULL((void *)0)) { |
791 | reason = "Received GRE packet has unknown call_id"; |
792 | goto bad_gre; |
793 | } |
794 | call = hl->item; |
795 | pptp_call_gre_input(call, seq, ack, input_flags, pkt, lpkt); |
796 | |
797 | return; |
798 | bad_gre: |
799 | pptp_gre_header_string(grehdr, logbuf, sizeof(logbuf)); |
800 | pptpd_log(_this, LOG_INFO6, |
801 | "Received malformed GRE packet: %s: peer=%s sock=%s %s seq=%u: " |
802 | "ack=%u ifidx=%d", reason, hbuf0, inet_ntoa(iphdr->ip_dst), logbuf, |
803 | seq, ack, listener->index); |
804 | fail: |
805 | return; |
806 | } |
807 | |
808 | /* start PPTP control, when new connection is established */ |
809 | static void |
810 | pptp_ctrl_start_by_pptpd(pptpd *_this, int sock, int listener_index, |
811 | struct sockaddr *peer) |
812 | { |
813 | pptp_ctrl *ctrl; |
814 | socklen_t sslen; |
815 | |
816 | ctrl = NULL((void *)0); |
817 | if ((ctrl = pptp_ctrl_create()) == NULL((void *)0)) |
818 | goto fail; |
819 | if (pptp_ctrl_init(ctrl) != 0) |
820 | goto fail; |
821 | |
822 | memset(&ctrl->peer, 0, sizeof(ctrl->peer)); |
823 | memcpy(&ctrl->peer, peer, peer->sa_len); |
824 | ctrl->pptpd = _this; |
825 | ctrl->sock = sock; |
826 | ctrl->listener_index = listener_index; |
827 | |
828 | sslen = sizeof(ctrl->our); |
829 | if (getsockname(ctrl->sock, (struct sockaddr *)&ctrl->our, |
830 | &sslen) != 0) { |
831 | pptpd_log(_this, LOG_WARNING4, |
832 | "getsockname() failed at %s(): %m", __func__); |
833 | goto fail; |
834 | } |
835 | |
836 | if (PPTP_CTRL_CONF(ctrl)((pptpd_listener *)slist_get(&(ctrl)->pptpd->listener , (ctrl)->listener_index))->conf->echo_interval != 0) |
837 | ctrl->echo_interval = PPTP_CTRL_CONF(ctrl)((pptpd_listener *)slist_get(&(ctrl)->pptpd->listener , (ctrl)->listener_index))->conf->echo_interval; |
838 | if (PPTP_CTRL_CONF(ctrl)((pptpd_listener *)slist_get(&(ctrl)->pptpd->listener , (ctrl)->listener_index))->conf->echo_timeout != 0) |
839 | ctrl->echo_timeout = PPTP_CTRL_CONF(ctrl)((pptpd_listener *)slist_get(&(ctrl)->pptpd->listener , (ctrl)->listener_index))->conf->echo_timeout; |
840 | |
841 | if (pptp_ctrl_start(ctrl) != 0) |
842 | goto fail; |
843 | |
844 | slist_add(&_this->ctrl_list, ctrl); |
845 | |
846 | return; |
847 | fail: |
848 | close(sock); |
849 | pptp_ctrl_destroy(ctrl); |
850 | return; |
851 | } |
852 | |
853 | void |
854 | pptpd_ctrl_finished_notify(pptpd *_this, pptp_ctrl *ctrl) |
855 | { |
856 | pptp_ctrl *ctrl1; |
857 | int i, nctrl; |
858 | |
859 | PPTPD_ASSERT(_this != NULL); |
860 | PPTPD_ASSERT(ctrl != NULL); |
861 | |
862 | accept_unpause(); |
863 | |
864 | nctrl = 0; |
865 | for (i = 0; i < slist_length(&_this->ctrl_list); i++) { |
866 | ctrl1 = slist_get(&_this->ctrl_list, i); |
867 | if (ctrl1 == ctrl) { |
868 | slist_remove(&_this->ctrl_list, i); |
869 | break; |
870 | } |
871 | } |
872 | pptp_ctrl_destroy(ctrl); |
873 | |
874 | PPTPD_DBG((_this, LOG_DEBUG, "Remains %d ctrls", nctrl)); |
875 | if (pptpd_is_shutting_down(_this)(((_this)->state == 2)? 1 : 0) && nctrl == 0) |
876 | pptpd_stop_immediatly(_this); |
877 | } |
878 | |
879 | /* |
880 | * utility functions |
881 | */ |
882 | |
883 | /* logging with the this PPTP instance */ |
884 | static void |
885 | pptpd_log(pptpd *_this, int prio, const char *fmt, ...) |
886 | { |
887 | char logbuf[BUFSIZ1024]; |
888 | va_list ap; |
889 | |
890 | PPTPD_ASSERT(_this != NULL); |
891 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
892 | #ifdef PPTPD_MULTIPLE |
893 | snprintf(logbuf, sizeof(logbuf), "pptpd id=%u %s", _this->id, fmt); |
894 | #else |
895 | snprintf(logbuf, sizeof(logbuf), "pptpd %s", fmt); |
896 | #endif |
897 | vlog_printf(prio, logbuf, ap); |
898 | va_end(ap)__builtin_va_end(ap); |
899 | } |
900 | |
901 | static int |
902 | pptp_call_cmp(const void *a0, const void *b0) |
903 | { |
904 | return ((intptr_t)a0 - (intptr_t)b0); |
905 | } |
906 | |
907 | static uint32_t |
908 | pptp_call_hash(const void *ctx, int size) |
909 | { |
910 | return (uintptr_t)ctx % size; |
911 | } |
912 | |
913 | /* convert GRE packet header to strings */ |
914 | static void |
915 | pptp_gre_header_string(struct pptp_gre_header *grehdr, char *buf, int lbuf) |
916 | { |
917 | snprintf(buf, lbuf, |
918 | "[%s%s%s%s%s%s] ver=%d " |
919 | "protocol_type=%04x payload_length=%d call_id=%d", |
920 | (grehdr->C != 0)? "C" : "", (grehdr->R != 0)? "R" : "", |
921 | (grehdr->K != 0)? "K" : "", (grehdr->S != 0)? "S" : "", |
922 | (grehdr->s != 0)? "s" : "", (grehdr->A != 0)? "A" : "", grehdr->ver, |
923 | grehdr->protocol_type, grehdr->payload_length, grehdr->call_id); |
924 | } |