Skip to content

Commit 4555d8d

Browse files
committed
Add PROXY protocol support
1 parent 07bea82 commit 4555d8d

File tree

4 files changed

+71
-6
lines changed

4 files changed

+71
-6
lines changed

docker-entrypoint.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
#!/bin/sh
22
set -e
33

4+
if [ "${USE_PROXY_PROTOCOL}" == "1" ]; then
5+
set -- -x
6+
fi
7+
48
if [ "${HAS_WEBSOCKET}" == "1" ]; then
5-
set -- -x localhost "$@"
9+
set -- -w localhost "$@"
610
fi
711

812
if [ ! -z "${SSH_HOSTNAME}" ]; then

tmate-main.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ struct tmate_settings _tmate_settings = {
4141
.websocket_port = TMATE_DEFAULT_WEBSOCKET_PORT,
4242
.tmate_host = NULL,
4343
.log_level = LOG_NOTICE,
44+
.use_proxy_protocol = false,
4445
.use_syslog = false,
4546
};
4647

@@ -103,7 +104,7 @@ void request_server_termination(void)
103104

104105
static void usage(void)
105106
{
106-
fprintf(stderr, "usage: tmate-ssh-server [-b ip] [-h hostname] [-k keys_dir] [-a authorized_keys_path] [-p port] [-x websocket_hostname] [-q websocket_port] [-s] [-v]\n");
107+
fprintf(stderr, "usage: tmate-ssh-server [-b ip] [-h hostname] [-k keys_dir] [-a authorized_keys_path] [-p port] [-w websocket_hostname] [-q websocket_port] [-x] [-s] [-v]\n");
107108
}
108109

109110
static char* get_full_hostname(void)
@@ -156,7 +157,7 @@ int main(int argc, char **argv, char **envp)
156157
{
157158
int opt;
158159

159-
while ((opt = getopt(argc, argv, "b:h:k:a:p:x:q:sv")) != -1) {
160+
while ((opt = getopt(argc, argv, "b:h:k:a:p:w:q:xsv")) != -1) {
160161
switch (opt) {
161162
case 'b':
162163
tmate_settings->bind_addr = xstrdup(optarg);
@@ -173,12 +174,15 @@ int main(int argc, char **argv, char **envp)
173174
case 'p':
174175
tmate_settings->ssh_port = atoi(optarg);
175176
break;
176-
case 'x':
177+
case 'w':
177178
tmate_settings->websocket_hostname = xstrdup(optarg);
178179
break;
179180
case 'q':
180181
tmate_settings->websocket_port = atoi(optarg);
181182
break;
183+
case 'x':
184+
tmate_settings->use_proxy_protocol = true;
185+
break;
182186
case 's':
183187
tmate_settings->use_syslog = true;
184188
break;

tmate-ssh-server.c

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ static void client_bootstrap(struct tmate_session *_session)
278278
/* never reached */
279279
}
280280

281-
static int get_client_ip(int fd, char *dst, size_t len)
281+
static int get_client_ip_socket(int fd, char *dst, size_t len)
282282
{
283283
struct sockaddr sa;
284284
socklen_t sa_len = sizeof(sa);
@@ -305,6 +305,62 @@ static int get_client_ip(int fd, char *dst, size_t len)
305305
return 0;
306306
}
307307

308+
static void read_single_line(int fd, char *dst, size_t len)
309+
{
310+
/*
311+
* This reads exactly one line from fd.
312+
* We cannot read bytes after the new line.
313+
* We could use recv() with MSG_PEEK to do this more efficiently.
314+
*/
315+
for (size_t i = 0; i < len; i++) {
316+
if (read(fd, &dst[i], 1) <= 0)
317+
break;
318+
319+
if (dst[i] == '\r')
320+
i--;
321+
322+
if (dst[i] == '\n') {
323+
dst[i] = '\0';
324+
return;
325+
}
326+
}
327+
328+
tmate_fatal("Cannot read proxy header. Load balancer may be misconfigured");
329+
}
330+
331+
static int get_client_ip_proxy_protocol(int fd, char *dst, size_t len)
332+
{
333+
char header[110];
334+
const char *signature = "PROXY ";
335+
336+
if (read(fd, header, strlen(signature)) != (ssize_t)strlen(signature))
337+
tmate_fatal("Cannot read proxy header");
338+
339+
if (memcmp(header, signature, strlen(signature)))
340+
tmate_fatal("No proxy header found. Load balancer may be misconfigured");
341+
342+
read_single_line(fd, header, sizeof(header));
343+
344+
int tok_num = 0;
345+
for (char *tok = strtok(header, " "); tok; tok = strtok(NULL, " "), tok_num++) {
346+
if (tok_num == 1)
347+
strncpy(dst, tok, len);
348+
}
349+
350+
if (tok_num != 5)
351+
tmate_fatal("Proxy header is invalid");
352+
353+
return 0;
354+
}
355+
356+
static int get_client_ip(int fd, char *dst, size_t len)
357+
{
358+
if (tmate_settings->use_proxy_protocol)
359+
return get_client_ip_proxy_protocol(fd, dst, len);
360+
else
361+
return get_client_ip_socket(fd, dst, len);
362+
}
363+
308364
static void ssh_log_function(int priority, const char *function,
309365
const char *buffer, __unused void *userdata)
310366
{
@@ -426,7 +482,7 @@ void tmate_ssh_server_main(struct tmate_session *session, const char *keys_dir,
426482
alarm(TMATE_SSH_GRACE_PERIOD);
427483

428484
if (get_client_ip(fd, client->ip_address, sizeof(client->ip_address)) < 0)
429-
tmate_fatal("Error getting Client IP from connection");
485+
tmate_fatal("Error getting client IP from connection");
430486

431487
tmate_info("Connection accepted ip=%s", client->ip_address);
432488

tmate.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ struct tmate_settings {
216216
const char *tmate_host;
217217
const char *bind_addr;
218218
int log_level;
219+
bool use_proxy_protocol;
219220
bool use_syslog;
220221
};
221222
extern struct tmate_settings *tmate_settings;

0 commit comments

Comments
 (0)