static int runproxy (int acceptfd) { int connectfd; if ((connectfd = connecttoaddress (connectaddr)) < 0) { fprintf (stderr, "Could not connect\n"); close (acceptfd); return -1; } tlssession_t *session = tlssession_new (server, keyfile, certfile, cacertfile, hostname, insecure, debug, quitfn, NULL, NULL); if (!session) { fprintf (stderr, "Could create TLS session\n"); close (connectfd); close (acceptfd); return -1; } int ret; if (server) ret = tlssession_mainloop (acceptfd, connectfd, session); else ret = tlssession_mainloop (connectfd, acceptfd, session); tlssession_close (session); close (connectfd); close (acceptfd); if (ret < 0) { fprintf (stderr, "TLS proxy exited with an error\n"); return -1; } return 0; }
int setup_connection_common(int sock, char *name, CONNECTION_TYPE ctype, int *serverflags, int testflags) { char buf[256]; u64 tmp64; uint64_t mymagic = (name ? opts_magic : cliserv_magic); uint32_t tmp32 = 0; uint16_t handshakeflags = 0; uint32_t negotiationflags = 0; if (ctype < CONNECTION_TYPE_INIT_PASSWD) goto end; READ_ALL_ERRCHK(sock, buf, strlen(INIT_PASSWD), err, "Could not read INIT_PASSWD: %s", strerror(errno)); if (strlen(buf) == 0) { snprintf(errstr, errstr_len, "Server closed connection"); goto err; } if (strncmp(buf, INIT_PASSWD, strlen(INIT_PASSWD))) { snprintf(errstr, errstr_len, "INIT_PASSWD does not match"); goto err; } if (ctype < CONNECTION_TYPE_CLISERV) goto end; READ_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err, "Could not read cliserv_magic: %s", strerror(errno)); tmp64 = ntohll(tmp64); if (tmp64 != mymagic) { strncpy(errstr, "mymagic does not match", errstr_len); goto err; } if (ctype < CONNECTION_TYPE_FULL) goto end; if (!name) { READ_ALL_ERRCHK(sock, &size, sizeof(size), err, "Could not read size: %s", strerror(errno)); size = ntohll(size); uint32_t flags; READ_ALL_ERRCHK(sock, &flags, sizeof(uint32_t), err, "Could not read flags: %s", strerror(errno)); flags = ntohl(flags); *serverflags = flags; READ_ALL_ERRCHK(sock, buf, 124, err, "Could not read data: %s", strerror(errno)); goto end; } /* handshake flags */ READ_ALL_ERRCHK(sock, &handshakeflags, sizeof(handshakeflags), err, "Could not read reserved field: %s", strerror(errno)); handshakeflags = ntohs(handshakeflags); /* negotiation flags */ if (handshakeflags & NBD_FLAG_FIXED_NEWSTYLE) negotiationflags |= NBD_FLAG_C_FIXED_NEWSTYLE; else if (keyfile) { snprintf(errstr, errstr_len, "Cannot negotiate TLS without NBD_FLAG_FIXED_NEWSTYLE"); goto err; } negotiationflags = htonl(negotiationflags); WRITE_ALL_ERRCHK(sock, &negotiationflags, sizeof(negotiationflags), err, "Could not write reserved field: %s", strerror(errno)); if (testflags & TEST_HANDSHAKE) { /* Server must support newstyle for this test */ if (!(handshakeflags & NBD_FLAG_FIXED_NEWSTYLE)) { strncpy(errstr, "server does not support handshake", errstr_len); goto err; } goto end; } #if HAVE_GNUTLS /* TLS */ if (keyfile) { int plainfd[2]; // [0] is used by the proxy, [1] is used by NBD tlssession_t *s = NULL; int ret; /* magic */ tmp64 = htonll(opts_magic); WRITE_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err, "Could not write magic: %s", strerror(errno)); /* starttls */ tmp32 = htonl(NBD_OPT_STARTTLS); WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err, "Could not write option: %s", strerror(errno)); /* length of data */ tmp32 = htonl(0); WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err, "Could not write option length: %s", strerror(errno)); READ_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err, "Could not read cliserv_magic: %s", strerror(errno)); tmp64 = ntohll(tmp64); if (tmp64 != NBD_OPT_REPLY_MAGIC) { strncpy(errstr, "reply magic does not match", errstr_len); goto err; } READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err, "Could not read option type: %s", strerror(errno)); tmp32 = ntohl(tmp32); if (tmp32 != NBD_OPT_STARTTLS) { strncpy(errstr, "Reply to wrong option", errstr_len); goto err; } READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err, "Could not read option reply type: %s", strerror(errno)); tmp32 = ntohl(tmp32); if (tmp32 != NBD_REP_ACK) { if(tmp32 & NBD_REP_FLAG_ERROR) { snprintf(errstr, errstr_len, "Received error %d", tmp32 & ~NBD_REP_FLAG_ERROR); } else { snprintf(errstr, errstr_len, "Option reply type %d != NBD_REP_ACK", tmp32); } goto err; } READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err, "Could not read option data length: %s", strerror(errno)); tmp32 = ntohl(tmp32); if (tmp32 != 0) { strncpy(errstr, "Option reply data length != 0", errstr_len); goto err; } s = tlssession_new(FALSE, keyfile, certfile, cacertfile, tlshostname, !cacertfile || !tlshostname, // insecure flag #ifdef DODBG 1, // debug #else 0, // debug #endif NULL, // quitfn tlserrout, // erroutfn NULL // opaque ); if (!s) { strncpy(errstr, "Cannot establish TLS session", errstr_len); goto err; } if (socketpair(AF_UNIX, SOCK_STREAM, 0, plainfd) < 0) { strncpy(errstr, "Cannot get socket pair", errstr_len); goto err; } if (set_nonblocking(plainfd[0], 0) <0 || set_nonblocking(plainfd[1], 0) <0 || set_nonblocking(sock, 0) <0) { close(plainfd[0]); close(plainfd[1]); strncpy(errstr, "Cannot set socket options", errstr_len); goto err; } ret = fork(); if (ret < 0) err("Could not fork"); else if (ret == 0) { // we are the child signal (SIGPIPE, SIG_IGN); close(plainfd[1]); tlssession_mainloop(sock, plainfd[0], s); close(sock); close(plainfd[0]); exit(0); } close(plainfd[0]); close(sock); sock = plainfd[1]; /* use the decrypted FD from now on */ } #else if (keyfile) { strncpy(errstr, "TLS requested but support not compiled in", errstr_len); goto err; } #endif if(testflags & TEST_EXPECT_ERROR) { struct sigaction act; memset(&act, '0', sizeof act); act.sa_handler = SIG_IGN; sigaction(SIGPIPE, &act, NULL); } /* magic */ tmp64 = htonll(opts_magic); WRITE_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err, "Could not write magic: %s", strerror(errno)); /* name */ tmp32 = htonl(NBD_OPT_EXPORT_NAME); WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err, "Could not write option: %s", strerror(errno)); tmp32 = htonl((uint32_t) strlen(name)); WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err, "Could not write name length: %s", strerror(errno)); WRITE_ALL_ERRCHK(sock, name, strlen(name), err, "Could not write name:: %s", strerror(errno)); READ_ALL_ERRCHK(sock, &size, sizeof(size), err, "Could not read size: %s", strerror(errno)); size = ntohll(size); uint16_t flags; READ_ALL_ERRCHK(sock, &flags, sizeof(uint16_t), err, "Could not read flags: %s", strerror(errno)); flags = ntohs(flags); *serverflags = flags; READ_ALL_ERRCHK(sock, buf, 124, err, "Could not read reserved zeroes: %s", strerror(errno)); goto end; err: close(sock); sock = -1; end: return sock; }