Browse code

tls: new parameters for advanced openssl options

- ssl_release_buffers: release internal openssl read or write
buffers when they are no longer used (complete read or write that
does not have to buffer anything).
Should be used together with tls_free_list_max_len. Might have
some performance impact (and extra *malloc pressure), but has
also the potential of saving a lot of memory (at least 32k/idle
connection in the default config, or ~16k+tls_max_send_fragment)).
Works only with openssl >= 1.0.0.

- ssl_freelist_max_len: maximum length of free/unused memory
buffers/chunks per connection. Setting it to 0 would cause any
unused buffers to be immediately freed and hence a lower memory
footprint (at the cost of a possible performance hit and more
*malloc pressure). Too large value would result in extra memory
consumption. The default is 32 in openssl.
For lowest memory usage set it to 0 and tls_mode_release_buffers
to 1.
Works / makes sense only for openssl >= 1.0.0.

- ssl_max_send_fragment: maximum number of bytes (clear text) sent
into one record. The default and maximum value are ~16k. Lower
values would lead to a lower memory footprint. Values lower then
the typical app. write size might decrease performance, so
it should be kept ~2k+ for normal SIP traffic.
Too low values (e.g. <1024) might cause the initial handshake
to fail, so use with care.
Works only for openssl >= 0.9.9.

- ssl_read_ahead: enable read ahead. Should increase performance
(1 less syscall when enabled, else openssl makes 1 read() for
each record header and another or the content), but might
interact with SSL_pending() (not used right now).
Default: 1 (enabled).

Andrei Pelinescu-Onciul authored on 19/03/2010 14:11:49
Showing 3 changed files
... ...
@@ -23,11 +23,10 @@
23 23
  * along with this program; if not, write to the Free Software 
24 24
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25 25
  */
26
-/*!
27
- * \file
28
- * \brief SIP-router TLS support :: Virtual domain configuration support
29
- * \ingroup tls
30
- * Module: \ref tls
26
+/** SIP-router TLS support :: Virtual domain configuration support.
27
+ * @file
28
+ * @ingroup tls
29
+ * Module: @ref tls
31 30
  */
32 31
 
33 32
 
... ...
@@ -214,6 +213,116 @@ static int fill_missing(tls_domain_t* d, tls_domain_t* parent)
214 213
 }
215 214
 
216 215
 
