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-2005 OpenVPN Solutions LLC <info@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
26 #include "config-win32.h"
36 #include "forward-inline.h"
41 * Get a client instance based on real address. If
42 * the instance doesn't exist, create it while
43 * maintaining real address hash table atomicity.
46 struct multi_instance
*
47 multi_get_create_instance_udp (struct multi_context
*m
)
49 struct gc_arena gc
= gc_new ();
50 struct mroute_addr real
;
51 struct multi_instance
*mi
= NULL
;
52 struct hash
*hash
= m
->hash
;
54 if (mroute_extract_sockaddr_in (&real
, &m
->top
.c2
.from
, true))
56 struct hash_element
*he
;
57 const uint32_t hv
= hash_value (hash
, &real
);
58 struct hash_bucket
*bucket
= hash_bucket (hash
, hv
);
60 hash_bucket_lock (bucket
);
61 he
= hash_lookup_fast (hash
, bucket
, &real
, hv
);
65 mi
= (struct multi_instance
*) he
->value
;
69 if (!m
->top
.c2
.tls_auth_standalone
70 || tls_pre_decrypt_lite (m
->top
.c2
.tls_auth_standalone
, &m
->top
.c2
.from
, &m
->top
.c2
.buf
))
72 if (frequency_limit_event_allowed (m
->new_connection_limiter
))
74 mi
= multi_create_instance (m
, &real
);
77 hash_add_fast (hash
, bucket
, &mi
->real
, hv
, mi
);
78 mi
->did_real_hash
= true;
84 "MULTI: Connection from %s would exceed new connection frequency limit as controlled by --connect-freq",
85 mroute_addr_print (&real
, &gc
));
90 hash_bucket_unlock (bucket
);
93 if (check_debug_level (D_MULTI_DEBUG
))
98 status
= "[succeeded]";
100 status
= "[created]";
104 dmsg (D_MULTI_DEBUG
, "GET INST BY REAL: %s %s",
105 mroute_addr_print (&real
, &gc
),
112 ASSERT (!(mi
&& mi
->halt
));
117 * Send a packet to TCP/UDP socket.
120 multi_process_outgoing_link (struct multi_context
*m
, const unsigned int mpp_flags
)
122 struct multi_instance
*mi
= multi_process_outgoing_link_pre (m
);
124 multi_process_outgoing_link_dowork (m
, mi
, mpp_flags
);
128 * Process an I/O event.
131 multi_process_io_udp (struct multi_context
*m
)
133 const unsigned int status
= m
->top
.c2
.event_set_status
;
134 const unsigned int mpp_flags
= m
->top
.c2
.fast_io
135 ? (MPP_CONDITIONAL_PRE_SELECT
| MPP_CLOSE_ON_SIGNAL
)
136 : (MPP_PRE_SELECT
| MPP_CLOSE_ON_SIGNAL
);
138 #ifdef MULTI_DEBUG_EVENT_LOOP
141 if (status
& SOCKET_READ
)
143 else if (status
& SOCKET_WRITE
)
145 else if (status
& TUN_READ
)
147 else if (status
& TUN_WRITE
)
149 printf ("IO %s\n", buf
);
152 #ifdef ENABLE_MANAGEMENT
153 if (status
& (MANAGEMENT_READ
|MANAGEMENT_WRITE
))
156 management_io (management
);
160 /* UDP port ready to accept write */
161 if (status
& SOCKET_WRITE
)
163 multi_process_outgoing_link (m
, mpp_flags
);
165 /* TUN device ready to accept write */
166 else if (status
& TUN_WRITE
)
168 multi_process_outgoing_tun (m
, mpp_flags
);
170 /* Incoming data on UDP port */
171 else if (status
& SOCKET_READ
)
173 read_incoming_link (&m
->top
);
174 multi_release_io_lock (m
);
175 if (!IS_SIG (&m
->top
))
176 multi_process_incoming_link (m
, NULL
, mpp_flags
);
178 /* Incoming data on TUN device */
179 else if (status
& TUN_READ
)
181 read_incoming_tun (&m
->top
);
182 multi_release_io_lock (m
);
183 if (!IS_SIG (&m
->top
))
184 multi_process_incoming_tun (m
, mpp_flags
);
189 * Return the io_wait() flags appropriate for
190 * a point-to-multipoint tunnel.
192 static inline unsigned int
193 p2mp_iow_flags (const struct multi_context
*m
)
195 unsigned int flags
= IOW_WAIT_SIGNAL
;
198 if (TUN_OUT (&m
->pending
->context
))
200 if (LINK_OUT (&m
->pending
->context
))
201 flags
|= IOW_TO_LINK
;
203 else if (mbuf_defined (m
->mbuf
))
212 * Top level event loop for single-threaded operation.
216 tunnel_server_udp_single_threaded (struct context
*top
)
218 struct multi_context multi
;
221 context_clear_2 (top
);
223 /* initialize top-tunnel instance */
224 init_instance_handle_signals (top
, top
->es
, CC_HARD_USR1_TO_HUP
);
228 /* initialize global multi_context object */
229 multi_init (&multi
, top
, false, MC_SINGLE_THREADED
);
231 /* initialize our cloned top object */
232 multi_top_init (&multi
, top
, true);
234 /* initialize management interface */
235 init_management_callback_multi (&multi
);
237 /* finished with initialization */
238 initialization_sequence_completed (top
, ISC_SERVER
); /* --mode server --proto udp */
240 /* per-packet event loop */
243 perf_push (PERF_EVENT_LOOP
);
245 /* set up and do the io_wait() */
246 multi_get_timeout (&multi
, &multi
.top
.c2
.timeval
);
247 io_wait (&multi
.top
, p2mp_iow_flags (&multi
));
248 MULTI_CHECK_SIG (&multi
);
250 /* check on status of coarse timers */
251 multi_process_per_second_timers (&multi
);
254 if (multi
.top
.c2
.event_set_status
== ES_TIMEOUT
)
256 multi_process_timeout (&multi
, MPP_PRE_SELECT
|MPP_CLOSE_ON_SIGNAL
);
261 multi_process_io_udp (&multi
);
262 MULTI_CHECK_SIG (&multi
);
268 /* shut down management interface */
269 uninit_management_callback_multi (&multi
);
271 /* save ifconfig-pool */
272 multi_ifconfig_pool_persist (&multi
, true);
274 /* tear down tunnel instance (unless --persist-tun) */
275 multi_uninit (&multi
);
276 multi_top_free (&multi
);
277 close_instance (top
);
281 tunnel_server_udp (struct context
*top
)
283 tunnel_server_udp_single_threaded (top
);