From 10cb4c07ec476872210906a0e4eb09068903f324 Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Thu, 2 Feb 2017 14:32:41 +0500 Subject: sstp: implement preliminar sstp protocol support --- accel-pppd/ctrl/sstp/sstp.c | 1483 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1483 insertions(+) create mode 100644 accel-pppd/ctrl/sstp/sstp.c (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c new file mode 100644 index 0000000..b78ecc6 --- /dev/null +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -0,0 +1,1483 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CRYPTO_OPENSSL +#include +#include +#endif + +#include "triton.h" +#include "events.h" +#include "list.h" +#include "log.h" +#include "ppp.h" +#include "utils.h" +#include "mempool.h" +#include "iprange.h" +#include "connlimit.h" +#include "cli.h" + +#include "memdebug.h" + +#include "sstp_prot.h" + +#ifndef min +#define min(x,y) ((x) < (y) ? (x) : (y)) +#endif + +struct sstp_serv_t { + struct triton_context_t ctx; + struct triton_md_handler_t hnd; + + //uint8_t certificate_hash[32]; +}; + +struct sstp_conn_t { + struct triton_context_t ctx; + struct triton_md_handler_t hnd; + struct triton_md_handler_t ppp_hnd; + struct triton_timer_t timeout_timer; + struct triton_timer_t hello_timer; + +#ifdef CRYPTO_OPENSSL + SSL_CTX *ssl_ctx; + SSL *ssl; +#endif + int state; + int sstp_state; + int hello_sent; + +// int bypass_auth:1; +// char *http_cookie; +// uint8_t auth_key[32]; + + struct list_head send_queue; + void *ppp_buf; + uint8_t *in_buf; + int in_size; + + struct ap_ctrl ctrl; + struct ppp_t ppp; +}; + +struct sstp_pack_t { + struct list_head entry; + void *data; + int size; +}; + +static int conf_timeout = SSTP_NEGOTIOATION_TIMEOUT; +static int conf_hello_interval = SSTP_HELLO_TIMEOUT; +static int conf_verbose = 0; +static int conf_ppp_max_mtu = SSTP_MAX_PACKET_SIZE - 8; +static int conf_hash_protocol = CERT_HASH_PROTOCOL_SHA256; +//static int conf_bypass_auth = 0; +static const char *conf_ip_pool; +static int conf_ssl = 1; +static char *conf_ssl_ciphers = "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4"; +static char *conf_ssl_ca_file = NULL; +static char *conf_ssl_pemfile = NULL; + +static mempool_t conn_pool; +static mempool_t pack_pool; +static mempool_t data_pool; + +static unsigned int stat_starting; +static unsigned int stat_active; + +static int sstp_msg_call_abort(struct sstp_conn_t *conn); +static int sstp_msg_call_disconnect(struct sstp_conn_t *conn); +static int sstp_send(struct sstp_conn_t *conn, void *data, int size); + +/* http */ + +static char *http_getline(struct sstp_conn_t *conn, int *pos, char *buf, int size) +{ + unsigned char *src, *dst, c, pc; + + size = min(size - 1, conn->in_size - *pos); + if (size <= 0) + return NULL; + + src = conn->in_buf + *pos; + dst = (unsigned char *)buf; + for (pc = 0; size--; dst++) { + c = *dst = *src++; + if (c == '\0') + break; + if (c == '\n') { + if (pc == '\r') + dst--; + break; + } + pc = c; + } + *dst = '\0'; + + *pos = src - conn->in_buf; + + return buf; +} + +static int send_http_response(struct sstp_conn_t *conn, char *proto, char *status, char *headers) +{ + char timebuf[80], *msg = mempool_alloc(data_pool); + time_t now = time(NULL); + + if (!msg) { + log_error("sstp: no memory\n"); + return -1; + } + + strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now)); + snprintf(msg, SSTP_MAX_PACKET_SIZE, + "%s %s\r\n" + "%s" + "Server: Microsoft-HTTPAPI/2.0\r\n" + "Date: %s\r\n" + "\r\n", proto, status, headers, timebuf); + + if (conf_verbose) + log_ppp_debug("send [sstp HTTP reply <%s %s>]\n", proto, status); + + return sstp_send(conn, msg, strlen(msg)); +} + +static int http_request(struct sstp_conn_t *conn) +{ + char buf[1024]; + char *line, *method, *request, *proto; + int pos = 0; + + if (conn->sstp_state != STATE_SERVER_CALL_DISCONNECTED) + return -1; + + line = http_getline(conn, &pos, buf, sizeof(buf)); + if (line == NULL) + goto error; + if (conf_verbose) + log_ppp_debug("recv [sstp HTTP request <%s>]\n", line); + + method = strsep(&line, " "); + request = strsep(&line, " "); + proto = strsep(&line, " "); + + if (!method || !request || !proto) { + send_http_response(conn, "HTTP/1.1", "400 Bad Request", NULL); + goto error; + } + if (strncmp(proto, "HTTP/1", sizeof("HTTP/1") - 1) != 0) { + send_http_response(conn, "HTTP/1.1", "505 HTTP Version Not Supported", NULL); + goto error; + } + if (strcmp(method, SSTP_HTTP_METHOD) != 0) { + send_http_response(conn, proto, "405 Method Not Allowed", NULL); + goto error; + } + if (strcmp(request, SSTP_HTTP_URI) != 0) { + send_http_response(conn, proto, "404 Not Found", NULL); + goto error; + } + + while ((line = http_getline(conn, &pos, buf, sizeof(buf))) != NULL) { + if (*line == '\0') + break; + if (conf_verbose) + log_ppp_debug("recv [sstp HTTP request <%s>]\n", line); + } while (*line); + + if (send_http_response(conn, proto, "200 OK", + "Content-Length: 18446744073709551615\r\n")) { + goto error; + } + conn->sstp_state = STATE_SERVER_CONNECT_REQUEST_PENDING; + + return pos; + +error: + return -1; +} + +/* ppp */ + +static int ppp_allocate_pty(int *master, int *slave, int flags) +{ + struct termios tios; + char pty_name[16]; + int value, mfd, sfd = -1; + + mfd = open("/dev/ptmx", O_RDWR | flags); + if (mfd < 0) { + log_ppp_error("sstp: can't open pty %s: %s\n", "/dev/ptmx", strerror(errno)); + return -1; + } + + if (ioctl(mfd, TIOCGPTN, &value) < 0) { + log_ppp_error("sstp: can't allocate slave pty: %s\n", strerror(errno)); + goto error; + } + snprintf(pty_name, sizeof(pty_name), "/dev/pts/%d", value); + + value = 0; + if (ioctl(mfd, TIOCSPTLCK, &value) < 0) + log_ppp_warn("sstp: can't unlock pty %s: %s\n", pty_name, strerror(errno)); + + sfd = open(pty_name, O_RDWR | O_NOCTTY | flags); + if (sfd < 0) { + log_ppp_error("sstp: can't open pty %s: %s\n", pty_name, strerror(errno)); + goto error; + } + + if (tcgetattr(sfd, &tios) == 0) { + tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB); + tios.c_cflag |= CS8 | CREAD | CLOCAL; + tios.c_iflag = IGNPAR; + tios.c_oflag = 0; + tios.c_lflag = 0; + if (tcsetattr(sfd, TCSAFLUSH, &tios) < 0) + log_ppp_warn("sstp: can't set attributes on pty: %s\n", strerror(errno)); + } + + value = N_HDLC; + if (ioctl(mfd, TIOCSETD, &value) < 0) { + log_ppp_error("sstp: can't set N_HDLC line discipline: %s", strerror(errno)); + goto error; + } + + value = N_SYNC_PPP; + if (ioctl(sfd, TIOCSETD, &value) < 0) { + log_ppp_error("sstp: can't set N_SYNC_PPP line discipline: %s", strerror(errno)); + goto error; + } + + *master = mfd; + *slave = sfd; + return 0; + +error: + if (mfd >= 0) + close(mfd); + if (sfd >= 0) + close(sfd); + return -1; +} + +static void ppp_started(struct ap_session *ses) +{ + log_ppp_debug("sstp: ppp started\n"); +} + +static void ppp_finished(struct ap_session *ses) +{ + struct ppp_t *ppp = container_of(ses, typeof(*ppp), ses); + struct sstp_conn_t *conn = container_of(ppp, typeof(*conn), ppp); + + if (conn->state != STATE_CLOSE) { + log_ppp_debug("sstp: ppp finished\n"); + __sync_sub_and_fetch(&stat_active, 1); + conn->state = STATE_CLOSE; + sstp_msg_call_abort(conn); + } +} + +static int ppp_read(struct triton_md_handler_t *h) +{ + struct sstp_conn_t *conn = container_of(h, typeof(*conn), ppp_hnd); + struct sstp_hdr *hdr; + int n; + + hdr = conn->ppp_buf ? : mempool_alloc(data_pool); + if (!hdr) { + log_error("sstp: no memory\n"); + return -1; + } + +again: + n = read(h->fd, hdr->data, SSTP_MAX_PACKET_SIZE - sizeof(*hdr)); + +//int err = errno; +//log_ppp_info2("sstp: ppp.read = %d [%02x%02x...] errno %d %s\n", n, +// (n > 0) ? hdr->data[0] : 0, +// (n > 1) ? hdr->data[1] : 0, +// (n < 0) ? errno : 0, (n < 0) ? strerror(errno) : ""); +//errno = err; + + if (n < 0) { + if (errno == EINTR) + goto again; + if (errno == EAGAIN) { + conn->ppp_buf = hdr; + return 0; + } + if (errno != EPIPE && conf_verbose) + log_ppp_error("ppp error: %s\n", strerror(errno)); + goto drop; + } + if (n == 0) { + if (conf_verbose) + log_ppp_info2("ppp error\n"); + goto drop; + } + + switch (conn->sstp_state) { + case STATE_SERVER_CALL_CONNECTED_PENDING: + case STATE_SERVER_CALL_CONNECTED: + break; + default: + goto drop; + } + + n += sizeof(*hdr); + INIT_SSTP_DATA_HDR(hdr, n); + + if (sstp_send(conn, hdr, n)) + goto drop; + + conn->ppp_buf = NULL; + return 0; + +drop: + conn->ppp_buf = hdr; + return 1; +} + +/* sstp */ + +static void sstp_ctx_switch(struct triton_context_t *ctx, void *arg) +{ + if (arg) { + struct ap_session *s = arg; + net = s->net; + } else + net = def_net; + log_switch(ctx, arg); +} + +static void sstp_timer_set(struct triton_context_t *ctx, struct triton_timer_t *t, int timeout) +{ + t->period = timeout * 1000; + + if (timeout == 0) + triton_timer_del(t); + else if (t->tpd) + triton_timer_mod(t, 0); + else + triton_timer_add(ctx, t, 0); +} + +static void sstp_disconnect(struct sstp_conn_t *conn) +{ + struct sstp_pack_t *pack; + + log_ppp_debug("sstp: disconnect\n"); + +#ifdef CRYPTO_OPENSSL + if (conn->ssl) + SSL_free(conn->ssl); +#endif + triton_md_unregister_handler(&conn->hnd, 1); + + if (conn->timeout_timer.tpd) + triton_timer_del(&conn->timeout_timer); + if (conn->hello_timer.tpd) + triton_timer_del(&conn->hello_timer); + + if (conn->state == STATE_PPP) { + __sync_sub_and_fetch(&stat_active, 1); + conn->state = STATE_CLOSE; + ap_session_terminate(&conn->ppp.ses, TERM_LOST_CARRIER, 1); + } else if (conn->state != STATE_CLOSE) + __sync_sub_and_fetch(&stat_starting, 1); + + if (conn->ppp_hnd.tpd) + triton_md_unregister_handler(&conn->ppp_hnd, 1); + + triton_event_fire(EV_CTRL_FINISHED, &conn->ppp.ses); + + log_ppp_info1("disconnected\n"); + +#ifdef CRYPTO_OPENSSL + if (conn->ssl_ctx) + SSL_CTX_free(conn->ssl_ctx); +#endif + triton_context_unregister(&conn->ctx); + + while (!list_empty(&conn->send_queue)) { + pack = list_first_entry(&conn->send_queue, typeof(*pack), entry); + list_del(&pack->entry); + mempool_free(pack->data); + mempool_free(pack); + } + + if (conn->ppp_buf) + mempool_free(conn->ppp_buf); + _free(conn->in_buf); + _free(conn->ctrl.calling_station_id); + _free(conn->ctrl.called_station_id); + mempool_free(conn); +} + +static int send_sstp_msg_call_connect_ack(struct sstp_conn_t *conn) +{ + struct { + struct sstp_ctrl_hdr hdr; + struct sstp_attrib_crypto_binding_request attr; + } __attribute__((packed)) *msg = mempool_alloc(data_pool); + + if (conf_verbose) + log_ppp_info2("send [sstp SSTP_MSG_CALL_CONNECT_ACK]\n"); + + if (!msg) { + log_error("sstp: no memory\n"); + return -1; + } + + INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_CALL_CONNECT_ACK, 1, sizeof(*msg)); + INIT_SSTP_ATTR_HDR(&msg->attr.hdr, SSTP_ATTRIB_CRYPTO_BINDING_REQ, sizeof(msg->attr)); + msg->attr.hash_protocol_bitmask = conf_hash_protocol; + //read(urandom_fd, msg->attr.nonce, sizeof(msg->attr.nonce)); + memset(msg->attr.nonce, 0, sizeof(msg->attr.nonce)); + + return sstp_send(conn, msg, sizeof(*msg)); +} + +static int send_sstp_msg_call_connect_nak(struct sstp_conn_t *conn) +{ + struct { + struct sstp_ctrl_hdr hdr; + struct sstp_attrib_status_info attr; + uint16_t attr_value; + } __attribute__((packed)) *msg = mempool_alloc(data_pool); + + if (conf_verbose) + log_ppp_info2("send [sstp SSTP_MSG_CALL_CONNECT_NAK]\n"); + + if (!msg) { + log_error("sstp: no memory\n"); + return -1; + } + + INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_CALL_CONNECT_NAK, 1, sizeof(*msg)); + INIT_SSTP_ATTR_HDR(&msg->attr.hdr, SSTP_ATTRIB_STATUS_INFO, sizeof(msg->attr)); + msg->attr.attrib_id = SSTP_ATTRIB_ENCAPSULATED_PROTOCOL_ID; + msg->attr.status = htonl(ATTRIB_STATUS_VALUE_NOT_SUPPORTED); + msg->attr_value = 0; + + return sstp_send(conn, msg, sizeof(*msg)); +} + +static int send_sstp_msg_call_abort(struct sstp_conn_t *conn) +{ + struct { + struct sstp_ctrl_hdr hdr; + struct sstp_attrib_status_info attr; + } __attribute__((packed)) *msg = mempool_alloc(data_pool); + + if (conf_verbose) + log_ppp_info2("send [sstp SSTP_MSG_CALL_ABORT]\n"); + + if (!msg) { + log_error("sstp: no memory\n"); + return -1; + } + + INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_CALL_ABORT, 1, sizeof(*msg)); + INIT_SSTP_ATTR_HDR(&msg->attr.hdr, SSTP_ATTRIB_STATUS_INFO, sizeof(msg->attr)); + msg->attr.attrib_id = SSTP_ATTRIB_STATUS_INFO; + msg->attr.status = htonl(ATTRIB_STATUS_INVALID_FRAME_RECEIVED); + + if (sstp_send(conn, msg, sizeof(*msg))) + return -1; + + switch (conn->sstp_state) { + case STATE_CALL_ABORT_IN_PROGRESS_1: + sstp_timer_set(&conn->ctx, &conn->timeout_timer, SSTP_ABORT_TIMEOUT_1); + conn->sstp_state = STATE_CALL_ABORT_PENDING; + break; + case STATE_CALL_ABORT_IN_PROGRESS_2: + sstp_timer_set(&conn->ctx, &conn->timeout_timer, SSTP_ABORT_TIMEOUT_2); + conn->sstp_state = STATE_CALL_ABORT_TIMEOUT_PENDING; + break; + } + + return 0; +} + +static int send_sstp_msg_call_disconnect(struct sstp_conn_t *conn) +{ + struct { + struct sstp_ctrl_hdr hdr; + struct sstp_attrib_status_info attr; + } __attribute__((packed)) *msg = mempool_alloc(data_pool); + + if (conf_verbose) + log_ppp_info2("send [sstp SSTP_MSG_CALL_DISCONNECT]\n"); + + if (!msg) { + log_error("sstp: no memory\n"); + return -1; + } + + INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_CALL_DISCONNECT, 1, sizeof(*msg)); + INIT_SSTP_ATTR_HDR(&msg->attr.hdr, SSTP_ATTRIB_STATUS_INFO, sizeof(msg->attr)); + msg->attr.attrib_id = SSTP_ATTRIB_NO_ERROR; + msg->attr.status = htonl(ATTRIB_STATUS_NO_ERROR); + + if (sstp_send(conn, msg, sizeof(*msg))) + return -1; + + switch (conn->sstp_state) { + case STATE_CALL_DISCONNECT_IN_PROGRESS_1: + sstp_timer_set(&conn->ctx, &conn->timeout_timer, SSTP_DISCONNECT_TIMEOUT_1); + conn->sstp_state = STATE_CALL_DISCONNECT_ACK_PENDING; + break; + case STATE_CALL_DISCONNECT_IN_PROGRESS_2: + sstp_timer_set(&conn->ctx, &conn->timeout_timer, SSTP_DISCONNECT_TIMEOUT_2); + conn->sstp_state = STATE_CALL_DISCONNECT_TIMEOUT_PENDING; + break; + default: + break; + } + + return 0; +} + +static int send_sstp_msg_call_disconnect_ack(struct sstp_conn_t *conn) +{ + struct { + struct sstp_ctrl_hdr hdr; + } __attribute__((packed)) *msg = mempool_alloc(data_pool); + + if (conf_verbose) + log_ppp_info2("send [sstp SSTP_MSG_CALL_DISCONNECT_ACK]\n"); + + if (!msg) { + log_error("sstp: no memory\n"); + return -1; + } + + INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_CALL_DISCONNECT_ACK, 0, sizeof(*msg)); + + return sstp_send(conn, msg, sizeof(*msg)); +} + +static int send_sstp_msg_echo_request(struct sstp_conn_t *conn) +{ + struct { + struct sstp_ctrl_hdr hdr; + } __attribute__((packed)) *msg = mempool_alloc(data_pool); + + if (conf_verbose) + log_ppp_info2("send [sstp SSTP_MSG_ECHO_REQUEST]\n"); + + if (!msg) { + log_error("sstp: no memory\n"); + return -1; + } + + INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_ECHO_REQUEST, 0, sizeof(*msg)); + + return sstp_send(conn, msg, sizeof(*msg)); +} + +static int send_sstp_msg_echo_response(struct sstp_conn_t *conn) +{ + struct { + struct sstp_ctrl_hdr hdr; + } __attribute__((packed)) *msg = mempool_alloc(data_pool); + + if (conf_verbose) + log_ppp_info2("send [sstp SSTP_MSG_ECHO_RESPONSE]\n"); + + if (!msg) { + log_error("sstp: no memory\n"); + return -1; + } + + INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_ECHO_RESPONSE, 0, sizeof(*msg)); + + return sstp_send(conn, msg, sizeof(*msg)); +} + +static int sstp_msg_call_connect_request(struct sstp_conn_t *conn) +{ + struct { + struct sstp_ctrl_hdr hdr; + struct sstp_attrib_encapsulated_protocol attr; + } __attribute__((packed)) *msg = (void *)conn->in_buf; + int master, slave; + + if (conf_verbose) + log_ppp_info2("recv [sstp SSTP_MSG_CALL_CONNECT_REQUEST]\n"); + + switch (conn->sstp_state) { + case STATE_CALL_ABORT_TIMEOUT_PENDING: + case STATE_CALL_ABORT_PENDING: + case STATE_CALL_DISCONNECT_ACK_PENDING: + case STATE_CALL_DISCONNECT_TIMEOUT_PENDING: + return 0; + case STATE_SERVER_CONNECT_REQUEST_PENDING: + break; + default: + conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_1; + if (send_sstp_msg_call_abort(conn)) + return -1; + return 0; + } + + if (ntohs(msg->hdr.length) < sizeof(*msg) || + ntohs(msg->hdr.num_attributes) < 1 || + msg->attr.hdr.attribute_id != SSTP_ATTRIB_ENCAPSULATED_PROTOCOL_ID || + ntohs(msg->attr.hdr.length) < sizeof(msg->attr)) { + conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_1; + if (send_sstp_msg_call_abort(conn)) + return -1; + return 0; + } + if (ntohs(msg->attr.protocol_id) != SSTP_ENCAPSULATED_PROTOCOL_PPP) { + if (send_sstp_msg_call_connect_nak(conn)) + return -1; + return 0; + } + + if (ppp_allocate_pty(&master, &slave, O_CLOEXEC | O_NONBLOCK) < 0) + return -1; + + conn->ppp_hnd.fd = master; + conn->ppp_hnd.read = ppp_read; + triton_md_register_handler(&conn->ctx, &conn->ppp_hnd); + triton_md_enable_handler(&conn->ppp_hnd, MD_MODE_READ); + + triton_event_fire(EV_CTRL_STARTED, &conn->ppp.ses); + + if (send_sstp_msg_call_connect_ack(conn)) + goto error; + conn->sstp_state = STATE_SERVER_CALL_CONNECTED_PENDING; + + conn->ppp.fd = slave; + if (establish_ppp(&conn->ppp)) { + conn->state = STATE_FIN; + goto error; + } + + __sync_sub_and_fetch(&stat_starting, 1); + __sync_add_and_fetch(&stat_active, 1); + conn->state = STATE_PPP; + + if (conn->timeout_timer.tpd) + triton_timer_del(&conn->timeout_timer); + + if (conn->hello_timer.tpd) + triton_timer_mod(&conn->hello_timer, 0); + else if (conn->hello_timer.period) + triton_timer_add(&conn->ctx, &conn->hello_timer, 0); + + return 0; + +error: + if (conn->ppp_hnd.tpd) + triton_md_unregister_handler(&conn->ppp_hnd, 0); + close(master); + close(slave); + return -1; +} + +static int sstp_msg_call_connected(struct sstp_conn_t *conn) +{ + if (conf_verbose) + log_ppp_info2("recv [sstp SSTP_MSG_CALL_CONNECTED]\n"); + + switch (conn->sstp_state) { + case STATE_CALL_ABORT_TIMEOUT_PENDING: + case STATE_CALL_ABORT_PENDING: + case STATE_CALL_DISCONNECT_ACK_PENDING: + case STATE_CALL_DISCONNECT_TIMEOUT_PENDING: + return 0; + case STATE_SERVER_CALL_CONNECTED_PENDING: + break; + default: + conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_1; + if (send_sstp_msg_call_abort(conn)) + return -1; + return 0; + } + + conn->sstp_state = STATE_SERVER_CALL_CONNECTED; + + if (conn->hello_timer.tpd) + triton_timer_mod(&conn->hello_timer, 0); + else if (conn->hello_timer.period) + triton_timer_add(&conn->ctx, &conn->hello_timer, 0); + + return 0; +} + +static int sstp_msg_call_abort(struct sstp_conn_t *conn) +{ + if (conf_verbose) + log_ppp_info2("recv [sstp SSTP_MSG_CALL_ABORT]\n"); + + switch (conn->sstp_state) { + case STATE_CALL_ABORT_PENDING: + sstp_timer_set(&conn->ctx, &conn->timeout_timer, SSTP_ABORT_TIMEOUT_2); + conn->sstp_state = STATE_CALL_ABORT_TIMEOUT_PENDING; + break; + case STATE_CALL_ABORT_TIMEOUT_PENDING: + case STATE_CALL_DISCONNECT_TIMEOUT_PENDING: + break; + default: + conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_2; + if (send_sstp_msg_call_abort(conn)) + return -1; + break; + } + + return 0; +} + +static int sstp_msg_call_disconnect(struct sstp_conn_t *conn) +{ + if (conf_verbose) + log_ppp_info2("recv [sstp SSTP_MSG_CALL_DISCONNECT]\n"); + + switch (conn->sstp_state) { + case STATE_CALL_ABORT_TIMEOUT_PENDING: + case STATE_CALL_ABORT_PENDING: + case STATE_CALL_DISCONNECT_TIMEOUT_PENDING: + break; + case STATE_CALL_DISCONNECT_ACK_PENDING: + sstp_timer_set(&conn->ctx, &conn->timeout_timer, 0); + /* fall through */ + default: + conn->sstp_state = STATE_CALL_DISCONNECT_IN_PROGRESS_2; + if (send_sstp_msg_call_disconnect_ack(conn)) + return -1; + break; + } + + return 0; +} + +static int sstp_msg_call_disconnect_ack(struct sstp_conn_t *conn) +{ + if (conf_verbose) + log_ppp_info2("recv [sstp SSTP_MSG_CALL_DISCONNECT_ACK]\n"); + + switch (conn->sstp_state) { + case STATE_CALL_DISCONNECT_ACK_PENDING: + sstp_disconnect(conn); + conn->sstp_state = STATE_SERVER_CALL_DISCONNECTED; + break; + case STATE_CALL_ABORT_PENDING: + case STATE_CALL_ABORT_TIMEOUT_PENDING: + case STATE_CALL_DISCONNECT_TIMEOUT_PENDING: + break; + default: + conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_1; + if (send_sstp_msg_call_abort(conn)) + return -1; + break; + } + + return 0; +} + +static int sstp_msg_echo_request(struct sstp_conn_t *conn) +{ + if (conf_verbose) + log_ppp_info2("recv [sstp SSTP_MSG_ECHO_REQUEST]\n"); + + switch (conn->sstp_state) { + case STATE_SERVER_CALL_CONNECTED: + conn->hello_sent = 0; + if (conn->hello_timer.tpd) + triton_timer_mod(&conn->hello_timer, 0); + if (send_sstp_msg_echo_response(conn)) + return -1; + break; + case STATE_CALL_ABORT_TIMEOUT_PENDING: + case STATE_CALL_ABORT_PENDING: + case STATE_CALL_DISCONNECT_ACK_PENDING: + case STATE_CALL_DISCONNECT_TIMEOUT_PENDING: + break; + default: + conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_1; + if (send_sstp_msg_call_abort(conn)) + return -1; + break; + } + + return 0; +} + +static int sstp_msg_echo_response(struct sstp_conn_t *conn) +{ + if (conf_verbose) + log_ppp_info2("recv [sstp SSTP_MSG_ECHO_RESPONSE]\n"); + + switch (conn->sstp_state) { + case STATE_SERVER_CALL_CONNECTED: + conn->hello_sent = 0; + if (conn->hello_timer.tpd) + triton_timer_mod(&conn->hello_timer, 0); + break; + case STATE_CALL_ABORT_TIMEOUT_PENDING: + case STATE_CALL_ABORT_PENDING: + case STATE_CALL_DISCONNECT_ACK_PENDING: + case STATE_CALL_DISCONNECT_TIMEOUT_PENDING: + break; + default: + conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_1; + if (send_sstp_msg_call_abort(conn)) + return -1; + break; + } + + return 0; +} + +static int sstp_data_packet(struct sstp_conn_t *conn) +{ + struct sstp_hdr *hdr = (struct sstp_hdr *)conn->in_buf; + int n, pos, size; + + switch (conn->sstp_state) { + case STATE_SERVER_CALL_CONNECTED_PENDING: + case STATE_SERVER_CALL_CONNECTED: + break; + default: + return 0; + } + + pos = 0; + size = ntohs(hdr->length) - sizeof(*hdr); + while (pos < size) { + n = write(conn->ppp_hnd.fd, hdr->data + pos, size - pos); + if (n < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN) + break; + else { + if (conf_verbose && errno != EPIPE) + log_ppp_info2("sstp: write ppp: %s\n", strerror(errno)); + return -1; + } + } + pos += n; + } + + return 0; +} + +static int sstp_packet(struct sstp_conn_t *conn) +{ + struct sstp_ctrl_hdr *hdr = (struct sstp_ctrl_hdr *)conn->in_buf; + + switch (hdr->reserved) { + case SSTP_DATA_PACKET: + return sstp_data_packet(conn); + case SSTP_CTRL_PACKET: + break; + default: + log_ppp_warn("recv [sstp Unknown packet type %02x]\n", hdr->reserved); + return -1; + } + + switch (ntohs(hdr->message_type)) { + case SSTP_MSG_CALL_CONNECT_REQUEST: + return sstp_msg_call_connect_request(conn); + case SSTP_MSG_CALL_CONNECT_ACK: + case SSTP_MSG_CALL_CONNECT_NAK: + break; + case SSTP_MSG_CALL_CONNECTED: + return sstp_msg_call_connected(conn); + case SSTP_MSG_CALL_ABORT: + return sstp_msg_call_abort(conn); + case SSTP_MSG_CALL_DISCONNECT: + return sstp_msg_call_disconnect(conn); + case SSTP_MSG_CALL_DISCONNECT_ACK: + return sstp_msg_call_disconnect_ack(conn); + case SSTP_MSG_ECHO_REQUEST: + return sstp_msg_echo_request(conn); + case SSTP_MSG_ECHO_RESPONSE: + return sstp_msg_echo_response(conn); + default: + log_ppp_warn("recv [sstp Unknown message type %04x]\n", ntohs(hdr->message_type)); + } + + return 0; +} + +static int sstp_read(struct triton_md_handler_t *h) +{ + struct sstp_conn_t *conn = container_of(h, typeof(*conn), hnd); + struct sstp_hdr *hdr = (void *)conn->in_buf; + int n, size; +#ifdef CRYPTO_OPENSSL + int err, ssl_err; +#endif + + while (1) { +#ifdef CRYPTO_OPENSSL + if (conn->ssl) { + ERR_clear_error(); + n = SSL_read(conn->ssl, conn->in_buf + conn->in_size, SSTP_MAX_PACKET_SIZE - conn->in_size); +//err = errno; +//log_ppp_info2("sstp: sstp.read = %d/%d errno %d %s\n", n, SSTP_MAX_PACKET_SIZE - conn->in_size, (n < 0) ? errno : 0, (n < 0) ? strerror(errno) : ""); +//errno = err; + if (n < 0) { + err = errno; + ssl_err = SSL_get_error(conn->ssl, n); + switch (ssl_err) { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + return 0; + case SSL_ERROR_ZERO_RETURN: + n = 0; + break; + case SSL_ERROR_SYSCALL: + if (err == EINTR) + continue; + if (err == EAGAIN) + return 0; + log_ppp_error("sstp: SSL read: %s\n", strerror(err)); + goto drop; + default: + log_ppp_error("sstp: SSL read: %s\n", ERR_error_string(ssl_err, NULL)); + goto drop; + } + } + } else +#endif + { + n = read(h->fd, conn->in_buf + conn->in_size, SSTP_MAX_PACKET_SIZE - conn->in_size); +//err = errno; +//log_ppp_info2("sstp: sstp.read = %d/%d errno %d %s\n", n, SSTP_MAX_PACKET_SIZE - conn->in_size, (n < 0) ? errno : 0, (n < 0) ? strerror(errno) : ""); +//errno = err; + if (n < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN) + return 0; + log_ppp_error("sstp: read: %s\n", strerror(errno)); + goto drop; + } + } + + if (n == 0) { + if (conf_verbose) + log_ppp_info2("sstp: disconnect by peer\n"); + goto drop; + } + + conn->in_size += n; + + if (conn->sstp_state == STATE_SERVER_CALL_DISCONNECTED) { + size = http_request(conn); + if (size < 0) + goto drop; + conn->in_size -= size; + if (conn->in_size) + memmove(conn->in_buf, conn->in_buf + size, conn->in_size); + } + + if (conn->in_size >= sizeof(*hdr)) { + if (hdr->version != SSTP_VERSION) { + log_ppp_error("sstp: invalid version %d\n", hdr->version); + goto drop; + } + size = ntohs(hdr->length); + if (size > SSTP_MAX_PACKET_SIZE) { + log_ppp_error("sstp: message is too long\n"); + goto drop; + } + if (size <= conn->in_size) { + if (sstp_packet(conn)) + goto drop; + conn->in_size -= size; + if (conn->in_size) + memmove(conn->in_buf, conn->in_buf + size, conn->in_size); + } + } + } +drop: + sstp_disconnect(conn); + return 1; +} + +static int sstp_write(struct triton_md_handler_t *h) +{ + struct sstp_conn_t *conn = container_of(h, typeof(*conn), hnd); + struct sstp_pack_t *pack; + int n; +#ifdef CRYPTO_OPENSSL + int err, ssl_err; +#endif + + while (!list_empty(&conn->send_queue)) { + pack = list_first_entry(&conn->send_queue, typeof(*pack), entry); + again: +#ifdef CRYPTO_OPENSSL + if (conn->ssl) { + ERR_clear_error(); + n = SSL_write(conn->ssl, pack->data, pack->size); +//err = errno; +//log_ppp_info2("sstp: sstp.write = %d/%d errno %d %s\n", n, pack->size, (n < 0) ? errno : 0, (n < 0) ? strerror(errno) : ""); +//errno = err; + if (n < 0) { + err = errno; + ssl_err = SSL_get_error(conn->ssl, n); + switch (ssl_err) { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_ZERO_RETURN: + n = 0; + break; + case SSL_ERROR_SYSCALL: + if (err == EINTR) + goto again; + if (err == EAGAIN) + n = 0; + else { + if (conf_verbose && err != EPIPE) + log_ppp_info2("sstp: write: %s\n", strerror(errno)); + goto drop; + } + break; + default: + log_ppp_error("sstp: SSL write: %s\n", ERR_error_string(ssl_err, NULL)); + goto drop; + } + } + } else +#endif + { + n = write(h->fd, pack->data, pack->size); +//err = errno; +//log_ppp_info2("sstp: sstp.write = %d/%d errno %d %s\n", n, pack->size, (n < 0) ? errno : 0, (n < 0) ? strerror(errno) : ""); +//errno = err; + if (n < 0) { + if (errno == EINTR) + goto again; + if (errno == EAGAIN) + n = 0; + else { + if (conf_verbose && errno != EPIPE) + log_ppp_info2("sstp: write: %s\n", strerror(errno)); + goto drop; + } + } + } + + if (n == 0) + break; + + list_del(&pack->entry); + mempool_free(pack->data); + mempool_free(pack); + } + + if (list_empty(&conn->send_queue)) + triton_md_disable_handler(h, MD_MODE_WRITE); + + return 0; + +drop: + sstp_disconnect(conn); + return 1; +} + +static int sstp_send(struct sstp_conn_t *conn, void *data, int size) +{ + struct sstp_pack_t *pack; + int queue_empty = list_empty(&conn->send_queue); + + pack = mempool_alloc(pack_pool); + if (!pack) { + log_debug("sstp: packet: allocation fail\n"); + return -1; + } + + memset(pack, 0, sizeof(*pack)); + pack->data = data; + pack->size = size; + list_add_tail(&pack->entry, &conn->send_queue); + + if (queue_empty) + return sstp_write(&conn->hnd); + + triton_md_enable_handler(&conn->hnd, MD_MODE_WRITE); + + return 0; +} + +static void sstp_msg_echo(struct triton_timer_t *t) +{ + struct sstp_conn_t *conn = container_of(t, typeof(*conn), hello_timer); + + switch (conn->sstp_state) { + case STATE_SERVER_CALL_CONNECTED: + if (conn->hello_sent++) { + log_ppp_warn("sstp: no echo reply\n"); + conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_1; + send_sstp_msg_call_abort(conn); + } else + send_sstp_msg_echo_request(conn); + break; + } +} + +static void sstp_timeout(struct triton_timer_t *t) +{ + struct sstp_conn_t *conn = container_of(t, typeof(*conn), timeout_timer); + + switch (conn->sstp_state) { + case STATE_CALL_ABORT_TIMEOUT_PENDING: + case STATE_CALL_ABORT_PENDING: + case STATE_CALL_DISCONNECT_TIMEOUT_PENDING: + case STATE_CALL_DISCONNECT_ACK_PENDING: + sstp_disconnect(conn); + break; + default: + conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_1; + send_sstp_msg_call_abort(conn); + break; + } +} + +static void sstp_close(struct triton_context_t *ctx) +{ + struct sstp_conn_t *conn = container_of(ctx, typeof(*conn), ctx); + + if (conn->state == STATE_PPP) { + __sync_sub_and_fetch(&stat_active, 1); + conn->state = STATE_CLOSE; + ap_session_terminate(&conn->ppp.ses, TERM_ADMIN_RESET, 1); + conn->sstp_state = STATE_CALL_DISCONNECT_IN_PROGRESS_1; + send_sstp_msg_call_disconnect(conn); + } else { + conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_1; + send_sstp_msg_call_abort(conn); + } +} + +static void sstp_starting(struct sstp_conn_t *conn) +{ + log_ppp_debug("sstp: starting\n"); + +#ifdef CRYPTO_OPENSSL + if (conf_ssl) { + conn->ssl_ctx = SSL_CTX_new(SSLv23_server_method()); + if (!conn->ssl_ctx) { + log_error("sstp: SSL_CTX error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + goto error; + } + + SSL_CTX_set_options(conn->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION); + + if (conf_ssl_ciphers && + SSL_CTX_set_cipher_list(conn->ssl_ctx, conf_ssl_ciphers) != 1) { + log_error("sstp: SSL cipher list error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + goto error; + } + if (conf_ssl_ca_file && + SSL_CTX_load_verify_locations(conn->ssl_ctx, conf_ssl_ca_file, NULL) != 1) { + log_error("sstp: SSL ca file error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + return; + } + if (!conf_ssl_pemfile || + SSL_CTX_use_certificate_file(conn->ssl_ctx, conf_ssl_pemfile, SSL_FILETYPE_PEM) != 1 || + SSL_CTX_use_PrivateKey_file(conn->ssl_ctx, conf_ssl_pemfile, SSL_FILETYPE_PEM) != 1 || + SSL_CTX_check_private_key(conn->ssl_ctx) != 1) { + log_error("sstp: SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + goto error; + } + + SSL_CTX_set_default_read_ahead(conn->ssl_ctx, 1); + SSL_CTX_set_mode(conn->ssl_ctx, SSL_CTX_get_mode(conn->ssl_ctx) | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + + conn->ssl = SSL_new(conn->ssl_ctx); + if (!conn->ssl) { + log_error("sstp: SSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + goto error; + } + + SSL_set_accept_state(conn->ssl); + if (SSL_set_fd(conn->ssl, conn->hnd.fd) != 1) { + log_error("sstp: SSL bind error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + goto error; + } + } +#endif + + triton_md_enable_handler(&conn->hnd, MD_MODE_READ); + triton_timer_add(&conn->ctx, &conn->timeout_timer, 0); + + return; + +#ifdef CRYPTO_OPENSSL +error: + sstp_disconnect(conn); +#endif +} + +static int sstp_connect(struct triton_md_handler_t *h) +{ + struct sstp_conn_t *conn; + struct sockaddr_in addr; + socklen_t size = sizeof(addr); + int sock, value; + + while(1) { + sock = accept(h->fd, (struct sockaddr *)&addr, &size); + if (sock < 0) { + if (errno == EAGAIN) + return 0; + log_error("sstp: accept failed: %s\n", strerror(errno)); + continue; + } + + if (ap_shutdown) { + close(sock); + continue; + } + + if (triton_module_loaded("connlimit") && connlimit_check(cl_key_from_ipv4(addr.sin_addr.s_addr))) { + close(sock); + return 0; + } + + log_info2("sstp: new connection from %s\n", inet_ntoa(addr.sin_addr)); + + if (iprange_client_check(addr.sin_addr.s_addr)) { + log_warn("sstp: IP is out of client-ip-range, droping connection...\n"); + close(sock); + continue; + } + + if (fcntl(sock, F_SETFL, O_NONBLOCK)) { + log_error("sstp: failed to set nonblocking mode: %s, closing connection...\n", strerror(errno)); + close(sock); + continue; + } + + value = 1; + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &value, sizeof(value)) < 0) { + log_error("sstp: failed to disable nagle: %s, closing connection...\n", strerror(errno)); + close(sock); + continue; + } + + conn = mempool_alloc(conn_pool); + memset(conn, 0, sizeof(*conn)); + + conn->ctx.close = sstp_close; + conn->ctx.before_switch = sstp_ctx_switch; + conn->hnd.fd = sock; + conn->hnd.read = sstp_read; + conn->hnd.write = sstp_write; + + conn->timeout_timer.expire = sstp_timeout; + conn->timeout_timer.period = conf_timeout * 1000; + conn->hello_timer.expire = sstp_msg_echo; + conn->hello_timer.period = conf_hello_interval * 1000; + + //conn->bypass_auth = conf_bypass_auth; + //conn->http_cookie = NULL: + //conn->auth_key... + + conn->in_buf = _malloc(SSTP_MAX_PACKET_SIZE); + INIT_LIST_HEAD(&conn->send_queue); + + conn->ctrl.ctx = &conn->ctx; + conn->ctrl.started = ppp_started; + conn->ctrl.finished = ppp_finished; + conn->ctrl.terminate = ppp_terminate; + conn->ctrl.max_mtu = conf_ppp_max_mtu; + conn->ctrl.type = CTRL_TYPE_SSTP; + conn->ctrl.ppp = 1; + conn->ctrl.name = "sstp"; + conn->ctrl.ifname = ""; + conn->ctrl.mppe = MPPE_UNSET; + conn->ctrl.calling_station_id = _malloc(17); + conn->ctrl.called_station_id = _malloc(17); + u_inet_ntoa(addr.sin_addr.s_addr, conn->ctrl.calling_station_id); + getsockname(sock, &addr, &size); + u_inet_ntoa(addr.sin_addr.s_addr, conn->ctrl.called_station_id); + + ppp_init(&conn->ppp); + conn->ppp.ses.ctrl = &conn->ctrl; + conn->ppp.ses.chan_name = conn->ctrl.calling_station_id; + if (conf_ip_pool) + conn->ppp.ses.ipv4_pool_name = _strdup(conf_ip_pool); + + triton_context_register(&conn->ctx, &conn->ppp.ses); + triton_md_register_handler(&conn->ctx, &conn->hnd); + triton_context_wakeup(&conn->ctx); + + triton_context_call(&conn->ctx, (void (*)(void*))sstp_starting, conn); + + triton_event_fire(EV_CTRL_STARTING, &conn->ppp.ses); + + __sync_add_and_fetch(&stat_starting, 1); + } + return 0; +} + +static void sstp_serv_close(struct triton_context_t *ctx) +{ + struct sstp_serv_t *s = container_of(ctx, typeof(*s), ctx); + + triton_md_unregister_handler(&s->hnd, 1); + triton_context_unregister(ctx); +} + +static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt, void *client) +{ + cli_send(client, "sstp:\r\n"); + cli_sendv(client," starting: %u\r\n", stat_starting); + cli_sendv(client," active: %u\r\n", stat_active); + + return CLI_CMD_OK; +} + +void __export sstp_get_stat(unsigned int **starting, unsigned int **active) +{ + *starting = &stat_starting; + *active = &stat_active; +} + +static void load_config(void) +{ + char *opt; + + opt = conf_get_opt("sstp", "ssl"); + if (opt) + conf_ssl = atoi(opt); + + conf_ssl_ciphers = conf_get_opt("sstp", "ssl_ciphers"); + conf_ssl_ca_file = conf_get_opt("sstp", "ssl_ca_file"); + conf_ssl_pemfile = conf_get_opt("sstp", "ssl_pemfile"); + + opt = conf_get_opt("sstp", "timeout"); + if (opt && atoi(opt) > 0) + conf_timeout = atoi(opt); + + opt = conf_get_opt("sstp", "hello-interval"); + if (opt && atoi(opt) >= 0) + conf_hello_interval = atoi(opt); + + opt = conf_get_opt("sstp", "verbose"); + if (opt && atoi(opt) >= 0) + conf_verbose = atoi(opt) > 0; + + opt = conf_get_opt("sstp", "ppp-max-mtu"); + if (opt && atoi(opt) > 0) + conf_ppp_max_mtu = atoi(opt); + + conf_ip_pool = conf_get_opt("sstp", "ip-pool"); + + switch (iprange_check_activation()) { + case IPRANGE_DISABLED: + log_warn("sstp: iprange module disabled, improper IP configuration of PPP interfaces may cause kernel soft lockup\n"); + break; + case IPRANGE_NO_RANGE: + log_warn("sstp: no IP address range defined in section [%s], incoming sstp connections will be rejected\n", + IPRANGE_CONF_SECTION); + break; + default: + /* Makes compiler happy */ + break; + } + + //read(urandom_fd, &serv.certificate_hash, sizeof(serv.certificate_hash)); +} + +static struct sstp_serv_t serv = { + .hnd.read = sstp_connect, + .ctx.close = sstp_serv_close, + .ctx.before_switch = sstp_ctx_switch, +}; + +static void sstp_init(void) +{ + struct sockaddr_in addr; + char *opt; + +#ifdef CRYPTO_OPENSSL + SSL_load_error_strings(); + SSL_library_init(); +#endif + + serv.hnd.fd = socket(PF_INET, SOCK_STREAM, 0); + if (serv.hnd.fd < 0) { + log_emerg("sstp: failed to create server socket: %s\n", strerror(errno)); + return; + } + + fcntl(serv.hnd.fd, F_SETFD, fcntl(serv.hnd.fd, F_GETFD) | FD_CLOEXEC); + + addr.sin_family = AF_INET; + + opt = conf_get_opt("sstp", "bind"); + if (opt) + addr.sin_addr.s_addr = inet_addr(opt); + else + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + opt = conf_get_opt("sstp", "port"); + if (opt && atoi(opt) > 0) + addr.sin_port = htons(atoi(opt)); + else + addr.sin_port = htons(SSTP_PORT); + + setsockopt(serv.hnd.fd, SOL_SOCKET, SO_REUSEADDR, &serv.hnd.fd, 4); + + if (bind(serv.hnd.fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) { + log_emerg("sstp: failed to bind socket: %s\n", strerror(errno)); + close(serv.hnd.fd); + return; + } + + if (listen(serv.hnd.fd, 100) < 0) { + log_emerg("sstp: failed to listen socket: %s\n", strerror(errno)); + close(serv.hnd.fd); + return; + } + + if (fcntl(serv.hnd.fd, F_SETFL, O_NONBLOCK)) { + log_emerg("sstp: failed to set nonblocking mode: %s\n", strerror(errno)); + close(serv.hnd.fd); + return; + } + + conn_pool = mempool_create(sizeof(struct sstp_conn_t)); + pack_pool = mempool_create(sizeof(struct sstp_pack_t)); + data_pool = mempool_create(SSTP_MAX_PACKET_SIZE); + + load_config(); + + triton_context_register(&serv.ctx, NULL); + triton_md_register_handler(&serv.ctx, &serv.hnd); + triton_md_enable_handler(&serv.hnd, MD_MODE_READ); + triton_context_wakeup(&serv.ctx); + + cli_register_simple_cmd2(show_stat_exec, NULL, 2, "show", "stat"); + + triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config); +} + +DEFINE_INIT(20, sstp_init); -- cgit v1.2.3 From 3ecd0e3cc75b6ed011100dfd32cf6422889d7520 Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Thu, 2 Feb 2017 18:19:05 +0500 Subject: sstp: allow 3 nak replies per 3.3.5.2.2 --- accel-pppd/ctrl/sstp/sstp.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index b78ecc6..92a662e 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -57,6 +57,7 @@ struct sstp_conn_t { #endif int state; int sstp_state; + int nak_sent; int hello_sent; // int bypass_auth:1; @@ -647,6 +648,12 @@ static int sstp_msg_call_connect_request(struct sstp_conn_t *conn) return 0; } if (ntohs(msg->attr.protocol_id) != SSTP_ENCAPSULATED_PROTOCOL_PPP) { + if (conn->nak_sent++ == 3) { + log_ppp_warn("sstp: nak limit reached\n"); + conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_1; + if (send_sstp_msg_call_abort(conn)) + return -1; + } else if (send_sstp_msg_call_connect_nak(conn)) return -1; return 0; -- cgit v1.2.3 From 1e4af1c2d76f284574556ab50a0ec3360cc395c0 Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Mon, 30 Oct 2017 17:27:22 +0500 Subject: sstp: implement ifname option support --- accel-pppd/accel-ppp.conf | 1 + accel-pppd/ctrl/sstp/sstp.c | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf index 2a87f10..ee9f7f5 100644 --- a/accel-pppd/accel-ppp.conf +++ b/accel-pppd/accel-ppp.conf @@ -117,6 +117,7 @@ verbose=1 #timeout=60 #hello-interval=60 #ip-pool=sstp +#ifname=sstp%d [ipoe] verbose=1 diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index 92a662e..5200943 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -86,6 +86,7 @@ static int conf_ppp_max_mtu = SSTP_MAX_PACKET_SIZE - 8; static int conf_hash_protocol = CERT_HASH_PROTOCOL_SHA256; //static int conf_bypass_auth = 0; static const char *conf_ip_pool; +static const char *conf_ifname; static int conf_ssl = 1; static char *conf_ssl_ciphers = "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4"; static char *conf_ssl_ca_file = NULL; @@ -1330,6 +1331,8 @@ static int sstp_connect(struct triton_md_handler_t *h) conn->ppp.ses.chan_name = conn->ctrl.calling_station_id; if (conf_ip_pool) conn->ppp.ses.ipv4_pool_name = _strdup(conf_ip_pool); + if (conf_ifname) + conn->ppp.ses.ifname_rename = _strdup(conf_ifname); triton_context_register(&conn->ctx, &conn->ppp.ses); triton_md_register_handler(&conn->ctx, &conn->hnd); @@ -1396,6 +1399,7 @@ static void load_config(void) conf_ppp_max_mtu = atoi(opt); conf_ip_pool = conf_get_opt("sstp", "ip-pool"); + conf_ifname = conf_get_opt("sstp", "ifname"); switch (iprange_check_activation()) { case IPRANGE_DISABLED: -- cgit v1.2.3 From 1801847a36c5737b92ef25f96bb7e10135c0381a Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Mon, 27 Nov 2017 02:17:12 +0500 Subject: sstp: make sstp great again. simplify ssl handlers, fix crashes, move to async ppp TODO: accounting/statistics, minimize syscall & memory usage --- accel-pppd/ctrl/sstp/CMakeLists.txt | 2 + accel-pppd/ctrl/sstp/sstp.c | 1692 ++++++++++++++++++++++------------- accel-pppd/ctrl/sstp/sstp_prot.h | 5 - 3 files changed, 1052 insertions(+), 647 deletions(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/CMakeLists.txt b/accel-pppd/ctrl/sstp/CMakeLists.txt index 006a93b..3cb1799 100644 --- a/accel-pppd/ctrl/sstp/CMakeLists.txt +++ b/accel-pppd/ctrl/sstp/CMakeLists.txt @@ -2,4 +2,6 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) ADD_LIBRARY(sstp SHARED sstp.c) +TARGET_LINK_LIBRARIES(sstp util) + INSTALL(TARGETS sstp LIBRARY DESTINATION lib${LIB_SUFFIX}/accel-ppp) diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index 5200943..1796488 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -7,11 +7,13 @@ #include #include #include +#include #include #include #include #include #include +#include "linux_ppp.h" #ifdef CRYPTO_OPENSSL #include @@ -37,52 +39,111 @@ #define min(x,y) ((x) < (y) ? (x) : (y)) #endif -struct sstp_serv_t { - struct triton_context_t ctx; - struct triton_md_handler_t hnd; +#define log_sstp(log_func, conn, fmt, ...) \ + do { \ + log_func("sstp (%s): " fmt, \ + conn->ctrl.calling_station_id, \ + ##__VA_ARGS__); \ + } while (0) +#define log_sstp_error(conn, fmt, ...) log_sstp(log_error, conn, fmt, ####__VA_ARGS__) +#define log_sstp_warn(conn, fmt, ...) log_sstp(log_warn, conn, fmt, ####__VA_ARGS__) +#define log_sstp_info1(conn, fmt, ...) log_sstp(log_info1, conn, fmt, ####__VA_ARGS__) +#define log_sstp_info2(conn, fmt, ...) log_sstp(log_info2, conn, fmt, ####__VA_ARGS__) +#define log_sstp_debug(conn, fmt, ...) log_sstp(log_debug, conn, fmt, ####__VA_ARGS__) +#define log_sstp_msg(conn, fmt, ...) log_sstp(log_msg, conn, fmt, ####__VA_ARGS__) + +#define log_sstp_ppp(log_func, conn, fmt, ...) \ + do { \ + log_func("sstp (%s): " fmt, \ + conn->ctrl.ifname[0] ? conn->ctrl.ifname : \ + conn->ctrl.calling_station_id, \ + ##__VA_ARGS__); \ + } while (0) +#define log_sstp_ppp_error(conn, fmt, ...) log_sstp_ppp(log_ppp_error, conn, fmt, ####__VA_ARGS__) +#define log_sstp_ppp_warn(conn, fmt, ...) log_sstp_ppp(log_ppp_warn, conn, fmt, ####__VA_ARGS__) +#define log_sstp_ppp_info1(conn, fmt, ...) log_sstp_ppp(log_ppp_info1, conn, fmt, ####__VA_ARGS__) +#define log_sstp_ppp_info2(conn, fmt, ...) log_sstp_ppp(log_ppp_info2, conn, fmt, ####__VA_ARGS__) +#define log_sstp_ppp_debug(conn, fmt, ...) log_sstp_ppp(log_ppp_debug, conn, fmt, ####__VA_ARGS__) +#define log_sstp_ppp_msg(conn, fmt, ...) log_sstp_ppp(log_ppp_msg, conn, fmt, ####__VA_ARGS__) + +#define PPP_SYNC 0 /* buggy yet */ +#define PPP_BUF_SIZE 8192 +#define PPP_F_ESCAPE 1 +#define PPP_F_TOSS 2 + +enum { + STATE_INIT = 0, + STATE_STARTING, + STATE_STARTED, + STATE_FINISHED, +}; + +struct buffer_t { + struct list_head entry; + size_t len; + unsigned char *head; + unsigned char *tail; + unsigned char *end; + unsigned char data[0]; +}; - //uint8_t certificate_hash[32]; +struct sstp_stream_t { + union { + int fd; +#ifdef CRYPTO_OPENSSL + SSL *ssl; +#endif + }; + ssize_t (*read)(struct sstp_stream_t *stream, void *buf, size_t count); + ssize_t (*write)(struct sstp_stream_t *stream, const void *buf, size_t count); + int (*close)(struct sstp_stream_t *stream); + void (*free)(struct sstp_stream_t *stream); }; struct sstp_conn_t { struct triton_context_t ctx; - struct triton_md_handler_t hnd; - struct triton_md_handler_t ppp_hnd; + struct triton_md_handler_t hnd, ppp_hnd; + struct triton_timer_t timeout_timer; struct triton_timer_t hello_timer; -#ifdef CRYPTO_OPENSSL - SSL_CTX *ssl_ctx; - SSL *ssl; -#endif - int state; + struct sstp_stream_t *stream; + int (*handler)(struct sstp_conn_t *conn, struct buffer_t *buf); + int sstp_state; int nak_sent; int hello_sent; - + int hello_interval; // int bypass_auth:1; // char *http_cookie; // uint8_t auth_key[32]; + struct buffer_t *in; + struct list_head out_queue; - struct list_head send_queue; - void *ppp_buf; - uint8_t *in_buf; - int in_size; + int ppp_state; + int ppp_flags; + struct buffer_t *ppp_in; + struct list_head ppp_queue; - struct ap_ctrl ctrl; struct ppp_t ppp; -}; + struct ap_ctrl ctrl; -struct sstp_pack_t { - struct list_head entry; - void *data; - int size; +#ifdef CRYPTO_OPENSSL + SSL_CTX *ssl_ctx; +#endif }; +static struct sstp_serv_t { + struct triton_context_t ctx; + struct triton_md_handler_t hnd; + + uint8_t certificate_hash[32]; +} serv; + static int conf_timeout = SSTP_NEGOTIOATION_TIMEOUT; static int conf_hello_interval = SSTP_HELLO_TIMEOUT; static int conf_verbose = 0; -static int conf_ppp_max_mtu = SSTP_MAX_PACKET_SIZE - 8; +static int conf_ppp_max_mtu = 1456; static int conf_hash_protocol = CERT_HASH_PROTOCOL_SHA256; //static int conf_bypass_auth = 0; static const char *conf_ip_pool; @@ -93,15 +154,306 @@ static char *conf_ssl_ca_file = NULL; static char *conf_ssl_pemfile = NULL; static mempool_t conn_pool; -static mempool_t pack_pool; -static mempool_t data_pool; -static unsigned int stat_starting; -static unsigned int stat_active; +static int sstp_write(struct triton_md_handler_t *h); +static inline void sstp_queue(struct sstp_conn_t *conn, struct buffer_t *buf); +static int sstp_send(struct sstp_conn_t *conn, struct buffer_t *buf); +static int sstp_abort(struct sstp_conn_t *conn, int disconnect); +static void sstp_disconnect(struct sstp_conn_t *conn); +static int sstp_handler(struct sstp_conn_t *conn, struct buffer_t *buf); + +/* + * FCS lookup table as calculated by genfcstab. + */ +static const uint16_t fcstab[256] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +/* buffer */ + +static inline void *buf_put(struct buffer_t *buf, int len) +{ + void *tmp = buf->tail; + buf->tail += len; + buf->len += len; + return tmp; +} + +static inline void *buf_put_data(struct buffer_t *buf, const void *data, int len) +{ + void *tmp = buf_put(buf, len); + memcpy(tmp, data, len); + return tmp; +} + +static inline void *buf_push(struct buffer_t *buf, int len) +{ + buf->head -= len; + buf->len += len; + return buf->head; +} + +static inline void *buf_pull(struct buffer_t *buf, int len) +{ + buf->head += len; + buf->len -= len; + return buf->head; +} + +static inline int buf_headroom(const struct buffer_t *buf) +{ + return buf->head - buf->data; +} + +static inline int buf_tailroom(const struct buffer_t *buf) +{ + return buf->end - buf->tail; +} + +static inline void buf_reserve(struct buffer_t *buf, int len) +{ + buf->head += len; + buf->tail += len; +} + +static inline void buf_set_length(struct buffer_t *buf, int len) +{ + buf->tail = buf->head + len; + buf->len = len; +} + +static inline int buf_expand_tail(struct buffer_t *buf, int tailroom) +{ + if (buf->len == 0) + buf->head = buf->tail = buf->data; + else if (buf_tailroom(buf) < tailroom) { + buf->head = memmove(buf->data, buf->head, buf->len); + buf->tail = buf->head + buf->len; + } + return (buf_tailroom(buf) >= tailroom); +} + +static struct buffer_t *alloc_buf(size_t size) +{ + struct buffer_t *buf = _malloc(sizeof(*buf) + size); + + if (!buf) + return NULL; + + buf->head = buf->data; + buf->end = buf->data + size; + buf_set_length(buf, 0); + return buf; +} + +static void free_buf(struct buffer_t *buf) +{ + _free(buf); +} + +/* socket stream */ + +static ssize_t stream_read(struct sstp_stream_t *stream, void *buf, size_t count) +{ + return read(stream->fd, buf, count); +} + +static ssize_t stream_write(struct sstp_stream_t *stream, const void *buf, size_t count) +{ + return write(stream->fd, buf, count); +} + +static int stream_close(struct sstp_stream_t *stream) +{ + return close(stream->fd); +} + +static void stream_free(struct sstp_stream_t *stream) +{ + _free(stream); +} + +static struct sstp_stream_t *stream_init(int fd) +{ + struct sstp_stream_t *stream = _malloc(sizeof(*stream)); + + if (!stream) + return NULL; + + stream->fd = fd; + stream->read = stream_read; + stream->write = stream_write; + stream->close = stream_close; + stream->free = stream_free; + + return stream; +} + +/* ssl stream */ + +#ifdef CRYPTO_OPENSSL +#include + +static pthread_mutex_t *lock_cs; + +static unsigned long pthreads_thread_id(void) +{ + return (unsigned long)pthread_self(); +} -static int sstp_msg_call_abort(struct sstp_conn_t *conn); -static int sstp_msg_call_disconnect(struct sstp_conn_t *conn); -static int sstp_send(struct sstp_conn_t *conn, void *data, int size); +static void pthreads_locking_callback(int mode, int type, const char *file, int line) +{ + if (mode & CRYPTO_LOCK) + pthread_mutex_lock(&lock_cs[type]); + else + pthread_mutex_unlock(&lock_cs[type]); +} + +static void CRYPTO_thread_setup(void) +{ + int i; + + lock_cs = _malloc(CRYPTO_num_locks() * sizeof(*lock_cs)); + if (!lock_cs) + return; + + for (i = 0; i < CRYPTO_num_locks(); i++) + pthread_mutex_init(&lock_cs[i], NULL); + + CRYPTO_set_id_callback(pthreads_thread_id); + CRYPTO_set_locking_callback(pthreads_locking_callback); +} + +static void CRYPTO_thread_cleanup(void) +{ + int i; + + if (!lock_cs) + return; + + CRYPTO_set_id_callback(NULL); + CRYPTO_set_locking_callback(NULL); + + for (i = 0; i < CRYPTO_num_locks(); i++) + pthread_mutex_destroy(&lock_cs[i]); + + _free(lock_cs); +} + +static ssize_t ssl_stream_read(struct sstp_stream_t *stream, void *buf, size_t count) +{ + int ret, err; + + ERR_clear_error(); + ret = SSL_read(stream->ssl, buf, count); + err = SSL_get_error(stream->ssl, ret); + switch (err) { + case SSL_ERROR_NONE: + case SSL_ERROR_ZERO_RETURN: + return ret; + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_READ: + errno = EAGAIN; + /* fall through */ + case SSL_ERROR_SYSCALL: + default: + return -1; + } +} + +static ssize_t ssl_stream_write(struct sstp_stream_t *stream, const void *buf, size_t count) +{ + int ret, err; + + ERR_clear_error(); + ret = SSL_write(stream->ssl, buf, count); + err = SSL_get_error(stream->ssl, ret); + switch (err) { + case SSL_ERROR_NONE: + case SSL_ERROR_ZERO_RETURN: + return ret; + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_READ: + errno = EAGAIN; + /* fall through */ + case SSL_ERROR_SYSCALL: + default: + return -1; + } +} + +static int ssl_stream_close(struct sstp_stream_t *stream) +{ + SSL_shutdown(stream->ssl); + return close(SSL_get_fd(stream->ssl)); +} + +static void ssl_stream_free(struct sstp_stream_t *stream) +{ + if (stream && stream->ssl) + SSL_free(stream->ssl); + _free(stream); +} + +static struct sstp_stream_t *ssl_stream_init(int fd, SSL_CTX *ssl_ctx) +{ + struct sstp_stream_t *stream = _malloc(sizeof(*stream)); + + if (!stream) + return NULL; + + stream->ssl = SSL_new(ssl_ctx); + if (!stream->ssl) + goto error; + + SSL_set_verify(stream->ssl, SSL_VERIFY_NONE, NULL); + SSL_set_mode(stream->ssl, SSL_MODE_AUTO_RETRY); + SSL_set_accept_state(stream->ssl); + SSL_set_fd(stream->ssl, fd); + + stream->read = ssl_stream_read; + stream->write = ssl_stream_write; + stream->close = ssl_stream_close; + stream->free = ssl_stream_free; + + return stream; + +error: + ssl_stream_free(stream); + return NULL; +} +#endif /* http */ @@ -109,11 +461,11 @@ static char *http_getline(struct sstp_conn_t *conn, int *pos, char *buf, int siz { unsigned char *src, *dst, c, pc; - size = min(size - 1, conn->in_size - *pos); + size = min(size - 1, conn->in->len - *pos); if (size <= 0) return NULL; - src = conn->in_buf + *pos; + src = conn->in->head + *pos; dst = (unsigned char *)buf; for (pc = 0; size--; dst++) { c = *dst = *src++; @@ -128,36 +480,40 @@ static char *http_getline(struct sstp_conn_t *conn, int *pos, char *buf, int siz } *dst = '\0'; - *pos = src - conn->in_buf; + *pos = src - conn->in->head; return buf; } -static int send_http_response(struct sstp_conn_t *conn, char *proto, char *status, char *headers) +static int http_send_response(struct sstp_conn_t *conn, char *proto, char *status, char *headers) { - char timebuf[80], *msg = mempool_alloc(data_pool); + char datetime[sizeof("aaa, dd bbb yyyy HH:MM:SS GMT")], msg[1024]; + struct buffer_t *buf; time_t now = time(NULL); + int n; - if (!msg) { - log_error("sstp: no memory\n"); - return -1; - } - - strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now)); - snprintf(msg, SSTP_MAX_PACKET_SIZE, + strftime(datetime, sizeof(datetime), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now)); + n = snprintf(msg, sizeof(msg), "%s %s\r\n" - "%s" - "Server: Microsoft-HTTPAPI/2.0\r\n" + /* "Server: %s\r\n" */ "Date: %s\r\n" - "\r\n", proto, status, headers, timebuf); + "%s" + "\r\n", proto, status, /* "accel-ppp",*/ datetime, headers ? : ""); if (conf_verbose) - log_ppp_debug("send [sstp HTTP reply <%s %s>]\n", proto, status); + log_sstp_info2(conn, "send [HTTP <%s %s>]\n", proto, status); - return sstp_send(conn, msg, strlen(msg)); + buf = alloc_buf(n); + if (!buf) { + log_sstp_error(conn, "no memory\n"); + return -1; + } + buf_put_data(buf, msg, n); + + return sstp_send(conn, buf); } -static int http_request(struct sstp_conn_t *conn) +static int http_recv_request(struct sstp_conn_t *conn) { char buf[1024]; char *line, *method, *request, *proto; @@ -167,29 +523,29 @@ static int http_request(struct sstp_conn_t *conn) return -1; line = http_getline(conn, &pos, buf, sizeof(buf)); - if (line == NULL) + if (!line) goto error; if (conf_verbose) - log_ppp_debug("recv [sstp HTTP request <%s>]\n", line); + log_sstp_info2(conn, "recv [HTTP <%s>]\n", line); method = strsep(&line, " "); request = strsep(&line, " "); proto = strsep(&line, " "); if (!method || !request || !proto) { - send_http_response(conn, "HTTP/1.1", "400 Bad Request", NULL); + http_send_response(conn, "HTTP/1.1", "400 Bad Request", NULL); goto error; } if (strncmp(proto, "HTTP/1", sizeof("HTTP/1") - 1) != 0) { - send_http_response(conn, "HTTP/1.1", "505 HTTP Version Not Supported", NULL); + http_send_response(conn, "HTTP/1.1", "505 HTTP Version Not Supported", NULL); goto error; } if (strcmp(method, SSTP_HTTP_METHOD) != 0) { - send_http_response(conn, proto, "405 Method Not Allowed", NULL); + http_send_response(conn, proto, "405 Method Not Allowed", NULL); goto error; } if (strcmp(request, SSTP_HTTP_URI) != 0) { - send_http_response(conn, proto, "404 Not Found", NULL); + http_send_response(conn, proto, "404 Not Found", NULL); goto error; } @@ -197,13 +553,14 @@ static int http_request(struct sstp_conn_t *conn) if (*line == '\0') break; if (conf_verbose) - log_ppp_debug("recv [sstp HTTP request <%s>]\n", line); + log_sstp_info2(conn, "recv [HTTP <%s>]\n", line); } while (*line); - if (send_http_response(conn, proto, "200 OK", + if (http_send_response(conn, proto, "200 OK", "Content-Length: 18446744073709551615\r\n")) { goto error; } + conn->sstp_state = STATE_SERVER_CONNECT_REQUEST_PENDING; return pos; @@ -212,55 +569,70 @@ error: return -1; } +static int http_handler(struct sstp_conn_t *conn, struct buffer_t *buf) +{ + int n; + + n = http_recv_request(conn); + if (n < 0) + return -1; + buf_pull(buf, n); + + if (conn->sstp_state == STATE_SERVER_CONNECT_REQUEST_PENDING) + conn->handler = sstp_handler; + + return n; +} + /* ppp */ static int ppp_allocate_pty(int *master, int *slave, int flags) { struct termios tios; - char pty_name[16]; - int value, mfd, sfd = -1; + int value, mfd, sfd; - mfd = open("/dev/ptmx", O_RDWR | flags); - if (mfd < 0) { - log_ppp_error("sstp: can't open pty %s: %s\n", "/dev/ptmx", strerror(errno)); + if (openpty(&mfd, &sfd, NULL, &tios, NULL) < 0) { + log_ppp_error("sstp: allocate pty: %s\n", strerror(errno)); return -1; } - if (ioctl(mfd, TIOCGPTN, &value) < 0) { - log_ppp_error("sstp: can't allocate slave pty: %s\n", strerror(errno)); - goto error; + if (flags & O_CLOEXEC) { + fcntl(mfd, F_SETFD, fcntl(mfd, F_GETFD) | FD_CLOEXEC); + fcntl(sfd, F_SETFD, fcntl(sfd, F_GETFD) | FD_CLOEXEC); + flags &= ~O_CLOEXEC; } - snprintf(pty_name, sizeof(pty_name), "/dev/pts/%d", value); - - value = 0; - if (ioctl(mfd, TIOCSPTLCK, &value) < 0) - log_ppp_warn("sstp: can't unlock pty %s: %s\n", pty_name, strerror(errno)); - sfd = open(pty_name, O_RDWR | O_NOCTTY | flags); - if (sfd < 0) { - log_ppp_error("sstp: can't open pty %s: %s\n", pty_name, strerror(errno)); + tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB); + tios.c_cflag |= CS8 | CREAD | CLOCAL; + tios.c_iflag = IGNBRK | IGNPAR; + tios.c_oflag = 0; + tios.c_lflag = 0; + tios.c_cc[VMIN] = 1; + tios.c_cc[VTIME] = 0; + if (tcsetattr(sfd, TCSAFLUSH, &tios) < 0) { + log_ppp_warn("sstp: ppp: set pty attributes: %s\n", strerror(errno)); goto error; } - if (tcgetattr(sfd, &tios) == 0) { - tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB); - tios.c_cflag |= CS8 | CREAD | CLOCAL; - tios.c_iflag = IGNPAR; - tios.c_oflag = 0; - tios.c_lflag = 0; - if (tcsetattr(sfd, TCSAFLUSH, &tios) < 0) - log_ppp_warn("sstp: can't set attributes on pty: %s\n", strerror(errno)); - } - - value = N_HDLC; - if (ioctl(mfd, TIOCSETD, &value) < 0) { - log_ppp_error("sstp: can't set N_HDLC line discipline: %s", strerror(errno)); +#if PPP_SYNC + value = N_SYNC_PPP; +#else + value = N_PPP; +#endif + if (ioctl(sfd, TIOCSETD, &value) < 0) { + log_ppp_error("sstp: ppp: set pty line discipline: %s\n", strerror(errno)); goto error; } - value = N_SYNC_PPP; - if (ioctl(sfd, TIOCSETD, &value) < 0) { - log_ppp_error("sstp: can't set N_SYNC_PPP line discipline: %s", strerror(errno)); +// value = N_HDLC; +// if (ioctl(mfd, TIOCSETD, &value) < 0) { +// log_ppp_error("sstp: ppp: set pty line discipline: %s\n", strerror(errno)); +// goto error; +// } + + if ((value = fcntl(mfd, F_GETFL)) < 0 || fcntl(mfd, F_SETFL, value | flags) < 0 || + (value = fcntl(sfd, F_GETFL)) < 0 || fcntl(sfd, F_SETFL, value | flags) < 0) { + log_ppp_error("sstp: ppp: set pty status flags: %s\n", strerror(errno)); goto error; } @@ -269,16 +641,23 @@ static int ppp_allocate_pty(int *master, int *slave, int flags) return 0; error: - if (mfd >= 0) - close(mfd); - if (sfd >= 0) - close(sfd); + close(mfd); + close(sfd); return -1; } static void ppp_started(struct ap_session *ses) { - log_ppp_debug("sstp: ppp started\n"); + struct ppp_t *ppp = container_of(ses, typeof(*ppp), ses); + struct sstp_conn_t *conn = container_of(ppp, typeof(*conn), ppp); + + log_ppp_debug("sstp: ppp: started\n"); + + switch (conn->ppp_state) { + case STATE_STARTING: + conn->ppp_state = STATE_STARTED; + break; + } } static void ppp_finished(struct ap_session *ses) @@ -286,75 +665,176 @@ static void ppp_finished(struct ap_session *ses) struct ppp_t *ppp = container_of(ses, typeof(*ppp), ses); struct sstp_conn_t *conn = container_of(ppp, typeof(*conn), ppp); - if (conn->state != STATE_CLOSE) { - log_ppp_debug("sstp: ppp finished\n"); - __sync_sub_and_fetch(&stat_active, 1); - conn->state = STATE_CLOSE; - sstp_msg_call_abort(conn); + log_ppp_debug("sstp: ppp: finished\n"); + + switch (conn->ppp_state) { + case STATE_STARTING: + case STATE_STARTED: + conn->ppp_state = STATE_FINISHED; + sstp_abort(conn, 1); + break; } } static int ppp_read(struct triton_md_handler_t *h) { struct sstp_conn_t *conn = container_of(h, typeof(*conn), ppp_hnd); + struct buffer_t *buf; struct sstp_hdr *hdr; + uint8_t pppbuf[PPP_BUF_SIZE]; int n; +#if !PPP_SYNC + uint8_t *src, byte; + int i; - hdr = conn->ppp_buf ? : mempool_alloc(data_pool); - if (!hdr) { - log_error("sstp: no memory\n"); - return -1; - } + buf = conn->ppp_in; +#endif + while (1) { + n = read(h->fd, pppbuf, sizeof(pppbuf)); + if (n < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN) + break; + log_ppp_error("sstp: ppp: read: %s\n", strerror(errno)); + goto drop; + } else if (n == 0) { + if (conf_verbose) + log_ppp_info2("sstp: ppp: disconnect from tty\n"); + goto drop; + } -again: - n = read(h->fd, hdr->data, SSTP_MAX_PACKET_SIZE - sizeof(*hdr)); - -//int err = errno; -//log_ppp_info2("sstp: ppp.read = %d [%02x%02x...] errno %d %s\n", n, -// (n > 0) ? hdr->data[0] : 0, -// (n > 1) ? hdr->data[1] : 0, -// (n < 0) ? errno : 0, (n < 0) ? strerror(errno) : ""); -//errno = err; - - if (n < 0) { - if (errno == EINTR) - goto again; - if (errno == EAGAIN) { - conn->ppp_buf = hdr; - return 0; + switch (conn->sstp_state) { + case STATE_SERVER_CALL_CONNECTED_PENDING: + case STATE_SERVER_CALL_CONNECTED: + break; + default: + continue; } - if (errno != EPIPE && conf_verbose) - log_ppp_error("ppp error: %s\n", strerror(errno)); - goto drop; - } - if (n == 0) { - if (conf_verbose) - log_ppp_info2("ppp error\n"); - goto drop; - } - switch (conn->sstp_state) { - case STATE_SERVER_CALL_CONNECTED_PENDING: - case STATE_SERVER_CALL_CONNECTED: - break; - default: - goto drop; +#if PPP_SYNC + buf = alloc_buf(n + sizeof(*hdr)); + if (!buf) { + log_ppp_error("sstp: ppp: no memory\n"); + goto drop; + } + hdr = buf_put(buf, sizeof(*hdr)); + buf_put_data(buf, pppbuf, n); + INIT_SSTP_DATA_HDR(hdr, buf->len); + sstp_queue(conn, buf); +#else + src = pppbuf; + if (!buf) { + alloc: + conn->ppp_in = buf = alloc_buf(SSTP_MAX_PACKET_SIZE + PPP_FCSLEN); + if (!buf) { + log_ppp_error("sstp: ppp: no memory\n"); + goto drop; + } + buf_reserve(buf, sizeof(*hdr)); + } + + while (n > 0) { + if ((conn->ppp_flags & PPP_F_ESCAPE) && *src == PPP_ESCAPE) + i = 1; + else { + for (i = 0; i < n && + src[i] != PPP_ESCAPE && src[i] != PPP_FLAG; i++); + } + if (i > 0 && (conn->ppp_flags & PPP_F_TOSS) == 0) { + if (i <= buf_tailroom(buf)) { + char *p = buf_put_data(buf, src, i); + if (conn->ppp_flags & PPP_F_ESCAPE) { + *p ^= PPP_TRANS; + conn->ppp_flags &= ~PPP_F_ESCAPE; + } + } else + conn->ppp_flags |= PPP_F_TOSS; + } + + byte = src[i++]; + src += i; + n -= i; + + switch (byte) { + case PPP_FLAG: + if (buf->len <= PPP_FCSLEN || conn->ppp_flags) { + buf_set_length(buf, 0); + conn->ppp_flags = 0; + break; + } + buf_put(buf, -PPP_FCSLEN); + hdr = buf_push(buf, sizeof(*hdr)); + INIT_SSTP_DATA_HDR(hdr, buf->len); + sstp_queue(conn, buf); + goto alloc; + case PPP_ESCAPE: + conn->ppp_flags |= PPP_F_ESCAPE; + break; + } + } +#endif } + return sstp_write(&conn->hnd); + +drop: + sstp_disconnect(conn); + return 1; +} + +static int ppp_write(struct triton_md_handler_t *h) +{ + struct sstp_conn_t *conn = container_of(h, typeof(*conn), ppp_hnd); + struct buffer_t *buf; + int n; - n += sizeof(*hdr); - INIT_SSTP_DATA_HDR(hdr, n); + while (!list_empty(&conn->ppp_queue)) { + buf = list_first_entry(&conn->ppp_queue, typeof(*buf), entry); - if (sstp_send(conn, hdr, n)) - goto drop; + if (buf_headroom(buf) > 0) + triton_md_disable_handler(h, MD_MODE_WRITE); - conn->ppp_buf = NULL; + while (buf->len) { + n = write(conn->ppp_hnd.fd, buf->head, buf->len); + if (n < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN) + break; + if (conf_verbose && errno != EPIPE) + log_ppp_info2("sstp: ppp: write: %s\n", strerror(errno)); + goto drop; + } else if (n == 0) + break; + buf_pull(buf, n); + } + + if (buf->len) { + triton_md_enable_handler(h, MD_MODE_WRITE); + break; + } + + list_del(&buf->entry); + free_buf(buf); + } return 0; drop: - conn->ppp_buf = hdr; + triton_context_call(&conn->ctx, (triton_event_func)sstp_disconnect, conn); return 1; } +static inline void ppp_queue(struct sstp_conn_t *conn, struct buffer_t *buf) +{ + list_add_tail(&buf->entry, &conn->ppp_queue); +} + +static int ppp_send(struct sstp_conn_t *conn, struct buffer_t *buf) +{ + ppp_queue(conn, buf); + return ppp_write(&conn->ppp_hnd) ? -1 : 0; +} + /* sstp */ static void sstp_ctx_switch(struct triton_context_t *ctx, void *arg) @@ -367,262 +847,182 @@ static void sstp_ctx_switch(struct triton_context_t *ctx, void *arg) log_switch(ctx, arg); } -static void sstp_timer_set(struct triton_context_t *ctx, struct triton_timer_t *t, int timeout) -{ - t->period = timeout * 1000; - - if (timeout == 0) - triton_timer_del(t); - else if (t->tpd) - triton_timer_mod(t, 0); - else - triton_timer_add(ctx, t, 0); -} - -static void sstp_disconnect(struct sstp_conn_t *conn) -{ - struct sstp_pack_t *pack; - - log_ppp_debug("sstp: disconnect\n"); - -#ifdef CRYPTO_OPENSSL - if (conn->ssl) - SSL_free(conn->ssl); -#endif - triton_md_unregister_handler(&conn->hnd, 1); - - if (conn->timeout_timer.tpd) - triton_timer_del(&conn->timeout_timer); - if (conn->hello_timer.tpd) - triton_timer_del(&conn->hello_timer); - - if (conn->state == STATE_PPP) { - __sync_sub_and_fetch(&stat_active, 1); - conn->state = STATE_CLOSE; - ap_session_terminate(&conn->ppp.ses, TERM_LOST_CARRIER, 1); - } else if (conn->state != STATE_CLOSE) - __sync_sub_and_fetch(&stat_starting, 1); - - if (conn->ppp_hnd.tpd) - triton_md_unregister_handler(&conn->ppp_hnd, 1); - - triton_event_fire(EV_CTRL_FINISHED, &conn->ppp.ses); - - log_ppp_info1("disconnected\n"); - -#ifdef CRYPTO_OPENSSL - if (conn->ssl_ctx) - SSL_CTX_free(conn->ssl_ctx); -#endif - triton_context_unregister(&conn->ctx); - - while (!list_empty(&conn->send_queue)) { - pack = list_first_entry(&conn->send_queue, typeof(*pack), entry); - list_del(&pack->entry); - mempool_free(pack->data); - mempool_free(pack); - } - - if (conn->ppp_buf) - mempool_free(conn->ppp_buf); - _free(conn->in_buf); - _free(conn->ctrl.calling_station_id); - _free(conn->ctrl.called_station_id); - mempool_free(conn); -} - -static int send_sstp_msg_call_connect_ack(struct sstp_conn_t *conn) +static int sstp_send_msg_call_connect_ack(struct sstp_conn_t *conn) { struct { struct sstp_ctrl_hdr hdr; struct sstp_attrib_crypto_binding_request attr; - } __attribute__((packed)) *msg = mempool_alloc(data_pool); + } __attribute__((packed)) *msg; + struct buffer_t *buf = alloc_buf(sizeof(*msg)); if (conf_verbose) - log_ppp_info2("send [sstp SSTP_MSG_CALL_CONNECT_ACK]\n"); + log_sstp_ppp_info2(conn, "send [SSTP_MSG_CALL_CONNECT_ACK]\n"); - if (!msg) { - log_error("sstp: no memory\n"); + if (!buf) { + log_sstp_error(conn, "no memory\n"); return -1; } + msg = buf_put(buf, sizeof(*msg)); INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_CALL_CONNECT_ACK, 1, sizeof(*msg)); INIT_SSTP_ATTR_HDR(&msg->attr.hdr, SSTP_ATTRIB_CRYPTO_BINDING_REQ, sizeof(msg->attr)); msg->attr.hash_protocol_bitmask = conf_hash_protocol; //read(urandom_fd, msg->attr.nonce, sizeof(msg->attr.nonce)); memset(msg->attr.nonce, 0, sizeof(msg->attr.nonce)); - return sstp_send(conn, msg, sizeof(*msg)); + return sstp_send(conn, buf); } -static int send_sstp_msg_call_connect_nak(struct sstp_conn_t *conn) +static int sstp_send_msg_call_connect_nak(struct sstp_conn_t *conn) { struct { struct sstp_ctrl_hdr hdr; struct sstp_attrib_status_info attr; uint16_t attr_value; - } __attribute__((packed)) *msg = mempool_alloc(data_pool); + } __attribute__((packed)) *msg; + struct buffer_t *buf = alloc_buf(sizeof(*msg)); if (conf_verbose) - log_ppp_info2("send [sstp SSTP_MSG_CALL_CONNECT_NAK]\n"); + log_sstp_ppp_info2(conn, "send [SSTP_MSG_CALL_CONNECT_NAK]\n"); - if (!msg) { - log_error("sstp: no memory\n"); + if (!buf) { + log_sstp_error(conn, "no memory\n"); return -1; } + msg = buf_put(buf, sizeof(*msg)); INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_CALL_CONNECT_NAK, 1, sizeof(*msg)); INIT_SSTP_ATTR_HDR(&msg->attr.hdr, SSTP_ATTRIB_STATUS_INFO, sizeof(msg->attr)); msg->attr.attrib_id = SSTP_ATTRIB_ENCAPSULATED_PROTOCOL_ID; msg->attr.status = htonl(ATTRIB_STATUS_VALUE_NOT_SUPPORTED); msg->attr_value = 0; - return sstp_send(conn, msg, sizeof(*msg)); + return sstp_send(conn, buf); } -static int send_sstp_msg_call_abort(struct sstp_conn_t *conn) +static int sstp_send_msg_call_abort(struct sstp_conn_t *conn) { struct { struct sstp_ctrl_hdr hdr; struct sstp_attrib_status_info attr; - } __attribute__((packed)) *msg = mempool_alloc(data_pool); + } __attribute__((packed)) *msg; + struct buffer_t *buf = alloc_buf(sizeof(*msg)); if (conf_verbose) - log_ppp_info2("send [sstp SSTP_MSG_CALL_ABORT]\n"); + log_sstp_ppp_info2(conn, "send [SSTP_MSG_CALL_ABORT]\n"); - if (!msg) { - log_error("sstp: no memory\n"); + if (!buf) { + log_sstp_error(conn, "no memory\n"); return -1; } + msg = buf_put(buf, sizeof(*msg)); INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_CALL_ABORT, 1, sizeof(*msg)); INIT_SSTP_ATTR_HDR(&msg->attr.hdr, SSTP_ATTRIB_STATUS_INFO, sizeof(msg->attr)); msg->attr.attrib_id = SSTP_ATTRIB_STATUS_INFO; msg->attr.status = htonl(ATTRIB_STATUS_INVALID_FRAME_RECEIVED); - if (sstp_send(conn, msg, sizeof(*msg))) - return -1; - - switch (conn->sstp_state) { - case STATE_CALL_ABORT_IN_PROGRESS_1: - sstp_timer_set(&conn->ctx, &conn->timeout_timer, SSTP_ABORT_TIMEOUT_1); - conn->sstp_state = STATE_CALL_ABORT_PENDING; - break; - case STATE_CALL_ABORT_IN_PROGRESS_2: - sstp_timer_set(&conn->ctx, &conn->timeout_timer, SSTP_ABORT_TIMEOUT_2); - conn->sstp_state = STATE_CALL_ABORT_TIMEOUT_PENDING; - break; - } - - return 0; + return sstp_send(conn, buf); } -static int send_sstp_msg_call_disconnect(struct sstp_conn_t *conn) +static int sstp_send_msg_call_disconnect(struct sstp_conn_t *conn) { struct { struct sstp_ctrl_hdr hdr; struct sstp_attrib_status_info attr; - } __attribute__((packed)) *msg = mempool_alloc(data_pool); + } __attribute__((packed)) *msg; + struct buffer_t *buf = alloc_buf(sizeof(*msg)); if (conf_verbose) - log_ppp_info2("send [sstp SSTP_MSG_CALL_DISCONNECT]\n"); + log_sstp_ppp_info2(conn, "send [SSTP_MSG_CALL_DISCONNECT]\n"); - if (!msg) { - log_error("sstp: no memory\n"); + if (!buf) { + log_sstp_error(conn, "no memory\n"); return -1; } + msg = buf_put(buf, sizeof(*msg)); INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_CALL_DISCONNECT, 1, sizeof(*msg)); INIT_SSTP_ATTR_HDR(&msg->attr.hdr, SSTP_ATTRIB_STATUS_INFO, sizeof(msg->attr)); msg->attr.attrib_id = SSTP_ATTRIB_NO_ERROR; msg->attr.status = htonl(ATTRIB_STATUS_NO_ERROR); - if (sstp_send(conn, msg, sizeof(*msg))) - return -1; - - switch (conn->sstp_state) { - case STATE_CALL_DISCONNECT_IN_PROGRESS_1: - sstp_timer_set(&conn->ctx, &conn->timeout_timer, SSTP_DISCONNECT_TIMEOUT_1); - conn->sstp_state = STATE_CALL_DISCONNECT_ACK_PENDING; - break; - case STATE_CALL_DISCONNECT_IN_PROGRESS_2: - sstp_timer_set(&conn->ctx, &conn->timeout_timer, SSTP_DISCONNECT_TIMEOUT_2); - conn->sstp_state = STATE_CALL_DISCONNECT_TIMEOUT_PENDING; - break; - default: - break; - } - - return 0; + return sstp_send(conn, buf); } -static int send_sstp_msg_call_disconnect_ack(struct sstp_conn_t *conn) +static int sstp_send_msg_call_disconnect_ack(struct sstp_conn_t *conn) { struct { struct sstp_ctrl_hdr hdr; - } __attribute__((packed)) *msg = mempool_alloc(data_pool); + } __attribute__((packed)) *msg; + struct buffer_t *buf = alloc_buf(sizeof(*msg)); if (conf_verbose) - log_ppp_info2("send [sstp SSTP_MSG_CALL_DISCONNECT_ACK]\n"); + log_sstp_ppp_info2(conn, "send [SSTP_MSG_CALL_DISCONNECT_ACK]\n"); - if (!msg) { - log_error("sstp: no memory\n"); + if (!buf) { + log_sstp_error(conn, "no memory\n"); return -1; } + msg = buf_put(buf, sizeof(*msg)); INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_CALL_DISCONNECT_ACK, 0, sizeof(*msg)); - return sstp_send(conn, msg, sizeof(*msg)); + return sstp_send(conn, buf); } -static int send_sstp_msg_echo_request(struct sstp_conn_t *conn) +static int sstp_send_msg_echo_request(struct sstp_conn_t *conn) { struct { struct sstp_ctrl_hdr hdr; - } __attribute__((packed)) *msg = mempool_alloc(data_pool); + } __attribute__((packed)) *msg; + struct buffer_t *buf = alloc_buf(sizeof(*msg)); if (conf_verbose) - log_ppp_info2("send [sstp SSTP_MSG_ECHO_REQUEST]\n"); + log_sstp_ppp_info2(conn, "send [SSTP_MSG_ECHO_REQUEST]\n"); - if (!msg) { - log_error("sstp: no memory\n"); + if (!buf) { + log_sstp_error(conn, "no memory\n"); return -1; } + msg = buf_put(buf, sizeof(*msg)); INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_ECHO_REQUEST, 0, sizeof(*msg)); - return sstp_send(conn, msg, sizeof(*msg)); + return sstp_send(conn, buf); } -static int send_sstp_msg_echo_response(struct sstp_conn_t *conn) +static int sstp_send_msg_echo_response(struct sstp_conn_t *conn) { struct { struct sstp_ctrl_hdr hdr; - } __attribute__((packed)) *msg = mempool_alloc(data_pool); + } __attribute__((packed)) *msg; + struct buffer_t *buf = alloc_buf(sizeof(*msg)); if (conf_verbose) - log_ppp_info2("send [sstp SSTP_MSG_ECHO_RESPONSE]\n"); + log_sstp_ppp_info2(conn, "send [SSTP_MSG_ECHO_RESPONSE]\n"); - if (!msg) { - log_error("sstp: no memory\n"); + if (!buf) { + log_sstp_error(conn, "no memory\n"); return -1; } + msg = buf_put(buf, sizeof(*msg)); INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_ECHO_RESPONSE, 0, sizeof(*msg)); - return sstp_send(conn, msg, sizeof(*msg)); + return sstp_send(conn, buf); } -static int sstp_msg_call_connect_request(struct sstp_conn_t *conn) +static int sstp_recv_msg_call_connect_request(struct sstp_conn_t *conn, struct sstp_ctrl_hdr *hdr) { struct { struct sstp_ctrl_hdr hdr; struct sstp_attrib_encapsulated_protocol attr; - } __attribute__((packed)) *msg = (void *)conn->in_buf; + } __attribute__((packed)) *msg = (void *)hdr; int master, slave; if (conf_verbose) - log_ppp_info2("recv [sstp SSTP_MSG_CALL_CONNECT_REQUEST]\n"); + log_sstp_ppp_info2(conn, "recv [SSTP_MSG_CALL_CONNECT_REQUEST]\n"); switch (conn->sstp_state) { case STATE_CALL_ABORT_TIMEOUT_PENDING: @@ -633,31 +1033,21 @@ static int sstp_msg_call_connect_request(struct sstp_conn_t *conn) case STATE_SERVER_CONNECT_REQUEST_PENDING: break; default: - conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_1; - if (send_sstp_msg_call_abort(conn)) - return -1; - return 0; + return sstp_abort(conn, 0); } if (ntohs(msg->hdr.length) < sizeof(*msg) || ntohs(msg->hdr.num_attributes) < 1 || msg->attr.hdr.attribute_id != SSTP_ATTRIB_ENCAPSULATED_PROTOCOL_ID || ntohs(msg->attr.hdr.length) < sizeof(msg->attr)) { - conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_1; - if (send_sstp_msg_call_abort(conn)) - return -1; - return 0; + return sstp_abort(conn, 0); } if (ntohs(msg->attr.protocol_id) != SSTP_ENCAPSULATED_PROTOCOL_PPP) { if (conn->nak_sent++ == 3) { - log_ppp_warn("sstp: nak limit reached\n"); - conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_1; - if (send_sstp_msg_call_abort(conn)) - return -1; - } else - if (send_sstp_msg_call_connect_nak(conn)) - return -1; - return 0; + log_sstp_ppp_warn(conn, "nak limit reached\n"); + return sstp_abort(conn, 0); + } + return sstp_send_msg_call_connect_nak(conn); } if (ppp_allocate_pty(&master, &slave, O_CLOEXEC | O_NONBLOCK) < 0) @@ -665,47 +1055,41 @@ static int sstp_msg_call_connect_request(struct sstp_conn_t *conn) conn->ppp_hnd.fd = master; conn->ppp_hnd.read = ppp_read; + conn->ppp_hnd.write = ppp_write; + triton_md_register_handler(&conn->ctx, &conn->ppp_hnd); triton_md_enable_handler(&conn->ppp_hnd, MD_MODE_READ); - triton_event_fire(EV_CTRL_STARTED, &conn->ppp.ses); +// triton_event_fire(EV_CTRL_STARTED, &conn->ppp.ses); - if (send_sstp_msg_call_connect_ack(conn)) + if (sstp_send_msg_call_connect_ack(conn)) goto error; + conn->sstp_state = STATE_SERVER_CALL_CONNECTED_PENDING; + conn->ppp_state = STATE_STARTING; conn->ppp.fd = slave; if (establish_ppp(&conn->ppp)) { - conn->state = STATE_FIN; + conn->ppp_state = STATE_FINISHED; goto error; } - __sync_sub_and_fetch(&stat_starting, 1); - __sync_add_and_fetch(&stat_active, 1); - conn->state = STATE_PPP; - if (conn->timeout_timer.tpd) triton_timer_del(&conn->timeout_timer); - if (conn->hello_timer.tpd) - triton_timer_mod(&conn->hello_timer, 0); - else if (conn->hello_timer.period) - triton_timer_add(&conn->ctx, &conn->hello_timer, 0); - return 0; error: if (conn->ppp_hnd.tpd) - triton_md_unregister_handler(&conn->ppp_hnd, 0); - close(master); + triton_md_unregister_handler(&conn->ppp_hnd, 1); close(slave); return -1; } -static int sstp_msg_call_connected(struct sstp_conn_t *conn) +static int sstp_recv_msg_call_connected(struct sstp_conn_t *conn) { if (conf_verbose) - log_ppp_info2("recv [sstp SSTP_MSG_CALL_CONNECTED]\n"); + log_sstp_ppp_info2(conn, "recv [SSTP_MSG_CALL_CONNECTED]\n"); switch (conn->sstp_state) { case STATE_CALL_ABORT_TIMEOUT_PENDING: @@ -716,150 +1100,155 @@ static int sstp_msg_call_connected(struct sstp_conn_t *conn) case STATE_SERVER_CALL_CONNECTED_PENDING: break; default: - conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_1; - if (send_sstp_msg_call_abort(conn)) - return -1; + sstp_abort(conn, 0); return 0; } conn->sstp_state = STATE_SERVER_CALL_CONNECTED; - if (conn->hello_timer.tpd) - triton_timer_mod(&conn->hello_timer, 0); - else if (conn->hello_timer.period) + if (conn->hello_interval) { + conn->hello_timer.period = conn->hello_interval * 1000; triton_timer_add(&conn->ctx, &conn->hello_timer, 0); + } return 0; } -static int sstp_msg_call_abort(struct sstp_conn_t *conn) +static int sstp_recv_msg_call_abort(struct sstp_conn_t *conn) { + int ret = 0; + if (conf_verbose) - log_ppp_info2("recv [sstp SSTP_MSG_CALL_ABORT]\n"); + log_sstp_ppp_info2(conn, "recv [SSTP_MSG_CALL_ABORT]\n"); switch (conn->sstp_state) { case STATE_CALL_ABORT_PENDING: - sstp_timer_set(&conn->ctx, &conn->timeout_timer, SSTP_ABORT_TIMEOUT_2); - conn->sstp_state = STATE_CALL_ABORT_TIMEOUT_PENDING; break; case STATE_CALL_ABORT_TIMEOUT_PENDING: case STATE_CALL_DISCONNECT_TIMEOUT_PENDING: - break; + return 0; default: conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_2; - if (send_sstp_msg_call_abort(conn)) - return -1; + ret = sstp_send_msg_call_abort(conn); break; } - return 0; + conn->timeout_timer.period = SSTP_ABORT_TIMEOUT_2 * 1000; + if (conn->timeout_timer.tpd) + triton_timer_mod(&conn->timeout_timer, 0); + else + triton_timer_add(&conn->ctx, &conn->timeout_timer, 0); + + conn->sstp_state = STATE_CALL_ABORT_TIMEOUT_PENDING; + + return ret; } -static int sstp_msg_call_disconnect(struct sstp_conn_t *conn) +static int sstp_recv_msg_call_disconnect(struct sstp_conn_t *conn) { + int ret; + if (conf_verbose) - log_ppp_info2("recv [sstp SSTP_MSG_CALL_DISCONNECT]\n"); + log_sstp_ppp_info2(conn, "recv [SSTP_MSG_CALL_DISCONNECT]\n"); switch (conn->sstp_state) { case STATE_CALL_ABORT_TIMEOUT_PENDING: case STATE_CALL_ABORT_PENDING: case STATE_CALL_DISCONNECT_TIMEOUT_PENDING: - break; + return 0; case STATE_CALL_DISCONNECT_ACK_PENDING: - sstp_timer_set(&conn->ctx, &conn->timeout_timer, 0); - /* fall through */ - default: - conn->sstp_state = STATE_CALL_DISCONNECT_IN_PROGRESS_2; - if (send_sstp_msg_call_disconnect_ack(conn)) - return -1; + if (conn->timeout_timer.tpd) + triton_timer_del(&conn->timeout_timer); break; } - return 0; + conn->sstp_state = STATE_CALL_DISCONNECT_IN_PROGRESS_2; + + ret = sstp_send_msg_call_disconnect_ack(conn); + + conn->timeout_timer.period = SSTP_DISCONNECT_TIMEOUT_2 * 1000; + if (conn->timeout_timer.tpd) + triton_timer_mod(&conn->timeout_timer, 0); + else + triton_timer_add(&conn->ctx, &conn->timeout_timer, 0); + + conn->sstp_state = STATE_CALL_DISCONNECT_TIMEOUT_PENDING; + + return ret; } -static int sstp_msg_call_disconnect_ack(struct sstp_conn_t *conn) +static int sstp_recv_msg_call_disconnect_ack(struct sstp_conn_t *conn) { if (conf_verbose) - log_ppp_info2("recv [sstp SSTP_MSG_CALL_DISCONNECT_ACK]\n"); + log_sstp_ppp_info2(conn, "recv [SSTP_MSG_CALL_DISCONNECT_ACK]\n"); switch (conn->sstp_state) { case STATE_CALL_DISCONNECT_ACK_PENDING: - sstp_disconnect(conn); - conn->sstp_state = STATE_SERVER_CALL_DISCONNECTED; break; case STATE_CALL_ABORT_PENDING: case STATE_CALL_ABORT_TIMEOUT_PENDING: case STATE_CALL_DISCONNECT_TIMEOUT_PENDING: - break; + return 0; default: - conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_1; - if (send_sstp_msg_call_abort(conn)) - return -1; - break; + return sstp_abort(conn, 0); } + conn->sstp_state = STATE_SERVER_CALL_DISCONNECTED; + triton_context_call(&conn->ctx, (triton_event_func)sstp_disconnect, conn); + return 0; } -static int sstp_msg_echo_request(struct sstp_conn_t *conn) +static int sstp_recv_msg_echo_request(struct sstp_conn_t *conn) { if (conf_verbose) - log_ppp_info2("recv [sstp SSTP_MSG_ECHO_REQUEST]\n"); + log_sstp_ppp_info2(conn, "recv [SSTP_MSG_ECHO_REQUEST]\n"); switch (conn->sstp_state) { case STATE_SERVER_CALL_CONNECTED: - conn->hello_sent = 0; - if (conn->hello_timer.tpd) - triton_timer_mod(&conn->hello_timer, 0); - if (send_sstp_msg_echo_response(conn)) - return -1; break; case STATE_CALL_ABORT_TIMEOUT_PENDING: case STATE_CALL_ABORT_PENDING: case STATE_CALL_DISCONNECT_ACK_PENDING: case STATE_CALL_DISCONNECT_TIMEOUT_PENDING: - break; + return 0; default: - conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_1; - if (send_sstp_msg_call_abort(conn)) - return -1; - break; + return sstp_abort(conn, 0); } - return 0; + return sstp_send_msg_echo_response(conn); } -static int sstp_msg_echo_response(struct sstp_conn_t *conn) +static int sstp_recv_msg_echo_response(struct sstp_conn_t *conn) { if (conf_verbose) - log_ppp_info2("recv [sstp SSTP_MSG_ECHO_RESPONSE]\n"); + log_sstp_ppp_info2(conn, "recv [SSTP_MSG_ECHO_RESPONSE]\n"); switch (conn->sstp_state) { case STATE_SERVER_CALL_CONNECTED: - conn->hello_sent = 0; - if (conn->hello_timer.tpd) - triton_timer_mod(&conn->hello_timer, 0); break; case STATE_CALL_ABORT_TIMEOUT_PENDING: case STATE_CALL_ABORT_PENDING: case STATE_CALL_DISCONNECT_ACK_PENDING: case STATE_CALL_DISCONNECT_TIMEOUT_PENDING: - break; + return 0; default: - conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_1; - if (send_sstp_msg_call_abort(conn)) - return -1; - break; + return sstp_abort(conn, 0); } + conn->hello_sent = 0; return 0; } -static int sstp_data_packet(struct sstp_conn_t *conn) +static int sstp_recv_data_packet(struct sstp_conn_t *conn, struct sstp_hdr *hdr) { - struct sstp_hdr *hdr = (struct sstp_hdr *)conn->in_buf; - int n, pos, size; + struct buffer_t *buf; + int size; +#if !PPP_SYNC + uint8_t *src, *dst, byte; + uint16_t fcs; + int n; +#endif switch (conn->sstp_state) { case STATE_SERVER_CALL_CONNECTED_PENDING: @@ -869,62 +1258,119 @@ static int sstp_data_packet(struct sstp_conn_t *conn) return 0; } - pos = 0; size = ntohs(hdr->length) - sizeof(*hdr); - while (pos < size) { - n = write(conn->ppp_hnd.fd, hdr->data + pos, size - pos); - if (n < 0) { - if (errno == EINTR) - continue; - if (errno == EAGAIN) - break; - else { - if (conf_verbose && errno != EPIPE) - log_ppp_info2("sstp: write ppp: %s\n", strerror(errno)); - return -1; - } - } - pos += n; +#if PPP_SYNC + buf = alloc_buf(size); + if (!buf) { + log_sstp_error(conn, "no memory\n"); + return -1; } - return 0; + buf_put_data(buf, hdr->data, size); +#else + buf = alloc_buf(size*2 + 2 + PPP_FCSLEN); + if (!buf) { + log_sstp_error(conn, "no memory\n"); + return -1; + } + + src = hdr->data; + dst = buf->tail; + fcs = PPP_INITFCS; + + *dst++ = PPP_FLAG; + for (n = size + PPP_FCSLEN; n > 0; n--) { + if (n > PPP_FCSLEN) { + byte = *src++; + fcs = (fcs >> 8) ^ fcstab[(fcs ^ byte) & 0xff]; + } else if (n == PPP_FCSLEN) { + fcs ^= PPP_INITFCS; + byte = fcs & 0xff; + } else if (n == PPP_FCSLEN - 1) + byte = fcs >> 8; + if (byte < 0x20 || byte == PPP_FLAG || byte == PPP_ESCAPE) { + *dst++ = PPP_ESCAPE; + *dst++ = byte ^ PPP_TRANS; + } else + *dst++ = byte; + } + *dst++ = PPP_FLAG; + + buf_put(buf, dst - buf->tail); +#endif + + return ppp_send(conn, buf); } -static int sstp_packet(struct sstp_conn_t *conn) +static int sstp_recv_packet(struct sstp_conn_t *conn, struct sstp_hdr *hdr) { - struct sstp_ctrl_hdr *hdr = (struct sstp_ctrl_hdr *)conn->in_buf; + struct sstp_ctrl_hdr *msg = (struct sstp_ctrl_hdr *)hdr; switch (hdr->reserved) { case SSTP_DATA_PACKET: - return sstp_data_packet(conn); + return sstp_recv_data_packet(conn, hdr); case SSTP_CTRL_PACKET: - break; - default: - log_ppp_warn("recv [sstp Unknown packet type %02x]\n", hdr->reserved); + if (ntohs(hdr->length) >= sizeof(*msg)) + break; + log_sstp_ppp_error(conn, "recv [SSTP too short message]\n"); return -1; + default: + log_sstp_ppp_warn(conn, "recv [SSTP unknown packet type %02x]\n", hdr->reserved); + return 0; + } + + if (conn->hello_timer.tpd) { + conn->hello_timer.period = conn->hello_interval * 1000; + triton_timer_mod(&conn->hello_timer, 0); } - switch (ntohs(hdr->message_type)) { + switch (ntohs(msg->message_type)) { case SSTP_MSG_CALL_CONNECT_REQUEST: - return sstp_msg_call_connect_request(conn); + return sstp_recv_msg_call_connect_request(conn, msg); case SSTP_MSG_CALL_CONNECT_ACK: case SSTP_MSG_CALL_CONNECT_NAK: - break; + return sstp_abort(conn, 0); case SSTP_MSG_CALL_CONNECTED: - return sstp_msg_call_connected(conn); + return sstp_recv_msg_call_connected(conn); case SSTP_MSG_CALL_ABORT: - return sstp_msg_call_abort(conn); + return sstp_recv_msg_call_abort(conn); case SSTP_MSG_CALL_DISCONNECT: - return sstp_msg_call_disconnect(conn); + return sstp_recv_msg_call_disconnect(conn); case SSTP_MSG_CALL_DISCONNECT_ACK: - return sstp_msg_call_disconnect_ack(conn); + return sstp_recv_msg_call_disconnect_ack(conn); case SSTP_MSG_ECHO_REQUEST: - return sstp_msg_echo_request(conn); + return sstp_recv_msg_echo_request(conn); case SSTP_MSG_ECHO_RESPONSE: - return sstp_msg_echo_response(conn); + return sstp_recv_msg_echo_response(conn); default: - log_ppp_warn("recv [sstp Unknown message type %04x]\n", ntohs(hdr->message_type)); + log_sstp_ppp_warn(conn, "recv [SSTP unknown message type %04x]\n", ntohs(msg->message_type)); + return 0; } +} + +static int sstp_handler(struct sstp_conn_t *conn, struct buffer_t *buf) +{ + struct sstp_hdr *hdr; + int n; + + while (buf->len >= sizeof(*hdr)) { + hdr = (struct sstp_hdr *)buf->head; + if (hdr->version != SSTP_VERSION) { + log_sstp_ppp_error(conn, "recv [SSTP invalid version]\n"); + return -1; + } + + n = ntohs(hdr->length); + if (n > SSTP_MAX_PACKET_SIZE) { + log_sstp_ppp_error(conn, "recv [SSTP too long packet]\n"); + return -1; + } else if (n > buf->len) + break; + + if (sstp_recv_packet(conn, hdr) < 0) + return -1; + buf_pull(buf, n); + }; return 0; } @@ -932,95 +1378,33 @@ static int sstp_packet(struct sstp_conn_t *conn) static int sstp_read(struct triton_md_handler_t *h) { struct sstp_conn_t *conn = container_of(h, typeof(*conn), hnd); - struct sstp_hdr *hdr = (void *)conn->in_buf; - int n, size; -#ifdef CRYPTO_OPENSSL - int err, ssl_err; -#endif - - while (1) { -#ifdef CRYPTO_OPENSSL - if (conn->ssl) { - ERR_clear_error(); - n = SSL_read(conn->ssl, conn->in_buf + conn->in_size, SSTP_MAX_PACKET_SIZE - conn->in_size); -//err = errno; -//log_ppp_info2("sstp: sstp.read = %d/%d errno %d %s\n", n, SSTP_MAX_PACKET_SIZE - conn->in_size, (n < 0) ? errno : 0, (n < 0) ? strerror(errno) : ""); -//errno = err; - if (n < 0) { - err = errno; - ssl_err = SSL_get_error(conn->ssl, n); - switch (ssl_err) { - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - return 0; - case SSL_ERROR_ZERO_RETURN: - n = 0; - break; - case SSL_ERROR_SYSCALL: - if (err == EINTR) - continue; - if (err == EAGAIN) - return 0; - log_ppp_error("sstp: SSL read: %s\n", strerror(err)); - goto drop; - default: - log_ppp_error("sstp: SSL read: %s\n", ERR_error_string(ssl_err, NULL)); - goto drop; - } - } - } else -#endif - { - n = read(h->fd, conn->in_buf + conn->in_size, SSTP_MAX_PACKET_SIZE - conn->in_size); -//err = errno; -//log_ppp_info2("sstp: sstp.read = %d/%d errno %d %s\n", n, SSTP_MAX_PACKET_SIZE - conn->in_size, (n < 0) ? errno : 0, (n < 0) ? strerror(errno) : ""); -//errno = err; - if (n < 0) { - if (errno == EINTR) - continue; - if (errno == EAGAIN) - return 0; - log_ppp_error("sstp: read: %s\n", strerror(errno)); - goto drop; - } - } + struct buffer_t *buf = conn->in; + int n; - if (n == 0) { + while ((n = buf_tailroom(buf)) > 0) { + n = conn->stream->read(conn->stream, buf->tail, n); + if (n < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN) + return 0; + log_ppp_error("sstp: read: %s\n", strerror(errno)); + goto drop; + } else if (n == 0) { if (conf_verbose) log_ppp_info2("sstp: disconnect by peer\n"); goto drop; } + buf_put(buf, n); - conn->in_size += n; - - if (conn->sstp_state == STATE_SERVER_CALL_DISCONNECTED) { - size = http_request(conn); - if (size < 0) - goto drop; - conn->in_size -= size; - if (conn->in_size) - memmove(conn->in_buf, conn->in_buf + size, conn->in_size); - } + n = conn->handler(conn, buf); + if (n < 0) + goto drop; - if (conn->in_size >= sizeof(*hdr)) { - if (hdr->version != SSTP_VERSION) { - log_ppp_error("sstp: invalid version %d\n", hdr->version); - goto drop; - } - size = ntohs(hdr->length); - if (size > SSTP_MAX_PACKET_SIZE) { - log_ppp_error("sstp: message is too long\n"); - goto drop; - } - if (size <= conn->in_size) { - if (sstp_packet(conn)) - goto drop; - conn->in_size -= size; - if (conn->in_size) - memmove(conn->in_buf, conn->in_buf + size, conn->in_size); - } - } + buf_expand_tail(buf, SSTP_MAX_PACKET_SIZE); } + return 0; + drop: sstp_disconnect(conn); return 1; @@ -1029,121 +1413,73 @@ drop: static int sstp_write(struct triton_md_handler_t *h) { struct sstp_conn_t *conn = container_of(h, typeof(*conn), hnd); - struct sstp_pack_t *pack; + struct buffer_t *buf; int n; -#ifdef CRYPTO_OPENSSL - int err, ssl_err; -#endif - while (!list_empty(&conn->send_queue)) { - pack = list_first_entry(&conn->send_queue, typeof(*pack), entry); - again: -#ifdef CRYPTO_OPENSSL - if (conn->ssl) { - ERR_clear_error(); - n = SSL_write(conn->ssl, pack->data, pack->size); -//err = errno; -//log_ppp_info2("sstp: sstp.write = %d/%d errno %d %s\n", n, pack->size, (n < 0) ? errno : 0, (n < 0) ? strerror(errno) : ""); -//errno = err; - if (n < 0) { - err = errno; - ssl_err = SSL_get_error(conn->ssl, n); - switch (ssl_err) { - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - case SSL_ERROR_ZERO_RETURN: - n = 0; - break; - case SSL_ERROR_SYSCALL: - if (err == EINTR) - goto again; - if (err == EAGAIN) - n = 0; - else { - if (conf_verbose && err != EPIPE) - log_ppp_info2("sstp: write: %s\n", strerror(errno)); - goto drop; - } - break; - default: - log_ppp_error("sstp: SSL write: %s\n", ERR_error_string(ssl_err, NULL)); - goto drop; - } - } - } else -#endif - { - n = write(h->fd, pack->data, pack->size); -//err = errno; -//log_ppp_info2("sstp: sstp.write = %d/%d errno %d %s\n", n, pack->size, (n < 0) ? errno : 0, (n < 0) ? strerror(errno) : ""); -//errno = err; + while (!list_empty(&conn->out_queue)) { + buf = list_first_entry(&conn->out_queue, typeof(*buf), entry); + if (buf_headroom(buf) > 0) + triton_md_disable_handler(h, MD_MODE_WRITE); + + while (buf->len) { + n = conn->stream->write(conn->stream, buf->head, buf->len); if (n < 0) { if (errno == EINTR) - goto again; + continue; if (errno == EAGAIN) - n = 0; - else { - if (conf_verbose && errno != EPIPE) - log_ppp_info2("sstp: write: %s\n", strerror(errno)); - goto drop; - } - } + break; + if (conf_verbose && errno != EPIPE) + log_ppp_info2("sstp: write: %s\n", strerror(errno)); + goto drop; + } else if (n == 0) + break; + buf_pull(buf, n); } - if (n == 0) + if (buf->len) { + triton_md_enable_handler(h, MD_MODE_WRITE); break; + } - list_del(&pack->entry); - mempool_free(pack->data); - mempool_free(pack); + list_del(&buf->entry); + free_buf(buf); } - - if (list_empty(&conn->send_queue)) - triton_md_disable_handler(h, MD_MODE_WRITE); - return 0; drop: - sstp_disconnect(conn); + triton_context_call(&conn->ctx, (triton_event_func)sstp_disconnect, conn); return 1; } -static int sstp_send(struct sstp_conn_t *conn, void *data, int size) +static inline void sstp_queue(struct sstp_conn_t *conn, struct buffer_t *buf) { - struct sstp_pack_t *pack; - int queue_empty = list_empty(&conn->send_queue); - - pack = mempool_alloc(pack_pool); - if (!pack) { - log_debug("sstp: packet: allocation fail\n"); - return -1; - } - - memset(pack, 0, sizeof(*pack)); - pack->data = data; - pack->size = size; - list_add_tail(&pack->entry, &conn->send_queue); - - if (queue_empty) - return sstp_write(&conn->hnd); - - triton_md_enable_handler(&conn->hnd, MD_MODE_WRITE); + list_add_tail(&buf->entry, &conn->out_queue); +} - return 0; +static int sstp_send(struct sstp_conn_t *conn, struct buffer_t *buf) +{ + sstp_queue(conn, buf); + return sstp_write(&conn->hnd) ? -1 : 0; } static void sstp_msg_echo(struct triton_timer_t *t) { struct sstp_conn_t *conn = container_of(t, typeof(*conn), hello_timer); + struct ppp_idle idle; switch (conn->sstp_state) { case STATE_SERVER_CALL_CONNECTED: + if (ioctl(conn->ppp.unit_fd, PPPIOCGIDLE, &idle) >= 0 && + idle.recv_idle < conn->hello_interval) { + t->period = (conn->hello_interval - idle.recv_idle) * 1000; + triton_timer_mod(t, 0); + break; + } if (conn->hello_sent++) { log_ppp_warn("sstp: no echo reply\n"); - conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_1; - send_sstp_msg_call_abort(conn); + sstp_abort(conn, 0); } else - send_sstp_msg_echo_request(conn); + sstp_send_msg_echo_request(conn); break; } } @@ -1152,16 +1488,17 @@ static void sstp_timeout(struct triton_timer_t *t) { struct sstp_conn_t *conn = container_of(t, typeof(*conn), timeout_timer); + triton_timer_del(t); + switch (conn->sstp_state) { case STATE_CALL_ABORT_TIMEOUT_PENDING: case STATE_CALL_ABORT_PENDING: case STATE_CALL_DISCONNECT_TIMEOUT_PENDING: case STATE_CALL_DISCONNECT_ACK_PENDING: - sstp_disconnect(conn); + triton_context_call(&conn->ctx, (triton_event_func)sstp_disconnect, conn); break; default: - conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_1; - send_sstp_msg_call_abort(conn); + sstp_abort(conn, 0); break; } } @@ -1170,27 +1507,104 @@ static void sstp_close(struct triton_context_t *ctx) { struct sstp_conn_t *conn = container_of(ctx, typeof(*conn), ctx); - if (conn->state == STATE_PPP) { - __sync_sub_and_fetch(&stat_active, 1); - conn->state = STATE_CLOSE; + switch (conn->ppp_state) { + case STATE_STARTING: + case STATE_STARTED: + conn->ppp_state = STATE_FINISHED; ap_session_terminate(&conn->ppp.ses, TERM_ADMIN_RESET, 1); - conn->sstp_state = STATE_CALL_DISCONNECT_IN_PROGRESS_1; - send_sstp_msg_call_disconnect(conn); - } else { - conn->sstp_state = STATE_CALL_ABORT_IN_PROGRESS_1; - send_sstp_msg_call_abort(conn); + sstp_abort(conn, 1); + break; + default: + sstp_abort(conn, 0); + break; + } +} + +static int sstp_abort(struct sstp_conn_t *conn, int disconnect) +{ + static const struct { + int send_state; + int exit_state; + int timeout; + } modes[2] = { + { STATE_CALL_ABORT_IN_PROGRESS_1, STATE_CALL_ABORT_PENDING, SSTP_ABORT_TIMEOUT_1 }, + { STATE_CALL_DISCONNECT_IN_PROGRESS_1, STATE_CALL_DISCONNECT_ACK_PENDING, SSTP_DISCONNECT_TIMEOUT_1 } + }; + int ret, idx = !!disconnect; + + conn->sstp_state = modes[idx].send_state; + ret = idx ? sstp_send_msg_call_disconnect(conn) : sstp_send_msg_call_abort(conn); + + conn->timeout_timer.period = modes[idx].timeout * 1000; + if (conn->timeout_timer.tpd) + triton_timer_mod(&conn->timeout_timer, 0); + else + triton_timer_add(&conn->ctx, &conn->timeout_timer, 0); + + conn->sstp_state = modes[idx].exit_state; + + return ret; +} + +static void sstp_disconnect(struct sstp_conn_t *conn) +{ + struct buffer_t *buf; + + log_sstp_ppp_debug(conn, "disconnecting\n"); + + if (conn->timeout_timer.tpd) + triton_timer_del(&conn->timeout_timer); + if (conn->hello_timer.tpd) + triton_timer_del(&conn->hello_timer); + + if (conn->hnd.tpd) { + triton_md_unregister_handler(&conn->hnd, 0); + conn->stream->close(conn->stream); + } + if (conn->ppp_hnd.tpd) + triton_md_unregister_handler(&conn->ppp_hnd, 1); + + switch (conn->ppp_state) { + case STATE_STARTING: + case STATE_STARTED: + conn->ppp_state = STATE_FINISHED; + ap_session_terminate(&conn->ppp.ses, TERM_LOST_CARRIER, 1); } +// triton_event_fire(EV_CTRL_FINISHED, &conn->ppp.ses); + + conn->stream->free(conn->stream); + free_buf(conn->in); + free_buf(conn->ppp_in); + + list_splice_init(&conn->ppp_queue, &conn->out_queue); + while (!list_empty(&conn->out_queue)) { + buf = list_first_entry(&conn->out_queue, typeof(*buf), entry); + list_del(&buf->entry); + free_buf(buf); + } + + _free(conn->ctrl.calling_station_id); + _free(conn->ctrl.called_station_id); + +#ifdef CRYPTO_OPENSSL + if (conn->ssl_ctx) + SSL_CTX_free(conn->ssl_ctx); +#endif + + mempool_free(conn); + + log_info2("sstp: disconnected\n"); } -static void sstp_starting(struct sstp_conn_t *conn) +static void sstp_start(struct sstp_conn_t *conn) { - log_ppp_debug("sstp: starting\n"); + log_sstp_debug(conn, "start\n"); #ifdef CRYPTO_OPENSSL if (conf_ssl) { conn->ssl_ctx = SSL_CTX_new(SSLv23_server_method()); if (!conn->ssl_ctx) { - log_error("sstp: SSL_CTX error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + log_sstp_error(conn, "SSL_CTX error: %s\n", ERR_error_string(ERR_get_error(), NULL)); goto error; } @@ -1198,48 +1612,45 @@ static void sstp_starting(struct sstp_conn_t *conn) if (conf_ssl_ciphers && SSL_CTX_set_cipher_list(conn->ssl_ctx, conf_ssl_ciphers) != 1) { - log_error("sstp: SSL cipher list error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + log_sstp_error(conn, "SSL cipher list error: %s\n", ERR_error_string(ERR_get_error(), NULL)); goto error; } if (conf_ssl_ca_file && SSL_CTX_load_verify_locations(conn->ssl_ctx, conf_ssl_ca_file, NULL) != 1) { - log_error("sstp: SSL ca file error: %s\n", ERR_error_string(ERR_get_error(), NULL)); - return; + log_sstp_error(conn, "SSL ca file error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + goto error; } if (!conf_ssl_pemfile || SSL_CTX_use_certificate_file(conn->ssl_ctx, conf_ssl_pemfile, SSL_FILETYPE_PEM) != 1 || SSL_CTX_use_PrivateKey_file(conn->ssl_ctx, conf_ssl_pemfile, SSL_FILETYPE_PEM) != 1 || SSL_CTX_check_private_key(conn->ssl_ctx) != 1) { - log_error("sstp: SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + log_sstp_error(conn, "SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); goto error; } SSL_CTX_set_default_read_ahead(conn->ssl_ctx, 1); - SSL_CTX_set_mode(conn->ssl_ctx, SSL_CTX_get_mode(conn->ssl_ctx) | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - - conn->ssl = SSL_new(conn->ssl_ctx); - if (!conn->ssl) { - log_error("sstp: SSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); - goto error; - } + SSL_CTX_set_mode(conn->ssl_ctx, SSL_CTX_get_mode(conn->ssl_ctx) | + SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE); - SSL_set_accept_state(conn->ssl); - if (SSL_set_fd(conn->ssl, conn->hnd.fd) != 1) { - log_error("sstp: SSL bind error: %s\n", ERR_error_string(ERR_get_error(), NULL)); - goto error; - } - } + conn->stream = ssl_stream_init(conn->hnd.fd, conn->ssl_ctx); + } else #endif + conn->stream = stream_init(conn->hnd.fd); + if (!conn->stream) { + log_sstp_error(conn, "stream open error: %s\n", strerror(errno)); + goto error; + } + triton_md_register_handler(&conn->ctx, &conn->hnd); triton_md_enable_handler(&conn->hnd, MD_MODE_READ); - triton_timer_add(&conn->ctx, &conn->timeout_timer, 0); + + log_sstp_info2(conn, "started\n"); +// triton_event_fire(EV_CTRL_STARTING, &conn->ppp.ses); return; -#ifdef CRYPTO_OPENSSL error: sstp_disconnect(conn); -#endif } static int sstp_connect(struct triton_md_handler_t *h) @@ -1249,7 +1660,7 @@ static int sstp_connect(struct triton_md_handler_t *h) socklen_t size = sizeof(addr); int sock, value; - while(1) { + while (1) { sock = accept(h->fd, (struct sockaddr *)&addr, &size); if (sock < 0) { if (errno == EAGAIN) @@ -1268,7 +1679,8 @@ static int sstp_connect(struct triton_md_handler_t *h) return 0; } - log_info2("sstp: new connection from %s\n", inet_ntoa(addr.sin_addr)); + + log_info2("sstp: new connection from %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); if (iprange_client_check(addr.sin_addr.s_addr)) { log_warn("sstp: IP is out of client-ip-range, droping connection...\n"); @@ -1282,6 +1694,13 @@ static int sstp_connect(struct triton_md_handler_t *h) continue; } + value = 65536; + if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0) { + log_error("sstp: failed to set send buffer: %s, closing connection...\n", strerror(errno)); + close(sock); + continue; + } + value = 1; if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &value, sizeof(value)) < 0) { log_error("sstp: failed to disable nagle: %s, closing connection...\n", strerror(errno)); @@ -1301,14 +1720,19 @@ static int sstp_connect(struct triton_md_handler_t *h) conn->timeout_timer.expire = sstp_timeout; conn->timeout_timer.period = conf_timeout * 1000; conn->hello_timer.expire = sstp_msg_echo; - conn->hello_timer.period = conf_hello_interval * 1000; + conn->hello_interval = conf_hello_interval; + + conn->sstp_state = STATE_SERVER_CALL_DISCONNECTED; + conn->ppp_state = STATE_INIT; + conn->handler = http_handler; //conn->bypass_auth = conf_bypass_auth; //conn->http_cookie = NULL: //conn->auth_key... - conn->in_buf = _malloc(SSTP_MAX_PACKET_SIZE); - INIT_LIST_HEAD(&conn->send_queue); + conn->in = alloc_buf(SSTP_MAX_PACKET_SIZE*2); + INIT_LIST_HEAD(&conn->out_queue); + INIT_LIST_HEAD(&conn->ppp_queue); conn->ctrl.ctx = &conn->ctx; conn->ctrl.started = ppp_started; @@ -1320,9 +1744,10 @@ static int sstp_connect(struct triton_md_handler_t *h) conn->ctrl.name = "sstp"; conn->ctrl.ifname = ""; conn->ctrl.mppe = MPPE_UNSET; - conn->ctrl.calling_station_id = _malloc(17); - conn->ctrl.called_station_id = _malloc(17); - u_inet_ntoa(addr.sin_addr.s_addr, conn->ctrl.calling_station_id); + conn->ctrl.calling_station_id = _malloc(sizeof("255.255.255.255:65535")); + conn->ctrl.called_station_id = _malloc(sizeof("255.255.255.255")); + sprintf(conn->ctrl.calling_station_id, "%s:%d", + inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); getsockname(sock, &addr, &size); u_inet_ntoa(addr.sin_addr.s_addr, conn->ctrl.called_station_id); @@ -1335,39 +1760,25 @@ static int sstp_connect(struct triton_md_handler_t *h) conn->ppp.ses.ifname_rename = _strdup(conf_ifname); triton_context_register(&conn->ctx, &conn->ppp.ses); - triton_md_register_handler(&conn->ctx, &conn->hnd); + triton_context_call(&conn->ctx, (triton_event_func)sstp_start, conn); triton_context_wakeup(&conn->ctx); - triton_context_call(&conn->ctx, (void (*)(void*))sstp_starting, conn); - - triton_event_fire(EV_CTRL_STARTING, &conn->ppp.ses); - - __sync_add_and_fetch(&stat_starting, 1); + triton_timer_add(&conn->ctx, &conn->timeout_timer, 0); } + return 0; } static void sstp_serv_close(struct triton_context_t *ctx) { - struct sstp_serv_t *s = container_of(ctx, typeof(*s), ctx); + struct sstp_serv_t *serv = container_of(ctx, typeof(*serv), ctx); - triton_md_unregister_handler(&s->hnd, 1); + triton_md_unregister_handler(&serv->hnd, 1); triton_context_unregister(ctx); -} - -static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt, void *client) -{ - cli_send(client, "sstp:\r\n"); - cli_sendv(client," starting: %u\r\n", stat_starting); - cli_sendv(client," active: %u\r\n", stat_active); - return CLI_CMD_OK; -} - -void __export sstp_get_stat(unsigned int **starting, unsigned int **active) -{ - *starting = &stat_starting; - *active = &stat_active; +#ifdef CRYPTO_OPENSSL + CRYPTO_thread_cleanup(); +#endif } static void load_config(void) @@ -1428,11 +1839,6 @@ static void sstp_init(void) struct sockaddr_in addr; char *opt; -#ifdef CRYPTO_OPENSSL - SSL_load_error_strings(); - SSL_library_init(); -#endif - serv.hnd.fd = socket(PF_INET, SOCK_STREAM, 0); if (serv.hnd.fd < 0) { log_emerg("sstp: failed to create server socket: %s\n", strerror(errno)); @@ -1475,9 +1881,13 @@ static void sstp_init(void) return; } +#ifdef CRYPTO_OPENSSL + CRYPTO_thread_setup(); + SSL_load_error_strings(); + SSL_library_init(); +#endif + conn_pool = mempool_create(sizeof(struct sstp_conn_t)); - pack_pool = mempool_create(sizeof(struct sstp_pack_t)); - data_pool = mempool_create(SSTP_MAX_PACKET_SIZE); load_config(); @@ -1486,8 +1896,6 @@ static void sstp_init(void) triton_md_enable_handler(&serv.hnd, MD_MODE_READ); triton_context_wakeup(&serv.ctx); - cli_register_simple_cmd2(show_stat_exec, NULL, 2, "show", "stat"); - triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config); } diff --git a/accel-pppd/ctrl/sstp/sstp_prot.h b/accel-pppd/ctrl/sstp/sstp_prot.h index 54acaf4..0e5785f 100644 --- a/accel-pppd/ctrl/sstp/sstp_prot.h +++ b/accel-pppd/ctrl/sstp/sstp_prot.h @@ -73,11 +73,6 @@ enum { }; /* State */ -#define STATE_INIT 0 -#define STATE_ESTB 1 -#define STATE_PPP 2 -#define STATE_FIN 3 -#define STATE_CLOSE 4 enum { STATE_SERVER_CALL_DISCONNECTED = 0, STATE_SERVER_CONNECT_REQUEST_PENDING, -- cgit v1.2.3 From 2a7fabff21b0ecf48f5f5e1789d7d91a71962c68 Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Tue, 28 Nov 2017 05:44:46 +0500 Subject: sstp: zero allocated packets, fix non-zero reserved fields --- accel-pppd/ctrl/sstp/sstp.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index 1796488..b6c2ce3 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -217,6 +217,13 @@ static inline void *buf_put_data(struct buffer_t *buf, const void *data, int len return tmp; } +static inline void *buf_put_zero(struct buffer_t *buf, int len) +{ + void *tmp = buf_put(buf, len); + memset(tmp, 0, len); + return tmp; +} + static inline void *buf_push(struct buffer_t *buf, int len) { buf->head -= len; @@ -863,7 +870,8 @@ static int sstp_send_msg_call_connect_ack(struct sstp_conn_t *conn) return -1; } - msg = buf_put(buf, sizeof(*msg)); + msg = buf_put_zero(buf, sizeof(*msg)); + INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_CALL_CONNECT_ACK, 1, sizeof(*msg)); INIT_SSTP_ATTR_HDR(&msg->attr.hdr, SSTP_ATTRIB_CRYPTO_BINDING_REQ, sizeof(msg->attr)); msg->attr.hash_protocol_bitmask = conf_hash_protocol; @@ -890,7 +898,8 @@ static int sstp_send_msg_call_connect_nak(struct sstp_conn_t *conn) return -1; } - msg = buf_put(buf, sizeof(*msg)); + msg = buf_put_zero(buf, sizeof(*msg)); + INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_CALL_CONNECT_NAK, 1, sizeof(*msg)); INIT_SSTP_ATTR_HDR(&msg->attr.hdr, SSTP_ATTRIB_STATUS_INFO, sizeof(msg->attr)); msg->attr.attrib_id = SSTP_ATTRIB_ENCAPSULATED_PROTOCOL_ID; @@ -916,7 +925,8 @@ static int sstp_send_msg_call_abort(struct sstp_conn_t *conn) return -1; } - msg = buf_put(buf, sizeof(*msg)); + msg = buf_put_zero(buf, sizeof(*msg)); + INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_CALL_ABORT, 1, sizeof(*msg)); INIT_SSTP_ATTR_HDR(&msg->attr.hdr, SSTP_ATTRIB_STATUS_INFO, sizeof(msg->attr)); msg->attr.attrib_id = SSTP_ATTRIB_STATUS_INFO; @@ -941,7 +951,8 @@ static int sstp_send_msg_call_disconnect(struct sstp_conn_t *conn) return -1; } - msg = buf_put(buf, sizeof(*msg)); + msg = buf_put_zero(buf, sizeof(*msg)); + INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_CALL_DISCONNECT, 1, sizeof(*msg)); INIT_SSTP_ATTR_HDR(&msg->attr.hdr, SSTP_ATTRIB_STATUS_INFO, sizeof(msg->attr)); msg->attr.attrib_id = SSTP_ATTRIB_NO_ERROR; @@ -965,7 +976,8 @@ static int sstp_send_msg_call_disconnect_ack(struct sstp_conn_t *conn) return -1; } - msg = buf_put(buf, sizeof(*msg)); + msg = buf_put_zero(buf, sizeof(*msg)); + INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_CALL_DISCONNECT_ACK, 0, sizeof(*msg)); return sstp_send(conn, buf); @@ -986,7 +998,8 @@ static int sstp_send_msg_echo_request(struct sstp_conn_t *conn) return -1; } - msg = buf_put(buf, sizeof(*msg)); + msg = buf_put_zero(buf, sizeof(*msg)); + INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_ECHO_REQUEST, 0, sizeof(*msg)); return sstp_send(conn, buf); @@ -1007,7 +1020,8 @@ static int sstp_send_msg_echo_response(struct sstp_conn_t *conn) return -1; } - msg = buf_put(buf, sizeof(*msg)); + msg = buf_put_zero(buf, sizeof(*msg)); + INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_ECHO_RESPONSE, 0, sizeof(*msg)); return sstp_send(conn, buf); -- cgit v1.2.3 From c1cf64e3cb530706983c719e5de25495cb08620b Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Tue, 28 Nov 2017 05:48:06 +0500 Subject: sstp: fix thread crash on certificate-error diconnect --- accel-pppd/ctrl/sstp/sstp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index b6c2ce3..4bacb79 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -1586,7 +1586,8 @@ static void sstp_disconnect(struct sstp_conn_t *conn) } // triton_event_fire(EV_CTRL_FINISHED, &conn->ppp.ses); - conn->stream->free(conn->stream); + if (conn->stream) + conn->stream->free(conn->stream); free_buf(conn->in); free_buf(conn->ppp_in); -- cgit v1.2.3 From ebc291f26c82248b5a1250c751d6d8f9623b09ae Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Tue, 28 Nov 2017 05:52:07 +0500 Subject: sstp: implement Crypto Binding attr & nonce checking per 3.3.5.2.3 --- accel-pppd/ctrl/sstp/sstp.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index 4bacb79..a7c1335 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -114,9 +114,12 @@ struct sstp_conn_t { int nak_sent; int hello_sent; int hello_interval; + // int bypass_auth:1; // char *http_cookie; // uint8_t auth_key[32]; + uint8_t *nonce; + struct buffer_t *in; struct list_head out_queue; @@ -875,8 +878,8 @@ static int sstp_send_msg_call_connect_ack(struct sstp_conn_t *conn) INIT_SSTP_CTRL_HDR(&msg->hdr, SSTP_MSG_CALL_CONNECT_ACK, 1, sizeof(*msg)); INIT_SSTP_ATTR_HDR(&msg->attr.hdr, SSTP_ATTRIB_CRYPTO_BINDING_REQ, sizeof(msg->attr)); msg->attr.hash_protocol_bitmask = conf_hash_protocol; - //read(urandom_fd, msg->attr.nonce, sizeof(msg->attr.nonce)); - memset(msg->attr.nonce, 0, sizeof(msg->attr.nonce)); + if (conn->nonce) + memcpy(msg->attr.nonce, conn->nonce, SSTP_NONCE_SIZE); return sstp_send(conn, buf); } @@ -1076,6 +1079,8 @@ static int sstp_recv_msg_call_connect_request(struct sstp_conn_t *conn, struct s // triton_event_fire(EV_CTRL_STARTED, &conn->ppp.ses); + if (conn->nonce) + read(urandom_fd, conn->nonce, SSTP_NONCE_SIZE); if (sstp_send_msg_call_connect_ack(conn)) goto error; @@ -1100,8 +1105,13 @@ error: return -1; } -static int sstp_recv_msg_call_connected(struct sstp_conn_t *conn) +static int sstp_recv_msg_call_connected(struct sstp_conn_t *conn, struct sstp_ctrl_hdr *hdr) { + struct { + struct sstp_ctrl_hdr hdr; + struct sstp_attrib_crypto_binding attr; + } __attribute__((packed)) *msg = (void *)hdr; + if (conf_verbose) log_sstp_ppp_info2(conn, "recv [SSTP_MSG_CALL_CONNECTED]\n"); @@ -1118,8 +1128,21 @@ static int sstp_recv_msg_call_connected(struct sstp_conn_t *conn) return 0; } + if (ntohs(msg->hdr.length) < sizeof(*msg) || + ntohs(msg->hdr.num_attributes) < 1 || + msg->attr.hdr.attribute_id != SSTP_ATTRIB_CRYPTO_BINDING || + ntohs(msg->attr.hdr.length) < sizeof(msg->attr)) { + return sstp_abort(conn, 0); + } + + if (conn->nonce && memcmp(msg->attr.nonce, conn->nonce, SSTP_NONCE_SIZE) != 0) + return sstp_abort(conn, 0); + conn->sstp_state = STATE_SERVER_CALL_CONNECTED; + _free(conn->nonce); + conn->nonce = NULL; + if (conn->hello_interval) { conn->hello_timer.period = conn->hello_interval * 1000; triton_timer_add(&conn->ctx, &conn->hello_timer, 0); @@ -1345,7 +1368,7 @@ static int sstp_recv_packet(struct sstp_conn_t *conn, struct sstp_hdr *hdr) case SSTP_MSG_CALL_CONNECT_NAK: return sstp_abort(conn, 0); case SSTP_MSG_CALL_CONNECTED: - return sstp_recv_msg_call_connected(conn); + return sstp_recv_msg_call_connected(conn, msg); case SSTP_MSG_CALL_ABORT: return sstp_recv_msg_call_abort(conn); case SSTP_MSG_CALL_DISCONNECT: @@ -1586,6 +1609,8 @@ static void sstp_disconnect(struct sstp_conn_t *conn) } // triton_event_fire(EV_CTRL_FINISHED, &conn->ppp.ses); + _free(conn->nonce); + if (conn->stream) conn->stream->free(conn->stream); free_buf(conn->in); @@ -1744,6 +1769,7 @@ static int sstp_connect(struct triton_md_handler_t *h) //conn->bypass_auth = conf_bypass_auth; //conn->http_cookie = NULL: //conn->auth_key... + conn->nonce = _malloc(SSTP_NONCE_SIZE); conn->in = alloc_buf(SSTP_MAX_PACKET_SIZE*2); INIT_LIST_HEAD(&conn->out_queue); -- cgit v1.2.3 From 0ac7701588db59aeb443f0b26bee0a3cb9ebb7b4 Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Tue, 28 Nov 2017 06:14:39 +0500 Subject: sstp: implement Crypto Binding's Certificate hash & proto checking per 3.3.5.2.3 Warning: config options are changed aligned with general accel-ppp style. Following cases, including no-openssl build are supported: ssl | ssl-pemfile | behavior 1 set get both sha1 & sha256 from the certificate 0 set get both sha1 & sha256 from the certificate 0 unset use cert-hash-sha1 and/or cert-hash-sha256 hex options no-openssl use cert-hash-sha1 and/or cert-hash-sha256 hex options cert-hash-sha1 and/or cert-hash-sha256 hex options override certificate's, so it's possible to turn certficate hash verification off with just empty values (default). --- accel-pppd/accel-ppp.conf | 9 +- accel-pppd/ctrl/sstp/sstp.c | 188 +++++++++++++++++++++++++++++++++++---- accel-pppd/ctrl/sstp/sstp_prot.h | 4 +- 3 files changed, 181 insertions(+), 20 deletions(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf index ee9f7f5..a4a4a71 100644 --- a/accel-pppd/accel-ppp.conf +++ b/accel-pppd/accel-ppp.conf @@ -110,10 +110,13 @@ verbose=1 [sstp] verbose=1 +#cert-hash-proto=sha1,sha256 +#cert-hash-sha1= +#cert-hash-sha256= #ssl=1 -#ssl_ciphers=HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4 -#ssl_ca_file=/etc/ssl/sstp-ca.crt -#ssl_pemfile=/etc/ssl/sstp.pem +#ssl-ciphers=HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4 +#ssl-ca-file=/etc/ssl/sstp-ca.crt +#ssl-pemfile=/etc/ssl/sstp.pem #timeout=60 #hello-interval=60 #ip-pool=sstp diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index a7c1335..281c332 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -71,6 +71,13 @@ #define PPP_F_ESCAPE 1 #define PPP_F_TOSS 2 +#ifndef SHA_DIGEST_LENGTH +#define SHA_DIGEST_LENGTH 20 +#endif +#ifndef SHA256_DIGEST_LENGTH +#define SHA256_DIGEST_LENGTH 32 +#endif + enum { STATE_INIT = 0, STATE_STARTING, @@ -78,6 +85,11 @@ enum { STATE_FINISHED, }; +struct hash_t { + unsigned int len; + uint8_t hash[32]; +}; + struct buffer_t { struct list_head entry; size_t len; @@ -139,22 +151,28 @@ struct sstp_conn_t { static struct sstp_serv_t { struct triton_context_t ctx; struct triton_md_handler_t hnd; - - uint8_t certificate_hash[32]; } serv; static int conf_timeout = SSTP_NEGOTIOATION_TIMEOUT; static int conf_hello_interval = SSTP_HELLO_TIMEOUT; static int conf_verbose = 0; static int conf_ppp_max_mtu = 1456; -static int conf_hash_protocol = CERT_HASH_PROTOCOL_SHA256; -//static int conf_bypass_auth = 0; static const char *conf_ip_pool; static const char *conf_ifname; + +static int conf_hash_protocol = CERT_HASH_PROTOCOL_SHA1 | CERT_HASH_PROTOCOL_SHA256; +static struct hash_t conf_hash_sha1 = { .len = 0 }; +static struct hash_t conf_hash_sha256 = { .len = 0 }; +//static int conf_bypass_auth = 0; + +#ifdef CRYPTO_OPENSSL +static X509 *conf_ssl_cert = NULL; +static EVP_PKEY *conf_ssl_pkey = NULL; + +static const char *conf_ssl_ca_file = NULL; +static const char *conf_ssl_ciphers = "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4"; static int conf_ssl = 1; -static char *conf_ssl_ciphers = "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4"; -static char *conf_ssl_ca_file = NULL; -static char *conf_ssl_pemfile = NULL; +#endif static mempool_t conn_pool; @@ -1138,6 +1156,21 @@ static int sstp_recv_msg_call_connected(struct sstp_conn_t *conn, struct sstp_ct if (conn->nonce && memcmp(msg->attr.nonce, conn->nonce, SSTP_NONCE_SIZE) != 0) return sstp_abort(conn, 0); + switch (msg->attr.hash_protocol_bitmask & conf_hash_protocol) { + case CERT_HASH_PROTOCOL_SHA1: + if (conf_hash_sha1.len == SHA_DIGEST_LENGTH && + memcmp(msg->attr.cert_hash, conf_hash_sha1.hash, SHA_DIGEST_LENGTH) != 0) + return sstp_abort(conn, 0); + break; + case CERT_HASH_PROTOCOL_SHA256: + if (conf_hash_sha256.len == SHA256_DIGEST_LENGTH && + memcmp(msg->attr.cert_hash, conf_hash_sha256.hash, SHA256_DIGEST_LENGTH) != 0) + return sstp_abort(conn, 0); + break; + default: + return sstp_abort(conn, 0); + } + conn->sstp_state = STATE_SERVER_CALL_CONNECTED; _free(conn->nonce); @@ -1660,9 +1693,9 @@ static void sstp_start(struct sstp_conn_t *conn) log_sstp_error(conn, "SSL ca file error: %s\n", ERR_error_string(ERR_get_error(), NULL)); goto error; } - if (!conf_ssl_pemfile || - SSL_CTX_use_certificate_file(conn->ssl_ctx, conf_ssl_pemfile, SSL_FILETYPE_PEM) != 1 || - SSL_CTX_use_PrivateKey_file(conn->ssl_ctx, conf_ssl_pemfile, SSL_FILETYPE_PEM) != 1 || + if (!conf_ssl_cert || !conf_ssl_pkey || + SSL_CTX_use_certificate(conn->ssl_ctx, conf_ssl_cert) != 1 || + SSL_CTX_use_PrivateKey(conn->ssl_ctx, conf_ssl_pkey) != 1 || SSL_CTX_check_private_key(conn->ssl_ctx) != 1) { log_sstp_error(conn, "SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); goto error; @@ -1818,21 +1851,148 @@ static void sstp_serv_close(struct triton_context_t *ctx) triton_context_unregister(ctx); #ifdef CRYPTO_OPENSSL + if (conf_ssl_cert) + X509_free(conf_ssl_cert); + conf_ssl_cert = NULL; + + if (conf_ssl_pkey) + EVP_PKEY_free(conf_ssl_pkey); + conf_ssl_pkey = NULL; + CRYPTO_thread_cleanup(); #endif } +static int strhas(const char *s1, const char *s2, int delim) +{ + char *ptr; + int n = strlen(s2); + + while ((ptr = strchr(s1, delim))) { + if (ptr - s1 == n && memcmp(s1, s2, n) == 0) + return 0; + s1 = ++ptr; + } + return strcmp(s1, s2); +} + +static int hex2bin(const char *src, uint8_t *dst, size_t size) +{ + char buf[3], *err; + int n; + + memset(buf, 0, sizeof(buf)); + for (n = 0; n < size && src[0] && src[1]; n++) { + buf[0] = *src++; + buf[1] = *src++; + dst[n] = strtoul(buf, &err, 16); + if (err == buf || *err) + break; + } + return n; +} + static void load_config(void) { char *opt; + opt = conf_get_opt("sstp", "cert-hash-proto"); + if (opt) { + conf_hash_protocol = 0; + if (strhas(opt, "sha1", ',') == 0) + conf_hash_protocol |= CERT_HASH_PROTOCOL_SHA1; + if (strhas(opt, "sha256", ',') == 0) + conf_hash_protocol |= CERT_HASH_PROTOCOL_SHA256; + } + + memset(&conf_hash_sha1, 0, sizeof(conf_hash_sha1)); + memset(&conf_hash_sha256, 0, sizeof(conf_hash_sha256)); + +#ifdef CRYPTO_OPENSSL + if (conf_ssl_cert) { + X509_free(conf_ssl_cert); + conf_ssl_cert = NULL; + } + if (conf_ssl_pkey) { + EVP_PKEY_free(conf_ssl_pkey); + conf_ssl_pkey = NULL; + } + opt = conf_get_opt("sstp", "ssl"); if (opt) conf_ssl = atoi(opt); - conf_ssl_ciphers = conf_get_opt("sstp", "ssl_ciphers"); - conf_ssl_ca_file = conf_get_opt("sstp", "ssl_ca_file"); - conf_ssl_pemfile = conf_get_opt("sstp", "ssl_pemfile"); + conf_ssl_ciphers = conf_get_opt("sstp", "ssl-ciphers"); + + conf_ssl_ca_file = conf_get_opt("sstp", "ssl-ca-file"); + + opt = conf_get_opt("sstp", "ssl-pemfile"); + if (opt) { + BIO *in; + + in = BIO_new(BIO_s_file_internal()); + if (!in) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_BUF_LIB); + log_error("sstp: SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + goto done; + } + + if (BIO_read_filename(in, opt) <= 0) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_SYS_LIB); + log_error("sstp: SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + goto done; + } + + conf_ssl_cert = PEM_read_bio_X509(in, NULL, NULL, NULL); + if (!conf_ssl_cert) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_PEM_LIB); + log_error("sstp: SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + goto done; + } + + if (conf_hash_protocol & CERT_HASH_PROTOCOL_SHA1) { + X509_digest(conf_ssl_cert, EVP_sha1(), + conf_hash_sha1.hash, &conf_hash_sha1.len); + } + + if (conf_hash_protocol & CERT_HASH_PROTOCOL_SHA256) { + X509_digest(conf_ssl_cert, EVP_sha256(), + conf_hash_sha256.hash, &conf_hash_sha256.len); + } + + if (!conf_ssl) + goto done; + + if (BIO_read_filename(in, opt) <= 0) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_SYS_LIB); + log_error("sstp: SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + goto done; + } + + conf_ssl_pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL); + if (!conf_ssl_pkey) { + SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_PEM_LIB); + log_error("sstp: SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + goto done; + } + + done: + if (in) + BIO_free(in); + } +#endif + + opt = conf_get_opt("sstp", "cert-hash-sha1"); + if (opt) { + conf_hash_sha1.len = hex2bin(opt, + conf_hash_sha1.hash, sizeof(conf_hash_sha1.hash)); + } + + opt = conf_get_opt("sstp", "cert-hash-sha256"); + if (opt) { + conf_hash_sha256.len = hex2bin(opt, + conf_hash_sha256.hash, sizeof(conf_hash_sha256.hash)); + } opt = conf_get_opt("sstp", "timeout"); if (opt && atoi(opt) > 0) @@ -1865,8 +2025,6 @@ static void load_config(void) /* Makes compiler happy */ break; } - - //read(urandom_fd, &serv.certificate_hash, sizeof(serv.certificate_hash)); } static struct sstp_serv_t serv = { diff --git a/accel-pppd/ctrl/sstp/sstp_prot.h b/accel-pppd/ctrl/sstp/sstp_prot.h index 0e5785f..f9f78d8 100644 --- a/accel-pppd/ctrl/sstp/sstp_prot.h +++ b/accel-pppd/ctrl/sstp/sstp_prot.h @@ -130,8 +130,8 @@ struct sstp_attrib_crypto_binding { uint8_t reserved[3]; uint8_t hash_protocol_bitmask; uint8_t nonce[SSTP_NONCE_SIZE]; - uint8_t cert_hash[SSTP_NONCE_SIZE]; - uint8_t compound_mac[SSTP_NONCE_SIZE]; + uint8_t cert_hash[32]; + uint8_t compound_mac[32]; } __attribute__((packed)); struct sstp_attrib_crypto_binding_request { -- cgit v1.2.3 From 004ff247ffaad4016bb631b238a11abc285c1d0c Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Tue, 28 Nov 2017 06:30:11 +0500 Subject: sstp: allow to prefer server ciphers with ssl-prefer-server-ciphers option --- accel-pppd/accel-ppp.conf | 1 + accel-pppd/ctrl/sstp/sstp.c | 22 +++++++++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf index a4a4a71..ce41e92 100644 --- a/accel-pppd/accel-ppp.conf +++ b/accel-pppd/accel-ppp.conf @@ -115,6 +115,7 @@ verbose=1 #cert-hash-sha256= #ssl=1 #ssl-ciphers=HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4 +#ssl-prefer-server-ciphers=0 #ssl-ca-file=/etc/ssl/sstp-ca.crt #ssl-pemfile=/etc/ssl/sstp.pem #timeout=60 diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index 281c332..d3e945d 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -171,6 +171,7 @@ static EVP_PKEY *conf_ssl_pkey = NULL; static const char *conf_ssl_ca_file = NULL; static const char *conf_ssl_ciphers = "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4"; +static int conf_ssl_prefer_server_ciphers = 0; static int conf_ssl = 1; #endif @@ -1681,7 +1682,18 @@ static void sstp_start(struct sstp_conn_t *conn) goto error; } - SSL_CTX_set_options(conn->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION); + SSL_CTX_set_options(conn->ssl_ctx, +#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS + SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS | +#endif + SSL_OP_NO_SSLv2 | + SSL_OP_NO_SSLv3 | + SSL_OP_NO_COMPRESSION | + (conf_ssl_prefer_server_ciphers ? SSL_OP_CIPHER_SERVER_PREFERENCE : 0)); + SSL_CTX_set_mode(conn->ssl_ctx, + SSL_MODE_ENABLE_PARTIAL_WRITE | + SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + SSL_CTX_set_read_ahead(conn->ssl_ctx, 1); if (conf_ssl_ciphers && SSL_CTX_set_cipher_list(conn->ssl_ctx, conf_ssl_ciphers) != 1) { @@ -1701,10 +1713,6 @@ static void sstp_start(struct sstp_conn_t *conn) goto error; } - SSL_CTX_set_default_read_ahead(conn->ssl_ctx, 1); - SSL_CTX_set_mode(conn->ssl_ctx, SSL_CTX_get_mode(conn->ssl_ctx) | - SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE); - conn->stream = ssl_stream_init(conn->hnd.fd, conn->ssl_ctx); } else #endif @@ -1924,6 +1932,10 @@ static void load_config(void) conf_ssl_ciphers = conf_get_opt("sstp", "ssl-ciphers"); + opt = conf_get_opt("sstp", "ssl-prefer-server-ciphers"); + if (opt) + conf_ssl_prefer_server_ciphers = atoi(opt); + conf_ssl_ca_file = conf_get_opt("sstp", "ssl-ca-file"); opt = conf_get_opt("sstp", "ssl-pemfile"); -- cgit v1.2.3 From b75f1663f44fbeff4479998e37cdf208117be40a Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Wed, 29 Nov 2017 00:19:21 +0500 Subject: sstp: keep default ssl ciphers for better compatibility --- accel-pppd/accel-ppp.conf | 2 +- accel-pppd/ctrl/sstp/sstp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf index ce41e92..e692253 100644 --- a/accel-pppd/accel-ppp.conf +++ b/accel-pppd/accel-ppp.conf @@ -114,7 +114,7 @@ verbose=1 #cert-hash-sha1= #cert-hash-sha256= #ssl=1 -#ssl-ciphers=HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4 +#ssl-ciphers=DEFAULT #ssl-prefer-server-ciphers=0 #ssl-ca-file=/etc/ssl/sstp-ca.crt #ssl-pemfile=/etc/ssl/sstp.pem diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index d3e945d..bfd61c1 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -170,7 +170,7 @@ static X509 *conf_ssl_cert = NULL; static EVP_PKEY *conf_ssl_pkey = NULL; static const char *conf_ssl_ca_file = NULL; -static const char *conf_ssl_ciphers = "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4"; +static const char *conf_ssl_ciphers = NULL; static int conf_ssl_prefer_server_ciphers = 0; static int conf_ssl = 1; #endif -- cgit v1.2.3 From bfc5edb07582e78533e8e47817abfb0b44edea33 Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Wed, 29 Nov 2017 00:21:08 +0500 Subject: sstp: treat SSL errors as EIO --- accel-pppd/ctrl/sstp/sstp.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index bfd61c1..dc2a1a2 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -416,7 +416,9 @@ static ssize_t ssl_stream_read(struct sstp_stream_t *stream, void *buf, size_t c errno = EAGAIN; /* fall through */ case SSL_ERROR_SYSCALL: + return -1; default: + errno = EIO; return -1; } } @@ -437,7 +439,9 @@ static ssize_t ssl_stream_write(struct sstp_stream_t *stream, const void *buf, s errno = EAGAIN; /* fall through */ case SSL_ERROR_SYSCALL: + return -1; default: + errno = EIO; return -1; } } -- cgit v1.2.3 From 0da2a12029cc8c8dd54ab7c2dc8ea468b985e919 Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Wed, 29 Nov 2017 00:23:38 +0500 Subject: sstp: use ssl-keyfile option for certificate private key if not set, fallback to private key in the same ssl-pemfile --- accel-pppd/accel-ppp.conf | 3 +- accel-pppd/ctrl/sstp/sstp.c | 92 ++++++++++++++++++++++----------------------- 2 files changed, 47 insertions(+), 48 deletions(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf index e692253..68cb45c 100644 --- a/accel-pppd/accel-ppp.conf +++ b/accel-pppd/accel-ppp.conf @@ -117,7 +117,8 @@ verbose=1 #ssl-ciphers=DEFAULT #ssl-prefer-server-ciphers=0 #ssl-ca-file=/etc/ssl/sstp-ca.crt -#ssl-pemfile=/etc/ssl/sstp.pem +#ssl-pemfile=/etc/ssl/sstp-cert.pem +#ssl-keyfile=/etc/ssl/sstp-key.pem #timeout=60 #hello-interval=60 #ip-pool=sstp diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index dc2a1a2..209de22 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -1907,6 +1907,9 @@ static int hex2bin(const char *src, uint8_t *dst, size_t size) static void load_config(void) { char *opt; +#ifdef CRYPTO_OPENSSL + BIO *in; +#endif opt = conf_get_opt("sstp", "cert-hash-proto"); if (opt) { @@ -1942,59 +1945,54 @@ static void load_config(void) conf_ssl_ca_file = conf_get_opt("sstp", "ssl-ca-file"); - opt = conf_get_opt("sstp", "ssl-pemfile"); - if (opt) { - BIO *in; - - in = BIO_new(BIO_s_file_internal()); - if (!in) { - SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_BUF_LIB); - log_error("sstp: SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); - goto done; - } - - if (BIO_read_filename(in, opt) <= 0) { - SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_SYS_LIB); - log_error("sstp: SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); - goto done; - } - - conf_ssl_cert = PEM_read_bio_X509(in, NULL, NULL, NULL); - if (!conf_ssl_cert) { - SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_PEM_LIB); - log_error("sstp: SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); - goto done; - } + in = BIO_new(BIO_s_file_internal()); + if (in) { + opt = conf_get_opt("sstp", "ssl-pemfile"); + if (opt) do { + if (BIO_read_filename(in, opt) <= 0) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_SYS_LIB); + log_error("sstp: SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + break; + } - if (conf_hash_protocol & CERT_HASH_PROTOCOL_SHA1) { - X509_digest(conf_ssl_cert, EVP_sha1(), - conf_hash_sha1.hash, &conf_hash_sha1.len); - } + conf_ssl_cert = PEM_read_bio_X509(in, NULL, NULL, NULL); + if (!conf_ssl_cert) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_PEM_LIB); + log_error("sstp: SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + break; + } - if (conf_hash_protocol & CERT_HASH_PROTOCOL_SHA256) { - X509_digest(conf_ssl_cert, EVP_sha256(), - conf_hash_sha256.hash, &conf_hash_sha256.len); - } + if (conf_hash_protocol & CERT_HASH_PROTOCOL_SHA1) { + X509_digest(conf_ssl_cert, EVP_sha1(), + conf_hash_sha1.hash, &conf_hash_sha1.len); + } - if (!conf_ssl) - goto done; + if (conf_hash_protocol & CERT_HASH_PROTOCOL_SHA256) { + X509_digest(conf_ssl_cert, EVP_sha256(), + conf_hash_sha256.hash, &conf_hash_sha256.len); + } + } while (0); - if (BIO_read_filename(in, opt) <= 0) { - SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_SYS_LIB); - log_error("sstp: SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); - goto done; - } + opt = conf_get_opt("sstp", "ssl-keyfile") ? : opt; + if (opt && conf_ssl) do { + if (BIO_read_filename(in, opt) <= 0) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_SYS_LIB); + log_error("sstp: SSL private key error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + break; + } - conf_ssl_pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL); - if (!conf_ssl_pkey) { - SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_PEM_LIB); - log_error("sstp: SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); - goto done; - } + conf_ssl_pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL); + if (!conf_ssl_pkey) { + SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_PEM_LIB); + log_error("sstp: SSL private key error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + break; + } + } while (0); - done: - if (in) - BIO_free(in); + BIO_free(in); + } else { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_BUF_LIB); + log_error("sstp: SSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); } #endif -- cgit v1.2.3 From 6eb32046351a0efd702db74c7e8521c4fcdb7bee Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Wed, 29 Nov 2017 00:40:15 +0500 Subject: sstp: allow colons in cert-hash-* hex values Simplify copy-pasting from openssl x509 -fingerprint output: Examples: openssl x509 -in cert.pem -noout -fingerprint -sha1 openssl x509 -in cert.pem -noout -fingerprint -sha256 --- accel-pppd/ctrl/sstp/sstp.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index 209de22..9ecd1f6 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -1900,6 +1900,8 @@ static int hex2bin(const char *src, uint8_t *dst, size_t size) dst[n] = strtoul(buf, &err, 16); if (err == buf || *err) break; + if (*src == ':') + src++; } return n; } -- cgit v1.2.3 From ae45db860e6fe628c8e2fa107ee6b7dacd3aacbe Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Fri, 1 Dec 2017 18:00:20 +0500 Subject: sstp: fix eof result of ssl read/write ops although no harm was really happened --- accel-pppd/ctrl/sstp/sstp.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index 9ecd1f6..5953a1c 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -406,20 +406,21 @@ static ssize_t ssl_stream_read(struct sstp_stream_t *stream, void *buf, size_t c ERR_clear_error(); ret = SSL_read(stream->ssl, buf, count); + if (ret > 0) + return ret; + err = SSL_get_error(stream->ssl, ret); switch (err) { - case SSL_ERROR_NONE: - case SSL_ERROR_ZERO_RETURN: - return ret; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: errno = EAGAIN; /* fall through */ + case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_SYSCALL: - return -1; + return ret; default: errno = EIO; - return -1; + return ret; } } @@ -429,20 +430,21 @@ static ssize_t ssl_stream_write(struct sstp_stream_t *stream, const void *buf, s ERR_clear_error(); ret = SSL_write(stream->ssl, buf, count); + if (ret > 0) + return ret; + err = SSL_get_error(stream->ssl, ret); switch (err) { - case SSL_ERROR_NONE: - case SSL_ERROR_ZERO_RETURN: - return ret; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: errno = EAGAIN; /* fall through */ + case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_SYSCALL: - return -1; + return ret; default: errno = EIO; - return -1; + return ret; } } -- cgit v1.2.3 From c6ec453152b28ca78031145b96a21669908085d1 Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Fri, 1 Dec 2017 22:13:45 +0500 Subject: sstp: http: get rid of static reply buffer --- accel-pppd/ctrl/sstp/sstp.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index 5953a1c..cb1cdfe 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -306,6 +306,26 @@ static struct buffer_t *alloc_buf(size_t size) return buf; } +static struct buffer_t *alloc_buf_printf(const char* format, ...) +{ + struct buffer_t *buf = NULL; + va_list ap; + int len; + + va_start(ap, format); + len = vsnprintf(NULL, 0, format, ap); + if (len < 0) { + va_end(ap); + return NULL; + } + + buf = alloc_buf(len + 1); + if (buf) + vsnprintf(buf_put(buf, len), len + 1, format, ap); + va_end(ap); + return buf; +} + static void free_buf(struct buffer_t *buf) { _free(buf); @@ -522,28 +542,24 @@ static char *http_getline(struct sstp_conn_t *conn, int *pos, char *buf, int siz static int http_send_response(struct sstp_conn_t *conn, char *proto, char *status, char *headers) { - char datetime[sizeof("aaa, dd bbb yyyy HH:MM:SS GMT")], msg[1024]; + char datetime[sizeof("aaa, dd bbb yyyy HH:MM:SS GMT")]; struct buffer_t *buf; time_t now = time(NULL); - int n; + + if (conf_verbose) + log_sstp_info2(conn, "send [HTTP <%s %s>]\n", proto, status); strftime(datetime, sizeof(datetime), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now)); - n = snprintf(msg, sizeof(msg), + buf = alloc_buf_printf( "%s %s\r\n" /* "Server: %s\r\n" */ "Date: %s\r\n" "%s" "\r\n", proto, status, /* "accel-ppp",*/ datetime, headers ? : ""); - - if (conf_verbose) - log_sstp_info2(conn, "send [HTTP <%s %s>]\n", proto, status); - - buf = alloc_buf(n); if (!buf) { log_sstp_error(conn, "no memory\n"); return -1; } - buf_put_data(buf, msg, n); return sstp_send(conn, buf); } -- cgit v1.2.3 From 951a55128ea3382a923d2cc2f5694ec4e3aaa793 Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Sun, 3 Dec 2017 21:36:15 +0500 Subject: sstp: use HTTP status code 510 for HTTP method errors --- accel-pppd/ctrl/sstp/sstp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index cb1cdfe..c6b1813 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -592,7 +592,7 @@ static int http_recv_request(struct sstp_conn_t *conn) goto error; } if (strcmp(method, SSTP_HTTP_METHOD) != 0) { - http_send_response(conn, proto, "405 Method Not Allowed", NULL); + http_send_response(conn, proto, "501 Not Implemented", NULL); goto error; } if (strcmp(request, SSTP_HTTP_URI) != 0) { -- cgit v1.2.3 From 6697db732031d11ac937c8955a90f0a827047f70 Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Sun, 3 Dec 2017 21:51:16 +0500 Subject: sstp: drop ssl_mode_auto_retry, not required afer 7945857927b4cedab365ba86934d771281eeb213 --- accel-pppd/ctrl/sstp/sstp.c | 1 - 1 file changed, 1 deletion(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index c6b1813..26db08e 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -493,7 +493,6 @@ static struct sstp_stream_t *ssl_stream_init(int fd, SSL_CTX *ssl_ctx) goto error; SSL_set_verify(stream->ssl, SSL_VERIFY_NONE, NULL); - SSL_set_mode(stream->ssl, SSL_MODE_AUTO_RETRY); SSL_set_accept_state(stream->ssl); SSL_set_fd(stream->ssl, fd); -- cgit v1.2.3 From 4d6d7e6edc224cfc10ed389d85d1343a54848538 Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Sun, 3 Dec 2017 21:55:10 +0500 Subject: sstp: implement HTTP host header and TLS SNI checking --- accel-pppd/accel-ppp.conf | 1 + accel-pppd/ctrl/sstp/sstp.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf index 68cb45c..f1f66e2 100644 --- a/accel-pppd/accel-ppp.conf +++ b/accel-pppd/accel-ppp.conf @@ -119,6 +119,7 @@ verbose=1 #ssl-ca-file=/etc/ssl/sstp-ca.crt #ssl-pemfile=/etc/ssl/sstp-cert.pem #ssl-keyfile=/etc/ssl/sstp-key.pem +#host-name=domain.tld #timeout=60 #hello-interval=60 #ip-pool=sstp diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index 26db08e..fb379f2 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -164,6 +164,7 @@ static int conf_hash_protocol = CERT_HASH_PROTOCOL_SHA1 | CERT_HASH_PROTOCOL_SHA static struct hash_t conf_hash_sha1 = { .len = 0 }; static struct hash_t conf_hash_sha256 = { .len = 0 }; //static int conf_bypass_auth = 0; +static const char *conf_hostname = NULL; #ifdef CRYPTO_OPENSSL static X509 *conf_ssl_cert = NULL; @@ -566,7 +567,7 @@ static int http_send_response(struct sstp_conn_t *conn, char *proto, char *statu static int http_recv_request(struct sstp_conn_t *conn) { char buf[1024]; - char *line, *method, *request, *proto; + char *line, *method, *request, *proto, *host; int pos = 0; if (conn->sstp_state != STATE_SERVER_CALL_DISCONNECTED) @@ -581,6 +582,7 @@ static int http_recv_request(struct sstp_conn_t *conn) method = strsep(&line, " "); request = strsep(&line, " "); proto = strsep(&line, " "); + host = NULL; if (!method || !request || !proto) { http_send_response(conn, "HTTP/1.1", "400 Bad Request", NULL); @@ -604,8 +606,19 @@ static int http_recv_request(struct sstp_conn_t *conn) break; if (conf_verbose) log_sstp_info2(conn, "recv [HTTP <%s>]\n", line); + + if (conf_hostname && strncmp(line, "Host", sizeof("Host") - 1) == 0) { + host = line + sizeof("Host") - 1; + while (*host == ' ' || *host == ':') + host++; + } } while (*line); + if (conf_hostname && (!host || strcasecmp(host, conf_hostname) != 0)) { + http_send_response(conn, proto, "434 Requested host unavailable", NULL); + goto error; + } + if (http_send_response(conn, proto, "200 OK", "Content-Length: 18446744073709551615\r\n")) { goto error; @@ -1691,6 +1704,27 @@ static void sstp_disconnect(struct sstp_conn_t *conn) log_info2("sstp: disconnected\n"); } +#ifdef CRYPTO_OPENSSL +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME +static int sstp_servername(SSL *ssl, int *al, void *arg) +{ + struct sstp_conn_t *conn = (struct sstp_conn_t *)arg; + const char *servername; + + servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); + if (conf_verbose) + log_sstp_info2(conn, "recv [SSL SNI <%s>]\n", servername ? : ""); + + if (conf_hostname && (!servername || strcasecmp(servername, conf_hostname) != 0)) { + log_sstp_error(conn, "recv [SSL SNI error]\n"); + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + + return SSL_TLSEXT_ERR_OK; +} +#endif +#endif + static void sstp_start(struct sstp_conn_t *conn) { log_sstp_debug(conn, "start\n"); @@ -1734,6 +1768,13 @@ static void sstp_start(struct sstp_conn_t *conn) goto error; } +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + if (SSL_CTX_set_tlsext_servername_callback(conn->ssl_ctx, sstp_servername) == 1) + SSL_CTX_set_tlsext_servername_arg(conn->ssl_ctx, conn); + else + log_sstp_warn(conn, "SSl library has no tlsext support"); +#endif + conn->stream = ssl_stream_init(conn->hnd.fd, conn->ssl_ctx); } else #endif @@ -2027,6 +2068,8 @@ static void load_config(void) conf_hash_sha256.hash, sizeof(conf_hash_sha256.hash)); } + conf_hostname = conf_get_opt("sstp", "host-name"); + opt = conf_get_opt("sstp", "timeout"); if (opt && atoi(opt) > 0) conf_timeout = atoi(opt); -- cgit v1.2.3 From 6f08b5ca4298a917ae8f41a93cb199e7b36720a8 Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Mon, 4 Dec 2017 03:34:05 +0500 Subject: sstp: http: protect against oversized headers and improve parsing --- accel-pppd/ctrl/sstp/sstp.c | 117 ++++++++++++++++++++++++++------------------ 1 file changed, 70 insertions(+), 47 deletions(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index fb379f2..3e96193 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -512,32 +512,33 @@ error: /* http */ -static char *http_getline(struct sstp_conn_t *conn, int *pos, char *buf, int size) +static char *http_getline(struct buffer_t *buf, char *line, size_t size) { - unsigned char *src, *dst, c, pc; + char *src, *dst, *ptr; + int len; - size = min(size - 1, conn->in->len - *pos); - if (size <= 0) + if (buf->len == 0 || size == 0) return NULL; - src = conn->in->head + *pos; - dst = (unsigned char *)buf; - for (pc = 0; size--; dst++) { - c = *dst = *src++; - if (c == '\0') - break; - if (c == '\n') { - if (pc == '\r') - dst--; - break; - } - pc = c; + src = (void *)buf->head; + ptr = memchr(src, '\n', buf->len); + if (ptr) { + len = ptr - src; + buf_pull(buf, len + 1); + if (len > 0 && src[len - 1] == '\r') + len--; + } else { + len = buf->len; + buf_pull(buf, len); } - *dst = '\0'; - *pos = src - conn->in->head; + dst = line; + while (len-- > 0 && size-- > 1) + *dst++ = *src++; + if (size > 0) + *dst = '\0'; - return buf; + return line; } static int http_send_response(struct sstp_conn_t *conn, char *proto, char *status, char *headers) @@ -564,16 +565,18 @@ static int http_send_response(struct sstp_conn_t *conn, char *proto, char *statu return sstp_send(conn, buf); } -static int http_recv_request(struct sstp_conn_t *conn) +static int http_recv_request(struct sstp_conn_t *conn, uint8_t *data, int len) { - char buf[1024]; - char *line, *method, *request, *proto, *host; - int pos = 0; + char linebuf[1024], protobuf[sizeof("HTTP/1.x")]; + char *line, *method, *request, *proto; + struct buffer_t buf; + int host_match; - if (conn->sstp_state != STATE_SERVER_CALL_DISCONNECTED) - return -1; + buf.head = data; + buf.end = data + len; + buf_set_length(&buf, len); - line = http_getline(conn, &pos, buf, sizeof(buf)); + line = http_getline(&buf, linebuf, sizeof(linebuf)); if (!line) goto error; if (conf_verbose) @@ -582,39 +585,44 @@ static int http_recv_request(struct sstp_conn_t *conn) method = strsep(&line, " "); request = strsep(&line, " "); proto = strsep(&line, " "); - host = NULL; if (!method || !request || !proto) { http_send_response(conn, "HTTP/1.1", "400 Bad Request", NULL); goto error; } - if (strncmp(proto, "HTTP/1", sizeof("HTTP/1") - 1) != 0) { + if (strncasecmp(proto, "HTTP/1", sizeof("HTTP/1") - 1) != 0) { http_send_response(conn, "HTTP/1.1", "505 HTTP Version Not Supported", NULL); goto error; } - if (strcmp(method, SSTP_HTTP_METHOD) != 0) { + if (strcasecmp(method, SSTP_HTTP_METHOD) != 0) { http_send_response(conn, proto, "501 Not Implemented", NULL); goto error; } - if (strcmp(request, SSTP_HTTP_URI) != 0) { + if (strcasecmp(request, SSTP_HTTP_URI) != 0) { http_send_response(conn, proto, "404 Not Found", NULL); goto error; } - while ((line = http_getline(conn, &pos, buf, sizeof(buf))) != NULL) { + snprintf(protobuf, sizeof(protobuf), "%s", proto); + proto = protobuf; + + host_match = 0; + while ((line = http_getline(&buf, linebuf, sizeof(linebuf))) != NULL) { if (*line == '\0') break; if (conf_verbose) log_sstp_info2(conn, "recv [HTTP <%s>]\n", line); - if (conf_hostname && strncmp(line, "Host", sizeof("Host") - 1) == 0) { - host = line + sizeof("Host") - 1; - while (*host == ' ' || *host == ':') - host++; + if (conf_hostname && strncasecmp(line, "Host", sizeof("Host") - 1) == 0) { + line += sizeof("Host") - 1; + while (*line == ' ' || *line == ':') + line++; + if (strcasecmp(line, conf_hostname) == 0) + host_match = 1; } - } while (*line); + } - if (conf_hostname && (!host || strcasecmp(host, conf_hostname) != 0)) { + if (conf_hostname && !host_match) { http_send_response(conn, proto, "434 Requested host unavailable", NULL); goto error; } @@ -623,10 +631,7 @@ static int http_recv_request(struct sstp_conn_t *conn) "Content-Length: 18446744073709551615\r\n")) { goto error; } - - conn->sstp_state = STATE_SERVER_CONNECT_REQUEST_PENDING; - - return pos; + return 0; error: return -1; @@ -634,17 +639,35 @@ error: static int http_handler(struct sstp_conn_t *conn, struct buffer_t *buf) { + static const char *table[] = { "\r\n\r\n", "\n\n", NULL }; + const char **pptr; + char *ptr, *end; int n; - n = http_recv_request(conn); - if (n < 0) + if (conn->sstp_state != STATE_SERVER_CALL_DISCONNECTED) return -1; - buf_pull(buf, n); - if (conn->sstp_state == STATE_SERVER_CONNECT_REQUEST_PENDING) - conn->handler = sstp_handler; + end = NULL; + for (pptr = table; *pptr; pptr++) { + ptr = memmem(buf->head, buf->len, *pptr, strlen(*pptr)); + if (ptr && (!end || ptr < end)) + end = ptr + strlen(*pptr); + } + if (!end) { + if (buf_tailroom(buf) > 0) + return 0; + log_sstp_error(conn, "recv [HTTP too long header]\n"); + return -1; + } else + n = end - (char *)buf->head; - return n; + if (http_recv_request(conn, buf->head, n) < 0) + return -1; + buf_pull(buf, n); + + conn->sstp_state = STATE_SERVER_CONNECT_REQUEST_PENDING; + conn->handler = sstp_handler; + return 0; } /* ppp */ -- cgit v1.2.3 From 5846bfc1b2f0154aed398661b30a42441954a841 Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Mon, 4 Dec 2017 04:48:01 +0500 Subject: sstp: fix va_start/va_end usage on x64 platforms --- accel-pppd/ctrl/sstp/sstp.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index 3e96193..fa96a91 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -309,21 +309,22 @@ static struct buffer_t *alloc_buf(size_t size) static struct buffer_t *alloc_buf_printf(const char* format, ...) { - struct buffer_t *buf = NULL; + struct buffer_t *buf; va_list ap; int len; va_start(ap, format); len = vsnprintf(NULL, 0, format, ap); - if (len < 0) { - va_end(ap); + va_end(ap); + if (len < 0) return NULL; - } buf = alloc_buf(len + 1); - if (buf) + if (buf) { + va_start(ap, format); vsnprintf(buf_put(buf, len), len + 1, format, ap); - va_end(ap); + va_end(ap); + } return buf; } -- cgit v1.2.3 From 384c2453e399226bf09f3846d5f9940868edaed9 Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Tue, 5 Dec 2017 16:20:58 +0500 Subject: sstp: rework certificate load, fix build issue with some openssl version --- accel-pppd/ctrl/sstp/sstp.c | 65 +++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 40 deletions(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index fa96a91..b6aa70e 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -2029,55 +2029,40 @@ static void load_config(void) conf_ssl_ca_file = conf_get_opt("sstp", "ssl-ca-file"); - in = BIO_new(BIO_s_file_internal()); + in = BIO_new(BIO_s_file()); if (in) { opt = conf_get_opt("sstp", "ssl-pemfile"); - if (opt) do { - if (BIO_read_filename(in, opt) <= 0) { - SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_SYS_LIB); - log_error("sstp: SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); - break; - } - - conf_ssl_cert = PEM_read_bio_X509(in, NULL, NULL, NULL); - if (!conf_ssl_cert) { - SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_PEM_LIB); + if (opt) { + /* conf_ssl_cert set to NULL already */ + if (BIO_read_filename(in, opt) > 0) + conf_ssl_cert = PEM_read_bio_X509(in, NULL, NULL, NULL); + + if (conf_ssl_cert) { + if (conf_hash_protocol & CERT_HASH_PROTOCOL_SHA1) { + X509_digest(conf_ssl_cert, EVP_sha1(), + conf_hash_sha1.hash, &conf_hash_sha1.len); + } + if (conf_hash_protocol & CERT_HASH_PROTOCOL_SHA256) { + X509_digest(conf_ssl_cert, EVP_sha256(), + conf_hash_sha256.hash, &conf_hash_sha256.len); + } + } else log_error("sstp: SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); - break; - } - - if (conf_hash_protocol & CERT_HASH_PROTOCOL_SHA1) { - X509_digest(conf_ssl_cert, EVP_sha1(), - conf_hash_sha1.hash, &conf_hash_sha1.len); - } - - if (conf_hash_protocol & CERT_HASH_PROTOCOL_SHA256) { - X509_digest(conf_ssl_cert, EVP_sha256(), - conf_hash_sha256.hash, &conf_hash_sha256.len); - } - } while (0); + } opt = conf_get_opt("sstp", "ssl-keyfile") ? : opt; - if (opt && conf_ssl) do { - if (BIO_read_filename(in, opt) <= 0) { - SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_SYS_LIB); - log_error("sstp: SSL private key error: %s\n", ERR_error_string(ERR_get_error(), NULL)); - break; - } + if (opt && conf_ssl) { + /* conf_ssl_pkey set to NULL already */ + if (BIO_read_filename(in, opt) > 0) + conf_ssl_pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL); - conf_ssl_pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL); - if (!conf_ssl_pkey) { - SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_PEM_LIB); + if (!conf_ssl_pkey) log_error("sstp: SSL private key error: %s\n", ERR_error_string(ERR_get_error(), NULL)); - break; - } - } while (0); + } - BIO_free(in); - } else { - SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_BUF_LIB); + BIO_free_all(in); + } else log_error("sstp: SSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); - } #endif opt = conf_get_opt("sstp", "cert-hash-sha1"); -- cgit v1.2.3 From 7e704a12a28ee31a40b27778631b0006df65411f Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Sat, 16 Dec 2017 01:44:33 +0500 Subject: sstp: fix obsolete contexts leak --- accel-pppd/ctrl/sstp/sstp.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index b6aa70e..21787ea 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -1701,6 +1701,8 @@ static void sstp_disconnect(struct sstp_conn_t *conn) } // triton_event_fire(EV_CTRL_FINISHED, &conn->ppp.ses); + triton_context_unregister(&conn->ctx); + _free(conn->nonce); if (conn->stream) -- cgit v1.2.3 From 86c13de11eddba55dcbbf94a3f355bf4edefba4b Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Sat, 16 Dec 2017 02:15:21 +0500 Subject: sstp: optimize SSL context & config reload handling --- accel-pppd/ctrl/sstp/sstp.c | 293 +++++++++++++++++++++----------------------- 1 file changed, 137 insertions(+), 156 deletions(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index 21787ea..4be7370 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -87,7 +87,11 @@ enum { struct hash_t { unsigned int len; - uint8_t hash[32]; + union { + uint8_t hash[0]; + uint8_t sha1[SHA_DIGEST_LENGTH]; + uint8_t sha256[SHA256_DIGEST_LENGTH]; + }; }; struct buffer_t { @@ -142,15 +146,15 @@ struct sstp_conn_t { struct ppp_t ppp; struct ap_ctrl ctrl; - -#ifdef CRYPTO_OPENSSL - SSL_CTX *ssl_ctx; -#endif }; static struct sstp_serv_t { struct triton_context_t ctx; struct triton_md_handler_t hnd; + +#ifdef CRYPTO_OPENSSL + SSL_CTX *ssl_ctx; +#endif } serv; static int conf_timeout = SSTP_NEGOTIOATION_TIMEOUT; @@ -166,16 +170,6 @@ static struct hash_t conf_hash_sha256 = { .len = 0 }; //static int conf_bypass_auth = 0; static const char *conf_hostname = NULL; -#ifdef CRYPTO_OPENSSL -static X509 *conf_ssl_cert = NULL; -static EVP_PKEY *conf_ssl_pkey = NULL; - -static const char *conf_ssl_ca_file = NULL; -static const char *conf_ssl_ciphers = NULL; -static int conf_ssl_prefer_server_ciphers = 0; -static int conf_ssl = 1; -#endif - static mempool_t conn_pool; static int sstp_write(struct triton_md_handler_t *h); @@ -1720,89 +1714,19 @@ static void sstp_disconnect(struct sstp_conn_t *conn) _free(conn->ctrl.calling_station_id); _free(conn->ctrl.called_station_id); -#ifdef CRYPTO_OPENSSL - if (conn->ssl_ctx) - SSL_CTX_free(conn->ssl_ctx); -#endif - mempool_free(conn); log_info2("sstp: disconnected\n"); } -#ifdef CRYPTO_OPENSSL -#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME -static int sstp_servername(SSL *ssl, int *al, void *arg) -{ - struct sstp_conn_t *conn = (struct sstp_conn_t *)arg; - const char *servername; - - servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); - if (conf_verbose) - log_sstp_info2(conn, "recv [SSL SNI <%s>]\n", servername ? : ""); - - if (conf_hostname && (!servername || strcasecmp(servername, conf_hostname) != 0)) { - log_sstp_error(conn, "recv [SSL SNI error]\n"); - return SSL_TLSEXT_ERR_ALERT_FATAL; - } - - return SSL_TLSEXT_ERR_OK; -} -#endif -#endif - static void sstp_start(struct sstp_conn_t *conn) { log_sstp_debug(conn, "start\n"); #ifdef CRYPTO_OPENSSL - if (conf_ssl) { - conn->ssl_ctx = SSL_CTX_new(SSLv23_server_method()); - if (!conn->ssl_ctx) { - log_sstp_error(conn, "SSL_CTX error: %s\n", ERR_error_string(ERR_get_error(), NULL)); - goto error; - } - - SSL_CTX_set_options(conn->ssl_ctx, -#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS - SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS | -#endif - SSL_OP_NO_SSLv2 | - SSL_OP_NO_SSLv3 | - SSL_OP_NO_COMPRESSION | - (conf_ssl_prefer_server_ciphers ? SSL_OP_CIPHER_SERVER_PREFERENCE : 0)); - SSL_CTX_set_mode(conn->ssl_ctx, - SSL_MODE_ENABLE_PARTIAL_WRITE | - SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - SSL_CTX_set_read_ahead(conn->ssl_ctx, 1); - - if (conf_ssl_ciphers && - SSL_CTX_set_cipher_list(conn->ssl_ctx, conf_ssl_ciphers) != 1) { - log_sstp_error(conn, "SSL cipher list error: %s\n", ERR_error_string(ERR_get_error(), NULL)); - goto error; - } - if (conf_ssl_ca_file && - SSL_CTX_load_verify_locations(conn->ssl_ctx, conf_ssl_ca_file, NULL) != 1) { - log_sstp_error(conn, "SSL ca file error: %s\n", ERR_error_string(ERR_get_error(), NULL)); - goto error; - } - if (!conf_ssl_cert || !conf_ssl_pkey || - SSL_CTX_use_certificate(conn->ssl_ctx, conf_ssl_cert) != 1 || - SSL_CTX_use_PrivateKey(conn->ssl_ctx, conf_ssl_pkey) != 1 || - SSL_CTX_check_private_key(conn->ssl_ctx) != 1) { - log_sstp_error(conn, "SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); - goto error; - } - -#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME - if (SSL_CTX_set_tlsext_servername_callback(conn->ssl_ctx, sstp_servername) == 1) - SSL_CTX_set_tlsext_servername_arg(conn->ssl_ctx, conn); - else - log_sstp_warn(conn, "SSl library has no tlsext support"); -#endif - - conn->stream = ssl_stream_init(conn->hnd.fd, conn->ssl_ctx); - } else + if (serv.ssl_ctx) + conn->stream = ssl_stream_init(conn->hnd.fd, serv.ssl_ctx); + else #endif conn->stream = stream_init(conn->hnd.fd); if (!conn->stream) { @@ -1947,13 +1871,9 @@ static void sstp_serv_close(struct triton_context_t *ctx) triton_context_unregister(ctx); #ifdef CRYPTO_OPENSSL - if (conf_ssl_cert) - X509_free(conf_ssl_cert); - conf_ssl_cert = NULL; - - if (conf_ssl_pkey) - EVP_PKEY_free(conf_ssl_pkey); - conf_ssl_pkey = NULL; + if (serv->ssl_ctx) + SSL_CTX_free(serv->ssl_ctx); + serv->ssl_ctx = NULL; CRYPTO_thread_cleanup(); #endif @@ -1990,81 +1910,144 @@ static int hex2bin(const char *src, uint8_t *dst, size_t size) return n; } -static void load_config(void) -{ - char *opt; #ifdef CRYPTO_OPENSSL - BIO *in; +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME +static int ssl_servername(SSL *ssl, int *al, void *arg) +{ + const char *servername; + + servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); + if (conf_verbose) + log_ppp_info2("sstp: recv [SSL SNI <%s>]\n", servername ? : ""); + + if (conf_hostname && (!servername || strcasecmp(servername, conf_hostname) != 0)) { + log_ppp_error("sstp: recv [SSL SNI error]\n"); + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + + return SSL_TLSEXT_ERR_OK; +} #endif - opt = conf_get_opt("sstp", "cert-hash-proto"); +static void ssl_load_config(struct sstp_serv_t *serv, const char *servername) +{ + SSL_CTX *old_ctx, *ssl_ctx = NULL; + X509 *cert = NULL; + BIO *in = NULL; + char *opt; + + opt = conf_get_opt("sstp", "ssl-pemfile"); if (opt) { - conf_hash_protocol = 0; - if (strhas(opt, "sha1", ',') == 0) - conf_hash_protocol |= CERT_HASH_PROTOCOL_SHA1; - if (strhas(opt, "sha256", ',') == 0) - conf_hash_protocol |= CERT_HASH_PROTOCOL_SHA256; - } + in = BIO_new(BIO_s_file()); + if (!in) { + log_error("sstp: SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + goto error; + } - memset(&conf_hash_sha1, 0, sizeof(conf_hash_sha1)); - memset(&conf_hash_sha256, 0, sizeof(conf_hash_sha256)); + if (BIO_read_filename(in, opt) <= 0) { + log_error("sstp: SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + goto error; + } -#ifdef CRYPTO_OPENSSL - if (conf_ssl_cert) { - X509_free(conf_ssl_cert); - conf_ssl_cert = NULL; - } - if (conf_ssl_pkey) { - EVP_PKEY_free(conf_ssl_pkey); - conf_ssl_pkey = NULL; + cert = PEM_read_bio_X509(in, NULL, NULL, NULL); + if (!cert) { + log_error("sstp: SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + goto error; + } } opt = conf_get_opt("sstp", "ssl"); - if (opt) - conf_ssl = atoi(opt); + if (atoi(opt) > 0) { + ssl_ctx = SSL_CTX_new(SSLv23_server_method()); + if (!ssl_ctx) { + log_error("sstp: SSL_CTX error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + goto error; + } - conf_ssl_ciphers = conf_get_opt("sstp", "ssl-ciphers"); + SSL_CTX_set_options(ssl_ctx, +#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS + SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS | +#endif + SSL_OP_NO_SSLv2 | + SSL_OP_NO_SSLv3 | + SSL_OP_NO_COMPRESSION); + SSL_CTX_set_mode(ssl_ctx, + SSL_MODE_ENABLE_PARTIAL_WRITE | + SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + SSL_CTX_set_read_ahead(ssl_ctx, 1); - opt = conf_get_opt("sstp", "ssl-prefer-server-ciphers"); - if (opt) - conf_ssl_prefer_server_ciphers = atoi(opt); - - conf_ssl_ca_file = conf_get_opt("sstp", "ssl-ca-file"); - - in = BIO_new(BIO_s_file()); - if (in) { - opt = conf_get_opt("sstp", "ssl-pemfile"); - if (opt) { - /* conf_ssl_cert set to NULL already */ - if (BIO_read_filename(in, opt) > 0) - conf_ssl_cert = PEM_read_bio_X509(in, NULL, NULL, NULL); - - if (conf_ssl_cert) { - if (conf_hash_protocol & CERT_HASH_PROTOCOL_SHA1) { - X509_digest(conf_ssl_cert, EVP_sha1(), - conf_hash_sha1.hash, &conf_hash_sha1.len); - } - if (conf_hash_protocol & CERT_HASH_PROTOCOL_SHA256) { - X509_digest(conf_ssl_cert, EVP_sha256(), - conf_hash_sha256.hash, &conf_hash_sha256.len); - } - } else - log_error("sstp: SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + opt = conf_get_opt("sstp", "ssl-ciphers"); + if (opt && SSL_CTX_set_cipher_list(ssl_ctx, opt) != 1) { + log_error("sstp: SSL cipher list error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + goto error; } - opt = conf_get_opt("sstp", "ssl-keyfile") ? : opt; - if (opt && conf_ssl) { - /* conf_ssl_pkey set to NULL already */ - if (BIO_read_filename(in, opt) > 0) - conf_ssl_pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL); + opt = conf_get_opt("sstp", "ssl-prefer-server-ciphers"); + if (opt && atoi(opt)) + SSL_CTX_set_options(ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); - if (!conf_ssl_pkey) - log_error("sstp: SSL private key error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + if (cert && SSL_CTX_use_certificate(ssl_ctx, cert) != 1) { + log_error("sstp: SSL certificate error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + goto error; } - BIO_free_all(in); - } else - log_error("sstp: SSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + opt = conf_get_opt("sstp", "ssl-keyfile") ? : conf_get_opt("sstp", "ssl-pemfile"); + if ((opt && SSL_CTX_use_PrivateKey_file(ssl_ctx, opt, SSL_FILETYPE_PEM) != 1) || + SSL_CTX_check_private_key(ssl_ctx) != 1) { + log_error("sstp: SSL private key error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + goto error; + } + + opt = conf_get_opt("sstp", "ssl-ca-file"); + if (opt && SSL_CTX_load_verify_locations(ssl_ctx, opt, NULL) != 1) { + log_error("sstp: SSL ca file error: %s\n", ERR_error_string(ERR_get_error(), NULL)); + goto error; + } + +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + if (servername && SSL_CTX_set_tlsext_servername_callback(ssl_ctx, ssl_servername) != 1) + log_warn("sstp: SSL server name check error: %s\n", ERR_error_string(ERR_get_error(), NULL)); +#endif + } + + if (cert) { + if (conf_hash_protocol & CERT_HASH_PROTOCOL_SHA1) + X509_digest(cert, EVP_sha1(), conf_hash_sha1.hash, &conf_hash_sha1.len); + if (conf_hash_protocol & CERT_HASH_PROTOCOL_SHA256) + X509_digest(cert, EVP_sha256(), conf_hash_sha256.hash, &conf_hash_sha256.len); + } + + old_ctx = serv->ssl_ctx; + serv->ssl_ctx = ssl_ctx; + ssl_ctx = old_ctx; + +error: + if (ssl_ctx) + SSL_CTX_free(ssl_ctx); + if (cert) + X509_free(cert); + if (in) + BIO_free(in); +} +#endif + +static void load_config(void) +{ + char *opt; + + conf_hostname = conf_get_opt("sstp", "host-name"); + + opt = conf_get_opt("sstp", "cert-hash-proto"); + if (opt) { + conf_hash_protocol = 0; + if (strhas(opt, "sha1", ',') == 0) + conf_hash_protocol |= CERT_HASH_PROTOCOL_SHA1; + if (strhas(opt, "sha256", ',') == 0) + conf_hash_protocol |= CERT_HASH_PROTOCOL_SHA256; + } + +#ifdef CRYPTO_OPENSSL + ssl_load_config(&serv, conf_hostname); #endif opt = conf_get_opt("sstp", "cert-hash-sha1"); @@ -2079,8 +2062,6 @@ static void load_config(void) conf_hash_sha256.hash, sizeof(conf_hash_sha256.hash)); } - conf_hostname = conf_get_opt("sstp", "host-name"); - opt = conf_get_opt("sstp", "timeout"); if (opt && atoi(opt) > 0) conf_timeout = atoi(opt); -- cgit v1.2.3 From d4b00b28c986e89ac3265150fd9928a1c20fe4ea Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Sat, 16 Dec 2017 02:20:09 +0500 Subject: sstp: log current SSL mode for reference --- accel-pppd/ctrl/sstp/sstp.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index 4be7370..4255286 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -2035,6 +2035,10 @@ static void load_config(void) { char *opt; + opt = conf_get_opt("sstp", "verbose"); + if (opt && atoi(opt) >= 0) + conf_verbose = atoi(opt) > 0; + conf_hostname = conf_get_opt("sstp", "host-name"); opt = conf_get_opt("sstp", "cert-hash-proto"); @@ -2048,7 +2052,12 @@ static void load_config(void) #ifdef CRYPTO_OPENSSL ssl_load_config(&serv, conf_hostname); + opt = serv.ssl_ctx ? "enabled" : "disabled"; +#else + opt = "not available"; #endif + if (conf_verbose) + log_info2("sstp: SSL support %s\n", opt); opt = conf_get_opt("sstp", "cert-hash-sha1"); if (opt) { @@ -2070,10 +2079,6 @@ static void load_config(void) if (opt && atoi(opt) >= 0) conf_hello_interval = atoi(opt); - opt = conf_get_opt("sstp", "verbose"); - if (opt && atoi(opt) >= 0) - conf_verbose = atoi(opt) > 0; - opt = conf_get_opt("sstp", "ppp-max-mtu"); if (opt && atoi(opt) > 0) conf_ppp_max_mtu = atoi(opt); -- cgit v1.2.3 From 1f473ffa8df20b929d885d41392a25fe57ded5c2 Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Sat, 16 Dec 2017 02:48:17 +0500 Subject: sstp: add generic base for parsing http header values, improve host-name checking --- accel-pppd/ctrl/sstp/sstp.c | 59 +++++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 18 deletions(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index 4255286..ef782e2 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -536,6 +536,27 @@ static char *http_getline(struct buffer_t *buf, char *line, size_t size) return line; } +static char *http_getvalue(char *line, const char *name, int len) +{ + int sep; + + if (len < 0) + len = strlen(name); + + if (strncasecmp(line, name, len) != 0) + return NULL; + + line += len; + for (sep = 0; *line; line++) { + if (!sep && *line == ':') + sep = 1; + else if (*line != ' ' && *line != '\t') + break; + } + + return sep ? line : NULL; +} + static int http_send_response(struct sstp_conn_t *conn, char *proto, char *status, char *headers) { char datetime[sizeof("aaa, dd bbb yyyy HH:MM:SS GMT")]; @@ -563,9 +584,9 @@ static int http_send_response(struct sstp_conn_t *conn, char *proto, char *statu static int http_recv_request(struct sstp_conn_t *conn, uint8_t *data, int len) { char linebuf[1024], protobuf[sizeof("HTTP/1.x")]; - char *line, *method, *request, *proto; + char *line, *method, *request, *proto, *host; struct buffer_t buf; - int host_match; + int ret = -1; buf.head = data; buf.end = data + len; @@ -573,13 +594,14 @@ static int http_recv_request(struct sstp_conn_t *conn, uint8_t *data, int len) line = http_getline(&buf, linebuf, sizeof(linebuf)); if (!line) - goto error; + return -1; if (conf_verbose) log_sstp_info2(conn, "recv [HTTP <%s>]\n", line); method = strsep(&line, " "); request = strsep(&line, " "); proto = strsep(&line, " "); + host = NULL; if (!method || !request || !proto) { http_send_response(conn, "HTTP/1.1", "400 Bad Request", NULL); @@ -601,23 +623,20 @@ static int http_recv_request(struct sstp_conn_t *conn, uint8_t *data, int len) snprintf(protobuf, sizeof(protobuf), "%s", proto); proto = protobuf; - host_match = 0; while ((line = http_getline(&buf, linebuf, sizeof(linebuf))) != NULL) { if (*line == '\0') break; if (conf_verbose) log_sstp_info2(conn, "recv [HTTP <%s>]\n", line); - if (conf_hostname && strncasecmp(line, "Host", sizeof("Host") - 1) == 0) { - line += sizeof("Host") - 1; - while (*line == ' ' || *line == ':') - line++; - if (strcasecmp(line, conf_hostname) == 0) - host_match = 1; + if (!host && conf_hostname) { + host = http_getvalue(line, "Host", sizeof("Host") - 1); + if (host) + host = _strdup(host); } } - if (conf_hostname && !host_match) { + if (conf_hostname && strcasecmp(host ? : "", conf_hostname) != 0) { http_send_response(conn, proto, "434 Requested host unavailable", NULL); goto error; } @@ -626,10 +645,11 @@ static int http_recv_request(struct sstp_conn_t *conn, uint8_t *data, int len) "Content-Length: 18446744073709551615\r\n")) { goto error; } - return 0; + ret = 0; error: - return -1; + _free(host); + return ret; } static int http_handler(struct sstp_conn_t *conn, struct buffer_t *buf) @@ -1916,14 +1936,17 @@ static int ssl_servername(SSL *ssl, int *al, void *arg) { const char *servername; + if (!conf_hostname) + return SSL_TLSEXT_ERR_OK; + servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); - if (conf_verbose) - log_ppp_info2("sstp: recv [SSL SNI <%s>]\n", servername ? : ""); + if (conf_verbose) { + log_ppp_info2("sstp: recv [SSL <%s%s>]\n", + servername ? "SNI " : "no SNI", servername ? : ""); + } - if (conf_hostname && (!servername || strcasecmp(servername, conf_hostname) != 0)) { - log_ppp_error("sstp: recv [SSL SNI error]\n"); + if (strcasecmp(servername ? : "", conf_hostname) != 0) return SSL_TLSEXT_ERR_ALERT_FATAL; - } return SSL_TLSEXT_ERR_OK; } -- cgit v1.2.3 From c9d32e8baefb2784a8ab7e1052df704273135ff6 Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Sun, 31 Dec 2017 00:57:33 +0500 Subject: sstp: fix default max mtu to fit standard 1500 media --- accel-pppd/ctrl/sstp/sstp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index ef782e2..763c90f 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -160,7 +160,7 @@ static struct sstp_serv_t { static int conf_timeout = SSTP_NEGOTIOATION_TIMEOUT; static int conf_hello_interval = SSTP_HELLO_TIMEOUT; static int conf_verbose = 0; -static int conf_ppp_max_mtu = 1456; +static int conf_ppp_max_mtu = 1452; static const char *conf_ip_pool; static const char *conf_ifname; -- cgit v1.2.3 From 3bf08b872e9a9640db468b823358523ec74cc178 Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Sun, 31 Dec 2017 02:11:33 +0500 Subject: sstp: possible sync ppp mode fix --- accel-pppd/ctrl/sstp/sstp.c | 49 ++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 18 deletions(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index 763c90f..a390cd9 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -725,11 +725,13 @@ static int ppp_allocate_pty(int *master, int *slave, int flags) goto error; } -// value = N_HDLC; -// if (ioctl(mfd, TIOCSETD, &value) < 0) { -// log_ppp_error("sstp: ppp: set pty line discipline: %s\n", strerror(errno)); -// goto error; -// } +#if PPP_SYNC + value = N_HDLC; + if (ioctl(mfd, TIOCSETD, &value) < 0) { + log_ppp_error("sstp: ppp: set pty line discipline: %s\n", strerror(errno)); + goto error; + } +#endif if ((value = fcntl(mfd, F_GETFL)) < 0 || fcntl(mfd, F_SETFL, value | flags) < 0 || (value = fcntl(sfd, F_GETFL)) < 0 || fcntl(sfd, F_SETFL, value | flags) < 0) { @@ -782,11 +784,10 @@ static int ppp_read(struct triton_md_handler_t *h) struct sstp_conn_t *conn = container_of(h, typeof(*conn), ppp_hnd); struct buffer_t *buf; struct sstp_hdr *hdr; - uint8_t pppbuf[PPP_BUF_SIZE]; - int n; + uint8_t pppbuf[PPP_BUF_SIZE], *src; + int i, n; #if !PPP_SYNC - uint8_t *src, byte; - int i; + uint8_t byte; buf = conn->ppp_in; #endif @@ -813,18 +814,30 @@ static int ppp_read(struct triton_md_handler_t *h) continue; } + src = pppbuf; #if PPP_SYNC - buf = alloc_buf(n + sizeof(*hdr)); - if (!buf) { - log_ppp_error("sstp: ppp: no memory\n"); - goto drop; + while (n > 0) { + if (src[0] == PPP_ALLSTATIONS) + i = conn->ppp.mtu + 4 - (src[2] & 1); + else + i = conn->ppp.mtu + 2 - (src[0] & 1); + if (i > n) + i = n; + + buf = alloc_buf(i + sizeof(*hdr)); + if (!buf) { + log_ppp_error("sstp: ppp: no memory\n"); + goto drop; + } + hdr = buf_put(buf, sizeof(*hdr)); + buf_put_data(buf, src, i); + INIT_SSTP_DATA_HDR(hdr, buf->len); + sstp_queue(conn, buf); + + n -= i; + src += i; } - hdr = buf_put(buf, sizeof(*hdr)); - buf_put_data(buf, pppbuf, n); - INIT_SSTP_DATA_HDR(hdr, buf->len); - sstp_queue(conn, buf); #else - src = pppbuf; if (!buf) { alloc: conn->ppp_in = buf = alloc_buf(SSTP_MAX_PACKET_SIZE + PPP_FCSLEN); -- cgit v1.2.3 From 569891d4a75806d5cb4150f708a5d76c9a27adb7 Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Sat, 6 Jan 2018 00:04:36 +0500 Subject: sstp: reuse general logging framework --- accel-pppd/ctrl/sstp/sstp.c | 103 ++++++++++++++++---------------------------- 1 file changed, 38 insertions(+), 65 deletions(-) (limited to 'accel-pppd/ctrl/sstp/sstp.c') diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index a390cd9..0c7bd9b 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -39,33 +39,6 @@ #define min(x,y) ((x) < (y) ? (x) : (y)) #endif -#define log_sstp(log_func, conn, fmt, ...) \ - do { \ - log_func("sstp (%s): " fmt, \ - conn->ctrl.calling_station_id, \ - ##__VA_ARGS__); \ - } while (0) -#define log_sstp_error(conn, fmt, ...) log_sstp(log_error, conn, fmt, ####__VA_ARGS__) -#define log_sstp_warn(conn, fmt, ...) log_sstp(log_warn, conn, fmt, ####__VA_ARGS__) -#define log_sstp_info1(conn, fmt, ...) log_sstp(log_info1, conn, fmt, ####__VA_ARGS__) -#define log_sstp_info2(conn, fmt, ...) log_sstp(log_info2, conn, fmt, ####__VA_ARGS__) -#define log_sstp_debug(conn, fmt, ...) log_sstp(log_debug, conn, fmt, ####__VA_ARGS__) -#define log_sstp_msg(conn, fmt, ...) log_sstp(log_msg, conn, fmt, ####__VA_ARGS__) - -#define log_sstp_ppp(log_func, conn, fmt, ...) \ - do { \ - log_func("sstp (%s): " fmt, \ - conn->ctrl.ifname[0] ? conn->ctrl.ifname : \ - conn->ctrl.calling_station_id, \ - ##__VA_ARGS__); \ - } while (0) -#define log_sstp_ppp_error(conn, fmt, ...) log_sstp_ppp(log_ppp_error, conn, fmt, ####__VA_ARGS__) -#define log_sstp_ppp_warn(conn, fmt, ...) log_sstp_ppp(log_ppp_warn, conn, fmt, ####__VA_ARGS__) -#define log_sstp_ppp_info1(conn, fmt, ...) log_sstp_ppp(log_ppp_info1, conn, fmt, ####__VA_ARGS__) -#define log_sstp_ppp_info2(conn, fmt, ...) log_sstp_ppp(log_ppp_info2, conn, fmt, ####__VA_ARGS__) -#define log_sstp_ppp_debug(conn, fmt, ...) log_sstp_ppp(log_ppp_debug, conn, fmt, ####__VA_ARGS__) -#define log_sstp_ppp_msg(conn, fmt, ...) log_sstp_ppp(log_ppp_msg, conn, fmt, ####__VA_ARGS__) - #define PPP_SYNC 0 /* buggy yet */ #define PPP_BUF_SIZE 8192 #define PPP_F_ESCAPE 1 @@ -564,7 +537,7 @@ static int http_send_response(struct sstp_conn_t *conn, char *proto, char *statu time_t now = time(NULL); if (conf_verbose) - log_sstp_info2(conn, "send [HTTP <%s %s>]\n", proto, status); + log_ppp_info2("send [HTTP <%s %s>]\n", proto, status); strftime(datetime, sizeof(datetime), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now)); buf = alloc_buf_printf( @@ -574,7 +547,7 @@ static int http_send_response(struct sstp_conn_t *conn, char *proto, char *statu "%s" "\r\n", proto, status, /* "accel-ppp",*/ datetime, headers ? : ""); if (!buf) { - log_sstp_error(conn, "no memory\n"); + log_error("sstp: no memory\n"); return -1; } @@ -596,7 +569,7 @@ static int http_recv_request(struct sstp_conn_t *conn, uint8_t *data, int len) if (!line) return -1; if (conf_verbose) - log_sstp_info2(conn, "recv [HTTP <%s>]\n", line); + log_ppp_info2("recv [HTTP <%s>]\n", line); method = strsep(&line, " "); request = strsep(&line, " "); @@ -627,7 +600,7 @@ static int http_recv_request(struct sstp_conn_t *conn, uint8_t *data, int len) if (*line == '\0') break; if (conf_verbose) - log_sstp_info2(conn, "recv [HTTP <%s>]\n", line); + log_ppp_info2("recv [HTTP <%s>]\n", line); if (!host && conf_hostname) { host = http_getvalue(line, "Host", sizeof("Host") - 1); @@ -671,7 +644,7 @@ static int http_handler(struct sstp_conn_t *conn, struct buffer_t *buf) if (!end) { if (buf_tailroom(buf) > 0) return 0; - log_sstp_error(conn, "recv [HTTP too long header]\n"); + log_ppp_error("recv [HTTP too long header]\n"); return -1; } else n = end - (char *)buf->head; @@ -970,10 +943,10 @@ static int sstp_send_msg_call_connect_ack(struct sstp_conn_t *conn) struct buffer_t *buf = alloc_buf(sizeof(*msg)); if (conf_verbose) - log_sstp_ppp_info2(conn, "send [SSTP_MSG_CALL_CONNECT_ACK]\n"); + log_ppp_info2("send [SSTP SSTP_MSG_CALL_CONNECT_ACK]\n"); if (!buf) { - log_sstp_error(conn, "no memory\n"); + log_error("sstp: no memory\n"); return -1; } @@ -998,10 +971,10 @@ static int sstp_send_msg_call_connect_nak(struct sstp_conn_t *conn) struct buffer_t *buf = alloc_buf(sizeof(*msg)); if (conf_verbose) - log_sstp_ppp_info2(conn, "send [SSTP_MSG_CALL_CONNECT_NAK]\n"); + log_ppp_info2("send [SSTP SSTP_MSG_CALL_CONNECT_NAK]\n"); if (!buf) { - log_sstp_error(conn, "no memory\n"); + log_error("sstp: no memory\n"); return -1; } @@ -1025,10 +998,10 @@ static int sstp_send_msg_call_abort(struct sstp_conn_t *conn) struct buffer_t *buf = alloc_buf(sizeof(*msg)); if (conf_verbose) - log_sstp_ppp_info2(conn, "send [SSTP_MSG_CALL_ABORT]\n"); + log_ppp_info2("send [SSTP SSTP_MSG_CALL_ABORT]\n"); if (!buf) { - log_sstp_error(conn, "no memory\n"); + log_error("sstp: no memory\n"); return -1; } @@ -1051,10 +1024,10 @@ static int sstp_send_msg_call_disconnect(struct sstp_conn_t *conn) struct buffer_t *buf = alloc_buf(sizeof(*msg)); if (conf_verbose) - log_sstp_ppp_info2(conn, "send [SSTP_MSG_CALL_DISCONNECT]\n"); + log_ppp_info2("send [SSTP SSTP_MSG_CALL_DISCONNECT]\n"); if (!buf) { - log_sstp_error(conn, "no memory\n"); + log_error("sstp: no memory\n"); return -1; } @@ -1076,10 +1049,10 @@ static int sstp_send_msg_call_disconnect_ack(struct sstp_conn_t *conn) struct buffer_t *buf = alloc_buf(sizeof(*msg)); if (conf_verbose) - log_sstp_ppp_info2(conn, "send [SSTP_MSG_CALL_DISCONNECT_ACK]\n"); + log_ppp_info2("send [SSTP SSTP_MSG_CALL_DISCONNECT_ACK]\n"); if (!buf) { - log_sstp_error(conn, "no memory\n"); + log_error("sstp: no memory\n"); return -1; } @@ -1098,10 +1071,10 @@ static int sstp_send_msg_echo_request(struct sstp_conn_t *conn) struct buffer_t *buf = alloc_buf(sizeof(*msg)); if (conf_verbose) - log_sstp_ppp_info2(conn, "send [SSTP_MSG_ECHO_REQUEST]\n"); + log_ppp_info2("send [SSTP SSTP_MSG_ECHO_REQUEST]\n"); if (!buf) { - log_sstp_error(conn, "no memory\n"); + log_error("sstp: no memory\n"); return -1; } @@ -1120,10 +1093,10 @@ static int sstp_send_msg_echo_response(struct sstp_conn_t *conn) struct buffer_t *buf = alloc_buf(sizeof(*msg)); if (conf_verbose) - log_sstp_ppp_info2(conn, "send [SSTP_MSG_ECHO_RESPONSE]\n"); + log_ppp_info2("send [SSTP SSTP_MSG_ECHO_RESPONSE]\n"); if (!buf) { - log_sstp_error(conn, "no memory\n"); + log_error("sstp: no memory\n"); return -1; } @@ -1143,7 +1116,7 @@ static int sstp_recv_msg_call_connect_request(struct sstp_conn_t *conn, struct s int master, slave; if (conf_verbose) - log_sstp_ppp_info2(conn, "recv [SSTP_MSG_CALL_CONNECT_REQUEST]\n"); + log_ppp_info2("recv [SSTP SSTP_MSG_CALL_CONNECT_REQUEST]\n"); switch (conn->sstp_state) { case STATE_CALL_ABORT_TIMEOUT_PENDING: @@ -1165,7 +1138,7 @@ static int sstp_recv_msg_call_connect_request(struct sstp_conn_t *conn, struct s } if (ntohs(msg->attr.protocol_id) != SSTP_ENCAPSULATED_PROTOCOL_PPP) { if (conn->nak_sent++ == 3) { - log_sstp_ppp_warn(conn, "nak limit reached\n"); + log_ppp_error("sstp: nak limit reached\n"); return sstp_abort(conn, 0); } return sstp_send_msg_call_connect_nak(conn); @@ -1217,7 +1190,7 @@ static int sstp_recv_msg_call_connected(struct sstp_conn_t *conn, struct sstp_ct } __attribute__((packed)) *msg = (void *)hdr; if (conf_verbose) - log_sstp_ppp_info2(conn, "recv [SSTP_MSG_CALL_CONNECTED]\n"); + log_ppp_info2("recv [SSTP SSTP_MSG_CALL_CONNECTED]\n"); switch (conn->sstp_state) { case STATE_CALL_ABORT_TIMEOUT_PENDING: @@ -1275,7 +1248,7 @@ static int sstp_recv_msg_call_abort(struct sstp_conn_t *conn) int ret = 0; if (conf_verbose) - log_sstp_ppp_info2(conn, "recv [SSTP_MSG_CALL_ABORT]\n"); + log_ppp_info2("recv [SSTP SSTP_MSG_CALL_ABORT]\n"); switch (conn->sstp_state) { case STATE_CALL_ABORT_PENDING: @@ -1305,7 +1278,7 @@ static int sstp_recv_msg_call_disconnect(struct sstp_conn_t *conn) int ret; if (conf_verbose) - log_sstp_ppp_info2(conn, "recv [SSTP_MSG_CALL_DISCONNECT]\n"); + log_ppp_info2("recv [SSTP SSTP_MSG_CALL_DISCONNECT]\n"); switch (conn->sstp_state) { case STATE_CALL_ABORT_TIMEOUT_PENDING: @@ -1336,7 +1309,7 @@ static int sstp_recv_msg_call_disconnect(struct sstp_conn_t *conn) static int sstp_recv_msg_call_disconnect_ack(struct sstp_conn_t *conn) { if (conf_verbose) - log_sstp_ppp_info2(conn, "recv [SSTP_MSG_CALL_DISCONNECT_ACK]\n"); + log_ppp_info2("recv [SSTP SSTP_MSG_CALL_DISCONNECT_ACK]\n"); switch (conn->sstp_state) { case STATE_CALL_DISCONNECT_ACK_PENDING: @@ -1358,7 +1331,7 @@ static int sstp_recv_msg_call_disconnect_ack(struct sstp_conn_t *conn) static int sstp_recv_msg_echo_request(struct sstp_conn_t *conn) { if (conf_verbose) - log_sstp_ppp_info2(conn, "recv [SSTP_MSG_ECHO_REQUEST]\n"); + log_ppp_info2("recv [SSTP SSTP_MSG_ECHO_REQUEST]\n"); switch (conn->sstp_state) { case STATE_SERVER_CALL_CONNECTED: @@ -1378,7 +1351,7 @@ static int sstp_recv_msg_echo_request(struct sstp_conn_t *conn) static int sstp_recv_msg_echo_response(struct sstp_conn_t *conn) { if (conf_verbose) - log_sstp_ppp_info2(conn, "recv [SSTP_MSG_ECHO_RESPONSE]\n"); + log_ppp_info2("recv [SSTP SSTP_MSG_ECHO_RESPONSE]\n"); switch (conn->sstp_state) { case STATE_SERVER_CALL_CONNECTED: @@ -1418,7 +1391,7 @@ static int sstp_recv_data_packet(struct sstp_conn_t *conn, struct sstp_hdr *hdr) #if PPP_SYNC buf = alloc_buf(size); if (!buf) { - log_sstp_error(conn, "no memory\n"); + log_error("sstp: no memory\n"); return -1; } @@ -1426,7 +1399,7 @@ static int sstp_recv_data_packet(struct sstp_conn_t *conn, struct sstp_hdr *hdr) #else buf = alloc_buf(size*2 + 2 + PPP_FCSLEN); if (!buf) { - log_sstp_error(conn, "no memory\n"); + log_error("sstp: no memory\n"); return -1; } @@ -1468,10 +1441,10 @@ static int sstp_recv_packet(struct sstp_conn_t *conn, struct sstp_hdr *hdr) case SSTP_CTRL_PACKET: if (ntohs(hdr->length) >= sizeof(*msg)) break; - log_sstp_ppp_error(conn, "recv [SSTP too short message]\n"); + log_ppp_error("recv [SSTP too short message]\n"); return -1; default: - log_sstp_ppp_warn(conn, "recv [SSTP unknown packet type %02x]\n", hdr->reserved); + log_ppp_warn("recv [SSTP unknown packet type %02x]\n", hdr->reserved); return 0; } @@ -1499,7 +1472,7 @@ static int sstp_recv_packet(struct sstp_conn_t *conn, struct sstp_hdr *hdr) case SSTP_MSG_ECHO_RESPONSE: return sstp_recv_msg_echo_response(conn); default: - log_sstp_ppp_warn(conn, "recv [SSTP unknown message type %04x]\n", ntohs(msg->message_type)); + log_ppp_warn("recv [SSTP unknown message type %04x]\n", ntohs(msg->message_type)); return 0; } } @@ -1512,13 +1485,13 @@ static int sstp_handler(struct sstp_conn_t *conn, struct buffer_t *buf) while (buf->len >= sizeof(*hdr)) { hdr = (struct sstp_hdr *)buf->head; if (hdr->version != SSTP_VERSION) { - log_sstp_ppp_error(conn, "recv [SSTP invalid version]\n"); + log_ppp_error("recv [SSTP invalid version]\n"); return -1; } n = ntohs(hdr->length); if (n > SSTP_MAX_PACKET_SIZE) { - log_sstp_ppp_error(conn, "recv [SSTP too long packet]\n"); + log_ppp_error("recv [SSTP too long packet]\n"); return -1; } else if (n > buf->len) break; @@ -1706,7 +1679,7 @@ static void sstp_disconnect(struct sstp_conn_t *conn) { struct buffer_t *buf; - log_sstp_ppp_debug(conn, "disconnecting\n"); + log_ppp_debug("disconnecting\n"); if (conn->timeout_timer.tpd) triton_timer_del(&conn->timeout_timer); @@ -1754,7 +1727,7 @@ static void sstp_disconnect(struct sstp_conn_t *conn) static void sstp_start(struct sstp_conn_t *conn) { - log_sstp_debug(conn, "start\n"); + log_debug("sstp: start\n"); #ifdef CRYPTO_OPENSSL if (serv.ssl_ctx) @@ -1763,14 +1736,14 @@ static void sstp_start(struct sstp_conn_t *conn) #endif conn->stream = stream_init(conn->hnd.fd); if (!conn->stream) { - log_sstp_error(conn, "stream open error: %s\n", strerror(errno)); + log_error("sstp: stream open error: %s\n", strerror(errno)); goto error; } triton_md_register_handler(&conn->ctx, &conn->hnd); triton_md_enable_handler(&conn->hnd, MD_MODE_READ); - log_sstp_info2(conn, "started\n"); + log_info2("sstp: started\n"); // triton_event_fire(EV_CTRL_STARTING, &conn->ppp.ses); return; -- cgit v1.2.3