-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Linux: Manage routes in a routing table dedicated to ZET. #892
base: main
Are you sure you want to change the base?
Changes from all commits
4f711eb
6262418
831d806
e4a935f
a52fb86
caeff5b
4d99d25
e92f6ae
fd59e95
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,6 +38,15 @@ | |
|
||
#define KEEPALIVE_DELAY 60 | ||
|
||
#ifndef WIN32 | ||
# define closesocket(s) close(s) | ||
#endif /* WIN32 */ | ||
|
||
/** | ||
* Override socket creation | ||
*/ | ||
extern int ziti_tunnel_hosting_socket(/* out */ uv_os_sock_t *, /* in */ const struct addrinfo *); | ||
|
||
/********** hosting **********/ | ||
static void on_bridge_close(uv_handle_t *handle); | ||
|
||
|
@@ -54,13 +63,15 @@ | |
uv_tcp_t tcp; | ||
uv_udp_t udp; | ||
} server; | ||
struct addrinfo *bind_address; | ||
}; | ||
|
||
static void hosted_io_context_free(hosted_io_context io) { | ||
if (io) { | ||
if (io->app_data) { | ||
free_tunneler_app_data_ptr(io->app_data); | ||
} | ||
uv_freeaddrinfo(io->bind_address); | ||
free(io); | ||
} | ||
} | ||
|
@@ -435,9 +446,21 @@ | |
return port_from_config; | ||
} | ||
|
||
static int do_bind(hosted_io_context io, const char *addr, int socktype) { | ||
static int resolve_bind_address(hosted_io_context io, const tunneler_app_data *app_data, int socktype) { | ||
// if app_data includes source ip[:port], verify that it is allowed before attempting to bind | ||
const char *addr; | ||
|
||
if (!app_data || !app_data->source_addr || !app_data->source_addr[0]) | ||
return 0; | ||
|
||
addr = app_data->source_addr; | ||
|
||
// split out the ip and port if port was specified | ||
char *src_ip = strdup(addr); | ||
if (src_ip == NULL) | ||
return UV_ENOMEM; | ||
|
||
// XXX Does this work for IPv6 addresses? | ||
char *port = strchr(src_ip, ':'); | ||
if (port != NULL) { | ||
*port = '\0'; | ||
|
@@ -446,6 +469,7 @@ | |
|
||
uv_getaddrinfo_t ai_req = {0}; | ||
struct addrinfo hints = {0}; | ||
hints.ai_family = AF_UNSPEC; | ||
hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; | ||
hints.ai_protocol = get_protocol_id(io->computed_dst_protocol); | ||
hints.ai_socktype = socktype; | ||
|
@@ -456,7 +480,7 @@ | |
if (uv_err != 0) { | ||
ZITI_LOG(ERROR, "hosted_service[%s], client[%s]: getaddrinfo(%s) failed: %s", | ||
io->service->service_name, io->client_identity, addr, uv_strerror(uv_err)); | ||
return -1; | ||
return uv_err; | ||
} | ||
|
||
if (ai_req.addrinfo->ai_next != NULL) { | ||
|
@@ -469,36 +493,38 @@ | |
if (!address_match(&src_za, &io->service->allowed_source_addresses)) { | ||
ZITI_LOG(ERROR, "hosted_service[%s], client[%s] client requested source IP %s is not allowed", | ||
io->service->service_name, io->client_identity, addr); | ||
return -1; | ||
uv_err = UV_EPERM; | ||
goto free_and_exit; | ||
} | ||
|
||
switch (hints.ai_protocol) { | ||
case IPPROTO_TCP: | ||
uv_err = uv_tcp_bind(&io->server.tcp, ai_req.addrinfo->ai_addr, 0); | ||
break; | ||
case IPPROTO_UDP: | ||
uv_err = uv_udp_bind(&io->server.udp, ai_req.addrinfo->ai_addr, 0); | ||
break; | ||
default: | ||
ZITI_LOG(ERROR, "hosted_service[%s] client[%s] unsupported protocol %d when binding source address", | ||
ZITI_LOG(ERROR, "hosted_service[%s] client[%s] unsupported protocol %d", | ||
io->service->service_name, io->client_identity, hints.ai_protocol); | ||
uv_err = UV_EINVAL; | ||
uv_err = UV_EPROTONOSUPPORT; | ||
goto free_and_exit; | ||
} | ||
|
||
uv_freeaddrinfo(ai_req.addrinfo); | ||
|
||
if (uv_err != 0) { | ||
ZITI_LOG(ERROR, "hosted_service[%s] client[%s]: bind failed: %s", io->service->service_name, | ||
io->client_identity, uv_strerror(uv_err)); | ||
return -1; | ||
} | ||
io->bind_address = ai_req.addrinfo; | ||
|
||
return 0; | ||
|
||
free_and_exit: | ||
uv_freeaddrinfo(ai_req.addrinfo); | ||
return uv_err; | ||
} | ||
|
||
static hosted_io_context hosted_io_context_new(struct hosted_service_ctx_s *service_ctx, ziti_connection client, | ||
tunneler_app_data *app_data, const char *dst_protocol, const char *dst_ip_or_hn, const char *dst_port) { | ||
hosted_io_context io = calloc(1, sizeof(struct hosted_io_ctx_s)); | ||
|
||
if (!io) | ||
return NULL; | ||
|
||
io->service = service_ctx; | ||
|
||
// include underlay details in client identity if available | ||
|
@@ -526,25 +552,21 @@ | |
io->server.udp.data = io; | ||
break; | ||
default: | ||
ZITI_LOG(ERROR, "hosted_service[%s] client[%s] unsupported protocol '%s''", service_ctx->service_name, | ||
io->client_identity, dst_protocol); | ||
free(io); | ||
return NULL; | ||
uv_err = UV_EPROTONOSUPPORT; | ||
} | ||
|
||
if (uv_err != 0) { | ||
ZITI_LOG(ERROR, "hosted_service[%s] client[%s] dst[%s:%s:%s] failed to initialize underlay handle: %s", | ||
service_ctx->service_name, io->client_identity, dst_protocol, dst_ip_or_hn, dst_port, uv_strerror(uv_err)); | ||
free(io); | ||
return NULL; | ||
} | ||
|
||
// uv handle has been initialized and must be closed before freeing `io` now. | ||
|
||
// if app_data includes source ip[:port], verify that it is allowed before attempting to bind | ||
if (app_data && app_data->source_addr && app_data->source_addr[0] != '\0') { | ||
if (do_bind(io, app_data->source_addr, socktype) != 0) { | ||
hosted_server_close(io); | ||
return NULL; | ||
} | ||
if (resolve_bind_address(io, app_data, socktype) != 0) { | ||
hosted_server_close(io); | ||
return NULL; | ||
} | ||
|
||
// success. now set references to ziti connection and app_data so cleanup happens in ziti_conn_close_cb | ||
|
@@ -637,10 +659,14 @@ | |
ZITI_LOG(INFO, "hosted_service[%s] client[%s] dst_addr[%s:%s:%s]: incoming connection", | ||
service_ctx->service_name, io->client_identity, protocol, ip_or_hn, port); | ||
|
||
/** | ||
* make remote_address compatible with supplied bind_address | ||
*/ | ||
struct addrinfo hints = {0}; | ||
hints.ai_family = io->bind_address ? io->bind_address->ai_family : AF_UNSPEC; | ||
hints.ai_protocol = protocol_number; | ||
hints.ai_socktype = protocol_number == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; | ||
hints.ai_flags = AI_NUMERICSERV; | ||
hints.ai_flags = AI_V4MAPPED | AI_NUMERICSERV; | ||
if (is_ip) hints.ai_flags |= AI_NUMERICHOST; | ||
ziti_conn_set_data(clt, io); | ||
|
||
|
@@ -670,6 +696,65 @@ | |
} | ||
} | ||
|
||
static int do_tcp_connect(hosted_io_context io, const struct addrinfo *remote_address, uv_connect_cb cb) | ||
{ | ||
uv_connect_t *request; | ||
uv_os_sock_t sock; | ||
int uv_err; | ||
|
||
if ((request = calloc(1, sizeof *request)) == NULL) | ||
return UV_ENOMEM; | ||
|
||
/** | ||
* remote_address is made compatible with bind_address | ||
*/ | ||
uv_err = ziti_tunnel_hosting_socket(&sock, remote_address); | ||
if (uv_err < 0 && uv_err != UV_ENOSYS) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please log errors for each of the failure paths in this function. It will make it much easier to support users if we know exactly which function failed when something goes wrong. |
||
goto free_request_and_exit; | ||
|
||
if (uv_err == 0 && (uv_err = uv_tcp_open(&io->server.tcp, sock)) < 0) { | ||
(void) closesocket(sock); | ||
goto free_request_and_exit; | ||
} | ||
|
||
if (io->bind_address && (uv_err = uv_tcp_bind(&io->server.tcp, io->bind_address->ai_addr, 0))) | ||
goto free_request_and_exit; | ||
|
||
uv_err = uv_tcp_connect(request, &io->server.tcp, remote_address->ai_addr, cb); | ||
if (uv_err < 0) | ||
goto free_request_and_exit; | ||
|
||
return 0; | ||
|
||
free_request_and_exit: | ||
|
||
free(request); | ||
return uv_err; | ||
} | ||
|
||
static int do_udp_connect(hosted_io_context io, const struct addrinfo *remote_address) | ||
{ | ||
uv_os_sock_t sock; | ||
int uv_err; | ||
|
||
uv_err = ziti_tunnel_hosting_socket(&sock, remote_address); | ||
if (uv_err < 0 && uv_err != UV_ENOSYS) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please log errors for each of the failure paths in this function, also. |
||
return uv_err; | ||
|
||
if (uv_err == 0 && (uv_err = uv_udp_open(&io->server.udp, sock)) < 0) { | ||
(void) closesocket(sock); | ||
return uv_err; | ||
} | ||
|
||
if (io->bind_address && (uv_err = uv_udp_bind(&io->server.udp, io->bind_address->ai_addr, 0)) < 0) | ||
return uv_err; | ||
|
||
if ((uv_err = udp_connect(&io->server.udp, remote_address->ai_addr)) < 0) | ||
Check failure on line 752 in lib/ziti-tunnel-cbs/ziti_hosting.c GitHub Actions / build macOS-x64
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should this be |
||
return uv_err; | ||
|
||
return 0; | ||
} | ||
|
||
static void on_hosted_client_connect_resolved(uv_getaddrinfo_t* ai_req, int status, struct addrinfo* res) { | ||
hosted_io_context io = ai_req->data; | ||
if (io == NULL) { | ||
|
@@ -711,22 +796,18 @@ | |
|
||
switch (res->ai_protocol) { | ||
case IPPROTO_TCP: | ||
{ | ||
uv_connect_t *c = malloc(sizeof(uv_connect_t)); | ||
uv_err = uv_tcp_connect(c, &io->server.tcp, res->ai_addr, on_hosted_tcp_server_connect_complete); | ||
if (uv_err != 0) { | ||
ZITI_LOG(ERROR, "hosted_service[%s], client[%s]: uv_tcp_connect failed: %s", | ||
io->service->service_name, io->client_identity, uv_strerror(uv_err)); | ||
hosted_server_close(io); | ||
free(c); | ||
} | ||
uv_err = do_tcp_connect(io, res, on_hosted_tcp_server_connect_complete); | ||
if (uv_err != 0) { | ||
ZITI_LOG(ERROR, "hosted_service[%s] client[%s]: TCP connection failed: %s", | ||
io->service->service_name, io->client_identity, uv_strerror(uv_err)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should omit the uv error string here, especially if the specific failures are logged in |
||
hosted_server_close(io); | ||
} | ||
break; | ||
case IPPROTO_UDP: | ||
uv_err = uv_udp_connect(&io->server.udp, res->ai_addr); | ||
uv_err = do_udp_connect(io, res); | ||
if (uv_err != 0) { | ||
ZITI_LOG(ERROR, "hosted_service[%s], client[%s]: uv_udp_connect failed: %s", | ||
io->service->service_name, io->client_identity, uv_strerror(uv_err)); | ||
ZITI_LOG(ERROR, "hosted_service[%s] client[%s]: uv_udp_open failed: %s", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's better to log a generic message here (like you did for the TCP case) rather than mention a function that may (or may not) have been the cause of the failure. |
||
io->service->service_name, io->client_identity, uv_strerror(uv_err)); | ||
hosted_server_close(io); | ||
} else if (ziti_accept(io->client, on_hosted_client_connect_complete, NULL) != ZITI_OK) { | ||
ZITI_LOG(ERROR, "ziti_accept failed"); | ||
|
@@ -737,6 +818,9 @@ | |
|
||
uv_freeaddrinfo(res); | ||
free(ai_req); | ||
|
||
uv_freeaddrinfo(io->bind_address); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is it sufficient to let |
||
io->bind_address = NULL; | ||
} | ||
|
||
/** called by ziti SDK when a hosted service listener is ready */ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#include <uv.h> | ||
|
||
extern int ziti_tunnel_hosting_socket(uv_os_sock_t *, const struct addrinfo *ai); | ||
|
||
int | ||
ziti_tunnel_hosting_socket(uv_os_sock_t *sock, const struct addrinfo *ai) | ||
{ | ||
(void) sock; | ||
(void) ai; | ||
return UV_ENOSYS; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is worth logging an ERROR message