mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-03-13 14:58:07 +08:00
cstp_recv_nb: improve operation under receiving from UNIX socket
That is, ensure that all possible packet size combinations are correctly received. Signed-off-by: Nikos Mavrogiannopoulos <nmav@gnutls.org>
This commit is contained in:
129
src/tlslib.c
129
src/tlslib.c
@@ -137,6 +137,75 @@ int ret;
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int recv_remaining(int fd, uint8_t *p, int left)
|
||||||
|
{
|
||||||
|
int counter = 100; /* allow 10 seconds for a full packet */
|
||||||
|
unsigned total = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
while(left > 0) {
|
||||||
|
ret = recv(fd, p, left, 0);
|
||||||
|
if (ret == -1 && counter > 0 && (errno == EINTR || errno == EAGAIN)) {
|
||||||
|
counter--;
|
||||||
|
ms_sleep(100);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ret == 0)
|
||||||
|
ret = GNUTLS_E_PREMATURE_TERMINATION;
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
left -= ret;
|
||||||
|
p += ret;
|
||||||
|
total += ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Receives CSTP packet, after the channel is established.
|
||||||
|
* It makes sure that CSTP packet boundaries are respected in
|
||||||
|
* case we do not read over TLS - e.g., when TLS is done by
|
||||||
|
* a proxy. */
|
||||||
|
static ssize_t _cstp_recv_packet(worker_st *ws, void *data, size_t data_size)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* socket is in non-blocking mode already */
|
||||||
|
|
||||||
|
if (ws->session != NULL) {
|
||||||
|
return gnutls_record_recv(ws->session, data, data_size);
|
||||||
|
} else {
|
||||||
|
/* It can happen in UNIX sockets case that we receive an
|
||||||
|
* incomplete CSTP packet. In that case we attempt to read
|
||||||
|
* a full CSTP packet.
|
||||||
|
*/
|
||||||
|
unsigned pktlen;
|
||||||
|
uint8_t *p = data;
|
||||||
|
|
||||||
|
/* read the header */
|
||||||
|
ret = recv_remaining(ws->conn_fd, p, 8);
|
||||||
|
if (ret <= 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* get the actual length from headers */
|
||||||
|
pktlen = (p[4] << 8) + p[5];
|
||||||
|
if (pktlen+8 > data_size) {
|
||||||
|
oclog(ws, LOG_ERR, "error in CSTP packet length");
|
||||||
|
return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pktlen > 0) {
|
||||||
|
ret = recv_remaining(ws->conn_fd, p+8, pktlen);
|
||||||
|
if (ret <= 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 8+pktlen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t cstp_recv_packet(worker_st *ws, gnutls_datum_t *data, void **p)
|
ssize_t cstp_recv_packet(worker_st *ws, gnutls_datum_t *data, void **p)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@@ -150,13 +219,13 @@ ssize_t cstp_recv_packet(worker_st *ws, gnutls_datum_t *data, void **p)
|
|||||||
gnutls_packet_get(packet, data, NULL);
|
gnutls_packet_get(packet, data, NULL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ret = cstp_recv_nb(ws, ws->buffer, ws->buffer_size);
|
ret = _cstp_recv_packet(ws, ws->buffer, ws->buffer_size);
|
||||||
data->data = ws->buffer;
|
data->data = ws->buffer;
|
||||||
data->size = ret;
|
data->size = ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
ret = cstp_recv_nb(ws, ws->buffer, ws->buffer_size);
|
ret = _cstp_recv_packet(ws, ws->buffer, ws->buffer_size);
|
||||||
data->data = ws->buffer;
|
data->data = ws->buffer;
|
||||||
data->size = ret;
|
data->size = ret;
|
||||||
#endif
|
#endif
|
||||||
@@ -190,62 +259,6 @@ ssize_t cstp_recv(worker_st *ws, void *data, size_t data_size)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t cstp_recv_nb(worker_st *ws, void *data, size_t data_size)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* socket is in non-blocking mode already */
|
|
||||||
|
|
||||||
if (ws->session != NULL) {
|
|
||||||
ret = gnutls_record_recv(ws->session, data, data_size);
|
|
||||||
} else {
|
|
||||||
/* It can happen in UNIX sockets case that we receive an
|
|
||||||
* incomplete CSTP packet. In that case we attempt to read
|
|
||||||
* a full CSTP packet.
|
|
||||||
*/
|
|
||||||
int counter = 100; /* allow 10 seconds for a full packet */
|
|
||||||
unsigned pktlen;
|
|
||||||
unsigned total = 0;
|
|
||||||
int left = data_size;
|
|
||||||
uint8_t *p = data;
|
|
||||||
|
|
||||||
ret = recv(ws->conn_fd, p, left, 0);
|
|
||||||
if (ret > 6) {
|
|
||||||
total += ret;
|
|
||||||
/* get the actual length from headers */
|
|
||||||
pktlen = (p[4] << 8) + p[5];
|
|
||||||
if (pktlen+8 > data_size) {
|
|
||||||
oclog(ws, LOG_ERR, "error in CSTP packet length");
|
|
||||||
return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
p = p + ret;
|
|
||||||
left = pktlen+8 - ret;
|
|
||||||
|
|
||||||
while(left > 0) {
|
|
||||||
ret = recv(ws->conn_fd, p, left, 0);
|
|
||||||
if (ret == -1 && counter > 0 && (errno == EINTR || errno == EAGAIN)) {
|
|
||||||
counter--;
|
|
||||||
ms_sleep(100);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (ret == 0)
|
|
||||||
ret = GNUTLS_E_PREMATURE_TERMINATION;
|
|
||||||
if (ret < 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
left -= ret;
|
|
||||||
p += ret;
|
|
||||||
total += ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = total;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Typically used in a resumed session. It will return
|
/* Typically used in a resumed session. It will return
|
||||||
* true if a certificate has been used.
|
* true if a certificate has been used.
|
||||||
|
|||||||
@@ -126,7 +126,6 @@ void cstp_close(struct worker_st *ws);
|
|||||||
void cstp_fatal_close(struct worker_st *ws,
|
void cstp_fatal_close(struct worker_st *ws,
|
||||||
gnutls_alert_description_t a);
|
gnutls_alert_description_t a);
|
||||||
ssize_t cstp_recv(struct worker_st *ws, void *data, size_t data_size);
|
ssize_t cstp_recv(struct worker_st *ws, void *data, size_t data_size);
|
||||||
ssize_t cstp_recv_nb(struct worker_st *ws, void *data, size_t data_size);
|
|
||||||
ssize_t cstp_send_file(struct worker_st *ws, const char *file);
|
ssize_t cstp_send_file(struct worker_st *ws, const char *file);
|
||||||
ssize_t cstp_send(struct worker_st *ws, const void *data,
|
ssize_t cstp_send(struct worker_st *ws, const void *data,
|
||||||
size_t data_size);
|
size_t data_size);
|
||||||
|
|||||||
Reference in New Issue
Block a user