├── .gitignore ├── certs ├── ca.tmpl ├── server.tmpl ├── ca-cert.pem ├── server-cert.pem ├── ca-key.pem └── server-key.pem ├── .gitmodules ├── merge_output.py ├── Makefile ├── plain_server.h ├── verify.h ├── connection.h ├── ktls.h ├── benchmark.h ├── xlibgnutls.h ├── generate_index.py ├── server.h ├── client.h ├── connection.c ├── action.h ├── common.h ├── benchmark.c ├── README.md ├── plain_server.c ├── xlibgnutls.c ├── ktls.c ├── common.c ├── server-main.c ├── benchmarks.sh ├── server.c ├── verify.c ├── LICENSE └── action.c /.gitignore: -------------------------------------------------------------------------------- 1 | client 2 | server 3 | *.o 4 | file_100MB.bin 5 | file_100kB.bin 6 | file_1MB.bin 7 | file_500MB.bin 8 | benchmarks 9 | -------------------------------------------------------------------------------- /certs/ca.tmpl: -------------------------------------------------------------------------------- 1 | cn = "VPN CA" 2 | organization = "Big Corp" 3 | serial = 1 4 | expiration_days = -1 5 | ca 6 | signing_key 7 | cert_signing_key 8 | crl_signing_key 9 | 10 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "af_ktls"] 2 | path = af_ktls 3 | url = https://github.com/fridex/af_ktls/ 4 | [submodule "af_ktls-visualize"] 5 | path = af_ktls-visualize 6 | url = https://github.com/fridex/af_ktls-visualize/ 7 | -------------------------------------------------------------------------------- /merge_output.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import json 3 | import sys 4 | 5 | out = [] 6 | for filename in sys.argv[2:]: 7 | with open(filename, 'r') as f: 8 | out = out + json.load(f) 9 | 10 | with open(sys.argv[1], 'w') as f: 11 | json.dump(out, f, sort_keys=True, separators=(',', ': '), indent = 2) 12 | f.write('\n') 13 | 14 | -------------------------------------------------------------------------------- /certs/server.tmpl: -------------------------------------------------------------------------------- 1 | cn = "VPN server" 2 | dns_name = "www.example.com" 3 | dns_name = "vpn1.example.com" 4 | organization = "MyCompany" 5 | expiration_days = -1 6 | signing_key 7 | encryption_key #only if the generated key is an RSA one 8 | tls_www_server 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -Wall -pedantic -O2 3 | LDFLAGS = -lgnutls -lpthread 4 | 5 | all: client server 6 | 7 | ktls.o: ktls.c 8 | ${CC} ${CFLAGS} ${LDFLAGS} $^ -c -o $@ 9 | 10 | client: client.c benchmark.c server.c verify.c common.c connection.c xlibgnutls.c ktls.o action.c plain_server.c 11 | ${CC} ${CLFLAGS} ${LDFLAGS} -DBENCHMARK_RECV $^ -o $@ 12 | 13 | server: server.c server-main.c common.c ktls.c plain_server.c 14 | ${CC} ${CFLAGS} ${LDFLAGS} $^ -o $@ 15 | 16 | insmod: 17 | (cd .. && make insmod) 18 | 19 | clean: 20 | rm -f *.o client server 21 | 22 | -------------------------------------------------------------------------------- /plain_server.h: -------------------------------------------------------------------------------- 1 | /* 2 | * af_ktls tool 3 | * 4 | * Copyright (C) 2016 Fridolin Pokorny 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by the Free 8 | * Software Foundation; either version 2 of the License, or (at your option) 9 | * any later version. 10 | */ 11 | 12 | #ifndef PLAIN_SERVER_H_ 13 | #define PLAIN_SERVER_H_ 14 | 15 | struct server_opts; 16 | 17 | extern int plain_udp_server(const struct server_opts *opts); 18 | extern int plain_tcp_server(const struct server_opts *opts); 19 | 20 | #endif // PLAIN_SERVER_H_ 21 | -------------------------------------------------------------------------------- /verify.h: -------------------------------------------------------------------------------- 1 | /* 2 | * af_ktls tool 3 | * 4 | * Copyright (C) 2016 Fridolin Pokorny 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by the Free 8 | * Software Foundation; either version 2 of the License, or (at your option) 9 | * any later version. 10 | */ 11 | 12 | #ifndef VERIFY_H_ 13 | #define VERIFY_H_ 14 | 15 | #include 16 | 17 | extern int verify_sendpage(int ksd, bool tls); 18 | extern int verify_transmission(int ksd); 19 | extern int verify_splice_read(int ksd); 20 | extern int verify_handling(int ksd, bool tls); 21 | 22 | #endif 23 | 24 | -------------------------------------------------------------------------------- /connection.h: -------------------------------------------------------------------------------- 1 | /* 2 | * af_ktls tool 3 | * 4 | * Copyright (C) 2016 Fridolin Pokorny 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by the Free 8 | * Software Foundation; either version 2 of the License, or (at your option) 9 | * any later version. 10 | */ 11 | 12 | #ifndef CONNECTION_H_ 13 | #define CONNECTION_H_ 14 | 15 | extern int udp_connect(const char *host, unsigned port); 16 | extern void udp_close(int sd); 17 | extern int tcp_connect(const char *host, unsigned port); 18 | extern void tcp_close(int sd); 19 | 20 | 21 | #endif /* CONNECTION_H_ */ 22 | 23 | -------------------------------------------------------------------------------- /ktls.h: -------------------------------------------------------------------------------- 1 | /* 2 | * af_ktls tool 3 | * 4 | * Copyright (C) 2016 Fridolin Pokorny 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by the Free 8 | * Software Foundation; either version 2 of the License, or (at your option) 9 | * any later version. 10 | */ 11 | 12 | #ifndef KTLS_H_ 13 | #define KTLS_H_ 14 | 15 | extern int ktls_socket_update_state(gnutls_session_t session, int ksd, bool tls); 16 | extern int ktls_socket_init(gnutls_session_t session, int sd, size_t sendfile_mtu, bool tls); 17 | extern int ktls_socket_destruct(int ksd, gnutls_session_t session); 18 | 19 | 20 | #endif // KTLS_H_ 21 | -------------------------------------------------------------------------------- /benchmark.h: -------------------------------------------------------------------------------- 1 | /* 2 | * af_ktls tool 3 | * 4 | * Copyright (C) 2016 Fridolin Pokorny 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by the Free 8 | * Software Foundation; either version 2 of the License, or (at your option) 9 | * any later version. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | typedef void (*sighandler_t)(int); 18 | 19 | struct benchmark_st 20 | { 21 | struct timeval start; 22 | sighandler_t old_handler; 23 | }; 24 | 25 | extern int benchmark_must_finish; 26 | 27 | int start_benchmark(struct benchmark_st * st, time_t secs); 28 | int stop_benchmark(struct benchmark_st * st, unsigned long * elapsed); 29 | 30 | -------------------------------------------------------------------------------- /xlibgnutls.h: -------------------------------------------------------------------------------- 1 | /* 2 | * af_ktls tool 3 | * 4 | * Copyright (C) 2016 Fridolin Pokorny 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by the Free 8 | * Software Foundation; either version 2 of the License, or (at your option) 9 | * any later version. 10 | */ 11 | 12 | #ifndef XLIBGNUTLS_H_ 13 | #define XLIBGNUTLS_H_ 14 | 15 | #include 16 | 17 | extern int xlibgnutls_dtls_handshake(gnutls_session_t *session, int udp_sd, unsigned verbose_level); 18 | extern int xlibgnutls_dtls_terminate(gnutls_session_t session); 19 | 20 | extern int xlibgnutls_tls_handshake(gnutls_session_t *session, int tcp_sd, unsigned verbose_level); 21 | extern int xlibgnutls_tls_terminate(gnutls_session_t session); 22 | 23 | #endif // XLIBGNUTLS_H_ 24 | 25 | -------------------------------------------------------------------------------- /generate_index.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import json 3 | import sys 4 | import os 5 | 6 | INDEX_NAME = "index.html" 7 | CPUINFO_FILE = "cpuinfo" 8 | 9 | index_pre = ''' 10 | 11 | 12 | 13 | 14 | AF_KTLS Benchmarks Index 15 | 16 | 17 |

AF_KTLS Benchmarks Index

18 |
    19 | ''' 20 | 21 | index_post = \ 22 | ''' 23 |
