Coder Social home page Coder Social logo

nplab / dtls-examples Goto Github PK

View Code? Open in Web Editor NEW
134.0 6.0 52.0 760 KB

Examples for DTLS via SCTP and UDP using OpenSSL

License: BSD 3-Clause "New" or "Revised" License

C 98.40% Makefile 0.93% Shell 0.67%
dtls sctp udp openssl freebsd tutorial macos linux ubuntu

dtls-examples's Introduction

DTLS Examples for OpenSSL

This repository contains examples for DTLS via SCTP and UDP. Each application in src can be used as client or server.

Our examples are developed against the OpenSSL 1.1.x API.

Use OpenSSL Version 1.1.1a or higher.

SCTP/UDP Examples

DTLS Echo Server and Client
This sample includes a multi-threaded echo server and client sending messages over an SCTP/UDP connection encrypted with DTLS.

Usage: dtls_(udp|sctp)_echo [options] [address]
Options:
        -l      message length (default: 100 Bytes)
        -L      local address
        -p      port (default: 23232)
        -n      number of messages to send (default: 5)
        -v      verbose
        -V      very verbose

DTLS Character Generator Server and Client
This sample includes a multi-threaded character generator server and client sending as many messages as possible to each other over an SCTP/UDP connection encrypted with DTLS for a given time. Statistics how many messages have been sent and received and how many got lost are printed at the end.

Usage: dtls_(udp|sctp)_chargen [options] [address]
Options
        -l      message length (default: 100 Bytes)
        -L      local address
        -s      streams (default: 5, sctp only)
        -p      port (default: 23232)
        -t      time to send (default: 10 sec)
        -u      unordered (sctp only)
        -v      verbose
        -V      very verbose

DTLS Discard Server and Client
This sample includes a multi-threaded discard server and client sending messages over an SCTP/UDP connection encrypted with DTLS.

Usage: dtls_(udp|sctp)_discard [options] [address]
Options:
        -l      message length (Default: 100 Bytes)
        -L      local address
        -s      streams (default: 5, sctp only)
        -p      port (default: 23232)
        -t      time to send (Default: 10 sec)
        -u      unordered (sctp only)
        -v      verbose
        -V      very verbose

OS Requirements

FreeBSD

Since FreeBSD 12.0, the built-in OpenSSL version is sufficient to run the UDP examples.
The SCTP examples and older versions of FreeBSD require OpenSSL to be installed via pkg or from scratch.
For FreeBSD 12.0 and 11.2, the OpenSSL 1.1.1 package from pkg is openssl111.

$ pkg install openssl111

Linux (Ubuntu)

The UDP examples should work with recent Linux distributions out-of-the-box. In order to run the SCTP examples, OpenSSL has to be built from scratch with SCTP support.

  • Install the SCTP headers.
sudo apt-get install libsctp-dev
  • Download the recent OpenSSL version.
    This example has been tested with OpenSSL 1.1.1a and Ubuntu 18.10.
  • Configure OpenSSL to include SCTP support and (optionally) set a custom install prefix.
  • Build and install OpenSSL.
$ ./config sctp --prefix=$HOME/my-openssl/
$ make
$ make install

In addition to a loaded SCTP module, Linux requires SCTP AUTH support.

$ modprobe sctp
$ sysctl -w net.sctp.auth_enable=1

macOS

If you only want to run the UDP examples, prebuilt OpenSSL binaries can be installed via brew.

$ brew install [email protected]

A SCTP enabled OpenSSL version has to be compiled from source, follow the tutorial in the Linux section. Since macOS does not support SCTP out of the box, it is necessary to use the SCTP NKE.

Build the Examples

Before calling make in the src directory, it may be necessary to specify custom library and include paths. This is either done by modifying the Makefile or by providing the path as a command line argument. It is also possible to only build SCTP or UDP examples.

$ make
$ make sctp  # only SCTP examples
$ make udp  # only UDP examples

