Example #1
0
/* returns error if no retry_after hdr field is present */
static int blst_add_retry_after_f(struct sip_msg* msg, char* min, char* max)
{
#ifdef USE_DST_BLACKLIST
	int t_min, t_max, t;
	struct dest_info src;
	struct hdr_field* hf;
	
	if (likely(cfg_get(core, core_cfg, use_dst_blacklist))){
		if (unlikely(get_int_fparam(&t_min, msg, (fparam_t*)min)<0)) return -1;
		if (likely(max)){
			if (unlikely(get_int_fparam(&t_max, msg, (fparam_t*)max)<0))
				return -1;
		}else{
			t_max=0;
		}
	
		init_dest_info(&src);
		src.send_sock=0;
		src.to=msg->rcv.src_su;
		src.id=msg->rcv.proto_reserved1;
		src.proto=msg->rcv.proto;
		t=-1;
		if ((parse_headers(msg, HDR_RETRY_AFTER_F, 0)==0) && 
			(msg->parsed_flag & HDR_RETRY_AFTER_F)){
			for (hf=msg->headers; hf; hf=hf->next)
				if (hf->type==HDR_RETRY_AFTER_T){
					/* found */
					t=(unsigned)(unsigned long)hf->parsed;
					break;
			}
		}
		if (t<0)
			return -1;
		
		t=MAX_unsigned(t, t_min);
		t=MIN_unsigned(t, t_max);
		if (likely(t))
			dst_blacklist_force_add_to(BLST_ADM_PROHIBITED, &src, msg,
										S_TO_TICKS(t));
		return 1;
	}else{
		LOG(L_WARN, "WARNING: blst: blst_add_retry_after:"
					" blacklist support disabled\n");
	}
#else /* USE_DST_BLACKLIST */
	LOG(L_WARN, "WARNING: blst: blst_add_retry_after:"
			" blacklist support not compiled-in - no effect -\n");
#endif /* USE_DST_BLACKLIST */
	return 1;
}
Example #2
0
/** tls read.
 * Each modification of ssl data structures has to be protected, another process * might ask for the same connection and attempt write to it which would
 * result in updating the ssl structures.
 * WARNING: must be called whic c->write_lock _unlocked_.
 * @param c - tcp connection pointer. The following flags might be set:
 * @param flags - value/result:
 *                     input: RD_CONN_FORCE_EOF  - force EOF after the first
 *                            successful read (bytes_read >=0 )
 *                     output: RD_CONN_SHORT_READ if the read exhausted
 *                              all the bytes in the socket read buffer.
 *                             RD_CONN_EOF if EOF detected (0 bytes read)
 *                              or forced via RD_CONN_FORCE_EOF.
 *                             RD_CONN_REPEAT_READ  if this function should
 *                              be called again (e.g. has some data
 *                              buffered internally that didn't fit in
 *                              tcp_req).
 *                     Note: RD_CONN_SHORT_READ & RD_CONN_EOF should be cleared
 *                           before calling this function when there is new
 *                           data (e.g. POLLIN), but not if the called is
 *                           retried because of RD_CONN_REPEAT_READ and there
 *                           is no information about the socket having more
 *                           read data available.
 * @return bytes decrypted on success, -1 on error (it also sets some
 *         tcp connection flags and might set c->state and r->error on
 *         EOF or error).
 */
