#include #include #include //#include #include #include #include #include #include #include #include #include #include #include #include "ds.h" int openSslLoaded = 0; char *availableCiphers = "EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:" "+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:" "!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA"; void *clear(void *ptr){ int e = errno; if(ptr){ free(ptr); } errno = e; return NULL; } pthread_mutex_t loadLock; void loadOpenSSL(const char *dh){ if(openSslLoaded) return; pthread_mutex_lock(&loadLock); if(!openSslLoaded){ SSL_load_error_strings(); ERR_load_BIO_strings(); ERR_load_crypto_strings(); SSL_library_init(); OpenSSL_add_all_algorithms(); openSslLoaded = 1; } pthread_mutex_unlock(&loadLock); } void copy6addr(unsigned char d[16], const unsigned char s[16]){ int i; for(i = 0; i < 16; i++) d[i] = s[i]; } void zero6addr(unsigned char d[16]){ int i; for(i = 0; i < 16; i++) d[i] = 0; } nethandler getNethandler(const int ipv6, const int port){ nethandler h = (nethandler)malloc(sizeof(s_nethandler)); h->ipv6 = ipv6; if(ipv6){ h->fd = socket(AF_INET6, SOCK_STREAM, 0); }else{ h->fd = socket(AF_INET, SOCK_STREAM, 0); } int optval = 1; setsockopt(h->fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); int e, en; if(ipv6){ struct sockaddr_in6 add; add.sin6_family = AF_INET6; zero6addr(add.sin6_addr.s6_addr); add.sin6_port = htons(port); e = bind(h->fd, (struct sockaddr*) &add, sizeof(add)); }else{ struct sockaddr_in add; add.sin_family = AF_INET; add.sin_addr.s_addr = INADDR_ANY; add.sin_port = htons(port); e = bind(h->fd, (struct sockaddr*) &add, sizeof(add)); } if(e) return clear(h); e = listen(h->fd, DEFAULT_LISTENNING_QUEUE); if(e) return clear(h); return h; } nethandler getIPv4Port(const int port){ return getNethandler(0, port); } nethandler getPort(const int port){ return getNethandler(1, port); } ds createFromFile(int f){ ds d = (ds)malloc(sizeof(s_ds)); d->tp = file; d->fd = f; return d; } ds createFromFileName(const char *f){ int fd = open(f, O_CREAT | O_RDWR, 0666); if(fd == -1){ return NULL; } return createFromFile(fd); } ds createFromHandler(nethandler h){ ds d = (ds)malloc(sizeof(s_ds)); d->tp = sock; unsigned int s = sizeof(d->peer); d->fd = accept(h->fd, (struct sockaddr*)&(d->peer), &s); if(d->fd <= 0) return clear(d); d->ipv6 = d->peer.ss_family == AF_INET6; d->server = 1; return d; } ds createToHost(struct sockaddr *add, const int add_size, const int ipv6){ ds d = (ds)malloc(sizeof(s_ds)); d->tp = sock; if(ipv6){ d->fd = socket(AF_INET6, SOCK_STREAM, 0); }else{ d->fd = socket(AF_INET, SOCK_STREAM, 0); } if(connect(d->fd, add, add_size) < 0){ int e = errno; free(d); errno = e; return NULL; } d->server = 0; return d; } ds createToIPv4Host(const unsigned long host, const int port){ struct sockaddr_in add; add.sin_family = AF_INET; add.sin_port = htons(port); add.sin_addr.s_addr = host; return createToHost((struct sockaddr*) &add, sizeof(add), 0); } ds createToIPv6Host(const unsigned char host[16], const int port){ struct sockaddr_in6 add; add.sin6_family = AF_INET6; add.sin6_port = htons(port); add.sin6_flowinfo = 0; copy6addr(add.sin6_addr.s6_addr, host); add.sin6_scope_id = 0; return createToHost((struct sockaddr*) &add, sizeof(add), 1); } int getPeer(ds d, unsigned long *ipv4peer, unsigned char ipv6peer[16], int *ipv6){ int port = 0; struct sockaddr_storage peer; int peer_size = sizeof(peer); if(getpeername(d->fd, (struct sockaddr*)&peer, &peer_size)){ return 0; } if(peer.ss_family == AF_INET){ struct sockaddr_in *a = (struct sockaddr_in*)&(peer); zero6addr(ipv6peer); *ipv6 = -1; *ipv4peer = a->sin_addr.s_addr; port = a->sin_port; }else{ struct sockaddr_in6 *a = (struct sockaddr_in6*)&(peer); *ipv4peer = 0; *ipv6 = 1; copy6addr(ipv6peer, a->sin6_addr.s6_addr); port = a->sin6_port; } return port; } int sendDs(ds d, const char *b, const int s){ return write(d->fd, b, s); } int tlsDsSend(tlsDs d, const char *b, const int s){ return SSL_write(d->s, b, s); } int stdDsSend(const char *b, const int s){ return write(1, b, s); } int recvDs(ds d, char *b, const int s){ return read(d->fd, b, s); } int tlsDsRecv(tlsDs d, char *b, const int s){ return SSL_read(d->s, b, s); } int stdDsRecv(char *b, const int s){ return read(0, b, s); } int prepareToClose(ds d){ int fd = d->fd; free(d); return fd; } ds closeTls(tlsDs d){ ds original = d->original; SSL_shutdown(d->s); //No bidirectional shutdown supported //SSL_shutdown(d->s); SSL_free(d->s); free(d); return original; } void closeHandler(nethandler h){ close(h->fd); free(h); } tlsDs startSockTls(ds d, const char *cert, const char *key, const char *dh){ loadOpenSSL(dh); SSL_CTX * ctx = NULL; if(d->server) ctx = SSL_CTX_new(TLSv1_1_server_method()); else ctx = SSL_CTX_new(TLSv1_1_client_method()); if(!ctx) return NULL; if(d->server){ FILE *dhfile = fopen(dh, "r"); DH *dhdt = PEM_read_DHparams(dhfile, NULL, NULL, NULL); fclose(dhfile); if(SSL_CTX_set_tmp_dh(ctx, dhdt) <= 0){ int f = prepareToClose(d); closeFd(f); clear(dhdt); return clear(ctx); } } SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE); if(cert) if(SSL_CTX_use_certificate_chain_file(ctx, cert) != 1){ int f = prepareToClose(d); closeFd(f); return clear(ctx); } if(key) if(SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) != 1){ int f = prepareToClose(d); closeFd(f); return clear(ctx); } if(SSL_CTX_set_cipher_list(ctx, availableCiphers) <= 0){ int f = prepareToClose(d); closeFd(f); return clear(ctx); } tlsDs t = (tlsDs)malloc(sizeof(s_tlsDs)); t->original = d; if(!(t->s = SSL_new(ctx))){ int f = prepareToClose(d); closeFd(f); clear(ctx); return clear(t); } if(!SSL_set_fd(t->s, d->fd)){ closeTls(t); return NULL; } int retry = 1; int e; while(retry){ retry = 0; if(d->server){ SSL_set_accept_state(t->s); e = SSL_accept(t->s); }else{ SSL_set_connect_state(t->s); e = SSL_connect(t->s); } if(e <= 0){ unsigned long erval = SSL_get_error(t->s, e); //char ertxt[300]; //ERR_error_string(erval, ertxt); //fprintf(stderr, "SSL Error: %s\n", ertxt); if((erval == SSL_ERROR_WANT_READ) || (erval == SSL_ERROR_WANT_WRITE)){ //Here goes support to non-blocking IO, once it's supported //retry = 1; }else{ closeTls(t); return NULL; } } } return t; } int getFd(ds d){ return d->fd; } int getTlsFd(tlsDs t){ ds d = t->original; return d->fd; } void closeFd(int fd){ close(fd); }