diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2012-01-25 23:48:46 +0100 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2012-01-26 19:18:40 +0100 |
commit | c62c365b893c783ca466912dc830ace1bff87653 (patch) | |
tree | ca95ba712f0907482fcf33b5fb270a60d10f6725 /src | |
parent | ee7b5358c29aa106e62c554fdb61aa43aa589d46 (diff) | |
download | gnutls-c62c365b893c783ca466912dc830ace1bff87653.tar.gz |
Added --ask option to ocsptool.
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 22 | ||||
-rw-r--r-- | src/cli.c | 200 | ||||
-rw-r--r-- | src/common.c | 39 | ||||
-rw-r--r-- | src/common.h | 2 | ||||
-rw-r--r-- | src/ocsptool-args.def.in | 11 | ||||
-rw-r--r-- | src/ocsptool.c | 262 | ||||
-rw-r--r-- | src/serv.c | 4 | ||||
-rw-r--r-- | src/socket.c | 250 | ||||
-rw-r--r-- | src/socket.h | 23 | ||||
-rw-r--r-- | src/tls_test.c | 4 |
10 files changed, 537 insertions, 280 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 5335b1bc6b..136484d3ce 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -50,11 +50,12 @@ endif noinst_LTLIBRARIES = -gnutls_serv_SOURCES = \ - list.h serv.c \ - udp-serv.c udp-serv.h \ - common.h common.c \ - certtool-common.h \ +gnutls_serv_SOURCES = \ + list.h serv.c \ + udp-serv.c udp-serv.h \ + socket.c socket.h \ + common.h common.c \ + certtool-common.h \ $(PKCS11_SRCS) gnutls_serv_LDADD = ../lib/libgnutls.la gnutls_serv_LDADD += libcmd-serv.la ../gl/libgnu.la $(LIBOPTS_LDADD) @@ -72,7 +73,8 @@ libcmd_srp_la_SOURCES = srptool-args.def srptool-args.c srptool-args.h endif if ENABLE_OCSP -ocsptool_SOURCES = ocsptool.c ocsptool-common.h +ocsptool_SOURCES = ocsptool.c ocsptool-common.h \ + socket.c socket.h ocsptool_LDADD = ../lib/libgnutls.la libcmd-ocsp.la ../gl/libgnu.la $(LIBOPTS_LDADD) noinst_LTLIBRARIES += libcmd-ocsp.la libcmd_ocsp_la_CFLAGS = @@ -87,7 +89,9 @@ libcmd_psk_la_SOURCES = psk-args.def psk-args.c psk-args.h BENCHMARK_SRCS = benchmark-cipher.c benchmark.c benchmark.h benchmark-tls.c -gnutls_cli_SOURCES = cli.c common.h common.c $(PKCS11_SRCS) $(BENCHMARK_SRCS) +gnutls_cli_SOURCES = cli.c common.h common.c \ + socket.c socket.h \ + $(PKCS11_SRCS) $(BENCHMARK_SRCS) gnutls_cli_LDADD = ../lib/libgnutls.la gnutls_cli_LDADD += libcmd-cli.la ../gl/libgnu.la $(LIBOPTS_LDADD) gnutls_cli_LDADD += $(LIBSOCKET) $(GETADDRINFO_LIB) $(LIB_CLOCK_GETTIME) @@ -95,7 +99,9 @@ noinst_LTLIBRARIES += libcmd-cli.la libcmd_cli_la_CFLAGS = libcmd_cli_la_SOURCES = cli-args.def cli-args.c cli-args.h -gnutls_cli_debug_SOURCES = tls_test.c tests.h tests.c common.h common.c $(PKCS11_SRCS) +gnutls_cli_debug_SOURCES = tls_test.c tests.h tests.c \ + socket.c socket.h common.h common.c \ + $(PKCS11_SRCS) gnutls_cli_debug_LDADD = ../lib/libgnutls.la libcmd-cli-debug.la $(LIBOPTS_LDADD) gnutls_cli_debug_LDADD += ../gl/libgnu.la $(LIBSOCKET) $(GETADDRINFO_LIB) noinst_LTLIBRARIES += libcmd-cli-debug.la @@ -49,12 +49,14 @@ #include <read-file.h> #include <getpass.h> #include <minmax.h> + #include "sockets.h" -#include "common.h" +#include <common.h> +#include <socket.h> -#include "gettext.h" -#include "cli-args.h" +#include <gettext.h> +#include <cli-args.h> #define MAX_BUF 4096 @@ -65,7 +67,7 @@ const char *service = NULL; int record_max_size; int fingerprint; int crlf; -int verbose = 0; +unsigned int verbose = 0; extern int print_cert; const char *srp_passwd = NULL; @@ -92,24 +94,6 @@ static gnutls_certificate_credentials_t xcred; /* end of global stuff */ /* prototypes */ -typedef struct -{ - int fd; - gnutls_session_t session; - int secure; - char *hostname; - char *ip; - char *service; - struct addrinfo *ptr; - struct addrinfo *addr_info; -} socket_st; - -ssize_t socket_recv (const socket_st * socket, void *buffer, int buffer_size); -ssize_t socket_send (const socket_st * socket, const void *buffer, - int buffer_size); -void socket_open (socket_st * hd, const char *hostname, const char *service); -void socket_connect (const socket_st * hd); -void socket_bye (socket_st * socket); static void check_rehandshake (socket_st * socket, int ret); static int do_handshake (socket_st * socket); @@ -773,13 +757,9 @@ main (int argc, char **argv) sockets_init (); -#ifndef _WIN32 - signal (SIGPIPE, SIG_IGN); -#endif - init_global_tls_stuff (); - socket_open (&hd, hostname, service); + socket_open (&hd, hostname, service, udp); socket_connect (&hd); hd.session = init_tls_session (hostname); @@ -833,7 +813,7 @@ main (int argc, char **argv) printf ("\n\n- Connecting again- trying to resume previous session\n"); - socket_open (&hd, hostname, service); + socket_open (&hd, hostname, service, udp); socket_connect (&hd); } else @@ -1384,168 +1364,4 @@ init_global_tls_stuff (void) } -/* Functions to manipulate sockets - */ - -ssize_t -socket_recv (const socket_st * socket, void *buffer, int buffer_size) -{ - int ret; - - if (socket->secure) - do - { - ret = gnutls_record_recv (socket->session, buffer, buffer_size); - } - while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); - else - do - { - ret = recv (socket->fd, buffer, buffer_size, 0); - } - while (ret == -1 && errno == EINTR); - - return ret; -} - -ssize_t -socket_send (const socket_st * socket, const void *buffer, int buffer_size) -{ - int ret; - - if (socket->secure) - do - { - ret = gnutls_record_send (socket->session, buffer, buffer_size); - } - while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); - else - do - { - ret = send (socket->fd, buffer, buffer_size, 0); - } - while (ret == -1 && errno == EINTR); - - if (ret > 0 && ret != buffer_size && verbose) - fprintf (stderr, - "*** Only sent %d bytes instead of %d.\n", ret, buffer_size); - - return ret; -} - -void -socket_bye (socket_st * socket) -{ - int ret; - if (socket->secure) - { - do - ret = gnutls_bye (socket->session, GNUTLS_SHUT_WR); - while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); - if (ret < 0) - fprintf (stderr, "*** gnutls_bye() error: %s\n", - gnutls_strerror (ret)); - gnutls_deinit (socket->session); - socket->session = NULL; - } - - freeaddrinfo (socket->addr_info); - socket->addr_info = socket->ptr = NULL; - - free (socket->ip); - free (socket->hostname); - free (socket->service); - - shutdown (socket->fd, SHUT_RDWR); /* no more receptions */ - close (socket->fd); - - socket->fd = -1; - socket->secure = 0; -} - -void -socket_connect (const socket_st * hd) -{ - int err; - - printf ("Connecting to '%s:%s'...\n", hd->ip, hd->service); - - err = connect (hd->fd, hd->ptr->ai_addr, hd->ptr->ai_addrlen); - if (err < 0) - { - fprintf (stderr, "Cannot connect to %s:%s: %s\n", hd->hostname, - hd->service, strerror (errno)); - exit (1); - } -} - -void -socket_open (socket_st * hd, const char *hostname, const char *service) -{ - struct addrinfo hints, *res, *ptr; - int sd, err; - char buffer[MAX_BUF + 1]; - char portname[16] = { 0 }; - - printf ("Resolving '%s'...\n", hostname); - /* get server name */ - memset (&hints, 0, sizeof (hints)); - hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM; - if ((err = getaddrinfo (hostname, service, &hints, &res))) - { - fprintf (stderr, "Cannot resolve %s:%s: %s\n", hostname, service, - gai_strerror (err)); - exit (1); - } - - sd = -1; - for (ptr = res; ptr != NULL; ptr = ptr->ai_next) - { - sd = socket (ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); - if (sd == -1) - continue; - - if ((err = getnameinfo (ptr->ai_addr, ptr->ai_addrlen, buffer, MAX_BUF, - portname, sizeof (portname), - NI_NUMERICHOST | NI_NUMERICSERV)) != 0) - { - fprintf (stderr, "getnameinfo(): %s\n", gai_strerror (err)); - freeaddrinfo (res); - exit (1); - } - - break; - } - - if (sd == -1) - { - fprintf (stderr, "socket(): %s\n", strerror (errno)); - exit (1); - } - - if (hints.ai_socktype == SOCK_DGRAM) - { -#if defined(IP_DONTFRAG) - int yes = 1; - if (setsockopt (sd, IPPROTO_IP, IP_DONTFRAG, - (const void *) &yes, sizeof (yes)) < 0) - perror ("setsockopt(IP_DF) failed"); -#elif defined(IP_MTU_DISCOVER) - int yes = IP_PMTUDISC_DO; - if (setsockopt(sd, IPPROTO_IP, IP_MTU_DISCOVER, - (const void*) &yes, sizeof (yes)) < 0) - perror ("setsockopt(IP_DF) failed"); -#endif - } - - hd->secure = 0; - hd->fd = sd; - hd->hostname = strdup (hostname); - hd->ip = strdup (buffer); - hd->service = strdup (portname); - hd->ptr = ptr; - hd->addr_info = res; - - return; -} diff --git a/src/common.c b/src/common.c index dcaf421dcd..40aa5b05d5 100644 --- a/src/common.c +++ b/src/common.c @@ -882,42 +882,3 @@ print_list (const char *priorities, int verbose) } } -void -sockets_init (void) -{ -#ifdef _WIN32 - WORD wVersionRequested; - WSADATA wsaData; - - wVersionRequested = MAKEWORD (1, 1); - if (WSAStartup (wVersionRequested, &wsaData) != 0) - { - perror ("WSA_STARTUP_ERROR"); - } -#endif -} - -/* converts a service name or a port (in string) to a - * port number. The protocol is assumed to be TCP. - * - * returns -1 on error; - */ -int -service_to_port (const char *service) -{ - int port; - struct servent *server_port; - - port = atoi (service); - if (port != 0) - return port; - - server_port = getservbyname (service, "tcp"); - if (server_port == NULL) - { - perror ("getservbyname()"); - return (-1); - } - - return ntohs (server_port->s_port); -} diff --git a/src/common.h b/src/common.h index f8254cf71f..dd6d569881 100644 --- a/src/common.h +++ b/src/common.h @@ -55,6 +55,4 @@ void print_cert_info (gnutls_session_t state, const char *hostname, void print_list (const char* priorities, int verbose); const char *raw_to_string (const unsigned char *raw, size_t raw_size); -int service_to_port (const char *service); void pkcs11_common (void); -void sockets_init (void); diff --git a/src/ocsptool-args.def.in b/src/ocsptool-args.def.in index 70182b6310..7f4fb3ab85 100644 --- a/src/ocsptool-args.def.in +++ b/src/ocsptool-args.def.in @@ -36,6 +36,17 @@ flag = { }; flag = { + name = ask; + arg-type = string; + arg-name = "url"; + arg-optional; + descrip = "Ask server about the loaded certificate"; + flags-must = load-cert; + flags-must = load-issuer; + doc = "Connects to the specified HTTP URL and queries an OCSP request."; +}; + +flag = { name = verify-response; value = e; descrip = "Verify response"; diff --git a/src/ocsptool.c b/src/ocsptool.c index c90e6a9bff..9810f0db43 100644 --- a/src/ocsptool.c +++ b/src/ocsptool.c @@ -35,6 +35,7 @@ #include <progname.h> #include <version-etc.h> #include <read-file.h> +#include <socket.h> #include <ocsptool-common.h> #include <ocsptool-args.h> @@ -42,6 +43,7 @@ FILE *outfile; FILE *infile; static unsigned int encoding; +unsigned int verbose = 0; static void tls_log_func (int level, const char *str) @@ -85,17 +87,39 @@ request_info (void) } static void -response_info (void) +_response_info (const gnutls_datum_t* data) { gnutls_ocsp_resp_t resp; int ret; - gnutls_datum_t dat; - size_t size; + gnutls_datum buf; ret = gnutls_ocsp_resp_init (&resp); if (ret < 0) error (EXIT_FAILURE, 0, "ocsp_resp_init: %s", gnutls_strerror (ret)); + ret = gnutls_ocsp_resp_import (resp, data); + if (ret < 0) + error (EXIT_FAILURE, 0, "importing response: %s", gnutls_strerror (ret)); + + if (ENABLED_OPT(VERBOSE)) + ret = gnutls_ocsp_resp_print (resp, GNUTLS_OCSP_PRINT_FULL, &buf); + else + ret = gnutls_ocsp_resp_print (resp, GNUTLS_OCSP_PRINT_COMPACT, &buf); + if (ret != 0) + error (EXIT_FAILURE, 0, "ocsp_resp_print: %s", gnutls_strerror (ret)); + + printf ("%.*s", buf.size, buf.data); + gnutls_free (buf.data); + + gnutls_ocsp_resp_deinit (resp); +} + +static void +response_info (void) +{ + gnutls_datum_t dat; + size_t size; + if (HAVE_OPT(LOAD_RESPONSE)) dat.data = (void*)read_binary_file (OPT_ARG(LOAD_RESPONSE), &size); else @@ -104,19 +128,8 @@ response_info (void) error (EXIT_FAILURE, errno, "reading response"); dat.size = size; - ret = gnutls_ocsp_resp_import (resp, &dat); - free (dat.data); - if (ret < 0) - error (EXIT_FAILURE, 0, "importing response: %s", gnutls_strerror (ret)); - - ret = gnutls_ocsp_resp_print (resp, GNUTLS_OCSP_PRINT_FULL, &dat); - if (ret != 0) - error (EXIT_FAILURE, 0, "ocsp_resp_print: %s", gnutls_strerror (ret)); - - printf ("%.*s", dat.size, dat.data); + _response_info(&dat); gnutls_free (dat.data); - - gnutls_ocsp_resp_deinit (resp); } static gnutls_x509_crt_t @@ -180,7 +193,7 @@ load_cert (void) } static void -generate_request (void) +_generate_request (gnutls_datum_t * rdata) { gnutls_ocsp_req_t req; int ret; @@ -193,14 +206,14 @@ generate_request (void) issuer = load_issuer (); cert = load_cert (); - + ret = gnutls_ocsp_req_add_cert (req, GNUTLS_DIG_SHA1, - issuer, cert); + issuer, cert); if (ret < 0) error (EXIT_FAILURE, 0, "ocsp_req_add_cert: %s", gnutls_strerror (ret)); - - gnutls_x509_crt_deinit (cert); + gnutls_x509_crt_deinit (issuer); + gnutls_x509_crt_deinit (cert); if (ENABLED_OPT(NONCE)) { @@ -221,13 +234,25 @@ generate_request (void) if (ret != 0) error (EXIT_FAILURE, 0, "ocsp_req_export: %s", gnutls_strerror (ret)); + gnutls_ocsp_req_deinit (req); + + memcpy(rdata, &dat, sizeof(*rdata)); + return; +} + +static void +generate_request (void) +{ + gnutls_datum_t dat; + + _generate_request(&dat); + fwrite (dat.data, 1, dat.size, outfile); gnutls_free (dat.data); - - gnutls_ocsp_req_deinit (req); } + static void print_verify_res (unsigned int output) { @@ -301,33 +326,24 @@ print_verify_res (unsigned int output) } } -static void -verify_response (void) +static int +_verify_response (gnutls_datum_t *data) { gnutls_ocsp_resp_t resp; int ret; - gnutls_datum_t dat; size_t size; gnutls_x509_crt_t *x509_ca_list = NULL; unsigned int x509_ncas = 0; gnutls_x509_trust_list_t list; gnutls_x509_crt_t signer; unsigned verify; + gnutls_datum_t dat; ret = gnutls_ocsp_resp_init (&resp); if (ret < 0) error (EXIT_FAILURE, 0, "ocsp_resp_init: %s", gnutls_strerror (ret)); - if (HAVE_OPT(LOAD_RESPONSE)) - dat.data = (void*)read_binary_file (OPT_ARG(LOAD_RESPONSE), &size); - else - dat.data = (void*)fread_file (infile, &size); - if (dat.data == NULL) - error (EXIT_FAILURE, errno, "reading response"); - dat.size = size; - - ret = gnutls_ocsp_resp_import (resp, &dat); - free (dat.data); + ret = gnutls_ocsp_resp_import (resp, data); if (ret < 0) error (EXIT_FAILURE, 0, "importing response: %s", gnutls_strerror (ret)); @@ -423,8 +439,182 @@ verify_response (void) printf (".\n"); gnutls_ocsp_resp_deinit (resp); + + return verify; +} + +static void +verify_response (void) +{ + gnutls_datum_t dat; + size_t size; + + if (HAVE_OPT(LOAD_RESPONSE)) + dat.data = (void*)read_binary_file (OPT_ARG(LOAD_RESPONSE), &size); + else + dat.data = (void*)fread_file (infile, &size); + if (dat.data == NULL) + error (EXIT_FAILURE, errno, "reading response"); + dat.size = size; + + _verify_response(&dat); +} + +static size_t get_data(void *buffer, size_t size, size_t nmemb, void *userp) +{ +gnutls_datum_t *ud = userp; + + size *= nmemb; + + ud->data = realloc(ud->data, size+ud->size); + if (ud->data == NULL) + { + fprintf(stderr, "Not enough memory for the request\n"); + exit(1); + } + + memcpy(&ud->data[ud->size], buffer, size); + ud->size += size; + + return size; } +/* returns the host part of a URL */ +static const char* host_from_url(const char* url, unsigned int* port) +{ +static char hostname[512]; +char * p; + + *port = 0; + + if ((p=strstr(url, "http://")) != NULL) + { + snprintf(hostname, sizeof(hostname), "%s", p+7); + p = strchr(hostname, '/'); + if (p != NULL) *p = 0; + + p = strchr(hostname, ':'); + if (p != NULL) { + *p = 0; + *port = atoi(p+1); + } + + return hostname; + } + else + { + return url; + } +} + +#define MAX_BUF 4*1024 +#define HEADER_PATTERN "POST / HTTP/1.1\r\n" \ + "Host: %s\r\n" \ + "Accept: */*\r\n" \ + "Content-Type: application/ocsp-request\r\n" \ + "Content-Length: %u\r\n" \ + "Connection: close\r\n\r\n" +static char buffer[MAX_BUF + 1]; + +static void ask_server(const char* _url) +{ +gnutls_datum_t ud, resp_data; +int ret, v; +gnutls_datum_t req; +char* url = (void*)_url; +char headers[1024]; +char service[16]; +const char *hostname; +unsigned int headers_size = 0, port; +socket_st hd; + + sockets_init (); + + if (url == NULL) + { + /* try to read URL from issuer certificate */ + gnutls_x509_crt_t issuer = load_issuer(); + gnutls_datum_t data; + + ret = gnutls_x509_crt_get_authority_info_access(issuer, 0, + GNUTLS_IA_OCSP_URI, &data, NULL); + if (ret < 0) + { + fprintf(stderr, "Cannot find URL from issuer: %s\n", gnutls_strerror(ret)); + exit(1); + } + + url = malloc(data.size+1); + memcpy(url, data.data, data.size); + url[data.size] = 0; + + gnutls_free(data.data); + + gnutls_x509_crt_deinit(issuer); + } + + hostname = host_from_url(url, &port); + if (port != 0) + snprintf(service, sizeof(service), "%u", port); + else strcpy(service, "80"); + + fprintf(stderr, "Connecting to %s\n", hostname); + + memset(&ud, 0, sizeof(ud)); + + _generate_request(&req); + + snprintf(headers, sizeof(headers), HEADER_PATTERN, hostname, (unsigned int)req.size); + headers_size = strlen(headers); + + socket_open(&hd, hostname, service, 0); + socket_connect (&hd); + + socket_send(&hd, headers, headers_size); + socket_send(&hd, req.data, req.size); + + do { + ret = socket_recv(&hd, buffer, sizeof(buffer)); + if (ret > 0) get_data(buffer, ret, 1, &ud); + } while(ret > 0); + + if (ret < 0 || ud.size == 0) + { + perror("recv"); + exit(1); + } + + socket_bye(&hd); + + resp_data.data = memmem(ud.data, ud.size, "\r\n\r\n", 4); + if (resp_data.data == NULL) + { + fprintf(stderr, "Cannot interpret HTTP response\n"); + exit(1); + } + + resp_data.data += 4; + resp_data.size = ud.size - (resp_data.data - ud.data); + + _response_info (&resp_data); + + if (HAVE_OPT(LOAD_SIGNER)) + { + fprintf(outfile, "\n"); + v = _verify_response(&resp_data); + } + else + { + fprintf(stderr, "\nResponse could not be verified (use --load-signer).\n"); + v = 0; + } + + if (HAVE_OPT(OUTFILE) && v == 0) + { + fwrite(resp_data.data, 1, resp_data.size, outfile); + } +} + int main (int argc, char **argv) { @@ -471,6 +661,8 @@ main (int argc, char **argv) generate_request (); else if (HAVE_OPT(VERIFY_RESPONSE)) verify_response (); + else if (HAVE_OPT(ASK)) + ask_server(OPT_ARG(ASK)); else { USAGE(1); diff --git a/src/serv.c b/src/serv.c index 351df98fd0..151ee301e3 100644 --- a/src/serv.c +++ b/src/serv.c @@ -40,6 +40,7 @@ #include <list.h> #include <netdb.h> #include <unistd.h> +#include <socket.h> /* Gnulib portability files. */ #include "progname.h" @@ -58,7 +59,7 @@ static int http = 0; static int x509ctype; static int debug = 0; -int verbose = 1; +unsigned int verbose = 1; static int nodb; static int noticket; int require_cert; @@ -911,7 +912,6 @@ main (int argc, char **argv) cmd_parser(argc, argv); #ifndef _WIN32 - signal (SIGPIPE, SIG_IGN); signal (SIGHUP, SIG_IGN); signal (SIGTERM, terminate); if (signal (SIGINT, terminate) == SIG_IGN) diff --git a/src/socket.c b/src/socket.c new file mode 100644 index 0000000000..3dc722b648 --- /dev/null +++ b/src/socket.c @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2000-2012 Free Software Foundation, Inc. + * + * This file is part of GnuTLS. + * + * GnuTLS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GnuTLS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#if HAVE_SYS_SOCKET_H +# include <sys/socket.h> +#elif HAVE_WS2TCPIP_H +# include <ws2tcpip.h> +#endif +#include <netdb.h> +#include <string.h> +#include <errno.h> +#include <sys/select.h> +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#ifndef _WIN32 +# include <unistd.h> +# include <signal.h> +#endif +#include <socket.h> +#include "sockets.h" + +#define MAX_BUF 4096 + +extern unsigned int verbose; +/* Functions to manipulate sockets + */ + +ssize_t +socket_recv (const socket_st * socket, void *buffer, int buffer_size) +{ + int ret; + + if (socket->secure) + do + { + ret = gnutls_record_recv (socket->session, buffer, buffer_size); + } + while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); + else + do + { + ret = recv (socket->fd, buffer, buffer_size, 0); + } + while (ret == -1 && errno == EINTR); + + return ret; +} + +ssize_t +socket_send (const socket_st * socket, const void *buffer, int buffer_size) +{ + int ret; + + if (socket->secure) + do + { + ret = gnutls_record_send (socket->session, buffer, buffer_size); + } + while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); + else + do + { + ret = send (socket->fd, buffer, buffer_size, 0); + } + while (ret == -1 && errno == EINTR); + + if (ret > 0 && ret != buffer_size && verbose) + fprintf (stderr, + "*** Only sent %d bytes instead of %d.\n", ret, buffer_size); + + return ret; +} + +void +socket_bye (socket_st * socket) +{ + int ret; + if (socket->secure) + { + do + ret = gnutls_bye (socket->session, GNUTLS_SHUT_WR); + while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); + if (ret < 0) + fprintf (stderr, "*** gnutls_bye() error: %s\n", + gnutls_strerror (ret)); + gnutls_deinit (socket->session); + socket->session = NULL; + } + + freeaddrinfo (socket->addr_info); + socket->addr_info = socket->ptr = NULL; + + free (socket->ip); + free (socket->hostname); + free (socket->service); + + shutdown (socket->fd, SHUT_RDWR); /* no more receptions */ + close (socket->fd); + + socket->fd = -1; + socket->secure = 0; +} + +void +socket_connect (const socket_st * hd) +{ + int err; + + printf ("Connecting to '%s:%s'...\n", hd->ip, hd->service); + + err = connect (hd->fd, hd->ptr->ai_addr, hd->ptr->ai_addrlen); + if (err < 0) + { + fprintf (stderr, "Cannot connect to %s:%s: %s\n", hd->hostname, + hd->service, strerror (errno)); + exit (1); + } +} + +void +socket_open (socket_st * hd, const char *hostname, const char *service, int udp) +{ + struct addrinfo hints, *res, *ptr; + int sd, err; + char buffer[MAX_BUF + 1]; + char portname[16] = { 0 }; + + printf ("Resolving '%s'...\n", hostname); + /* get server name */ + memset (&hints, 0, sizeof (hints)); + hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM; + if ((err = getaddrinfo (hostname, service, &hints, &res))) + { + fprintf (stderr, "Cannot resolve %s:%s: %s\n", hostname, service, + gai_strerror (err)); + exit (1); + } + + sd = -1; + for (ptr = res; ptr != NULL; ptr = ptr->ai_next) + { + sd = socket (ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); + if (sd == -1) + continue; + + if ((err = getnameinfo (ptr->ai_addr, ptr->ai_addrlen, buffer, MAX_BUF, + portname, sizeof (portname), + NI_NUMERICHOST | NI_NUMERICSERV)) != 0) + { + fprintf (stderr, "getnameinfo(): %s\n", gai_strerror (err)); + freeaddrinfo (res); + exit (1); + } + + break; + } + + if (sd == -1) + { + fprintf (stderr, "socket(): %s\n", strerror (errno)); + exit (1); + } + + if (hints.ai_socktype == SOCK_DGRAM) + { +#if defined(IP_DONTFRAG) + int yes = 1; + if (setsockopt (sd, IPPROTO_IP, IP_DONTFRAG, + (const void *) &yes, sizeof (yes)) < 0) + perror ("setsockopt(IP_DF) failed"); +#elif defined(IP_MTU_DISCOVER) + int yes = IP_PMTUDISC_DO; + if (setsockopt(sd, IPPROTO_IP, IP_MTU_DISCOVER, + (const void*) &yes, sizeof (yes)) < 0) + perror ("setsockopt(IP_DF) failed"); +#endif + } + + hd->secure = 0; + hd->fd = sd; + hd->hostname = strdup (hostname); + hd->ip = strdup (buffer); + hd->service = strdup (portname); + hd->ptr = ptr; + hd->addr_info = res; + + return; +} + +void +sockets_init (void) +{ +#ifdef _WIN32 + WORD wVersionRequested; + WSADATA wsaData; + + wVersionRequested = MAKEWORD (1, 1); + if (WSAStartup (wVersionRequested, &wsaData) != 0) + { + perror ("WSA_STARTUP_ERROR"); + } +#else + signal (SIGPIPE, SIG_IGN); +#endif + +} + +/* converts a service name or a port (in string) to a + * port number. The protocol is assumed to be TCP. + * + * returns -1 on error; + */ +int +service_to_port (const char *service) +{ + int port; + struct servent *server_port; + + port = atoi (service); + if (port != 0) + return port; + + server_port = getservbyname (service, "tcp"); + if (server_port == NULL) + { + perror ("getservbyname()"); + return (-1); + } + + return ntohs (server_port->s_port); +} diff --git a/src/socket.h b/src/socket.h new file mode 100644 index 0000000000..4846465092 --- /dev/null +++ b/src/socket.h @@ -0,0 +1,23 @@ +#include <gnutls/gnutls.h> + +typedef struct +{ + int fd; + gnutls_session_t session; + int secure; + char *hostname; + char *ip; + char *service; + struct addrinfo *ptr; + struct addrinfo *addr_info; +} socket_st; + +ssize_t socket_recv (const socket_st * socket, void *buffer, int buffer_size); +ssize_t socket_send (const socket_st * socket, const void *buffer, + int buffer_size); +void socket_open (socket_st * hd, const char *hostname, const char *service, int udp); +void socket_connect (const socket_st * hd); +void socket_bye (socket_st * socket); + +void sockets_init (void); +int service_to_port (const char *service); diff --git a/src/tls_test.c b/src/tls_test.c index efef925842..2ba714ded1 100644 --- a/src/tls_test.c +++ b/src/tls_test.c @@ -34,6 +34,7 @@ #include <tests.h> #include <common.h> #include <cli-debug-args.h> +#include <socket.h> /* Gnulib portability files. */ #include <progname.h> @@ -59,8 +60,7 @@ gnutls_certificate_credentials_t xcred; /* end of global stuff */ - -int verbose = 0; +unsigned int verbose = 0; extern int tls1_ok; extern int tls1_1_ok; |