OpenSSL Certificates

In order to run the example programs, the required server and client certificates should be located in a certs subfolder.

  • client-cert.pem
  • client-key.pem
  • server-cert.pem
  • server-key.pem

The following commands create signed certificates for client and server of the samples above.

touch ca-db-index
echo 01 > ca-db-serial

# Certificate Authority
openssl req -nodes -x509 -newkey rsa:2048 -days 365 -keyout ca-key.pem -out ca-cert.pem

# Server Certificate
openssl req -nodes -new -newkey rsa:2048 -keyout server-key.pem -out server.csr

# Sign Server Certificate
openssl ca -config ca.conf -days 365 -in server.csr -out server-cert.pem

# Client Certificate
openssl req -nodes -new -newkey rsa:2048 -keyout client-key.pem -out client.csr

# Sign Client Certificate
openssl ca -config ca.conf -days 365 -in client.csr -out client-cert.pem

You can create your own ca.conf file or use a minimal sample.

Usage with OpenSSL s_client / s_server

The examples are not limited to be used with each other, they may also be used with the built-in OpenSSL application.

The example below starts a SCTP echo server. The client connects via OpenSSL's s_client application and sends input read from stdin to the server. The server echos received messages.

$ dtls_sctp_echo -V -L 127.0.0.1
$ openssl s_client -sctp -dtls -connect 127.0.0.1:23232

dtls-examples's People

Contributors

liuqun avatar tuexen avatar weinrank avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

dtls-examples's Issues

dtls comm can not work in windows7

communication is not possible after running the code. The client is stuck in ssl_connect and the server is stuck in ssl-accept.my environment is windows 7 64bits and vs2015 and openssl-1.1.1w.

Failed to build SCTP programs against Linux 5.0 kernel headers

On Ubuntu 19.04 with Linux 5.0 kernel,
the kernel header file /usr/include/linux/sctp.h added the following line:

#define SCTP_EVENT      127

This breaks the following code that rely on the SCTP_EVENT micro which were disabled in the past (Linux 4.18 kernel).

#ifdef SCTP_EVENT
memset(&event, 0, sizeof(event));
event.se_assoc_id = SCTP_FUTURE_ASSOC;
event.se_on = 1;
for (i = 0; i < sizeof(event_types)/sizeof(uint16_t); i++) {
event.se_type = event_types[i];
if (setsockopt(fd, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(event)) < 0) {
perror("setsockopt");
}
}
#else
memset(&event, 1, sizeof(event));
if (setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) != 0) {
perror("set event failed");
}
#endif

On Ubuntu 19.04 I got such gcc error:

$ make
cc -std=c99 -pedantic -Wall -g -Wextra -Wno-unused-parameter -Wno-unused-function -Wno-overlength-strings -I/usr/local/include -o dtls_sctp_chargen dtls_sctp_chargen.c -L/usr/local/lib -lssl -lcrypto -pthread -lm -ldl
dtls_sctp_chargen.c: In function ‘start_server’:
dtls_sctp_chargen.c:586:23: error: ‘SCTP_FUTURE_ASSOC’ undeclared (first use in this function); did you mean ‘SCTP_RESET_ASSOC’?
   event.se_assoc_id = SCTP_FUTURE_ASSOC;
                       ^~~~~~~~~~~~~~~~~
                       SCTP_RESET_ASSOC
dtls_sctp_chargen.c:586:23: note: each undeclared identifier is reported only once for each function it appears in
...
$ uname -a
Linux vmware 5.0.0-15-generic #16-Ubuntu SMP Mon May 6 17:41:33 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

header file /usr/include/netinet/sctp.h provided by libsctp-dev relies on /usr/include/linux/sctp.h.

And there is NO definition of SCTP_FUTURE_ASSOC in any version of Linux kernel headers (4.18.x-5.0.x).

I guess the SCTP_FUTURE_ASSOC only came with freebsd kernel...