216
+/* called for ctx, with 2 args.
217
+ * should return 0 on succes, <0 on critical error.
218
+ */
219
+typedef int (*per_ctx_cbk_f)(SSL_CTX* ctx, long larg, void* parg);
220
+
221
+
222
+/** execute callback on all the CTX'es on a domain.
223
+ * @param d - domain
224
+ * @param f - callback function
225
+ * @param l - parameter passed to the callback
226
+ * @param p - parameter passed to the callback
227
+ * @return 0 on success, <0 on error.
228
+ */
229
+static int tls_domain_foreach_CTX(tls_domain_t* d, per_ctx_cbk_f ctx_cbk,
230
+									long l1, void* p2)
231
+{
232
+	int i,ret;
233
+	int procs_no;
234
+	
235
+	procs_no=get_max_procs();
236
+	for(i = 0; i < procs_no; i++) {
237
+		if ((ret=ctx_cbk(d->ctx[i], l1, p2))<0)
238
+			return ret;
239
+	}
240
+	return 0;
241
+}
242
+
243
+
244
+/** execute callback on all the CTX'es on in a domain list.
245
+ * @param d - domain
246
+ * @param f - callback function
247
+ * @param l - parameter passed to the callback
248
+ * @param p - parameter passed to the callback
249
+ * @return 0 on success, <0 on error.
250
+ */
251
+static int tls_foreach_CTX_in_domain_lst(tls_domain_t* d,
252
+										per_ctx_cbk_f ctx_cbk,
253
+										long l1, void* p2)
254
+{
255
+	int ret;
256
+	for (; d; d=d->next)
257
+		if ((ret=tls_domain_foreach_CTX(d, ctx_cbk, l1, p2))<0)
258
+			return ret;
259
+	return 0;
260
+}
261
+
262
+
263
+/** execute callback on all the CTX'es in all the srv domains in a tls cfg.
264
+ * @param cfg - tls cfg.
265
+ * @param f - callback function
266
+ * @param l - parameter passed to the callback
267
+ * @param p - parameter passed to the callback
268
+ * @return 0 on success, <0 on error.
269
+ */
270
+static int tls_foreach_CTX_in_srv_domains(tls_cfg_t* cfg,
271
+											per_ctx_cbk_f ctx_cbk,
272
+											long l1, void* p2)
273
+{
274
+	int ret;
275
+	if ((ret = tls_domain_foreach_CTX(cfg->srv_default, ctx_cbk, l1, p2)) < 0)
276
+		return ret;
277
+	if ((ret = tls_foreach_CTX_in_domain_lst(cfg->srv_list, ctx_cbk, l1, p2))
278
+			< 0)
279
+		return ret;
280
+	return 0;
281
+}
282
+
283
+
284
+/** execute callback on all the CTX'es in all the client domains in a tls cfg.
285
+ * @param cfg - tls cfg.
286
+ * @param f - callback function
287
+ * @param l - parameter passed to the callback
288
+ * @param p - parameter passed to the callback
289
+ * @return 0 on success, <0 on error.
290
+ */
291
+static int tls_foreach_CTX_in_cli_domains(tls_cfg_t* cfg,
292
+											per_ctx_cbk_f ctx_cbk,
293
+											long l1, void* p2)
294
+{
295
+	int ret;
296
+	if ((ret = tls_domain_foreach_CTX(cfg->cli_default, ctx_cbk, l1, p2)) < 0)
297
+		return ret;
298
+	if ((ret = tls_foreach_CTX_in_domain_lst(cfg->cli_list, ctx_cbk, l1, p2))
299
+			< 0)
300
+		return ret;
301
+	return 0;
302
+}
303
+
304
+
305
+/** execute callback on all the CTX'es in all the domains in a tls cfg.
306
+ * @param cfg - tls cfg
307
+ * @param f - callback function
308
+ * @param l - parameter passed to the callback
309
+ * @param p - parameter passed to the callback
310
+ * @return 0 on success, <0 on error.
311
+ */
312
+static int tls_foreach_CTX_in_cfg(tls_cfg_t* cfg, per_ctx_cbk_f ctx_cbk,
313
+										long l1, void* p2)
314
+{
315
+	int ret;
316
+
317
+	if ((ret = tls_foreach_CTX_in_srv_domains(cfg, ctx_cbk, l1, p2)) < 0)
318
+		return ret;
319
+	if ((ret = tls_foreach_CTX_in_cli_domains(cfg, ctx_cbk, l1, p2)) < 0)
320
+		return ret;
321
+	return 0;
322
+}
323
+
324
+
325
+
217 326
 /* 
218 327
  * Load certificate from file 
219 328
  */
... ...
@@ -433,6 +542,74 @@ static int set_session_cache(tls_domain_t* d)
433 542
 }
434 543
 
435 544
 
