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