header file netinet/sctp.h is missing by default

I was testing under Ubuntu 19.04, and got such gcc errors:

DTLS-Examples/src$ make
cc -std=c99 -pedantic -Wall -g -Wextra -Wno-unused-parameter -Wno-unused-function -Wno-overlength-strings -I/usr/local/include -o dtls_sctp_chargen dtls_sctp_chargen.c -L/usr/local/lib -lssl -lcrypto -pthread -lm -ldl
dtls_sctp_chargen.c:48:10: fatal error: netinet/sctp.h: No such file or directory
 #include <netinet/sctp.h>
          ^~~~~~~~~~~~~~~~
compilation terminated.
make: *** [Makefile:21: dtls_sctp_chargen] Error 1

suggestion:

sudo apt-get install libsctp-dev
$ dpkg-query --listfiles libsctp-dev
/usr/include/netinet
/usr/include/netinet/sctp.h
/usr/lib
/usr/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu/libsctp.a
/usr/lib/x86_64-linux-gnu/pkgconfig
/usr/lib/x86_64-linux-gnu/pkgconfig/libsctp.pc
...

SCTP AUTH may be disabled in kernel

I've followed all the README steps, but got the next error:

$ LD_LIBRARY_PATH=/opt/openssl/lib ./dtls_sctp_echo 
139858668435264:error:20091002:BIO routines:BIO_new_dgram_sctp:system lib:crypto/bio/bss_dgram.c:844:Ensure SCTP AUTH chunks are enabled in kernel

As pointed here: openssl/openssl#8582 (comment), this message shows that SCTP AUTH chuncks are disabled in the kernel.

I suggest to add to README recommendation to check that /proc/sys/net/sctp/auth_enable contains 1. Otherwise, to run

sysctl -w net.sctp.auth_enable=1

as root.

DTLS server在windows系统中不支持多client同时连入

windows不支持UDP的端口复用,所以在Linux中server支持多client同时连接,握手和通信,但是winodws中server只能支持一个client的访问。我尝试用了一个很复杂的办法解决这个问题,最终成功了。
我是在localhost上开启了多个server,每个server只为一个client提供服务。又做了一个udp的转发模块,监听一个外部端口,将所有的通信按照ip+port进行向内转发,同时内部server回复的所有消息也按照同样的规则向外转发。这样对外模拟出一个支持多client同时接入的server

SCTP examples segfault on Ubuntu 18.10