545
+
546
+/** tls SSL_CTX_set_mode and SSL_CTX_clear_mode wrapper.
547
+ *  @param mode - SSL_MODE_*.
548
+ *  @param clear - if set to !=0 will do a clear, else (==0) a set.
549
+ *  @return - 0 (always succeeds).
550
+ */
551
+int tls_ssl_ctx_mode(SSL_CTX* ctx, long mode, void* clear)
552
+{
553
+	if (clear)
554
+#if OPENSSL_VERSION_NUMBER >= 0x01000000L || \
555
+	defined SSL_CTX_clear_mode
556
+		SSL_CTX_clear_mode(ctx, mode);
557
+#else
558
+	return -1;
559
+#endif
560
+	else
561
+		SSL_CTX_set_mode(ctx, mode);
562
+	return 0;
563
+}
564
+
565
+
566
+
567
+/** tls set ctx->free_list_max_len.
568
+ *  @param val - value (<0 ignored).
569
+ *  @return - 0 (always succeeds).
570
+ */
571
+int tls_ssl_ctx_set_freelist(SSL_CTX* ctx, long val, void* unused)
572
+{
573
+	if (val >= 0)
574
+#if OPENSSL_VERSION_NUMBER >= 0x01000000L
575
+#ifndef OPENSSL_NO_BUF_FREELISTS
576
+		ctx->freelist_max_len = val;
577
+#endif
578
+#endif
579
+#if defined (OPENSSL_NO_BUF_FREELISTS) || OPENSSL_VERSION_NUMBER < 0x01000000L
580
+		return -1;
581
+#endif
582
+	return 0;
583
+}
584
+
585
+/** tls SSL_CTX_set_max_send_fragment wrapper.
586
+ *  @param val - value (<0 ignored). Should be between 512 and 16k.
587
+ *  @return  0 on success, < 0 on failure (invalid value)
588
+ */
589
+int tls_ssl_ctx_set_max_send_fragment(SSL_CTX* ctx, long val, void* unused)
590
+{
591
+	if (val >= 0)
592
+#if OPENSSL_VERSION_NUMBER >= 0x00909000L
593
+		return SSL_CTX_set_max_send_fragment(ctx, val) -1;
594
+#else
595
+		return -1;
596
+#endif
597
+	return 0;
598
+}
599
+
600
+
601
+
602
+/** tls SSL_CTX_set_read_ahead wrapper.
603
+ *  @param val - value (<0 ignored, 0 or >0).
604
+ *  @return  0 (always success).
605
+ */
606
+int tls_ssl_ctx_set_read_ahead(SSL_CTX* ctx, long val, void* unused)
607
+{
608
+	if (val >= 0)
609
+		SSL_CTX_set_read_ahead(ctx, val);
610
+	return 0;
611
+}
612
+
436 613
 /*
437 614
  * Initialize all domain attributes from default domains
438 615
  * if necessary
... ...
@@ -465,7 +642,6 @@ static int fix_domain(tls_domain_t* d, tls_domain_t* def)
465 642
 	if (set_verification(d) < 0) return -1;
466 643
 	if (set_ssl_options(d) < 0) return -1;
467 644
 	if (set_session_cache(d) < 0) return -1;
468
-
469 645
 	return 0;
470 646
 }
471 647
 
... ...
@@ -602,6 +778,62 @@ int tls_fix_cfg(tls_cfg_t* cfg, tls_domain_t* srv_defaults, tls_domain_t* cli_de
602 778
 	if (load_private_key(cfg->srv_default) < 0) return -1;
603 779
 	if (load_private_key(cfg->cli_default) < 0) return -1;
604 780
 
781
+	/* set various global per CTX options
782
+	 * (done here to show possible missing features messages only once)
783
+	 */
784
+#if OPENSSL_VERSION_NUMBER >= 0x01000000L
785
+	/* set SSL_MODE_RELEASE_BUFFERS if ssl_mode_release_buffers !=0,
786
+	   reset if == 0 and ignore if < 0 */
787
+	/* only in >= 1.0.0 */
788
+	if (ssl_mode_release_buffers >= 0 &&
789
+		tls_foreach_CTX_in_cfg(cfg, tls_ssl_ctx_mode, SSL_MODE_RELEASE_BUFFERS,
790
+								(void*)(long)(ssl_mode_release_buffers==0))
791
+		< 0) {
792
+		ERR("invalid ssl_release_buffers value (%d)\n",
793
+				ssl_mode_release_buffers);
794
+		return -1;
795
+	}
796
+#else
797
+	if (ssl_mode_release_buffers > 0)
798
+		ERR("cannot change openssl mode_release_buffers, the openssl version"
799
+				" is too old (need at least 1.0.0)\n");
800
+#endif
801
+	/* only in >= 1.0.0 */
802
+#if OPENSSL_VERSION_NUMBER >= 0x01000000L
803
+#ifndef OPENSSL_NO_BUF_FREELISTS
804
+	if (tls_foreach_CTX_in_cfg(cfg, tls_ssl_ctx_set_freelist,
805
+								ssl_freelist_max_len, 0) < 0) {
806
+		ERR("invalid ssl_freelist_max_len value (%d)\n",
807
+				ssl_freelist_max_len);
808
+		return -1;
809
+	}
810
+#endif
811
+#endif
812
+#if defined (OPENSSL_NO_BUF_FREELISTS) || OPENSSL_VERSION_NUMBER < 0x01000000L
813
+	if (ssl_freelist_max_len != 0)
814
+		ERR("cannot change openssl freelist_max_len, openssl too old"
815
+				"(needed at least 1.0.0) or compiled without freelist support"
816
+				" (OPENSSL_NO_BUF_FREELIST)\n");
817
+#endif
818
+#if OPENSSL_VERSION_NUMBER >= 0x00909000L
819
+	/* only in >= 0.9.9 */
820
+	if (tls_foreach_CTX_in_cfg(cfg, tls_ssl_ctx_set_max_send_fragment,
821
+								ssl_max_send_fragment, 0) < 0) {
822
+		ERR("invalid ssl_max_send_fragment value (%d)\n",
823
+				ssl_max_send_fragment);
824
+		return -1;
825
+	}
826
+#else
827
+	if (ssl_max_send_fragment > 0)
828
+		ERR("cannot change openssl max_send_fragment, the openssl version"
829
+				" is too old (need at least 0.9.9)\n");
830
+#endif
831
+	if (tls_foreach_CTX_in_cfg(cfg, tls_ssl_ctx_set_read_ahead,
832
+								ssl_read_ahead, 0) < 0) {
833
+		ERR("invalid ssl_read_ahead value (%d)\n", ssl_read_ahead);
834
+		return -1;
835
+	}
836
+
605 837
 	return 0;
