2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
8 * Copyright (C) 2002-2009 OpenVPN Technologies, Inc. <sales@openvpn.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program (see the file COPYING included with this
21 * distribution); if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include "forward-inline.h"
35 * Get a client instance based on real address. If
36 * the instance doesn't exist, create it while
37 * maintaining real address hash table atomicity.
40 struct multi_instance
*
41 multi_get_create_instance_udp (struct multi_context
*m
)
43 struct gc_arena gc
= gc_new ();
44 struct mroute_addr real
;
45 struct multi_instance
*mi
= NULL
;
46 struct hash
*hash
= m
->hash
;
48 if (mroute_extract_openvpn_sockaddr (&real
, &m
->top
.c2
.from
.dest
, true))
50 struct hash_element
*he
;
51 const uint32_t hv
= hash_value (hash
, &real
);
52 struct hash_bucket
*bucket
= hash_bucket (hash
, hv
);
54 hash_bucket_lock (bucket
);
55 he
= hash_lookup_fast (hash
, bucket
, &real
, hv
);
59 mi
= (struct multi_instance
*) he
->value
;
63 if (!m
->top
.c2
.tls_auth_standalone
64 || tls_pre_decrypt_lite (m
->top
.c2
.tls_auth_standalone
, &m
->top
.c2
.from
, &m
->top
.c2
.buf
))
66 if (frequency_limit_event_allowed (m
->new_connection_limiter
))
68 mi
= multi_create_instance (m
, &real
);
71 hash_add_fast (hash
, bucket
, &mi
->real
, hv
, mi
);
72 mi
->did_real_hash
= true;
78 "MULTI: Connection from %s would exceed new connection frequency limit as controlled by --connect-freq",
79 mroute_addr_print (&real
, &gc
));
84 hash_bucket_unlock (bucket
);
87 if (check_debug_level (D_MULTI_DEBUG
))
92 status
= "[succeeded]";
98 dmsg (D_MULTI_DEBUG
, "GET INST BY REAL: %s %s",
99 mroute_addr_print (&real
, &gc
),
106 ASSERT (!(mi
&& mi
->halt
));
111 * Send a packet to TCP/UDP socket.
114 multi_process_outgoing_link (struct multi_context
*m
, const unsigned int mpp_flags
)
116 struct multi_instance
*mi
= multi_process_outgoing_link_pre (m
);
118 multi_process_outgoing_link_dowork (m
, mi
, mpp_flags
);
122 * Process an I/O event.
125 multi_process_io_udp (struct multi_context
*m
)
127 const unsigned int status
= m
->top
.c2
.event_set_status
;
128 const unsigned int mpp_flags
= m
->top
.c2
.fast_io
129 ? (MPP_CONDITIONAL_PRE_SELECT
| MPP_CLOSE_ON_SIGNAL
)
130 : (MPP_PRE_SELECT
| MPP_CLOSE_ON_SIGNAL
);
132 #ifdef MULTI_DEBUG_EVENT_LOOP
135 if (status
& SOCKET_READ
)
137 else if (status
& SOCKET_WRITE
)
139 else if (status
& TUN_READ
)
141 else if (status
& TUN_WRITE
)
143 printf ("IO %s\n", buf
);
146 #ifdef ENABLE_MANAGEMENT
147 if (status
& (MANAGEMENT_READ
|MANAGEMENT_WRITE
))
150 management_io (management
);
154 /* UDP port ready to accept write */
155 if (status
& SOCKET_WRITE
)
157 multi_process_outgoing_link (m
, mpp_flags
);
159 /* TUN device ready to accept write */
160 else if (status
& TUN_WRITE
)
162 multi_process_outgoing_tun (m
, mpp_flags
);
164 /* Incoming data on UDP port */
165 else if (status
& SOCKET_READ
)
167 read_incoming_link (&m
->top
);
168 multi_release_io_lock (m
);
169 if (!IS_SIG (&m
->top
))
170 multi_process_incoming_link (m
, NULL
, mpp_flags
);
172 /* Incoming data on TUN device */
173 else if (status
& TUN_READ
)
175 read_incoming_tun (&m
->top
);
176 multi_release_io_lock (m
);
177 if (!IS_SIG (&m
->top
))
178 multi_process_incoming_tun (m
, mpp_flags
);
183 * Return the io_wait() flags appropriate for
184 * a point-to-multipoint tunnel.
186 static inline unsigned int
187 p2mp_iow_flags (const struct multi_context
*m
)
189 unsigned int flags
= IOW_WAIT_SIGNAL
;
192 if (TUN_OUT (&m
->pending
->context
))
194 if (LINK_OUT (&m
->pending
->context
))
195 flags
|= IOW_TO_LINK
;
197 else if (mbuf_defined (m
->mbuf
))
206 * Top level event loop for single-threaded operation.
210 tunnel_server_udp_single_threaded (struct context
*top
)
212 struct multi_context multi
;
215 context_clear_2 (top
);
217 /* initialize top-tunnel instance */
218 init_instance_handle_signals (top
, top
->es
, CC_HARD_USR1_TO_HUP
);
222 /* initialize global multi_context object */
223 multi_init (&multi
, top
, false, MC_SINGLE_THREADED
);
225 /* initialize our cloned top object */
226 multi_top_init (&multi
, top
, true);
228 /* initialize management interface */
229 init_management_callback_multi (&multi
);
231 /* finished with initialization */
232 initialization_sequence_completed (top
, ISC_SERVER
); /* --mode server --proto udp */
234 /* per-packet event loop */
237 perf_push (PERF_EVENT_LOOP
);
239 /* set up and do the io_wait() */
240 multi_get_timeout (&multi
, &multi
.top
.c2
.timeval
);
241 io_wait (&multi
.top
, p2mp_iow_flags (&multi
));
242 MULTI_CHECK_SIG (&multi
);
244 /* check on status of coarse timers */
245 multi_process_per_second_timers (&multi
);
248 if (multi
.top
.c2
.event_set_status
== ES_TIMEOUT
)
250 multi_process_timeout (&multi
, MPP_PRE_SELECT
|MPP_CLOSE_ON_SIGNAL
);
255 multi_process_io_udp (&multi
);
256 MULTI_CHECK_SIG (&multi
);
262 /* shut down management interface */
263 uninit_management_callback_multi (&multi
);
265 /* save ifconfig-pool */
266 multi_ifconfig_pool_persist (&multi
, true);
268 /* tear down tunnel instance (unless --persist-tun) */
269 multi_uninit (&multi
);
270 multi_top_free (&multi
);
271 close_instance (top
);
275 tunnel_server_udp (struct context
*top
)
277 tunnel_server_udp_single_threaded (top
);