➜  ~ uname -a
Linux wks1 4.18.0-13-generic #14-Ubuntu SMP Wed Dec 5 09:04:24 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
➜  ~ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 18.10
Release:	18.10
Codename:	cosmic
➜  src git:(refurbish) ✗ LD_LIBRARY_PATH=~/openssl/lib /home/weinrank/openssl/bin/openssl version
OpenSSL 1.1.1b-dev  xx XXX xxxx
➜  src git:(refurbish) ✗ LD_LIBRARY_PATH=~/openssl/lib valgrind ./dtls_sctp_chargen 212.201.121.83
==31897== Memcheck, a memory error detector
==31897== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==31897== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==31897== Command: ./dtls_sctp_chargen 212.201.121.83
==31897==
==31897== Invalid read of size 8
==31897==    at 0x498C450: BIO_method_type (in /home/weinrank/openssl/lib/libcrypto.so.1.1)
==31897==    by 0x4991528: BIO_dgram_is_sctp (in /home/weinrank/openssl/lib/libcrypto.so.1.1)
==31897==    by 0x48962DF: state_machine.part.5 (in /home/weinrank/openssl/lib/libssl.so.1.1)
==31897==    by 0x4880EC3: SSL_do_handshake (in /home/weinrank/openssl/lib/libssl.so.1.1)
==31897==    by 0x10C347: start_client (dtls_sctp_chargen.c:778)
==31897==    by 0x10D04F: main (dtls_sctp_chargen.c:1021)
==31897==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==31897==
==31897==
==31897== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==31897==  Access not within mapped region at address 0x0
==31897==    at 0x498C450: BIO_method_type (in /home/weinrank/openssl/lib/libcrypto.so.1.1)
==31897==    by 0x4991528: BIO_dgram_is_sctp (in /home/weinrank/openssl/lib/libcrypto.so.1.1)
==31897==    by 0x48962DF: state_machine.part.5 (in /home/weinrank/openssl/lib/libssl.so.1.1)
==31897==    by 0x4880EC3: SSL_do_handshake (in /home/weinrank/openssl/lib/libssl.so.1.1)
==31897==    by 0x10C347: start_client (dtls_sctp_chargen.c:778)
==31897==    by 0x10D04F: main (dtls_sctp_chargen.c:1021)
==31897==  If you believe this happened as a result of a stack
==31897==  overflow in your program's main thread (unlikely but
==31897==  possible), you can try to increase the size of the
==31897==  main thread stack using the --main-stacksize= flag.
==31897==  The main thread stack size used in this run was 8388608.
==31897== Invalid read of size 8
==31897==    at 0x4DF3B89: check_free (dlerror.c:188)
==31897==    by 0x4DF3B89: free_key_mem (dlerror.c:218)
==31897==    by 0x4DF3B89: __dlerror_main_freeres (dlerror.c:236)
==31897==    by 0x4D99A41: __libc_freeres (in /lib/x86_64-linux-gnu/libc-2.28.so)
==31897==    by 0x482D19E: _vgnU_freeres (in /usr/lib/valgrind/vgpreload_core-amd64-linux.so)
==31897==    by 0x4991528: BIO_dgram_is_sctp (in /home/weinrank/openssl/lib/libcrypto.so.1.1)
==31897==    by 0x48962DF: state_machine.part.5 (in /home/weinrank/openssl/lib/libssl.so.1.1)
==31897==    by 0x4880EC3: SSL_do_handshake (in /home/weinrank/openssl/lib/libssl.so.1.1)
==31897==    by 0x10C347: start_client (dtls_sctp_chargen.c:778)
==31897==    by 0x10D04F: main (dtls_sctp_chargen.c:1021)
==31897==  Address 0x4e0d738 is 12 bytes after a block of size 12 alloc'd
==31897==    at 0x483774F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==31897==    by 0x4A63768: CRYPTO_zalloc (in /home/weinrank/openssl/lib/libcrypto.so.1.1)
==31897==    by 0x4A5F33D: ossl_init_thread_start (in /home/weinrank/openssl/lib/libcrypto.so.1.1)
==31897==    by 0x4A3910B: ERR_get_state (in /home/weinrank/openssl/lib/libcrypto.so.1.1)
==31897==    by 0x4A39675: ERR_clear_error (in /home/weinrank/openssl/lib/libcrypto.so.1.1)
==31897==    by 0x4A5E9A8: ossl_init_engine_dynamic_ossl_ (in /home/weinrank/openssl/lib/libcrypto.so.1.1)
==31897==    by 0x4BF70C6: __pthread_once_slow (pthread_once.c:116)
==31897==    by 0x4AD1078: CRYPTO_THREAD_run_once (in /home/weinrank/openssl/lib/libcrypto.so.1.1)
==31897==    by 0x4A5F26B: OPENSSL_init_crypto (in /home/weinrank/openssl/lib/libcrypto.so.1.1)
==31897==    by 0x49C983D: openssl_config_int (in /home/weinrank/openssl/lib/libcrypto.so.1.1)
==31897==    by 0x4A5EA3F: ossl_init_config_ossl_ (in /home/weinrank/openssl/lib/libcrypto.so.1.1)
==31897==    by 0x4BF70C6: __pthread_once_slow (pthread_once.c:116)
==31897==
==31897==
==31897== HEAP SUMMARY:
==31897==     in use at exit: 152,952 bytes in 3,797 blocks
==31897==   total heap usage: 4,882 allocs, 1,085 frees, 295,219 bytes allocated
==31897==
==31897== LEAK SUMMARY:
==31897==    definitely lost: 0 bytes in 0 blocks
==31897==    indirectly lost: 0 bytes in 0 blocks
==31897==      possibly lost: 0 bytes in 0 blocks
==31897==    still reachable: 152,952 bytes in 3,797 blocks
==31897==         suppressed: 0 bytes in 0 blocks
==31897== Rerun with --leak-check=full to see details of leaked memory
==31897==
==31897== For counts of detected and suppressed errors, rerun with: -v
==31897== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