24 | 25 | 26 | ''' 27 | 28 | if len(sys.argv) != 2: 29 | raise ValueError("Expected directory as the first argument") 30 | 31 | index = os.path.join(sys.argv[1], INDEX_NAME) 32 | cpuinfo = os.path.join(sys.argv[1], CPUINFO_FILE) 33 | 34 | with open(index, 'w') as f: 35 | f.write(index_pre) 36 | dirnames = os.listdir(sys.argv[1]) 37 | dirnames.sort() 38 | 39 | for dirname in dirnames: 40 | if os.path.isdir(os.path.join(sys.argv[1], dirname)): 41 | f.write('
  • %s
  • \n' 42 | % (dirname, dirname)) 43 | 44 | 45 | with open(cpuinfo, 'r') as c: 46 | f.write('
    %s
    ' % c.read()) 47 | 48 | f.write(index_post) 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /server.h: -------------------------------------------------------------------------------- 1 | /* 2 | * af_ktls tool 3 | * 4 | * Copyright (C) 2016 Fridolin Pokorny 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by the Free 8 | * Software Foundation; either version 2 of the License, or (at your option) 9 | * any later version. 10 | */ 11 | 12 | #ifndef SERVER_H_ 13 | #define SERVER_H_ 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | #define SERVER_MAX_MTU (1 << 14) 23 | 24 | typedef struct { 25 | gnutls_session_t session; 26 | int fd; 27 | struct sockaddr *cli_addr; 28 | socklen_t cli_addr_size; 29 | } priv_data_st; 30 | 31 | struct server_opts { 32 | unsigned verbose_level; 33 | unsigned port; 34 | unsigned mtu; 35 | bool tls; 36 | int store_file; 37 | // used to contact client on which port is server running 38 | int *port_mem; 39 | // release this once server is up 40 | pthread_cond_t *condition_initialized; 41 | bool ktls; 42 | bool no_echo; 43 | bool raw_recv; 44 | /* without TLS options */ 45 | bool no_tls; 46 | bool tcp; 47 | }; 48 | 49 | extern int server_err; 50 | extern void *run_server(void *arg); 51 | 52 | #endif // SERVER_H_ 53 | 54 | -------------------------------------------------------------------------------- /certs/ca-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEBzCCAm+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAkMQ8wDQYDVQQDEwZWUE4g 3 | Q0ExETAPBgNVBAoTCEJpZyBDb3JwMCAXDTE2MDIwNzEzNDM0MloYDzk5OTkxMjMx 4 | MjM1OTU5WjAkMQ8wDQYDVQQDEwZWUE4gQ0ExETAPBgNVBAoTCEJpZyBDb3JwMIIB 5 | ojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAwsM2yf8gZJiQJFL06eoPgRYd 6 | BMGeOPx3FcfBViIF3kj2PqwxcmnFyO5r08TXQ/WzvmaKwp8fg1ct5co4CIgbOTs5 7 | 6r8iOhS2sOZmp+53eieb7ts7fPys3zIlVO3YzC5Cl2hjz9Nwac8/e6//AIHCP3MJ 8 | IqTdgR6r6NMq20MbbBjONB84v2AACSUfhlDlaPSqEDOPyu091/PSvCe9kHrQbaVV 9 | +JK7npCW/TM+vnCQ8xH0/kVh4JPQeH6N76Z0owL9/BL3eZ7TMv37zQ8qOVnd4SdN 10 | p8Cw5SYjLffVYb6MB0rnMeiBBQMIjKcDgDq1WyYgKp5VEGO9O7h0hNKE7XhEe+gP 11 | G3F7q4hVxMR9CHlHW2yQP1PX5EN1jVUjL05RLvTq+dRmuBk87K5UEbchthfLjIGd 12 | YrzEU7tvL3Zn++kICU5WoEbWGIQnJABS9miqQf1dUOTduMjSSn920BEz1V31h70t 13 | v9kiWTmpwtb/d2yQXUiby9ISfxOyCVObhM2kqHCjAgMBAAGjQjBAMA8GA1UdEwEB 14 | /wQFMAMBAf8wDgYDVR0PAQH/BAQDAgYAMB0GA1UdDgQWBBQMhvajZuD118a/bSYq 15 | fLDGynHx3zANBgkqhkiG9w0BAQsFAAOCAYEAPHw28tCKyy2lyIAJu6Kl8XFemNV5 16 | yziSr44rO1e+v6vGiKQLqe6DdmIZgIXE0OtL8eo4c+TVW2LmcdMF7lK3L4R46mJt 17 | sQRfxO5+8c3TGQQ7Qt0eQ3FTXsO3+m5PAlVbOauBdtvDtDs7/gqYGfYRMHcpVf1j 18 | rqhJTiBgIbw+N3t/ivuujUKUw+9F9tWjqBEmpe37vYoOEm6+KczCjQUY30QImcix 19 | v/kPmUF8WnDnHEz1+eSSiICfFejGwtETgmiYjZl2Fb4JL4s1t/6x1J870WdfW8CA 20 | 4sly3DKoX2QyOtqXREavyyXyJWNWFXkT9TJyM2Gj0Cabfd7MjmYVTK8Uw58dzV8h 21 | PukNErUrjd8FvUL9oN8LLLZqmeqtcB+t+uaAOXwQmsMRRcDIeBSIPqMoxM4f9dVn 22 | ZVA40+O0tlbCcsOfg2gHPIMzjGK2snhUph3U9TjD9yR/chKr/bpvQ2yJ3A+7WIyR 23 | IHUJBWHFBPYfMdctdDq7b88vdW1jr76kwEUG 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /certs/server-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEejCCAuKgAwIBAgIMVrdKLSgpibo9RB7+MA0GCSqGSIb3DQEBCwUAMCQxDzAN 3 | BgNVBAMTBlZQTiBDQTERMA8GA1UEChMIQmlnIENvcnAwIBcNMTYwMjA3MTM0NDEz 4 | WhgPOTk5OTEyMzEyMzU5NTlaMCkxEzARBgNVBAMTClZQTiBzZXJ2ZXIxEjAQBgNV 5 | BAoTCU15Q29tcGFueTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAPIW 6 | YKd58XJjHDAF2qXZ+JkKncocez0SYBY6C4b3XdeAi28AqnFKnZsHKrOnlVaeMdv8 7 | Ah1dfpt8mmEBqmYn9n5Yv/IXwDRSRbmOgmDRGCNGXwDuYk9kBJP9Z6eTlg52wcaZ 8 | tLAgFCVNVtXRXszBZC7BmSnAGIF28BTtpH2V8sc2PjN5ohSIZYZabRv5t/3Iaoo+ 9 | bIFtrRQhP/KnhwuTg5qLk540gdS9boRiFOBHFnb/UUCWGMg+TZTv6BJpSyXggjdU 10 | nfgi7T8j4FQhr3mwYi0zO7dcb/YlzZyCwFSfps1/8L0AswmbnT/x0dwgQUEUviz0 11 | uBKIqq+mTgkrlyLCMMthzOPDxnzB04aRPK9W+EKm5aBfg6ITN6vUgqzIunfxLmkU 12 | lBfCgUVX2Tz+sGecKIUWmIt0GleTknKRjTeXdOVUIbtIlzSJ9ngsVMgK3YblzA0B 13 | AU6qkkeM6G2BpcPQxiGW1nWEhH6l9CCpxxTmj2IFvHDELxSxQoYNWRgrKghl3QID 14 | AQABo4GkMIGhMAwGA1UdEwEB/wQCMAAwLAYDVR0RBCUwI4IPd3d3LmV4YW1wbGUu 15 | Y29tghB2cG4xLmV4YW1wbGUuY29tMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA4GA1Ud 16 | DwEB/wQEAwIGgDAdBgNVHQ4EFgQUYFzn2JxPtLOQ8vvMG2vUMDNIcWowHwYDVR0j 17 | BBgwFoAUDIb2o2bg9dfGv20mKnywxspx8d8wDQYJKoZIhvcNAQELBQADggGBABJn 18 | aOUqiGlcQg3t5JUSd6tiJ4DIRRoFK0ebHh1M7y/atleSoatY0b0Lohj4pO+Q6KDC 19 | 3I37pPIoypijqiLFj+YiNfa1ZQQkFHSjvxmZGC9+jQrfXNHbInS+N4fhycik4kng 20 | /5mn2COiwDaWrHiLMijvUXSHEOxDfgqwN13EMWeCOSxolsOueQgABL04Rv51Maip 21 | 8+TS+PG0T1pryHFv0aablewfs4f+p74/3yHABo8V4J3PKQnqrQQ8XmTADSw4AGJN 22 | BuYexmBQhcbrlmJ4r1KkXuN6enDD4a+RXI8Rz9Z/0PNkxvpV6AbHYnX6o3wnur4X 23 | rusmBOE0nmfG6AKsjnYbC3LBiY6rAdiKjyOJqaqnJwEXzWtABmOIjLEjrJCocGwa 24 | 9v5JI2fuG18ajAKI+30mmHQp4ZiLi9dB89KoieBX2La9Iy5+6CNKagoyP/Npqj0E 25 | dP5DAjUVPXowISWSbyYyGMSxx+9mXQuq5Wbjj2Qs//RKWLGNeogHfPTwvQqhIA== 26 | -----END CERTIFICATE----- 27 | -------------------------------------------------------------------------------- /client.h: -------------------------------------------------------------------------------- 1 | /* 2 | * af_ktls tool 3 | * 4 | * Copyright (C) 2016 Fridolin Pokorny 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by the Free 8 | * Software Foundation; either version 2 of the License, or (at your option) 9 | * any later version. 10 | */ 11 | 12 | #ifndef CLIENT_H_ 13 | #define CLIENT_H_ 14 | 15 | #include 16 | #include 17 | 18 | #define VERIFY_NONE (0) 19 | #define VERIFY_SENDPAGE (1 << 0) 20 | #define VERIFY_TRANSMISSION (1 << 1) 21 | #define VERIFY_SPLICE_READ (1 << 2) 22 | #define VERIFY_HANDLING (1 << 3) 23 | 24 | #define DO_DROP_CACHES(O) if (O->drop_caches) { if (do_drop_caches()) return -1; } 25 | 26 | struct client_opts { 27 | bool tls; 28 | bool tcp; 29 | const char *server_host; 30 | unsigned server_port; 31 | unsigned src_port; 32 | const char *sendfile; 33 | const char *sendfile_user; 34 | size_t sendfile_mtu; 35 | size_t sendfile_size; 36 | unsigned send_ktls_count; 37 | unsigned send_gnutls_count; 38 | unsigned payload_size; 39 | unsigned splice_count; 40 | unsigned verbose_level; 41 | const char *sendfile_mmap; 42 | time_t send_ktls_time; 43 | time_t send_gnutls_time; 44 | time_t splice_time; 45 | const char *splice_file; 46 | unsigned splice_echo_count; 47 | time_t splice_echo_time; 48 | bool json; 49 | bool drop_caches; 50 | int server_store; 51 | bool server_ktls; 52 | bool server_openssl; 53 | unsigned verify; 54 | const char *output; 55 | bool server_no_echo; 56 | unsigned server_mtu; 57 | unsigned raw_send_time; 58 | unsigned splice_send_raw_time; 59 | const char *plain_sendfile; 60 | const char *plain_sendfile_user; 61 | const char *plain_sendfile_mmap; 62 | const char *plain_splice_emu; 63 | }; 64 | 65 | extern int do_drop_caches(void); 66 | 67 | #endif // CLIENT_H_ 68 | 69 | -------------------------------------------------------------------------------- /connection.c: -------------------------------------------------------------------------------- 1 | /* 2 | * af_ktls tool 3 | * 4 | * Copyright (C) 2016 Fridolin Pokorny 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by the Free 8 | * Software Foundation; either version 2 of the License, or (at your option) 9 | * any later version. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "connection.h" 22 | 23 | extern int udp_connect(const char *host, unsigned port) 24 | { 25 | int err, sd, optval; 26 | struct sockaddr_in sa; 27 | 28 | sd = socket(AF_INET, SOCK_DGRAM, 0); 29 | 30 | memset(&sa, 0, sizeof(sa)); 31 | sa.sin_family = AF_INET; 32 | sa.sin_port = htons(port); 33 | inet_pton(AF_INET, host, &sa.sin_addr); 34 | 35 | #if defined(IP_DONTFRAG) 36 | optval = 1; 37 | setsockopt(sd, IPPROTO_IP, IP_DONTFRAG, (const void *) &optval, sizeof(optval)); 38 | #elif defined(IP_MTU_DISCOVER) 39 | optval = IP_PMTUDISC_DO; 40 | setsockopt(sd, IPPROTO_IP, IP_MTU_DISCOVER, (const void *) &optval, sizeof(optval)); 41 | #endif 42 | 43 | err = connect(sd, (struct sockaddr *) &sa, sizeof(sa)); 44 | return err ? err : sd; 45 | } 46 | 47 | extern void udp_close(int sd) { 48 | close(sd); 49 | } 50 | 51 | extern int tcp_connect(const char *host, unsigned port) { 52 | int err, sd; 53 | struct sockaddr_in sa; 54 | 55 | sd = socket(AF_INET, SOCK_STREAM, 0); 56 | 57 | memset(&sa, 0, sizeof(sa)); 58 | sa.sin_family = AF_INET; 59 | sa.sin_port = htons(port); 60 | inet_pton(AF_INET, host, &sa.sin_addr); 61 | 62 | err = connect(sd, (struct sockaddr *) &sa, sizeof(sa)); 63 | 64 | return err ? err : sd; 65 | } 66 | 67 | extern void tcp_close(int sd) { 68 | shutdown(sd, SHUT_RDWR); //no more receptions 69 | close(sd); 70 | } 71 | 72 | -------------------------------------------------------------------------------- /action.h: -------------------------------------------------------------------------------- 1 | /* 2 | * af_ktls tool 3 | * 4 | * Copyright (C) 2016 Fridolin Pokorny 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by the Free 8 | * Software Foundation; either version 2 of the License, or (at your option) 9 | * any later version. 10 | */ 11 | 12 | #ifndef ACTION_H_ 13 | #define ACTION_H_ 14 | 15 | struct client_opts; 16 | 17 | extern int do_send_count(const struct client_opts *opts, int ksd, void *mem, gnutls_session_t session, int flags); 18 | extern int do_send_time(const struct client_opts *opts, int ksd, void *mem, int flags); 19 | extern int do_gnutls_send_count(const struct client_opts *opts, gnutls_session_t session, void *mem); 20 | extern int do_gnutls_send_time(const struct client_opts *opts, gnutls_session_t session, void *mem); 21 | extern int do_splice_count(const struct client_opts *opts, int ksd); 22 | extern int do_splice_time(const struct client_opts *opts, int ksd); 23 | extern int do_splice_echo_time(const struct client_opts *opts, int ksd, void *mem); 24 | extern int do_splice_echo_count(const struct client_opts *opts, int ksd, void *mem); 25 | extern int do_sendfile_mmap(const struct client_opts *opts, gnutls_session_t session); 26 | extern int do_sendfile_user(const struct client_opts *opts, gnutls_session_t session); 27 | extern int do_sendfile(const struct client_opts *opts, int ksd); 28 | extern int do_raw_send_time(const struct client_opts *opts, gnutls_session_t session, int raw_sd, void *mem); 29 | extern int do_splice_send_raw_time(const struct client_opts *opts, int raw_sd, int ksd, void *mem); 30 | 31 | extern int do_plain_sendfile_user(const struct client_opts *otps, int sd); 32 | extern int do_plain_sendfile_mmap(const struct client_opts *opts, int sd); 33 | extern int do_plain_splice_emu(const struct client_opts *opts, int sd); 34 | extern int do_plain_sendfile(const struct client_opts *opts, int sd); 35 | 36 | #endif // ACTION_H_ 37 | -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * af_ktls tool 3 | * 4 | * Copyright (C) 2016 Fridolin Pokorny 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by the Free 8 | * Software Foundation; either version 2 of the License, or (at your option) 9 | * any later version. 10 | */ 11 | 12 | #ifndef COMMON_H_ 13 | #define COMMON_H_ 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #define UNUSED(X) ((void) X) 20 | 21 | #define VERBOSE_LEVEL_SILENT 0 22 | #define VERBOSE_LEVEL_CLIENT 1 23 | #define VERBOSE_LEVEL_SERVER VERBOSE_LEVEL_CLIENT 24 | #define VERBOSE_LEVEL_GNUTLS 2 25 | #define VERBOSE_LEVEL_PACKETS 3 26 | #define VERBOSE_LEVEL_ALL 4 27 | 28 | struct client_opts; 29 | struct server_opts; 30 | 31 | #define print_info(...) do_print_info(__FILE__, __LINE__, __VA_ARGS__) 32 | #define print_error(...) do_print_error(__FILE__, __LINE__, __VA_ARGS__) 33 | #define print_warning(...) do_print_warning(__FILE__, __LINE__, __VA_ARGS__) 34 | 35 | extern int do_print_error(const char *file, unsigned line, const char *fmt, ...); 36 | extern int do_print_info(const char *file, unsigned line, const char *fmt, ...); 37 | extern int do_print_warning(const char *file, unsigned line, const char *fmt, ...); 38 | 39 | extern int print_debug_client(const struct client_opts *opts, const char *fmt, ...); 40 | extern int print_debug_server(const struct server_opts *opts, const char *fmt, ...); 41 | extern int print_debug_tls(const struct client_opts *opts, const char *fmt, ...); 42 | extern void gnutls_log(int level, const char *msg); 43 | extern void print_hex(const char * data, size_t len); 44 | extern ssize_t gnutls_push_func_custom(gnutls_transport_ptr_t p, const void *data, size_t size); 45 | 46 | extern void print_stats(const char *fmt, ...); 47 | extern void print_stats_json(bool json); 48 | extern void print_stats_file(FILE *f); 49 | 50 | extern void print_init(void); 51 | extern void print_destruct(void); 52 | extern bool print_touched(void); 53 | extern bool print_touch_reset(void); 54 | 55 | #endif 56 | 57 | -------------------------------------------------------------------------------- /benchmark.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GnuTLS. 5 | * 6 | * GnuTLS is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * GnuTLS is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "benchmark.h" 27 | 28 | int benchmark_must_finish = 0; 29 | 30 | static void 31 | alarm_handler (int signo) 32 | { 33 | benchmark_must_finish = 1; 34 | } 35 | 36 | int start_benchmark(struct benchmark_st * st, time_t secs) 37 | { 38 | int ret; 39 | struct itimerval timer; 40 | 41 | memset(st, 0, sizeof(*st)); 42 | 43 | st->old_handler = signal (SIGPROF, alarm_handler); 44 | 45 | ret = gettimeofday (&st->start, NULL); 46 | if (ret < 0) { 47 | perror("gettimeofday"); 48 | return -1; 49 | } 50 | 51 | benchmark_must_finish = 0; 52 | 53 | memset(&timer, 0, sizeof(timer)); 54 | timer.it_value.tv_sec = secs; 55 | timer.it_value.tv_usec = 0; 56 | 57 | ret = setitimer(ITIMER_PROF, &timer, NULL); 58 | if (ret < 0) { 59 | perror("setitimer"); 60 | return -1; 61 | } 62 | 63 | return 0; 64 | } 65 | 66 | /* Returns -1 on error or 0 on success. 67 | * elapsed: the elapsed time in milliseconds 68 | */ 69 | int stop_benchmark(struct benchmark_st * st, unsigned long * elapsed) 70 | { 71 | unsigned long msecs; 72 | struct timeval stop; 73 | int ret; 74 | 75 | signal(SIGPROF, st->old_handler); 76 | 77 | ret = gettimeofday (&stop, NULL); 78 | if (ret < 0) 79 | return -1; 80 | 81 | msecs = (stop.tv_sec * 1000 + stop.tv_usec / 1000 - 82 | (st->start.tv_sec * 1000 + st->start.tv_usec / (1000))); 83 | 84 | if (elapsed) *elapsed = msecs; 85 | 86 | return 0; 87 | } 88 | 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Linux Kernel TLS/DTLS Socket Tool 2 | 3 | *Note that the implementation is under heavy development. Use on your own risk!* 4 | 5 | This tool is demonstrating usage, benchmarking and verifying the implementation 6 | of [AF_KTLS socket](https://github.com/fridex/af_ktls/). 7 | 8 | This tool consists of two parts - a client and a server. You can run server as 9 | a standalone process or you can run the server in a separate thread. Note that 10 | benchmarks use ```clock(3)``` to determine processor time, so you will be 11 | benchmarking server as well when run in a thread. 12 | 13 | The implementation is using Gnu TLS now. ```AF_KTLS``` currently support only 14 | AES GCM, but Gnu TLS and OpenSSL are sharing code for AES GCM cipher. 15 | 16 | Consider dropping caches by ```--drop-caches``` before each run to omit kernel 17 | caching impact. 18 | 19 | ## Scenarios 20 | 21 | There are two types of benchmarks: 22 | * ```*-count COUNT``` to send (and receive) specified number of records 23 | * ```*-time SECS``` to run scenario specified amount of time 24 | 25 | You can specify MTU by: 26 | * ```--payload``` to specify payload for ```send(2), recv(2)``` and 27 | ```splice(2)``` when ```AF_KTLS``` is destination socket 28 | * ```--sendfile-mtu``` to specify MTU when benchmarking ```sendfile(2)``` and 29 | ```splice(2)``` when ```AF_KTLS``` socket is destination socket 30 | (```sendpage()``` is called in the kernel) 31 | 32 | To evaluate speed impact, there were designed following scenarios: 33 | 34 | ### Send 35 | 36 | This scenario can be run by supplying ```--send-{gnutls,ktls}-{time,count}```. 37 | In this case you will test Gnu TLS and ```AF_KTLS``` sending and receiving (if 38 | compiled with ```BENCHMARK_RECV``` defined) - to be more concrete ```send(2)``` 39 | and ```recv(2)``` calls. 40 | 41 | 42 | ### Splice 43 | 44 | By supplying ```--splice-{count,time}``` you can splice a file (by default 45 | ```/dev/zero``` is used to omit hard disk drive and file system impact. 46 | A content is read from a file, written to a pipe and transmitted from pipe to 47 | a ```AF_KTLS``` socket. 48 | 49 | ### Splice Echo 50 | 51 | This scenario can be run by supplying ```--splice-echo-{time,count}```. This 52 | scenario uses ```splice(2)``` to read from ```AF_KTLS``` socket, write to 53 | a pipe, read from a pipe and write to ```AF_KTLS``` socket again. 54 | 55 | ### Send a File 56 | 57 | You can send a file using ```sendfile(2)``` or you can do ```recv(2)``` 58 | - encrypt in userspace -- ```send(2)```. For benchmarking ```sendfile(2)``` 59 | supply ```--sendfile FILE```, for use space encryption, supply ```--sendfile-buf 60 | FILE```. If you want to specify MTU, for ```sendfile(2)```, specify 61 | ```--sendfile-mtu MTU```, for user space encryption, you have to adjust payload 62 | by ```--payload BYTES```. Please note that ```AF_KTLS``` is computing MTU with 63 | TLS/DTLS overhead. That means that if you supply MTU 1400 for a TLS, the data 64 | carried within one packet will be 1400 - sizeof(tls_overhead) (1400 - 5 (header) 65 | - 8 (iv) - 16(tag) for TLS and 1400 - 13 (header) - 8(iv) - 16(tag)). 66 | 67 | ## Verifying Implementation 68 | 69 | There is implemented a test suite. You can access it by supplying 70 | ```--verify-sendpage``` (```sendpage()``` implmenetation in the kernel), 71 | ```--verify-transmission``` (```send(2)``` and ```recv(2)```), 72 | ```--verify-splice-read``` (```splice_read()``` implementation in the kernel) 73 | and ```--verify-handling``` (```getsockopt(2)```, ```setsockopt(2)``` and basic 74 | socket operatiosn). 75 | 76 | ## Help 77 | 78 | To see all available options, see ```--help```. Feel free to visit 79 | [issues](https://github.com/fridex/af_ktls-tool/issues) page as well. 80 | 81 | See also [AF_KTLS](https://github.com/fridex/af_ktls), [AF_KTLS 82 | visualize](https://github.com/fridex/af_ktls-visualize). 83 | 84 | -------------------------------------------------------------------------------- /plain_server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * af_ktls tool 3 | * 4 | * Copyright (C) 2016 Fridolin Pokorny 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by the Free 8 | * Software Foundation; either version 2 of the License, or (at your option) 9 | * any later version. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "server.h" 23 | #include "plain_server.h" 24 | 25 | #define BUFSIZE 65535 26 | 27 | extern int plain_tcp_server(const struct server_opts *opts) { 28 | int err; 29 | int sd = 0; 30 | int sd_client = 0; 31 | socklen_t slen = sizeof(struct sockaddr_in); 32 | struct sockaddr_in si_me , si_other; 33 | char *buf = NULL; 34 | 35 | sd = socket(AF_INET , SOCK_STREAM , 0); 36 | if (sd == -1) { 37 | perror("socket"); 38 | err = sd; 39 | goto end; 40 | } 41 | 42 | si_me.sin_family = AF_INET; 43 | si_me.sin_addr.s_addr = INADDR_ANY; 44 | si_me.sin_port = htons(opts->port); 45 | 46 | err = bind(sd,(struct sockaddr *)&si_me , sizeof(si_me)); 47 | 48 | if (err < 0) { 49 | perror("bind"); 50 | goto end; 51 | } 52 | 53 | listen(sd , 128); 54 | 55 | buf = malloc(BUFSIZE); 56 | if (!buf) { 57 | perror("malloc"); 58 | goto end; 59 | } 60 | 61 | if (opts->condition_initialized) { 62 | // TODO: get actual port 63 | if (opts->port_mem) 64 | *opts->port_mem = opts->port; 65 | pthread_cond_broadcast(opts->condition_initialized); 66 | } 67 | 68 | sd_client = accept(sd, (struct sockaddr *)&si_other, (socklen_t*)&slen); 69 | if (sd_client < 0) { 70 | perror("accept"); 71 | goto end; 72 | } 73 | 74 | for (;;) { 75 | err = recv(sd_client, buf, BUFSIZE, 0); 76 | if (err < 0) { 77 | perror("recv"); 78 | goto end; 79 | } 80 | 81 | if (err == 0) 82 | break; 83 | 84 | if (opts->store_file) 85 | write(opts->store_file, buf, err); 86 | 87 | if (!opts->no_echo) { 88 | 89 | err = send(sd_client, buf, err, 0); 90 | if (err < 0) { 91 | perror("send"); 92 | goto end; 93 | } 94 | } 95 | } 96 | 97 | end: 98 | if (buf) 99 | free(buf); 100 | 101 | if (sd > 0) 102 | close(sd); 103 | 104 | return err; 105 | } 106 | 107 | extern int plain_udp_server(const struct server_opts *opts) { 108 | int err; 109 | int sd = 0; 110 | char *buf = NULL; 111 | struct sockaddr_in si_me, si_other; 112 | socklen_t slen = sizeof(si_other); 113 | 114 | sd=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 115 | 116 | if (sd < 0) { 117 | perror("socket"); 118 | return sd; 119 | } 120 | 121 | memset((char *) &si_me, 0, sizeof(si_me)); 122 | si_me.sin_family = AF_INET; 123 | si_me.sin_port = htons(opts->port); 124 | si_me.sin_addr.s_addr = htonl(INADDR_ANY); 125 | 126 | err = bind(sd, (struct sockaddr*) &si_me, sizeof(si_me)); 127 | if (err < 0) { 128 | perror("bind"); 129 | goto end; 130 | } 131 | 132 | buf = malloc(BUFSIZE); 133 | if (!buf) { 134 | perror("malloc"); 135 | goto end; 136 | } 137 | 138 | if (opts->condition_initialized) { 139 | // TODO: get actual port 140 | if (opts->port_mem) 141 | *opts->port_mem = opts->port; 142 | pthread_cond_broadcast(opts->condition_initialized); 143 | } 144 | 145 | for (;;) { 146 | err = recvfrom(sd, buf, BUFSIZE, 0, (struct sockaddr*) &si_other, &slen); 147 | if (err < 0) { 148 | perror("recvfrom"); 149 | goto end; 150 | } 151 | 152 | if (err == 0) { 153 | break; 154 | } 155 | 156 | if (opts->store_file) 157 | write(opts->store_file, buf, err); 158 | 159 | if (!opts->no_echo) { 160 | err = sendto(sd, buf, err, 0, (struct sockaddr*) &si_other, slen); 161 | if (err < 0) { 162 | perror("sendto"); 163 | goto end; 164 | } 165 | } 166 | } 167 | 168 | end: 169 | if (sd > 0) 170 | close(sd); 171 | 172 | if (buf) 173 | free(buf); 174 | 175 | return err; 176 | } 177 | 178 | -------------------------------------------------------------------------------- /xlibgnutls.c: -------------------------------------------------------------------------------- 1 | /* 2 | * af_ktls tool 3 | * 4 | * Copyright (C) 2016 Fridolin Pokorny 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by the Free 8 | * Software Foundation; either version 2 of the License, or (at your option) 9 | * any later version. 10 | */ 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #include "common.h" 18 | 19 | #include "xlibgnutls.h" 20 | #include "connection.h" 21 | 22 | // this is ugly, but let's simplify things 23 | static gnutls_certificate_credentials_t xcred; 24 | static gnutls_anon_client_credentials_t anoncred; 25 | 26 | static int verify_certificate_callback(gnutls_session_t session) { 27 | return 0; 28 | } 29 | 30 | extern int xlibgnutls_dtls_handshake(gnutls_session_t *session, int udp_sd, unsigned verbose_level) { 31 | const char *CAFILE = "ca-cert.pem"; // TODO: use anoncred 32 | int ret; 33 | const char *err; 34 | 35 | if (gnutls_check_version("3.1.4") == NULL) { 36 | print_error("GnuTLS 3.1.4 or later is required"); 37 | return -1; 38 | } 39 | 40 | /* for backwards compatibility with gnutls < 3.3.0 */ 41 | gnutls_global_init(); 42 | 43 | if (verbose_level >= VERBOSE_LEVEL_GNUTLS) { 44 | gnutls_global_set_log_level(9999); 45 | gnutls_global_set_log_function(gnutls_log); 46 | } 47 | 48 | /* X509 stuff */ 49 | gnutls_certificate_allocate_credentials(&xcred); 50 | 51 | /* sets the trusted cas file */ 52 | gnutls_certificate_set_x509_trust_file(xcred, CAFILE, GNUTLS_X509_FMT_PEM); 53 | gnutls_certificate_set_verify_function(xcred, verify_certificate_callback); 54 | 55 | /* Initialize TLS session */ 56 | gnutls_init(session, GNUTLS_CLIENT | GNUTLS_DATAGRAM); 57 | 58 | /* put the x509 credentials to the current session */ 59 | gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE, xcred); 60 | gnutls_server_name_set(*session, GNUTLS_NAME_DNS, "my_host_name", strlen("my_host_name")); 61 | 62 | if (verbose_level >= VERBOSE_LEVEL_PACKETS) { 63 | gnutls_transport_set_push_function(*session, gnutls_push_func_custom); 64 | //gnutls_transport_set_pull_function(*session, gnutls_pull_func_custom); 65 | //gnutls_transport_set_pull_timeout_function(*session, gnutls_pull_timeout_func_custom); 66 | } 67 | 68 | gnutls_dtls_set_mtu(*session, 1 << 14); 69 | gnutls_set_default_priority(*session); 70 | /* if more fine-graned control is required */ 71 | ret = gnutls_priority_set_direct(*session, "NORMAL", &err); 72 | if (ret < 0) { 73 | if (ret == GNUTLS_E_INVALID_REQUEST) 74 | print_error("syntax error at: %d", err); 75 | goto end; 76 | } 77 | 78 | gnutls_transport_set_int(*session, udp_sd); 79 | gnutls_handshake_set_timeout(*session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); 80 | 81 | if (verbose_level >= VERBOSE_LEVEL_CLIENT) 82 | print_info("handshake started"); 83 | do { 84 | ret = gnutls_handshake(*session); 85 | } 86 | while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); 87 | /* Note that DTLS may also receive GNUTLS_E_LARGE_PACKET */ 88 | if (verbose_level >= VERBOSE_LEVEL_CLIENT) 89 | print_info("handshake finished"); 90 | 91 | if (ret < 0) { 92 | print_error("handshake failed with return code %d", ret); 93 | gnutls_perror(ret); 94 | goto end; 95 | } else { 96 | char *desc; 97 | desc = gnutls_session_get_desc(*session); 98 | if (verbose_level >= VERBOSE_LEVEL_CLIENT) 99 | print_info("session info: %s", desc); 100 | gnutls_free(desc); 101 | } 102 | 103 | ret = 0; 104 | 105 | end: 106 | return ret; 107 | } 108 | 109 | extern int xlibgnutls_dtls_terminate(gnutls_session_t session) { 110 | gnutls_bye(session, GNUTLS_SHUT_WR); 111 | 112 | gnutls_deinit(session); 113 | gnutls_certificate_free_credentials(xcred); 114 | gnutls_global_deinit(); 115 | 116 | return 0; 117 | } 118 | 119 | extern int xlibgnutls_tls_handshake(gnutls_session_t *session, int tcp_sd, unsigned verbose_level) { 120 | int ret, ii; 121 | /* Need to enable anonymous KX specifically. */ 122 | 123 | gnutls_global_init(); 124 | gnutls_anon_allocate_client_credentials(&anoncred); 125 | gnutls_init(session, GNUTLS_CLIENT); 126 | 127 | gnutls_priority_set_direct(*session, "NORMAL:+ANON-ECDH:+ANON-DH", NULL); 128 | gnutls_credentials_set(*session, GNUTLS_CRD_ANON, anoncred); 129 | gnutls_transport_set_int(*session, tcp_sd); 130 | gnutls_handshake_set_timeout(*session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); 131 | 132 | do { 133 | ret = gnutls_handshake(*session); 134 | } 135 | while (ret < 0 && gnutls_error_is_fatal(ret) == 0); 136 | 137 | if (ret < 0) { 138 | print_error("handshake failed"); 139 | gnutls_perror(ret); 140 | } else { 141 | char *desc; 142 | desc = gnutls_session_get_desc(*session); 143 | print_info("- Session info: %s\n", desc); 144 | gnutls_free(desc); 145 | } 146 | 147 | return ret; 148 | } 149 | 150 | extern int xlibgnutls_tls_terminate(gnutls_session_t session) { 151 | gnutls_bye(session, GNUTLS_SHUT_WR); 152 | 153 | gnutls_deinit(session); 154 | gnutls_anon_free_client_credentials(anoncred); 155 | gnutls_global_deinit(); 156 | 157 | return 0; 158 | } 159 | 160 | -------------------------------------------------------------------------------- /ktls.c: -------------------------------------------------------------------------------- 1 | /* 2 | * af_ktls tool 3 | * 4 | * Copyright (C) 2016 Fridolin Pokorny 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by the Free 8 | * Software Foundation; either version 2 of the License, or (at your option) 9 | * any later version. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "common.h" 17 | #include "af_ktls/af_ktls.h" 18 | 19 | #include "ktls.h" 20 | 21 | extern int ktls_socket_update_state(gnutls_session_t session, int ksd, bool tls) { 22 | int err; 23 | gnutls_datum_t mac_key; 24 | gnutls_datum_t iv_read; 25 | gnutls_datum_t iv_write; 26 | gnutls_datum_t cipher_key_read; 27 | gnutls_datum_t cipher_key_write; 28 | unsigned char seq_number_read[8]; 29 | unsigned char seq_number_write[8]; 30 | 31 | // now we need to initialize state after the handshake in the kernel 32 | err = gnutls_record_get_state(session, 1, &mac_key, &iv_read, &cipher_key_read, seq_number_read); 33 | if (err < 0) { 34 | print_error("failed to get receiving state from Gnu TLS session"); 35 | goto update_state_error; 36 | } 37 | 38 | err = gnutls_record_get_state(session, 0, &mac_key, &iv_write, &cipher_key_write, seq_number_write); 39 | if (err < 0) { 40 | print_error("failed to get sendig state from Gnu TLS session"); 41 | goto update_state_error; 42 | } 43 | 44 | err = setsockopt(ksd, AF_KTLS, KTLS_SET_SALT_SEND, iv_write.data, 4); 45 | if (err < 0) { 46 | perror("failed to set send salt on AF_KTLS socket using setsockopt(2)"); 47 | goto update_state_error; 48 | } 49 | 50 | err = setsockopt(ksd, AF_KTLS, KTLS_SET_SALT_RECV, iv_read.data, 4); 51 | if (err < 0) { 52 | perror("failed to set recv salt on AF_KTLS socket using setsockopt(2)"); 53 | goto update_state_error; 54 | } 55 | 56 | err = setsockopt(ksd, AF_KTLS, KTLS_SET_KEY_SEND, cipher_key_write.data, cipher_key_write.size); 57 | if (err < 0) { 58 | perror("failed to set send key on AF_KTLS socket using setsockopt(2)"); 59 | goto update_state_error; 60 | } 61 | 62 | err = setsockopt(ksd, AF_KTLS, KTLS_SET_KEY_RECV, cipher_key_read.data, cipher_key_read.size); 63 | if (err < 0) { 64 | perror("failed to set receive key on AF_KTLS socket using setsockopt(2)"); 65 | goto update_state_error; 66 | } 67 | 68 | err = setsockopt(ksd, AF_KTLS, KTLS_SET_IV_SEND, seq_number_write, 8); 69 | if (err < 0) { 70 | print_error("failed to set send IV on AF_KTLS socket using setsockopt(2)"); 71 | goto update_state_error; 72 | } 73 | 74 | /* 75 | * Gnu TLS this is a workaround since Gnu TLS does not propagate recv seq num 76 | * for DTLS. 77 | * It should be fixed in the new release (today is Apr 1 2016). Once fixed, 78 | * this has to be removed. 79 | */ 80 | if (!tls) { 81 | seq_number_read[1] = 1; 82 | seq_number_read[7] = 1; 83 | } 84 | 85 | err = setsockopt(ksd, AF_KTLS, KTLS_SET_IV_RECV, seq_number_read, 8); 86 | if (err < 0) { 87 | print_error("failed to set receive IV on AF_KTLS socket using setsockopt(2)"); 88 | goto update_state_error; 89 | } 90 | 91 | return 0; 92 | 93 | update_state_error: 94 | return err; 95 | } 96 | 97 | extern int ktls_socket_init(gnutls_session_t session, int sd, size_t sendfile_mtu, bool tls) { 98 | int err; 99 | struct sockaddr_ktls sa_ktls; 100 | 101 | int ksd = socket(AF_KTLS, tls ? SOCK_STREAM : SOCK_DGRAM, 0); 102 | if (ksd == -1) { 103 | perror("socket error:"); 104 | return -1; 105 | } 106 | 107 | sa_ktls.sa_cipher = KTLS_CIPHER_AES_GCM_128; 108 | sa_ktls.sa_socket = sd; // bind to this socket 109 | sa_ktls.sa_version = KTLS_VERSION_1_2; 110 | 111 | err = bind(ksd, (struct sockaddr *) &sa_ktls, sizeof(sa_ktls)); 112 | if (err < 0) { 113 | perror("failed to bind TCP/UCP socket"); 114 | goto init_error; 115 | } 116 | 117 | err = ktls_socket_update_state(session, ksd, tls); 118 | if (err < 0) 119 | goto init_error; 120 | 121 | if (sendfile_mtu) { 122 | err = setsockopt(ksd, AF_KTLS, KTLS_SET_MTU, &sendfile_mtu, sizeof(sendfile_mtu)); 123 | if (err < 0) { 124 | perror("setsockopt"); 125 | print_error("failed to set MTU on AF_KTLS socket using setsockopt(2)"); 126 | goto init_error; 127 | } 128 | } 129 | 130 | return ksd; 131 | 132 | init_error: 133 | close(ksd); 134 | return -1; 135 | } 136 | 137 | extern int ktls_socket_destruct(int ksd, gnutls_session_t session) { 138 | const int iv_len = 8; 139 | int err; 140 | unsigned char new_iv[iv_len]; 141 | 142 | err = getsockopt(ksd, AF_KTLS, KTLS_GET_IV_SEND, new_iv, (socklen_t *) &iv_len); 143 | if (err < 0) { 144 | perror("getsockopt"); 145 | print_error("failed to get send IV from AF_KTLS socket"); 146 | goto destruct_error; 147 | } 148 | 149 | // we set only sequence number 150 | err = gnutls_record_set_state(session, 0, new_iv); 151 | if (err) { 152 | print_error("failed to set send IV on Gnu TLS's session"); 153 | goto destruct_error; 154 | } 155 | 156 | err = getsockopt(ksd, AF_KTLS, KTLS_GET_IV_RECV, new_iv, (socklen_t *) &iv_len); 157 | if (err < 0) { 158 | print_error("failed to get receive IV from AF_KTLS socket"); 159 | goto destruct_error; 160 | } 161 | 162 | // we set only sequence number 163 | err = gnutls_record_set_state(session, 1, new_iv); 164 | if (err) { 165 | print_error("failed to set receive IV on Gnu TLS's session"); 166 | goto destruct_error; 167 | } 168 | 169 | close(ksd); 170 | return 0; 171 | 172 | destruct_error: 173 | // we close kernel TLS socket anyway... 174 | close(ksd); 175 | return -1; 176 | } 177 | 178 | -------------------------------------------------------------------------------- /common.c: -------------------------------------------------------------------------------- 1 | /* 2 | * af_ktls tool 3 | * 4 | * Copyright (C) 2016 Fridolin Pokorny 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by the Free 8 | * Software Foundation; either version 2 of the License, or (at your option) 9 | * any later version. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "client.h" 20 | #include "server.h" 21 | 22 | #include "common.h" 23 | 24 | /* 25 | * we want to be informed about printing, since printing effects 26 | * benchmarks 27 | */ 28 | static bool was_printed; 29 | 30 | /* 31 | * if server runs in a separate thread, we want to be thread safe 32 | */ 33 | pthread_mutex_t output_mutex; 34 | 35 | /* 36 | * if print_stats() should expect JSON to be printed 37 | */ 38 | static bool stats_json = false; 39 | /* 40 | * we need to handle JSON in special case since it starts with [, there are 41 | * comma separators, but last entry does not contain comma delimiter 42 | * true, if we have already printed some statistics in JSON 43 | * I know this is ugly, but for simplicity it is enough 44 | */ 45 | static bool stats_json_printed = false; 46 | 47 | static FILE *stats_file = NULL; 48 | 49 | extern int do_print_error(const char *file, unsigned line, const char *fmt, ...) { 50 | int ret; 51 | va_list va; 52 | 53 | va_start(va, fmt); 54 | 55 | pthread_mutex_lock(&output_mutex); 56 | 57 | fprintf(stderr, "ERR:%s:%u: ", file, line); 58 | ret = vfprintf(stderr, fmt, va); 59 | fputs("\n", stderr); 60 | 61 | was_printed = true; 62 | pthread_mutex_unlock(&output_mutex); 63 | 64 | va_end(va); 65 | return ret; 66 | } 67 | 68 | extern int do_print_info(const char *file, unsigned line, const char *fmt, ...) { 69 | int ret; 70 | va_list va; 71 | 72 | va_start(va, fmt); 73 | 74 | pthread_mutex_lock(&output_mutex); 75 | 76 | fprintf(stderr, "INFO:%s:%u: ", file, line); 77 | ret = vfprintf(stderr, fmt, va); 78 | fputs("\n", stderr); 79 | 80 | was_printed = true; 81 | pthread_mutex_unlock(&output_mutex); 82 | 83 | va_end(va); 84 | return ret; 85 | } 86 | 87 | extern void print_stats(const char *fmt, ...) { 88 | va_list va; 89 | va_start(va, fmt); 90 | 91 | if (!stats_file) { 92 | fprintf(stderr, "FATAL ERROR: print_init() not called\n"); 93 | assert(false); 94 | } 95 | 96 | pthread_mutex_lock(&output_mutex); 97 | 98 | if (stats_json) { 99 | if (!stats_json_printed) 100 | fprintf(stats_file, "[\n"); 101 | else 102 | fprintf(stats_file, ",\n"); 103 | 104 | vfprintf(stats_file, fmt, va); 105 | stats_json_printed = true; 106 | } else { 107 | fprintf(stats_file, "============ Benchmark statistics ============\n"); 108 | vfprintf(stats_file, fmt, va); 109 | fprintf(stats_file, "==============================================\n"); 110 | } 111 | 112 | // we do not set was_printed here, since these are actual statistics 113 | pthread_mutex_unlock(&output_mutex); 114 | 115 | va_end(va); 116 | } 117 | 118 | extern void print_stats_json(bool json) { 119 | stats_json = json; 120 | } 121 | 122 | extern int do_print_warning(const char *file, unsigned line, const char *fmt, ...) { 123 | int ret; 124 | va_list va; 125 | 126 | va_start(va, fmt); 127 | 128 | pthread_mutex_lock(&output_mutex); 129 | fprintf(stderr, "WARN:%s:%u: ", file, line); 130 | ret = vfprintf(stderr, fmt, va); 131 | fputs("\n", stderr); 132 | 133 | was_printed = true; 134 | pthread_mutex_unlock(&output_mutex); 135 | 136 | va_end(va); 137 | return ret; 138 | } 139 | 140 | extern int print_debug_client(const struct client_opts *opts, const char *fmt, ...) { 141 | int ret = 0; 142 | va_list va; 143 | 144 | if (opts->verbose_level >= VERBOSE_LEVEL_CLIENT) { 145 | va_start(va, fmt); 146 | 147 | pthread_mutex_lock(&output_mutex); 148 | fputs("DBG:CLIENT: ", stderr); 149 | ret = vfprintf(stderr, fmt, va); 150 | fputs("\n", stderr); 151 | 152 | was_printed = true; 153 | pthread_mutex_unlock(&output_mutex); 154 | 155 | va_end(va); 156 | } 157 | 158 | return ret; 159 | } 160 | 161 | extern int print_debug_server(const struct server_opts *opts, const char *fmt, ...) { 162 | int ret = 0; 163 | va_list va; 164 | 165 | if (opts->verbose_level >= VERBOSE_LEVEL_SERVER) { 166 | va_start(va, fmt); 167 | 168 | pthread_mutex_lock(&output_mutex); 169 | fputs("DBG:SERVER: ", stderr); 170 | ret = vfprintf(stderr, fmt, va); 171 | fputs("\n", stderr); 172 | 173 | was_printed = true; 174 | pthread_mutex_unlock(&output_mutex); 175 | 176 | va_end(va); 177 | } 178 | 179 | return ret; 180 | } 181 | 182 | extern int print_debug_tls(const struct client_opts *opts, const char *fmt, ...) { 183 | int ret = 0; 184 | va_list va; 185 | 186 | if (opts->verbose_level >= VERBOSE_LEVEL_CLIENT) { 187 | va_start(va, fmt); 188 | 189 | pthread_mutex_lock(&output_mutex); 190 | fputs("DBG:TLS: ", stderr); 191 | ret = vfprintf(stderr, fmt, va); 192 | fputs("\n", stderr); 193 | 194 | was_printed = true; 195 | pthread_mutex_unlock(&output_mutex); 196 | 197 | va_end(va); 198 | } 199 | 200 | return ret; 201 | } 202 | 203 | extern void gnutls_log(int level, const char *msg) { 204 | UNUSED(level); 205 | pthread_mutex_lock(&output_mutex); 206 | fprintf(stderr, "DBG:TLS-LIB: %s", msg); 207 | was_printed = true; 208 | pthread_mutex_unlock(&output_mutex); 209 | } 210 | 211 | extern void print_hex(const char * data, size_t len) { 212 | pthread_mutex_lock(&output_mutex); 213 | fputs("hex: ", stderr); 214 | for (size_t i = 0; i < len; i++) 215 | fprintf(stderr, "%02X", (unsigned char) data[i]); 216 | fputs("\n", stderr); 217 | was_printed = true; 218 | pthread_mutex_unlock(&output_mutex); 219 | } 220 | 221 | extern ssize_t gnutls_push_func_custom(gnutls_transport_ptr_t p, const void *data, size_t size) { 222 | int s = (int) p; 223 | int ret; 224 | 225 | print_hex(data, size); 226 | ret = send(s, data, size, 0); 227 | return ret; 228 | } 229 | 230 | extern void print_init(void) { 231 | was_printed = false; 232 | stats_json = false; 233 | stats_json_printed = false; 234 | stats_file = stdout; 235 | pthread_mutex_init(&output_mutex, NULL); 236 | } 237 | 238 | extern void print_stats_file(FILE *f) { 239 | stats_file = f; 240 | } 241 | 242 | extern void print_destruct(void) { 243 | if (stats_json && stats_json_printed) { // we have to terminate JSON 244 | fprintf(stats_file, "\n]\n"); 245 | } 246 | was_printed = false; 247 | stats_json = false; 248 | stats_json_printed = false; 249 | stats_file = stdout; 250 | pthread_mutex_destroy(&output_mutex); 251 | } 252 | 253 | extern bool print_touched(void) { 254 | return was_printed; 255 | } 256 | 257 | extern bool print_touch_reset(void) { 258 | bool old; 259 | 260 | old = was_printed; 261 | was_printed = false; 262 | return old; 263 | } 264 | 265 | -------------------------------------------------------------------------------- /server-main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * af_ktls tool 3 | * 4 | * Copyright (C) 2016 Fridolin Pokorny 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by the Free 8 | * Software Foundation; either version 2 of the License, or (at your option) 9 | * any later version. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "common.h" 24 | #include "server.h" 25 | 26 | #define OPT_TLS 't' 27 | #define OPT_DTLS 'd' 28 | #define OPT_PORT 'p' 29 | #define OPT_VERBOSE 'v' 30 | #define OPT_STORE 's' 31 | #define OPT_HELP 'h' 32 | #define OPT_KTLS 'k' 33 | #define OPT_NO_ECHO 'x' 34 | #define OPT_MTU 'm' 35 | #define OPT_RAW_RECV 'r' 36 | #define OPT_TCP 'c' 37 | #define OPT_UDP 'u' 38 | #define OPT_SHORT_OPTS "tdp:vs:hxm:cu" 39 | 40 | static struct option long_options[] = { 41 | /* -t */{"tls", no_argument, 0, OPT_TLS}, 42 | /* -d */{"dtls", no_argument, 0, OPT_DTLS}, 43 | /* -p */{"port", required_argument, 0, OPT_PORT}, 44 | /* -v */{"verbose", no_argument, 0, OPT_VERBOSE}, 45 | /* -s */{"store", required_argument, 0, OPT_STORE}, 46 | /* -h */{"help", no_argument, 0, OPT_HELP}, 47 | /* -k */{"ktls", no_argument, 0, OPT_KTLS}, 48 | /* -x */{"no-echo", no_argument, 0, OPT_NO_ECHO}, 49 | /* -m */{"mtu", required_argument, 0, OPT_MTU}, 50 | /* -r */{"raw-recv", no_argument, 0, OPT_RAW_RECV}, 51 | /* -c */{"tcp", no_argument, 0, OPT_TCP}, 52 | /* -u */{"udp", no_argument, 0, OPT_UDP}, 53 | {0, 0, 0, 0} 54 | }; 55 | static void print_help(char *progname) { 56 | static const char *help_msg = \ 57 | "Usage: %s OPTIONS\n" 58 | "Benchmark Gnu TLS and AL_TLS kernel implementation (echo server)\n" 59 | "\nOptions:\n\n" 60 | "\t--tls|-t benchmark TLS protocol\n" 61 | "\t--dtls|-d benchmark DTLS protocol; the default is TLS\n" 62 | "\t--port|-p benchmark DTLS protocol; the default is TLS\n" 63 | "\t--verbose|-v be verbose like an old lady at marketplace, can be used multiple times\n" 64 | "\t--store FILE|-s FILE store result to file FILE\n" 65 | "\t--ktls|-k use AF_KTLS for communication\n" 66 | "\t--no-echo do not echo data messages\n" 67 | "\t--raw_recv expect unencrypted data\n" 68 | "\t--mtu set MTU\n" 69 | "\t--tcp|-c use TCP (can be used only with --no-tls)\n" 70 | "\t--udp|-u use UDP (can be used only with --no-tls)\n" 71 | "\t--help|-h print this help\n\n"; 72 | 73 | assert(progname); 74 | printf(help_msg, progname); 75 | } 76 | 77 | static int parse_opts(struct server_opts *opts, int argc, char *argv[]) { 78 | int c; 79 | int idx = 0; 80 | char *tmp_ptr = NULL; 81 | bool protocol_seen = false; 82 | bool no_tls_protocol_seen = false; 83 | 84 | // assign default values at first 85 | opts->tls = true; 86 | opts->port = 0; 87 | opts->verbose_level = VERBOSE_LEVEL_SILENT; 88 | opts->store_file = 0; 89 | opts->store_file = 0; 90 | opts->ktls = false; 91 | opts->no_echo = false; 92 | opts->raw_recv = false; 93 | opts->no_tls = false; 94 | opts->tcp = true; 95 | opts->mtu = SERVER_MAX_MTU; 96 | // not used when standalone process 97 | opts->port_mem = NULL; 98 | opts->condition_initialized = NULL; 99 | 100 | for (;;) { 101 | c = getopt_long (argc, argv, OPT_SHORT_OPTS, long_options, &idx); 102 | 103 | if (c == -1) // we are done 104 | break; 105 | 106 | switch (c) { 107 | case OPT_TLS: 108 | if (protocol_seen && !opts->tls) { 109 | print_error("option --tls is disjoint with --dtls"); 110 | return 1; 111 | } 112 | if (no_tls_protocol_seen) { 113 | print_error("option --dtls/--tls is disjoint with --udp/--tcp"); 114 | return 1; 115 | } 116 | protocol_seen = true; 117 | opts->tls = true; 118 | opts->no_tls = false; 119 | break; 120 | case OPT_DTLS: 121 | if (protocol_seen && opts->tls) { 122 | print_error("option --dtls is disjoint with --tls"); 123 | return 1; 124 | } 125 | if (no_tls_protocol_seen) { 126 | print_error("option --dtls/--tls is disjoint with --udp/--tcp"); 127 | return 1; 128 | } 129 | protocol_seen = true; 130 | opts->tls = false; 131 | opts->no_tls = false; 132 | break; 133 | case OPT_TCP: 134 | if (no_tls_protocol_seen && !opts->tcp) { 135 | print_error("option --tcp is disjoint with --udp"); 136 | return 1; 137 | } 138 | if (protocol_seen) { 139 | print_error("option --tcp/--udp is disjoint with --tls/--dtls"); 140 | return 1; 141 | } 142 | no_tls_protocol_seen = true; 143 | opts->tcp = true; 144 | opts->no_tls = true; 145 | break; 146 | case OPT_UDP: 147 | if (no_tls_protocol_seen && opts->tcp) { 148 | print_error("option --udp is disjoint with --tcp"); 149 | return 1; 150 | } 151 | if (protocol_seen) { 152 | print_error("option --tcp/--udp is disjoint with --tls/--dtls"); 153 | return 1; 154 | } 155 | no_tls_protocol_seen = true; 156 | opts->tcp = false; 157 | opts->no_tls = true; 158 | break; 159 | case OPT_PORT: 160 | opts->port = strtoul(optarg, &tmp_ptr, 10); 161 | if (*tmp_ptr != '\0' || opts->port > 65535) { 162 | print_error("unknown port '%s'", optarg); 163 | return 1; 164 | } 165 | break; 166 | case OPT_MTU: 167 | opts->mtu = strtoul(optarg, &tmp_ptr, 10); 168 | if (*tmp_ptr != '\0' || opts->port > SERVER_MAX_MTU) { 169 | print_error("unknown mtu '%s'", optarg); 170 | return 1; 171 | } 172 | break; 173 | 174 | case OPT_STORE: 175 | if (opts->store_file) { 176 | print_error("multiple --store supplied"); 177 | return 1; 178 | } 179 | opts->store_file = open(optarg, O_WRONLY|O_CREAT|O_TRUNC); 180 | if (opts->store_file < 0) { 181 | perror(optarg); 182 | return 1; 183 | } 184 | break; 185 | case OPT_VERBOSE: 186 | if (opts->verbose_level < VERBOSE_LEVEL_ALL) 187 | opts->verbose_level++; 188 | break; 189 | case OPT_KTLS: 190 | opts->ktls = true; 191 | break; 192 | case OPT_RAW_RECV: 193 | opts->raw_recv = true; 194 | break; 195 | case OPT_NO_ECHO: 196 | opts->no_echo = true; 197 | break; 198 | case OPT_HELP: 199 | print_help(argv[0]); 200 | return 1; 201 | break; 202 | case '?': 203 | print_help(argv[0]); 204 | return 1; 205 | break; 206 | default: 207 | /* should be unreachable */ 208 | assert(&long_options); 209 | } 210 | } 211 | 212 | /* no additional arguments allowed */ 213 | if (optind < argc) { 214 | print_error("unknown argument supplied: %s", argv[optind]); 215 | print_help(argv[0]); 216 | return 1; 217 | } 218 | 219 | return 0; 220 | } 221 | 222 | static void print_opts(struct server_opts *opts) { 223 | if (opts->no_tls) { 224 | print_debug_server(opts, "protocol: %s", opts->tcp ? "TCP" : "UDP"); 225 | } else { 226 | print_debug_server(opts, "protocol: %s", opts->tls ? "TLS" : "DTLS"); 227 | } 228 | if (opts->port) 229 | print_debug_server(opts, "port: %u", opts->port); 230 | else 231 | print_debug_server(opts, "port: auto"); 232 | if (opts->store_file) 233 | print_debug_server(opts, "store to file: (fd) '%d'", opts->store_file); 234 | if (opts->ktls) 235 | print_debug_server(opts, "using AF_KTLS socket"); 236 | if (opts->no_echo) 237 | print_debug_server(opts, "server is not echoing data messages"); 238 | } 239 | 240 | int main(int argc, char *argv[]) { 241 | int err; 242 | struct server_opts opts; 243 | 244 | print_init(); 245 | 246 | err = parse_opts(&opts, argc, argv); 247 | if (err) 248 | return err; 249 | 250 | if (opts.verbose_level >= VERBOSE_LEVEL_SERVER) 251 | print_opts(&opts); 252 | 253 | run_server(&opts); 254 | 255 | if (opts.store_file) 256 | close(opts.store_file); 257 | 258 | print_destruct(); 259 | 260 | return server_err; 261 | } 262 | 263 | -------------------------------------------------------------------------------- /benchmarks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | OUTPUT_DIR=${OUTPUT_DIR:-benchmarks} 4 | FILE_100KB=${FILE_100KB:-file_100kB.bin} 5 | FILE_1MB=${FILE_1MB:-file_1MB.bin} 6 | FILE_100MB=${FILE_100MB:-file_100MB.bin} 7 | FILE_100MB=${FILE_100MB:-file_100MB.bin} 8 | FILE_500MB=${FILE_500MB:-file_500MB.bin} 9 | SERVER_PORT=${SERVER_PORT:-5557} 10 | SERVER_BIN=${SERVER_BIN:-./server} 11 | CLIENT_BIN=${CLIENT_BIN:-./client} 12 | BENCH_COUNT=${BENCH_COUNT:-5000} 13 | BENCH_TIME=${BENCH_TIME:-2} 14 | 15 | TLS_OVERHEAD=$((5 + 8 + 16)) 16 | DTLS_OVERHEAD=$((13 + 8 + 16)) 17 | 18 | CLIENT_EXEC="${CLIENT_BIN} --server-port ${SERVER_PORT} --server-host localhost --json --drop-caches" 19 | 20 | function xecho { 21 | echo ">>> $@" 22 | } 23 | 24 | function run_server { 25 | ${SERVER_BIN} --port ${SERVER_PORT} "$@" & 26 | } 27 | 28 | function stop_server { 29 | kill -9 %% 30 | } 31 | 32 | function run_client { 33 | sleep 2 # give server some time to spawn 34 | eval ${CLIENT_EXEC} $@ 35 | } 36 | 37 | [ `id -u` -eq 0 ] || { 38 | echo "This script has to be run under root due to cache drops" >&2 39 | exit 1 40 | } 41 | 42 | [ -d "${OUTPUT_DIR}" ] && { 43 | xecho "Removing old output file '${OUTPUT_DIR}'" 44 | rm -rf "${OUTPUT_DIR}" 45 | } 46 | 47 | mkdir -p "${OUTPUT_DIR}" 48 | 49 | xecho "Preparing files" 50 | [ -f "${FILE_100KB}" ] || dd if=/dev/urandom of="${FILE_100KB}" bs=1000 count=100 51 | [ -f "${FILE_1MB}" ] || dd if=/dev/urandom of="${FILE_1MB}" bs=1000 count=1000 52 | [ -f "${FILE_100MB}" ] || dd if=/dev/urandom of="${FILE_100MB}" bs=1000 count=100000 53 | [ -f "${FILE_500MB}" ] || dd if=/dev/urandom of="${FILE_500MB}" bs=1000 count=500000 54 | 55 | # we need to do comparison tests separately for Gnu TLS and AF_KTLS now because 56 | # Gnu TLS does not handle getting recv sequence number in DTLS, see xlibgnutls.c 57 | # 58 | # for details of how tests are implemented, see action.c 59 | # 60 | # TLS note: if running test where client does not collect data from server, 61 | # server has to be run with --no-echo, to avoid kernel recv stack to be 62 | # fulfilled 63 | for protocol in "--tls" "--dtls"; do 64 | for i in `seq 1 3`; do 65 | for payload in 1000 1280 1400 4000 6000 9000 13000 16000; do 66 | # AF_KTLS is using MTU for raw data, without TLS/DTLS packetization 67 | # overhead 68 | if [ "${protocol}" == "--tls" ]; then 69 | SENDFILE_MTU=$(( ${payload} + ${TLS_OVERHEAD} )) 70 | else 71 | SENDFILE_MTU=$(( ${payload} + ${DTLS_OVERHEAD} )) 72 | fi 73 | 74 | 75 | ########## sendfile(2) vs userspace buffered copy 76 | for file in "${FILE_100KB}" "${FILE_1MB}" "${FILE_100MB}" "${FILE_500MB}"; do 77 | TEST_OUTPUT_DIR="${OUTPUT_DIR}/sendfile-${file}-${payload}${protocol}" 78 | xecho "Performing benchmark, output: ${TEST_OUTPUT_DIR}" 79 | [ -d "${TEST_OUTPUT_DIR}" ] || mkdir "${TEST_OUTPUT_DIR}" 80 | 81 | run_server "${protocol}" --no-echo 82 | run_client "${protocol}" --sendfile "${file}" --sendfile-mtu ${SENDFILE_MTU} \ 83 | --sendfile-user ${file} --payload ${payload} \ 84 | --sendfile-mmap ${file} \ 85 | --output "${TEST_OUTPUT_DIR}/output.${i}.json" 86 | stop_server 87 | 88 | # now we will test without encryption 89 | if [ ${protocol} == "--dtls" ]; then 90 | plain_protocol="--udp" 91 | else 92 | plain_protocol="--tcp" 93 | fi 94 | 95 | TEST_OUTPUT_DIR="${OUTPUT_DIR}/plain-sendfile-${file}-${payload}${plain_protocol}" 96 | xecho "Performing benchmark, output: ${TEST_OUTPUT_DIR}" 97 | [ -d "${TEST_OUTPUT_DIR}" ] || mkdir "${TEST_OUTPUT_DIR}" 98 | 99 | run_server "${plain_protocol}" --no-echo 100 | run_client "${plain_protocol}" --sendfile-mtu ${payload} \ 101 | --plain-sendfile-user ${file} \ 102 | --plain-sendfile-mmap ${file} \ 103 | --plain-sendfile ${file} \ 104 | --plain-splice-emu ${file} \ 105 | --output "${TEST_OUTPUT_DIR}/output.${i}.json" 106 | stop_server 107 | done 108 | 109 | ########## sendmsg(2) and recvmsg(2) - COUNT 110 | TEST_OUTPUT_DIR="${OUTPUT_DIR}/transmission-count-${BENCH_COUNT}-${payload}${protocol}" 111 | xecho "Performing benchmark, output ${TEST_OUTPUT_DIR}" 112 | [ -d "${TEST_OUTPUT_DIR}" ] || mkdir "${TEST_OUTPUT_DIR}" 113 | run_server "${protocol}" 114 | run_client "${protocol}" --send-ktls-count "${BENCH_COUNT}" --payload ${payload} \ 115 | --output "${TEST_OUTPUT_DIR}/ktls-output.${i}.json" 116 | stop_server 117 | run_server "${protocol}" 118 | run_client "${protocol}" --send-gnutls-count "${BENCH_COUNT}" --payload ${payload} \ 119 | --output "${TEST_OUTPUT_DIR}/gnutls-output.${i}.json" 120 | stop_server 121 | 122 | ########## splice(2) - COUNT 123 | TEST_OUTPUT_DIR="${OUTPUT_DIR}/splice-count-dev-zero-${payload}${protocol}" 124 | xecho "Performing benchmark, output: ${TEST_OUTPUT_DIR}" 125 | [ -d "${TEST_OUTPUT_DIR}" ] || mkdir "${TEST_OUTPUT_DIR}" 126 | run_server "${protocol}" --no-echo 127 | run_client "${protocol}" --splice-count "${BENCH_COUNT}" --payload ${payload} \ 128 | --splice-file /dev/zero --output "${TEST_OUTPUT_DIR}/output.${i}.json" 129 | stop_server 130 | 131 | ########### splice(2) echo -- "ping-pong" - COUNT 132 | TEST_OUTPUT_DIR="${OUTPUT_DIR}/splice-echo-count-${payload}${protocol}" 133 | xecho "Performing benchmark, output: ${TEST_OUTPUT_DIR}" 134 | [ -d "${TEST_OUTPUT_DIR}" ] || mkdir "${TEST_OUTPUT_DIR}" 135 | run_server "${protocol}" --mtu ${payload} 136 | run_client "${protocol}" --splice-echo-count "${BENCH_COUNT}" --payload ${payload} \ 137 | --sendfile-mtu ${SENDFILE_MTU} --output "${TEST_OUTPUT_DIR}/output.${i}.json" 138 | stop_server 139 | 140 | ########## sendmsg(2) and recvmsg(2) - TIME 141 | TEST_OUTPUT_DIR="${OUTPUT_DIR}/transmission-time-${BENCH_TIME}-${payload}${protocol}" 142 | xecho "Performing benchmark, output ${TEST_OUTPUT_DIR}" 143 | [ -d "${TEST_OUTPUT_DIR}" ] || mkdir "${TEST_OUTPUT_DIR}" 144 | 145 | run_server "${protocol}" 146 | run_client "${protocol}" --send-ktls-time "${BENCH_TIME}" --payload ${payload} \ 147 | --output "${TEST_OUTPUT_DIR}/ktls-output.${i}.json" 148 | stop_server 149 | run_server "${protocol}" 150 | run_client "${protocol}" --send-gnutls-time "${BENCH_TIME}" --payload ${payload} \ 151 | --output "${TEST_OUTPUT_DIR}/gnutls-output.${i}.json" 152 | stop_server 153 | 154 | ########## splice(2) - TIME 155 | TEST_OUTPUT_DIR="${OUTPUT_DIR}/splice-time-${BENCH_TIME}-dev-zero-${payload}${protocol}" 156 | xecho "Performing benchmark, output: ${TEST_OUTPUT_DIR}" 157 | [ -d "${TEST_OUTPUT_DIR}" ] || mkdir "${TEST_OUTPUT_DIR}" 158 | run_server "${protocol}" --no-echo 159 | run_client "${protocol}" --splice-time "${BENCH_TIME}" --payload ${payload} \ 160 | --splice-file /dev/zero --output "${TEST_OUTPUT_DIR}/output.${i}.json" 161 | stop_server 162 | 163 | ########## raw send & encrypt recv - openconnect and haproxy emulation 164 | TEST_OUTPUT_DIR="${OUTPUT_DIR}/raw-send-time-${BENCH_TIME}-${payload}${protocol}" 165 | xecho "Performing benchmark, output: ${TEST_OUTPUT_DIR}" 166 | [ -d "${TEST_OUTPUT_DIR}" ] || mkdir "${TEST_OUTPUT_DIR}" 167 | run_server "${protocol}" --raw-recv 168 | run_client "${protocol}" --raw-send-time "${BENCH_TIME}" --payload ${payload} \ 169 | --output "${TEST_OUTPUT_DIR}/output.${i}.json" 170 | stop_server 171 | 172 | ########## raw send & encrypt recv - openconnect and haproxy optimized emulation 173 | TEST_OUTPUT_DIR="${OUTPUT_DIR}/splice-send-raw-time-${BENCH_TIME}-${payload}${protocol}" 174 | xecho "Performing benchmark, output: ${TEST_OUTPUT_DIR}" 175 | [ -d "${TEST_OUTPUT_DIR}" ] || mkdir "${TEST_OUTPUT_DIR}" 176 | run_server "${protocol}" --raw-recv 177 | run_client "${protocol}" --splice-send-raw-time "${BENCH_TIME}" --payload ${payload} \ 178 | --sendfile-mtu ${SENDFILE_MTU} --output "${TEST_OUTPUT_DIR}/output.${i}.json" 179 | stop_server 180 | 181 | 182 | ########### splice(2) echo -- "ping-pong" - TIME 183 | TEST_OUTPUT_DIR="${OUTPUT_DIR}/splice-echo-time-${BENCH_TIME}-${payload}${protocol}" 184 | xecho "Performing benchmark, output: ${TEST_OUTPUT_DIR}" 185 | [ -d "${TEST_OUTPUT_DIR}" ] || mkdir "${TEST_OUTPUT_DIR}" 186 | run_server "${protocol}" --mtu ${payload} 187 | run_client "${protocol}" --splice-echo-time "${BENCH_TIME}" --payload ${payload} \ 188 | --sendfile-mtu ${SENDFILE_MTU} --output "${TEST_OUTPUT_DIR}/output.${i}.json" 189 | stop_server 190 | 191 | done 192 | 193 | done 194 | 195 | done 196 | 197 | for dir in "${OUTPUT_DIR}"/*; do 198 | find "${dir}" -iname '*.json' -exec python merge_output.py "${dir}/output.json" {} \+ 199 | done 200 | 201 | xecho "Adding cpuinfo" 202 | cat /proc/cpuinfo > "${OUTPUT_DIR}/cpuinfo" 203 | 204 | for json in `find "${OUTPUT_DIR}" -iname 'output.json'`; do 205 | xecho "Generating HTML statistics for ${json}" 206 | outdir=`dirname "${json}"` 207 | ./af_ktls-visualize/visualize.py --html-stats --input "${json}" --output-dir "${outdir}" 208 | done 209 | 210 | xecho "Generating Index" 211 | python generate_index.py "${OUTPUT_DIR}" 212 | 213 | -------------------------------------------------------------------------------- /certs/ca-key.pem: -------------------------------------------------------------------------------- 1 | Public Key Info: 2 | Public Key Algorithm: RSA 3 | Key Security Level: High (3072 bits) 4 | 5 | modulus: 6 | 00:c2:c3:36:c9:ff:20:64:98:90:24:52:f4:e9:ea:0f 7 | 81:16:1d:04:c1:9e:38:fc:77:15:c7:c1:56:22:05:de 8 | 48:f6:3e:ac:31:72:69:c5:c8:ee:6b:d3:c4:d7:43:f5 9 | b3:be:66:8a:c2:9f:1f:83:57:2d:e5:ca:38:08:88:1b 10 | 39:3b:39:ea:bf:22:3a:14:b6:b0:e6:66:a7:ee:77:7a 11 | 27:9b:ee:db:3b:7c:fc:ac:df:32:25:54:ed:d8:cc:2e 12 | 42:97:68:63:cf:d3:70:69:cf:3f:7b:af:ff:00:81:c2 13 | 3f:73:09:22:a4:dd:81:1e:ab:e8:d3:2a:db:43:1b:6c 14 | 18:ce:34:1f:38:bf:60:00:09:25:1f:86:50:e5:68:f4 15 | aa:10:33:8f:ca:ed:3d:d7:f3:d2:bc:27:bd:90:7a:d0 16 | 6d:a5:55:f8:92:bb:9e:90:96:fd:33:3e:be:70:90:f3 17 | 11:f4:fe:45:61:e0:93:d0:78:7e:8d:ef:a6:74:a3:02 18 | fd:fc:12:f7:79:9e:d3:32:fd:fb:cd:0f:2a:39:59:dd 19 | e1:27:4d:a7:c0:b0:e5:26:23:2d:f7:d5:61:be:8c:07 20 | 4a:e7:31:e8:81:05:03:08:8c:a7:03:80:3a:b5:5b:26 21 | 20:2a:9e:55:10:63:bd:3b:b8:74:84:d2:84:ed:78:44 22 | 7b:e8:0f:1b:71:7b:ab:88:55:c4:c4:7d:08:79:47:5b 23 | 6c:90:3f:53:d7:e4:43:75:8d:55:23:2f:4e:51:2e:f4 24 | ea:f9:d4:66:b8:19:3c:ec:ae:54:11:b7:21:b6:17:cb 25 | 8c:81:9d:62:bc:c4:53:bb:6f:2f:76:67:fb:e9:08:09 26 | 4e:56:a0:46:d6:18:84:27:24:00:52:f6:68:aa:41:fd 27 | 5d:50:e4:dd:b8:c8:d2:4a:7f:76:d0:11:33:d5:5d:f5 28 | 87:bd:2d:bf:d9:22:59:39:a9:c2:d6:ff:77:6c:90:5d 29 | 48:9b:cb:d2:12:7f:13:b2:09:53:9b:84:cd:a4:a8:70 30 | a3: 31 | 32 | public exponent: 33 | 01:00:01: 34 | 35 | private exponent: 36 | 27:57:f6:1e:72:1a:62:17:eb:ae:5a:cf:bc:dd:1a:8a 37 | b2:23:e4:8d:14:60:60:a7:d1:cf:8b:7f:d1:d9:ab:a0 38 | c3:95:bf:85:31:9e:aa:64:bf:bd:2a:87:6e:10:fd:76 39 | 74:f5:13:fc:e2:d6:23:db:1d:9b:78:f1:3e:cf:f7:e7 40 | e4:cd:fb:5c:e7:16:22:8f:11:47:49:df:8c:ad:b8:10 41 | 7e:50:8f:1b:02:51:ac:be:5d:cb:ea:cf:2d:67:79:c4 42 | db:ff:2b:82:95:2c:f5:42:f7:89:0d:f1:8e:71:a8:02 43 | d7:43:36:2b:65:cf:aa:99:81:ab:fe:d1:52:4a:1c:d9 44 | 19:f6:af:83:f0:2c:fd:74:db:79:f5:d1:2b:b6:bb:0e 45 | 0b:bd:ce:c3:68:8f:80:ab:71:9b:ae:cf:7d:7b:41:d5 46 | 94:7b:bc:7e:2f:c6:85:60:ea:ff:4a:22:80:6c:d7:9d 47 | 7e:07:4b:8e:cd:26:2f:0b:d8:4c:e5:e7:93:52:46:cd 48 | 1b:14:9e:2e:bc:24:67:48:6e:7b:60:5b:0b:6d:71:f3 49 | 42:94:ea:2d:b4:5a:b5:d3:05:15:08:44:7f:27:60:0a 50 | b7:58:10:45:58:b8:ef:4a:c9:78:a0:3b:11:84:c6:8d 51 | 4d:a6:18:9a:89:cb:58:5a:66:9a:d4:03:47:d4:a7:74 52 | 5a:77:57:7e:0c:28:ca:5a:6b:f7:e4:24:50:61:3a:45 53 | 60:a9:f9:20:6d:d3:89:33:0c:af:03:fd:cd:78:70:d4 54 | 3d:33:15:75:72:4b:76:d6:f4:e2:f0:99:f7:38:0b:60 55 | bc:42:68:c0:9e:7c:05:8e:6a:85:41:4f:c9:07:6e:78 56 | a0:c7:ae:c6:58:e7:fe:f0:98:fe:d1:58:6b:9f:75:50 57 | 7a:05:b4:69:33:2b:f6:ba:97:a8:6d:cf:5a:61:7d:c7 58 | b7:9b:c0:54:ae:8b:d8:48:6c:b0:8f:99:c4:f8:2b:03 59 | 4e:08:ce:b3:a4:18:b9:50:8a:bf:5b:85:0c:94:d8:51 60 | 61 | 62 | prime1: 63 | 00:fc:75:22:35:7f:f4:76:a4:44:46:3c:23:98:a7:b3 64 | 84:6d:0f:11:7e:1d:8a:59:88:95:2b:cd:5a:56:07:c4 65 | 5f:38:4c:1d:9d:75:0e:1d:5a:03:9a:63:56:db:27:5b 66 | 34:14:94:06:e0:3b:b3:ca:56:d0:13:eb:ed:1b:95:76 67 | cc:1b:c8:e1:0e:39:95:a3:48:ac:48:97:72:68:67:c9 68 | 97:f9:1d:92:64:99:a9:b0:2c:31:17:f5:27:66:76:17 69 | 64:e9:09:22:fb:e3:8c:1b:d1:4c:23:18:c6:b1:a4:b7 70 | b4:f7:04:8b:1f:0e:78:aa:8e:54:3c:34:9c:72:f1:8d 71 | 63:62:18:23:62:47:fd:01:cb:f3:0b:2c:1b:ff:56:e3 72 | 10:e9:49:8b:20:08:99:63:95:52:6f:a4:fb:e3:c5:57 73 | 5d:60:a1:51:ee:eb:f6:5f:c9:f1:10:78:c4:fc:2e:2a 74 | 22:0d:28:97:d7:bf:8e:cf:b1:24:40:b6:af:11:c9:de 75 | f9: 76 | 77 | prime2: 78 | 00:c5:7e:d4:c1:ab:0f:2a:8d:da:7d:c7:20:28:10:40 79 | 46:ca:0f:00:f2:d6:f2:b9:9e:d0:68:9d:33:c2:3d:ed 80 | fd:da:32:6e:87:44:93:8e:c1:00:1f:63:2a:79:a8:1a 81 | 29:b5:68:10:91:9b:30:98:da:4e:0a:2b:f3:bb:11:dd 82 | 1e:09:e3:25:a6:b1:3c:93:e8:e9:06:80:3c:ee:b6:cb 83 | 8a:02:71:c1:8f:00:80:b0:d0:27:da:19:3e:89:9b:a4 84 | 41:17:35:23:e5:84:96:2a:ca:6f:2c:5e:f3:b4:4c:5a 85 | 8a:a5:5b:3c:25:c7:66:b2:3c:4c:73:62:03:32:e3:62 86 | f3:ec:31:0d:da:44:63:2e:b1:05:93:8b:95:ea:84:fc 87 | 7b:7b:bb:9b:53:02:d5:9c:03:2d:00:1d:ca:eb:4b:9d 88 | 94:d2:8d:51:ed:18:93:f3:55:ed:df:45:8b:80:c3:59 89 | 28:5a:c6:2c:96:9f:06:b4:1a:e2:d7:45:61:88:fd:87 90 | 7b: 91 | 92 | coefficient: 93 | 00:ee:59:bc:0d:35:a3:a8:66:6e:50:ed:52:9f:7f:c0 94 | 2c:b3:ad:e8:8d:35:fa:32:b7:d5:2d:13:ff:a4:3e:26 95 | a4:66:9c:66:ea:ef:99:09:81:ef:03:5f:39:27:e6:73 96 | f1:e5:ad:62:d2:ef:f7:8b:5a:ac:76:69:49:09:3b:a3 97 | 43:2d:76:09:b8:71:19:63:d8:b6:d1:9b:23:6c:dd:a5 98 | 99:db:4a:ba:1a:e6:d4:79:b5:d8:51:41:b5:e0:23:5a 99 | 23:1f:12:6c:66:77:71:e1:41:dc:65:57:30:cf:7f:fd 100 | 9b:28:cd:2f:8f:2c:5e:f9:7d:93:07:36:38:3b:a3:9c 101 | f6:2f:be:19:70:fb:b7:56:22:28:b2:d9:a5:c2:e9:cf 102 | 18:18:c3:1e:57:35:55:35:2c:c5:8d:a0:17:1d:66:10 103 | 92:84:0d:99:91:0b:d1:c4:4e:44:57:94:c6:58:a0:76 104 | b6:14:3c:d3:52:cd:d4:3c:a3:97:b1:fc:1e:f1:7b:4b 105 | dc: 106 | 107 | exp1: 108 | 00:f3:91:1b:11:1c:c3:41:d7:d8:1b:1f:18:84:c6:7f 109 | 77:2b:35:17:7e:62:87:c1:3b:fa:17:89:87:37:6b:44 110 | f5:4d:3e:7a:70:18:a8:26:7f:5a:ec:90:1d:13:51:54 111 | 37:da:06:ba:df:8a:1a:3b:04:28:ba:9f:ab:62:2a:80 112 | b4:09:b6:74:13:a2:51:11:79:22:e6:e2:5e:ba:06:30 113 | 44:14:4f:88:96:d0:7e:1b:7f:77:5a:12:e7:11:7e:ab 114 | b1:6a:f7:aa:ad:f4:ea:8f:48:0d:b9:ea:c4:80:4d:58 115 | 04:1b:32:61:fa:f3:9e:4d:87:06:14:13:fa:41:17:75 116 | 7e:c5:fc:5d:df:0b:6f:39:55:88:c6:65:a7:19:61:bd 117 | ae:ea:34:4f:2a:f7:c0:ed:87:fa:41:c6:9e:53:31:68 118 | c9:a9:59:da:cf:b5:0e:3d:7a:7a:be:96:96:0e:6b:87 119 | b0:d4:9b:2e:6c:33:df:57:d8:23:0e:e0:71:e5:aa:ab 120 | 19: 121 | 122 | exp2: 123 | 00:9d:8d:32:b9:55:77:81:e1:2c:5e:8e:ce:2e:67:d8 124 | 7f:20:8e:9b:99:1e:b5:00:33:9b:da:f9:1d:e3:65:78 125 | 48:bd:1a:e2:65:f2:e5:2c:4a:f7:88:12:9a:3d:f7:46 126 | f7:e3:0a:23:bd:a4:ea:3d:e6:59:bf:6f:94:be:b5:df 127 | 8a:29:25:16:52:46:ae:26:e8:f5:8d:04:1c:97:eb:27 128 | b0:ef:86:44:7d:8a:4f:1f:be:cf:2c:04:5b:89:77:aa 129 | af:6a:8e:30:16:d7:90:dc:8e:25:e6:65:d1:51:12:60 130 | 60:9e:cd:8b:cc:2f:a8:d3:a3:9a:f1:a9:4d:17:f9:a2 131 | 65:29:15:71:11:a0:e0:e6:cc:bd:c0:18:e8:fd:f0:1d 132 | 63:7d:30:0b:17:4b:f9:90:be:4f:d5:f9:ee:79:8b:17 133 | 29:34:57:1c:f6:62:57:15:16:85:ef:4a:11:a2:25:35 134 | 29:26:51:56:1c:ca:bc:94:4d:a6:8d:49:82:27:c0:e9 135 | a5: 136 | 137 | 138 | Public Key ID: 0C:86:F6:A3:66:E0:F5:D7:C6:BF:6D:26:2A:7C:B0:C6:CA:71:F1:DF 139 | Public key's random art: 140 | +--[ RSA 3072]----+ 141 | | | 142 | | . | 143 | | o o | 144 | | . o o | 145 | | . . o S | 146 | | . o o ..= | 147 | | . + oooo= | 148 | | o . +*..o.oo | 149 | | oo o..+=E | 150 | +-----------------+ 151 | 152 | -----BEGIN RSA PRIVATE KEY----- 153 | MIIG5QIBAAKCAYEAwsM2yf8gZJiQJFL06eoPgRYdBMGeOPx3FcfBViIF3kj2Pqwx 154 | cmnFyO5r08TXQ/WzvmaKwp8fg1ct5co4CIgbOTs56r8iOhS2sOZmp+53eieb7ts7 155 | fPys3zIlVO3YzC5Cl2hjz9Nwac8/e6//AIHCP3MJIqTdgR6r6NMq20MbbBjONB84 156 | v2AACSUfhlDlaPSqEDOPyu091/PSvCe9kHrQbaVV+JK7npCW/TM+vnCQ8xH0/kVh 157 | 4JPQeH6N76Z0owL9/BL3eZ7TMv37zQ8qOVnd4SdNp8Cw5SYjLffVYb6MB0rnMeiB 158 | BQMIjKcDgDq1WyYgKp5VEGO9O7h0hNKE7XhEe+gPG3F7q4hVxMR9CHlHW2yQP1PX 159 | 5EN1jVUjL05RLvTq+dRmuBk87K5UEbchthfLjIGdYrzEU7tvL3Zn++kICU5WoEbW 160 | GIQnJABS9miqQf1dUOTduMjSSn920BEz1V31h70tv9kiWTmpwtb/d2yQXUiby9IS 161 | fxOyCVObhM2kqHCjAgMBAAECggGAJ1f2HnIaYhfrrlrPvN0airIj5I0UYGCn0c+L 162 | f9HZq6DDlb+FMZ6qZL+9KoduEP12dPUT/OLWI9sdm3jxPs/35+TN+1znFiKPEUdJ 163 | 34ytuBB+UI8bAlGsvl3L6s8tZ3nE2/8rgpUs9UL3iQ3xjnGoAtdDNitlz6qZgav+ 164 | 0VJKHNkZ9q+D8Cz9dNt59dErtrsOC73Ow2iPgKtxm67PfXtB1ZR7vH4vxoVg6v9K 165 | IoBs151+B0uOzSYvC9hM5eeTUkbNGxSeLrwkZ0hue2BbC21x80KU6i20WrXTBRUI 166 | RH8nYAq3WBBFWLjvSsl4oDsRhMaNTaYYmonLWFpmmtQDR9SndFp3V34MKMpaa/fk 167 | JFBhOkVgqfkgbdOJMwyvA/3NeHDUPTMVdXJLdtb04vCZ9zgLYLxCaMCefAWOaoVB 168 | T8kHbnigx67GWOf+8Jj+0Vhrn3VQegW0aTMr9rqXqG3PWmF9x7ebwFSui9hIbLCP 169 | mcT4KwNOCM6zpBi5UIq/W4UMlNhRAoHBAPx1IjV/9HakREY8I5ins4RtDxF+HYpZ 170 | iJUrzVpWB8RfOEwdnXUOHVoDmmNW2ydbNBSUBuA7s8pW0BPr7RuVdswbyOEOOZWj 171 | SKxIl3JoZ8mX+R2SZJmpsCwxF/UnZnYXZOkJIvvjjBvRTCMYxrGkt7T3BIsfDniq 172 | jlQ8NJxy8Y1jYhgjYkf9AcvzCywb/1bjEOlJiyAImWOVUm+k++PFV11goVHu6/Zf 173 | yfEQeMT8LioiDSiX17+Oz7EkQLavEcne+QKBwQDFftTBqw8qjdp9xyAoEEBGyg8A 174 | 8tbyuZ7QaJ0zwj3t/doybodEk47BAB9jKnmoGim1aBCRmzCY2k4KK/O7Ed0eCeMl 175 | prE8k+jpBoA87rbLigJxwY8AgLDQJ9oZPombpEEXNSPlhJYqym8sXvO0TFqKpVs8 176 | JcdmsjxMc2IDMuNi8+wxDdpEYy6xBZOLleqE/Ht7u5tTAtWcAy0AHcrrS52U0o1R 177 | 7RiT81Xt30WLgMNZKFrGLJafBrQa4tdFYYj9h3sCgcEA85EbERzDQdfYGx8YhMZ/ 178 | dys1F35ih8E7+heJhzdrRPVNPnpwGKgmf1rskB0TUVQ32ga634oaOwQoup+rYiqA 179 | tAm2dBOiURF5IubiXroGMEQUT4iW0H4bf3daEucRfquxaveqrfTqj0gNuerEgE1Y 180 | BBsyYfrznk2HBhQT+kEXdX7F/F3fC285VYjGZacZYb2u6jRPKvfA7Yf6QcaeUzFo 181 | yalZ2s+1Dj16er6Wlg5rh7DUmy5sM99X2CMO4HHlqqsZAoHBAJ2NMrlVd4HhLF6O 182 | zi5n2H8gjpuZHrUAM5va+R3jZXhIvRriZfLlLEr3iBKaPfdG9+MKI72k6j3mWb9v 183 | lL6134opJRZSRq4m6PWNBByX6yew74ZEfYpPH77PLARbiXeqr2qOMBbXkNyOJeZl 184 | 0VESYGCezYvML6jTo5rxqU0X+aJlKRVxEaDg5sy9wBjo/fAdY30wCxdL+ZC+T9X5 185 | 7nmLFyk0Vxz2YlcVFoXvShGiJTUpJlFWHMq8lE2mjUmCJ8DppQKBwQDuWbwNNaOo 186 | Zm5Q7VKff8Ass63ojTX6MrfVLRP/pD4mpGacZurvmQmB7wNfOSfmc/HlrWLS7/eL 187 | Wqx2aUkJO6NDLXYJuHEZY9i20ZsjbN2lmdtKuhrm1Hm12FFBteAjWiMfEmxmd3Hh 188 | QdxlVzDPf/2bKM0vjyxe+X2TBzY4O6Oc9i++GXD7t1YiKLLZpcLpzxgYwx5XNVU1 189 | LMWNoBcdZhCShA2ZkQvRxE5EV5TGWKB2thQ801LN1Dyjl7H8HvF7S9w= 190 | -----END RSA PRIVATE KEY----- 191 | -------------------------------------------------------------------------------- /certs/server-key.pem: -------------------------------------------------------------------------------- 1 | Public Key Info: 2 | Public Key Algorithm: RSA 3 | Key Security Level: High (3072 bits) 4 | 5 | modulus: 6 | 00:f2:16:60:a7:79:f1:72:63:1c:30:05:da:a5:d9:f8 7 | 99:0a:9d:ca:1c:7b:3d:12:60:16:3a:0b:86:f7:5d:d7 8 | 80:8b:6f:00:aa:71:4a:9d:9b:07:2a:b3:a7:95:56:9e 9 | 31:db:fc:02:1d:5d:7e:9b:7c:9a:61:01:aa:66:27:f6 10 | 7e:58:bf:f2:17:c0:34:52:45:b9:8e:82:60:d1:18:23 11 | 46:5f:00:ee:62:4f:64:04:93:fd:67:a7:93:96:0e:76 12 | c1:c6:99:b4:b0:20:14:25:4d:56:d5:d1:5e:cc:c1:64 13 | 2e:c1:99:29:c0:18:81:76:f0:14:ed:a4:7d:95:f2:c7 14 | 36:3e:33:79:a2:14:88:65:86:5a:6d:1b:f9:b7:fd:c8 15 | 6a:8a:3e:6c:81:6d:ad:14:21:3f:f2:a7:87:0b:93:83 16 | 9a:8b:93:9e:34:81:d4:bd:6e:84:62:14:e0:47:16:76 17 | ff:51:40:96:18:c8:3e:4d:94:ef:e8:12:69:4b:25:e0 18 | 82:37:54:9d:f8:22:ed:3f:23:e0:54:21:af:79:b0:62 19 | 2d:33:3b:b7:5c:6f:f6:25:cd:9c:82:c0:54:9f:a6:cd 20 | 7f:f0:bd:00:b3:09:9b:9d:3f:f1:d1:dc:20:41:41:14 21 | be:2c:f4:b8:12:88:aa:af:a6:4e:09:2b:97:22:c2:30 22 | cb:61:cc:e3:c3:c6:7c:c1:d3:86:91:3c:af:56:f8:42 23 | a6:e5:a0:5f:83:a2:13:37:ab:d4:82:ac:c8:ba:77:f1 24 | 2e:69:14:94:17:c2:81:45:57:d9:3c:fe:b0:67:9c:28 25 | 85:16:98:8b:74:1a:57:93:92:72:91:8d:37:97:74:e5 26 | 54:21:bb:48:97:34:89:f6:78:2c:54:c8:0a:dd:86:e5 27 | cc:0d:01:01:4e:aa:92:47:8c:e8:6d:81:a5:c3:d0:c6 28 | 21:96:d6:75:84:84:7e:a5:f4:20:a9:c7:14:e6:8f:62 29 | 05:bc:70:c4:2f:14:b1:42:86:0d:59:18:2b:2a:08:65 30 | dd: 31 | 32 | public exponent: 33 | 01:00:01: 34 | 35 | private exponent: 36 | 00:b1:b4:d3:86:9c:f1:2c:32:ac:c2:63:c9:b8:ed:64 37 | 9b:93:3b:78:dd:a7:69:91:4f:8f:81:54:6c:e2:b0:b4 38 | 3c:dc:1d:c3:b3:5a:2e:97:ba:f1:6b:db:2d:2d:66:c4 39 | 01:7d:a6:64:37:02:26:aa:24:b1:7e:7c:26:85:8e:d8 40 | 56:ae:f7:57:d3:2f:78:38:dc:8d:f5:9a:a7:4f:56:14 41 | ae:d7:96:6b:67:27:38:18:54:3a:34:18:c3:31:e7:b4 42 | 2d:52:88:0a:27:2f:a5:1a:2c:c7:8d:75:7f:cd:76:39 43 | 00:49:85:11:2c:bd:d0:6b:6a:99:32:49:09:17:45:7c 44 | 0e:c9:62:27:eb:5e:7f:31:67:8a:81:85:83:ae:18:51 45 | 42:43:f0:c6:dd:cb:90:bd:b2:1a:ab:19:66:fc:8c:70 46 | 92:c5:da:ba:cb:78:72:9e:0b:be:89:f1:21:21:8d:d0 47 | 14:63:a4:b1:89:c7:94:54:86:fc:04:b3:5f:2f:96:c2 48 | 51:e6:a0:60:96:ed:ee:c5:e4:0b:7b:a2:75:30:c0:c4 49 | 82:21:2a:32:59:5a:9d:65:16:e4:c3:6c:c9:6f:23:6f 50 | 85:8e:fb:c1:b0:81:e8:fb:01:72:55:1f:05:53:67:8d 51 | 60:2e:ec:d7:92:ac:de:51:73:26:13:e7:74:9b:78:fc 52 | 21:ff:d9:19:23:75:3c:f6:62:d3:ae:47:76:66:8a:08 53 | f5:ea:ec:0a:42:aa:e4:5a:17:fd:f0:df:94:e2:39:98 54 | 2d:81:86:88:c6:6a:e0:bb:a4:fa:7f:f2:1b:48:7c:4f 55 | f0:42:e0:52:bb:90:86:5f:4b:99:76:7b:b7:b4:38:3e 56 | 0d:6c:ca:b6:65:4e:d4:1d:3f:76:e6:61:32:58:f1:ea 57 | 2f:13:92:75:6b:9c:cd:c0:74:ef:e2:f9:96:d9:7c:ba 58 | 86:66:0f:ec:f1:44:40:fe:13:30:91:33:0e:5f:d6:e2 59 | d6:2b:67:16:2a:a6:37:be:cf:0d:e0:2a:91:6d:71:87 60 | d1: 61 | 62 | prime1: 63 | 00:f6:05:38:41:7b:24:8f:31:fe:39:6f:87:f5:c1:6f 64 | 89:7f:38:bf:29:50:4f:ec:4b:cc:d4:10:76:db:79:4b 65 | e2:95:ee:cc:36:08:fa:4a:75:95:70:e5:94:96:82:c4 66 | 5b:3a:dd:5f:ad:8f:de:77:2c:20:ce:0d:3c:29:1a:e7 67 | 20:b4:42:b2:3b:4f:71:74:ee:c5:76:52:82:15:f3:a7 68 | b9:f8:1b:da:58:37:57:a4:f3:c0:ba:13:10:5f:33:e8 69 | fe:33:6e:ec:e4:fe:bb:96:80:40:f6:80:02:ce:69:05 70 | 0f:c9:91:80:15:90:d6:f4:cf:13:b0:32:46:46:d5:c9 71 | a8:cb:b4:a7:73:71:8b:8d:8f:93:00:3a:0e:03:45:b3 72 | 9c:9d:6f:92:3c:84:2c:83:69:46:9e:15:85:cd:3c:4e 73 | ca:e3:29:6f:e6:6c:00:26:3b:78:e1:17:00:c2:4a:33 74 | ab:f2:aa:c4:32:0e:69:7f:84:16:f0:dc:5d:33:e8:25 75 | 17: 76 | 77 | prime2: 78 | 00:fb:e8:50:eb:db:07:bc:56:da:a2:82:0b:7c:94:59 79 | aa:b7:ed:27:8f:ec:4b:50:eb:66:02:54:9c:6b:a0:2d 80 | 98:82:74:09:4c:79:4a:17:3d:ff:5e:77:29:14:c8:66 81 | 2f:28:16:3f:16:ae:81:9a:51:91:0b:1c:9b:74:5b:06 82 | 2d:0d:23:35:93:07:fe:ea:0b:8b:f3:12:ad:e9:ef:da 83 | c2:c3:10:66:dd:b2:98:fa:a1:fb:99:46:5b:64:b4:0b 84 | 62:cb:c5:e8:db:db:ae:26:2e:37:14:c4:d1:58:1c:6c 85 | b8:3a:87:01:00:fd:d6:9d:43:3f:e0:aa:f6:d9:77:45 86 | 5b:cc:6a:2f:8f:7b:15:81:0c:6b:eb:2b:7f:00:6b:06 87 | cc:df:f7:e5:8e:51:42:57:2a:2a:35:33:94:bd:73:ba 88 | a5:db:fa:66:5a:82:0e:d2:b6:57:af:4b:d9:09:b3:05 89 | 5e:e2:80:1c:8b:50:cf:27:29:7c:67:35:a5:02:18:0d 90 | 2b: 91 | 92 | coefficient: 93 | 00:ab:07:bd:0b:f2:2b:59:e9:16:fc:7a:07:05:1d:f1 94 | 5f:43:c9:c2:5a:7a:7c:aa:f0:80:c9:35:66:11:96:d6 95 | b5:c7:63:1d:9a:14:27:fa:09:6e:78:70:ea:82:e4:2b 96 | ad:a3:00:e4:04:ef:6b:1d:87:07:bc:75:b9:65:b2:b7 97 | b8:5a:78:be:54:cd:af:2e:08:49:88:66:56:25:b2:79 98 | 5d:47:f7:16:bd:d2:ad:73:cc:df:b2:7f:b5:fd:ae:1d 99 | f6:eb:18:bf:49:30:60:41:84:ce:c8:55:90:7c:0c:93 100 | a8:f2:1b:f9:31:fa:87:50:e2:8e:f1:fc:c2:d8:b9:07 101 | 5a:8e:a4:1c:3f:ce:cf:5d:4c:06:d1:fc:92:3a:2b:f6 102 | 75:20:4c:c0:a8:97:80:4b:be:52:cd:1a:1d:91:8f:c2 103 | 51:f6:4b:01:13:85:9d:90:5e:c3:73:f7:d9:6f:f0:4a 104 | 4c:84:c7:c8:90:ae:40:8f:8f:ee:a9:61:11:02:9e:09 105 | d2: 106 | 107 | exp1: 108 | 47:50:2a:07:69:1f:a6:d6:71:ff:ca:21:9a:0e:31:3b 109 | a5:02:18:ff:6b:c5:4f:14:85:d2:2e:d7:95:34:ea:d7 110 | 4a:68:c7:0f:1e:b9:16:9e:50:ec:41:d0:39:74:bc:60 111 | 49:86:e3:f6:16:8f:00:f2:6c:ab:ed:d0:33:86:15:db 112 | 38:05:61:4e:a9:ef:94:5a:a6:28:6f:30:40:16:b9:d6 113 | c1:61:a9:80:0a:c2:c0:10:dc:1b:d3:ec:d9:fb:dd:1c 114 | da:61:dc:0f:60:fb:95:5b:a5:f9:0e:10:42:2e:d5:05 115 | c7:83:02:a2:bd:b2:61:92:28:fd:d9:04:e0:01:96:8b 116 | f4:48:70:85:99:33:3f:9c:8f:9a:f0:39:21:9f:b1:b9 117 | c3:35:15:29:af:92:8b:a1:17:94:39:5e:e8:a8:03:9a 118 | f2:10:0f:dc:b6:0f:b1:05:6a:3b:ad:04:4e:4d:5d:ff 119 | 08:bf:91:51:85:35:f5:7d:9f:7c:c0:13:d0:39:09:8f 120 | 121 | 122 | exp2: 123 | 00:e5:ce:52:fc:47:6d:b0:30:9f:f5:fe:a3:11:fc:98 124 | 2c:78:ec:3d:da:3b:5b:9e:2f:91:78:f0:cd:5e:15:db 125 | 62:b5:27:bc:4f:ea:9a:5f:c7:ac:4e:f6:70:20:c8:8d 126 | 07:da:0f:29:70:bc:b3:f9:1f:0e:2d:cf:e4:35:6a:d0 127 | a0:8a:ca:a3:16:46:06:14:67:82:3d:b6:bd:b7:9b:9b 128 | bb:6f:8e:67:f9:39:f3:fb:39:88:b8:94:89:cd:bd:be 129 | 61:5b:ba:69:ab:20:a6:a7:a8:23:91:ab:d7:bb:04:fb 130 | 5d:b9:ee:ed:48:85:49:a3:5f:f5:47:35:50:4a:a5:57 131 | 3d:de:a6:c4:4a:a5:a3:c1:7d:9e:7a:04:cd:30:89:72 132 | c3:b6:52:85:35:a7:05:d9:54:da:fa:7b:da:e6:56:4c 133 | 61:00:e4:57:39:9c:4a:7f:89:df:46:48:f0:6f:bb:c4 134 | 5b:82:50:13:3a:38:f7:32:27:d3:98:a8:44:a7:3b:5f 135 | cf: 136 | 137 | 138 | Public Key ID: 60:5C:E7:D8:9C:4F:B4:B3:90:F2:FB:CC:1B:6B:D4:30:33:48:71:6A 139 | Public key's random art: 140 | +--[ RSA 3072]----+ 141 | | . o.o | 142 | | . . *.* . | 143 | | + o.E.+ | 144 | | . . +.+=o | 145 | | S . o* | 146 | | .. . | 147 | | ... | 148 | | +.o | 149 | | .*. | 150 | +-----------------+ 151 | 152 | -----BEGIN RSA PRIVATE KEY----- 153 | MIIG5QIBAAKCAYEA8hZgp3nxcmMcMAXapdn4mQqdyhx7PRJgFjoLhvdd14CLbwCq 154 | cUqdmwcqs6eVVp4x2/wCHV1+m3yaYQGqZif2fli/8hfANFJFuY6CYNEYI0ZfAO5i 155 | T2QEk/1np5OWDnbBxpm0sCAUJU1W1dFezMFkLsGZKcAYgXbwFO2kfZXyxzY+M3mi 156 | FIhlhlptG/m3/chqij5sgW2tFCE/8qeHC5ODmouTnjSB1L1uhGIU4EcWdv9RQJYY 157 | yD5NlO/oEmlLJeCCN1Sd+CLtPyPgVCGvebBiLTM7t1xv9iXNnILAVJ+mzX/wvQCz 158 | CZudP/HR3CBBQRS+LPS4Eoiqr6ZOCSuXIsIwy2HM48PGfMHThpE8r1b4QqbloF+D 159 | ohM3q9SCrMi6d/EuaRSUF8KBRVfZPP6wZ5wohRaYi3QaV5OScpGNN5d05VQhu0iX 160 | NIn2eCxUyArdhuXMDQEBTqqSR4zobYGlw9DGIZbWdYSEfqX0IKnHFOaPYgW8cMQv 161 | FLFChg1ZGCsqCGXdAgMBAAECggGBALG004ac8SwyrMJjybjtZJuTO3jdp2mRT4+B 162 | VGzisLQ83B3Ds1oul7rxa9stLWbEAX2mZDcCJqoksX58JoWO2Fau91fTL3g43I31 163 | mqdPVhSu15ZrZyc4GFQ6NBjDMee0LVKICicvpRosx411f812OQBJhREsvdBrapky 164 | SQkXRXwOyWIn615/MWeKgYWDrhhRQkPwxt3LkL2yGqsZZvyMcJLF2rrLeHKeC76J 165 | 8SEhjdAUY6SxiceUVIb8BLNfL5bCUeagYJbt7sXkC3uidTDAxIIhKjJZWp1lFuTD 166 | bMlvI2+FjvvBsIHo+wFyVR8FU2eNYC7s15Ks3lFzJhPndJt4/CH/2RkjdTz2YtOu 167 | R3Zmigj16uwKQqrkWhf98N+U4jmYLYGGiMZq4Luk+n/yG0h8T/BC4FK7kIZfS5l2 168 | e7e0OD4NbMq2ZU7UHT925mEyWPHqLxOSdWuczcB07+L5ltl8uoZmD+zxRED+EzCR 169 | Mw5f1uLWK2cWKqY3vs8N4CqRbXGH0QKBwQD2BThBeySPMf45b4f1wW+Jfzi/KVBP 170 | 7EvM1BB223lL4pXuzDYI+kp1lXDllJaCxFs63V+tj953LCDODTwpGucgtEKyO09x 171 | dO7FdlKCFfOnufgb2lg3V6TzwLoTEF8z6P4zbuzk/ruWgED2gALOaQUPyZGAFZDW 172 | 9M8TsDJGRtXJqMu0p3Nxi42PkwA6DgNFs5ydb5I8hCyDaUaeFYXNPE7K4ylv5mwA 173 | Jjt44RcAwkozq/KqxDIOaX+EFvDcXTPoJRcCgcEA++hQ69sHvFbaooILfJRZqrft 174 | J4/sS1DrZgJUnGugLZiCdAlMeUoXPf9edykUyGYvKBY/Fq6BmlGRCxybdFsGLQ0j 175 | NZMH/uoLi/MSrenv2sLDEGbdspj6ofuZRltktAtiy8Xo29uuJi43FMTRWBxsuDqH 176 | AQD91p1DP+Cq9tl3RVvMai+PexWBDGvrK38AawbM3/fljlFCVyoqNTOUvXO6pdv6 177 | ZlqCDtK2V69L2QmzBV7igByLUM8nKXxnNaUCGA0rAoHAR1AqB2kfptZx/8ohmg4x 178 | O6UCGP9rxU8UhdIu15U06tdKaMcPHrkWnlDsQdA5dLxgSYbj9haPAPJsq+3QM4YV 179 | 2zgFYU6p75RapihvMEAWudbBYamACsLAENwb0+zZ+90c2mHcD2D7lVul+Q4QQi7V 180 | BceDAqK9smGSKP3ZBOABlov0SHCFmTM/nI+a8Dkhn7G5wzUVKa+Si6EXlDle6KgD 181 | mvIQD9y2D7EFajutBE5NXf8Iv5FRhTX1fZ98wBPQOQmPAoHBAOXOUvxHbbAwn/X+ 182 | oxH8mCx47D3aO1ueL5F48M1eFdtitSe8T+qaX8esTvZwIMiNB9oPKXC8s/kfDi3P 183 | 5DVq0KCKyqMWRgYUZ4I9tr23m5u7b45n+Tnz+zmIuJSJzb2+YVu6aasgpqeoI5Gr 184 | 17sE+1257u1IhUmjX/VHNVBKpVc93qbESqWjwX2eegTNMIlyw7ZShTWnBdlU2vp7 185 | 2uZWTGEA5Fc5nEp/id9GSPBvu8RbglATOjj3MifTmKhEpztfzwKBwQCrB70L8itZ 186 | 6Rb8egcFHfFfQ8nCWnp8qvCAyTVmEZbWtcdjHZoUJ/oJbnhw6oLkK62jAOQE72sd 187 | hwe8dbllsre4Wni+VM2vLghJiGZWJbJ5XUf3Fr3SrXPM37J/tf2uHfbrGL9JMGBB 188 | hM7IVZB8DJOo8hv5MfqHUOKO8fzC2LkHWo6kHD/Oz11MBtH8kjor9nUgTMCol4BL 189 | vlLNGh2Rj8JR9ksBE4WdkF7Dc/fZb/BKTITHyJCuQI+P7qlhEQKeCdI= 190 | -----END RSA PRIVATE KEY----- 191 | -------------------------------------------------------------------------------- /server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * af_ktls tool 3 | * 4 | * Copyright (C) 2016 Fridolin Pokorny 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by the Free 8 | * Software Foundation; either version 2 of the License, or (at your option) 9 | * any later version. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "plain_server.h" 37 | #include "server.h" 38 | #include "common.h" 39 | #include "ktls.h" 40 | 41 | #define KEYFILE "certs/server-key.pem" 42 | #define CERTFILE "certs/server-cert.pem" 43 | #define CAFILE "certs/ca-cert.pem" 44 | #define CRLFILE "/etc/ocserv/cert.key" 45 | 46 | #define SOCKET_ERR(err,s) if(err==-1) {perror(s);return(1);} 47 | 48 | /* 49 | * we will do it with global var since we want to capture error in thread even 50 | * in a standalone process and we want to keep it simple; modified only by 51 | * run_server(); 52 | */ 53 | int server_err = 0; 54 | 55 | static int dtls_pull_timeout_func(gnutls_transport_ptr_t ptr, unsigned int ms); 56 | static ssize_t dtls_push_func(gnutls_transport_ptr_t p, const void *data, 57 | size_t size); 58 | static ssize_t dtls_pull_func(gnutls_transport_ptr_t p, void *data, 59 | size_t size); 60 | static const char *human_addr(const struct sockaddr *sa, socklen_t salen, 61 | char *buf, size_t buflen); 62 | static int dtls_wait_for_connection(int fd); 63 | static int generate_dh_params(void); 64 | 65 | /* Use global credentials and parameters to simplify 66 | * the example. */ 67 | static gnutls_certificate_credentials_t x509_cred; 68 | static gnutls_dh_params_t dh_params; 69 | 70 | 71 | static int server_gnutls_loop(const struct server_opts *opts, gnutls_session_t session, 72 | char *buffer, int sd) { 73 | int ret; 74 | unsigned char sequence[8]; 75 | 76 | for (;;) { 77 | if (!opts->raw_recv) { 78 | do { 79 | ret = gnutls_record_recv_seq(session, buffer, opts->mtu, sequence); 80 | } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); 81 | } else { 82 | ret = recv(sd, buffer, opts->mtu, 0); 83 | if (ret < 0) { 84 | perror("recv"); 85 | print_error("failed to recv"); 86 | break; 87 | } 88 | } 89 | 90 | if (!opts->raw_recv) { 91 | if (ret < 0 && gnutls_error_is_fatal(ret) == 0) { 92 | print_warning("*** Warning: %s", gnutls_strerror(ret)); 93 | continue; 94 | } else if (ret < 0) { 95 | print_error("Error in recv(): %s", gnutls_strerror(ret)); 96 | break; 97 | } 98 | } 99 | 100 | if (ret == 0) { 101 | if (opts->verbose_level >= VERBOSE_LEVEL_PACKETS) 102 | print_info("connection closed"); 103 | break; 104 | } 105 | 106 | if (opts->verbose_level >= VERBOSE_LEVEL_PACKETS) { 107 | buffer[ret] = 0; 108 | print_info 109 | ("received[%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x]: ", 110 | sequence[0], sequence[1], sequence[2], 111 | sequence[3], sequence[4], sequence[5], 112 | sequence[6], sequence[7]); 113 | 114 | print_hex(buffer, ret); 115 | } 116 | 117 | if (!opts->no_echo) { 118 | ret = gnutls_record_send(session, buffer, ret); 119 | if (ret < 0) { 120 | // if we do raw recv, just ignore recv errors, since recv channel is tainted, 121 | // this handling is OK for benchmark tests 122 | if (!opts->raw_recv) { 123 | print_error("Error in send(): %s", 124 | gnutls_strerror(ret)); 125 | } else { 126 | ret = 0; 127 | } 128 | break; 129 | } 130 | } 131 | 132 | if (opts->store_file) 133 | write(opts->store_file, buffer, ret); 134 | } 135 | 136 | return ret < 0 ? ret : 0; 137 | } 138 | 139 | static int server_ktls_loop(const struct server_opts *opts, gnutls_session_t session, int sd, struct sockaddr *cli_addr, socklen_t cli_addr_size, char *buf) { 140 | int err; 141 | int ksd = 0; 142 | socklen_t cli_addr_size_tmp; 143 | 144 | ksd = ktls_socket_init(session, sd, 0, opts->tls); 145 | if (ksd < 0) { 146 | print_error("failed to make AF_KTLS socket on server"); 147 | return ksd; 148 | } 149 | 150 | for (;;) { 151 | err = recvfrom(ksd, buf, opts->mtu, 0, cli_addr, &cli_addr_size_tmp); 152 | if (err < 0) { 153 | perror("recv"); 154 | print_error("probably not data packet, fallback to Gnu TLS"); 155 | err = server_gnutls_loop(opts, session, buf, sd); 156 | goto ktls_loop_end; 157 | } 158 | 159 | if (err == 0) { 160 | print_info("connection terminated by client"); 161 | goto ktls_loop_end; 162 | } 163 | 164 | if (opts->store_file) 165 | write(opts->store_file, buf, err); 166 | 167 | if (!opts->no_echo) { 168 | err = sendto(ksd, buf, err, 0, cli_addr, cli_addr_size); 169 | if (err < 0) { 170 | perror("send"); 171 | print_error("failed to sent to AF_KTLS on server"); 172 | goto ktls_loop_end; 173 | } 174 | } 175 | } 176 | 177 | ktls_loop_end: 178 | ktls_socket_update_state(session, ksd, opts->tls); 179 | if (ksd) 180 | ktls_socket_destruct(ksd, session); 181 | return err < 0 ? err : 0; 182 | } 183 | 184 | // TODO: use anoncred 185 | static int dtls_run_server(struct server_opts *opts) { 186 | int listen_sd = 0; 187 | int sock, ret; 188 | struct sockaddr_in sa_serv; 189 | struct sockaddr_in cli_addr; 190 | socklen_t cli_addr_size; 191 | gnutls_session_t session; 192 | char buffer[opts->mtu]; 193 | priv_data_st priv; 194 | gnutls_datum_t cookie_key; 195 | gnutls_dtls_prestate_st prestate; 196 | 197 | gnutls_global_init(); 198 | 199 | if (opts->verbose_level >= VERBOSE_LEVEL_GNUTLS) { 200 | gnutls_global_set_log_level(9999); 201 | gnutls_global_set_log_function(gnutls_log); 202 | } 203 | 204 | gnutls_certificate_allocate_credentials(&x509_cred); 205 | //gnutls_certificate_set_x509_trust_file(x509_cred, CAFILE, 206 | // GNUTLS_X509_FMT_PEM); 207 | //gnutls_certificate_set_x509_crl_file(x509_cred, CRLFILE, 208 | // GNUTLS_X509_FMT_PEM); 209 | 210 | ret = gnutls_certificate_set_x509_key_file(x509_cred, CERTFILE, KEYFILE, 211 | GNUTLS_X509_FMT_PEM); 212 | 213 | if (ret < 0) { 214 | print_error("No certificate or key were found"); 215 | goto dtls_run_server_end; 216 | } 217 | 218 | generate_dh_params(); 219 | gnutls_certificate_set_dh_params(x509_cred, dh_params); 220 | gnutls_key_generate(&cookie_key, GNUTLS_COOKIE_KEY_SIZE); 221 | 222 | listen_sd = socket(AF_INET, SOCK_DGRAM, 0); 223 | 224 | memset(&sa_serv, '\0', sizeof(sa_serv)); 225 | sa_serv.sin_family = AF_INET; 226 | sa_serv.sin_addr.s_addr = INADDR_ANY; 227 | sa_serv.sin_port = htons(opts->port); 228 | 229 | { 230 | /* DTLS requires the IP don't fragment (DF) bit to be set */ 231 | #if defined(IP_DONTFRAG) 232 | int optval = 1; 233 | setsockopt(listen_sd, IPPROTO_IP, IP_DONTFRAG, (const void *) &optval, sizeof(optval)); 234 | #elif defined(IP_MTU_DISCOVER) 235 | int optval = IP_PMTUDISC_DO; 236 | setsockopt(listen_sd, IPPROTO_IP, IP_MTU_DISCOVER, 237 | (const void *) &optval, sizeof(optval)); 238 | #endif 239 | } 240 | 241 | bind(listen_sd, (struct sockaddr *) &sa_serv, sizeof(sa_serv)); 242 | 243 | if (opts->verbose_level >= VERBOSE_LEVEL_SERVER) 244 | print_info("UDP server ready. Listening to port '%d'!", opts->port); 245 | 246 | if (opts->condition_initialized) { 247 | if (opts->port_mem) 248 | // TODO: get actual port 249 | *opts->port_mem = opts->port; 250 | pthread_cond_broadcast(opts->condition_initialized); 251 | } 252 | 253 | for (;;) { 254 | print_debug_server(opts, "Waiting for connection..."); 255 | sock = dtls_wait_for_connection(listen_sd); 256 | if (sock < 0) 257 | continue; 258 | 259 | cli_addr_size = sizeof(cli_addr); 260 | ret = recvfrom(sock, buffer, sizeof(buffer), MSG_PEEK, 261 | (struct sockaddr *) &cli_addr, 262 | &cli_addr_size); 263 | if (ret > 0) { 264 | if (opts->verbose_level >= VERBOSE_LEVEL_PACKETS) { 265 | print_info("received:"); 266 | print_hex(buffer, ret); 267 | } 268 | memset(&prestate, 0, sizeof(prestate)); 269 | ret = 270 | gnutls_dtls_cookie_verify(&cookie_key, 271 | &cli_addr, 272 | sizeof(cli_addr), 273 | buffer, ret, 274 | &prestate); 275 | if (ret < 0) { /* cookie not valid */ 276 | priv_data_st s; 277 | 278 | memset(&s, 0, sizeof(s)); 279 | s.fd = sock; 280 | s.cli_addr = (void *) &cli_addr; 281 | s.cli_addr_size = sizeof(cli_addr); 282 | 283 | //printf 284 | // ("Sending hello verify request to %s", 285 | // human_addr((struct sockaddr *) 286 | // &cli_addr, 287 | // sizeof(cli_addr), buffer, 288 | // sizeof(buffer))); 289 | 290 | gnutls_dtls_cookie_send(&cookie_key, 291 | &cli_addr, 292 | sizeof(cli_addr), 293 | &prestate, 294 | (gnutls_transport_ptr_t) 295 | & s, dtls_push_func); 296 | 297 | /* discard peeked data */ 298 | recvfrom(sock, buffer, sizeof(buffer), 0, 299 | (struct sockaddr *) &cli_addr, 300 | &cli_addr_size); 301 | usleep(100); 302 | continue; 303 | } 304 | //print_info("Accepted connection from %s", 305 | // human_addr((struct sockaddr *) 306 | // &cli_addr, sizeof(cli_addr), 307 | // buffer, sizeof(buffer))); 308 | } else 309 | continue; 310 | 311 | gnutls_init(&session, GNUTLS_SERVER | GNUTLS_DATAGRAM); 312 | gnutls_set_default_priority(session); 313 | /* if more fine-graned control is required */ 314 | 315 | //ret = gnutls_priority_set_direct(session, 316 | // "NORMAL:+ANON-ECDH:+ANON-DH", 317 | // NULL); 318 | ret = gnutls_priority_set_direct(session, 319 | "NORMAL", NULL); 320 | if (ret < 0) { 321 | if (ret == GNUTLS_E_INVALID_REQUEST) { 322 | print_error("Syntax error at: %d", ret); 323 | } 324 | exit(1); 325 | } 326 | 327 | gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, 328 | x509_cred); 329 | 330 | gnutls_dtls_prestate_set(session, &prestate); 331 | gnutls_dtls_set_mtu(session, SERVER_MAX_MTU); 332 | 333 | priv.session = session; 334 | priv.fd = sock; 335 | priv.cli_addr = (struct sockaddr *) &cli_addr; 336 | priv.cli_addr_size = sizeof(cli_addr); 337 | 338 | gnutls_transport_set_ptr(session, &priv); 339 | gnutls_transport_set_push_function(session, dtls_push_func); 340 | gnutls_transport_set_pull_function(session, dtls_pull_func); 341 | gnutls_transport_set_pull_timeout_function(session, dtls_pull_timeout_func); 342 | 343 | do { 344 | ret = gnutls_handshake(session); 345 | } 346 | while (ret == GNUTLS_E_INTERRUPTED 347 | || ret == GNUTLS_E_AGAIN); 348 | /* Note that DTLS may also receive GNUTLS_E_LARGE_PACKET. 349 | * In that case the MTU should be adjusted. 350 | */ 351 | 352 | if (ret < 0) { 353 | print_error("Error in handshake(): %s", 354 | gnutls_strerror(ret)); 355 | gnutls_deinit(session); 356 | continue; 357 | } 358 | 359 | if (opts->verbose_level >= VERBOSE_LEVEL_PACKETS) 360 | print_info("Handshake was completed"); 361 | 362 | if (opts->ktls) { 363 | server_ktls_loop(opts, session, sock, (struct sockaddr *)&cli_addr, sizeof(cli_addr), buffer); 364 | } else { 365 | server_gnutls_loop(opts, session, buffer, sock); 366 | } 367 | 368 | gnutls_bye(session, GNUTLS_SHUT_WR); 369 | gnutls_deinit(session); 370 | } 371 | 372 | ret = 0; 373 | 374 | dtls_run_server_end: 375 | if (listen_sd); 376 | close(listen_sd); 377 | 378 | gnutls_certificate_free_credentials(x509_cred); 379 | 380 | gnutls_global_deinit(); 381 | 382 | return ret; 383 | } 384 | 385 | static int dtls_wait_for_connection(int fd) { 386 | fd_set rd, wr; 387 | int n; 388 | 389 | FD_ZERO(&rd); 390 | FD_ZERO(&wr); 391 | 392 | FD_SET(fd, &rd); 393 | 394 | /* waiting part */ 395 | n = select(fd + 1, &rd, &wr, NULL, NULL); 396 | if (n == -1 && errno == EINTR) 397 | return -1; 398 | 399 | if (n < 0) { 400 | perror("select()"); 401 | exit(1); 402 | } 403 | 404 | return fd; 405 | } 406 | 407 | /* Wait for data to be received within a timeout period in milliseconds 408 | */ 409 | static int dtls_pull_timeout_func(gnutls_transport_ptr_t ptr, unsigned int ms) { 410 | fd_set rfds; 411 | struct timeval tv; 412 | priv_data_st *priv = ptr; 413 | struct sockaddr_in cli_addr; 414 | socklen_t cli_addr_size; 415 | int ret; 416 | char c; 417 | 418 | FD_ZERO(&rfds); 419 | FD_SET(priv->fd, &rfds); 420 | 421 | tv.tv_sec = 0; 422 | tv.tv_usec = ms * 1000; 423 | 424 | while (tv.tv_usec >= 1000000) { 425 | tv.tv_usec -= 1000000; 426 | tv.tv_sec++; 427 | } 428 | 429 | ret = select(priv->fd + 1, &rfds, NULL, NULL, &tv); 430 | 431 | if (ret <= 0) 432 | return ret; 433 | 434 | /* only report ok if the next message is from the peer we expect from */ 435 | cli_addr_size = sizeof(cli_addr); 436 | ret = recvfrom(priv->fd, &c, 1, MSG_PEEK, 437 | (struct sockaddr *) &cli_addr, &cli_addr_size); 438 | if (ret > 0) { 439 | if (cli_addr_size == priv->cli_addr_size && 440 | memcmp(&cli_addr, priv->cli_addr, sizeof(cli_addr)) == 0) 441 | return 1; 442 | } 443 | 444 | return 0; 445 | } 446 | 447 | static ssize_t dtls_push_func(gnutls_transport_ptr_t p, const void *data, size_t size) { 448 | priv_data_st *priv = p; 449 | 450 | #if 0 451 | // this can occour missplaced in output, but who cares?, if you, patch it! 452 | print_info("push (%lu (%lu))", size, size); 453 | print_hex(data, size); 454 | #endif 455 | 456 | return sendto(priv->fd, data, size, 0, priv->cli_addr, priv->cli_addr_size); 457 | } 458 | 459 | static ssize_t dtls_pull_func(gnutls_transport_ptr_t p, void *data, size_t size) { 460 | priv_data_st *priv = p; 461 | struct sockaddr_in cli_addr; 462 | socklen_t cli_addr_size; 463 | char buffer[64]; 464 | int ret; 465 | 466 | cli_addr_size = sizeof(cli_addr); 467 | ret = recvfrom(priv->fd, data, size, 0, 468 | (struct sockaddr *) &cli_addr, &cli_addr_size); 469 | 470 | #if 0 471 | if (ret > 0) { 472 | // this can occour missplaced in output, but who cares?, if you, patch it! 473 | print_info("pull (%d):", ret); 474 | print_hex(data, ret); 475 | } 476 | #endif 477 | 478 | if (ret == -1) 479 | return ret; 480 | 481 | if (cli_addr_size == priv->cli_addr_size && 482 | memcmp(&cli_addr, priv->cli_addr, sizeof(cli_addr)) == 0) 483 | return ret; 484 | 485 | print_warning("Denied connection from %s", human_addr((struct sockaddr *) 486 | &cli_addr, sizeof(cli_addr), buffer, sizeof(buffer))); 487 | 488 | gnutls_transport_set_errno(priv->session, EAGAIN); 489 | return -1; 490 | } 491 | 492 | static const char *human_addr(const struct sockaddr *sa, socklen_t salen, 493 | char *buf, size_t buflen) { 494 | const char *save_buf = buf; 495 | size_t l; 496 | 497 | if (!buf || !buflen) 498 | return NULL; 499 | 500 | *buf = '\0'; 501 | 502 | switch (sa->sa_family) { 503 | #if HAVE_IPV6 504 | case AF_INET6: 505 | snprintf(buf, buflen, "IPv6 "); 506 | break; 507 | #endif 508 | case AF_INET: 509 | snprintf(buf, buflen, "IPv4 "); 510 | break; 511 | } 512 | 513 | l = strlen(buf); 514 | buf += l; 515 | buflen -= l; 516 | 517 | if (getnameinfo(sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) != 0) 518 | return NULL; 519 | 520 | l = strlen(buf); 521 | buf += l; 522 | buflen -= l; 523 | 524 | strncat(buf, " port ", buflen); 525 | 526 | l = strlen(buf); 527 | buf += l; 528 | buflen -= l; 529 | 530 | if (getnameinfo(sa, salen, NULL, 0, buf, buflen, NI_NUMERICSERV) != 0) 531 | return NULL; 532 | 533 | return save_buf; 534 | } 535 | 536 | static int generate_dh_params(void) { 537 | int bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_LEGACY); 538 | 539 | /* Generate Diffie-Hellman parameters - for use with DHE 540 | * kx algorithms. When short bit length is used, it might 541 | * be wise to regenerate parameters often. 542 | */ 543 | gnutls_dh_params_init(&dh_params); 544 | gnutls_dh_params_generate2(dh_params, bits); 545 | 546 | return 0; 547 | } 548 | 549 | static int tls_run_server(struct server_opts *opts) { 550 | int err, listen_sd; 551 | int sd, ret; 552 | struct sockaddr_in sa_serv; 553 | struct sockaddr_in sa_cli; 554 | socklen_t client_len; 555 | char topbuf[512]; 556 | gnutls_session_t session; 557 | gnutls_anon_server_credentials_t anoncred; 558 | char buffer[opts->mtu + 1]; 559 | int optval = 1; 560 | 561 | // TODO: review printing 562 | 563 | if (gnutls_check_version("3.1.4") == NULL) { 564 | print_error("GnuTLS 3.1.4 or later is required for this example\n"); 565 | return -1; 566 | } 567 | 568 | /* for backwards compatibility with gnutls < 3.3.0 */ 569 | gnutls_global_init(); 570 | gnutls_anon_allocate_server_credentials(&anoncred); 571 | generate_dh_params(); 572 | gnutls_anon_set_server_dh_params(anoncred, dh_params); 573 | 574 | /* Socket operations 575 | */ 576 | listen_sd = socket(AF_INET, SOCK_STREAM, 0); 577 | SOCKET_ERR(listen_sd, "socket"); 578 | 579 | memset(&sa_serv, '\0', sizeof(sa_serv)); 580 | sa_serv.sin_family = AF_INET; 581 | sa_serv.sin_addr.s_addr = INADDR_ANY; 582 | sa_serv.sin_port = htons(opts->port); /* Server Port number */ 583 | 584 | setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (void *) &optval, sizeof(int)); 585 | 586 | err = bind(listen_sd, (struct sockaddr *) &sa_serv, sizeof(sa_serv)); 587 | SOCKET_ERR(err, "bind"); 588 | err = listen(listen_sd, 1024); 589 | SOCKET_ERR(err, "listen"); 590 | 591 | struct sockaddr_in sin; 592 | socklen_t len = sizeof(sin); 593 | err = getsockname(listen_sd, (struct sockaddr *)&sin, &len); 594 | SOCKET_ERR(err, "getsockname") 595 | print_info("Server ready. Listening to port '%d'.", ntohs(sin.sin_port)); 596 | 597 | if (opts->condition_initialized) { 598 | if (opts->port_mem) 599 | // TODO: get actual port 600 | *opts->port_mem = opts->port; 601 | pthread_cond_broadcast(opts->condition_initialized); 602 | } 603 | 604 | client_len = sizeof(sa_cli); 605 | for (;;) { 606 | gnutls_init(&session, GNUTLS_SERVER); 607 | gnutls_priority_set_direct(session, "NORMAL:+ANON-DH:+AES-128-GCM", NULL); 608 | gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred); 609 | 610 | sd = accept(listen_sd, (struct sockaddr *) &sa_cli, &client_len); 611 | 612 | print_info("- connection from %s, port %d", inet_ntop(AF_INET, &sa_cli.sin_addr, topbuf, 613 | sizeof(topbuf)), ntohs(sa_cli.sin_port)); 614 | 615 | gnutls_transport_set_int(session, sd); 616 | 617 | do { 618 | ret = gnutls_handshake(session); 619 | } while (ret < 0 && gnutls_error_is_fatal(ret) == 0); 620 | 621 | if (ret < 0) { 622 | close(sd); 623 | gnutls_deinit(session); 624 | print_error("*** Handshake has failed (%s)", gnutls_strerror(ret)); 625 | continue; 626 | } 627 | print_info("- Handshake was completed"); 628 | 629 | /* see the Getting peer's information example */ 630 | /* print_info(session); */ 631 | 632 | if (opts->ktls) { 633 | server_ktls_loop(opts, session, sd, (struct sockaddr *)&sa_cli, sizeof(sa_cli), buffer); 634 | } else { 635 | server_gnutls_loop(opts, session, buffer, sd); 636 | } 637 | 638 | /* do not wait for the peer to close the connection. 639 | */ 640 | gnutls_bye(session, GNUTLS_SHUT_WR); 641 | 642 | close(sd); 643 | gnutls_deinit(session); 644 | 645 | } 646 | 647 | close(listen_sd); 648 | gnutls_anon_free_server_credentials(anoncred); 649 | gnutls_global_deinit(); 650 | 651 | return 0; 652 | } 653 | 654 | extern void *run_server(void *arg) { 655 | int ret; 656 | struct server_opts *opts = (struct server_opts *) arg; 657 | 658 | if (opts->no_tls) { 659 | if (opts->tcp) { 660 | ret = plain_tcp_server(opts); 661 | } else { 662 | ret = plain_udp_server(opts); 663 | } 664 | } else { 665 | if (opts->tls) { 666 | ret = tls_run_server(opts); 667 | } else { 668 | ret = dtls_run_server(opts); 669 | } 670 | } 671 | 672 | server_err = ret; 673 | 674 | return NULL; 675 | } 676 | 677 | -------------------------------------------------------------------------------- /verify.c: -------------------------------------------------------------------------------- 1 | /* 2 | * af_ktls tool 3 | * 4 | * Copyright (C) 2016 Fridolin Pokorny 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by the Free 8 | * Software Foundation; either version 2 of the License, or (at your option) 9 | * any later version. 10 | */ 11 | 12 | #define _GNU_SOURCE 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "af_ktls/af_ktls.h" 26 | 27 | #include "common.h" 28 | #include "verify.h" 29 | 30 | #define TLS_PAYLOAD_MAX_LEN (1 << 14) 31 | #define DTLS_OVERHEAD (13 + 8 + 16) // TODO: rewrite 32 | #define TLS_OVERHEAD (5 + 8 + 16) // TODO: rewrite 33 | #define MIN(X, Y) ((X) > (Y) ? (Y) : (X)) 34 | #define AES128_GCM_KEY_SIZE ((size_t) 16) 35 | #define AES128_GCM_IV_SIZE ((size_t)8) 36 | #define AES128_GCM_SALT_SIZE ((size_t)4) 37 | 38 | static int pipe_write(int ksd, char *mem_send, size_t send_size, char *mem_recv, size_t recv_size, unsigned mtu) { 39 | int err; 40 | int p[2] = {0, 0}; 41 | size_t received; 42 | 43 | err = pipe(p); 44 | if (err < 0) { 45 | perror("pipe"); 46 | goto pipe_write_end; 47 | } 48 | 49 | memset(mem_send, 0x12, send_size); 50 | memset(mem_recv, 0x43, recv_size); 51 | 52 | print_info("verifying tls_sendpage() for MTU == %u, size of send data %ld, size of recv buffer %ld", mtu, send_size, recv_size); 53 | 54 | err = write(p[1], mem_send, send_size); 55 | if (err < 0) { 56 | perror("write"); 57 | goto pipe_write_end; 58 | } 59 | 60 | if (err != send_size) 61 | print_warning("write: return value differs from write count"); 62 | 63 | err = splice(p[0], NULL, ksd, NULL, send_size, 0); 64 | if (err < 0) { 65 | perror("splice"); 66 | goto pipe_write_end; 67 | } 68 | 69 | if (err != send_size) 70 | print_warning("splice: return value differs from splice len"); 71 | 72 | received = 0; 73 | do { 74 | err = recv(ksd, mem_recv, recv_size, 0); 75 | 76 | if (err < 0) { 77 | perror("received"); 78 | goto pipe_write_end; 79 | } 80 | 81 | if (memcmp(mem_send + received, mem_recv, err)) { 82 | print_error("sent and received data differ"); 83 | print_error("sent chunk:"); 84 | print_hex(mem_send + received, err); 85 | print_error("received:"); 86 | print_hex(mem_recv, recv_size); 87 | err = -EBADMSG; 88 | goto pipe_write_end; 89 | } 90 | 91 | received += err; 92 | 93 | if (err == 0) { 94 | print_error("premature end of connection"); 95 | err = -ECONNABORTED; 96 | break; 97 | } 98 | } while (received != send_size); 99 | 100 | if (received != send_size) { 101 | print_error("not all data received"); 102 | err = -EAGAIN; 103 | } 104 | 105 | pipe_write_end: 106 | if (p[0]) 107 | close(p[0]); 108 | if (p[1]) 109 | close(p[1]); 110 | return err; 111 | } 112 | 113 | extern int verify_sendpage(int ksd, bool tls) { 114 | int err; 115 | char *mem_send = NULL; 116 | char *mem_recv = NULL; 117 | size_t size; 118 | size_t mtu; 119 | 120 | assert(ksd > 0); 121 | 122 | mem_send = malloc(TLS_PAYLOAD_MAX_LEN + 1); 123 | mem_recv = malloc(TLS_PAYLOAD_MAX_LEN + 1); 124 | if (!mem_send || !mem_recv) { 125 | perror("malloc"); 126 | err = errno; 127 | goto verify_sendpage_end; 128 | } 129 | 130 | print_info("verifying tls_sendpage() implementation, page size == %ld", PAGE_SIZE); 131 | 132 | mtu = TLS_PAYLOAD_MAX_LEN; 133 | err = setsockopt(ksd, AF_KTLS, KTLS_SET_MTU, &mtu, sizeof(mtu)); 134 | if (err < 0) { 135 | perror("failed to perform setsockopt()"); 136 | goto verify_sendpage_end; 137 | } 138 | 139 | size = PAGE_SIZE >> 1; 140 | err = pipe_write(ksd, mem_send, size, mem_recv, size, mtu); 141 | if (err < 0) 142 | goto verify_sendpage_end; 143 | 144 | size = PAGE_SIZE; 145 | err = pipe_write(ksd, mem_send, size, mem_recv, size, mtu); 146 | if (err < 0) 147 | goto verify_sendpage_failed; 148 | 149 | size = (PAGE_SIZE << 1) + 10; 150 | err = pipe_write(ksd, mem_send, size, mem_recv, size, mtu); 151 | if (err < 0) 152 | goto verify_sendpage_end; 153 | 154 | //if (!tls) 155 | size = TLS_PAYLOAD_MAX_LEN - DTLS_OVERHEAD; 156 | //else 157 | // size = TLS_PAYLOAD_MAX_LEN - TLS_OVERHEAD; 158 | err = pipe_write(ksd, mem_send, size, mem_recv, size, mtu); 159 | if (err < 0) { 160 | print_error("failed to verify tls_sendpage() for size == %ld", size); 161 | goto verify_sendpage_end; 162 | } 163 | 164 | mtu = 100; 165 | err = setsockopt(ksd, AF_KTLS, KTLS_SET_MTU, &mtu, sizeof(mtu)); 166 | if (err < 0) { 167 | perror("failed to perform setsockopt()"); 168 | goto verify_sendpage_end; 169 | } 170 | 171 | size = PAGE_SIZE; 172 | err = pipe_write(ksd, mem_send, size, mem_recv, size, mtu); 173 | if (err < 0) 174 | goto verify_sendpage_failed; 175 | 176 | size = PAGE_SIZE*2 + 42; 177 | err = pipe_write(ksd, mem_send, size, mem_recv, size, mtu); 178 | if (err < 0) 179 | goto verify_sendpage_failed; 180 | 181 | err = 0; 182 | print_info("verify tls_sendpage() passed"); 183 | 184 | verify_sendpage_failed: 185 | if (err < 0) 186 | print_error("failed to verify tls_sendpage() for size == %ld", size); 187 | 188 | verify_sendpage_end: 189 | if (mem_send) 190 | free(mem_send); 191 | if (mem_recv) 192 | free(mem_recv); 193 | return err; 194 | } 195 | 196 | static int send_recv(int ksd, char *mem_send, size_t send_size, char *mem_recv, size_t recv_size) { 197 | int err; 198 | size_t received; 199 | 200 | memset(mem_send, 0x98, send_size); 201 | memset(mem_recv, 0x67, send_size); 202 | 203 | print_info("verifying tls_sendmsg()/tls_recvmsg(), size of send data %ld, size of recv buffer %ld", send_size, recv_size); 204 | 205 | err = send(ksd, mem_send, send_size, 0); 206 | if (err < 0) { 207 | perror("send"); 208 | goto send_recv_end; 209 | } 210 | 211 | if (err != send_size) 212 | print_warning("send returned different"); 213 | 214 | received = 0; 215 | do { 216 | err = recv(ksd, mem_recv, recv_size, 0); 217 | if (err < 0) { 218 | perror("recv"); 219 | goto send_recv_end; 220 | } 221 | 222 | if (err == 0) { 223 | print_error("premature end of connection"); 224 | err = -ECONNABORTED; 225 | goto send_recv_end; 226 | } 227 | 228 | if (memcmp(mem_send + received, mem_recv, err)) { 229 | print_error("sent and received data differ"); 230 | print_error("sent chunk:"); 231 | print_hex(mem_send + received, err); 232 | print_error("received:"); 233 | print_hex(mem_recv, recv_size); 234 | err = -EBADMSG; 235 | goto send_recv_end; 236 | } 237 | 238 | received += err; 239 | 240 | } while(send_size != received); 241 | 242 | send_recv_end: 243 | return err; 244 | } 245 | 246 | extern int verify_transmission(int ksd) { 247 | int err; 248 | size_t size; 249 | char *mem_send = NULL; 250 | char *mem_recv = NULL; 251 | 252 | assert(ksd > 0); 253 | 254 | print_info("verifying tls_sendmsg()/tls_recvmsg() implementation, page size == %ld", PAGE_SIZE); 255 | 256 | mem_send = malloc(TLS_PAYLOAD_MAX_LEN + 1); 257 | mem_recv = malloc(TLS_PAYLOAD_MAX_LEN + 1); 258 | if (!mem_send || !mem_recv) { 259 | perror("malloc"); 260 | err = errno; 261 | goto verify_transmission_end; 262 | } 263 | 264 | /* 265 | * normal send() first 266 | */ 267 | size = TLS_PAYLOAD_MAX_LEN - DTLS_OVERHEAD; 268 | err = send_recv(ksd, mem_send, size, mem_recv, size); 269 | if (err < 0) 270 | goto verify_transmission_failed; 271 | 272 | size = 100; 273 | err = send_recv(ksd, mem_send, size, mem_recv, size); 274 | if (err < 0) 275 | goto verify_transmission_failed; 276 | 277 | size = (PAGE_SIZE*2) + 42; 278 | err = send_recv(ksd, mem_send, size, mem_recv, size); 279 | if (err < 0) 280 | goto verify_transmission_failed; 281 | 282 | size = PAGE_SIZE; 283 | err = send_recv(ksd, mem_send, size, mem_recv, size); 284 | if (err < 0) 285 | goto verify_transmission_failed; 286 | 287 | /* 288 | * Try to send in a record more than allowed 289 | */ 290 | 291 | print_info("trying to send more than allowed per record - error signalization expected"); 292 | size = TLS_PAYLOAD_MAX_LEN + 1; 293 | err = send(ksd, mem_send, size, 0); 294 | if (errno != E2BIG) { 295 | print_error("AF_KTLS allowed to send bigger record than allowed"); 296 | err = -EBADMSG; 297 | } 298 | 299 | err = 0; 300 | print_info("verify tls_sendmsg()/tls_recvmsg() passed"); 301 | 302 | verify_transmission_failed: 303 | if (err < 0) 304 | print_error("failed to verify tls_sendmsg()/tls_recvmsg() for size == %ld", size); 305 | 306 | verify_transmission_end: 307 | if (mem_send) 308 | free(mem_send); 309 | if (mem_recv) 310 | free(mem_recv); 311 | return err; 312 | } 313 | 314 | static int splice_read(int ksd, char *mem_send, size_t send_size, char *mem_recv, size_t recv_size) { 315 | int err; 316 | int p[2] = {0, 0}; 317 | size_t received; 318 | 319 | print_info("verifying tls_splice_read(), size of send data %ld, size of recv buffer %ld", send_size, recv_size); 320 | 321 | err = pipe(p); 322 | if (err < 0) { 323 | perror("pipe"); 324 | goto splice_read_end; 325 | } 326 | 327 | memset(mem_recv, 0x67, recv_size); 328 | memset(mem_send, 0x92, send_size); 329 | 330 | err = send(ksd, mem_send, send_size, 0); 331 | if (err < 0) { 332 | perror("send"); 333 | goto splice_read_end; 334 | } 335 | 336 | received = 0; 337 | do { 338 | // be careful with pipe buf len 339 | err = splice(ksd, NULL, p[1], NULL, recv_size, 0); 340 | if (err < 0) { 341 | perror("splice"); 342 | goto splice_read_end; 343 | } 344 | 345 | if (err != send_size) 346 | print_warning("splice returned different size"); 347 | 348 | err = read(p[0], mem_recv, recv_size); 349 | if (err < 0) 350 | perror("read"); 351 | 352 | if (memcmp(mem_send + received, mem_recv, err)) { 353 | print_error("sent and received data differ"); 354 | print_error("sent chunk:"); 355 | print_hex(mem_send + received, err); 356 | print_error("received:"); 357 | print_hex(mem_recv, recv_size); 358 | err = -EBADMSG; 359 | goto splice_read_end; 360 | } 361 | 362 | received += err; 363 | 364 | if (err == 0) { 365 | print_error("premature end of connection"); 366 | err = -ECONNABORTED; 367 | break; 368 | } 369 | } while (received != send_size); 370 | 371 | err = 0; 372 | 373 | splice_read_end: 374 | if (p[0]) 375 | close(p[0]); 376 | if (p[1]) 377 | close(p[1]); 378 | return err; 379 | } 380 | 381 | extern int verify_splice_read(int ksd) { 382 | int err; 383 | char *mem_recv = NULL; 384 | char *mem_send = NULL; 385 | size_t size; 386 | 387 | assert(ksd > 0); 388 | 389 | print_info("verifying tls_splice_read() implementation, page size == %ld", PAGE_SIZE); 390 | 391 | mem_send = malloc(TLS_PAYLOAD_MAX_LEN + 1); 392 | mem_recv = malloc(TLS_PAYLOAD_MAX_LEN + 1); 393 | if (!mem_send || !mem_recv) { 394 | perror("malloc"); 395 | err = -ENOMEM; 396 | goto verify_splice_read_end; 397 | } 398 | 399 | size = TLS_PAYLOAD_MAX_LEN - DTLS_OVERHEAD; 400 | err = splice_read(ksd, mem_send, size, mem_recv, size); 401 | if (err < 0) 402 | goto verify_splice_read_failed; 403 | 404 | size = 100; 405 | err = splice_read(ksd, mem_send, size, mem_recv, size); 406 | if (err < 0) 407 | goto verify_splice_read_failed; 408 | 409 | size = (PAGE_SIZE*2) + 42; 410 | err = splice_read(ksd, mem_send, size, mem_recv, size); 411 | if (err < 0) 412 | goto verify_splice_read_failed; 413 | 414 | size = PAGE_SIZE; 415 | err = splice_read(ksd, mem_send, size, mem_recv, size); 416 | if (err < 0) 417 | goto verify_splice_read_failed; 418 | 419 | err = 0; 420 | 421 | verify_splice_read_failed: 422 | if (err < 0) 423 | print_error("failed to verify tls_splice_read() for size == %ld", size); 424 | 425 | verify_splice_read_end: 426 | if (mem_recv) 427 | free(mem_recv); 428 | if (mem_send) 429 | free(mem_send); 430 | return err; 431 | } 432 | 433 | static int sockopt_iv(int ksd, bool recv) { 434 | int err; 435 | const int optname_set = recv ? KTLS_SET_IV_RECV : KTLS_SET_IV_SEND; 436 | const int optname_get = recv ? KTLS_GET_IV_RECV : KTLS_GET_IV_SEND; 437 | socklen_t optlen; 438 | char buf[AES128_GCM_IV_SIZE + 1]; 439 | char buf_tmp[AES128_GCM_IV_SIZE + 1]; 440 | 441 | print_info("trying to get IV, but not enough memory supplied"); 442 | optlen = AES128_GCM_IV_SIZE - 1; 443 | err = getsockopt(ksd, AF_KTLS, optname_get, buf, &optlen); 444 | if (err >= 0 || errno != ENOMEM) { 445 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 446 | err = -EBADMSG; 447 | goto sockopt_iv_end; 448 | } 449 | 450 | print_info("trying to set IV, but smaller IV size supplied"); 451 | optlen = AES128_GCM_IV_SIZE - 1; 452 | err = setsockopt(ksd, AF_KTLS, optname_set, buf, optlen); 453 | if (err >= 0 || errno != EBADMSG) { 454 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 455 | err = -EBADMSG; 456 | goto sockopt_iv_end; 457 | } 458 | 459 | print_info("trying to set IV, but bigger IV size supplied"); 460 | optlen = AES128_GCM_IV_SIZE - 1; 461 | err = setsockopt(ksd, AF_KTLS, optname_set, buf, optlen); 462 | if (err >= 0 || errno != EBADMSG) { 463 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 464 | err = -EBADMSG; 465 | goto sockopt_iv_end; 466 | } 467 | 468 | print_info("trying to set IV"); 469 | optlen = AES128_GCM_IV_SIZE; 470 | memset(buf, 0, sizeof(buf)); 471 | err = setsockopt(ksd, AF_KTLS, optname_set, buf, optlen); 472 | if (err < 0) { 473 | perror("setsockopt: failed to set IV"); 474 | goto sockopt_iv_end; 475 | } 476 | 477 | print_info("trying to get IV"); 478 | optlen = AES128_GCM_IV_SIZE; 479 | memset(buf_tmp, 0x11, sizeof(buf_tmp)); 480 | err = getsockopt(ksd, AF_KTLS, optname_get, buf_tmp, &optlen); 481 | if (err < 0) { 482 | perror("getsockopt: failed to get IV"); 483 | goto sockopt_iv_end; 484 | } 485 | 486 | if (optlen != AES128_GCM_IV_SIZE) { 487 | print_error("getsockopt: optlen does not match IV size"); 488 | err = -EBADMSG; 489 | goto sockopt_iv_end; 490 | } 491 | 492 | if (memcmp(buf, buf_tmp, AES128_GCM_IV_SIZE)) { 493 | print_error("set and received IV differs from "); 494 | err = -EBADMSG; 495 | goto sockopt_iv_end; 496 | } 497 | 498 | err = 0; 499 | 500 | sockopt_iv_end: 501 | return err; 502 | } 503 | 504 | static int sockopt_key(int ksd, bool recv) { 505 | int err; 506 | const int optname_set = recv ? KTLS_SET_KEY_RECV : KTLS_SET_KEY_SEND; 507 | const int optname_get = recv ? KTLS_GET_KEY_RECV : KTLS_GET_KEY_SEND; 508 | socklen_t optlen; 509 | char buf[AES128_GCM_KEY_SIZE + 1]; 510 | char buf_tmp[AES128_GCM_KEY_SIZE + 1]; 511 | 512 | print_info("trying to get key, but not enough memory supplied"); 513 | optlen = AES128_GCM_KEY_SIZE - 1; 514 | err = getsockopt(ksd, AF_KTLS, optname_get, buf, &optlen); 515 | if (err >= 0 || errno != ENOMEM) { 516 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 517 | err = -EBADMSG; 518 | goto sockopt_key_end; 519 | } 520 | 521 | print_info("trying to set key, but smaller key size supplied"); 522 | optlen = AES128_GCM_KEY_SIZE - 1; 523 | err = setsockopt(ksd, AF_KTLS, optname_set, buf, optlen); 524 | if (err >= 0 || errno != EBADMSG) { 525 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 526 | err = -EBADMSG; 527 | goto sockopt_key_end; 528 | } 529 | 530 | print_info("trying to set key, but bigger key size supplied"); 531 | optlen = AES128_GCM_KEY_SIZE - 1; 532 | err = setsockopt(ksd, AF_KTLS, optname_set, buf, optlen); 533 | if (err >= 0 || errno != EBADMSG) { 534 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 535 | err = -EBADMSG; 536 | goto sockopt_key_end; 537 | } 538 | 539 | print_info("trying to set key"); 540 | optlen = AES128_GCM_KEY_SIZE; 541 | memset(buf, 0, sizeof(buf)); 542 | err = setsockopt(ksd, AF_KTLS, optname_set, buf, optlen); 543 | if (err < 0) { 544 | perror("setsockopt: failed to set key"); 545 | goto sockopt_key_end; 546 | } 547 | 548 | print_info("trying to get key"); 549 | optlen = AES128_GCM_KEY_SIZE; 550 | memset(buf_tmp, 0x11, sizeof(buf_tmp)); 551 | err = getsockopt(ksd, AF_KTLS, optname_get, buf_tmp, &optlen); 552 | if (err < 0) { 553 | perror("getsockopt: failed to get key"); 554 | goto sockopt_key_end; 555 | } 556 | 557 | if (optlen != AES128_GCM_KEY_SIZE) { 558 | print_error("getsockopt: optlen does not match key size"); 559 | err = -EBADMSG; 560 | goto sockopt_key_end; 561 | } 562 | 563 | if (memcmp(buf, buf_tmp, AES128_GCM_KEY_SIZE)) { 564 | print_error("set and received key differs from "); 565 | err = -EBADMSG; 566 | goto sockopt_key_end; 567 | } 568 | 569 | err = 0; 570 | 571 | sockopt_key_end: 572 | return err; 573 | } 574 | 575 | static int sockopt_salt(int ksd, bool recv) { 576 | int err; 577 | const int optname_set = recv ? KTLS_SET_SALT_RECV : KTLS_SET_SALT_SEND; 578 | const int optname_get = recv ? KTLS_GET_SALT_RECV : KTLS_GET_SALT_SEND; 579 | socklen_t optlen; 580 | char buf[AES128_GCM_SALT_SIZE + 1]; 581 | char buf_tmp[AES128_GCM_SALT_SIZE + 1]; 582 | 583 | print_info("trying to get salt, but not enough memory supplied"); 584 | optlen = AES128_GCM_SALT_SIZE - 1; 585 | err = getsockopt(ksd, AF_KTLS, optname_get, buf, &optlen); 586 | if (err >= 0 || errno != ENOMEM) { 587 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 588 | err = -EBADMSG; 589 | goto sockopt_salt_end; 590 | } 591 | 592 | print_info("trying to set salt, but smaller salt size supplied"); 593 | optlen = AES128_GCM_SALT_SIZE - 1; 594 | err = setsockopt(ksd, AF_KTLS, optname_set, buf, optlen); 595 | if (err >= 0 || errno != EBADMSG) { 596 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 597 | err = -EBADMSG; 598 | goto sockopt_salt_end; 599 | } 600 | 601 | print_info("trying to set salt, but bigger salt size supplied"); 602 | optlen = AES128_GCM_SALT_SIZE - 1; 603 | err = setsockopt(ksd, AF_KTLS, optname_set, buf, optlen); 604 | if (err >= 0 || errno != EBADMSG) { 605 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 606 | err = -EBADMSG; 607 | goto sockopt_salt_end; 608 | } 609 | 610 | print_info("trying to set salt"); 611 | optlen = AES128_GCM_SALT_SIZE; 612 | memset(buf, 0, sizeof(buf)); 613 | err = setsockopt(ksd, AF_KTLS, optname_set, buf, optlen); 614 | if (err < 0) { 615 | perror("setsockopt: failed to set salt"); 616 | goto sockopt_salt_end; 617 | } 618 | print_info("trying to get salt"); 619 | optlen = AES128_GCM_SALT_SIZE; 620 | memset(buf_tmp, 0x11, sizeof(buf_tmp)); 621 | err = getsockopt(ksd, AF_KTLS, optname_get, buf_tmp, &optlen); 622 | if (err < 0) { 623 | perror("getsockopt: failed to get salt"); 624 | goto sockopt_salt_end; 625 | } 626 | 627 | if (optlen != AES128_GCM_SALT_SIZE) { 628 | print_error("getsockopt: optlen does not match salt size"); 629 | err = -EBADMSG; 630 | goto sockopt_salt_end; 631 | } 632 | 633 | if (memcmp(buf, buf_tmp, AES128_GCM_SALT_SIZE)) { 634 | print_error("set and received salt differs from "); 635 | err = -EBADMSG; 636 | goto sockopt_salt_end; 637 | } 638 | 639 | err = 0; 640 | 641 | sockopt_salt_end: 642 | return err; 643 | } 644 | 645 | static int sockopt_mtu(int ksd, bool tls) { 646 | int err; 647 | const size_t probe_mtu = 1280; 648 | size_t mtu; 649 | socklen_t size; 650 | 651 | print_info("trying to set MTU"); 652 | mtu = probe_mtu; 653 | err = setsockopt(ksd, AF_KTLS, KTLS_SET_MTU, &mtu, sizeof(mtu)); 654 | if (err < 0) { 655 | perror("setsockopt"); 656 | goto sockopt_mtu_end; 657 | } 658 | 659 | print_info("trying to get MTU"); 660 | mtu = 0; 661 | size = sizeof(mtu); 662 | err = getsockopt(ksd, AF_KTLS, KTLS_GET_MTU, &mtu, &size); 663 | if (err < 0) { 664 | perror("getsockopt"); 665 | goto sockopt_mtu_end; 666 | } 667 | 668 | if (mtu != probe_mtu) { 669 | print_error("set and get MTU are different; set: %lu, got: %lu", probe_mtu, mtu); 670 | err = -EBADMSG; 671 | goto sockopt_mtu_end; 672 | } 673 | 674 | if (sizeof(mtu) != size) { 675 | print_error("suspicious MTU size from getsockopt(2) (%u)", size); 676 | err = -EBADMSG; 677 | goto sockopt_mtu_end; 678 | } 679 | 680 | err = 0; 681 | 682 | sockopt_mtu_end: 683 | return err; 684 | } 685 | 686 | static int sockopt_unbinded(void) { 687 | int err; 688 | int ksd = 0; 689 | size_t mtu; 690 | int p[2] = {0, 0}; 691 | const char buf_len = AES128_GCM_KEY_SIZE; 692 | char buf[buf_len]; 693 | socklen_t optlen; 694 | 695 | /* 696 | * SEQPACKET is not supported 697 | */ 698 | //print_info("trying to create unsupported type"); 699 | //ksd = socket(AF_KTLS, SOCK_SEQPACKET, 0); 700 | //if (ksd >= 0 || errno != ESOCKTNOSUPPORT) { 701 | // print_error("getsockopt: AF_KTLS did not populated error correctly"); 702 | // err = -EBADMSG; 703 | // goto sockopt_unbinded_end; 704 | //} 705 | 706 | print_info("creating unbinded socket"); 707 | ksd = socket(AF_KTLS, SOCK_DGRAM, 0); 708 | if (ksd < 0) { 709 | perror("socket"); 710 | err = errno; 711 | goto sockopt_unbinded_end; 712 | } 713 | 714 | print_info("getting IV recv from uninitialized socket"); 715 | optlen = AES128_GCM_IV_SIZE; 716 | err = getsockopt(ksd, AF_KTLS, KTLS_GET_IV_RECV, buf, &optlen); 717 | if (err >= 0 || errno != EBADMSG) { 718 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 719 | err = -EBADMSG; 720 | goto sockopt_unbinded_end; 721 | } 722 | 723 | print_info("setting IV recv from uninitialized socket"); 724 | optlen = AES128_GCM_IV_SIZE; 725 | err = setsockopt(ksd, AF_KTLS, KTLS_GET_IV_RECV, buf, optlen); 726 | if (err >= 0 || errno != EBADMSG) { 727 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 728 | err = -EBADMSG; 729 | goto sockopt_unbinded_end; 730 | } 731 | 732 | print_info("getting IV send from uninitialized socket"); 733 | optlen = AES128_GCM_IV_SIZE; 734 | err = getsockopt(ksd, AF_KTLS, KTLS_GET_IV_SEND, buf, &optlen); 735 | if (err >= 0 || errno != EBADMSG) { 736 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 737 | err = -EBADMSG; 738 | goto sockopt_unbinded_end; 739 | } 740 | 741 | print_info("setting IV send from uninitialized socket"); 742 | optlen = AES128_GCM_IV_SIZE; 743 | err = setsockopt(ksd, AF_KTLS, KTLS_GET_IV_SEND, buf, optlen); 744 | if (err >= 0 || errno != EBADMSG) { 745 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 746 | err = -EBADMSG; 747 | goto sockopt_unbinded_end; 748 | } 749 | 750 | print_info("getting key recv from uninitialized socket"); 751 | optlen = AES128_GCM_KEY_SIZE; 752 | err = getsockopt(ksd, AF_KTLS, KTLS_GET_KEY_RECV, buf, &optlen); 753 | if (err >= 0 || errno != EBADMSG) { 754 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 755 | err = -EBADMSG; 756 | goto sockopt_unbinded_end; 757 | } 758 | 759 | print_info("setting key recv from uninitialized socket"); 760 | optlen = AES128_GCM_KEY_SIZE; 761 | err = setsockopt(ksd, AF_KTLS, KTLS_GET_KEY_RECV, buf, optlen); 762 | if (err >= 0 || errno != EBADMSG) { 763 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 764 | err = -EBADMSG; 765 | goto sockopt_unbinded_end; 766 | } 767 | 768 | print_info("getting key send from uninitialized socket"); 769 | optlen = AES128_GCM_KEY_SIZE; 770 | err = getsockopt(ksd, AF_KTLS, KTLS_GET_KEY_SEND, buf, &optlen); 771 | if (err >= 0 || errno != EBADMSG) { 772 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 773 | err = -EBADMSG; 774 | goto sockopt_unbinded_end; 775 | } 776 | 777 | print_info("setting key send from uninitialized socket"); 778 | optlen = AES128_GCM_KEY_SIZE; 779 | err = setsockopt(ksd, AF_KTLS, KTLS_GET_KEY_SEND, buf, optlen); 780 | if (err >= 0 || errno != EBADMSG) { 781 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 782 | err = -EBADMSG; 783 | goto sockopt_unbinded_end; 784 | } 785 | 786 | print_info("getting salt recv from uninitialized socket"); 787 | optlen = AES128_GCM_SALT_SIZE; 788 | err = getsockopt(ksd, AF_KTLS, KTLS_GET_SALT_RECV, buf, &optlen); 789 | if (err >= 0 || errno != EBADMSG) { 790 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 791 | err = -EBADMSG; 792 | goto sockopt_unbinded_end; 793 | } 794 | 795 | print_info("setting salt recv from uninitialized socket"); 796 | optlen = AES128_GCM_SALT_SIZE; 797 | err = setsockopt(ksd, AF_KTLS, KTLS_GET_SALT_RECV, buf, optlen); 798 | if (err >= 0 || errno != EBADMSG) { 799 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 800 | err = -EBADMSG; 801 | goto sockopt_unbinded_end; 802 | } 803 | 804 | print_info("getting salt send from uninitialized socket"); 805 | optlen = AES128_GCM_SALT_SIZE; 806 | err = getsockopt(ksd, AF_KTLS, KTLS_GET_SALT_SEND, buf, &optlen); 807 | if (err >= 0 || errno != EBADMSG) { 808 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 809 | err = -EBADMSG; 810 | goto sockopt_unbinded_end; 811 | } 812 | 813 | print_info("setting salt send from uninitialized socket"); 814 | optlen = AES128_GCM_SALT_SIZE; 815 | err = setsockopt(ksd, AF_KTLS, KTLS_GET_SALT_SEND, buf, optlen); 816 | if (err >= 0 || errno != EBADMSG) { 817 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 818 | err = -EBADMSG; 819 | goto sockopt_unbinded_end; 820 | } 821 | 822 | print_info("getting MTU from uninitialized socket"); 823 | optlen = sizeof(mtu); 824 | err = getsockopt(ksd, AF_KTLS, KTLS_GET_MTU, &mtu, &optlen); 825 | if (err >= 0 || errno != EBADMSG) { 826 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 827 | err = -EBADMSG; 828 | goto sockopt_unbinded_end; 829 | } 830 | 831 | print_info("trying to call send(2) on unbinded socket"); 832 | err = send(ksd, buf, buf_len, 0); 833 | if (err >= 0 || errno != EBADMSG) { 834 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 835 | err = -EBADMSG; 836 | goto sockopt_unbinded_end; 837 | } 838 | 839 | print_info("trying to call recv(2) on unbinded socket"); 840 | err = recv(ksd, buf, buf_len, 0); 841 | if (err >= 0 || errno != EBADMSG) { 842 | print_error("getsockopt: AF_KTLS did not populated error correctly"); 843 | err = -EBADMSG; 844 | goto sockopt_unbinded_end; 845 | } 846 | 847 | /* 848 | * verify tls_sendpage() and tls_splice_read() 849 | */ 850 | err = pipe(p); 851 | if (err < 0) { 852 | perror("pipe"); 853 | goto sockopt_unbinded_end; 854 | } 855 | 856 | print_info("testing tls_splice_read() on uninitialized socket"); 857 | err = splice(ksd, NULL, p[1], NULL, 100, 0); 858 | if (err >= 0 || errno != EBADMSG) { 859 | print_error("AF_KTLS did not populated error correctly"); 860 | err = -EBADMSG; 861 | goto sockopt_unbinded_end; 862 | } 863 | 864 | err = write(p[1], buf, buf_len); 865 | if (err < 0) { 866 | print_error("write"); 867 | goto sockopt_unbinded_end; 868 | } 869 | 870 | print_info("testing tls_sendpage() on uninitialized socket"); 871 | err = splice(p[0], NULL, ksd, NULL, buf_len, 0); 872 | if (err >= 0 || errno != EBADMSG) { 873 | print_error("AF_KTLS did not populated error correctly"); 874 | err = -EBADMSG; 875 | goto sockopt_unbinded_end; 876 | } 877 | 878 | err = 0; 879 | 880 | sockopt_unbinded_end: 881 | if (p[0]) 882 | close(p[0]); 883 | if (p[1]) 884 | close(p[1]); 885 | if (ksd) 886 | close(ksd); 887 | return err; 888 | } 889 | 890 | extern int verify_handling(int ksd, bool tls) { 891 | // TODO: sockopt_{iv,key,salt} can be merged into one 892 | int err; 893 | 894 | assert(ksd > 0); 895 | 896 | print_info("verifying tls_setsockopt()/tls_getsockopt() implementation"); 897 | 898 | /* 899 | * Expected AES GCM, currently the only supported cipher by AF_KTLS 900 | */ 901 | err = sockopt_iv(ksd, 0); 902 | if (err < 0) { 903 | print_error("failed to verify tls_setsockopt()/tls_getsockopt() of IV recv"); 904 | goto verify_handling_end; 905 | } else { 906 | print_info("tls_setsockopt()/tls_getsockopt() of IV recv passed"); 907 | } 908 | 909 | err = sockopt_iv(ksd, 1); 910 | if (err < 0) { 911 | print_error("failed to verify tls_setsockopt()/tls_getsockopt() of IV send"); 912 | goto verify_handling_end; 913 | } else { 914 | print_info("tls_setsockopt()/tls_getsockopt() of IV send passed"); 915 | } 916 | 917 | err = sockopt_key(ksd, 0); 918 | if (err < 0) { 919 | print_error("failed to verify tls_setsockopt()/tls_getsockopt() of key recv"); 920 | goto verify_handling_end; 921 | } else { 922 | print_info("tls_setsockopt()/tls_getsockopt() of key recv passed"); 923 | } 924 | 925 | err = sockopt_key(ksd, 1); 926 | if (err < 0) { 927 | print_error("failed to verify tls_setsockopt()/tls_getsockopt() of key send"); 928 | goto verify_handling_end; 929 | } else { 930 | print_info("tls_setsockopt()/tls_getsockopt() of key send passed"); 931 | } 932 | 933 | err = sockopt_salt(ksd, 0); 934 | if (err < 0) { 935 | print_error("failed to verify tls_setsockopt()/tls_getsockopt() of salt recv"); 936 | goto verify_handling_end; 937 | } else { 938 | print_info("tls_setsockopt()/tls_getsockopt() of salt recv passed"); 939 | } 940 | 941 | err = sockopt_salt(ksd, 0); 942 | if (err < 0) { 943 | print_error("failed to verify tls_setsockopt()/tls_getsockopt() of salt send"); 944 | goto verify_handling_end; 945 | } else { 946 | print_info("tls_setsockopt()/tls_getsockopt() of salt send passed"); 947 | } 948 | 949 | err = sockopt_mtu(ksd, tls); 950 | if (err < 0) { 951 | print_error("failed to verify tls_setsockopt()/tls_getsockopt() of MTU"); 952 | goto verify_handling_end; 953 | } else { 954 | print_info("tls_setsockopt()/tls_getsockopt() of MTU passed"); 955 | } 956 | 957 | /* 958 | * Operations on nonbinded socket should reveal errors 959 | */ 960 | err = sockopt_unbinded(); 961 | if (err < 0) { 962 | print_error("failed to verify correct behaviour of AF_KTLS on unbinded socket"); 963 | goto verify_handling_end; 964 | } else { 965 | print_info("tls_setsockopt()/tls_getsockopt() on unbinded socket passed"); 966 | } 967 | 968 | print_info("vefify handling passed, the connection will not be closed " 969 | "properly since socket state is tainted"); 970 | 971 | err = 0; 972 | 973 | verify_handling_end: 974 | return err; 975 | } 976 | 977 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | {one line to give the program's name and a brief idea of what it does.} 635 | Copyright (C) {year} {name of author} 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | {project} Copyright (C) {year} {fullname} 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /action.c: -------------------------------------------------------------------------------- 1 | /* 2 | * af_ktls tool 3 | * 4 | * Copyright (C) 2016 Fridolin Pokorny 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by the Free 8 | * Software Foundation; either version 2 of the License, or (at your option) 9 | * any later version. 10 | */ 11 | 12 | #define _GNU_SOURCE 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | #include "ktls.h" 33 | #include "common.h" 34 | #include "benchmark.h" 35 | #include "client.h" 36 | 37 | #include "action.h" 38 | 39 | #define MIN(A, B) ((A) < (B) ? (A) : (B)) 40 | 41 | static ssize_t get_file_size(int fd) { 42 | ssize_t err; 43 | ssize_t filesize; 44 | 45 | filesize = lseek(fd, 0L, SEEK_END); 46 | if (filesize < 0) { 47 | perror("lseek() to EOF"); 48 | err = filesize; 49 | goto out; 50 | } 51 | 52 | err = lseek(fd, 0L, SEEK_SET); 53 | if (err < 0) { 54 | perror("lseek() to beginning"); 55 | goto out; 56 | } 57 | 58 | return filesize; 59 | 60 | out: 61 | return err; 62 | } 63 | 64 | static void print_send_count_stats(const struct client_opts *opts, bool gnutls, size_t total_sent, size_t total_recv, double clocks) { 65 | const char *json_msg = \ 66 | " {\n" 67 | " \"test\": \"%s\",\n" 68 | " \"type\": \"count\",\n" 69 | " \"configuration\": {\n" 70 | " \"size\": %lu,\n" 71 | " \"count\": %u\n" 72 | " },\n" 73 | " \"result\": {\n" 74 | " \"sent\": %lu,\n" 75 | " \"received\": %lu,\n" 76 | " \"elapsed\": %g\n" 77 | " }\n" 78 | " }"; 79 | const char *txt_msg = \ 80 | "statistics for %s:\n" 81 | "data size in packet: %lu\n" 82 | "number of calls: %u\n" 83 | "total bytes sent: %lu\n" 84 | "total bytes received: %lu\n" 85 | "CPU clock time: %g\n"; 86 | 87 | const char *msg = opts->json ? json_msg : txt_msg; 88 | const char *name = gnutls ? "gnutls_record_send()" : "send(2)"; 89 | const size_t count = gnutls ? opts->send_gnutls_count : opts->send_ktls_count; 90 | 91 | print_stats(msg, name, opts->payload_size, count, total_sent, total_recv, clocks); 92 | } 93 | 94 | static void print_send_time_stats(const struct client_opts *opts, bool gnutls, size_t total_sent, size_t total_recv, double elapsed) { 95 | const char *json_msg = \ 96 | " {\n" 97 | " \"test\": \"%s\",\n" 98 | " \"type\": \"time\",\n" 99 | " \"configuration\": {\n" 100 | " \"size\": %lu,\n" 101 | " \"time\": %u\n" 102 | " },\n" 103 | " \"result\": {\n" 104 | " \"sent\": %lu,\n" 105 | " \"received\": %lu,\n" 106 | " \"elapsed\": %g\n" 107 | " }\n" 108 | " }"; 109 | const char *txt_msg = \ 110 | "statistics for %s:\n" 111 | "data size in packet: %lu\n" 112 | "number of seconds: %lu\n" 113 | "total bytes sent: %lu\n" 114 | "total bytes received: %lu\n" 115 | "elapsed time: %g\n"; 116 | 117 | const char *msg = opts->json ? json_msg : txt_msg; 118 | const char *name = gnutls ? "gnutls_record_send()" : "send(2)"; 119 | const size_t time = gnutls ? opts->send_gnutls_time : opts->send_ktls_time; 120 | 121 | print_stats(msg, name, opts->payload_size, time, total_sent, total_recv, elapsed); 122 | } 123 | 124 | static void print_raw_send_time_stats(const struct client_opts *opts, size_t total_sent, size_t total_recv, double elapsed) { 125 | const char *json_msg = \ 126 | " {\n" 127 | " \"test\": \"raw send, enc recv\",\n" 128 | " \"type\": \"time\",\n" 129 | " \"configuration\": {\n" 130 | " \"size\": %lu,\n" 131 | " \"time\": %u\n" 132 | " },\n" 133 | " \"result\": {\n" 134 | " \"sent\": %lu,\n" 135 | " \"received\": %lu,\n" 136 | " \"elapsed\": %g\n" 137 | " }\n" 138 | " }"; 139 | const char *txt_msg = \ 140 | "statistics for raw senc, enc recv:\n" 141 | "data size in packet: %lu\n" 142 | "number of seconds: %lu\n" 143 | "total bytes sent: %lu\n" 144 | "total bytes received: %lu\n" 145 | "elapsed time: %g\n"; 146 | 147 | const char *msg = opts->json ? json_msg : txt_msg; 148 | 149 | print_stats(msg, opts->payload_size, opts->raw_send_time, total_sent, total_recv, elapsed); 150 | } 151 | 152 | static void print_splice_count_stats(const struct client_opts *opts, size_t total_sent, size_t total_recv, double clocks) { 153 | const char *json_msg = \ 154 | " {\n" 155 | " \"test\": \"splice(2)\",\n" 156 | " \"type\": \"count\",\n" 157 | " \"configuration\": {\n" 158 | " \"size\": %lu,\n" 159 | " \"count\": %u\n" 160 | " },\n" 161 | " \"result\": {\n" 162 | " \"sent\": %lu,\n" 163 | " \"received\": %lu,\n" 164 | " \"elapsed\": %g\n" 165 | " }\n" 166 | " }"; 167 | const char *txt_msg = \ 168 | "statistics for splice(2):\n" 169 | "data size per call: %lu\n" 170 | "number of calls: %u\n" 171 | "total bytes sent: %lu\n" 172 | "total bytes received: %lu\n" 173 | "CPU clock time: %g\n"; 174 | 175 | const char *msg = opts->json ? json_msg : txt_msg; 176 | 177 | print_stats(msg, opts->payload_size, opts->splice_count, total_sent, total_recv, clocks); 178 | } 179 | 180 | static void print_splice_time_stats(const struct client_opts *opts, size_t total_sent, size_t total_recv, double elapsed) { 181 | const char *json_msg = \ 182 | " {\n" 183 | " \"test\": \"splice(2)\",\n" 184 | " \"type\": \"time\",\n" 185 | " \"configuration\": {\n" 186 | " \"size\": %lu\n" 187 | " },\n" 188 | " \"result\": {\n" 189 | " \"sent\": %lu,\n" 190 | " \"received\": %lu,\n" 191 | " \"elapsed\": %g\n" 192 | " }\n" 193 | " }"; 194 | const char *txt_msg = \ 195 | "statistics for splice(2):\n" 196 | "data size per call: %lu\n" 197 | "total bytes sent: %lu\n" 198 | "total bytes received: %lu\n" 199 | "elapsed time: %g\n"; 200 | 201 | const char *msg = opts->json ? json_msg : txt_msg; 202 | 203 | print_stats(msg, opts->payload_size, total_sent, total_recv, elapsed); 204 | } 205 | 206 | static void print_sendfile_mmap_stats(const struct client_opts *opts, size_t filesize, size_t total_sent, double clocks) { 207 | const char *json_msg = \ 208 | " {\n" 209 | " \"test\": \"sendfile mmap(2)\",\n" 210 | " \"type\": \"time\",\n" 211 | " \"configuration\": {\n" 212 | " \"file\": \"%s\",\n" 213 | " \"file-size\": %lu,\n" 214 | " \"mtu\": %lu\n" 215 | " },\n" 216 | " \"result\": {\n" 217 | " \"sent\": %lu,\n" 218 | " \"received\": 0,\n" 219 | " \"elapsed\": %g\n" 220 | " }\n" 221 | " }"; 222 | const char *txt_msg = \ 223 | "file: '%s'\n" 224 | "file size: %lu\n" 225 | "total bytes sent: %lu\n" 226 | "CPU clock time: %0.4g\n"; 227 | 228 | if (opts->json) 229 | print_stats(json_msg, 230 | opts->sendfile_mmap, 231 | filesize, 232 | opts->sendfile_mtu, 233 | total_sent, 234 | clocks); 235 | else 236 | print_stats(txt_msg, opts->sendfile_mmap, filesize, total_sent, clocks); 237 | } 238 | 239 | 240 | static void print_sendfile_user_stats(const struct client_opts *opts, size_t filesize, size_t total_sent, double clocks) { 241 | const char *json_msg = \ 242 | " {\n" 243 | " \"test\": \"send file user\",\n" 244 | " \"type\": \"time\",\n" 245 | " \"configuration\": {\n" 246 | " \"file\": \"%s\",\n" 247 | " \"file-size\": %lu,\n" 248 | " \"mtu\": %lu\n" 249 | " },\n" 250 | " \"result\": {\n" 251 | " \"sent\": %lu,\n" 252 | " \"received\": 0,\n" 253 | " \"elapsed\": %g\n" 254 | " }\n" 255 | " }"; 256 | const char *txt_msg = \ 257 | "file: '%s'\n" 258 | "file size: %lu\n" 259 | "total bytes sent: %lu\n" 260 | "CPU clock time: %0.4g\n"; 261 | 262 | if (opts->json) 263 | print_stats(json_msg, 264 | opts->sendfile_user, 265 | filesize, 266 | opts->sendfile_mtu, 267 | total_sent, 268 | clocks); 269 | else 270 | print_stats(txt_msg, opts->sendfile_user, filesize, total_sent, clocks); 271 | } 272 | 273 | static void print_sendfile_stats(const struct client_opts *opts, size_t filesize, size_t total_sent, double clocks) { 274 | const char *json_msg = \ 275 | " {\n" 276 | " \"test\": \"sendfile(2)\",\n" 277 | " \"type\": \"time\",\n" 278 | " \"configuration\": {\n" 279 | " \"file\": \"%s\",\n" 280 | " \"file-size\": %lu,\n" 281 | " \"mtu\": %lu\n" 282 | " },\n" 283 | " \"result\": {\n" 284 | " \"sent\": %lu,\n" 285 | " \"received\": 0,\n" 286 | " \"elapsed\": %g\n" 287 | " }\n" 288 | " }"; 289 | const char *txt_msg = \ 290 | "file: '%s'\n" 291 | "file size: %lu\n" 292 | "total bytes sent: %lu\n" 293 | "CPU clock time: %0.4g\n"; 294 | 295 | if (opts->json) 296 | print_stats(json_msg, 297 | opts->sendfile, 298 | filesize, 299 | opts->sendfile_mtu, 300 | total_sent, 301 | clocks); 302 | else 303 | print_stats(txt_msg, opts->sendfile, filesize, total_sent, clocks); 304 | } 305 | 306 | static void print_splice_echo_time_stats(const struct client_opts *opts, size_t total_sent, size_t total_recv, double clocks) { 307 | const char *json_msg = \ 308 | " {\n" 309 | " \"test\": \"splice(2) echo\",\n" 310 | " \"type\": \"time\",\n" 311 | " \"configuration\": {\n" 312 | " \"size\": \"%u\"\n" 313 | " },\n" 314 | " \"result\": {\n" 315 | " \"sent\": %lu,\n" 316 | " \"received\": 0,\n" 317 | " \"elapsed\": %g\n" 318 | " }\n" 319 | " }"; 320 | const char *txt_msg = \ 321 | "payload: %lu\n" 322 | "total bytes sent: %lu\n" 323 | "total bytes received: %lu\n" 324 | "CPU clock time: %0.4g\n"; 325 | 326 | if (opts->json) 327 | print_stats(json_msg, 328 | opts->payload_size, 329 | total_sent, 330 | total_recv, 331 | clocks); 332 | else 333 | print_stats(txt_msg, opts->payload_size, total_sent, total_recv, clocks); 334 | } 335 | 336 | static void print_splice_send_raw_time_stats(const struct client_opts *opts, size_t total_sent, size_t total_recv, double clocks) { 337 | const char *json_msg = \ 338 | " {\n" 339 | " \"test\": \"splice(2) raw send\",\n" 340 | " \"type\": \"time\",\n" 341 | " \"configuration\": {\n" 342 | " \"size\": \"%u\",\n" 343 | " \"sendfile mtu\": \"%u\"\n" 344 | " },\n" 345 | " \"result\": {\n" 346 | " \"sent\": %lu,\n" 347 | " \"received\": %lu,\n" 348 | " \"elapsed\": %g\n" 349 | " }\n" 350 | " }"; 351 | const char *txt_msg = \ 352 | "payload: %lu\n" 353 | "sendfile mtu: %lu\n" 354 | "total bytes sent: %lu\n" 355 | "total bytes received: %lu\n" 356 | "CPU clock time: %0.4g\n"; 357 | 358 | if (opts->json) 359 | print_stats(json_msg, 360 | opts->payload_size, 361 | opts->sendfile_mtu, 362 | total_sent, 363 | total_recv, 364 | clocks); 365 | else 366 | print_stats(txt_msg, opts->payload_size, total_sent, total_recv, clocks); 367 | } 368 | 369 | static void print_splice_echo_count_stats(const struct client_opts *opts, size_t total_sent, size_t total_recv, double clocks) { 370 | const char *json_msg = \ 371 | " {\n" 372 | " \"test\": \"splice(2) echo\",\n" 373 | " \"type\": \"count\",\n" 374 | " \"configuration\": {\n" 375 | " \"size\": \"%u\",\n" 376 | " \"count\": \"%u\"\n" 377 | " },\n" 378 | " \"result\": {\n" 379 | " \"sent\": %lu,\n" 380 | " \"received\": 0,\n" 381 | " \"elapsed\": %g\n" 382 | " }\n" 383 | " }"; 384 | const char *txt_msg = \ 385 | "payload: %lu\n" 386 | "count: %lu\n" 387 | "total bytes sent: %lu\n" 388 | "total bytes received: %lu\n" 389 | "CPU clock time: %0.4g\n"; 390 | 391 | if (opts->json) 392 | print_stats(json_msg, 393 | opts->payload_size, 394 | opts->splice_echo_count, 395 | total_sent, 396 | total_recv, 397 | clocks); 398 | else 399 | print_stats(txt_msg, opts->payload_size, opts->splice_echo_count, total_sent, total_recv, clocks); 400 | } 401 | 402 | static void print_plain_stats(const struct client_opts *opts, const char *testname, const char *filename, size_t total_sent, size_t total_recv, double elapsed) { 403 | const char *json_msg = \ 404 | " {\n" 405 | " \"test\": \"%s\",\n" 406 | " \"type\": \"time\",\n" 407 | " \"configuration\": {\n" 408 | " \"filesize\": %lu,\n" 409 | " \"mtu\": %u,\n" 410 | " \"filename\": \"%s\"\n" 411 | " },\n" 412 | " \"result\": {\n" 413 | " \"sent\": %lu,\n" 414 | " \"received\": %lu,\n" 415 | " \"elapsed\": %g\n" 416 | " }\n" 417 | " }"; 418 | const char *txt_msg = \ 419 | "statistics for %s:\n" 420 | "file size (from param): %lu\n" 421 | "mtu: %lu\n" 422 | "file: %s\n" 423 | "total bytes sent: %lu\n" 424 | "total bytes received: %lu\n" 425 | "elapsed time: %g\n"; 426 | 427 | const char *msg = opts->json ? json_msg : txt_msg; 428 | 429 | print_stats(msg, testname, opts->sendfile_size, opts->sendfile_mtu, 430 | filename, total_sent, total_recv, elapsed); 431 | } 432 | 433 | extern int do_send_count(const struct client_opts *opts, int ksd, void *mem, gnutls_session_t session, int flags) { 434 | clock_t start, end; 435 | register int ret = -1; 436 | register size_t total_recv = 0; 437 | register size_t total_sent = 0; 438 | 439 | start = clock(); 440 | for (register unsigned i = 0; i < opts->send_ktls_count; i++) { 441 | ret = send(ksd, mem, opts->payload_size, flags); 442 | if (ret < 0) 443 | perror("send"); 444 | if (ret <= 0) 445 | break; 446 | total_sent += ret; 447 | #ifdef BENCHMARK_RECV 448 | ret = recv(ksd, mem, opts->payload_size, flags); 449 | if (ret < 0) 450 | perror("recv"); 451 | if (ret <= 0) 452 | break; 453 | total_recv += ret; 454 | #endif 455 | } 456 | end = clock(); 457 | 458 | print_send_count_stats(opts, 0, total_sent, total_recv, ((double) (end - start)) / CLOCKS_PER_SEC); 459 | return ret < 0 ? ret : total_sent; 460 | } 461 | 462 | extern int do_send_time(const struct client_opts *opts, int ksd, void *mem, int flags) { 463 | int err; 464 | long unsigned elapsed; 465 | register int ret; 466 | register size_t total_recv = 0; 467 | register size_t total_sent = 0; 468 | struct benchmark_st bst; 469 | 470 | memset(&bst, 0, sizeof(bst)); 471 | 472 | ret = start_benchmark(&bst, opts->send_ktls_time); 473 | if (ret < 0) { 474 | print_error("failed to set up timer"); 475 | return -1; 476 | } 477 | 478 | do { 479 | //printf("benchmark_must_finish: %d\n", benchmark_must_finish); 480 | ret = send(ksd, mem, opts->payload_size, flags); 481 | if (ret < 0) 482 | perror("send"); 483 | if (ret <= 0) 484 | break; 485 | total_sent += ret; 486 | #ifdef BENCHMARK_RECV 487 | ret = recv(ksd, mem, opts->payload_size, flags); 488 | if (ret < 0) 489 | perror("recv"); 490 | if (ret <= 0) 491 | break; 492 | total_recv += ret; 493 | #endif 494 | } while(benchmark_must_finish == 0); 495 | 496 | err = stop_benchmark(&bst, &elapsed); 497 | 498 | print_send_time_stats(opts, 0, total_sent, total_recv, (double) elapsed / 1000); 499 | if (err < 0) 500 | print_error("failed to stop timer"); 501 | 502 | return ret < 0 ? ret : total_sent; 503 | } 504 | 505 | extern int do_gnutls_send_count(const struct client_opts *opts, gnutls_session_t session, void *mem) { 506 | clock_t start, end; 507 | register int ret = -1; 508 | register size_t total_recv = 0; 509 | register size_t total_sent = 0; 510 | 511 | start = clock(); 512 | for (register unsigned i = 0; i < opts->send_gnutls_count; i++) { 513 | ret = gnutls_record_send(session, mem, opts->payload_size); 514 | if (ret < 0) 515 | break; 516 | total_sent += ret; 517 | #ifdef BENCHMARK_RECV 518 | ret = gnutls_record_recv(session, mem, opts->payload_size); 519 | if (ret < 0) 520 | break; 521 | total_recv += ret; 522 | #endif 523 | } 524 | end = clock(); 525 | 526 | if (ret < 0) 527 | gnutls_perror(ret); 528 | 529 | print_send_count_stats(opts, true, total_sent, total_recv, ((double) (end - start)) / CLOCKS_PER_SEC); 530 | return ret < 0 ? ret : total_sent; 531 | } 532 | 533 | extern int do_gnutls_send_time(const struct client_opts *opts, gnutls_session_t session, void *mem) { 534 | int err; 535 | long unsigned elapsed; 536 | register int ret; 537 | register size_t total_recv = 0; 538 | register size_t total_sent = 0; 539 | struct benchmark_st bst; 540 | 541 | memset(&bst, 0, sizeof(bst)); 542 | 543 | ret = start_benchmark(&bst, opts->send_gnutls_time); 544 | if (ret < 0) { 545 | print_error("failed to set up timer"); 546 | return -1; 547 | } 548 | 549 | do { 550 | ret = gnutls_record_send(session, mem, opts->payload_size); 551 | if (ret < 0) 552 | break; 553 | total_sent += ret; 554 | #ifdef BENCHMARK_RECV 555 | ret = gnutls_record_recv(session, mem, opts->payload_size); 556 | if (ret < 0) 557 | break; 558 | total_recv += ret; 559 | #endif 560 | } while(benchmark_must_finish == 0); 561 | 562 | if (ret < 0) 563 | gnutls_perror(ret); 564 | 565 | err = stop_benchmark(&bst, &elapsed); 566 | 567 | print_send_time_stats(opts, true, total_sent, total_recv, (double) elapsed / 1000); 568 | if (err < 0) 569 | print_error("failed to stop timer"); 570 | 571 | return ret < 0 ? ret : total_sent; 572 | } 573 | 574 | extern int do_splice_count(const struct client_opts *opts, int ksd) { 575 | int err; 576 | int ret; 577 | int fd_f = 0; 578 | int p[2] = {0, 0}; 579 | clock_t start, end; 580 | size_t total_sent = 0; 581 | size_t total_recv = 0; // not used now 582 | 583 | /* 584 | * we will perform splice(2) on /dev/zero in order to avoid the impact of 585 | * disk drive and FS 586 | */ 587 | 588 | err = pipe(p); 589 | if (err) 590 | return err; 591 | 592 | fd_f = open(opts->splice_file, O_RDONLY); 593 | if (fd_f < 0) { 594 | perror(opts->splice_file); 595 | return fd_f; 596 | } 597 | 598 | start = clock(); 599 | 600 | for (register unsigned i = 0; i < opts->splice_count; i++) { 601 | ret = splice(fd_f, NULL, p[1], NULL, opts->payload_size, 0); 602 | if (err < 0) { 603 | perror("splice"); 604 | err = ret; 605 | goto out; 606 | } 607 | 608 | if (ret != opts->payload_size) 609 | print_warning("splice(2) write size %d differs from return value %d", opts->payload_size, ret); 610 | 611 | ret = splice(p[0], NULL, ksd, NULL, opts->payload_size, 0); 612 | if (err < 0) { 613 | perror("splice"); 614 | err = ret; 615 | goto out; 616 | } 617 | 618 | if (ret != opts->payload_size) 619 | print_warning("splice(2) write size %d differs from return value %d", opts->payload_size, ret); 620 | 621 | total_sent += ret; 622 | } 623 | 624 | end = clock(); 625 | 626 | print_splice_count_stats(opts, total_sent, total_recv, ((double) (end - start)) / CLOCKS_PER_SEC); 627 | 628 | out: 629 | if (p[0]) 630 | close(p[0]); 631 | if (p[1]) 632 | close(p[1]); 633 | if (fd_f > 0) 634 | close(fd_f); 635 | 636 | return err; 637 | } 638 | 639 | 640 | extern int do_splice_send_raw_time(const struct client_opts *opts, int raw_sd, int ksd, void *mem) { 641 | int err; 642 | int ret; 643 | int p[2] = {0, 0}; 644 | size_t total_recv, total_sent; 645 | unsigned long elapsed; 646 | struct benchmark_st bst; 647 | 648 | memset(&bst, 0, sizeof(bst)); 649 | 650 | err = pipe(p); 651 | if (err) { 652 | perror("pipe"); 653 | return err; 654 | } 655 | 656 | // do initial send 657 | err = send(raw_sd, mem, opts->payload_size, 0); 658 | if (err < 0) { 659 | perror("send"); 660 | print_error("failed to do send"); 661 | return err; 662 | } 663 | 664 | if (err != opts->payload_size) 665 | print_warning("send %u, send() returned %d", opts->payload_size, err); 666 | 667 | total_recv = 0; 668 | total_sent = 0; 669 | 670 | ret = start_benchmark(&bst, opts->splice_send_raw_time); 671 | if (ret < 0) { 672 | print_error("failed to set up timer"); 673 | return -1; 674 | } 675 | 676 | do { 677 | err = splice(ksd, NULL, p[1], NULL, opts->payload_size, 0); 678 | if (err < 0) { 679 | perror("splice"); 680 | print_error("failed to do splice(2)"); 681 | goto out; 682 | } 683 | if (err == 0) 684 | break; 685 | 686 | total_recv += err; 687 | 688 | err = splice(p[0], NULL, raw_sd, NULL, opts->payload_size, 0); 689 | if (err < 0) { 690 | perror("splice"); 691 | print_error("failed to do splice(2)"); 692 | goto out; 693 | } 694 | 695 | if (err == 0) 696 | break; 697 | 698 | total_sent += err; 699 | 700 | } while(benchmark_must_finish == 0); 701 | 702 | out: 703 | ret = stop_benchmark(&bst, &elapsed); 704 | if (!ret) 705 | print_splice_send_raw_time_stats(opts, total_sent, total_recv, (double) elapsed / 1000); 706 | 707 | if (ret < 0) 708 | print_error("failed to stop timer"); 709 | 710 | if (p[0]) 711 | close(p[0]); 712 | if (p[1]) 713 | close(p[1]); 714 | 715 | return err; 716 | } 717 | 718 | 719 | extern int do_splice_time(const struct client_opts *opts, int ksd) { 720 | int err; 721 | int ret; 722 | int fd_f = 0; 723 | int p[2] = {0, 0}; 724 | size_t total_sent = 0; 725 | size_t total_recv = 0; // unused now 726 | unsigned long elapsed; 727 | struct benchmark_st bst; 728 | 729 | memset(&bst, 0, sizeof(bst)); 730 | 731 | err = pipe(p); 732 | if (err) 733 | return err; 734 | 735 | fd_f = open(opts->splice_file, O_RDONLY); 736 | if (fd_f < 0) { 737 | perror("open"); 738 | return fd_f; 739 | } 740 | 741 | ret = start_benchmark(&bst, opts->splice_time); 742 | if (ret < 0) { 743 | print_error("failed to set up timer"); 744 | return -1; 745 | } 746 | 747 | do { 748 | ret = splice(fd_f, NULL, p[1], NULL, opts->payload_size, 0); 749 | if (err < 0) { 750 | perror("splice"); 751 | err = ret; 752 | goto out; 753 | } 754 | 755 | if (ret == 0) 756 | break; 757 | 758 | if (ret != opts->payload_size) 759 | print_warning("splice(2) write size %d differs from return value %d", opts->payload_size, ret); 760 | 761 | ret = splice(p[0], NULL, ksd, NULL, opts->payload_size, 0); 762 | if (err < 0) { 763 | perror("splice(2):"); 764 | err = ret; 765 | goto out; 766 | } 767 | 768 | if (ret == 0) 769 | break; 770 | 771 | if (ret != opts->payload_size) 772 | print_warning("splice(2) write size %d differs from return value %d", opts->payload_size, ret); 773 | 774 | total_sent += ret; 775 | } while(benchmark_must_finish == 0); 776 | 777 | out: 778 | ret = stop_benchmark(&bst, &elapsed); 779 | if (!err) 780 | print_splice_time_stats(opts, total_sent, total_recv, (double) elapsed / 1000); 781 | 782 | if (ret < 0) 783 | print_error("failed to stop timer"); 784 | 785 | if (p[0]) 786 | close(p[0]); 787 | if (p[1]) 788 | close(p[1]); 789 | if (fd_f > 0) 790 | close(fd_f); 791 | 792 | return err; 793 | } 794 | 795 | extern int do_splice_echo_time(const struct client_opts *opts, int ksd, void *mem) { 796 | int err; 797 | int ret; 798 | int p[2] = {0, 0}; 799 | size_t total_recv, total_sent; 800 | unsigned long elapsed; 801 | struct benchmark_st bst; 802 | 803 | memset(&bst, 0, sizeof(bst)); 804 | 805 | err = pipe(p); 806 | if (err) { 807 | perror("pipe"); 808 | return err; 809 | } 810 | 811 | // do initial send, so we have data in echo'ed -- ping-pong :) 812 | err = send(ksd, mem, opts->payload_size, 0); 813 | if (err < 0) { 814 | perror("send"); 815 | return err; 816 | } 817 | 818 | if (err != opts->payload_size) 819 | print_warning("send %u, send() returned %d", opts->payload_size, err); 820 | 821 | ret = start_benchmark(&bst, opts->splice_echo_time); 822 | if (ret < 0) { 823 | print_error("failed to set up timer"); 824 | return -1; 825 | } 826 | 827 | total_recv = 0; 828 | total_sent = 0; 829 | do { 830 | err = splice(ksd, NULL, p[1], NULL, opts->payload_size, 0); 831 | if (err < 0) { 832 | perror("splice"); 833 | err = ret; 834 | goto out; 835 | } 836 | if (err == 0) 837 | break; 838 | 839 | total_recv += err; 840 | 841 | err = splice(p[0], NULL, ksd, NULL, opts->payload_size, 0); 842 | if (err < 0) { 843 | perror("splice(2):"); 844 | err = ret; 845 | goto out; 846 | } 847 | 848 | if (err == 0) 849 | break; 850 | 851 | total_sent += err; 852 | 853 | } while(benchmark_must_finish == 0); 854 | 855 | out: 856 | ret = stop_benchmark(&bst, &elapsed); 857 | if (!ret) 858 | print_splice_echo_time_stats(opts, total_sent, total_recv, (double) elapsed / 1000); 859 | 860 | if (ret < 0) 861 | print_error("failed to stop timer"); 862 | 863 | if (p[0]) 864 | close(p[0]); 865 | if (p[1]) 866 | close(p[1]); 867 | 868 | return err; 869 | } 870 | 871 | extern int do_splice_echo_count(const struct client_opts *opts, int ksd, void *mem) { 872 | int err; 873 | int p[2] = {0, 0}; 874 | clock_t start, end; 875 | size_t total_recv, total_sent; 876 | 877 | total_recv = 0; 878 | total_sent = 0; 879 | 880 | err = pipe(p); 881 | if (err) { 882 | perror("pipe"); 883 | return err; 884 | } 885 | 886 | // do initial send, so we have data in echo'ed -- ping-pong :) 887 | err = send(ksd, mem, opts->payload_size, 0); 888 | if (err < 0) { 889 | perror("send"); 890 | return err; 891 | } 892 | 893 | if (err != opts->payload_size) 894 | print_warning("send %u, send() returned %d", opts->payload_size, err); 895 | 896 | start = clock(); 897 | for (unsigned i = 0; i < opts->splice_echo_count; i++) { 898 | 899 | err = splice(ksd, NULL, p[1], NULL, opts->payload_size, 0); 900 | if (err < 0) { 901 | perror("splice"); 902 | goto out; 903 | } 904 | 905 | total_recv += err; 906 | 907 | err = splice(p[0], NULL, ksd, NULL, opts->payload_size, 0); 908 | if (err < 0) { 909 | perror("splice(2):"); 910 | goto out; 911 | } 912 | 913 | total_sent += err; 914 | } 915 | end = clock(); 916 | 917 | if (err > 0) 918 | print_splice_echo_count_stats(opts, total_sent, total_recv, ((double) (end - start)) / CLOCKS_PER_SEC); 919 | 920 | out: 921 | 922 | if (p[0]) 923 | close(p[0]); 924 | if (p[1]) 925 | close(p[1]); 926 | return err; 927 | } 928 | 929 | extern int do_sendfile_mmap(const struct client_opts *opts, gnutls_session_t session) { 930 | int err; 931 | int in_fd = 0; 932 | clock_t start, end; 933 | ssize_t total = 0; 934 | ssize_t filesize; 935 | char *buf = NULL; 936 | 937 | in_fd = open(opts->sendfile_mmap, O_RDONLY); 938 | if (in_fd < 0) { 939 | perror("open"); 940 | goto out; 941 | } 942 | 943 | if (opts->sendfile_size == 0) { 944 | filesize = lseek(in_fd, 0L, SEEK_END); 945 | if (filesize < 0) { 946 | perror("lseek() to EOF"); 947 | err = filesize; 948 | goto out; 949 | } 950 | err = lseek(in_fd, 0L, SEEK_SET); 951 | if (err < 0) { 952 | perror("lseek() to beginning"); 953 | goto out; 954 | } 955 | } else { 956 | filesize = opts->sendfile_size; 957 | } 958 | 959 | // we explicitly drop caches since we used seek 960 | DO_DROP_CACHES(opts); 961 | 962 | start = clock(); 963 | 964 | buf = mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, in_fd, /*offset*/ 0); 965 | if (buf == MAP_FAILED) { 966 | perror("mmap"); 967 | goto out; 968 | } 969 | 970 | for (total = 0; total != filesize; total += err) { 971 | err = gnutls_record_send(session, buf + total, MIN(opts->sendfile_mtu, filesize - total)); 972 | if (err < 0) { 973 | print_error("failed to send via Gnu TLS"); 974 | goto out; 975 | } 976 | } 977 | 978 | end = clock(); 979 | 980 | print_sendfile_mmap_stats(opts, filesize, total, ((double) (end - start)) / CLOCKS_PER_SEC); 981 | 982 | out: 983 | if (buf) 984 | munmap(buf, filesize); 985 | if (in_fd > 0) 986 | close(in_fd); 987 | 988 | return err; 989 | } 990 | 991 | extern int do_raw_send_time(const struct client_opts *opts, gnutls_session_t session, int raw_sd, void *mem) { 992 | int err; 993 | long unsigned elapsed; 994 | register int ret; 995 | register size_t total_recv = 0; 996 | register size_t total_sent = 0; 997 | struct benchmark_st bst; 998 | 999 | assert(raw_sd > 0); 1000 | 1001 | memset(&bst, 0, sizeof(bst)); 1002 | 1003 | // initial send 1004 | ret = send(raw_sd, mem, opts->payload_size, 0); 1005 | if (ret < 0) { 1006 | gnutls_perror(ret); 1007 | print_error("failed to do initial send"); 1008 | return -1; 1009 | } 1010 | 1011 | ret = start_benchmark(&bst, opts->raw_send_time); 1012 | if (ret < 0) { 1013 | print_error("failed to set up timer"); 1014 | return -1; 1015 | } 1016 | 1017 | do { 1018 | ret = gnutls_record_recv(session, mem, opts->payload_size); 1019 | if (ret < 0) { 1020 | gnutls_perror(ret); 1021 | print_error("failed to do gnutls_record_recv"); 1022 | break; 1023 | } 1024 | total_recv += ret; 1025 | 1026 | ret = send(raw_sd, mem, opts->payload_size, 0); 1027 | if (ret < 0) { 1028 | gnutls_perror(ret); 1029 | break; 1030 | } 1031 | total_sent += ret; 1032 | } while(benchmark_must_finish == 0 && ret > 0); 1033 | 1034 | if (ret > 0) { 1035 | err = stop_benchmark(&bst, &elapsed); 1036 | 1037 | print_raw_send_time_stats(opts, total_sent, total_recv, (double) elapsed / 1000); 1038 | if (err < 0) 1039 | print_error("failed to stop timer"); 1040 | } 1041 | 1042 | return ret < 0 ? ret : total_sent; 1043 | } 1044 | 1045 | extern int do_sendfile_user(const struct client_opts *opts, gnutls_session_t session) { 1046 | int err; 1047 | int in_fd = 0; 1048 | clock_t start, end; 1049 | ssize_t total = 0; 1050 | ssize_t filesize; 1051 | char *buf = NULL; 1052 | 1053 | in_fd = open(opts->sendfile_user, O_RDONLY); 1054 | if (in_fd < 0) { 1055 | perror(opts->sendfile_user); 1056 | err = -1; 1057 | goto do_sendfile_user_end; 1058 | } 1059 | 1060 | if (opts->sendfile_size == 0) { 1061 | filesize = lseek(in_fd, 0L, SEEK_END); 1062 | if (filesize < 0) { 1063 | perror("lseek() to EOF"); 1064 | err = -1; 1065 | goto do_sendfile_user_end; 1066 | } 1067 | err = lseek(in_fd, 0L, SEEK_SET); 1068 | if (err < 0) { 1069 | perror("lseek() to beginning"); 1070 | goto do_sendfile_user_end; 1071 | } 1072 | } else { 1073 | filesize = opts->sendfile_size; 1074 | } 1075 | 1076 | close(in_fd); 1077 | 1078 | buf = malloc(opts->sendfile_mtu); 1079 | if (!buf) { 1080 | perror("malloc"); 1081 | return -1; 1082 | } 1083 | 1084 | // we explicitly drop caches since we used seek 1085 | DO_DROP_CACHES(opts); 1086 | 1087 | start = clock(); 1088 | 1089 | in_fd = open(opts->sendfile_user, O_RDONLY); 1090 | if (in_fd < 0) { 1091 | perror(opts->sendfile_user); 1092 | err = -1; 1093 | goto do_sendfile_user_end; 1094 | } 1095 | 1096 | do { 1097 | err = read(in_fd, buf, opts->sendfile_mtu); 1098 | if (err < 0) { 1099 | perror("read"); 1100 | goto do_sendfile_user_end; 1101 | } 1102 | 1103 | err = gnutls_record_send(session, buf, err); 1104 | if (err < 0) { 1105 | print_error("failed to send via Gnu TLS"); 1106 | goto do_sendfile_user_end; 1107 | } 1108 | 1109 | if (err == 0) 1110 | print_warning("premature end of send"); 1111 | 1112 | total += err; 1113 | } while (total != filesize && err != 0); 1114 | 1115 | end = clock(); 1116 | 1117 | print_sendfile_user_stats(opts, filesize, total, ((double) (end - start)) / CLOCKS_PER_SEC); 1118 | 1119 | err = total; 1120 | 1121 | do_sendfile_user_end: 1122 | if (buf) 1123 | free(buf); 1124 | 1125 | if (in_fd) 1126 | close(in_fd); 1127 | 1128 | return err; 1129 | } 1130 | 1131 | extern int do_sendfile(const struct client_opts *opts, int ksd) { 1132 | int err; 1133 | int fd; 1134 | clock_t start, end; 1135 | ssize_t total = 0; 1136 | ssize_t filesize; 1137 | off_t offset = 0; 1138 | 1139 | fd = open(opts->sendfile, O_RDONLY); 1140 | if (fd < 0) { 1141 | perror("open"); 1142 | return fd; 1143 | } 1144 | 1145 | if (opts->sendfile_size == 0) { 1146 | filesize = lseek(fd, 0L, SEEK_END); 1147 | if (filesize < 0) { 1148 | perror("lseek() to EOF"); 1149 | return -1; 1150 | } 1151 | err = lseek(fd, 0L, SEEK_SET); 1152 | if (err < 0) { 1153 | perror("lseek() to beginning"); 1154 | return err; 1155 | } 1156 | } else { 1157 | filesize = opts->sendfile_size; 1158 | } 1159 | 1160 | // we do it explicitly because of lseek() 1161 | DO_DROP_CACHES(opts); 1162 | 1163 | start = clock(); 1164 | total = sendfile(ksd, fd, &offset, filesize); 1165 | end = clock(); 1166 | 1167 | if (total < 0) 1168 | perror("sendfile"); 1169 | else 1170 | print_sendfile_stats(opts, filesize, total, ((double) (end - start)) / CLOCKS_PER_SEC); 1171 | 1172 | return total; 1173 | } 1174 | 1175 | /* actions not using TLS - plain text actions */ 1176 | 1177 | extern int do_plain_sendfile_user(const struct client_opts *opts, int sd) { 1178 | int err; 1179 | int fd = 0; 1180 | off_t offset = 0; 1181 | ssize_t filesize; 1182 | size_t sent, mtu; 1183 | clock_t start, end; 1184 | char *buf = NULL; 1185 | 1186 | fd = open(opts->plain_sendfile_user, O_RDONLY); 1187 | if (fd < 0) { 1188 | perror("open"); 1189 | err = fd; 1190 | goto out; 1191 | } 1192 | 1193 | if (opts->sendfile_size == 0) { 1194 | filesize = get_file_size(fd); 1195 | if (filesize < 0) { 1196 | err = filesize; 1197 | goto out; 1198 | } 1199 | } else 1200 | filesize = opts->sendfile_size; 1201 | 1202 | buf = malloc(opts->sendfile_mtu); 1203 | if (!buf) { 1204 | perror("malloc"); 1205 | err = -errno; 1206 | goto out; 1207 | } 1208 | 1209 | // we do this explicitly because of get_file_size() 1210 | DO_DROP_CACHES(opts); 1211 | 1212 | start = clock(); 1213 | 1214 | for (sent = 0; sent != filesize; sent += err) { 1215 | err = read(fd, buf, opts->sendfile_mtu); 1216 | if (err < 0) { 1217 | perror("read"); 1218 | goto out; 1219 | } 1220 | 1221 | if (err == 0) // EOF reached 1222 | break; 1223 | 1224 | err = send(sd, buf, err, 0); 1225 | 1226 | if (err < 0) { 1227 | perror("send"); 1228 | goto out; 1229 | } 1230 | } 1231 | 1232 | end = clock(); 1233 | 1234 | print_plain_stats(opts, "plain send file user", opts->plain_sendfile_user, 1235 | sent, 0, ((double) (end - start)) / CLOCKS_PER_SEC); 1236 | 1237 | out: 1238 | if (fd > 0) 1239 | close(fd); 1240 | 1241 | if (buf) 1242 | free(buf); 1243 | 1244 | return err; 1245 | } 1246 | 1247 | extern int do_plain_sendfile_mmap(const struct client_opts *opts, int sd) { 1248 | int err; 1249 | int fd = 0; 1250 | off_t offset = 0; 1251 | ssize_t filesize; 1252 | size_t sent, mtu; 1253 | clock_t start, end; 1254 | char *mem; 1255 | 1256 | fd = open(opts->plain_sendfile_mmap, O_RDONLY); 1257 | if (fd < 0) { 1258 | perror("open"); 1259 | err = fd; 1260 | goto out; 1261 | } 1262 | 1263 | if (opts->sendfile_size == 0) { 1264 | filesize = get_file_size(fd); 1265 | if (filesize < 0) { 1266 | err = filesize; 1267 | goto out; 1268 | } 1269 | } else 1270 | filesize = opts->sendfile_size; 1271 | 1272 | mtu = MIN(filesize, opts->sendfile_mtu); 1273 | 1274 | // we do this explicitly because of get_file_size() 1275 | DO_DROP_CACHES(opts); 1276 | 1277 | mem = mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, fd, /*offset*/0); 1278 | if (!mem) { 1279 | perror("mmap"); 1280 | err = -1; 1281 | goto out; 1282 | } 1283 | 1284 | start = clock(); 1285 | 1286 | for (sent = 0; sent != filesize; sent += err) { 1287 | err = send(sd, mem + sent, MIN(filesize - sent, mtu), 0); 1288 | if (err < 0) { 1289 | perror("sendfile"); 1290 | goto out; 1291 | } 1292 | } 1293 | 1294 | end = clock(); 1295 | 1296 | print_plain_stats(opts, "plain send file mmap", opts->plain_sendfile_mmap, 1297 | sent, 0, ((double) (end - start)) / CLOCKS_PER_SEC); 1298 | 1299 | out: 1300 | if (fd > 0) 1301 | close(fd); 1302 | 1303 | if (mem) 1304 | munmap(mem, filesize); 1305 | 1306 | return err; 1307 | } 1308 | 1309 | extern int do_plain_splice_emu(const struct client_opts *opts, int sd) { 1310 | int err; 1311 | int fd = 0; 1312 | int p[2] = {0, 0}; 1313 | clock_t start, end; 1314 | size_t total_sent = 0; 1315 | size_t total_recv = 0; // not used now 1316 | ssize_t filesize; 1317 | 1318 | err = pipe(p); 1319 | if (err) { 1320 | perror("pipe"); 1321 | return err; 1322 | } 1323 | 1324 | fd = open(opts->plain_splice_emu, O_RDONLY); 1325 | if (fd < 0) { 1326 | perror(opts->plain_splice_emu); 1327 | err = fd; 1328 | goto out; 1329 | } 1330 | 1331 | if (!opts->sendfile_size) { 1332 | filesize = get_file_size(fd); 1333 | if (filesize < 0) { 1334 | err = filesize; 1335 | goto out; 1336 | } 1337 | } else 1338 | filesize = opts->sendfile_size; 1339 | 1340 | // explicitly because of get_file_size() 1341 | DO_DROP_CACHES(opts); 1342 | 1343 | start = clock(); 1344 | 1345 | for (total_sent = 0; total_sent != filesize; total_sent += err) { 1346 | err = splice(fd, NULL, p[1], NULL, opts->sendfile_mtu, 0); 1347 | if (err < 0) { 1348 | perror("splice"); 1349 | goto out; 1350 | } 1351 | 1352 | if (err == 0) // EOF reached 1353 | break; 1354 | 1355 | err = splice(p[0], NULL, sd, NULL, opts->sendfile_mtu, 0); 1356 | if (err < 0) { 1357 | perror("splice"); 1358 | goto out; 1359 | } 1360 | } 1361 | 1362 | end = clock(); 1363 | 1364 | print_plain_stats(opts, "plain splice(2) send file emu", opts->plain_splice_emu, 1365 | total_sent, 0, ((double) (end - start)) / CLOCKS_PER_SEC); 1366 | out: 1367 | if (p[0]) 1368 | close(p[0]); 1369 | if (p[1]) 1370 | close(p[1]); 1371 | if (fd > 0) 1372 | close(fd); 1373 | 1374 | return err; 1375 | } 1376 | 1377 | extern int do_plain_sendfile(const struct client_opts *opts, int sd) { 1378 | int err; 1379 | int fd = 0; 1380 | off_t offset = 0; 1381 | ssize_t filesize; 1382 | size_t sent, mtu; 1383 | clock_t start, end; 1384 | 1385 | fd = open(opts->plain_sendfile, O_RDONLY); 1386 | if (fd < 0) { 1387 | perror("open"); 1388 | err = fd; 1389 | goto out; 1390 | } 1391 | 1392 | if (opts->sendfile_size == 0) { 1393 | filesize = get_file_size(fd); 1394 | if (filesize < 0) { 1395 | err = filesize; 1396 | goto out; 1397 | } 1398 | } else 1399 | filesize = opts->sendfile_size; 1400 | 1401 | if (opts->sendfile_mtu) 1402 | mtu = MIN(filesize, opts->sendfile_mtu); 1403 | else 1404 | mtu = filesize; 1405 | 1406 | // we do this explicitly because of get_file_size() 1407 | DO_DROP_CACHES(opts); 1408 | 1409 | start = clock(); 1410 | 1411 | for (sent = 0; sent != filesize; sent += err) { 1412 | err = sendfile(sd, fd, &offset, mtu); 1413 | if (err < 0) { 1414 | perror("sendfile"); 1415 | } 1416 | } 1417 | 1418 | end = clock(); 1419 | 1420 | print_plain_stats(opts, "plain sendfile(2)", opts->plain_sendfile, 1421 | sent, 0, ((double) (end - start)) / CLOCKS_PER_SEC); 1422 | 1423 | out: 1424 | if (fd > 0) 1425 | close(fd); 1426 | return err; 1427 | } 1428 | 1429 | --------------------------------------------------------------------------------