606 838
 }
607 839
 
... ...
@@ -33,12 +33,14 @@
33 33
  *              calls to domain_db_{bind,init,close,ver} (andrei)
34 34
  * 2007-02-09  updated to the new tls_hooks api and renamed tls hooks hanlder
35 35
  *              functions to avoid conflicts: s/tls_/tls_h_/   (andrei)
36
+ * 2010-03-19  new parameters to control advanced openssl lib options
37
+ *              (mostly work on 1.0.0+): ssl_release_buffers, ssl_read_ahead,
38
+ *              ssl_freelist_max_len, ssl_max_send_fragment   (andrei)
36 39
  */
37
-/*!
38
- * \file
39
- * \brief SIP-router TLS support :: Module interface
40
- * \ingroup tls
41
- * Module: \ref tls
40
+/** SIP-router TLS support :: Module interface.
41
+ * @file
42
+ * @ingroup tls
43
+ * Module: @ref tls
42 44
  */
43 45
 
44 46
 
... ...
@@ -175,6 +177,35 @@ int tls_con_lifetime = 600; /* this value will be adjusted to ticks later */
175 177
 int tls_log = 3;
176 178
 int tls_session_cache = 0;
177 179
 str tls_session_id = STR_STATIC_INIT("ser-tls-2.1.0");