OpenSSL is thread-safe but multiple threads should not read from the same UDP socket fd concurrently

The dtls_udp_echo server is a multi-threaded application, but things get weird when 2 server threads
are running together.

For example, I start 1 echo server, then start 2 client process:

# Echo server
/dtls_udp_echo -L 127.0.0.1 -p 23232 -v
# Then in another terminal, start 2 clients concurrently
./dtls_udp_echo -p 23232 127.0.0.1 & ./dtls_udp_echo -p 23232 127.0.0.1

I have been testing whether it could serve 2 or more clients concurrently. The tcpdump/wireshark packet sniffer shows that the DTLS handshake would be disturbed when 2 threads are running together, and only the first client can complete the DTLS handshake with the echo server.

There is a question in openssl's offical FAQ page:

  • Is OpenSSL thread-safe?
    Yes but with some limitations; for example, an SSL connection cannot be used concurrently by multiple threads. This is true for most OpenSSL objects.
    For version 1.1.0 and later, there is nothing further you need do.
    For earlier versions than 1.1.0, it is necessary for your application to set up the thread callback functions. To do this, your application must call CRYPTO_set_locking_callback(3) and one of the CRYPTO_THREADID_set... API's. See the OpenSSL threads manpage for details and "note on multi-threading" in the INSTALL file in the source distribution.

The following code does create different SSL connection for each thread, and each SSL connection has its own BIO buffer. But it doesn't work as expected when 2 clients connect to the same echo server concurrently.

int start_server()
{
        fd = socket(server_addr.ss.ss_family, SOCK_DGRAM, 0);
        //...
	if (server_addr.ss.ss_family == AF_INET) {
		bind(fd, (const struct sockaddr *) &server_addr, sizeof(struct sockaddr_in));
	} else {
		setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&off, sizeof(off));
		bind(fd, (const struct sockaddr *) &server_addr, sizeof(struct sockaddr_in6));
	}
        //...
       	while (1) {
		memset(&client_addr, 0, sizeof(struct sockaddr_storage));

		/* Create BIO */
		bio = BIO_new_dgram(fd, BIO_NOCLOSE);

		/* Set and activate timeouts */
		timeout.tv_sec = 5;
		timeout.tv_usec = 0;
		BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);

		ssl = SSL_new(ctx);

		SSL_set_bio(ssl, bio, bio);
		SSL_set_options(ssl, SSL_OP_COOKIE_EXCHANGE);

		while (DTLSv1_listen(ssl, (BIO_ADDR *) &client_addr) <= 0){
			;
		}

		info = (struct pass_info*) malloc (sizeof(struct pass_info));
		memcpy(&info->server_addr, &server_addr, sizeof(struct sockaddr_storage));
		memcpy(&info->client_addr, &client_addr, sizeof(struct sockaddr_storage));
		info->ssl = ssl;

		if (pthread_create( &tid, NULL, connection_handle, info) != 0) {
			perror("pthread_create");
			exit(-1);
		}
	}
}

Here in the main loop of start_server(), all the bios share the same UDP socket fd to listen, even if each server thread has its own bio and ssl object.

In each service thread, connection_handle() builds a different socket fd and and update the bio to use the new fd.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.