Compare commits

...

9 Commits
master ... v0.7

Author SHA1 Message Date
Andri Yngvason 14619e6281 Release v0.7.2 2024-02-02 22:42:16 +00:00
Andri Yngvason a77ff634f0 Keep zlib streams when switching encodings
Both RealVNC and TigerVNC clients expect zlib streams to remain when
switching encodings, so when they switch back, inflate fails if the
encoder is discared.

fixes #109
2024-02-02 22:41:33 +00:00
Andri Yngvason 4148503d0c server: Allow server to request more than 32 encodings
fixes #108
2024-01-24 18:30:58 +00:00
Andri Yngvason b5b330b22c Release v0.7.1 2023-11-05 15:47:14 +00:00
Andri Yngvason d4c3083c42 server: Remove DNS lookup
DNS lookup is slow and can even fail. Under some circumstances, it will
even block for a significant amount of time until it completes.

The user of this library can do the lookup instead if they wish.
2023-11-05 10:32:17 +00:00
Andri Yngvason 5ef65d2c2b crypto: Initialise AES-ECB decode context correctly
This fixes Apple DH
2023-11-04 23:28:17 +00:00
Andri Yngvason 823870f88e server: Fix double-free on failed Apple DH 2023-11-04 23:28:15 +00:00
Andri Yngvason 112391140a Release v0.7.0 2023-10-04 21:12:49 +00:00
Andri Yngvason 2e61346c3f server: Disable NTP and PTS extensions
They are note ready to be released.
2023-10-04 21:11:45 +00:00
4 changed files with 57 additions and 17 deletions

View File

