diff options
Diffstat (limited to 'accel-pppd/ctrl')
-rw-r--r-- | accel-pppd/ctrl/sstp/sstp.c | 170 | ||||
-rw-r--r-- | accel-pppd/ctrl/sstp/sstp_prot.h | 3 |
2 files changed, 133 insertions, 40 deletions
diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index be8762d..2fc2662 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -59,6 +59,7 @@ #endif #define ADDRSTR_MAXLEN (sizeof("unix:") + sizeof(((struct sockaddr_un *)0)->sun_path)) +#define FLAG_NOPORT 1 enum { STATE_INIT = 0, @@ -126,8 +127,8 @@ struct sstp_conn_t { // int bypass_auth:1; // char *http_cookie; -// uint8_t auth_key[32]; uint8_t *nonce; + uint8_t *hlak_key; struct buffer_t *in; struct list_head out_queue; @@ -171,6 +172,9 @@ static const char *conf_http_url = NULL; static mempool_t conn_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); @@ -285,24 +289,26 @@ static in_addr_t sockaddr_ipv4(struct sockaddr_t *addr) } } -static int sockaddr_ntop(struct sockaddr_t *addr, char *dst, socklen_t size) +static int sockaddr_ntop(struct sockaddr_t *addr, char *dst, socklen_t size, int flags) { char ipv6_buf[INET6_ADDRSTRLEN], *path, sign; switch (addr->u.sa.sa_family) { case AF_INET: - return snprintf(dst, size, "%s:%d", + return snprintf(dst, size, (flags & FLAG_NOPORT) ? "%s" : "%s:%d", inet_ntoa(addr->u.sin.sin_addr), ntohs(addr->u.sin.sin_port)); case AF_INET6: if (IN6_IS_ADDR_V4MAPPED(&addr->u.sin6.sin6_addr)) { inet_ntop(AF_INET, &addr->u.sin6.sin6_addr.s6_addr32[3], ipv6_buf, sizeof(ipv6_buf)); + return snprintf(dst, size, (flags & FLAG_NOPORT) ? "%s" : "%s:%d", + ipv6_buf, ntohs(addr->u.sin6.sin6_port)); } else { inet_ntop(AF_INET6, &addr->u.sin6.sin6_addr, ipv6_buf, sizeof(ipv6_buf)); + return snprintf(dst, size, (flags & FLAG_NOPORT) ? "%s" : "[%s]:%d", + ipv6_buf, ntohs(addr->u.sin6.sin6_port)); } - return snprintf(dst, size, "%s:%d", - ipv6_buf, ntohs(addr->u.sin6.sin6_port)); case AF_UNIX: if (addr->len <= offsetof(typeof(addr->u.sun), sun_path)) { path = "NULL"; @@ -733,7 +739,7 @@ static int proxy_handler(struct sstp_conn_t *conn, struct buffer_t *buf) if (ip && triton_module_loaded("connlimit") && connlimit_check(cl_key_from_ipv4(ip))) return -1; - sockaddr_ntop(&conn->addr, addr_buf, sizeof(addr_buf)); + sockaddr_ntop(&conn->addr, addr_buf, sizeof(addr_buf), 0); log_info2("sstp: proxy: connection from %s\n", addr_buf); if (ip && iprange_client_check(ip)) { @@ -742,11 +748,14 @@ static int proxy_handler(struct sstp_conn_t *conn, struct buffer_t *buf) } if (addr.u.sa.sa_family != AF_UNSPEC) { + _free(conn->ppp.ses.chan_name); + conn->ppp.ses.chan_name = _strdup(addr_buf); + + sockaddr_ntop(&conn->addr, addr_buf, sizeof(addr_buf), FLAG_NOPORT); _free(conn->ctrl.calling_station_id); conn->ctrl.calling_station_id = _strdup(addr_buf); - conn->ppp.ses.chan_name = conn->ctrl.calling_station_id; - sockaddr_ntop(&addr, addr_buf, sizeof(addr_buf)); + sockaddr_ntop(&addr, addr_buf, sizeof(addr_buf), FLAG_NOPORT); _free(conn->ctrl.called_station_id); conn->ctrl.called_station_id = _strdup(addr_buf); } @@ -864,12 +873,12 @@ static int http_recv_request(struct sstp_conn_t *conn, uint8_t *data, int len) } if (strncasecmp(proto, "HTTP/1", sizeof("HTTP/1") - 1) != 0) { if (conf_http_mode) - http_send_response(conn, "HTTP/1.1", "505 HTTP Version Not Supported", NULL); + http_send_response(conn, "HTTP/1.1", "400 Bad Request", NULL); return -1; } if (strcasecmp(method, SSTP_HTTP_METHOD) != 0 && strcasecmp(method, "GET") != 0) { if (conf_http_mode) - http_send_response(conn, proto, "405 Method Not Allowed", NULL); + http_send_response(conn, proto, "501 Not Implemented", NULL); return -1; } @@ -1447,16 +1456,19 @@ static int sstp_recv_msg_call_connect_request(struct sstp_conn_t *conn, struct s 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 (conn->nonce) read(urandom_fd, conn->nonce, SSTP_NONCE_SIZE); + if (conn->hlak_key) + memset(conn->hlak_key, 0, SSTP_HLAK_SIZE); if (sstp_send_msg_call_connect_ack(conn)) goto error; conn->sstp_state = STATE_SERVER_CALL_CONNECTED_PENDING; - conn->ppp_state = STATE_STARTING; + __sync_sub_and_fetch(&stat_starting, 1); + __sync_add_and_fetch(&stat_active, 1); + triton_event_fire(EV_CTRL_STARTED, &conn->ppp.ses); + conn->ppp_state = STATE_STARTING; conn->ppp.fd = slave; if (establish_ppp(&conn->ppp)) { conn->ppp_state = STATE_FINISHED; @@ -1480,7 +1492,10 @@ static int sstp_recv_msg_call_connected(struct sstp_conn_t *conn, struct sstp_ct struct { struct sstp_ctrl_hdr hdr; struct sstp_attrib_crypto_binding attr; - } __attribute__((packed)) *msg = (void *)hdr; + } __attribute__((packed)) buf, *msg = (void *)hdr; + uint8_t md[EVP_MAX_MD_SIZE], hash, *ptr; + const EVP_MD *evp; + unsigned int len, mdlen; if (conf_verbose) log_ppp_info2("recv [SSTP SSTP_MSG_CALL_CONNECTED]\n"); @@ -1505,28 +1520,58 @@ static int sstp_recv_msg_call_connected(struct sstp_conn_t *conn, struct sstp_ct return sstp_abort(conn, 0); } - if (conn->nonce && memcmp(msg->attr.nonce, conn->nonce, SSTP_NONCE_SIZE) != 0) + if (conn->nonce && memcmp(msg->attr.nonce, conn->nonce, SSTP_NONCE_SIZE) != 0) { + log_ppp_error("sstp: invalid Nonce"); 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) + hash = msg->attr.hash_protocol_bitmask & conf_hash_protocol; + if (hash & CERT_HASH_PROTOCOL_SHA256) { + len = SHA256_DIGEST_LENGTH; + if (conf_hash_sha256.len == len && + memcmp(msg->attr.cert_hash, conf_hash_sha256.hash, len) != 0) { + log_ppp_error("sstp: invalid SHA256 Cert Hash"); 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) + } + evp = EVP_sha256(); + } else if (hash & CERT_HASH_PROTOCOL_SHA1) { + len = SHA_DIGEST_LENGTH; + if (conf_hash_sha1.len == len && + memcmp(msg->attr.cert_hash, conf_hash_sha1.hash, len) != 0) { + log_ppp_error("sstp: invalid SHA1 Cert Hash"); return sstp_abort(conn, 0); - break; - default: + } + evp = EVP_sha1(); + } else { + log_ppp_error("sstp: invalid Hash Protocol 0x%02x\n", + msg->attr.hash_protocol_bitmask); return sstp_abort(conn, 0); } + if (conn->hlak_key) { + ptr = mempcpy(md, SSTP_CMK_SEED, SSTP_CMK_SEED_SIZE); + *ptr++ = len; + *ptr++ = 0; + *ptr++ = 1; + mdlen = sizeof(md); + HMAC(evp, conn->hlak_key, SSTP_HLAK_SIZE, md, ptr - md, md, &mdlen); + + memcpy(&buf, msg, sizeof(buf)); + memset(buf.attr.compound_mac, 0, sizeof(buf.attr.compound_mac)); + HMAC(evp, md, mdlen, (void *)&buf, sizeof(buf), buf.attr.compound_mac, &len); + + if (memcmp(msg->attr.compound_mac, buf.attr.compound_mac, len) != 0) { + log_ppp_error("sstp: invalid Compound MAC"); + return sstp_abort(conn, 0); + } + } + conn->sstp_state = STATE_SERVER_CALL_CONNECTED; _free(conn->nonce); conn->nonce = NULL; + _free(conn->hlak_key); + conn->hlak_key = NULL; if (conn->hello_interval) { conn->hello_timer.period = conn->hello_interval * 1000; @@ -1585,7 +1630,6 @@ static int sstp_recv_msg_call_disconnect(struct sstp_conn_t *conn) } 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; @@ -1765,7 +1809,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_ppp_warn("recv [SSTP unknown message type %04x]\n", ntohs(msg->message_type)); + log_ppp_warn("recv [SSTP unknown message type 0x%04x]\n", ntohs(msg->message_type)); return 0; } } @@ -1778,7 +1822,7 @@ 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_ppp_error("recv [SSTP invalid version]\n"); + log_ppp_error("recv [SSTP invalid version 0x%02x]\n", hdr->version); return -1; } @@ -2049,16 +2093,25 @@ static void sstp_disconnect(struct sstp_conn_t *conn) triton_md_unregister_handler(&conn->ppp_hnd, 1); switch (conn->ppp_state) { + case STATE_INIT: + __sync_sub_and_fetch(&stat_starting, 1); + break; case STATE_STARTING: case STATE_STARTED: conn->ppp_state = STATE_FINISHED; + __sync_sub_and_fetch(&stat_active, 1); ap_session_terminate(&conn->ppp.ses, TERM_LOST_CARRIER, 1); + break; + case STATE_FINISHED: + __sync_sub_and_fetch(&stat_active, 1); + break; } -// triton_event_fire(EV_CTRL_FINISHED, &conn->ppp.ses); + triton_event_fire(EV_CTRL_FINISHED, &conn->ppp.ses); triton_context_unregister(&conn->ctx); _free(conn->nonce); + _free(conn->hlak_key); if (conn->stream) conn->stream->free(conn->stream); @@ -2072,6 +2125,7 @@ static void sstp_disconnect(struct sstp_conn_t *conn) free_buf(buf); } + _free(conn->ppp.ses.chan_name); _free(conn->ctrl.calling_station_id); _free(conn->ctrl.called_station_id); @@ -2082,7 +2136,7 @@ static void sstp_disconnect(struct sstp_conn_t *conn) static void sstp_start(struct sstp_conn_t *conn) { - log_debug("sstp: start\n"); + log_debug("sstp: starting\n"); #ifdef CRYPTO_OPENSSL if (serv.ssl_ctx) @@ -2099,7 +2153,6 @@ static void sstp_start(struct sstp_conn_t *conn) triton_md_enable_handler(&conn->hnd, MD_MODE_READ); log_info2("sstp: started\n"); -// triton_event_fire(EV_CTRL_STARTING, &conn->ppp.ses); return; @@ -2136,7 +2189,7 @@ static int sstp_connect(struct triton_md_handler_t *h) return 0; } - sockaddr_ntop(&addr, addr_buf, sizeof(addr_buf)); + sockaddr_ntop(&addr, addr_buf, sizeof(addr_buf), 0); log_info2("sstp: new connection from %s\n", addr_buf); if (ip && iprange_client_check(addr.u.sin.sin_addr.s_addr)) { @@ -2188,8 +2241,8 @@ 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->hlak_key = _malloc(SSTP_HLAK_SIZE); conn->in = alloc_buf(SSTP_MAX_PACKET_SIZE*2); INIT_LIST_HEAD(&conn->out_queue); @@ -2207,24 +2260,29 @@ static int sstp_connect(struct triton_md_handler_t *h) conn->ctrl.ifname = ""; conn->ctrl.mppe = MPPE_DENY; - conn->ctrl.calling_station_id = _strdup(addr_buf); - addr.len = sizeof(addr.u); - getsockname(sock, &addr.u.sa, &addr.len); - sockaddr_ntop(&addr, addr_buf, sizeof(addr_buf)); - conn->ctrl.called_station_id = _strdup(addr_buf); - ppp_init(&conn->ppp); conn->ppp.ses.ctrl = &conn->ctrl; - conn->ppp.ses.chan_name = conn->ctrl.calling_station_id; + conn->ppp.ses.chan_name = _strdup(addr_buf); 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); + sockaddr_ntop(&addr, addr_buf, sizeof(addr_buf), FLAG_NOPORT); + conn->ctrl.calling_station_id = _strdup(addr_buf); + + addr.len = sizeof(addr.u); + getsockname(sock, &addr.u.sa, &addr.len); + sockaddr_ntop(&addr, addr_buf, sizeof(addr_buf), FLAG_NOPORT); + conn->ctrl.called_station_id = _strdup(addr_buf); + triton_context_register(&conn->ctx, &conn->ppp.ses); triton_context_call(&conn->ctx, (triton_event_func)sstp_start, conn); triton_context_wakeup(&conn->ctx); + __sync_add_and_fetch(&stat_starting, 1); + triton_event_fire(EV_CTRL_STARTING, &conn->ppp.ses); + triton_timer_add(&conn->ctx, &conn->timeout_timer, 0); } @@ -2378,6 +2436,35 @@ error: } #endif +static void ev_mppe_keys(struct ev_mppe_keys_t *ev) +{ + struct ppp_t *ppp = ev->ppp; + struct sstp_conn_t *conn = container_of(ppp, typeof(*conn), ppp); + + if (ppp->ses.ctrl->type != CTRL_TYPE_SSTP) + return; + + if (conn->hlak_key) { + memcpy(conn->hlak_key, ev->recv_key, 16); + memcpy(conn->hlak_key + 16, ev->send_key, 16); + } +} + +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) { int ipmode; @@ -2563,6 +2650,9 @@ 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_MPPE_KEYS, (triton_event_func)ev_mppe_keys); triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config); return; diff --git a/accel-pppd/ctrl/sstp/sstp_prot.h b/accel-pppd/ctrl/sstp/sstp_prot.h index f9f78d8..e3c4c9c 100644 --- a/accel-pppd/ctrl/sstp/sstp_prot.h +++ b/accel-pppd/ctrl/sstp/sstp_prot.h @@ -10,6 +10,9 @@ #define SSTP_VERSION 0x10 #define SSTP_MAX_PACKET_SIZE 4095 #define SSTP_NONCE_SIZE 32 +#define SSTP_HLAK_SIZE 32 +#define SSTP_CMK_SEED "SSTP inner method derived CMK" +#define SSTP_CMK_SEED_SIZE 29 #define SSTP_NEGOTIOATION_TIMEOUT 60 #define SSTP_HELLO_TIMEOUT 60 #define SSTP_ABORT_TIMEOUT_1 3 |