int tls_read_f(struct tcp_connection* c, int* flags)
{
	struct tcp_req* r;
	int bytes_free, bytes_read, read_size, ssl_error, ssl_read;
	SSL* ssl;
	unsigned char rd_buf[TLS_RD_MBUF_SZ];
	unsigned char wr_buf[TLS_WR_MBUF_SZ];
	struct tls_mbuf rd, wr;
	struct tls_extra_data* tls_c;
	struct tls_rd_buf* enc_rd_buf;
	int n, flush_flags;
	char* err_src;
	int x;
	int tls_dbg;
	
	TLS_RD_TRACE("(%p, %p (%d)) start (%s -> %s:%d*)\n",
					c, flags, *flags,
					su2a(&c->rcv.src_su, sizeof(c->rcv.src_su)),
					ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port);
	ssl_read = 0;
	r = &c->req;
	enc_rd_buf = 0;
	*flags &= ~RD_CONN_REPEAT_READ;
	if (unlikely(tls_fix_connection(c) < 0)) {
		TLS_RD_TRACE("(%p, %p) end: tls_fix_connection failed =>"
						" immediate error exit\n", c, flags);
		return -1;
	}
	/* here it's safe to use c->extra_data in read-only mode.
	   If it's != 0 is changed only on destroy. It's not possible to have
	   parallel reads.*/
	tls_c = c->extra_data;
	bytes_free = c->req.b_size - (int)(r->pos - r->buf);
	if (unlikely(bytes_free == 0)) {
		ERR("Buffer overrun, dropping\n");
		r->error = TCP_REQ_OVERRUN;
		return -1;
	}
redo_read:
	/* if data queued from a previous read(), use it (don't perform
	 * a real read()).
	*/
	if (unlikely(tls_c->enc_rd_buf)) {
		/* use queued data */
		/* safe to use without locks, because only read changes it and
		   there can't be parallel reads on the same connection */
		enc_rd_buf = tls_c->enc_rd_buf;
		tls_c->enc_rd_buf = 0;
		TLS_RD_TRACE("(%p, %p) using queued data (%p: %p %d bytes)\n", c,
					flags, enc_rd_buf, enc_rd_buf->buf + enc_rd_buf->pos,
					enc_rd_buf->size - enc_rd_buf->pos);
		tls_mbuf_init(&rd, enc_rd_buf->buf + enc_rd_buf->pos,
						enc_rd_buf->size - enc_rd_buf->pos);
		rd.used = enc_rd_buf->size - enc_rd_buf->pos;
	} else {
		/* if we were using using queued data before, free & reset the
			the queued read data before performing the real read() */
		if (unlikely(enc_rd_buf)) {
			TLS_RD_TRACE("(%p, %p) reset prev. used enc_rd_buf (%p)\n", c,
							flags, enc_rd_buf);
			shm_free(enc_rd_buf);
			enc_rd_buf = 0;
		}
		/* real read() */
		tls_mbuf_init(&rd, rd_buf, sizeof(rd_buf));
		/* read() only if no previously detected EOF, or previous
		   short read (which means the socket buffer was emptied) */
		if (likely(!(*flags & (RD_CONN_EOF|RD_CONN_SHORT_READ)))) {
			/* don't read more then the free bytes in the tcp req buffer */
			read_size = MIN_unsigned(rd.size, bytes_free);
			bytes_read = tcp_read_data(c->fd, c, (char*)rd.buf, read_size,
										flags);
			TLS_RD_TRACE("(%p, %p) tcp_read_data(..., %d, *%d) => %d bytes\n",
						c, flags, read_size, *flags, bytes_read);
			/* try SSL_read even on 0 bytes read, it might have
			   internally buffered data */
			if (unlikely(bytes_read < 0)) {
					goto error;
			}
			rd.used = bytes_read;
		}
	}
	
continue_ssl_read:
	tls_mbuf_init(&wr, wr_buf, sizeof(wr_buf));
	ssl_error = SSL_ERROR_NONE;
	err_src = "TLS read:";
	/* we have to avoid to run in the same time 
	 * with a tls_write because of the
	 * update bio stuff  (we don't want a write
	 * stealing the wbio or rbio under us or vice versa)
	 * => lock on con->write_lock (ugly hack) */
	lock_get(&c->write_lock);
		tls_set_mbufs(c, &rd, &wr);
		ssl = tls_c->ssl;
		n = 0;
		if (unlikely(tls_write_wants_read(tls_c) &&
						!(*flags & RD_CONN_EOF))) {
			n = tls_ct_wq_flush(c, &tls_c->ct_wq, &flush_flags,
								&ssl_error);
			TLS_RD_TRACE("(%p, %p) tls write on read (WRITE_WANTS_READ):"
							" ct_wq_flush()=> %d (ff=%d ssl_error=%d))\n",
							c, flags, n, flush_flags, ssl_error);
			if (unlikely(n < 0 )) {
				tls_set_mbufs(c, 0, 0);
				lock_release(&c->write_lock);
				ERR("write flush error (%d)\n", n);
				goto error;
			}
			if (likely(flush_flags & F_BUFQ_EMPTY))
				tls_c->flags &= ~F_TLS_CON_WR_WANTS_RD;
			if (unlikely(flush_flags & F_BUFQ_ERROR_FLUSH))
				err_src = "TLS write:";
		}
		if (likely(ssl_error == SSL_ERROR_NONE)) {
			if (unlikely(tls_c->state == S_TLS_CONNECTING)) {
				n = tls_connect(c, &ssl_error);
				TLS_RD_TRACE("(%p, %p) tls_connect() => %d (err=%d)\n",
								c, flags, n, ssl_error);
				if (unlikely(n>=1)) {
					n = SSL_read(ssl, r->pos, bytes_free);
				} else {
					/* tls_connect failed/needs more IO */
					if (unlikely(n < 0 && ssl_error == SSL_ERROR_NONE)) {
						lock_release(&c->write_lock);
						goto error;
					}
					err_src = "TLS connect:";
					goto ssl_read_skipped;
				}
			} else if (unlikely(tls_c->state == S_TLS_ACCEPTING)) {
				n = tls_accept(c, &ssl_error);
				TLS_RD_TRACE("(%p, %p) tls_accept() => %d (err=%d)\n",
								c, flags, n, ssl_error);
				if (unlikely(n>=1)) {
					n = SSL_read(ssl, r->pos, bytes_free);
				} else {
					/* tls_accept failed/needs more IO */
					if (unlikely(n < 0 && ssl_error == SSL_ERROR_NONE)) {
						lock_release(&c->write_lock);
						goto error;
					}
					err_src = "TLS accept:";
					goto ssl_read_skipped;
				}
			} else {
				/* if bytes in then decrypt read buffer into tcpconn req.
				   buffer */
				n = SSL_read(ssl, r->pos, bytes_free);
			}
			/** handle SSL_read() return.
			 *  There are 3 main cases, each with several sub-cases, depending
			 *  on whether or not the output buffer was filled, if there
			 *  is still unconsumed input data in the input buffer (rd)
			 *  and if there is "cached" data in the internal openssl
			 *  buffers.
			 *  0. error (n<=0):
			 *     SSL_ERROR_WANT_READ - input data fully
			 *       consumed, no more returnable cached data inside openssl
			 *       => exit.
			 *     SSL_ERROR_WANT_WRITE - should never happen (the write
			 *       buffer is big enough to handle any re-negociation).
			 *     SSL_ERROR_ZERO_RETURN - ssl level shutdown => exit.
			 *    other errors are unexpected.
			 * 1. output buffer filled (n == bytes_free):
			 *    1i.  - still unconsumed input, nothing buffered by openssl
			 *    1ip. - unconsumed input + buffered data by openssl (pending
			             on the next SSL_read).
			 *    1p.  - completely consumed input, buffered data internally
			 *            by openssl (pending).
			 *           Likely to happen, about the only case when
			 *           SSL_pending() could be used (but only if readahead=0).
			 *    1f.  - consumed input, no buffered data.
			 * 2. output buffer not fully filled (n < bytes_free):
			 *     2i. - still unconsumed input, nothing buffered by openssl.
			 *           This can appear if SSL readahead is 0 (SSL_read()
			 *           tries to get only 1 record from the input).
			 *     2ip. - unconsumed input and buffered data by openssl.
			 *            Unlikely to happen (e.g. readahead is 1, more
			 *            records are buffered internally by openssl, but
			 *            there was not enough space for buffering the whole
			 *            input).
			 *     2p  - consumed input, but buffered data by openssl.
			 *            It happens especially when readahead is 1.
			 *     2f.  - consumed input, no buffered data.
			 *
			 * One should repeat SSL_read() until and error is detected
			 *  (0*) or the input and internal ssl buffers are fully consumed
			 *  (1f or 2f). However in general is not possible to see if
			 *  SSL_read() could return more data. SSL_pending() has very
			 *  limited usability (basically it would return !=0 only if there
			 *  was no enough space in the output buffer and only if this did
			 *  not happen at a record boundary).
			 * The solution is to repeat SSL_read() until error or until
			 *  the output buffer is filled (0* or 1*).
			 *  In the later case, this whole function should be called again
			 *  once there is more output space (set RD_CONN_REPEAT_READ).
			 */

			if (unlikely(tls_c->flags & F_TLS_CON_RENEGOTIATION)) {
				/* Fix CVE-2009-3555 - disable renegotiation if started by client
				 * - simulate SSL EOF to force close connection*/
				tls_dbg = cfg_get(tls, tls_cfg, debug);
				LOG(tls_dbg, "Reading on a renegotiation of connection (n:%d) (%d)\n",
						n, SSL_get_error(ssl, n));
				err_src = "TLS R-N read:";
				ssl_error = SSL_ERROR_ZERO_RETURN;
			} else {
				if (unlikely(n <= 0)) {
					ssl_error = SSL_get_error(ssl, n);
					err_src = "TLS read:";
					/*  errors handled below, outside the lock */
				} else {
					ssl_error = SSL_ERROR_NONE;
					r->pos += n;
					ssl_read += n;
					bytes_free -=n;
				}
			}
			TLS_RD_TRACE("(%p, %p) SSL_read() => %d (err=%d) ssl_read=%d"
							" *flags=%d tls_c->flags=%d\n",
							c, flags, n, ssl_error, ssl_read, *flags,
							tls_c->flags);
ssl_read_skipped:
			;
		}
		if (unlikely(wr.used != 0 && ssl_error != SSL_ERROR_ZERO_RETURN)) {
			TLS_RD_TRACE("(%p, %p) tcpconn_send_unsafe %d bytes\n",
							c, flags, wr.used);
			/* something was written and it's not ssl EOF*/
			if (unlikely(tcpconn_send_unsafe(c->fd, c, (char*)wr.buf,
											wr.used, c->send_flags) < 0)) {
				tls_set_mbufs(c, 0, 0);
				lock_release(&c->write_lock);
				TLS_RD_TRACE("(%p, %p) tcpconn_send_unsafe error\n", c, flags);
				goto error_send;
			}
		}
	/* quickly catch bugs: segfault if accessed and not set */
	tls_set_mbufs(c, 0, 0);
	lock_release(&c->write_lock);
	switch(ssl_error) {
		case SSL_ERROR_NONE:
			if (unlikely(n < 0)) {
				BUG("unexpected SSL_ERROR_NONE for n=%d\n", n);
				goto error;
			}
			break;
		case SSL_ERROR_ZERO_RETURN:
			/* SSL EOF */
			TLS_RD_TRACE("(%p, %p) SSL EOF (fd=%d)\n", c, flags, c->fd);
			goto ssl_eof;
		case SSL_ERROR_WANT_READ:
			TLS_RD_TRACE("(%p, %p) SSL_ERROR_WANT_READ *flags=%d\n",
							c, flags, *flags);
			/* needs to read more data */
			if (unlikely(rd.pos != rd.used)) {
				/* data still in the read buffer */
				BUG("SSL_ERROR_WANT_READ but data still in"
						" the rbio (%p, %d bytes at %d)\n", rd.buf,
						rd.used - rd.pos, rd.pos);
				goto bug;
			}
			if (unlikely((*flags & (RD_CONN_EOF | RD_CONN_SHORT_READ)) == 0) &&
							bytes_free){
				/* there might still be data to read and there is space
				   to decrypt it in tcp_req (no byte has been written into
				    tcp_req in this case) */
				TLS_RD_TRACE("(%p, %p) redo read *flags=%d bytes_free=%d\n",
								c, flags, *flags, bytes_free);
				goto redo_read;
			}
			goto end; /* no more data to read */
		case SSL_ERROR_WANT_WRITE:
			if (wr.used) {
				/* something was written => buffer not big enough to hold
				   everything => reset buffer & retry (the tcp_write already
				   happened if we are here) */
				TLS_RD_TRACE("(%p) SSL_ERROR_WANT_WRITE partial write"
							" (written  %d), retrying\n", c, wr.used);
				goto continue_ssl_read;
			}
			/* else write buffer too small, nothing written */
			BUG("write buffer too small (%d/%d bytes)\n",
						wr.used, wr.size);
			goto bug;
		case SSL_ERROR_SSL:
			/* protocol level error */
			TLS_ERR(err_src);
			goto error;
#if OPENSSL_VERSION_NUMBER >= 0x00907000L /*0.9.7*/
		case SSL_ERROR_WANT_CONNECT:
			/* only if the underlying BIO is not yet connected
			   and the call would block in connect().
			   (not possible in our case) */
			BUG("unexpected SSL_ERROR_WANT_CONNECT\n");
			goto bug;
		case SSL_ERROR_WANT_ACCEPT:
			/* only if the underlying BIO is not yet connected
			   and call would block in accept()
			   (not possible in our case) */
			BUG("unexpected SSL_ERROR_WANT_ACCEPT\n");
			goto bug;
#endif
		case SSL_ERROR_WANT_X509_LOOKUP:
			/* can only appear on client application and it indicates that
			   an installed client cert. callback should be called again
			   (it returned < 0 indicated that it wants to be called
			   later). Not possible in our case */
			BUG("unsupported SSL_ERROR_WANT_X509_LOOKUP");
			goto bug;
		case SSL_ERROR_SYSCALL:
			TLS_ERR_RET(x, err_src);
			if (!x) {
				if (n == 0) {
					WARN("Unexpected EOF\n");
				} else
					/* should never happen */
					BUG("IO error (%d) %s\n", errno, strerror(errno));
			}
			goto error;
		default:
			TLS_ERR(err_src);
			BUG("unexpected SSL error %d\n", ssl_error);
			goto bug;
	}
	if (unlikely(n < 0)) {
		/* here n should always be >= 0 */
		BUG("unexpected value (n = %d)\n", n);
		goto bug;
	}
	if (unlikely(rd.pos != rd.used)) {
		/* encrypted data still in the read buffer (SSL_read() did not
		   consume all of it) */
		if (unlikely(n < 0))
			/* here n should always be >= 0 */
			BUG("unexpected value (n = %d)\n", n);
		else {
			if (unlikely(bytes_free != 0)) {
				/* 2i or 2ip: unconsumed input and output buffer not filled =>
				  retry ssl read (SSL_read() will read will stop at
				  record boundaries, unless readahead==1).
				  No tcp_read() is attempted, since that would reset the
				  current no-yet-consumed input data.
				 */
				TLS_RD_TRACE("(%p, %p) input not fully consumed =>"
								" retry SSL_read"
								" (pos: %d, remaining %d, output free %d)\n",
								c, flags, rd.pos, rd.used-rd.pos, bytes_free);
				goto continue_ssl_read;
			}
			/* 1i or 1ip: bytes_free == 0
			   (unconsumed input, but filled output  buffer) =>
			    queue read data, and exit asking for repeating the call
			    once there is some space in the output buffer.
			 */
			if (likely(!enc_rd_buf)) {
				TLS_RD_TRACE("(%p, %p) creating enc_rd_buf (for %d bytes)\n",
								c, flags, rd.used - rd.pos);
				enc_rd_buf = shm_malloc(sizeof(*enc_rd_buf) -
										sizeof(enc_rd_buf->buf) +
										rd.used - rd.pos);
				if (unlikely(enc_rd_buf == 0)) {
					ERR("memory allocation error (%d bytes requested)\n",
						(int)(sizeof(*enc_rd_buf) + sizeof(enc_rd_buf->buf) +
										rd.used - rd.pos));
					goto error;
				}
				enc_rd_buf->pos = 0;
				enc_rd_buf->size = rd.used - rd.pos;
				memcpy(enc_rd_buf->buf, rd.buf + rd.pos,
										enc_rd_buf->size);
			} else if ((enc_rd_buf->buf + enc_rd_buf->pos) == rd.buf) {
				TLS_RD_TRACE("(%p, %p) enc_rd_buf already in use,"
								" updating pos %d\n",
								c, flags, enc_rd_buf->pos);
				enc_rd_buf->pos += rd.pos;
			} else {
				BUG("enc_rd_buf->buf = %p, pos = %d, rd_buf.buf = %p\n",
						enc_rd_buf->buf, enc_rd_buf->pos, rd.buf);
				goto bug;
			}
			if (unlikely(tls_c->enc_rd_buf))
				BUG("tls_c->enc_rd_buf!=0 (%p)\n", tls_c->enc_rd_buf);
			/* there can't be 2 reads in parallel, so no locking is needed
			   here */
			tls_c->enc_rd_buf = enc_rd_buf;
			enc_rd_buf = 0;
			*flags |= RD_CONN_REPEAT_READ;
		}
	} else if (bytes_free != 0) {
		/*  2f or 2p: input fully consumed (rd.pos == rd.used),
		    output buffer not filled, still possible to have pending
		    data buffered by openssl */
		if (unlikely((*flags & (RD_CONN_EOF|RD_CONN_SHORT_READ)) == 0)) {
			/* still space in the tcp unenc. req. buffer, no SSL_read error,
			   not a short read and not an EOF (possible more data in
			   the socket buffer) => try a new tcp read too */
			TLS_RD_TRACE("(%p, %p) retry read (still space and no short"
							" tcp read: %d)\n", c, flags, *flags);
			goto redo_read;
		} else {
			/* don't tcp_read() anymore, but there might still be data
			   buffered internally by openssl (e.g. if readahead==1) =>
			   retry SSL_read() with the current full input buffer
			   (if no more internally SSL buffered data => WANT_READ => exit).
			 */
			TLS_RD_TRACE("(%p, %p) retry SSL_read only (*flags =%d)\n",
							c, flags, *flags);
			goto continue_ssl_read;
		}
	} else {
		/*   1p or 1f: rd.pos == rd.used && bytes_free == 0
			 (input fully consumed && output buffer filled) */
		/* ask for a repeat when there is more buffer space
		   (there is no definitive way to know if ssl doesn't still have
		    some internal buffered data until we get WANT_READ, see
			SSL_read() comment above) */
		*flags |= RD_CONN_REPEAT_READ;
		TLS_RD_TRACE("(%p, %p) output filled, exit asking to be called again"
						" (*flags =%d)\n", c, flags, *flags);
	}
	
end:
	if (enc_rd_buf)
		shm_free(enc_rd_buf);
	TLS_RD_TRACE("(%p, %p) end => %d (*flags=%d)\n",
					c, flags, ssl_read, *flags);
	return ssl_read;
ssl_eof:
	/* behave as an EOF would have been received at the tcp level */
	if (enc_rd_buf)
		shm_free(enc_rd_buf);
	c->state = S_CONN_EOF;
	*flags |= RD_CONN_EOF;
	TLS_RD_TRACE("(%p, %p) end EOF => %d (*flags=%d)\n",
					c, flags, ssl_read, *flags);
	return ssl_read;
error_send:
error:
bug:
	if (enc_rd_buf)
		shm_free(enc_rd_buf);
	r->error=TCP_READ_ERROR;
	TLS_RD_TRACE("(%p, %p) end error => %d (*flags=%d)\n",
					c, flags, ssl_read, *flags);
	return -1;
}