@ -105,6 +105,8 @@ struct nvnc_client {
struct cut_text cut_text; struct cut_text cut_text;
bool is_ext_notified; bool is_ext_notified;
struct encoder* encoder; struct encoder* encoder;
struct encoder* zrle_encoder;
struct encoder* tight_encoder;
uint32_t cursor_seq; uint32_t cursor_seq;
int quality; int quality;

View File

@ -1,7 +1,7 @@
project( project(
'neatvnc', 'neatvnc',
'c', 'c',
version: '0.6.0', version: '0.7.2',
license: 'ISC', license: 'ISC',
default_options: [ default_options: [
'c_std=gnu11', 'c_std=gnu11',

View File

@ -318,7 +318,7 @@ static struct crypto_cipher* crypto_cipher_new_aes128_ecb(
aes128_set_encrypt_key(&self->enc_ctx.aes128_ecb, enc_key); aes128_set_encrypt_key(&self->enc_ctx.aes128_ecb, enc_key);
if (dec_key) if (dec_key)
aes128_set_decrypt_key(&self->enc_ctx.aes128_ecb, dec_key); aes128_set_decrypt_key(&self->dec_ctx.aes128_ecb, dec_key);
self->encrypt = crypto_cipher_aes128_ecb_encrypt; self->encrypt = crypto_cipher_aes128_ecb_encrypt;
self->decrypt = crypto_cipher_aes128_ecb_decrypt; self->decrypt = crypto_cipher_aes128_ecb_decrypt;

View File

@ -82,6 +82,8 @@ static void on_encode_frame_done(struct encoder*, struct rcbuf*, uint64_t pts);
static bool client_has_encoding(const struct nvnc_client* client, static bool client_has_encoding(const struct nvnc_client* client,
enum rfb_encodings encoding); enum rfb_encodings encoding);
static void process_fb_update_requests(struct nvnc_client* client); static void process_fb_update_requests(struct nvnc_client* client);
static void sockaddr_to_string(char* dst, size_t sz,
const struct sockaddr* addr);
#if defined(GIT_VERSION) #if defined(GIT_VERSION)
EXPORT const char nvnc_version[] = GIT_VERSION; EXPORT const char nvnc_version[] = GIT_VERSION;
@ -141,6 +143,8 @@ static void client_close(struct nvnc_client* client)
client->encoder->on_done = NULL; client->encoder->on_done = NULL;
} }
encoder_unref(client->encoder); encoder_unref(client->encoder);
encoder_unref(client->zrle_encoder);
encoder_unref(client->tight_encoder);
pixman_region_fini(&client->damage); pixman_region_fini(&client->damage);
free(client->cut_text.buffer); free(client->cut_text.buffer);
free(client); free(client);
@ -494,7 +498,6 @@ static int on_apple_dh_response(struct nvnc_client* client)
} else { } else {
nvnc_log(NVNC_LOG_INFO, "User \"%s\" rejected", username); nvnc_log(NVNC_LOG_INFO, "User \"%s\" rejected", username);
security_handshake_failed(client, "Invalid username or password"); security_handshake_failed(client, "Invalid username or password");
crypto_cipher_del(cipher);
} }
return sizeof(*msg) + key_len; return sizeof(*msg) + key_len;
@ -945,7 +948,7 @@ static int on_client_set_encodings(struct nvnc_client* client)
(struct rfb_client_set_encodings_msg*)(client->msg_buffer + (struct rfb_client_set_encodings_msg*)(client->msg_buffer +
client->buffer_index); client->buffer_index);
size_t n_encodings = MIN(MAX_ENCODINGS, ntohs(msg->n_encodings)); size_t n_encodings = ntohs(msg->n_encodings);
size_t n = 0; size_t n = 0;
if (client->buffer_len - client->buffer_index < if (client->buffer_len - client->buffer_index <
@ -954,7 +957,7 @@ static int on_client_set_encodings(struct nvnc_client* client)
client->quality = 10; client->quality = 10;
for (size_t i = 0; i < n_encodings; ++i) { for (size_t i = 0; i < n_encodings && n < MAX_ENCODINGS; ++i) {
enum rfb_encodings encoding = htonl(msg->encodings[i]); enum rfb_encodings encoding = htonl(msg->encodings[i]);
switch (encoding) { switch (encoding) {
@ -970,9 +973,10 @@ static int on_client_set_encodings(struct nvnc_client* client)
case RFB_ENCODING_DESKTOPSIZE: case RFB_ENCODING_DESKTOPSIZE:
case RFB_ENCODING_EXTENDEDDESKTOPSIZE: case RFB_ENCODING_EXTENDEDDESKTOPSIZE:
case RFB_ENCODING_QEMU_EXT_KEY_EVENT: case RFB_ENCODING_QEMU_EXT_KEY_EVENT:
client->encodings[n++] = encoding;
case RFB_ENCODING_PTS: case RFB_ENCODING_PTS:
case RFB_ENCODING_NTP: case RFB_ENCODING_NTP:
client->encodings[n++] = encoding; ;
} }
if (RFB_ENCODING_JPEG_LOWQ <= encoding && if (RFB_ENCODING_JPEG_LOWQ <= encoding &&
@ -1109,7 +1113,32 @@ static void process_fb_update_requests(struct nvnc_client* client)
client->encoder->on_done = NULL; client->encoder->on_done = NULL;
} }
encoder_unref(client->encoder); encoder_unref(client->encoder);
/* Zlib streams need to be saved so we keep encoders around that
* use them.
*/
switch (encoding) {
case RFB_ENCODING_ZRLE:
if (!client->zrle_encoder) {
client->zrle_encoder = encoder_new(encoding,
width, height);
}
client->encoder = client->zrle_encoder;
encoder_ref(client->encoder);
break;
case RFB_ENCODING_TIGHT:
if (!client->tight_encoder) {
client->tight_encoder = encoder_new(encoding,
width, height);
}
client->encoder = client->tight_encoder;
encoder_ref(client->encoder);
break;
default:
client->encoder = encoder_new(encoding, width, height); client->encoder = encoder_new(encoding, width, height);
break;
}
if (!client->encoder) { if (!client->encoder) {
nvnc_log(NVNC_LOG_ERROR, "Failed to allocate new encoder"); nvnc_log(NVNC_LOG_ERROR, "Failed to allocate new encoder");
return; return;
@ -1673,21 +1702,23 @@ static void on_client_event(struct stream* stream, enum stream_event event)
client->buffer_index = 0; client->buffer_index = 0;
} }
// TODO: Remove this when nvnc_client_get_hostname gets renamed.
static void record_peer_hostname(int fd, struct nvnc_client* client) static void record_peer_hostname(int fd, struct nvnc_client* client)
{ {
struct sockaddr_storage storage; struct sockaddr_storage storage;
struct sockaddr* peer = (struct sockaddr*)&storage; struct sockaddr* peer = (struct sockaddr*)&storage;
socklen_t peerlen = sizeof(storage); socklen_t peerlen = sizeof(storage);
if (getpeername(fd, peer, &peerlen) == 0) { if (getpeername(fd, peer, &peerlen) < 0) {
nvnc_log(NVNC_LOG_WARNING, "Failed to get address for client: %m");
return;
}
if (peer->sa_family == AF_UNIX) { if (peer->sa_family == AF_UNIX) {
snprintf(client->hostname, sizeof(client->hostname), snprintf(client->hostname, sizeof(client->hostname),
"unix domain socket"); "unix domain socket");
} else { } else {
getnameinfo(peer, peerlen, sockaddr_to_string(client->hostname, sizeof(client->hostname),
client->hostname, sizeof(client->hostname), peer);
NULL, 0, // no need for port
0);
}
} }
} }
@ -1774,6 +1805,11 @@ static void sockaddr_to_string(char* dst, size_t sz, const struct sockaddr* addr
case AF_INET6: case AF_INET6:
inet_ntop(addr->sa_family, &sa_in6->sin6_addr, dst, sz); inet_ntop(addr->sa_family, &sa_in6->sin6_addr, dst, sz);
break; break;
default:
nvnc_log(NVNC_LOG_DEBUG,
"Don't know how to convert sa_family %d to string",
addr->sa_family);
break;
} }
} }
@ -2265,6 +2301,8 @@ struct nvnc* nvnc_client_get_server(const struct nvnc_client* client)
return client->server; return client->server;
} }
// TODO: This function should be renamed to nvnc_client_get_address and it
// should return the sockaddr.
EXPORT EXPORT
const char* nvnc_client_get_hostname(const struct nvnc_client* client) { const char* nvnc_client_get_hostname(const struct nvnc_client* client) {
if (client->hostname[0] == '\0') if (client->hostname[0] == '\0')