Skip to content

Commit

Permalink
ames: add libnatpmp for automatic port forwarding (#593)
Browse files Browse the repository at this point in the history
Same as urbit/urbit#3261 but for vere. From what
I can tell this NAT-PMP stuff is fairly well supported by routers, works
on my machine at least.
  • Loading branch information
pkova authored Apr 24, 2024
2 parents 25a7183 + 68429f6 commit ae89983
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 0 deletions.
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
62 changes: 62 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,51 @@ _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)
{
u3_ames* sam_u = handle->data;

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

uv_poll_stop(handle);

if ( 0 != res_i ) {
u3l_log("ames: natpmp error %i", res_i);
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;

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 +2936,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 @@ -3228,6 +3284,12 @@ 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;
initnatpmp(&sam_u->nat_u.req_u, 0, 0);
uv_timer_init(u3L, &sam_u->nat_u.tim_u);
uv_poll_init(u3L, &sam_u->nat_u.pol_u, sam_u->nat_u.req_u.s);

// 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

0 comments on commit ae89983

Please sign in to comment.