Skip to content

Commit 1549514

Browse files
authored
Add support for DTLS fragmentation (#49)
1 parent 47fa855 commit 1549514

File tree

9 files changed

+401
-121
lines changed

9 files changed

+401
-121
lines changed

bundlex.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ defmodule ExDTLS.BundlexProject do
1010
defp natives() do
1111
[
1212
native: [
13-
sources: ["native.c", "dtls.c", "dyn_buff.c"],
13+
sources: ["native.c", "dtls.c", "dyn_buff.c", "bio_frag.c"],
1414
deps: [unifex: :unifex],
1515
os_deps: [openssl: :pkg_config],
1616
libs: ["pthread"],

c_src/ex_dtls/bio_frag.c

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
2+
#include "bio_frag.h"
3+
#include <openssl/bio.h>
4+
5+
static int bwrite(BIO *bio, const char *buf, int len);
6+
static int bread(BIO *bio, char *buf, int len);
7+
static long ctrl(BIO *bio, int cmd, long arg1, void *arg2);
8+
static int create(BIO *bio);
9+
static int destroy(BIO *bio);
10+
static long callback_ctrl(BIO *bio, int cmd, BIO_info_cb *fp);
11+
12+
static BIO_METHOD *bio_methods = NULL;
13+
14+
#define MAX_FRAGS 100
15+
#define MTU 1200
16+
17+
struct Ctx {
18+
int frag_sizes[MAX_FRAGS];
19+
int witer;
20+
int riter;
21+
};
22+
23+
const BIO_METHOD *BIO_f_frag(void) {
24+
bio_methods = BIO_meth_new(BIO_TYPE_FILTER, "DTLS fragmentation for mem BIO");
25+
26+
BIO_meth_set_read(bio_methods, bread);
27+
BIO_meth_set_write(bio_methods, bwrite);
28+
BIO_meth_set_ctrl(bio_methods, ctrl);
29+
BIO_meth_set_create(bio_methods, create);
30+
BIO_meth_set_destroy(bio_methods, destroy);
31+
BIO_meth_set_callback_ctrl(bio_methods, callback_ctrl);
32+
33+
return bio_methods;
34+
}
35+
36+
static int create(BIO *bio) {
37+
struct Ctx *ctx = calloc(1, sizeof(struct Ctx));
38+
for (int i = 0; i < MAX_FRAGS; i++) {
39+
ctx->frag_sizes[i] = 0;
40+
}
41+
ctx->witer = 0;
42+
ctx->riter = 0;
43+
44+
BIO_set_data(bio, ctx);
45+
BIO_set_init(bio, 1);
46+
return 1;
47+
}
48+
49+
static int destroy(BIO *bio) {
50+
if (bio == NULL) {
51+
return 0;
52+
}
53+
54+
struct Ctx *ctx = BIO_get_data(bio);
55+
free(ctx);
56+
BIO_set_data(bio, NULL);
57+
BIO_set_init(bio, 0);
58+
return 1;
59+
}
60+
61+
static int bread(BIO *bio, char *buf, int len) {
62+
BIO *next = BIO_next(bio);
63+
if (next == NULL) {
64+
return 0;
65+
}
66+
67+
struct Ctx *ctx = BIO_get_data(bio);
68+
69+
if (len != ctx->frag_sizes[ctx->riter]) {
70+
return 0;
71+
}
72+
73+
int ret = BIO_read(next, buf, len);
74+
75+
if (ret > 0) {
76+
if (ret == ctx->frag_sizes[ctx->riter]) {
77+
ctx->frag_sizes[ctx->riter] = 0;
78+
ctx->riter++;
79+
80+
if (ctx->riter == ctx->witer && ctx->frag_sizes[ctx->riter] == 0) {
81+
// reset iterators
82+
ctx->riter = 0;
83+
ctx->witer = 0;
84+
}
85+
86+
} else if (ret < ctx->frag_sizes[ctx->riter]) {
87+
ctx->frag_sizes[ctx->riter] -= ret;
88+
} else {
89+
// This should never happen
90+
return 0;
91+
}
92+
};
93+
94+
return ret;
95+
}
96+
97+
static int bwrite(BIO *bio, const char *buf, int len) {
98+
BIO *next = BIO_next(bio);
99+
if (next == NULL) {
100+
return 0;
101+
}
102+
103+
struct Ctx *ctx = BIO_get_data(bio);
104+
105+
if (ctx->witer >= MAX_FRAGS) {
106+
return 0;
107+
}
108+
109+
int ret = BIO_write(next, buf, len);
110+
if (ret > 0) {
111+
ctx->frag_sizes[ctx->witer] = ret;
112+
ctx->witer++;
113+
}
114+
115+
return ret;
116+
}
117+
118+
static long ctrl(BIO *bio, int cmd, long num, void *ptr) {
119+
BIO *next = BIO_next(bio);
120+
if (next == NULL) {
121+
return 0;
122+
}
123+
124+
struct Ctx *ctx = BIO_get_data(bio);
125+
126+
if (cmd == BIO_CTRL_PENDING) {
127+
return ctx->frag_sizes[ctx->riter];
128+
} else if (cmd == BIO_CTRL_DGRAM_QUERY_MTU) {
129+
return MTU;
130+
}
131+
132+
return BIO_ctrl(next, cmd, num, ptr);
133+
}
134+
135+
static long callback_ctrl(BIO *bio, int cmd, BIO_info_cb *fp) {
136+
BIO *next = BIO_next(bio);
137+
if (next == NULL) {
138+
return 0;
139+
}
140+
141+
return BIO_callback_ctrl(next, cmd, fp);
142+
}

c_src/ex_dtls/bio_frag.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#include <openssl/opensslv.h>
2+
#include <openssl/err.h>
3+
#include <openssl/ssl.h>
4+
5+
#include "log.h"
6+
7+
const BIO_METHOD *BIO_f_frag(void);

c_src/ex_dtls/dtls.c

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "dtls.h"
22

3+
#include "bio_frag.h"
4+
35
SSL_CTX *create_ctx(int dtls_srtp) {
46
SSL_CTX *ssl_ctx = SSL_CTX_new(DTLS_method());
57
if (ssl_ctx == NULL) {
@@ -33,19 +35,41 @@ SSL *create_ssl(SSL_CTX *ssl_ctx, int mode) {
3335
return NULL;
3436
}
3537

36-
BIO *rbio = BIO_new(BIO_s_mem());
37-
if (rbio == NULL) {
38-
DEBUG("Cannot create rbio");
38+
BIO *frag_bio = BIO_new(BIO_f_frag());
39+
if (frag_bio == NULL) {
40+
DEBUG("Cannot create frag bio");
3941
return NULL;
4042
}
4143

42-
BIO *wbio = BIO_new(BIO_s_mem());
43-
if (wbio == NULL) {
44-
DEBUG("Cannot create wbio");
44+
BIO *wmem_bio = BIO_new(BIO_s_mem());
45+
if (wmem_bio == NULL) {
46+
DEBUG("Cannot create write mem bio");
4547
return NULL;
4648
}
4749

48-
SSL_set_bio(ssl, rbio, wbio);
50+
BIO *wchain = BIO_push(frag_bio, wmem_bio);
51+
52+
BIO *rmem_bio = BIO_new(BIO_s_mem());
53+
if (rmem_bio == NULL) {
54+
DEBUG("Cannot create read mem bio");
55+
return NULL;
56+
}
57+
58+
// #TODO Move to the BIO_s_dgram_mem once we require OpenSSL 3
59+
// BIO *rbio = BIO_new(BIO_s_dgram_mem());
60+
// if (rbio == NULL) {
61+
// DEBUG("Cannot create read dgram mem bio");
62+
// return NULL;
63+
// }
64+
65+
// BIO *wbio = BIO_new(BIO_s_dgram_mem());
66+
// if (wbio == NULL) {
67+
// DEBUG("Cannot create write dgram mem bio");
68+
// return NULL;
69+
// }
70+
71+
SSL_set_bio(ssl, rmem_bio, wchain);
72+
// SSL_set_bio(ssl, rbio, wbio);
4973

5074
return ssl;
5175
}

0 commit comments

Comments
 (0)