Example #1
0
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;
}
Example #2
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;
}