180
+/* release internal openssl read or write buffer when they are no longer used
181
+ * (complete read or write that does not have to buffer anything).
182
+ * Should be used together with tls_free_list_max_len. Might have some
183
+ * performance impact (and extra *malloc pressure), but has also the potential
184
+ * of saving a lot of memory (at least 32k/idle connection in the default
185
+ * config, or ~ 16k+tls_max_send_fragment)) */
186
+int ssl_mode_release_buffers = -1; /* don't set, leave the default (off) */
187
+/* maximum length of free/unused memory buffers/chunks per connection.
188
+ * Setting it to 0 would cause any unused buffers to be immediately freed
189
+ * and hence a lower memory footprint (at the cost of a possible performance
190
+ * decrease and more *malloc pressure).
191
+ * Too large value would result in extra memory consumption.
192
+ * The default is 32 in openssl.
193
+ * For lowest memory usage set it to 0 and tls_mode_release_buffers to 1
194
+ */
195
+int ssl_freelist_max_len = -1;   /* don't set, leave the default value (32) */
196
+/* maximum number of bytes (clear text) sent into one record.
197
+ * The default and maximum value are ~16k. Lower values would lead to a lower
198
+ *  memory footprint. 
199
+ * Values lower then the typical  app. write size might decrease performance 
200
+ * (extra write() syscalls), so it should be kept ~2k for ser.
201
+ */
202
+int ssl_max_send_fragment = -1;  /* don't set, leave the default (16k) */
203
+/* enable read ahead. Should increase performance (1 less syscall when
204
+ * enabled, else openssl makes 1 read() for each record header and another
205
+ * for the content), but might interact with SSL_pending() (not used right now)
206
+ */
207
+int ssl_read_ahead = 1; /* set (use -1 for the default value) */
208
+
178 209
 str tls_cfg_file = STR_NULL;
179 210
 
180 211
 
... ...
@@ -215,9 +246,13 @@ static param_export_t params[] = {
215 246
 	{"session_id",          PARAM_STR,    &tls_session_id         },
216 247
 	{"config",              PARAM_STR,    &tls_cfg_file           },
217 248
 	{"tls_disable_compression", PARAM_INT,&tls_disable_compression},
249
+	{"ssl_release_buffers",   PARAM_INT, &ssl_mode_release_buffers},
250
+	{"ssl_freelist_max_len",  PARAM_INT,    &ssl_freelist_max_len},
251
+	{"ssl_max_send_fragment", PARAM_INT,    &ssl_max_send_fragment},
252
+	{"ssl_read_ahead",        PARAM_INT,    &ssl_read_ahead},
218 253
 	{"tls_force_run",       PARAM_INT,    &tls_force_run},
219
-	{"low_mem_threshold1",       PARAM_INT,    &openssl_mem_threshold1},
220
-	{"low_mem_threshold2",       PARAM_INT,    &openssl_mem_threshold2},
254
+	{"low_mem_threshold1",  PARAM_INT,    &openssl_mem_threshold1},
255
+	{"low_mem_threshold2",  PARAM_INT,    &openssl_mem_threshold2},
221 256
 	{0, 0, 0}
222 257
 };
223 258
 
... ...
@@ -28,11 +28,10 @@
28 28
  * along with this program; if not, write to the Free Software 
29 29
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
30 30
  */
31
-/*!
32
- * \file
33
- * \brief SIP-router TLS support :: module interface
34
- * \ingroup tls
35
- * Module: \ref tls
31
+/** SIP-router TLS support :: module interface.
32
+ * @file
33
+ * @ingroup tls
34
+ * Module: @ref tls
36 35
  */
37 36
 
38 37
 
... ...
@@ -50,6 +49,10 @@ extern int tls_con_lifetime;
50 49
 extern int tls_log;
51 50
 extern int tls_session_cache;
52 51
 extern str tls_session_id;
52
+extern int ssl_mode_release_buffers;
53
+extern int ssl_freelist_max_len;
54
+extern int ssl_max_send_fragment;
55
+extern int ssl_read_ahead;
53 56
 
54 57
 /* Current TLS configuration */
55 58
 extern tls_cfg_t** tls_cfg;