Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions WORKSPACE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,15 @@ versioned_http_file(
version = "721fa05",
)

versioned_http_archive(
name = "natpmp",
build_file = "//bazel/third_party/natpmp:natpmp.BUILD",
sha256 = "0684ed2c8406437e7519a1bd20ea83780db871b3a3a5d752311ba3e889dbfc70",
strip_prefix = "libnatpmp-{version}",
url = "http://miniupnp.free.fr/files/libnatpmp-{version}.tar.gz",
version = "20230423",
)

versioned_http_file(
name = "solid_pill",
sha256 = "8b658fcee6978e2b19004a54233cab953e77ea0bb6c3a04d1bfda4ddc6be63c5",
Expand Down
Empty file.
8 changes: 8 additions & 0 deletions bazel/third_party/natpmp/natpmp.BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
cc_library(
name = "natpmp",
srcs = ["natpmp.c", "getgateway.c"],
hdrs = ["natpmp.h", "getgateway.h", "natpmp_declspec.h"],
copts = ["-O3"],
linkstatic = True,
visibility = ["//visibility:public"],
)
1 change: 1 addition & 0 deletions pkg/vere/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ vere_library(
"@lmdb",
"@openssl",
"@uv",
"@natpmp",
] + select({
"@platforms//os:macos": [],
"@platforms//os:linux": [
Expand Down
84 changes: 84 additions & 0 deletions pkg/vere/io/ames.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "ur.h"

#include "zlib.h"
#include "natpmp.h"

#include <ent.h>

Expand Down Expand Up @@ -71,6 +72,11 @@ typedef enum u3_stun_state {
u3_lane sef_u; // our lane, if we know it
c3_o wok_o; // STUN worked, set on first success
} sun_u; //
struct {
natpmp_t req_u; // libnatpmp struct for mapping request
uv_poll_t pol_u; // handle waits on libnatpmp socket
uv_timer_t tim_u; // every two hours if mapping succeeds
} nat_u; // libnatpmp stuff for port forwarding
c3_o nal_o; // lane cache backcompat flag
struct { // config:
c3_o net_o; // can send
Expand Down Expand Up @@ -2765,6 +2771,69 @@ _ames_recv_cb(uv_udp_t* wax_u,
}
}

static void natpmp_init(uv_timer_t* handle);

static void
natpmp_cb(uv_poll_t* handle,
c3_i status,
c3_i events)
{
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're not checking status for errors here. And I'm not sure if readnatpmpresponseorretry() can/will handle all cases for us.


if (status != 0) {
return;
}

u3_ames* sam_u = handle->data;

natpmpresp_t response;
c3_i err_i = readnatpmpresponseorretry(&sam_u->nat_u.req_u, &response);
if ( NATPMP_TRYAGAIN == err_i ) {
return;
}

uv_poll_stop(handle);

if ( 0 != err_i ) {
u3l_log("ames: natpmp error %i", err_i);
uv_poll_stop(&sam_u->nat_u.pol_u);
closenatpmp(&sam_u->nat_u.req_u);
return;
}

u3l_log("ames: mapped public port %hu to localport %hu lifetime %u",
response.pnu.newportmapping.mappedpublicport,
response.pnu.newportmapping.privateport,
response.pnu.newportmapping.lifetime);

closenatpmp(&sam_u->nat_u.req_u);
sam_u->nat_u.tim_u.data = sam_u;
uv_timer_start(&sam_u->nat_u.tim_u, natpmp_init, 7200000, 0);
}

static void
natpmp_init(uv_timer_t *handle)
{
u3_ames* sam_u = handle->data;
c3_s por_s = sam_u->pir_u->por_s;

c3_i err_i = initnatpmp(&sam_u->nat_u.req_u, 0, 0);

if (err_i != 0) {
return;
}

err_i = uv_poll_init(u3L, &sam_u->nat_u.pol_u, sam_u->nat_u.req_u.s);

if (err_i != 0) {
return;
}

sendnewportmappingrequest(&sam_u->nat_u.req_u, NATPMP_PROTOCOL_UDP, por_s, por_s, 7200);

sam_u->nat_u.pol_u.data = sam_u;
uv_poll_start(&sam_u->nat_u.pol_u, UV_READABLE, natpmp_cb);
}

static void
_mdns_dear_bail(u3_ovum* egg_u, u3_noun lud)
{
Expand Down Expand Up @@ -2885,6 +2954,11 @@ _ames_io_start(u3_ames* sam_u)
u3z(our);

mdns_init(por_s, !sam_u->pir_u->fak_o, our_s, _ames_put_dear, (void *)sam_u);

if ( c3n == sam_u->pir_u->fak_o ) {
uv_timer_start(&sam_u->nat_u.tim_u, natpmp_init, 0, 0);
}

c3_free(our_s);
}

Expand Down Expand Up @@ -3126,6 +3200,12 @@ _ames_io_exit(u3_auto* car_u)
uv_close(&sam_u->had_u, _ames_exit_cb);
uv_close((uv_handle_t*)&sam_u->sun_u.dns_u, 0);
uv_close((uv_handle_t*)&sam_u->sun_u.tim_u, 0);
uv_close((uv_handle_t*)&sam_u->nat_u.tim_u, 0);

uv_handle_type handle = uv_handle_get_type((uv_handle_t *)&sam_u->nat_u.pol_u);
if ( UV_UNKNOWN_HANDLE != handle) {
uv_close((uv_handle_t*)&sam_u->nat_u.pol_u, 0);
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this is quite right -- the definition of "active" for different handle types is fairly involved. What we actually want is just "has this handle every been initialized?". We can obviously track that ourselves, but I think this will also work:

if ( UV_UNKNOWN_HANDLE != uv_handle_get_type(&sam_u->nat_u.pol_u) ) {
  uv_close(...)
}

UV_UNKNOWN_HANDLE is 0, and we zero-initialize the uv_poll_t struct by virtue of allocating the u3_ames struct with c3_calloc().

}

/* _ames_io_info(): produce status info.
Expand Down Expand Up @@ -3228,6 +3308,10 @@ u3_ames_io_init(u3_pier* pir_u)
sam_u->sun_u.tim_u.data = sam_u;
sam_u->sun_u.dns_u.data = sam_u;

// initialize libnatpmp
sam_u->nat_u.tim_u.data = sam_u;
uv_timer_init(u3L, &sam_u->nat_u.tim_u);

// enable forwarding on galaxies only
u3_noun who = u3i_chubs(2, sam_u->pir_u->who_d);
u3_noun rac = u3do("clan:title", who);
Expand Down