1 |
|
|
/* $OpenBSD: l2tpd.c,v 1.20 2017/10/06 07:46:44 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 |
|
|
/**@file L2TP(Layer Two Tunneling Protocol "L2TP") / RFC2661 */ |
29 |
|
|
/* $Id: l2tpd.c,v 1.20 2017/10/06 07:46:44 yasuoka Exp $ */ |
30 |
|
|
#include <sys/types.h> |
31 |
|
|
#include <sys/socket.h> |
32 |
|
|
#include <sys/time.h> |
33 |
|
|
#include <netinet/in.h> |
34 |
|
|
#include <netinet/udp.h> |
35 |
|
|
#include <stdlib.h> |
36 |
|
|
#include <arpa/inet.h> |
37 |
|
|
#include <stdio.h> |
38 |
|
|
#include <unistd.h> |
39 |
|
|
#include <netdb.h> |
40 |
|
|
#include <syslog.h> |
41 |
|
|
#include <signal.h> |
42 |
|
|
#include <string.h> |
43 |
|
|
#include <fcntl.h> |
44 |
|
|
#include <errno.h> |
45 |
|
|
#include <stdarg.h> |
46 |
|
|
#include <event.h> |
47 |
|
|
|
48 |
|
|
#ifdef USE_LIBSOCKUTIL |
49 |
|
|
#include <seil/sockfromto.h> |
50 |
|
|
#else |
51 |
|
|
#include "recvfromto.h" |
52 |
|
|
#endif |
53 |
|
|
|
54 |
|
|
#include "bytebuf.h" |
55 |
|
|
#include "hash.h" |
56 |
|
|
#include "slist.h" |
57 |
|
|
#include "debugutil.h" |
58 |
|
|
#include "l2tp.h" |
59 |
|
|
#include "l2tp_subr.h" |
60 |
|
|
#include "l2tp_local.h" |
61 |
|
|
#include "addr_range.h" |
62 |
|
|
#include "net_utils.h" |
63 |
|
|
|
64 |
|
|
#ifdef L2TPD_DEBUG |
65 |
|
|
#define L2TPD_ASSERT(x) ASSERT(x) |
66 |
|
|
#define L2TPD_DBG(x) l2tpd_log x |
67 |
|
|
#else |
68 |
|
|
#define L2TPD_ASSERT(x) |
69 |
|
|
#endif |
70 |
|
|
#define L2TPD_IPSEC_POLICY_IN "in ipsec esp/transport//require" |
71 |
|
|
#define L2TPD_IPSEC_POLICY_OUT "out ipsec esp/transport//require" |
72 |
|
|
|
73 |
|
|
static void l2tpd_io_event (int, short, void *); |
74 |
|
|
static inline int short_cmp (const void *, const void *); |
75 |
|
|
static inline uint32_t short_hash (const void *, int); |
76 |
|
|
|
77 |
|
|
/* sequence # of l2tpd ID */ |
78 |
|
|
static u_int l2tpd_id_seq = 0; |
79 |
|
|
|
80 |
|
|
/* L2TP daemon instance */ |
81 |
|
|
|
82 |
|
|
/** |
83 |
|
|
* initialize L2TP daemon instance |
84 |
|
|
* <p> |
85 |
|
|
* {@link _l2tpd#bind_sin} will return with .sin_family = AF_INET, |
86 |
|
|
* .sin_port = 1701 and .sin_len = "appropriate value" |
87 |
|
|
* </p> |
88 |
|
|
*/ |
89 |
|
|
int |
90 |
|
|
l2tpd_init(l2tpd *_this) |
91 |
|
|
{ |
92 |
|
|
int i, off; |
93 |
|
|
u_int id; |
94 |
|
|
|
95 |
|
|
L2TPD_ASSERT(_this != NULL); |
96 |
|
|
memset(_this, 0, sizeof(l2tpd)); |
97 |
|
|
|
98 |
|
|
slist_init(&_this->listener); |
99 |
|
|
slist_init(&_this->free_session_id_list); |
100 |
|
|
|
101 |
|
|
_this->id = l2tpd_id_seq++; |
102 |
|
|
|
103 |
|
|
if ((_this->ctrl_map = hash_create(short_cmp, short_hash, |
104 |
|
|
L2TPD_TUNNEL_HASH_SIZ)) == NULL) { |
105 |
|
|
log_printf(LOG_ERR, "hash_create() failed in %s(): %m", |
106 |
|
|
__func__); |
107 |
|
|
return 1; |
108 |
|
|
} |
109 |
|
|
|
110 |
|
|
if (slist_add(&_this->free_session_id_list, |
111 |
|
|
(void *)L2TP_SESSION_ID_SHUFFLE_MARK) == NULL) { |
112 |
|
|
l2tpd_log(_this, LOG_ERR, "slist_add() failed on %s(): %m", |
113 |
|
|
__func__); |
114 |
|
|
return 1; |
115 |
|
|
} |
116 |
|
|
off = arc4random() & L2TP_SESSION_ID_MASK; |
117 |
|
|
for (i = 0; i < L2TP_NCALL; i++) { |
118 |
|
|
id = (i + off) & L2TP_SESSION_ID_MASK; |
119 |
|
|
if (id == 0) |
120 |
|
|
id = (off - 1) & L2TP_SESSION_ID_MASK; |
121 |
|
|
if (slist_add(&_this->free_session_id_list, |
122 |
|
|
(void *)(uintptr_t)id) == NULL) { |
123 |
|
|
l2tpd_log(_this, LOG_ERR, |
124 |
|
|
"slist_add() failed on %s(): %m", __func__); |
125 |
|
|
return 1; |
126 |
|
|
} |
127 |
|
|
} |
128 |
|
|
_this->purge_ipsec_sa = 1; |
129 |
|
|
_this->state = L2TPD_STATE_INIT; |
130 |
|
|
|
131 |
|
|
return 0; |
132 |
|
|
} |
133 |
|
|
|
134 |
|
|
/* |
135 |
|
|
* Add a {@link :l2tpd_listener} to the {@link ::l2tpd L2TP daemon} |
136 |
|
|
* @param _this {@link ::l2tpd L2TP daemon} |
137 |
|
|
* @param idx index of the lisnter |
138 |
|
|
* @param tun_name tunnel name (ex. "L2TP") |
139 |
|
|
* @param bindaddr bind address |
140 |
|
|
*/ |
141 |
|
|
int |
142 |
|
|
l2tpd_add_listener(l2tpd *_this, int idx, struct l2tp_conf *conf, |
143 |
|
|
struct sockaddr *addr) |
144 |
|
|
{ |
145 |
|
|
l2tpd_listener *plistener, *plsnr; |
146 |
|
|
|
147 |
|
|
plistener = NULL; |
148 |
|
|
if (idx == 0 && slist_length(&_this->listener) > 0) { |
149 |
|
|
slist_itr_first(&_this->listener); |
150 |
|
|
while (slist_itr_has_next(&_this->listener)) { |
151 |
|
|
slist_itr_next(&_this->listener); |
152 |
|
|
plsnr = slist_itr_remove(&_this->listener); |
153 |
|
|
L2TPD_ASSERT(plsnr != NULL); |
154 |
|
|
L2TPD_ASSERT(plsnr->sock == -1); |
155 |
|
|
free(plsnr); |
156 |
|
|
} |
157 |
|
|
} |
158 |
|
|
L2TPD_ASSERT(slist_length(&_this->listener) == idx); |
159 |
|
|
if (slist_length(&_this->listener) != idx) { |
160 |
|
|
l2tpd_log(_this, LOG_ERR, |
161 |
|
|
"Invalid argument error on %s(): idx must be %d but %d", |
162 |
|
|
__func__, slist_length(&_this->listener), idx); |
163 |
|
|
goto fail; |
164 |
|
|
} |
165 |
|
|
if ((plistener = calloc(1, sizeof(l2tpd_listener))) == NULL) { |
166 |
|
|
l2tpd_log(_this, LOG_ERR, "calloc() failed in %s: %m", |
167 |
|
|
__func__); |
168 |
|
|
goto fail; |
169 |
|
|
} |
170 |
|
|
L2TPD_ASSERT(sizeof(plistener->bind) >= addr->sa_len); |
171 |
|
|
memcpy(&plistener->bind, addr, addr->sa_len); |
172 |
|
|
|
173 |
|
|
if (plistener->bind.sin6.sin6_port == 0) |
174 |
|
|
plistener->bind.sin6.sin6_port = htons(L2TPD_DEFAULT_UDP_PORT); |
175 |
|
|
|
176 |
|
|
plistener->sock = -1; |
177 |
|
|
plistener->self = _this; |
178 |
|
|
plistener->index = idx; |
179 |
|
|
plistener->conf = conf; |
180 |
|
|
strlcpy(plistener->tun_name, conf->name, sizeof(plistener->tun_name)); |
181 |
|
|
|
182 |
|
|
if (slist_add(&_this->listener, plistener) == NULL) { |
183 |
|
|
l2tpd_log(_this, LOG_ERR, "slist_add() failed in %s: %m", |
184 |
|
|
__func__); |
185 |
|
|
goto fail; |
186 |
|
|
} |
187 |
|
|
return 0; |
188 |
|
|
fail: |
189 |
|
|
free(plistener); |
190 |
|
|
return 1; |
191 |
|
|
} |
192 |
|
|
|
193 |
|
|
/* finalize L2TP daemon instance */ |
194 |
|
|
void |
195 |
|
|
l2tpd_uninit(l2tpd *_this) |
196 |
|
|
{ |
197 |
|
|
l2tpd_listener *plsnr; |
198 |
|
|
|
199 |
|
|
L2TPD_ASSERT(_this != NULL); |
200 |
|
|
|
201 |
|
|
slist_fini(&_this->free_session_id_list); |
202 |
|
|
if (_this->ctrl_map != NULL) { |
203 |
|
|
hash_free(_this->ctrl_map); |
204 |
|
|
_this->ctrl_map = NULL; |
205 |
|
|
} |
206 |
|
|
|
207 |
|
|
slist_itr_first(&_this->listener); |
208 |
|
|
while (slist_itr_has_next(&_this->listener)) { |
209 |
|
|
plsnr = slist_itr_next(&_this->listener); |
210 |
|
|
L2TPD_ASSERT(plsnr != NULL); |
211 |
|
|
L2TPD_ASSERT(plsnr->sock == -1); |
212 |
|
|
free(plsnr); |
213 |
|
|
} |
214 |
|
|
slist_fini(&_this->listener); |
215 |
|
|
|
216 |
|
|
event_del(&_this->ev_timeout); /* just in case */ |
217 |
|
|
_this->state = L2TPD_STATE_STOPPED; |
218 |
|
|
} |
219 |
|
|
|
220 |
|
|
/** assign the call to the l2tpd */ |
221 |
|
|
int |
222 |
|
|
l2tpd_assign_call(l2tpd *_this, l2tp_call *call) |
223 |
|
|
{ |
224 |
|
|
int shuffle_cnt; |
225 |
|
|
u_int session_id; |
226 |
|
|
|
227 |
|
|
shuffle_cnt = 0; |
228 |
|
|
do { |
229 |
|
|
session_id = (uintptr_t)slist_remove_first( |
230 |
|
|
&_this->free_session_id_list); |
231 |
|
|
if (session_id != L2TP_SESSION_ID_SHUFFLE_MARK) |
232 |
|
|
break; |
233 |
|
|
L2TPD_ASSERT(shuffle_cnt == 0); |
234 |
|
|
if (shuffle_cnt++ > 0) { |
235 |
|
|
l2tpd_log(_this, LOG_ERR, |
236 |
|
|
"unexpected errror in %s(): free_session_id_list " |
237 |
|
|
"full", __func__); |
238 |
|
|
slist_add(&_this->free_session_id_list, |
239 |
|
|
(void *)L2TP_SESSION_ID_SHUFFLE_MARK); |
240 |
|
|
return 1; |
241 |
|
|
} |
242 |
|
|
slist_shuffle(&_this->free_session_id_list); |
243 |
|
|
slist_add(&_this->free_session_id_list, |
244 |
|
|
(void *)L2TP_SESSION_ID_SHUFFLE_MARK); |
245 |
|
|
} while (1); |
246 |
|
|
call->id = session_id; |
247 |
|
|
|
248 |
|
|
return 0; |
249 |
|
|
} |
250 |
|
|
|
251 |
|
|
/* this function will be called when the call is released */ |
252 |
|
|
void |
253 |
|
|
l2tpd_release_call(l2tpd *_this, l2tp_call *call) |
254 |
|
|
{ |
255 |
|
|
slist_add(&_this->free_session_id_list, (void *)(uintptr_t)call->id); |
256 |
|
|
} |
257 |
|
|
|
258 |
|
|
/* start l2tpd listner */ |
259 |
|
|
static int |
260 |
|
|
l2tpd_listener_start(l2tpd_listener *_this) |
261 |
|
|
{ |
262 |
|
|
l2tpd *_l2tpd; |
263 |
|
|
int af, lvl, opt, sock, ival; |
264 |
|
|
char hbuf[NI_MAXHOST + NI_MAXSERV + 16]; |
265 |
|
|
|
266 |
|
|
_l2tpd = _this->self; |
267 |
|
|
sock = -1; |
268 |
|
|
af = _this->bind.sin6.sin6_family; |
269 |
|
|
lvl = (af == AF_INET)? IPPROTO_IP : IPPROTO_IPV6; |
270 |
|
|
|
271 |
|
|
if (_this->tun_name[0] == '\0') |
272 |
|
|
strlcpy(_this->tun_name, L2TPD_DEFAULT_LAYER2_LABEL, |
273 |
|
|
sizeof(_this->tun_name)); |
274 |
|
|
if ((sock = socket(_this->bind.sin6.sin6_family, |
275 |
|
|
SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP)) < 0) { |
276 |
|
|
l2tpd_log(_l2tpd, LOG_ERR, |
277 |
|
|
"socket() failed in %s(): %m", __func__); |
278 |
|
|
goto fail; |
279 |
|
|
} |
280 |
|
|
#if defined(IP_STRICT_RCVIF) && defined(USE_STRICT_RCVIF) |
281 |
|
|
ival = 1; |
282 |
|
|
if (setsockopt(sock, IPPROTO_IP, IP_STRICT_RCVIF, &ival, sizeof(ival)) |
283 |
|
|
!= 0) |
284 |
|
|
l2tpd_log(_l2tpd, LOG_WARNING, |
285 |
|
|
"%s(): setsockopt(IP_STRICT_RCVIF) failed: %m", __func__); |
286 |
|
|
#endif |
287 |
|
|
ival = 1; |
288 |
|
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &ival, sizeof(ival)) |
289 |
|
|
!= 0) { |
290 |
|
|
l2tpd_log(_l2tpd, LOG_ERR, |
291 |
|
|
"setsockopt(,,SO_REUSEPORT) failed in %s(): %m", __func__); |
292 |
|
|
goto fail; |
293 |
|
|
} |
294 |
|
|
if (bind(sock, (struct sockaddr *)&_this->bind, |
295 |
|
|
_this->bind.sin6.sin6_len) != 0) { |
296 |
|
|
l2tpd_log(_l2tpd, LOG_ERR, "Binding %s/udp: %m", |
297 |
|
|
addrport_tostring((struct sockaddr *)&_this->bind, |
298 |
|
|
_this->bind.sin6.sin6_len, hbuf, sizeof(hbuf))); |
299 |
|
|
goto fail; |
300 |
|
|
} |
301 |
|
|
#ifdef USE_LIBSOCKUTIL |
302 |
|
|
if (setsockoptfromto(sock) != 0) { |
303 |
|
|
l2tpd_log(_l2tpd, LOG_ERR, |
304 |
|
|
"setsockoptfromto() failed in %s(): %m", __func__); |
305 |
|
|
goto fail; |
306 |
|
|
} |
307 |
|
|
#else |
308 |
|
|
opt = (af == AF_INET)? IP_RECVDSTADDR : IPV6_RECVPKTINFO; |
309 |
|
|
ival = 1; |
310 |
|
|
if (setsockopt(sock, lvl, opt, &ival, sizeof(ival)) != 0) { |
311 |
|
|
l2tpd_log(_l2tpd, LOG_ERR, |
312 |
|
|
"setsockopt(,,IP{,V6}_RECVDSTADDR) failed in %s(): %m", |
313 |
|
|
__func__); |
314 |
|
|
goto fail; |
315 |
|
|
} |
316 |
|
|
#endif |
317 |
|
|
#ifdef USE_SA_COOKIE |
318 |
|
|
if (af == AF_INET) { |
319 |
|
|
ival = 1; |
320 |
|
|
if (setsockopt(sock, IPPROTO_IP, IP_IPSECFLOWINFO, &ival, |
321 |
|
|
sizeof(ival)) != 0) { |
322 |
|
|
l2tpd_log(_l2tpd, LOG_ERR, |
323 |
|
|
"setsockopt(,,IP_IPSECFLOWINFO) failed in %s(): %m", |
324 |
|
|
__func__); |
325 |
|
|
goto fail; |
326 |
|
|
} |
327 |
|
|
} |
328 |
|
|
#endif |
329 |
|
|
#ifdef IP_PIPEX |
330 |
|
|
opt = (af == AF_INET)? IP_PIPEX : IPV6_PIPEX; |
331 |
|
|
ival = 1; |
332 |
|
|
if (setsockopt(sock, lvl, opt, &ival, sizeof(ival)) != 0) |
333 |
|
|
l2tpd_log(_l2tpd, LOG_WARNING, |
334 |
|
|
"%s(): setsockopt(IP{,V6}_PIPEX) failed: %m", __func__); |
335 |
|
|
#endif |
336 |
|
|
if (_this->conf->require_ipsec) { |
337 |
|
|
#ifdef IP_IPSEC_POLICY |
338 |
|
|
caddr_t ipsec_policy_in, ipsec_policy_out; |
339 |
|
|
|
340 |
|
|
opt = (af == AF_INET)? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY; |
341 |
|
|
/* |
342 |
|
|
* Note: ipsec_set_policy() will assign the buffer for |
343 |
|
|
* yacc parser stack, however it never free. |
344 |
|
|
* it cause memory leak (-2000byte). |
345 |
|
|
*/ |
346 |
|
|
if ((ipsec_policy_in = ipsec_set_policy(L2TPD_IPSEC_POLICY_IN, |
347 |
|
|
strlen(L2TPD_IPSEC_POLICY_IN))) == NULL) { |
348 |
|
|
l2tpd_log(_l2tpd, LOG_ERR, |
349 |
|
|
"ipsec_set_policy(L2TPD_IPSEC_POLICY_IN) failed " |
350 |
|
|
"at %s(): %s: %m", __func__, ipsec_strerror()); |
351 |
|
|
} else if (setsockopt(sock, lvl, opt, ipsec_policy_in, |
352 |
|
|
ipsec_get_policylen(ipsec_policy_in)) < 0) { |
353 |
|
|
l2tpd_log(_l2tpd, LOG_WARNING, |
354 |
|
|
"setsockopt(,,IP_IPSEC_POLICY(in)) failed " |
355 |
|
|
"in %s(): %m", __func__); |
356 |
|
|
} |
357 |
|
|
if ((ipsec_policy_out = ipsec_set_policy(L2TPD_IPSEC_POLICY_OUT, |
358 |
|
|
strlen(L2TPD_IPSEC_POLICY_OUT))) == NULL) { |
359 |
|
|
l2tpd_log(_l2tpd, LOG_ERR, |
360 |
|
|
"ipsec_set_policy(L2TPD_IPSEC_POLICY_OUT) failed " |
361 |
|
|
"at %s(): %s: %m", __func__, ipsec_strerror()); |
362 |
|
|
} |
363 |
|
|
if (ipsec_policy_out != NULL && |
364 |
|
|
setsockopt(sock, lvl, opt, ipsec_policy_out, |
365 |
|
|
ipsec_get_policylen(ipsec_policy_out)) < 0) { |
366 |
|
|
l2tpd_log(_l2tpd, LOG_WARNING, |
367 |
|
|
"setsockopt(,,IP_IPSEC_POLICY(out)) failed " |
368 |
|
|
"in %s(): %m", __func__); |
369 |
|
|
} |
370 |
|
|
free(ipsec_policy_in); |
371 |
|
|
free(ipsec_policy_out); |
372 |
|
|
#elif defined(IP_ESP_TRANS_LEVEL) |
373 |
|
|
opt = (af == AF_INET) |
374 |
|
|
? IP_ESP_TRANS_LEVEL : IPV6_ESP_TRANS_LEVEL; |
375 |
|
|
ival = IPSEC_LEVEL_REQUIRE; |
376 |
|
|
if (setsockopt(sock, lvl, opt, &ival, sizeof(ival)) != 0) { |
377 |
|
|
l2tpd_log(_l2tpd, LOG_WARNING, |
378 |
|
|
"setsockopt(,,IP{,V6}_ESP_TRANS_LEVEL(out)) failed " |
379 |
|
|
"in %s(): %m", __func__); |
380 |
|
|
} |
381 |
|
|
#else |
382 |
|
|
#error IP_IPSEC_POLICY or IP_ESP_TRANS_LEVEL must be usable. |
383 |
|
|
#endif |
384 |
|
|
} |
385 |
|
|
|
386 |
|
|
_this->sock = sock; |
387 |
|
|
|
388 |
|
|
event_set(&_this->ev_sock, _this->sock, EV_READ | EV_PERSIST, |
389 |
|
|
l2tpd_io_event, _this); |
390 |
|
|
event_add(&_this->ev_sock, NULL); |
391 |
|
|
|
392 |
|
|
l2tpd_log(_l2tpd, LOG_INFO, "Listening %s/udp (L2TP LNS) [%s]", |
393 |
|
|
addrport_tostring((struct sockaddr *)&_this->bind, |
394 |
|
|
_this->bind.sin6.sin6_len, hbuf, sizeof(hbuf)), _this->tun_name); |
395 |
|
|
|
396 |
|
|
return 0; |
397 |
|
|
fail: |
398 |
|
|
if (sock >= 0) |
399 |
|
|
close(sock); |
400 |
|
|
|
401 |
|
|
return 1; |
402 |
|
|
} |
403 |
|
|
|
404 |
|
|
/* start L2TP daemon */ |
405 |
|
|
int |
406 |
|
|
l2tpd_start(l2tpd *_this) |
407 |
|
|
{ |
408 |
|
|
int rval; |
409 |
|
|
l2tpd_listener *plsnr; |
410 |
|
|
|
411 |
|
|
rval = 0; |
412 |
|
|
|
413 |
|
|
L2TPD_ASSERT(_this->state == L2TPD_STATE_INIT); |
414 |
|
|
if (_this->state != L2TPD_STATE_INIT) { |
415 |
|
|
l2tpd_log(_this, LOG_ERR, "Failed to start l2tpd: illegal " |
416 |
|
|
"state."); |
417 |
|
|
return -1; |
418 |
|
|
} |
419 |
|
|
|
420 |
|
|
slist_itr_first(&_this->listener); |
421 |
|
|
while (slist_itr_has_next(&_this->listener)) { |
422 |
|
|
plsnr = slist_itr_next(&_this->listener); |
423 |
|
|
rval |= l2tpd_listener_start(plsnr); |
424 |
|
|
} |
425 |
|
|
|
426 |
|
|
if (rval == 0) |
427 |
|
|
_this->state = L2TPD_STATE_RUNNING; |
428 |
|
|
|
429 |
|
|
return rval; |
430 |
|
|
} |
431 |
|
|
|
432 |
|
|
/* stop l2tp lisnter */ |
433 |
|
|
static void |
434 |
|
|
l2tpd_listener_stop(l2tpd_listener *_this) |
435 |
|
|
{ |
436 |
|
|
char hbuf[NI_MAXHOST + NI_MAXSERV + 16]; |
437 |
|
|
|
438 |
|
|
if (_this->sock >= 0) { |
439 |
|
|
event_del(&_this->ev_sock); |
440 |
|
|
close(_this->sock); |
441 |
|
|
l2tpd_log(_this->self, LOG_INFO, |
442 |
|
|
"Shutdown %s/udp (L2TP LNS)", |
443 |
|
|
addrport_tostring((struct sockaddr *)&_this->bind, |
444 |
|
|
_this->bind.sin6.sin6_len, hbuf, sizeof(hbuf))); |
445 |
|
|
_this->sock = -1; |
446 |
|
|
} |
447 |
|
|
} |
448 |
|
|
|
449 |
|
|
/* stop immediattly without disconnect operation */ |
450 |
|
|
void |
451 |
|
|
l2tpd_stop_immediatly(l2tpd *_this) |
452 |
|
|
{ |
453 |
|
|
l2tpd_listener *plsnr; |
454 |
|
|
|
455 |
|
|
slist_itr_first(&_this->listener); |
456 |
|
|
while (slist_itr_has_next(&_this->listener)) { |
457 |
|
|
plsnr = slist_itr_next(&_this->listener); |
458 |
|
|
l2tpd_listener_stop(plsnr); |
459 |
|
|
} |
460 |
|
|
event_del(&_this->ev_timeout); /* XXX */ |
461 |
|
|
_this->state = L2TPD_STATE_STOPPED; |
462 |
|
|
} |
463 |
|
|
|
464 |
|
|
/* |
465 |
|
|
* this function will be called when {@link ::_l2tp_ctrl control} |
466 |
|
|
* is terminated. |
467 |
|
|
*/ |
468 |
|
|
void |
469 |
|
|
l2tpd_ctrl_finished_notify(l2tpd *_this) |
470 |
|
|
{ |
471 |
|
|
if (_this->state != L2TPD_STATE_SHUTTING_DOWN) |
472 |
|
|
return; |
473 |
|
|
|
474 |
|
|
if (hash_first(_this->ctrl_map) != NULL) |
475 |
|
|
return; |
476 |
|
|
|
477 |
|
|
l2tpd_stop_immediatly(_this); |
478 |
|
|
} |
479 |
|
|
|
480 |
|
|
static void |
481 |
|
|
l2tpd_stop_timeout(int fd, short evtype, void *ctx) |
482 |
|
|
{ |
483 |
|
|
hash_link *hl; |
484 |
|
|
l2tp_ctrl *ctrl; |
485 |
|
|
l2tpd *_this; |
486 |
|
|
|
487 |
|
|
_this = ctx; |
488 |
|
|
l2tpd_log(_this, LOG_INFO, "Shutdown timeout"); |
489 |
|
|
for (hl = hash_first(_this->ctrl_map); hl != NULL; |
490 |
|
|
hl = hash_next(_this->ctrl_map)) { |
491 |
|
|
ctrl = hl->item; |
492 |
|
|
l2tp_ctrl_stop(ctrl, 0); |
493 |
|
|
} |
494 |
|
|
l2tpd_stop_immediatly(_this); |
495 |
|
|
} |
496 |
|
|
|
497 |
|
|
/* stop L2TP daemon */ |
498 |
|
|
void |
499 |
|
|
l2tpd_stop(l2tpd *_this) |
500 |
|
|
{ |
501 |
|
|
int nctrls = 0; |
502 |
|
|
hash_link *hl; |
503 |
|
|
l2tp_ctrl *ctrl; |
504 |
|
|
|
505 |
|
|
nctrls = 0; |
506 |
|
|
event_del(&_this->ev_timeout); |
507 |
|
|
if (l2tpd_is_stopped(_this)) |
508 |
|
|
return; |
509 |
|
|
if (l2tpd_is_shutting_down(_this)) { |
510 |
|
|
/* terminate immediately, when 2nd call */ |
511 |
|
|
l2tpd_stop_immediatly(_this); |
512 |
|
|
return; |
513 |
|
|
} |
514 |
|
|
for (hl = hash_first(_this->ctrl_map); hl != NULL; |
515 |
|
|
hl = hash_next(_this->ctrl_map)) { |
516 |
|
|
ctrl = hl->item; |
517 |
|
|
l2tp_ctrl_stop(ctrl, L2TP_STOP_CCN_RCODE_SHUTTING_DOWN); |
518 |
|
|
nctrls++; |
519 |
|
|
} |
520 |
|
|
_this->state = L2TPD_STATE_SHUTTING_DOWN; |
521 |
|
|
if (nctrls > 0) { |
522 |
|
|
struct timeval tv0; |
523 |
|
|
|
524 |
|
|
tv0.tv_usec = 0; |
525 |
|
|
tv0.tv_sec = L2TPD_SHUTDOWN_TIMEOUT; |
526 |
|
|
|
527 |
|
|
evtimer_set(&_this->ev_timeout, l2tpd_stop_timeout, _this); |
528 |
|
|
evtimer_add(&_this->ev_timeout, &tv0); |
529 |
|
|
|
530 |
|
|
return; |
531 |
|
|
} |
532 |
|
|
l2tpd_stop_immediatly(_this); |
533 |
|
|
} |
534 |
|
|
|
535 |
|
|
/* |
536 |
|
|
* Configuration |
537 |
|
|
*/ |
538 |
|
|
int |
539 |
|
|
l2tpd_reload(l2tpd *_this, struct l2tp_confs *l2tp_conf) |
540 |
|
|
{ |
541 |
|
|
int i; |
542 |
|
|
struct l2tp_conf *conf; |
543 |
|
|
l2tpd_listener *listener; |
544 |
|
|
struct l2tp_listen_addr *addr; |
545 |
|
|
|
546 |
|
|
if (slist_length(&_this->listener) > 0) { |
547 |
|
|
/* |
548 |
|
|
* TODO: add / remove / restart listener. |
549 |
|
|
*/ |
550 |
|
|
slist_itr_first(&_this->listener); |
551 |
|
|
while (slist_itr_has_next(&_this->listener)) { |
552 |
|
|
listener = slist_itr_next(&_this->listener); |
553 |
|
|
TAILQ_FOREACH(conf, l2tp_conf, entry) { |
554 |
|
|
if (strcmp(listener->tun_name, |
555 |
|
|
conf->name) == 0) { |
556 |
|
|
listener->conf = conf; |
557 |
|
|
break; |
558 |
|
|
} |
559 |
|
|
} |
560 |
|
|
} |
561 |
|
|
|
562 |
|
|
return 0; |
563 |
|
|
} |
564 |
|
|
|
565 |
|
|
i = 0; |
566 |
|
|
TAILQ_FOREACH(conf, l2tp_conf, entry) { |
567 |
|
|
TAILQ_FOREACH(addr, &conf->listen, entry) |
568 |
|
|
l2tpd_add_listener(_this, i++, conf, |
569 |
|
|
(struct sockaddr *)&addr->addr); |
570 |
|
|
} |
571 |
|
|
if (l2tpd_start(_this) != 0) |
572 |
|
|
return -1; |
573 |
|
|
|
574 |
|
|
return 0; |
575 |
|
|
} |
576 |
|
|
|
577 |
|
|
/* |
578 |
|
|
* I/O functions |
579 |
|
|
*/ |
580 |
|
|
/* logging when deny an access */ |
581 |
|
|
void |
582 |
|
|
l2tpd_log_access_deny(l2tpd *_this, const char *reason, struct sockaddr *peer) |
583 |
|
|
{ |
584 |
|
|
char buf[BUFSIZ]; |
585 |
|
|
|
586 |
|
|
l2tpd_log(_this, LOG_ALERT, "Received packet from %s/udp: " |
587 |
|
|
"%s", addrport_tostring(peer, peer->sa_len, buf, sizeof(buf)), |
588 |
|
|
reason); |
589 |
|
|
} |
590 |
|
|
|
591 |
|
|
/* I/O event handler */ |
592 |
|
|
static void |
593 |
|
|
l2tpd_io_event(int fd, short evtype, void *ctx) |
594 |
|
|
{ |
595 |
|
|
int sz; |
596 |
|
|
l2tpd *_l2tpd; |
597 |
|
|
l2tpd_listener *_this; |
598 |
|
|
socklen_t peerlen, socklen; |
599 |
|
|
struct sockaddr_storage peer, sock; |
600 |
|
|
u_char buf[8192]; |
601 |
|
|
void *nat_t; |
602 |
|
|
|
603 |
|
|
_this = ctx; |
604 |
|
|
_l2tpd = _this->self; |
605 |
|
|
if ((evtype & EV_READ) != 0) { |
606 |
|
|
peerlen = sizeof(peer); |
607 |
|
|
socklen = sizeof(sock); |
608 |
|
|
while (!l2tpd_is_stopped(_l2tpd)) { |
609 |
|
|
#if defined(USE_LIBSOCKUTIL) || defined(USE_SA_COOKIE) |
610 |
|
|
int sa_cookie_len; |
611 |
|
|
struct in_ipsec_sa_cookie sa_cookie; |
612 |
|
|
|
613 |
|
|
sa_cookie_len = sizeof(sa_cookie); |
614 |
|
|
if ((sz = recvfromto_nat_t(_this->sock, buf, |
615 |
|
|
sizeof(buf), 0, |
616 |
|
|
(struct sockaddr *)&peer, &peerlen, |
617 |
|
|
(struct sockaddr *)&sock, &socklen, |
618 |
|
|
&sa_cookie, &sa_cookie_len)) == -1) { |
619 |
|
|
#else |
620 |
|
|
if ((sz = recvfromto(_this->sock, buf, |
621 |
|
|
sizeof(buf), 0, |
622 |
|
|
(struct sockaddr *)&peer, &peerlen, |
623 |
|
|
(struct sockaddr *)&sock, &socklen)) == -1) { |
624 |
|
|
#endif |
625 |
|
|
if (errno == EAGAIN || errno == EINTR) |
626 |
|
|
break; |
627 |
|
|
l2tpd_log(_l2tpd, LOG_ERR, |
628 |
|
|
"recvfrom() failed in %s(): %m", |
629 |
|
|
__func__); |
630 |
|
|
l2tpd_stop(_l2tpd); |
631 |
|
|
return; |
632 |
|
|
} |
633 |
|
|
/* source address check (allows.in) */ |
634 |
|
|
switch (peer.ss_family) { |
635 |
|
|
case AF_INET: |
636 |
|
|
#if defined(USE_LIBSOCKUTIL) || defined(USE_SA_COOKIE) |
637 |
|
|
if (sa_cookie_len > 0) |
638 |
|
|
nat_t = &sa_cookie; |
639 |
|
|
else |
640 |
|
|
nat_t = NULL; |
641 |
|
|
#else |
642 |
|
|
nat_t = NULL; |
643 |
|
|
#endif |
644 |
|
|
l2tp_ctrl_input(_l2tpd, _this->index, |
645 |
|
|
(struct sockaddr *)&peer, |
646 |
|
|
(struct sockaddr *)&sock, nat_t, |
647 |
|
|
buf, sz); |
648 |
|
|
break; |
649 |
|
|
case AF_INET6: |
650 |
|
|
l2tp_ctrl_input(_l2tpd, _this->index, |
651 |
|
|
(struct sockaddr *)&peer, |
652 |
|
|
(struct sockaddr *)&sock, NULL, |
653 |
|
|
buf, sz); |
654 |
|
|
break; |
655 |
|
|
default: |
656 |
|
|
l2tpd_log(_l2tpd, LOG_ERR, |
657 |
|
|
"received from unknown address family = %d", |
658 |
|
|
peer.ss_family); |
659 |
|
|
break; |
660 |
|
|
} |
661 |
|
|
} |
662 |
|
|
} |
663 |
|
|
} |
664 |
|
|
|
665 |
|
|
/* |
666 |
|
|
* L2TP control |
667 |
|
|
*/ |
668 |
|
|
l2tp_ctrl * |
669 |
|
|
l2tpd_get_ctrl(l2tpd *_this, unsigned tunid) |
670 |
|
|
{ |
671 |
|
|
hash_link *hl; |
672 |
|
|
|
673 |
|
|
hl = hash_lookup(_this->ctrl_map, (void *)(uintptr_t)tunid); |
674 |
|
|
if (hl == NULL) |
675 |
|
|
return NULL; |
676 |
|
|
|
677 |
|
|
return hl->item; |
678 |
|
|
} |
679 |
|
|
|
680 |
|
|
void |
681 |
|
|
l2tpd_add_ctrl(l2tpd *_this, l2tp_ctrl *ctrl) |
682 |
|
|
{ |
683 |
|
|
hash_insert(_this->ctrl_map, (void *)(uintptr_t)ctrl->tunnel_id, ctrl); |
684 |
|
|
} |
685 |
|
|
|
686 |
|
|
void |
687 |
|
|
l2tpd_remove_ctrl(l2tpd *_this, unsigned tunid) |
688 |
|
|
{ |
689 |
|
|
hash_delete(_this->ctrl_map, (void *)(uintptr_t)tunid, 0); |
690 |
|
|
} |
691 |
|
|
|
692 |
|
|
|
693 |
|
|
/* |
694 |
|
|
* misc |
695 |
|
|
*/ |
696 |
|
|
|
697 |
|
|
void |
698 |
|
|
l2tpd_log(l2tpd *_this, int prio, const char *fmt, ...) |
699 |
|
|
{ |
700 |
|
|
char logbuf[BUFSIZ]; |
701 |
|
|
va_list ap; |
702 |
|
|
|
703 |
|
|
va_start(ap, fmt); |
704 |
|
|
#ifdef L2TPD_MULTIPLE |
705 |
|
|
snprintf(logbuf, sizeof(logbuf), "l2tpd id=%u %s", _this->id, fmt); |
706 |
|
|
#else |
707 |
|
|
snprintf(logbuf, sizeof(logbuf), "l2tpd %s", fmt); |
708 |
|
|
#endif |
709 |
|
|
vlog_printf(prio, logbuf, ap); |
710 |
|
|
va_end(ap); |
711 |
|
|
} |