diff --git a/book/api/metrics-generated.md b/book/api/metrics-generated.md
index c02bc40c972..9c74eccc5fc 100644
--- a/book/api/metrics-generated.md
+++ b/book/api/metrics-generated.md
@@ -900,6 +900,7 @@
| snapct_predicted_slot | gauge | The predicted slot from which replay starts after snapshot loading finishes. Might change if snapshot load is aborted and restarted |
| snapct_gossip_fresh_count | gauge | Number of fresh gossip peers seen when collecting gossip peers. |
| snapct_gossip_total_count | gauge | Number of total gossip peers seen when collecting gossip peers. |
+| snapct_ssl_alloc_errors | counter | Number of SSL allocation errors encountered. |
@@ -910,6 +911,7 @@
| Metric | Type | Description |
|--------|------|-------------|
| snapld_state | gauge | State of the tile. 0=IDLE, 1=PROCESSING, 2=FINISHING, 3=ERROR, 4=SHUTDOWN |
+| snapld_ssl_alloc_errors | counter | Number of SSL allocation errors encountered. |
@@ -1200,6 +1202,5 @@
| tower_hard_forks_seen | counter | Number of hard forks we've seen (block ids with multiple candidate bank hashes) |
| tower_hard_forks_pruned | counter | Number of hard forks (candidate bank hashes) we've pruned |
| tower_hard_forks_active | gauge | Currently active hard forks |
-| tower_hard_forks_max_width | gauge | The max width of hard forks (block id with most candidate bank hashes) we've ever seen |
diff --git a/deps.sh b/deps.sh
index cc7b3a7de61..c69b49c4f4e 100755
--- a/deps.sh
+++ b/deps.sh
@@ -505,10 +505,10 @@ install_openssl () {
echo "[+] Configuring OpenSSL"
./config \
- -static \
-fPIC \
--prefix="$PREFIX" \
--libdir=lib \
+ threads \
no-engine \
no-static-engine \
no-weak-ssl-ciphers \
diff --git a/src/app/firedancer/config/testnet.toml b/src/app/firedancer/config/testnet.toml
index 829d3b0a232..8cfff59748a 100644
--- a/src/app/firedancer/config/testnet.toml
+++ b/src/app/firedancer/config/testnet.toml
@@ -10,7 +10,7 @@
max_account_records = 200_000_000
[snapshots]
[snapshots.sources]
- servers = [ "http://solana-testnet-rpc.jumpisolated.com:8899" ]
+ servers = [ "http://solana-testnet-rpc.jumpisolated.com:8899", "https://solana-testnet-tls.jumpisolated.com" ]
[snapshots.sources.gossip]
allow_any = false
allow_list = []
diff --git a/src/app/firedancer/topology.c b/src/app/firedancer/topology.c
index 374cf67acdd..17b949eda21 100644
--- a/src/app/firedancer/topology.c
+++ b/src/app/firedancer/topology.c
@@ -185,6 +185,9 @@ setup_topo_vinyl_cache( fd_topo_t * topo,
return line_obj;
}
+/* Resolves a hostname to a single ip address. If multiple ip address
+ records are returned by getaddrinfo, only the first IPV4 address is
+ returned via ip_addr. */
static int
resolve_address( char const * address,
uint * ip_addr ) {
@@ -209,43 +212,98 @@ resolve_address( char const * address,
return resolved;
}
+/* Resolves a hostname to multiple ip addresses, specified by
+ ip_addr_cnt. ip_addrs points to an array of fd_ip4_port_t objects.
+ hints points to an optionally NULL addrinfo hints object. If hints
+ is NULL, a default hints settings containing the IPV4 address family
+ hint will be used. */
static int
-resolve_peer( char const * peer,
- fd_ip4_port_t * ip4_port ) {
+resolve_addresses( char const * address,
+ struct addrinfo const * hints,
+ fd_ip4_port_t * ip_addrs,
+ ulong ip_addr_cnt ) {
+ struct addrinfo default_hints = { .ai_family = AF_INET };
+ if( FD_UNLIKELY( !hints ) ) {
+ hints = &default_hints;
+ }
+
+ struct addrinfo * res;
+ int err = getaddrinfo( address, NULL, hints, &res );
+ if( FD_UNLIKELY( err ) ) {
+ FD_LOG_WARNING(( "cannot resolve address \"%s\": %i-%s", address, err, gai_strerror( err ) ));
+ return 0;
+ }
+
+ int resolved = 0;
+ for( struct addrinfo * cur=res; cur; cur=cur->ai_next ) {
+ if( FD_UNLIKELY( (ulong)resolved>=ip_addr_cnt ) ) break;
+ if( FD_UNLIKELY( cur->ai_addr->sa_family!=AF_INET ) ) continue;
+ struct sockaddr_in const * addr = (struct sockaddr_in const *)cur->ai_addr;
+ ip_addrs[ resolved ].addr = addr->sin_addr.s_addr;
+ resolved++;
+ }
+
+ freeaddrinfo( res );
+ return resolved;
+}
+
+static int
+resolve_peer( char const * peer,
+ struct addrinfo const * addr_resolve_hints,
+ char const * config_str,
+ char hostname[ static 256UL ],
+ fd_ip4_port_t * ip4_port,
+ ulong ip4_port_cnt,
+ int * is_https ) {
/* Split host:port */
+ int https = 0;
char const * host_port = peer;
if( FD_LIKELY( strncmp( peer, "http://", 7UL )==0 ) ) {
+ if( FD_LIKELY( is_https ) ) *is_https = 0;
host_port += 7UL;
} else if( FD_LIKELY( strncmp( peer, "https://", 8UL )==0 ) ) {
+ if( FD_LIKELY( is_https ) ) *is_https = 1;
host_port += 8UL;
+ https = 1;
}
- char const * colon = strrchr( host_port, ':' );
- if( FD_UNLIKELY( !colon ) ) {
- FD_LOG_ERR(( "invalid [gossip.entrypoints] entry \"%s\": no port number", host_port ));
+ char const * colon = strrchr( host_port, ':' );
+ char const * host_end = colon;
+ if( FD_LIKELY( FD_UNLIKELY( !colon && !https ) ) ) {
+ FD_LOG_ERR(( "invalid [%s] entry \"%s\": no port number", config_str, host_port ));
+ host_end = colon;
+ } else if( FD_LIKELY( !colon && https ) ) {
+ host_end = host_port + strlen( host_port );
}
- char fqdn[ 255 ];
- ulong fqdn_len = (ulong)( colon-host_port );
- if( FD_UNLIKELY( fqdn_len>254 ) ) {
- FD_LOG_ERR(( "invalid [gossip.entrypoints] entry \"%s\": hostname too long", host_port ));
+ ulong fqdn_len = (ulong)( host_end-host_port );
+ if( FD_UNLIKELY( fqdn_len>255 ) ) {
+ FD_LOG_ERR(( "invalid [%s] entry \"%s\": hostname too long", config_str, host_port ));
}
- fd_memcpy( fqdn, host_port, fqdn_len );
- fqdn[ fqdn_len ] = '\0';
+ fd_memcpy( hostname, host_port, fqdn_len );
+ hostname[ fqdn_len ] = '\0';
+
+ /* Resolve hostname */
+ int resolved = resolve_addresses( hostname, addr_resolve_hints, ip4_port, ip4_port_cnt );
/* Parse port number */
- char const * port_str = colon+1;
- char const * endptr = NULL;
- ulong port = strtoul( port_str, (char **)&endptr, 10 );
- if( FD_UNLIKELY( !endptr || !port || port>USHORT_MAX || *endptr!='\0' ) ) {
- FD_LOG_ERR(( "invalid [gossip.entrypoints] entry \"%s\": invalid port number", host_port ));
+ if( FD_LIKELY( colon ) ) {
+ char const * port_str = host_end+1;
+ char const * endptr = NULL;
+ ulong port = strtoul( port_str, (char **)&endptr, 10 );
+ if( FD_UNLIKELY( endptr==port_str || !port || port>USHORT_MAX || *endptr!='\0' ) ) {
+ FD_LOG_ERR(( "invalid [%s] entry \"%s\": invalid port number", config_str, host_port ));
+ }
+ for( ulong i=0UL; i<(ulong)resolved; i++ ) ip4_port[ i ].port = fd_ushort_bswap( (ushort)port );
+ } else if( FD_LIKELY( !colon && https ) ) {
+ /* use default https port */
+ for( ulong i=0UL; i<(ulong)resolved; i++ ) ip4_port[ i ].port = fd_ushort_bswap( 443U );
+ } else {
+ FD_LOG_ERR(( "invalid [%s] entry \"%s\": no port number", config_str, host_port ));
}
- ip4_port->port = (ushort)fd_ushort_bswap( (ushort)port );
- /* Resolve hostname */
- int resolved = resolve_address( fqdn, &ip4_port->addr );
return resolved;
}
@@ -253,7 +311,8 @@ static void
resolve_gossip_entrypoints( config_t * config ) {
ulong entrypoint_cnt = config->gossip.entrypoints_cnt;
for( ulong i=0UL; igossip.entrypoints[ i ], &config->gossip.resolved_entrypoints[ i ] ) ) ) {
+ char hostname[ 256UL ];
+ if( FD_UNLIKELY( 0==resolve_peer( config->gossip.entrypoints[ i ], NULL, "gossip.entrypoints", hostname, &config->gossip.resolved_entrypoints[ i ], 1, NULL ) ) ) {
FD_LOG_ERR(( "failed to resolve address of [gossip.entrypoints] entry \"%s\"", config->gossip.entrypoints[ i ] ));
}
}
@@ -1080,12 +1139,32 @@ fd_topo_configure_tile( fd_topo_tile_t * tile,
FD_LOG_ERR(( "[snapshots.sources.gossip.block_list[%lu] invalid (%s)", i, config->firedancer.snapshots.sources.gossip.block_list[ i ] ));
}
}
+
+ ulong resolved_peers_cnt = 0UL;
for( ulong i=0UL; isnapct.sources.servers_cnt; i++ ) {
- if( FD_UNLIKELY( !resolve_peer( config->firedancer.snapshots.sources.servers[ i ], &tile->snapct.sources.servers[ i ] ) ) ) {
+ fd_ip4_port_t resolved_addrs[ FD_TOPO_MAX_RESOLVED_ADDRS ];
+ struct addrinfo hints = { .ai_family = AF_INET, .ai_socktype = SOCK_STREAM };
+ int num_resolved = resolve_peer( config->firedancer.snapshots.sources.servers[ i ],
+ &hints,
+ "snapshots.sources.servers",
+ tile->snapct.sources.servers[ resolved_peers_cnt ].hostname,
+ resolved_addrs,
+ FD_TOPO_MAX_RESOLVED_ADDRS,
+ &tile->snapct.sources.servers[ resolved_peers_cnt ].is_https );
+ if( FD_UNLIKELY( 0==num_resolved ) ) {
FD_LOG_ERR(( "[snapshots.sources.servers[%lu] invalid (%s)", i, config->firedancer.snapshots.sources.servers[ i ] ));
+ } else {
+ for( ulong i=0UL; i<(ulong)num_resolved; i++ ) tile->snapct.sources.servers[ resolved_peers_cnt+i ].addr = resolved_addrs[ i ];
+ for( ulong i=1UL; i<(ulong)num_resolved; i++ ) {
+ tile->snapct.sources.servers[ resolved_peers_cnt+i ].is_https = tile->snapct.sources.servers[ resolved_peers_cnt ].is_https;
+ fd_memcpy( tile->snapct.sources.servers[ resolved_peers_cnt+i ].hostname,
+ tile->snapct.sources.servers[ resolved_peers_cnt ].hostname,
+ sizeof(tile->snapct.sources.servers[ resolved_peers_cnt ].hostname) );
+ }
+ resolved_peers_cnt += (ulong)num_resolved;
}
}
-
+ tile->snapct.sources.servers_cnt = resolved_peers_cnt;
} else if( FD_UNLIKELY( !strcmp( tile->name, "snapld" ) ) ) {
fd_memcpy( tile->snapld.snapshots_path, config->paths.snapshots, PATH_MAX );
diff --git a/src/disco/bundle/fd_bundle_tile.c b/src/disco/bundle/fd_bundle_tile.c
index c669f47e8bd..88d99401714 100644
--- a/src/disco/bundle/fd_bundle_tile.c
+++ b/src/disco/bundle/fd_bundle_tile.c
@@ -5,6 +5,7 @@
#include "../keyguard/fd_keyload.h"
#include "../plugin/fd_plugin.h"
#include "../../waltz/http/fd_url.h"
+#include "../../waltz/openssl/fd_openssl_tile.h"
#include
#include /* opendir */
@@ -55,6 +56,9 @@ metrics_write( fd_bundle_tile_t * ctx ) {
FD_MCNT_SET( BUNDLE, ERRORS_PROTOBUF, ctx->metrics.decode_fail_cnt );
FD_MCNT_SET( BUNDLE, ERRORS_TRANSPORT, ctx->metrics.transport_fail_cnt );
FD_MCNT_SET( BUNDLE, ERRORS_NO_FEE_INFO, ctx->metrics.missing_builder_info_fail_cnt );
+#if FD_HAS_OPENSSL
+ FD_MCNT_SET( BUNDLE, ERRORS_SSL_ALLOC, fd_ossl_alloc_errors );
+#endif
FD_MGAUGE_SET( BUNDLE, RTT_SAMPLE, (ulong)ctx->rtt->latest_rtt );
FD_MGAUGE_SET( BUNDLE, RTT_SMOOTHED, (ulong)ctx->rtt->smoothed_rtt );
@@ -247,65 +251,6 @@ fd_bundle_tile_parse_endpoint( fd_bundle_tile_t * ctx,
#if FD_HAS_OPENSSL
-/* OpenSSL allows us to specify custom memory allocation functions,
- which we want to point to an fd_alloc_t, but it does not let us use a
- context object. Instead we stash it in this thread local, which is
- OK because the parent workspace exists for the duration of the SSL
- context, and the process only has one thread.
-
- Currently fd_alloc doesn't support realloc, so it's implemented on
- top of malloc and free, and then also it doesn't support getting the
- size of an allocation from the pointer, which we need for realloc, so
- we pad each alloc by 8 bytes and stuff the size into the first 8
- bytes. */
-static FD_TL fd_alloc_t * fd_quic_ssl_mem_function_ctx = NULL;
-
-static void *
-crypto_malloc( ulong num,
- char const * file,
- int line ) {
- (void)file; (void)line;
- void * result = fd_alloc_malloc( fd_quic_ssl_mem_function_ctx, 16UL, num + 8UL );
- if( FD_UNLIKELY( !result ) ) {
- FD_MCNT_INC( BUNDLE, ERRORS_SSL_ALLOC, 1UL );
- return NULL;
- }
- *(ulong *)result = num;
- return (uchar *)result + 8UL;
-}
-
-static void
-crypto_free( void * addr,
- char const * file,
- int line ) {
- (void)file;
- (void)line;
-
- if( FD_UNLIKELY( !addr ) ) return;
- fd_alloc_free( fd_quic_ssl_mem_function_ctx, (uchar *)addr - 8UL );
-}
-
-static void *
-crypto_realloc( void * addr,
- ulong num,
- char const * file,
- int line ) {
- if( FD_UNLIKELY( !addr ) ) return crypto_malloc( num, file, line );
- if( FD_UNLIKELY( !num ) ) {
- crypto_free( addr, file, line );
- return NULL;
- }
-
- void * new = fd_alloc_malloc( fd_quic_ssl_mem_function_ctx, 16UL, num + 8UL );
- if( FD_UNLIKELY( !new ) ) return NULL;
-
- ulong old_num = *(ulong *)( (uchar *)addr - 8UL );
- fd_memcpy( (uchar*)new + 8, (uchar*)addr, fd_ulong_min( old_num, num ) );
- fd_alloc_free( fd_quic_ssl_mem_function_ctx, (uchar *)addr - 8UL );
- *(ulong *)new = num;
- return (uchar*)new + 8UL;
-}
-
static void
fd_ossl_keylog_callback( SSL const * ssl,
char const * line ) {
@@ -321,58 +266,6 @@ fd_ossl_keylog_callback( SSL const * ssl,
}
}
-static void
-fd_bundle_tile_load_certs( SSL_CTX * ssl_ctx ) {
- X509_STORE * ca_certs = X509_STORE_new();
- if( FD_UNLIKELY( !ca_certs ) ) {
- FD_LOG_ERR(( "X509_STORE_new failed" ));
- }
-
- static char const default_dir[] = "/etc/ssl/certs/";
- DIR * dir = opendir( default_dir );
- if( FD_UNLIKELY( !dir ) ) {
- FD_LOG_ERR(( "opendir(%s) failed (%i-%s)", default_dir, errno, fd_io_strerror( errno ) ));
- }
-
- struct dirent * entry;
- errno = 0; // clear old value since entry can be NULL when reaching end of directory.
- while( (entry = readdir( dir )) ) {
- if( !strcmp( entry->d_name, "." ) || !strcmp( entry->d_name, ".." ) ) continue;
-
- char cert_path[ PATH_MAX ];
- char * p = fd_cstr_init( cert_path );
- p = fd_cstr_append_text( p, default_dir, sizeof(default_dir)-1 );
- p = fd_cstr_append_cstr_safe( p, entry->d_name, (ulong)(cert_path+sizeof(cert_path)-1) - (ulong)p );
- fd_cstr_fini( p );
-
- if( !X509_STORE_load_locations( ca_certs, cert_path, NULL ) ) {
- /* Not all files in /etc/ssl/certs are valid certs, so ignore errors */
- continue;
- }
- errno = 0;
- }
-
- if( FD_UNLIKELY( errno && errno!=ENOENT ) ) {
- FD_LOG_ERR(( "readdir(%s) failed (%i-%s)", default_dir, errno, fd_io_strerror( errno ) ));
- }
-
- STACK_OF(X509) * cert_list = X509_STORE_get1_all_certs( ca_certs );
- FD_LOG_INFO(( "Loaded %d CA certs from %s into OpenSSL", sk_X509_num( cert_list ), default_dir ));
- if( fd_log_level_logfile()==0 ) {
- for( int i=0; issl_alloc = alloc;
- fd_quic_ssl_mem_function_ctx = alloc;
-
- if( FD_UNLIKELY( !CRYPTO_set_mem_functions( crypto_malloc, crypto_realloc, crypto_free ) ) ) {
- FD_LOG_ERR(( "CRYPTO_set_mem_functions failed" ));
- }
-
- OPENSSL_init_ssl(
- OPENSSL_INIT_LOAD_SSL_STRINGS |
- OPENSSL_INIT_LOAD_CRYPTO_STRINGS |
- OPENSSL_INIT_NO_LOAD_CONFIG,
- NULL
- );
+ ctx->ssl_alloc = alloc;
+ fd_ossl_tile_init( alloc );
SSL_CTX * ssl_ctx = SSL_CTX_new( TLS_client_method() );
if( FD_UNLIKELY( !ssl_ctx ) ) {
@@ -417,8 +299,7 @@ fd_bundle_tile_init_openssl( fd_bundle_tile_t * ctx,
}
if( tls_cert_verify ) {
- fd_bundle_tile_load_certs( ssl_ctx );
- SSL_CTX_set_verify( ssl_ctx, SSL_VERIFY_PEER, NULL );
+ fd_ossl_load_certs( ssl_ctx );
}
if( FD_LIKELY( ctx->keylog_fd >= 0 ) ) {
diff --git a/src/disco/metrics/generated/fd_metrics_snapct.c b/src/disco/metrics/generated/fd_metrics_snapct.c
index ba035bbae8d..25d8beddf28 100644
--- a/src/disco/metrics/generated/fd_metrics_snapct.c
+++ b/src/disco/metrics/generated/fd_metrics_snapct.c
@@ -16,4 +16,5 @@ const fd_metrics_meta_t FD_METRICS_SNAPCT[FD_METRICS_SNAPCT_TOTAL] = {
DECLARE_METRIC( SNAPCT_PREDICTED_SLOT, GAUGE ),
DECLARE_METRIC( SNAPCT_GOSSIP_FRESH_COUNT, GAUGE ),
DECLARE_METRIC( SNAPCT_GOSSIP_TOTAL_COUNT, GAUGE ),
+ DECLARE_METRIC( SNAPCT_SSL_ALLOC_ERRORS, COUNTER ),
};
diff --git a/src/disco/metrics/generated/fd_metrics_snapct.h b/src/disco/metrics/generated/fd_metrics_snapct.h
index a93a8f9a5cb..7665799d915 100644
--- a/src/disco/metrics/generated/fd_metrics_snapct.h
+++ b/src/disco/metrics/generated/fd_metrics_snapct.h
@@ -90,7 +90,13 @@
#define FD_METRICS_GAUGE_SNAPCT_GOSSIP_TOTAL_COUNT_DESC "Number of total gossip peers seen when collecting gossip peers."
#define FD_METRICS_GAUGE_SNAPCT_GOSSIP_TOTAL_COUNT_CVT (FD_METRICS_CONVERTER_NONE)
-#define FD_METRICS_SNAPCT_TOTAL (14UL)
+#define FD_METRICS_COUNTER_SNAPCT_SSL_ALLOC_ERRORS_OFF (30UL)
+#define FD_METRICS_COUNTER_SNAPCT_SSL_ALLOC_ERRORS_NAME "snapct_ssl_alloc_errors"
+#define FD_METRICS_COUNTER_SNAPCT_SSL_ALLOC_ERRORS_TYPE (FD_METRICS_TYPE_COUNTER)
+#define FD_METRICS_COUNTER_SNAPCT_SSL_ALLOC_ERRORS_DESC "Number of SSL allocation errors encountered."
+#define FD_METRICS_COUNTER_SNAPCT_SSL_ALLOC_ERRORS_CVT (FD_METRICS_CONVERTER_NONE)
+
+#define FD_METRICS_SNAPCT_TOTAL (15UL)
extern const fd_metrics_meta_t FD_METRICS_SNAPCT[FD_METRICS_SNAPCT_TOTAL];
#endif /* HEADER_fd_src_disco_metrics_generated_fd_metrics_snapct_h */
diff --git a/src/disco/metrics/generated/fd_metrics_snapld.c b/src/disco/metrics/generated/fd_metrics_snapld.c
index 78f8a09f587..53c048b8014 100644
--- a/src/disco/metrics/generated/fd_metrics_snapld.c
+++ b/src/disco/metrics/generated/fd_metrics_snapld.c
@@ -3,4 +3,5 @@
const fd_metrics_meta_t FD_METRICS_SNAPLD[FD_METRICS_SNAPLD_TOTAL] = {
DECLARE_METRIC( SNAPLD_STATE, GAUGE ),
+ DECLARE_METRIC( SNAPLD_SSL_ALLOC_ERRORS, COUNTER ),
};
diff --git a/src/disco/metrics/generated/fd_metrics_snapld.h b/src/disco/metrics/generated/fd_metrics_snapld.h
index 8add394913c..ebab731af55 100644
--- a/src/disco/metrics/generated/fd_metrics_snapld.h
+++ b/src/disco/metrics/generated/fd_metrics_snapld.h
@@ -12,7 +12,13 @@
#define FD_METRICS_GAUGE_SNAPLD_STATE_DESC "State of the tile. 0=IDLE, 1=PROCESSING, 2=FINISHING, 3=ERROR, 4=SHUTDOWN"
#define FD_METRICS_GAUGE_SNAPLD_STATE_CVT (FD_METRICS_CONVERTER_NONE)
-#define FD_METRICS_SNAPLD_TOTAL (1UL)
+#define FD_METRICS_COUNTER_SNAPLD_SSL_ALLOC_ERRORS_OFF (17UL)
+#define FD_METRICS_COUNTER_SNAPLD_SSL_ALLOC_ERRORS_NAME "snapld_ssl_alloc_errors"
+#define FD_METRICS_COUNTER_SNAPLD_SSL_ALLOC_ERRORS_TYPE (FD_METRICS_TYPE_COUNTER)
+#define FD_METRICS_COUNTER_SNAPLD_SSL_ALLOC_ERRORS_DESC "Number of SSL allocation errors encountered."
+#define FD_METRICS_COUNTER_SNAPLD_SSL_ALLOC_ERRORS_CVT (FD_METRICS_CONVERTER_NONE)
+
+#define FD_METRICS_SNAPLD_TOTAL (2UL)
extern const fd_metrics_meta_t FD_METRICS_SNAPLD[FD_METRICS_SNAPLD_TOTAL];
#endif /* HEADER_fd_src_disco_metrics_generated_fd_metrics_snapld_h */
diff --git a/src/disco/metrics/generated/fd_metrics_tower.c b/src/disco/metrics/generated/fd_metrics_tower.c
index 89fd394d404..13ce7ab6fb6 100644
--- a/src/disco/metrics/generated/fd_metrics_tower.c
+++ b/src/disco/metrics/generated/fd_metrics_tower.c
@@ -16,5 +16,4 @@ const fd_metrics_meta_t FD_METRICS_TOWER[FD_METRICS_TOWER_TOTAL] = {
DECLARE_METRIC( TOWER_HARD_FORKS_SEEN, COUNTER ),
DECLARE_METRIC( TOWER_HARD_FORKS_PRUNED, COUNTER ),
DECLARE_METRIC( TOWER_HARD_FORKS_ACTIVE, GAUGE ),
- DECLARE_METRIC( TOWER_HARD_FORKS_MAX_WIDTH, GAUGE ),
};
diff --git a/src/disco/metrics/generated/fd_metrics_tower.h b/src/disco/metrics/generated/fd_metrics_tower.h
index 332b04fa022..8de9e4272f7 100644
--- a/src/disco/metrics/generated/fd_metrics_tower.h
+++ b/src/disco/metrics/generated/fd_metrics_tower.h
@@ -90,13 +90,7 @@
#define FD_METRICS_GAUGE_TOWER_HARD_FORKS_ACTIVE_DESC "Currently active hard forks"
#define FD_METRICS_GAUGE_TOWER_HARD_FORKS_ACTIVE_CVT (FD_METRICS_CONVERTER_NONE)
-#define FD_METRICS_GAUGE_TOWER_HARD_FORKS_MAX_WIDTH_OFF (30UL)
-#define FD_METRICS_GAUGE_TOWER_HARD_FORKS_MAX_WIDTH_NAME "tower_hard_forks_max_width"
-#define FD_METRICS_GAUGE_TOWER_HARD_FORKS_MAX_WIDTH_TYPE (FD_METRICS_TYPE_GAUGE)
-#define FD_METRICS_GAUGE_TOWER_HARD_FORKS_MAX_WIDTH_DESC "The max width of hard forks (block id with most candidate bank hashes) we've ever seen"
-#define FD_METRICS_GAUGE_TOWER_HARD_FORKS_MAX_WIDTH_CVT (FD_METRICS_CONVERTER_NONE)
-
-#define FD_METRICS_TOWER_TOTAL (15UL)
+#define FD_METRICS_TOWER_TOTAL (14UL)
extern const fd_metrics_meta_t FD_METRICS_TOWER[FD_METRICS_TOWER_TOTAL];
#endif /* HEADER_fd_src_disco_metrics_generated_fd_metrics_tower_h */
diff --git a/src/disco/metrics/metrics.xml b/src/disco/metrics/metrics.xml
index 7eac549fa2e..a2e6f5c2dd8 100644
--- a/src/disco/metrics/metrics.xml
+++ b/src/disco/metrics/metrics.xml
@@ -1039,10 +1039,12 @@ metric introduced.
+
+
diff --git a/src/disco/topo/fd_topo.h b/src/disco/topo/fd_topo.h
index 4d1f6bce059..4c1f0e9a5aa 100644
--- a/src/disco/topo/fd_topo.h
+++ b/src/disco/topo/fd_topo.h
@@ -516,8 +516,10 @@ struct fd_topo_tile {
int slices_fd;
} shredcap;
-#define FD_TOPO_SNAPSHOTS_GOSSIP_LIST_MAX (32UL)
-#define FD_TOPO_SNAPSHOTS_SERVERS_MAX (16UL)
+#define FD_TOPO_SNAPSHOTS_GOSSIP_LIST_MAX (32UL)
+#define FD_TOPO_SNAPSHOTS_SERVERS_MAX (16UL)
+#define FD_TOPO_MAX_RESOLVED_ADDRS ( 4UL)
+#define FD_TOPO_SNAPSHOTS_SERVERS_MAX_RESOLVED (FD_TOPO_MAX_RESOLVED_ADDRS*FD_TOPO_SNAPSHOTS_SERVERS_MAX)
struct fd_topo_tile_snapct {
char snapshots_path[ PATH_MAX ];
@@ -535,7 +537,11 @@ struct fd_topo_tile {
} gossip;
ulong servers_cnt;
- fd_ip4_port_t servers[ FD_TOPO_SNAPSHOTS_SERVERS_MAX ];
+ struct {
+ fd_ip4_port_t addr;
+ char hostname[ 256UL ];
+ int is_https;
+ } servers[ FD_TOPO_SNAPSHOTS_SERVERS_MAX_RESOLVED ];
} sources;
int incremental_snapshots;
diff --git a/src/discof/restore/fd_snapct_tile.c b/src/discof/restore/fd_snapct_tile.c
index d1605a5f415..cfe0406859d 100644
--- a/src/discof/restore/fd_snapct_tile.c
+++ b/src/discof/restore/fd_snapct_tile.c
@@ -8,6 +8,7 @@
#include "../../disco/topo/fd_topo.h"
#include "../../disco/metrics/fd_metrics.h"
#include "../../flamenco/gossip/fd_gossip_types.h"
+#include "../../waltz/openssl/fd_openssl_tile.h"
#include
#include
@@ -32,7 +33,7 @@
/* FIXME: Handle cases where the slot number we start downloading differs from advertised */
#define GOSSIP_PEERS_MAX (FD_CONTACT_INFO_TABLE_SIZE)
-#define SERVER_PEERS_MAX (FD_TOPO_SNAPSHOTS_SERVERS_MAX)
+#define SERVER_PEERS_MAX (FD_TOPO_SNAPSHOTS_SERVERS_MAX_RESOLVED)
#define TOTAL_PEERS_MAX (GOSSIP_PEERS_MAX + SERVER_PEERS_MAX)
#define IN_KIND_ACK (0)
@@ -165,6 +166,13 @@ download_enabled( fd_topo_tile_t const * tile ) {
return gossip_enabled( tile ) || tile->snapct.sources.servers_cnt>0UL;
}
+FD_FN_CONST static inline ulong
+loose_footprint( fd_topo_tile_t const * tile ) {
+ (void)tile;
+ /* Leftover space for OpenSSL allocations */
+ return 1<<26UL; /* 64 MiB */
+}
+
static ulong
scratch_align( void ) {
return fd_ulong_max( alignof(fd_snapct_tile_t),
@@ -184,6 +192,7 @@ scratch_footprint( fd_topo_tile_t const * tile FD_PARAM_UNUSED ) {
l = FD_LAYOUT_APPEND( l, gossip_ci_map_align(), gossip_ci_map_footprint( gossip_ci_map_chain_cnt_est( GOSSIP_PEERS_MAX ) ) );
l = FD_LAYOUT_APPEND( l, fd_http_resolver_align(), fd_http_resolver_footprint( SERVER_PEERS_MAX ) );
l = FD_LAYOUT_APPEND( l, fd_sspeer_selector_align(), fd_sspeer_selector_footprint( TOTAL_PEERS_MAX ) );
+ l = FD_LAYOUT_APPEND( l, fd_alloc_align(), fd_alloc_footprint() );
return FD_LAYOUT_FINI( l, scratch_align() );
}
@@ -238,6 +247,10 @@ metrics_write( fd_snapct_tile_t * ctx ) {
FD_MGAUGE_SET( SNAPCT, PREDICTED_SLOT, ctx->predicted_incremental.slot );
+#if FD_HAS_OPENSSL
+ FD_MCNT_SET( SNAPCT, SSL_ALLOC_ERRORS, fd_ossl_alloc_errors );
+#endif
+
FD_MGAUGE_SET( SNAPCT, STATE, (ulong)ctx->state );
}
@@ -406,7 +419,16 @@ init_load( fd_snapct_tile_t * ctx,
fd_ssctrl_init_t * out = fd_chunk_to_laddr( ctx->out_ld.mem, ctx->out_ld.chunk );
out->file = file;
out->zstd = !file || (full ? ctx->local_in.full_snapshot_zstd : ctx->local_in.incremental_snapshot_zstd);
- if( !file ) out->addr = ctx->addr;
+ if( !file ) {
+ out->addr = ctx->addr;
+ for( ulong i=0UL; iaddr.l==ctx->config.sources.servers[ i ].addr.l ) ) {
+ fd_cstr_ncpy( out->hostname, ctx->config.sources.servers[ i ].hostname, sizeof(out->hostname) );
+ out->is_https = ctx->config.sources.servers[ i ].is_https;
+ break;
+ }
+ }
+ }
fd_stem_publish( stem, ctx->out_ld.idx, full ? FD_SNAPSHOT_MSG_CTRL_INIT_FULL : FD_SNAPSHOT_MSG_CTRL_INIT_INCR, ctx->out_ld.chunk, sizeof(fd_ssctrl_init_t), 0UL, 0UL, 0UL );
ctx->out_ld.chunk = fd_dcache_compact_next( ctx->out_ld.chunk, sizeof(fd_ssctrl_init_t), ctx->out_ld.chunk0, ctx->out_ld.wmark );
ctx->flush_ack = 0;
@@ -452,11 +474,18 @@ log_download( fd_snapct_tile_t * ctx,
}
for( ulong i=0UL; iconfig.sources.servers_cnt; i++ ) {
- if( addr.l==ctx->config.sources.servers[ i ].l ) {
- FD_LOG_NOTICE(( "downloading %s snapshot at slot %lu from configured server with index %lu at http://" FD_IP4_ADDR_FMT ":%hu/%s",
- full ? "full" : "incremental", slot, i,
- FD_IP4_ADDR_FMT_ARGS( addr.addr ), fd_ushort_bswap( addr.port ),
- full ? "snapshot.tar.bz2" : "incremental-snapshot.tar.bz2" ));
+ if( addr.l==ctx->config.sources.servers[ i ].addr.l ) {
+ if( ctx->config.sources.servers[ i ].is_https ) {
+ FD_LOG_NOTICE(( "downloading %s snapshot at slot %lu from configured server with index %lu at https://%s:%hu/%s",
+ full ? "full" : "incremental", slot, i,
+ ctx->config.sources.servers[ i ].hostname, fd_ushort_bswap( addr.port ),
+ full ? "snapshot.tar.bz2" : "incremental-snapshot.tar.bz2" ));
+ } else {
+ FD_LOG_NOTICE(( "downloading %s snapshot at slot %lu from configured server with index %lu at http://" FD_IP4_ADDR_FMT ":%hu/%s",
+ full ? "full" : "incremental", slot, i,
+ FD_IP4_ADDR_FMT_ARGS( addr.addr ), fd_ushort_bswap( addr.port ),
+ full ? "snapshot.tar.bz2" : "incremental-snapshot.tar.bz2" ));
+ }
return;
}
}
@@ -1156,11 +1185,23 @@ privileged_init( fd_topo_t * topo,
void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
FD_SCRATCH_ALLOC_INIT( l, scratch );
- fd_snapct_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_snapct_tile_t), sizeof(fd_snapct_tile_t) );
- void * _ssping = FD_SCRATCH_ALLOC_APPEND( l, fd_ssping_align(), fd_ssping_footprint( TOTAL_PEERS_MAX ) );
+ fd_snapct_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_snapct_tile_t), sizeof(fd_snapct_tile_t) );
+ void * _ssping = FD_SCRATCH_ALLOC_APPEND( l, fd_ssping_align(), fd_ssping_footprint( TOTAL_PEERS_MAX ) );
+ FD_SCRATCH_ALLOC_APPEND( l, alignof(gossip_ci_entry_t), sizeof(gossip_ci_entry_t)*GOSSIP_PEERS_MAX );
+ FD_SCRATCH_ALLOC_APPEND( l, gossip_ci_map_align(), gossip_ci_map_footprint( gossip_ci_map_chain_cnt_est( GOSSIP_PEERS_MAX ) ) );
+ void * _ssresolver = FD_SCRATCH_ALLOC_APPEND( l, fd_http_resolver_align(), fd_http_resolver_footprint( SERVER_PEERS_MAX ) );
+ FD_SCRATCH_ALLOC_APPEND( l, fd_sspeer_selector_align(), fd_sspeer_selector_footprint( TOTAL_PEERS_MAX ) );
+
+#if FD_HAS_OPENSSL
+ void * _alloc = FD_SCRATCH_ALLOC_APPEND( l, fd_alloc_align(), fd_alloc_footprint() );
+ fd_alloc_t * alloc = fd_alloc_join( fd_alloc_new( _alloc, 1UL ), tile->kind_id );
+ fd_ossl_tile_init( alloc );
+#endif
ctx->ssping = NULL;
- if( FD_LIKELY( download_enabled( tile ) ) ) ctx->ssping = fd_ssping_join( fd_ssping_new( _ssping, TOTAL_PEERS_MAX, 1UL, on_ping, ctx ) );
+ if( FD_LIKELY( download_enabled( tile ) ) ) ctx->ssping = fd_ssping_join( fd_ssping_new( _ssping, TOTAL_PEERS_MAX, 1UL, on_ping, ctx ) );
+ if( FD_LIKELY( tile->snapct.sources.servers_cnt ) ) ctx->ssresolver = fd_http_resolver_join( fd_http_resolver_new( _ssresolver, SERVER_PEERS_MAX, tile->snapct.incremental_snapshots, on_resolve, ctx ) );
+ else ctx->ssresolver = NULL;
/* FIXME: We will keep too many snapshots if we have local snapshots
but elect not to use them due to their age. */
@@ -1272,19 +1313,20 @@ unprivileged_init( fd_topo_t * topo,
FD_SCRATCH_ALLOC_APPEND( l, fd_ssping_align(), fd_ssping_footprint( TOTAL_PEERS_MAX ) );
void * _ci_table = FD_SCRATCH_ALLOC_APPEND( l, alignof(gossip_ci_entry_t), sizeof(gossip_ci_entry_t) * GOSSIP_PEERS_MAX );
void * _ci_map = FD_SCRATCH_ALLOC_APPEND( l, gossip_ci_map_align(), gossip_ci_map_footprint( gossip_ci_map_chain_cnt_est( GOSSIP_PEERS_MAX ) ) );
- void * _ssresolver = FD_SCRATCH_ALLOC_APPEND( l, fd_http_resolver_align(), fd_http_resolver_footprint( SERVER_PEERS_MAX ) );
+ FD_SCRATCH_ALLOC_APPEND( l, fd_http_resolver_align(), fd_http_resolver_footprint( SERVER_PEERS_MAX ) );
void * _selector = FD_SCRATCH_ALLOC_APPEND( l, fd_sspeer_selector_align(), fd_sspeer_selector_footprint( TOTAL_PEERS_MAX ) );
fd_memcpy( &ctx->config, &tile->snapct, sizeof(ctx->config) );
ctx->gossip_enabled = gossip_enabled( tile );
ctx->download_enabled = download_enabled( tile );
- ctx->ssresolver = NULL;
if( ctx->config.sources.servers_cnt ) {
- ctx->ssresolver = fd_http_resolver_join( fd_http_resolver_new( _ssresolver, SERVER_PEERS_MAX, ctx->config.incremental_snapshots, on_resolve, ctx ) );
for( ulong i=0UL; isnapct.sources.servers_cnt; i++ ) {
- fd_ssping_add ( ctx->ssping, tile->snapct.sources.servers[ i ] );
- fd_http_resolver_add( ctx->ssresolver, tile->snapct.sources.servers[ i ] );
+ fd_ssping_add ( ctx->ssping, tile->snapct.sources.servers[ i ].addr );
+ fd_http_resolver_add( ctx->ssresolver,
+ tile->snapct.sources.servers[ i ].addr,
+ tile->snapct.sources.servers[ i ].hostname,
+ tile->snapct.sources.servers[ i ].is_https );
}
}
@@ -1365,6 +1407,7 @@ fd_topo_run_tile_t fd_tile_snapct = {
.populate_allowed_fds = populate_allowed_fds,
.scratch_align = scratch_align,
.scratch_footprint = scratch_footprint,
+ .loose_footprint = loose_footprint,
.privileged_init = privileged_init,
.unprivileged_init = unprivileged_init,
.run = stem_run,
diff --git a/src/discof/restore/fd_snapct_tile.seccomppolicy b/src/discof/restore/fd_snapct_tile.seccomppolicy
index 88fa53a0e88..0df50f06cc3 100644
--- a/src/discof/restore/fd_snapct_tile.seccomppolicy
+++ b/src/discof/restore/fd_snapct_tile.seccomppolicy
@@ -8,13 +8,26 @@ uint logfile_fd, uint dir_fd, uint out_full_fd, uint out_inc_fd, uint ping_fd
# are always written to the log file.
#
# arg 0 is the file descriptor to write to. The boot process ensures
-# that descriptor 2 is always STDERR. The other files that can be
-# written to are the out descriptors for the full and incremental
-# snapshots.
-write: (or (eq (arg 0) 2)
- (eq (arg 0) logfile_fd)
- (eq (arg 0) out_full_fd)
- (eq (arg 0) out_inc_fd))
+# that descriptor 2 is always STDERR. Other files that can be
+# written to include the out descriptors for the full and incremental
+# snapshots. OpenSSL also calls write on the underlying socket
+# descriptor. We will restrict this being called on the snapshot
+# directory file descriptor and the ping file descriptor.
+write: (not (or (eq (arg 0) dir_fd)
+ (eq (arg 0) ping_fd)))
+
+# openssl: read
+#
+# OpenSSL calls read to receive bytes from a socket. We will restrict
+# this being called on the stderr, the log file descriptor, the snapshot
+# directory, the full and incremental snapshot files, and the ping file
+# descriptor.
+read: (not (or (eq (arg 0) 2)
+ (eq (arg 0) logfile_fd)
+ (eq (arg 0) dir_fd)
+ (eq (arg 0) out_full_fd)
+ (eq (arg 0) out_inc_fd)
+ (eq (arg 0) ping_fd)))
# logging: 'WARNING' and above fsync the logfile to disk immediately
#
@@ -113,5 +126,19 @@ setsockopt: (and (not (or (eq (arg 0) 2)
renameat: (and (eq (arg 0) dir_fd)
(eq (arg 2) dir_fd))
+# openssl: RAND_bytes requires getpid
+#
+# The OpenSSL implementation calls getpid() as an implementation
+# detail, they save the PID in a global and reseed the RNG if the PID
+# ever changes (the process was forked). We don't need this logic since
+# our process can't fork.
+getpid
+
+# openssl: RAND_bytes requires getrandom
+#
+# The OpenSSL implementation calls getrandom internally for periodically
+# reseeding the RNG.
+getrandom
+
# shutdown: exit is called on shutdown
exit: (eq (arg 0) 0)
diff --git a/src/discof/restore/fd_snapld_tile.c b/src/discof/restore/fd_snapld_tile.c
index ed29eec37d8..d1991f67c12 100644
--- a/src/discof/restore/fd_snapld_tile.c
+++ b/src/discof/restore/fd_snapld_tile.c
@@ -1,10 +1,13 @@
+#define _GNU_SOURCE
#include "utils/fd_ssarchive.h"
#include "utils/fd_ssctrl.h"
#include "utils/fd_sshttp.h"
#include "../../disco/topo/fd_topo.h"
#include "../../disco/metrics/fd_metrics.h"
+#include "../../waltz/openssl/fd_openssl_tile.h"
+#include /* memfd_create */
#include
#include
#include
@@ -29,8 +32,14 @@ typedef struct fd_snapld_tile {
int load_file;
int sent_meta;
+ int awaiting_ack;
+ ulong awaiting_ack_sig;
+
int local_full_fd;
int local_incr_fd;
+ int sockfd;
+
+ int is_https;
fd_sshttp_t * sshttp;
@@ -58,15 +67,33 @@ scratch_footprint( fd_topo_tile_t const * tile FD_PARAM_UNUSED ) {
ulong l = FD_LAYOUT_INIT;
l = FD_LAYOUT_APPEND( l, alignof(fd_snapld_tile_t), sizeof(fd_snapld_tile_t) );
l = FD_LAYOUT_APPEND( l, fd_sshttp_align(), fd_sshttp_footprint() );
+ l = FD_LAYOUT_APPEND( l, fd_alloc_align(), fd_alloc_footprint() );
return FD_LAYOUT_FINI( l, scratch_align() );
}
+FD_FN_CONST static inline ulong
+loose_footprint( fd_topo_tile_t const * tile ) {
+ (void)tile;
+ /* Leftover space for OpenSSL allocations */
+ return 1UL<<26UL; /* 64 MiB */
+}
+
static void
privileged_init( fd_topo_t * topo,
fd_topo_tile_t * tile ) {
void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
FD_SCRATCH_ALLOC_INIT( l, scratch );
fd_snapld_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_snapld_tile_t), sizeof(fd_snapld_tile_t) );
+ void * _sshttp = FD_SCRATCH_ALLOC_APPEND( l, fd_sshttp_align(), fd_sshttp_footprint() );
+
+#if FD_HAS_OPENSSL
+ void * _alloc = FD_SCRATCH_ALLOC_APPEND( l, fd_alloc_align(), fd_alloc_footprint() );
+ fd_alloc_t * alloc = fd_alloc_join( fd_alloc_new( _alloc, 1UL ), tile->kind_id );
+ fd_ossl_tile_init( alloc );
+#endif
+
+ ctx->sshttp = fd_sshttp_join( fd_sshttp_new( _sshttp ) );
+ FD_TEST( ctx->sshttp );
/* FIXME: Allow incremental_snapshots=0 config */
ulong full_slot = ULONG_MAX;
@@ -91,6 +118,12 @@ privileged_init( fd_topo_t * topo,
if( FD_UNLIKELY( -1==ctx->local_incr_fd ) ) FD_LOG_ERR(( "open() failed `%s` (%i-%s)", incr_path, errno, fd_io_strerror( errno ) ));
}
}
+
+ /* Create a temporary file descriptor for our socket file descriptor.
+ It is closed later in unprivileged init so that the sandbox sees
+ an existent file descriptor. */
+ ctx->sockfd = memfd_create( "snapld.sockfd", 0 );
+ if( FD_UNLIKELY( -1==ctx->sockfd ) ) FD_LOG_ERR(( "memfd_create() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
}
static ulong
@@ -111,6 +144,7 @@ populate_allowed_fds( fd_topo_t const * topo,
fd_snapld_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_snapld_tile_t), sizeof(fd_snapld_tile_t) );
if( FD_LIKELY( -1!=ctx->local_full_fd ) ) out_fds[ out_cnt++ ] = ctx->local_full_fd;
if( FD_LIKELY( -1!=ctx->local_incr_fd ) ) out_fds[ out_cnt++ ] = ctx->local_incr_fd;
+ out_fds[ out_cnt++ ] = ctx->sockfd;
return out_cnt;
}
@@ -124,7 +158,7 @@ populate_allowed_seccomp( fd_topo_t const * topo,
FD_SCRATCH_ALLOC_INIT( l, scratch );
fd_snapld_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_snapld_tile_t), sizeof(fd_snapld_tile_t) );
- populate_sock_filter_policy_fd_snapld_tile( out_cnt, out, (uint)fd_log_private_logfile_fd(), (uint)ctx->local_full_fd, (uint)ctx->local_incr_fd );
+ populate_sock_filter_policy_fd_snapld_tile( out_cnt, out, (uint)fd_log_private_logfile_fd(), (uint)ctx->local_full_fd, (uint)ctx->local_incr_fd, (uint)ctx->sockfd );
return sock_filter_policy_fd_snapld_tile_instr_cnt;
}
@@ -134,15 +168,11 @@ unprivileged_init( fd_topo_t * topo,
void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
FD_SCRATCH_ALLOC_INIT( l, scratch );
fd_snapld_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_snapld_tile_t), sizeof(fd_snapld_tile_t) );
- void * _sshttp = FD_SCRATCH_ALLOC_APPEND( l, fd_sshttp_align(), fd_sshttp_footprint() );
fd_memcpy( ctx->config.path, tile->snapld.snapshots_path, PATH_MAX );
ctx->state = FD_SNAPSHOT_STATE_IDLE;
- ctx->sshttp = fd_sshttp_join( fd_sshttp_new( _sshttp ) );
- FD_TEST( ctx->sshttp );
-
FD_TEST( tile->in_cnt==1UL );
fd_topo_link_t const * in_link = &topo->links[ tile->in_link_id[ 0 ] ];
FD_TEST( 0==strcmp( in_link->name, "snapct_ld" ) );
@@ -156,6 +186,15 @@ unprivileged_init( fd_topo_t * topo,
ctx->out_dc.wmark = fd_dcache_compact_wmark ( ctx->out_dc.mem, out_link->dcache, out_link->mtu );
ctx->out_dc.chunk = ctx->out_dc.chunk0;
ctx->out_dc.mtu = out_link->mtu;
+
+ ctx->awaiting_ack = 0;
+ ctx->awaiting_ack_sig = 0;
+ ctx->is_https = 0;
+
+ /* We can only close the temporary socket file descriptor after
+ entering the sandbox because the sandbox checks all file
+ descriptors are existent. */
+ if( -1==close( ctx->sockfd ) ) FD_LOG_ERR((" close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
}
static int
@@ -165,7 +204,10 @@ should_shutdown( fd_snapld_tile_t * ctx ) {
static void
metrics_write( fd_snapld_tile_t * ctx ) {
- FD_MGAUGE_SET( SNAPLD, STATE, (ulong)(ctx->state) );
+#if FD_HAS_OPENSSL
+ FD_MCNT_SET( SNAPLD, SSL_ALLOC_ERRORS, fd_ossl_alloc_errors );
+#endif
+ FD_MGAUGE_SET( SNAPLD, STATE, (ulong)(ctx->state) );
}
static void
@@ -173,6 +215,13 @@ after_credit( fd_snapld_tile_t * ctx,
fd_stem_context_t * stem,
int * opt_poll_in FD_PARAM_UNUSED,
int * charge_busy ) {
+ if( FD_UNLIKELY( ctx->awaiting_ack && ctx->state==FD_SNAPSHOT_STATE_FINISHING ) ) {
+ ctx->awaiting_ack = 0;
+ ctx->state = FD_SNAPSHOT_STATE_IDLE;
+ fd_stem_publish( stem, 0UL, ctx->awaiting_ack_sig, 0UL, 0UL, 0UL, 0UL, 0UL );
+ return;
+ }
+
if( ctx->state!=FD_SNAPSHOT_STATE_PROCESSING ) {
fd_log_sleep( (long)1e6 );
return;
@@ -258,12 +307,13 @@ returnable_frag( fd_snapld_tile_t * ctx,
ctx->load_file = msg_in->file;
ctx->state = FD_SNAPSHOT_STATE_PROCESSING;
ctx->sent_meta = 0;
+ ctx->is_https = msg_in->is_https;
if( ctx->load_file ) {
if( FD_UNLIKELY( 0!=lseek( ctx->load_full ? ctx->local_full_fd : ctx->local_incr_fd, 0, SEEK_SET ) ) )
FD_LOG_ERR(( "lseek(0) failed (%i-%s)", errno, fd_io_strerror( errno ) ));
} else {
- if( ctx->load_full ) fd_sshttp_init( ctx->sshttp, msg_in->addr, "/snapshot.tar.bz2", 17UL, fd_log_wallclock() );
- else fd_sshttp_init( ctx->sshttp, msg_in->addr, "/incremental-snapshot.tar.bz2", 29UL, fd_log_wallclock() );
+ if( ctx->load_full ) fd_sshttp_init( ctx->sshttp, msg_in->addr, msg_in->hostname, msg_in->is_https, "/snapshot.tar.bz2", 17UL, fd_log_wallclock() );
+ else fd_sshttp_init( ctx->sshttp, msg_in->addr, msg_in->hostname, msg_in->is_https, "/incremental-snapshot.tar.bz2", 29UL, fd_log_wallclock() );
}
fd_ssctrl_init_t * msg_out = fd_chunk_to_laddr( ctx->out_dc.mem, ctx->out_dc.chunk );
fd_memcpy( msg_out, msg_in, sz );
@@ -286,9 +336,16 @@ returnable_frag( fd_snapld_tile_t * ctx,
ctx->state==FD_SNAPSHOT_STATE_FINISHING ||
ctx->state==FD_SNAPSHOT_STATE_ERROR );
if( FD_UNLIKELY( ctx->state!=FD_SNAPSHOT_STATE_FINISHING ) ) {
- ctx->state = FD_SNAPSHOT_STATE_ERROR;
- fd_stem_publish( stem, 0UL, FD_SNAPSHOT_MSG_CTRL_ERROR, 0UL, 0UL, 0UL, 0UL, 0UL );
- return 0;
+ /* snapld should be in the finishing state when reading from a
+ file or downloading from http. It is only allowed to still
+ be in progress for shutting down an https connection. */
+ FD_TEST( ctx->is_https );
+ /* snapld might not be done with shutting down an https
+ connection. Save the sig here and send the message when
+ snapld is in the finishing state. */
+ ctx->awaiting_ack = 1;
+ ctx->awaiting_ack_sig = sig;
+ return 0; /* return directly to avoid fowarding the message */
}
ctx->state = FD_SNAPSHOT_STATE_IDLE;
break;
@@ -329,6 +386,7 @@ fd_topo_run_tile_t fd_tile_snapld = {
.populate_allowed_fds = populate_allowed_fds,
.scratch_align = scratch_align,
.scratch_footprint = scratch_footprint,
+ .loose_footprint = loose_footprint,
.privileged_init = privileged_init,
.unprivileged_init = unprivileged_init,
.run = stem_run,
diff --git a/src/discof/restore/fd_snapld_tile.seccomppolicy b/src/discof/restore/fd_snapld_tile.seccomppolicy
index 191ac6ff44a..2d140cba840 100644
--- a/src/discof/restore/fd_snapld_tile.seccomppolicy
+++ b/src/discof/restore/fd_snapld_tile.seccomppolicy
@@ -1,4 +1,4 @@
-uint logfile_fd, uint in_full_fd, uint in_incr_fd
+uint logfile_fd, uint in_full_fd, uint in_incr_fd, uint sockfd
# logging: all log messages are written to a file and/or pipe
#
@@ -8,9 +8,11 @@ uint logfile_fd, uint in_full_fd, uint in_incr_fd
# arg 0 is the file descriptor to write to. The boot process ensures
# that descriptor 2 is always STDERR. The other files that can be
# written to are the out descriptors for the full and incremental
-# snapshots.
+# snapshots and the socket file descriptor, which OpenSSL writes to
+# during the lifetime of an https connection.
write: (or (eq (arg 0) 2)
- (eq (arg 0) logfile_fd))
+ (eq (arg 0) logfile_fd)
+ (eq (arg 0) sockfd))
# logging: 'WARNING' and above fsync the logfile to disk immediately
#
@@ -18,11 +20,13 @@ write: (or (eq (arg 0) 2)
fsync: (eq (arg 0) logfile_fd)
# snapshot: need to be able to read from an open file for snapshot
-# loading
+# loading and from the socket file descriptor. OpenSSL calls read to
+# receive bytes from an https connection.
#
# arg 0 is the file descriptor that we want to read from
read: (or (eq (arg 0) in_full_fd)
- (eq (arg 0) in_incr_fd))
+ (eq (arg 0) in_incr_fd)
+ (eq (arg 0) sockfd))
# snapshot: Uses lseek to reset position in input file
lseek: (and (or (eq (arg 0) in_full_fd)
@@ -87,5 +91,19 @@ ppoll: (eq (arg 1) 1)
# snapshot: yield to scheduler during idle pipeline to save power
clock_nanosleep
+# openssl: RAND_bytes requires getpid
+#
+# The OpenSSL implementation calls getpid() as an implementation detail,
+# they save the PID in a global and reseed the RNG if the PID ever
+# changes (the process was forked). We don't need this logic since our
+# process can't fork.
+getpid
+
+# openssl: RAND_bytes requires getrandom
+#
+# The OpenSSL implementation calls getrandom internally for periodically
+# reseeding the RNG.
+getrandom
+
# shutdown: exit is called on shutdown
exit: (eq (arg 0) 0)
diff --git a/src/discof/restore/generated/fd_snapct_tile_seccomp.h b/src/discof/restore/generated/fd_snapct_tile_seccomp.h
index e0ad2251aad..bcb04dcf0cc 100644
--- a/src/discof/restore/generated/fd_snapct_tile_seccomp.h
+++ b/src/discof/restore/generated/fd_snapct_tile_seccomp.h
@@ -24,58 +24,80 @@
#else
# error "Target architecture is unsupported by seccomp."
#endif
-static const unsigned int sock_filter_policy_fd_snapct_tile_instr_cnt = 106;
+static const unsigned int sock_filter_policy_fd_snapct_tile_instr_cnt = 117;
static void populate_sock_filter_policy_fd_snapct_tile( ulong out_cnt, struct sock_filter * out, uint logfile_fd, uint dir_fd, uint out_full_fd, uint out_inc_fd, uint ping_fd ) {
- FD_TEST( out_cnt >= 106 );
- struct sock_filter filter[106] = {
+ FD_TEST( out_cnt >= 117 );
+ struct sock_filter filter[117] = {
/* Check: Jump to RET_KILL_PROCESS if the script's arch != the runtime arch */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, ( offsetof( struct seccomp_data, arch ) ) ),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, ARCH_NR, 0, /* RET_KILL_PROCESS */ 102 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, ARCH_NR, 0, /* RET_KILL_PROCESS */ 113 ),
/* loading syscall number in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, ( offsetof( struct seccomp_data, nr ) ) ),
/* allow write based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_write, /* check_write */ 12, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_write, /* check_write */ 15, 0 ),
+ /* allow read based on expression */
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_read, /* check_read */ 18, 0 ),
/* allow fsync based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_fsync, /* check_fsync */ 19, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_fsync, /* check_fsync */ 29, 0 ),
/* allow socket based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_socket, /* check_socket */ 20, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_socket, /* check_socket */ 30, 0 ),
/* allow connect based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_connect, /* check_connect */ 25, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_connect, /* check_connect */ 35, 0 ),
/* allow close based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_close, /* check_close */ 36, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_close, /* check_close */ 46, 0 ),
/* simply allow ppoll */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_ppoll, /* RET_ALLOW */ 96, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_ppoll, /* RET_ALLOW */ 106, 0 ),
/* allow sendto based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_sendto, /* check_sendto */ 46, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_sendto, /* check_sendto */ 56, 0 ),
/* allow sendmmsg based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_sendmmsg, /* check_sendmmsg */ 57, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_sendmmsg, /* check_sendmmsg */ 67, 0 ),
/* allow recvfrom based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_recvfrom, /* check_recvfrom */ 60, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_recvfrom, /* check_recvfrom */ 70, 0 ),
/* allow setsockopt based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_setsockopt, /* check_setsockopt */ 69, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_setsockopt, /* check_setsockopt */ 79, 0 ),
/* allow renameat based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_renameat, /* check_renameat */ 84, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_renameat, /* check_renameat */ 94, 0 ),
+ /* simply allow getpid */
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_getpid, /* RET_ALLOW */ 100, 0 ),
+ /* simply allow getrandom */
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_getrandom, /* RET_ALLOW */ 99, 0 ),
/* allow exit based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_exit, /* check_exit */ 87, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_exit, /* check_exit */ 95, 0 ),
/* none of the syscalls matched */
- { BPF_JMP | BPF_JA, 0, 0, /* RET_KILL_PROCESS */ 88 },
+ { BPF_JMP | BPF_JA, 0, 0, /* RET_KILL_PROCESS */ 96 },
// check_write:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_ALLOW */ 87, /* lbl_1 */ 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, dir_fd, /* RET_KILL_PROCESS */ 94, /* lbl_1 */ 0 ),
// lbl_1:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_ALLOW */ 85, /* lbl_2 */ 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, ping_fd, /* RET_KILL_PROCESS */ 92, /* RET_ALLOW */ 93 ),
+// check_read:
+ /* load syscall argument 0 in accumulator */
+ BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_KILL_PROCESS */ 90, /* lbl_2 */ 0 ),
// lbl_2:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_full_fd, /* RET_ALLOW */ 83, /* lbl_3 */ 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_KILL_PROCESS */ 88, /* lbl_3 */ 0 ),
// lbl_3:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_inc_fd, /* RET_ALLOW */ 81, /* RET_KILL_PROCESS */ 80 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, dir_fd, /* RET_KILL_PROCESS */ 86, /* lbl_4 */ 0 ),
+// lbl_4:
+ /* load syscall argument 0 in accumulator */
+ BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_full_fd, /* RET_KILL_PROCESS */ 84, /* lbl_5 */ 0 ),
+// lbl_5:
+ /* load syscall argument 0 in accumulator */
+ BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_inc_fd, /* RET_KILL_PROCESS */ 82, /* lbl_6 */ 0 ),
+// lbl_6:
+ /* load syscall argument 0 in accumulator */
+ BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, ping_fd, /* RET_KILL_PROCESS */ 80, /* RET_ALLOW */ 81 ),
// check_fsync:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
@@ -83,152 +105,152 @@ static void populate_sock_filter_policy_fd_snapct_tile( ulong out_cnt, struct so
// check_socket:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, AF_INET, /* lbl_4 */ 0, /* RET_KILL_PROCESS */ 76 ),
-// lbl_4:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, AF_INET, /* lbl_7 */ 0, /* RET_KILL_PROCESS */ 76 ),
+// lbl_7:
/* load syscall argument 1 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[1])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SOCK_STREAM|SOCK_NONBLOCK, /* lbl_5 */ 0, /* RET_KILL_PROCESS */ 74 ),
-// lbl_5:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SOCK_STREAM|SOCK_NONBLOCK, /* lbl_8 */ 0, /* RET_KILL_PROCESS */ 74 ),
+// lbl_8:
/* load syscall argument 2 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[2])),
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 0, /* RET_ALLOW */ 73, /* RET_KILL_PROCESS */ 72 ),
// check_connect:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_KILL_PROCESS */ 70, /* lbl_6 */ 0 ),
-// lbl_6:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_KILL_PROCESS */ 70, /* lbl_9 */ 0 ),
+// lbl_9:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_KILL_PROCESS */ 68, /* lbl_7 */ 0 ),
-// lbl_7:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_KILL_PROCESS */ 68, /* lbl_10 */ 0 ),
+// lbl_10:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, dir_fd, /* RET_KILL_PROCESS */ 66, /* lbl_8 */ 0 ),
-// lbl_8:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, dir_fd, /* RET_KILL_PROCESS */ 66, /* lbl_11 */ 0 ),
+// lbl_11:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_full_fd, /* RET_KILL_PROCESS */ 64, /* lbl_9 */ 0 ),
-// lbl_9:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_full_fd, /* RET_KILL_PROCESS */ 64, /* lbl_12 */ 0 ),
+// lbl_12:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_inc_fd, /* RET_KILL_PROCESS */ 62, /* lbl_10 */ 0 ),
-// lbl_10:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_inc_fd, /* RET_KILL_PROCESS */ 62, /* lbl_13 */ 0 ),
+// lbl_13:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, ping_fd, /* RET_KILL_PROCESS */ 60, /* RET_ALLOW */ 61 ),
// check_close:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_KILL_PROCESS */ 58, /* lbl_11 */ 0 ),
-// lbl_11:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_KILL_PROCESS */ 58, /* lbl_14 */ 0 ),
+// lbl_14:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_KILL_PROCESS */ 56, /* lbl_12 */ 0 ),
-// lbl_12:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_KILL_PROCESS */ 56, /* lbl_15 */ 0 ),
+// lbl_15:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, dir_fd, /* RET_KILL_PROCESS */ 54, /* lbl_13 */ 0 ),
-// lbl_13:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, dir_fd, /* RET_KILL_PROCESS */ 54, /* lbl_16 */ 0 ),
+// lbl_16:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_full_fd, /* RET_KILL_PROCESS */ 52, /* lbl_14 */ 0 ),
-// lbl_14:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_full_fd, /* RET_KILL_PROCESS */ 52, /* lbl_17 */ 0 ),
+// lbl_17:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_inc_fd, /* RET_KILL_PROCESS */ 50, /* lbl_15 */ 0 ),
-// lbl_15:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_inc_fd, /* RET_KILL_PROCESS */ 50, /* lbl_18 */ 0 ),
+// lbl_18:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, ping_fd, /* RET_KILL_PROCESS */ 48, /* RET_ALLOW */ 49 ),
// check_sendto:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_KILL_PROCESS */ 46, /* lbl_16 */ 0 ),
-// lbl_16:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_KILL_PROCESS */ 46, /* lbl_19 */ 0 ),
+// lbl_19:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_KILL_PROCESS */ 44, /* lbl_17 */ 0 ),
-// lbl_17:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_KILL_PROCESS */ 44, /* lbl_20 */ 0 ),
+// lbl_20:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, dir_fd, /* RET_KILL_PROCESS */ 42, /* lbl_18 */ 0 ),
-// lbl_18:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, dir_fd, /* RET_KILL_PROCESS */ 42, /* lbl_21 */ 0 ),
+// lbl_21:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_full_fd, /* RET_KILL_PROCESS */ 40, /* lbl_19 */ 0 ),
-// lbl_19:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_full_fd, /* RET_KILL_PROCESS */ 40, /* lbl_22 */ 0 ),
+// lbl_22:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_inc_fd, /* RET_KILL_PROCESS */ 38, /* lbl_20 */ 0 ),
-// lbl_20:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_inc_fd, /* RET_KILL_PROCESS */ 38, /* lbl_23 */ 0 ),
+// lbl_23:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, ping_fd, /* RET_KILL_PROCESS */ 36, /* RET_ALLOW */ 37 ),
// check_sendmmsg:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, ping_fd, /* lbl_21 */ 0, /* RET_KILL_PROCESS */ 34 ),
-// lbl_21:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, ping_fd, /* lbl_24 */ 0, /* RET_KILL_PROCESS */ 34 ),
+// lbl_24:
/* load syscall argument 3 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[3])),
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 0, /* RET_ALLOW */ 33, /* RET_KILL_PROCESS */ 32 ),
// check_recvfrom:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_KILL_PROCESS */ 30, /* lbl_22 */ 0 ),
-// lbl_22:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_KILL_PROCESS */ 30, /* lbl_25 */ 0 ),
+// lbl_25:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_KILL_PROCESS */ 28, /* lbl_23 */ 0 ),
-// lbl_23:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_KILL_PROCESS */ 28, /* lbl_26 */ 0 ),
+// lbl_26:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, dir_fd, /* RET_KILL_PROCESS */ 26, /* lbl_24 */ 0 ),
-// lbl_24:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, dir_fd, /* RET_KILL_PROCESS */ 26, /* lbl_27 */ 0 ),
+// lbl_27:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_full_fd, /* RET_KILL_PROCESS */ 24, /* lbl_25 */ 0 ),
-// lbl_25:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_full_fd, /* RET_KILL_PROCESS */ 24, /* lbl_28 */ 0 ),
+// lbl_28:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_inc_fd, /* RET_KILL_PROCESS */ 22, /* RET_ALLOW */ 23 ),
// check_setsockopt:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_KILL_PROCESS */ 20, /* lbl_27 */ 0 ),
-// lbl_27:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_KILL_PROCESS */ 20, /* lbl_30 */ 0 ),
+// lbl_30:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_KILL_PROCESS */ 18, /* lbl_28 */ 0 ),
-// lbl_28:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_KILL_PROCESS */ 18, /* lbl_31 */ 0 ),
+// lbl_31:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, dir_fd, /* RET_KILL_PROCESS */ 16, /* lbl_29 */ 0 ),
-// lbl_29:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, dir_fd, /* RET_KILL_PROCESS */ 16, /* lbl_32 */ 0 ),
+// lbl_32:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_full_fd, /* RET_KILL_PROCESS */ 14, /* lbl_30 */ 0 ),
-// lbl_30:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_full_fd, /* RET_KILL_PROCESS */ 14, /* lbl_33 */ 0 ),
+// lbl_33:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_inc_fd, /* RET_KILL_PROCESS */ 12, /* lbl_31 */ 0 ),
-// lbl_31:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, out_inc_fd, /* RET_KILL_PROCESS */ 12, /* lbl_34 */ 0 ),
+// lbl_34:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, ping_fd, /* RET_KILL_PROCESS */ 10, /* lbl_26 */ 0 ),
-// lbl_26:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, ping_fd, /* RET_KILL_PROCESS */ 10, /* lbl_29 */ 0 ),
+// lbl_29:
/* load syscall argument 1 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[1])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_TCP, /* lbl_32 */ 0, /* RET_KILL_PROCESS */ 8 ),
-// lbl_32:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_TCP, /* lbl_35 */ 0, /* RET_KILL_PROCESS */ 8 ),
+// lbl_35:
/* load syscall argument 2 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[2])),
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, TCP_NODELAY, /* RET_ALLOW */ 7, /* RET_KILL_PROCESS */ 6 ),
// check_renameat:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, dir_fd, /* lbl_33 */ 0, /* RET_KILL_PROCESS */ 4 ),
-// lbl_33:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, dir_fd, /* lbl_36 */ 0, /* RET_KILL_PROCESS */ 4 ),
+// lbl_36:
/* load syscall argument 2 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[2])),
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, dir_fd, /* RET_ALLOW */ 3, /* RET_KILL_PROCESS */ 2 ),
diff --git a/src/discof/restore/generated/fd_snapld_tile_seccomp.h b/src/discof/restore/generated/fd_snapld_tile_seccomp.h
index ec18f23a3fd..ea96c33873f 100644
--- a/src/discof/restore/generated/fd_snapld_tile_seccomp.h
+++ b/src/discof/restore/generated/fd_snapld_tile_seccomp.h
@@ -24,151 +24,163 @@
#else
# error "Target architecture is unsupported by seccomp."
#endif
-static const unsigned int sock_filter_policy_fd_snapld_tile_instr_cnt = 78;
+static const unsigned int sock_filter_policy_fd_snapld_tile_instr_cnt = 84;
-static void populate_sock_filter_policy_fd_snapld_tile( ulong out_cnt, struct sock_filter * out, uint logfile_fd, uint in_full_fd, uint in_incr_fd ) {
- FD_TEST( out_cnt >= 78 );
- struct sock_filter filter[78] = {
+static void populate_sock_filter_policy_fd_snapld_tile( ulong out_cnt, struct sock_filter * out, uint logfile_fd, uint in_full_fd, uint in_incr_fd, uint sockfd ) {
+ FD_TEST( out_cnt >= 84 );
+ struct sock_filter filter[84] = {
/* Check: Jump to RET_KILL_PROCESS if the script's arch != the runtime arch */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, ( offsetof( struct seccomp_data, arch ) ) ),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, ARCH_NR, 0, /* RET_KILL_PROCESS */ 74 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, ARCH_NR, 0, /* RET_KILL_PROCESS */ 80 ),
/* loading syscall number in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, ( offsetof( struct seccomp_data, nr ) ) ),
/* allow write based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_write, /* check_write */ 12, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_write, /* check_write */ 14, 0 ),
/* allow fsync based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_fsync, /* check_fsync */ 15, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_fsync, /* check_fsync */ 19, 0 ),
/* allow read based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_read, /* check_read */ 16, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_read, /* check_read */ 20, 0 ),
/* allow lseek based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_lseek, /* check_lseek */ 19, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_lseek, /* check_lseek */ 25, 0 ),
/* allow socket based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_socket, /* check_socket */ 26, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_socket, /* check_socket */ 32, 0 ),
/* allow connect based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_connect, /* check_connect */ 31, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_connect, /* check_connect */ 37, 0 ),
/* allow close based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_close, /* check_close */ 38, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_close, /* check_close */ 44, 0 ),
/* allow sendto based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_sendto, /* check_sendto */ 45, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_sendto, /* check_sendto */ 51, 0 ),
/* allow recvfrom based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_recvfrom, /* check_recvfrom */ 52, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_recvfrom, /* check_recvfrom */ 58, 0 ),
/* allow ppoll based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_ppoll, /* check_ppoll */ 59, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_ppoll, /* check_ppoll */ 65, 0 ),
/* simply allow clock_nanosleep */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_clock_nanosleep, /* RET_ALLOW */ 63, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_clock_nanosleep, /* RET_ALLOW */ 69, 0 ),
+ /* simply allow getpid */
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_getpid, /* RET_ALLOW */ 68, 0 ),
+ /* simply allow getrandom */
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_getrandom, /* RET_ALLOW */ 67, 0 ),
/* allow exit based on expression */
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_exit, /* check_exit */ 59, 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_exit, /* check_exit */ 63, 0 ),
/* none of the syscalls matched */
- { BPF_JMP | BPF_JA, 0, 0, /* RET_KILL_PROCESS */ 60 },
+ { BPF_JMP | BPF_JA, 0, 0, /* RET_KILL_PROCESS */ 64 },
// check_write:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_ALLOW */ 59, /* lbl_1 */ 0 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_ALLOW */ 63, /* lbl_1 */ 0 ),
// lbl_1:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_ALLOW */ 57, /* RET_KILL_PROCESS */ 56 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_ALLOW */ 61, /* lbl_2 */ 0 ),
+// lbl_2:
+ /* load syscall argument 0 in accumulator */
+ BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, sockfd, /* RET_ALLOW */ 59, /* RET_KILL_PROCESS */ 58 ),
// check_fsync:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_ALLOW */ 55, /* RET_KILL_PROCESS */ 54 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_ALLOW */ 57, /* RET_KILL_PROCESS */ 56 ),
// check_read:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, in_full_fd, /* RET_ALLOW */ 53, /* lbl_2 */ 0 ),
-// lbl_2:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, in_full_fd, /* RET_ALLOW */ 55, /* lbl_3 */ 0 ),
+// lbl_3:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, in_incr_fd, /* RET_ALLOW */ 51, /* RET_KILL_PROCESS */ 50 ),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, in_incr_fd, /* RET_ALLOW */ 53, /* lbl_4 */ 0 ),
+// lbl_4:
+ /* load syscall argument 0 in accumulator */
+ BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, sockfd, /* RET_ALLOW */ 51, /* RET_KILL_PROCESS */ 50 ),
// check_lseek:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, in_full_fd, /* lbl_3 */ 2, /* lbl_4 */ 0 ),
-// lbl_4:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, in_full_fd, /* lbl_5 */ 2, /* lbl_6 */ 0 ),
+// lbl_6:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, in_incr_fd, /* lbl_3 */ 0, /* RET_KILL_PROCESS */ 46 ),
-// lbl_3:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, in_incr_fd, /* lbl_5 */ 0, /* RET_KILL_PROCESS */ 46 ),
+// lbl_5:
/* load syscall argument 1 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[1])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 0, /* lbl_5 */ 0, /* RET_KILL_PROCESS */ 44 ),
-// lbl_5:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 0, /* lbl_7 */ 0, /* RET_KILL_PROCESS */ 44 ),
+// lbl_7:
/* load syscall argument 2 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[2])),
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SEEK_SET, /* RET_ALLOW */ 43, /* RET_KILL_PROCESS */ 42 ),
// check_socket:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, AF_INET, /* lbl_6 */ 0, /* RET_KILL_PROCESS */ 40 ),
-// lbl_6:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, AF_INET, /* lbl_8 */ 0, /* RET_KILL_PROCESS */ 40 ),
+// lbl_8:
/* load syscall argument 1 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[1])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SOCK_STREAM|SOCK_NONBLOCK, /* lbl_7 */ 0, /* RET_KILL_PROCESS */ 38 ),
-// lbl_7:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SOCK_STREAM|SOCK_NONBLOCK, /* lbl_9 */ 0, /* RET_KILL_PROCESS */ 38 ),
+// lbl_9:
/* load syscall argument 2 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[2])),
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 0, /* RET_ALLOW */ 37, /* RET_KILL_PROCESS */ 36 ),
// check_connect:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_KILL_PROCESS */ 34, /* lbl_8 */ 0 ),
-// lbl_8:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_KILL_PROCESS */ 34, /* lbl_10 */ 0 ),
+// lbl_10:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_KILL_PROCESS */ 32, /* lbl_9 */ 0 ),
-// lbl_9:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_KILL_PROCESS */ 32, /* lbl_11 */ 0 ),
+// lbl_11:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, in_full_fd, /* RET_KILL_PROCESS */ 30, /* lbl_10 */ 0 ),
-// lbl_10:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, in_full_fd, /* RET_KILL_PROCESS */ 30, /* lbl_12 */ 0 ),
+// lbl_12:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, in_incr_fd, /* RET_KILL_PROCESS */ 28, /* RET_ALLOW */ 29 ),
// check_close:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_KILL_PROCESS */ 26, /* lbl_11 */ 0 ),
-// lbl_11:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_KILL_PROCESS */ 26, /* lbl_13 */ 0 ),
+// lbl_13:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_KILL_PROCESS */ 24, /* lbl_12 */ 0 ),
-// lbl_12:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_KILL_PROCESS */ 24, /* lbl_14 */ 0 ),
+// lbl_14:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, in_full_fd, /* RET_KILL_PROCESS */ 22, /* lbl_13 */ 0 ),
-// lbl_13:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, in_full_fd, /* RET_KILL_PROCESS */ 22, /* lbl_15 */ 0 ),
+// lbl_15:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, in_incr_fd, /* RET_KILL_PROCESS */ 20, /* RET_ALLOW */ 21 ),
// check_sendto:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_KILL_PROCESS */ 18, /* lbl_14 */ 0 ),
-// lbl_14:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_KILL_PROCESS */ 18, /* lbl_16 */ 0 ),
+// lbl_16:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_KILL_PROCESS */ 16, /* lbl_15 */ 0 ),
-// lbl_15:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_KILL_PROCESS */ 16, /* lbl_17 */ 0 ),
+// lbl_17:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, in_full_fd, /* RET_KILL_PROCESS */ 14, /* lbl_16 */ 0 ),
-// lbl_16:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, in_full_fd, /* RET_KILL_PROCESS */ 14, /* lbl_18 */ 0 ),
+// lbl_18:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, in_incr_fd, /* RET_KILL_PROCESS */ 12, /* RET_ALLOW */ 13 ),
// check_recvfrom:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_KILL_PROCESS */ 10, /* lbl_17 */ 0 ),
-// lbl_17:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_KILL_PROCESS */ 10, /* lbl_19 */ 0 ),
+// lbl_19:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_KILL_PROCESS */ 8, /* lbl_18 */ 0 ),
-// lbl_18:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_KILL_PROCESS */ 8, /* lbl_20 */ 0 ),
+// lbl_20:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
- BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, in_full_fd, /* RET_KILL_PROCESS */ 6, /* lbl_19 */ 0 ),
-// lbl_19:
+ BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, in_full_fd, /* RET_KILL_PROCESS */ 6, /* lbl_21 */ 0 ),
+// lbl_21:
/* load syscall argument 0 in accumulator */
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, in_incr_fd, /* RET_KILL_PROCESS */ 4, /* RET_ALLOW */ 5 ),
diff --git a/src/discof/restore/utils/fd_http_resolver.c b/src/discof/restore/utils/fd_http_resolver.c
index 216257d5c10..421ea335634 100644
--- a/src/discof/restore/utils/fd_http_resolver.c
+++ b/src/discof/restore/utils/fd_http_resolver.c
@@ -11,13 +11,18 @@
#include
#include
+#if FD_HAS_OPENSSL
+#include
+#include "../../../waltz/openssl/fd_openssl_tile.h"
+#endif
+
#define PEER_STATE_UNRESOLVED (0)
#define PEER_STATE_REFRESHING (1)
#define PEER_STATE_VALID (2)
#define PEER_STATE_INVALID (3)
#define PEER_DEADLINE_NANOS_VALID (5L*1000L*1000L*1000L) /* 5 seconds */
-#define PEER_DEADLINE_NANOS_RESOLVE (1L*1000L*1000L*1000L) /* 1 second */
+#define PEER_DEADLINE_NANOS_RESOLVE (2L*1000L*1000L*1000L) /* 2 seconds */
#define PEER_DEADLINE_NANOS_INVALID (5L*1000L*1000L*1000L) /* 5 seconds */
/* FIXME: The fds/fds_len/idx logic is fragile, replace with something
@@ -25,6 +30,8 @@
struct fd_ssresolve_peer {
fd_ip4_port_t addr;
+ char const * hostname;
+ int is_https;
fd_ssinfo_t ssinfo;
fd_ssresolve_t * full_ssresolve;
@@ -76,6 +83,10 @@ struct fd_http_resolver_private {
void * cb_arg;
fd_http_resolver_on_resolve_fn_t on_resolve_cb;
+#if FD_HAS_OPENSSL
+ SSL_CTX * ssl_ctx;
+#endif
+
ulong magic; /* ==FD_HTTP_RESOLVER_MAGIC */
};
@@ -155,6 +166,22 @@ fd_http_resolver_new( void * shmem,
resolver->cb_arg = cb_arg;
resolver->on_resolve_cb = on_resolve_cb;
+#if FD_HAS_OPENSSL
+ SSL_CTX * ssl_ctx = SSL_CTX_new( TLS_client_method() );
+ if( FD_UNLIKELY( !ssl_ctx ) ) {
+ FD_LOG_ERR(( "SSL_CTX_new failed" ));
+ }
+
+ if( FD_UNLIKELY( !SSL_CTX_set_min_proto_version( ssl_ctx, TLS1_3_VERSION ) ) ) {
+ FD_LOG_ERR(( "SSL_CTX_set_min_proto_version(ssl_ctx,TLS1_3_VERSION) failed" ));
+ }
+
+ /* transfering ownership of ssl_ctx by assignment */
+ resolver->ssl_ctx = ssl_ctx;
+
+ fd_ossl_load_certs( resolver->ssl_ctx );
+#endif
+
FD_COMPILER_MFENCE();
FD_VOLATILE( resolver->magic ) = FD_HTTP_RESOLVER_MAGIC;
FD_COMPILER_MFENCE();
@@ -186,13 +213,17 @@ fd_http_resolver_join( void * shresolver ) {
void
fd_http_resolver_add( fd_http_resolver_t * resolver,
- fd_ip4_port_t addr ) {
+ fd_ip4_port_t addr,
+ char const * hostname,
+ int is_https ) {
if( !peer_pool_free( resolver->pool ) ) {
FD_LOG_ERR(( "peer pool exhausted" ));
}
fd_ssresolve_peer_t * peer = peer_pool_ele_acquire( resolver->pool );
peer->state = PEER_STATE_UNRESOLVED;
peer->addr = addr;
+ peer->hostname = hostname;
+ peer->is_https = is_https;
peer->fd.idx = ULONG_MAX;
peer->ssinfo.full.slot = ULONG_MAX;
peer->ssinfo.incremental.base_slot = ULONG_MAX;
@@ -240,14 +271,31 @@ peer_connect( fd_http_resolver_t * resolver,
resolver->fds_idx[ resolver->fds_len ] = peer_pool_idx( resolver->pool, peer );
peer->fd.idx = resolver->fds_len;
resolver->fds_len++;
- fd_ssresolve_init( peer->full_ssresolve, peer->addr, resolver->fds[ peer->fd.idx ].fd, 1 );
+
+ if( FD_UNLIKELY( peer->is_https ) ) {
+#if FD_HAS_OPENSSL
+ fd_ssresolve_init_https( peer->full_ssresolve, peer->addr, resolver->fds[ peer->fd.idx ].fd, 1, peer->hostname, resolver->ssl_ctx );
+#else
+ FD_LOG_ERR(( "peer %s requires https but firedancer is built without openssl support. Please remove this peer from your validator config.", peer->hostname ));
+#endif
+ } else {
+ fd_ssresolve_init( peer->full_ssresolve, peer->addr, resolver->fds[ peer->fd.idx ].fd, 1 );
+ }
if( FD_LIKELY( resolver->incremental_snapshot_fetch ) ) {
err = create_socket( resolver, peer ); /* incremental */
if( FD_UNLIKELY( err ) ) return err;
resolver->fds_idx[ resolver->fds_len ] = peer_pool_idx( resolver->pool, peer );
resolver->fds_len++;
- fd_ssresolve_init( peer->inc_ssresolve, peer->addr, resolver->fds[ peer->fd.idx+1UL ].fd, 0 );
+ if( FD_UNLIKELY( peer->is_https ) ) {
+#if FD_HAS_OPENSSL
+ fd_ssresolve_init_https( peer->inc_ssresolve, peer->addr, resolver->fds[ peer->fd.idx+1UL ].fd, 0, peer->hostname, resolver->ssl_ctx );
+#else
+ FD_LOG_ERR(( "peer requires https but firedancer is built without openssl support" ));
+#endif
+ } else {
+ fd_ssresolve_init( peer->inc_ssresolve, peer->addr, resolver->fds[ peer->fd.idx+1UL ].fd, 0 );
+ }
} else {
resolver->fds[ resolver->fds_len ] = (struct pollfd) {
.fd = -1,
@@ -266,9 +314,9 @@ remove_peer( fd_http_resolver_t * resolver,
ulong idx ) {
FD_TEST( idxfds_len );
- /* FIXME: These sockets should be closed at the correct location */
- close( resolver->fds[ idx ].fd );
- if( FD_LIKELY( -1!=resolver->fds[ idx+1UL ].fd ) ) close( resolver->fds[ idx+1UL ].fd );
+ fd_ssresolve_peer_t * cur_peer = peer_pool_ele( resolver->pool, resolver->fds_idx[ idx ] );
+ fd_ssresolve_cancel( cur_peer->full_ssresolve );
+ fd_ssresolve_cancel( cur_peer->inc_ssresolve );
if( FD_UNLIKELY( resolver->fds_len==2UL ) ) {
resolver->fds_len = 0UL;
@@ -306,6 +354,7 @@ poll_resolve( fd_http_resolver_t * resolver,
fd_ssresolve_t * ssresolve,
ulong idx,
long now ) {
+ FD_TEST( !fd_ssresolve_is_done( ssresolve ) );
if( FD_LIKELY( pfd->revents & POLLOUT ) ) {
int res = fd_ssresolve_advance_poll_out( ssresolve );
@@ -324,7 +373,7 @@ poll_resolve( fd_http_resolver_t * resolver,
return -1;
} else if( FD_UNLIKELY( res==FD_SSRESOLVE_ADVANCE_AGAIN ) ) {
return -1;
- } else { /* FD_SSRESOLVE_ADVANCE_SUCCESS */
+ } else if( FD_LIKELY( res==FD_SSRESOLVE_ADVANCE_RESULT ) ) {
FD_TEST( peer->deadline_nanos>now );
if( resolve_result.base_slot==ULONG_MAX ) {
diff --git a/src/discof/restore/utils/fd_http_resolver.h b/src/discof/restore/utils/fd_http_resolver.h
index bc9461a4bfa..08738c4fa86 100644
--- a/src/discof/restore/utils/fd_http_resolver.h
+++ b/src/discof/restore/utils/fd_http_resolver.h
@@ -36,7 +36,9 @@ fd_http_resolver_new( void * shmem,
be unique. */
void
fd_http_resolver_add( fd_http_resolver_t * resolver,
- fd_ip4_port_t addr );
+ fd_ip4_port_t addr,
+ char const * hostname,
+ int is_https );
fd_http_resolver_t *
fd_http_resolver_join( void * shresolve );
diff --git a/src/discof/restore/utils/fd_ssctrl.h b/src/discof/restore/utils/fd_ssctrl.h
index f00f9653f0a..b95cc3d2d68 100644
--- a/src/discof/restore/utils/fd_ssctrl.h
+++ b/src/discof/restore/utils/fd_ssctrl.h
@@ -88,6 +88,8 @@ typedef struct fd_ssctrl_init {
int file;
int zstd;
fd_ip4_port_t addr;
+ char hostname[ 256UL ];
+ int is_https;
} fd_ssctrl_init_t;
/* Sent by snapld to tell snapct metadata about a downloaded snapshot. */
diff --git a/src/discof/restore/utils/fd_sshttp.c b/src/discof/restore/utils/fd_sshttp.c
index 211a68e5ae3..3a6592f2fef 100644
--- a/src/discof/restore/utils/fd_sshttp.c
+++ b/src/discof/restore/utils/fd_sshttp.c
@@ -3,6 +3,7 @@
#include "fd_ssarchive.h"
#include "../../../waltz/http/picohttpparser.h"
+#include "../../../waltz/openssl/fd_openssl_tile.h"
#include "../../../util/log/fd_log.h"
#include "../../../flamenco/types/fd_types_custom.h"
@@ -14,23 +15,39 @@
#include
#include
+#if FD_HAS_OPENSSL
+#include
+#endif
+
#define FD_SSHTTP_MAGIC (0xF17EDA2CE5811900) /* FIREDANCE HTTP V0 */
-#define FD_SSHTTP_STATE_INIT (0) /* start */
-#define FD_SSHTTP_STATE_REQ (1) /* sending request */
-#define FD_SSHTTP_STATE_RESP (2) /* receiving response headers */
-#define FD_SSHTTP_STATE_DL (3) /* downloading response body */
+#define FD_SSHTTP_STATE_INIT (0) /* start */
+#define FD_SSHTTP_STATE_CONNECT (1) /* connecting ssl */
+#define FD_SSHTTP_STATE_REQ (2) /* sending request */
+#define FD_SSHTTP_STATE_RESP (3) /* receiving response headers */
+#define FD_SSHTTP_STATE_DL (4) /* downloading response body */
+#define FD_SSHTTP_STATE_SHUTTING_DOWN (5) /* shutting down ssl */
+#define FD_SSHTTP_STATE_REDIRECT (6) /* redirect after shutting down ssl */
+#define FD_SSHTTP_STATE_DONE (7) /* done */
+
+#define FD_SSHTTP_DEADLINE_NANOS (1L*1000L*1000L*1000L) /* 1 second */
/* FIXME: Cleanup / standardize all the error logging. */
struct fd_sshttp_private {
int state;
+ int next_state; /* used for state transitions in https connection */
long deadline;
ulong empty_recvs;
int hops;
+ char location[ PATH_MAX ];
+ ulong location_len;
+
fd_ip4_port_t addr;
+ char const * hostname;
+ int is_https;
int sockfd;
char request[ 4096UL ];
@@ -42,6 +59,11 @@ struct fd_sshttp_private {
char snapshot_name[ PATH_MAX ];
+#if FD_HAS_OPENSSL
+ SSL_CTX * ssl_ctx;
+ SSL * ssl;
+#endif
+
ulong content_len;
ulong content_read;
@@ -80,8 +102,27 @@ fd_sshttp_new( void * shmem ) {
sshttp->content_len = 0UL;
fd_cstr_fini( sshttp->snapshot_name );
+#if FD_HAS_OPENSSL
+ sshttp->ssl = NULL;
+ sshttp->ssl_ctx = NULL;
+
+ SSL_CTX * ssl_ctx = SSL_CTX_new( TLS_client_method() );
+ if( FD_UNLIKELY( !ssl_ctx ) ) {
+ FD_LOG_ERR(( "SSL_CTX_new failed" ));
+ }
+
+ if( FD_UNLIKELY( !SSL_CTX_set_min_proto_version( ssl_ctx, TLS1_3_VERSION ) ) ) {
+ FD_LOG_ERR(( "SSL_CTX_set_min_proto_version(ssl_ctx,TLS1_3_VERSION) failed" ));
+ }
+
+ /* transfering ownership of ssl_ctx by assignment */
+ sshttp->ssl_ctx = ssl_ctx;
+
+ fd_ossl_load_certs( sshttp->ssl_ctx );
+#endif
+
FD_COMPILER_MFENCE();
- FD_VOLATILE( sshttp->magic ) = FD_SSHTTP_MAGIC;
+ sshttp->magic = FD_SSHTTP_MAGIC;
FD_COMPILER_MFENCE();
return (void *)sshttp;
@@ -109,31 +150,78 @@ fd_sshttp_join( void * shhttp ) {
return sshttp;
}
+#if FD_HAS_OPENSSL
+static void
+http_init_ssl( fd_sshttp_t * http ) {
+ FD_TEST( http->hostname );
+ FD_TEST( http->ssl_ctx );
+
+ http->ssl = SSL_new( http->ssl_ctx );
+ if( FD_UNLIKELY( !http->ssl ) ) {
+ FD_LOG_ERR(( "SSL_new failed" ));
+ }
+
+ static uchar const alpn_protos[] = { 8, 'h', 't', 't', 'p', '/', '1', '.', '1' };
+ int alpn_res = SSL_set_alpn_protos( http->ssl, alpn_protos, sizeof(alpn_protos) );
+ if( FD_UNLIKELY( alpn_res!=0 ) ) {
+ FD_LOG_ERR(( "SSL_set_alpn_protos failed (%d)", alpn_res ));
+ }
+
+ /* set SNI */
+ int set1_host_res = SSL_set1_host( http->ssl, http->hostname );
+ if( FD_UNLIKELY( !set1_host_res ) ) {
+ FD_LOG_ERR(( "SSL_set1_host failed (%d)", set1_host_res ));
+ }
+}
+#endif
+
void
fd_sshttp_init( fd_sshttp_t * http,
fd_ip4_port_t addr,
+ char const * hostname,
+ int is_https,
char const * path,
ulong path_len,
long now ) {
FD_TEST( http->state==FD_SSHTTP_STATE_INIT );
- http->hops = 4UL;
+ http->hostname = hostname;
+ http->is_https = is_https;
+
+ if( FD_LIKELY( is_https ) ) {
+#if FD_HAS_OPENSSL
+ http_init_ssl( http );
+#else
+ FD_LOG_ERR(( "cannot make HTTPS connection without OpenSSL" ));
+#endif
+ }
+ http->hops = 4UL;
http->request_sent = 0UL;
- FD_TEST( fd_cstr_printf_check( http->request, sizeof(http->request), &http->request_len,
- "GET %.*s HTTP/1.1\r\n"
- "User-Agent: Firedancer\r\n"
- "Accept: */*\r\n"
- "Accept-Encoding: identity\r\n"
- "Host: " FD_IP4_ADDR_FMT "\r\n\r\n",
- (int)path_len, path, FD_IP4_ADDR_FMT_ARGS( addr.addr ) ) );
+ if( FD_LIKELY( is_https ) ) {
+ FD_TEST( fd_cstr_printf_check( http->request, sizeof(http->request), &http->request_len,
+ "GET %.*s HTTP/1.1\r\n"
+ "User-Agent: Firedancer\r\n"
+ "Accept: */*\r\n"
+ "Accept-Encoding: identity\r\n"
+ "Host: %s\r\n\r\n",
+ (int)path_len, path, hostname ) );
+ } else {
+ FD_TEST( fd_cstr_printf_check( http->request, sizeof(http->request), &http->request_len,
+ "GET %.*s HTTP/1.1\r\n"
+ "User-Agent: Firedancer\r\n"
+ "Accept: */*\r\n"
+ "Accept-Encoding: identity\r\n"
+ "Host: " FD_IP4_ADDR_FMT "\r\n\r\n",
+ (int)path_len, path, FD_IP4_ADDR_FMT_ARGS( addr.addr ) ) );
+ }
http->response_len = 0UL;
http->content_len = 0UL;
http->content_read = 0UL;
http->empty_recvs = 0UL;
- http->addr = addr;
+ http->addr = addr;
http->sockfd = socket( AF_INET, SOCK_STREAM|SOCK_NONBLOCK, 0 );
if( FD_UNLIKELY( -1==http->sockfd ) ) FD_LOG_ERR(( "socket() failed (%d-%s)", errno, fd_io_strerror( errno ) ));
@@ -149,10 +237,119 @@ fd_sshttp_init( fd_sshttp_t * http,
}
}
+ if( FD_LIKELY( is_https ) ) {
+ http->state = FD_SSHTTP_STATE_CONNECT;
+ http->deadline = now + FD_SSHTTP_DEADLINE_NANOS;
+ } else {
+ http->state = FD_SSHTTP_STATE_REQ;
+ http->deadline = now + FD_SSHTTP_DEADLINE_NANOS;
+ }
+}
+
+#if FD_HAS_OPENSSL
+static int
+http_connect_ssl( fd_sshttp_t * http,
+ long now ) {
+ if( FD_UNLIKELY( now>http->deadline ) ) {
+ FD_LOG_WARNING(("deadline exceeded during connect"));
+ fd_sshttp_cancel( http );
+ return FD_SSHTTP_ADVANCE_ERROR;
+ }
+
+ FD_TEST( http->ssl );
+ SSL_set_fd( http->ssl, http->sockfd );
+ int ssl_err = SSL_connect( http->ssl );
+ if( FD_UNLIKELY( ssl_err!=1 ) ) {
+ int ssl_err_code = SSL_get_error( http->ssl, ssl_err );
+ if( FD_UNLIKELY( ssl_err_code!=SSL_ERROR_WANT_READ && ssl_err_code!=SSL_ERROR_WANT_WRITE ) ) {
+ FD_LOG_WARNING(( "SSL_connect failed (%d)", ssl_err ));
+ SSL_free( http->ssl );
+ http->ssl = NULL;
+ return FD_SSHTTP_ADVANCE_ERROR;
+ }
+ /* in progress */
+ return FD_SSHTTP_ADVANCE_AGAIN;
+ }
+
http->state = FD_SSHTTP_STATE_REQ;
- http->deadline = now + 500L*1000L*1000L;
+ http->deadline = now + FD_SSHTTP_DEADLINE_NANOS;
+ return FD_SSHTTP_ADVANCE_AGAIN;
}
+static int
+http_shutdown_ssl( fd_sshttp_t * http,
+ long now ) {
+ if( FD_UNLIKELY( now>http->deadline ) ) {
+ FD_LOG_WARNING(("deadline exceeded during shutdown"));
+ fd_sshttp_cancel( http );
+ return FD_SSHTTP_ADVANCE_ERROR;
+ }
+
+ int res = SSL_shutdown( http->ssl );
+ if( FD_LIKELY( res<=0 ) ) {
+ int ssl_err_code = SSL_get_error( http->ssl, res );
+ if( FD_UNLIKELY( ssl_err_code!=SSL_ERROR_WANT_READ && ssl_err_code!=SSL_ERROR_WANT_WRITE && res!=0 ) ) {
+ FD_LOG_WARNING(( "SSL_shutdown failed (%d)", ssl_err_code ));
+ SSL_free( http->ssl );
+ http->ssl = NULL;
+ return FD_SSHTTP_ADVANCE_ERROR;
+ }
+
+ return FD_SSHTTP_ADVANCE_AGAIN;
+ }
+
+ http->state = http->next_state;
+ return FD_SSHTTP_ADVANCE_AGAIN;
+}
+
+static long
+http_recv_ssl( fd_sshttp_t * http,
+ void * buf,
+ ulong bufsz ) {
+ int read_res = SSL_read( http->ssl, buf, (int)bufsz );
+ if( FD_UNLIKELY( read_res<=0 ) ) {
+ int ssl_err = SSL_get_error( http->ssl, read_res );
+
+ if( FD_UNLIKELY( ssl_err!=SSL_ERROR_WANT_READ && ssl_err!=SSL_ERROR_WANT_WRITE ) ) {
+ FD_LOG_WARNING(( "SSL_read failed (%d)", ssl_err ));
+ return FD_SSHTTP_ADVANCE_ERROR;
+ }
+
+ return FD_SSHTTP_ADVANCE_AGAIN;
+ }
+
+ return (long)read_res;
+}
+
+static long
+http_send_ssl( fd_sshttp_t * http,
+ void * buf,
+ ulong bufsz ) {
+ int write_res = SSL_write( http->ssl, buf, (int)bufsz );
+ if( FD_UNLIKELY( write_res<=0 ) ) {
+ int ssl_err = SSL_get_error( http->ssl, write_res );
+
+ if( FD_UNLIKELY( ssl_err!=SSL_ERROR_WANT_READ && ssl_err!=SSL_ERROR_WANT_WRITE ) ) {
+ FD_LOG_WARNING(( "SSL_write failed (%d)", ssl_err ));
+ return FD_SSHTTP_ADVANCE_ERROR;
+ }
+
+ return FD_SSHTTP_ADVANCE_AGAIN;
+ }
+
+ return (long)write_res;
+}
+
+static int
+setup_redirect( fd_sshttp_t * http,
+ long now ) {
+ fd_sshttp_cancel( http );
+ fd_sshttp_init( http, http->addr, http->hostname, http->is_https, http->location, http->location_len, now );
+ return FD_SSHTTP_ADVANCE_AGAIN;
+}
+
+#endif
+
void
fd_sshttp_cancel( fd_sshttp_t * http ) {
if( FD_LIKELY( http->state!=FD_SSHTTP_STATE_INIT && -1!=http->sockfd ) ) {
@@ -160,6 +357,64 @@ fd_sshttp_cancel( fd_sshttp_t * http ) {
http->sockfd = -1;
}
http->state = FD_SSHTTP_STATE_INIT;
+
+#if FD_HAS_OPENSSL
+ if( FD_LIKELY( http->ssl ) ) {
+ SSL_free( http->ssl );
+ http->ssl = NULL;
+ }
+#endif
+}
+
+static long
+http_send( fd_sshttp_t * http,
+ void * buf,
+ ulong bufsz ) {
+#if FD_HAS_OPENSSL
+ if( FD_LIKELY( http->is_https ) ) return http_send_ssl( http, buf, bufsz );
+#endif
+
+ long sent = sendto( http->sockfd, buf, bufsz, 0, NULL, 0 );
+ if( FD_UNLIKELY( -1==sent && errno==EAGAIN ) ) return FD_SSHTTP_ADVANCE_AGAIN;
+ else if( FD_UNLIKELY( -1==sent ) ) {
+ FD_LOG_WARNING(( "sendto() failed (%d-%s)", errno, fd_io_strerror( errno ) ));
+ fd_sshttp_cancel( http );
+ return FD_SSHTTP_ADVANCE_ERROR;
+ }
+
+ return sent;
+}
+
+static long
+http_recv( fd_sshttp_t * http,
+ void * buf,
+ ulong bufsz ) {
+#if FD_HAS_OPENSSL
+ if( FD_LIKELY( http->is_https ) ) return http_recv_ssl( http, buf, bufsz );
+#endif
+
+ long read = recvfrom( http->sockfd, buf, bufsz, 0, NULL, NULL );
+ if( FD_UNLIKELY( -1==read && errno==EAGAIN ) ) {
+ if( FD_UNLIKELY( ++http->empty_recvs>8UL ) ) {
+ /* If we have gone several iterations without having any data to
+ read, sleep the thread for up to one millisecond, or until
+ the socket is readable again, whichever comes first. */
+ struct pollfd pfd = {
+ .fd = http->sockfd,
+ .events = POLLIN,
+ };
+ if( -1==fd_syscall_poll( &pfd, 1 /*fds*/, 1 /*ms*/ ) ) {
+ FD_LOG_ERR(("fd_syscall_poll() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
+ }
+ }
+ return FD_SSHTTP_ADVANCE_AGAIN;
+ } else if( FD_UNLIKELY( -1==read ) ) {
+ fd_sshttp_cancel( http );
+ return FD_SSHTTP_ADVANCE_ERROR;
+ }
+ http->empty_recvs = 0UL;
+
+ return read;
}
static int
@@ -170,18 +425,14 @@ send_request( fd_sshttp_t * http,
return FD_SSHTTP_ADVANCE_ERROR;
}
- long sent = sendto( http->sockfd, http->request+http->request_sent, http->request_len-http->request_sent, 0, NULL, 0 );
- if( FD_UNLIKELY( -1==sent && errno==EAGAIN ) ) return FD_SSHTTP_ADVANCE_AGAIN;
- else if( FD_UNLIKELY( -1==sent ) ) {
- fd_sshttp_cancel( http );
- return FD_SSHTTP_ADVANCE_ERROR;
- }
+ long sent = http_send( http, http->request+http->request_sent, http->request_len-http->request_sent );
+ if( FD_UNLIKELY( sent<=0 ) ) return (int)sent;
http->request_sent += (ulong)sent;
if( FD_UNLIKELY( http->request_sent==http->request_len ) ) {
- http->state = FD_SSHTTP_STATE_RESP;
+ http->state = FD_SSHTTP_STATE_RESP;
http->response_len = 0UL;
- http->deadline = now + 500L*1000L*1000L;
+ http->deadline = now + FD_SSHTTP_DEADLINE_NANOS;
}
return FD_SSHTTP_ADVANCE_AGAIN;
@@ -264,12 +515,21 @@ follow_redirect( fd_sshttp_t * http,
return FD_SSHTTP_ADVANCE_ERROR;
}
- FD_LOG_NOTICE(( "following redirect to http://" FD_IP4_ADDR_FMT ":%hu%.*s",
- FD_IP4_ADDR_FMT_ARGS( http->addr.addr ), fd_ushort_bswap( http->addr.port ),
+ FD_LOG_NOTICE(( "following redirect to %s://" FD_IP4_ADDR_FMT ":%hu%.*s",
+ http->is_https ? "https" : "http", FD_IP4_ADDR_FMT_ARGS( http->addr.addr ), fd_ushort_bswap( http->addr.port ),
(int)location_len, location ));
- fd_sshttp_cancel( http );
- fd_sshttp_init( http, http->addr, location, location_len, now );
+ if( FD_UNLIKELY( http->is_https ) ) {
+ http->next_state = FD_SSHTTP_STATE_REDIRECT;
+ http->state = FD_SSHTTP_STATE_SHUTTING_DOWN;
+ http->location_len = location_len;
+ FD_TEST( location_lenlocation, location, location_len );
+ http->location[ location_len ] = '\0';
+ } else {
+ fd_sshttp_cancel( http );
+ fd_sshttp_init( http, http->addr, http->hostname, http->is_https, location, location_len, now );
+ }
return FD_SSHTTP_ADVANCE_AGAIN;
}
@@ -285,13 +545,8 @@ read_response( fd_sshttp_t * http,
return FD_SSHTTP_ADVANCE_ERROR;
}
- long read = recvfrom( http->sockfd, http->response+http->response_len, sizeof(http->response)-http->response_len, 0, NULL, NULL );
- if( FD_UNLIKELY( -1==read && errno==EAGAIN ) ) return FD_SSHTTP_ADVANCE_AGAIN;
- else if( FD_UNLIKELY( -1==read ) ) {
- FD_LOG_WARNING(( "recv() failed (%d-%s)", errno, fd_io_strerror( errno ) ));
- fd_sshttp_cancel( http );
- return FD_SSHTTP_ADVANCE_ERROR;
- }
+ long read = http_recv( http, http->response+http->response_len, sizeof(http->response)-http->response_len );
+ if( FD_UNLIKELY( read<=0 ) ) return (int)read;
http->response_len += (ulong)read;
@@ -362,32 +617,26 @@ read_response( fd_sshttp_t * http,
static int
read_body( fd_sshttp_t * http,
ulong * data_len,
- uchar * data ) {
+ uchar * data,
+ long now ) {
/* FIXME: Add a forward-progress timeout */
if( FD_UNLIKELY( http->content_read>=http->content_len ) ) {
- fd_sshttp_cancel( http );
- return FD_SSHTTP_ADVANCE_DONE;
- }
-
- long read = recvfrom( http->sockfd, data, fd_ulong_min( *data_len, http->content_len-http->content_read ), 0, NULL, NULL );
- if( FD_UNLIKELY( -1==read && errno==EAGAIN ) ) {
- if( FD_UNLIKELY( ++http->empty_recvs>8UL ) ) {
- /* If we have gone several iterations without having any data to
- read, sleep the thread for up to one millisecond, or until
- the socket is readable again, whichever comes first. */
- struct pollfd pfd = {
- .fd = http->sockfd,
- .events = POLLIN,
- };
- fd_syscall_poll( &pfd, 1 /*fds*/, 1 /*ms*/ );
+ if( FD_UNLIKELY( http->is_https ) ) {
+ http->next_state = FD_SSHTTP_STATE_DONE;
+ http->state = FD_SSHTTP_STATE_SHUTTING_DOWN;
+ http->deadline = now + FD_SSHTTP_DEADLINE_NANOS;
+ return FD_SSHTTP_ADVANCE_AGAIN;
+ } else {
+ fd_sshttp_cancel( http );
+ http->state = FD_SSHTTP_STATE_INIT;
+ return FD_SSHTTP_ADVANCE_DONE;
}
- return FD_SSHTTP_ADVANCE_AGAIN;
- } else if( FD_UNLIKELY( -1==read ) ) {
- fd_sshttp_cancel( http );
- return FD_SSHTTP_ADVANCE_ERROR;
}
- http->empty_recvs = 0UL;
+
+ FD_TEST( http->content_readcontent_len );
+ long read = http_recv( http, data, fd_ulong_min( *data_len, http->content_len-http->content_read ) );
+ if( FD_UNLIKELY( read<=0 ) ) return (int)read;
if( FD_UNLIKELY( !read ) ) return FD_SSHTTP_ADVANCE_AGAIN;
@@ -413,10 +662,19 @@ fd_sshttp_advance( fd_sshttp_t * http,
uchar * data,
long now ) {
switch( http->state ) {
- case FD_SSHTTP_STATE_INIT: return FD_SSHTTP_ADVANCE_ERROR;
- case FD_SSHTTP_STATE_REQ: return send_request( http, now );
- case FD_SSHTTP_STATE_RESP: return read_response( http, data_len, data, now );
- case FD_SSHTTP_STATE_DL: return read_body( http, data_len, data );
- default: return FD_SSHTTP_ADVANCE_ERROR;
+ case FD_SSHTTP_STATE_INIT: return FD_SSHTTP_ADVANCE_AGAIN;
+#if FD_HAS_OPENSSL
+ case FD_SSHTTP_STATE_CONNECT: return http_connect_ssl( http, now );
+ case FD_SSHTTP_STATE_SHUTTING_DOWN: return http_shutdown_ssl( http, now );
+ case FD_SSHTTP_STATE_REDIRECT: return setup_redirect( http, now );
+#endif
+ case FD_SSHTTP_STATE_REQ: return send_request( http, now );
+ case FD_SSHTTP_STATE_RESP: return read_response( http, data_len, data, now );
+ case FD_SSHTTP_STATE_DL: return read_body( http, data_len, data, now );
+ case FD_SSHTTP_STATE_DONE:
+ fd_sshttp_cancel( http );
+ http->state = FD_SSHTTP_STATE_INIT;
+ return FD_SSHTTP_ADVANCE_DONE;
+ default: return FD_SSHTTP_ADVANCE_ERROR;
}
}
diff --git a/src/discof/restore/utils/fd_sshttp.h b/src/discof/restore/utils/fd_sshttp.h
index 83130d26cf7..2cf91a26673 100644
--- a/src/discof/restore/utils/fd_sshttp.h
+++ b/src/discof/restore/utils/fd_sshttp.h
@@ -29,6 +29,8 @@ fd_sshttp_content_len( fd_sshttp_t const * http );
void
fd_sshttp_init( fd_sshttp_t * http,
fd_ip4_port_t addr,
+ char const * hostname,
+ int is_https,
char const * path,
ulong path_len,
long now );
diff --git a/src/discof/restore/utils/fd_sspeer_selector.c b/src/discof/restore/utils/fd_sspeer_selector.c
index e253ccb4b9c..336ff12bc78 100644
--- a/src/discof/restore/utils/fd_sspeer_selector.c
+++ b/src/discof/restore/utils/fd_sspeer_selector.c
@@ -319,9 +319,9 @@ fd_sspeer_selector_best( fd_sspeer_selector_t * selector,
(!incremental ||
(incremental && peer->ssinfo.incremental.base_slot==base_slot) ) ) ) {
return (fd_sspeer_t){
- .addr = peer->addr,
- .ssinfo = peer->ssinfo,
- .score = peer->score,
+ .addr = peer->addr,
+ .ssinfo = peer->ssinfo,
+ .score = peer->score,
};
}
}
diff --git a/src/discof/restore/utils/fd_ssresolve.c b/src/discof/restore/utils/fd_ssresolve.c
index 40733f73846..c1a04d476ae 100644
--- a/src/discof/restore/utils/fd_ssresolve.c
+++ b/src/discof/restore/utils/fd_ssresolve.c
@@ -13,9 +13,14 @@
#include
#include
-#define FD_SSRESOLVE_STATE_REQ (0) /* sending request for snapshot */
-#define FD_SSRESOLVE_STATE_RESP (1) /* receiving snapshot response */
-#define FD_SSRESOLVE_STATE_DONE (2) /* done */
+/* TODO: consider refactoring the common http code in ssresolve and
+ sshttp into a common library */
+
+#define FD_SSRESOLVE_CONNECT (0) /* connecting ssl */
+#define FD_SSRESOLVE_STATE_REQ (1) /* sending request for snapshot */
+#define FD_SSRESOLVE_STATE_RESP (2) /* receiving snapshot response */
+#define FD_SSRESOLVE_STATE_SHUTTING_DOWN (3) /* shutting down ssl */
+#define FD_SSRESOLVE_STATE_DONE (4) /* done */
struct fd_ssresolve_private {
int state;
@@ -24,6 +29,8 @@ struct fd_ssresolve_private {
fd_ip4_port_t addr;
int sockfd;
int full;
+ int is_https;
+ char const * hostname;
char request[ 4096UL ];
ulong request_sent;
@@ -32,6 +39,10 @@ struct fd_ssresolve_private {
ulong response_len;
char response[ USHORT_MAX ];
+#if FD_HAS_OPENSSL
+ SSL * ssl;
+#endif
+
ulong magic;
};
@@ -67,6 +78,11 @@ fd_ssresolve_new( void * shmem ) {
ssresolve->request_sent = 0UL;
ssresolve->request_len = 0UL;
ssresolve->response_len = 0UL;
+ ssresolve->sockfd = -1;
+
+#if FD_HAS_OPENSSL
+ ssresolve->ssl = NULL;
+#endif
FD_COMPILER_MFENCE();
FD_VOLATILE( ssresolve->magic ) = FD_SSRESOLVE_MAGIC;
@@ -110,27 +126,86 @@ fd_ssresolve_init( fd_ssresolve_t * ssresolve,
ssresolve->request_sent = 0UL;
ssresolve->request_len = 0UL;
ssresolve->response_len = 0UL;
+ ssresolve->is_https = 0;
}
+#if FD_HAS_OPENSSL
+void
+fd_ssresolve_init_https( fd_ssresolve_t * ssresolve,
+ fd_ip4_port_t addr,
+ int sockfd,
+ int full,
+ char const * hostname,
+ SSL_CTX * ssl_ctx ) {
+ ssresolve->addr = addr;
+ ssresolve->sockfd = sockfd;
+ ssresolve->full = full;
+
+ ssresolve->state = FD_SSRESOLVE_CONNECT;
+ ssresolve->request_sent = 0UL;
+ ssresolve->request_len = 0UL;
+ ssresolve->response_len = 0UL;
+ ssresolve->is_https = 1;
+ ssresolve->hostname = hostname;
+
+ ssresolve->ssl = SSL_new( ssl_ctx );
+ if( FD_UNLIKELY( !ssresolve->ssl ) ) {
+ FD_LOG_ERR(( "SSL_new failed" ));
+ }
+
+ static uchar const alpn_protos[] = { 8, 'h', 't', 't', 'p', '/', '1', '.', '1' };
+ int alpn_res = SSL_set_alpn_protos( ssresolve->ssl, alpn_protos, sizeof(alpn_protos) );
+ if( FD_UNLIKELY( alpn_res!=0 ) ) {
+ FD_LOG_ERR(( "SSL_set_alpn_protos failed (%d)", alpn_res ));
+ }
+
+ /* set SNI */
+ FD_TEST( hostname && hostname[ 0 ]!='\0' );
+ int set1_host_res = SSL_set1_host( ssresolve->ssl, hostname );
+ if( FD_UNLIKELY( !set1_host_res ) ) {
+ FD_LOG_ERR(( "SSL_set1_host failed (%d)", set1_host_res ));
+ }
+}
+#endif
+
static void
-fd_ssresolve_render_req( fd_ssresolve_t * ssresolve,
- fd_ip4_port_t addr ) {
+fd_ssresolve_render_req( fd_ssresolve_t * ssresolve ) {
if( FD_LIKELY( ssresolve->full ) ) {
- FD_TEST( fd_cstr_printf_check( ssresolve->request, sizeof(ssresolve->request), &ssresolve->request_len,
- "GET /snapshot.tar.bz2 HTTP/1.1\r\n"
+ if( FD_UNLIKELY( ssresolve->is_https ) ) {
+ FD_TEST( fd_cstr_printf_check( ssresolve->request, sizeof(ssresolve->request), &ssresolve->request_len,
+ "HEAD /snapshot.tar.bz2 HTTP/1.1\r\n"
+ "User-Agent: Firedancer\r\n"
+ "Accept: */*\r\n"
+ "Accept-Encoding: identity\r\n"
+ "Host: %s\r\n\r\n",
+ ssresolve->hostname ) );
+ } else {
+ FD_TEST( fd_cstr_printf_check( ssresolve->request, sizeof(ssresolve->request), &ssresolve->request_len,
+ "HEAD /snapshot.tar.bz2 HTTP/1.1\r\n"
"User-Agent: Firedancer\r\n"
"Accept: */*\r\n"
"Accept-Encoding: identity\r\n"
"Host: " FD_IP4_ADDR_FMT "\r\n\r\n",
- FD_IP4_ADDR_FMT_ARGS( addr.addr ) ) );
+ FD_IP4_ADDR_FMT_ARGS( ssresolve->addr.addr ) ) );
+ }
} else {
- FD_TEST( fd_cstr_printf_check( ssresolve->request, sizeof(ssresolve->request), &ssresolve->request_len,
- "GET /incremental-snapshot.tar.bz2 HTTP/1.1\r\n"
+ if( FD_UNLIKELY( ssresolve->is_https ) ) {
+ FD_TEST( fd_cstr_printf_check( ssresolve->request, sizeof(ssresolve->request), &ssresolve->request_len,
+ "HEAD /incremental-snapshot.tar.bz2 HTTP/1.1\r\n"
+ "User-Agent: Firedancer\r\n"
+ "Accept: */*\r\n"
+ "Accept-Encoding: identity\r\n"
+ "Host: %s\r\n\r\n",
+ ssresolve->hostname ) );
+ } else {
+ FD_TEST( fd_cstr_printf_check( ssresolve->request, sizeof(ssresolve->request), &ssresolve->request_len,
+ "HEAD /incremental-snapshot.tar.bz2 HTTP/1.1\r\n"
"User-Agent: Firedancer\r\n"
"Accept: */*\r\n"
"Accept-Encoding: identity\r\n"
"Host: " FD_IP4_ADDR_FMT "\r\n\r\n",
- FD_IP4_ADDR_FMT_ARGS( addr.addr ) ) );
+ FD_IP4_ADDR_FMT_ARGS( ssresolve->addr.addr ) ) );
+ }
}
}
@@ -139,13 +214,32 @@ fd_ssresolve_send_request( fd_ssresolve_t * ssresolve ) {
FD_TEST( ssresolve->state==FD_SSRESOLVE_STATE_REQ );
if( FD_UNLIKELY( !ssresolve->request_len ) ) {
- fd_ssresolve_render_req( ssresolve, ssresolve->addr );
+ fd_ssresolve_render_req( ssresolve );
}
- long sent = sendto( ssresolve->sockfd, ssresolve->request+ssresolve->request_sent, ssresolve->request_len-ssresolve->request_sent, 0, NULL, 0 );
- if( FD_UNLIKELY( -1==sent && errno==EAGAIN ) ) return FD_SSRESOLVE_ADVANCE_AGAIN;
- else if( FD_UNLIKELY( -1==sent ) ) {
- return FD_SSRESOLVE_ADVANCE_ERROR;
+ long sent = 0L;
+ if( FD_LIKELY( ssresolve->is_https ) ) {
+#if FD_HAS_OPENSSL
+ int write_res = SSL_write( ssresolve->ssl, ssresolve->request+ssresolve->request_sent, (int)(ssresolve->request_len-ssresolve->request_sent) );
+ if( FD_UNLIKELY( write_res<=0 ) ) {
+ int ssl_err = SSL_get_error( ssresolve->ssl, write_res );
+
+ if( FD_UNLIKELY( ssl_err!=SSL_ERROR_WANT_READ && ssl_err!=SSL_ERROR_WANT_WRITE ) ) {
+ FD_LOG_WARNING(( "SSL_write failed (%d)", ssl_err ));
+ return FD_SSRESOLVE_ADVANCE_ERROR;
+ }
+
+ return FD_SSRESOLVE_ADVANCE_AGAIN;
+ }
+
+ sent = (long)write_res;
+#else
+ FD_LOG_ERR(( "cannot use HTTPS without OpenSSL" ));
+#endif
+ } else {
+ sent = sendto( ssresolve->sockfd, ssresolve->request+ssresolve->request_sent, ssresolve->request_len-ssresolve->request_sent, 0, NULL, 0 );
+ if( FD_UNLIKELY( -1==sent && errno==EAGAIN ) ) return FD_SSRESOLVE_ADVANCE_AGAIN;
+ else if( FD_UNLIKELY( -1==sent ) ) return FD_SSRESOLVE_ADVANCE_ERROR;
}
ssresolve->request_sent += (ulong)sent;
@@ -202,19 +296,42 @@ fd_ssresolve_parse_redirect( fd_ssresolve_t * ssresolve,
result->base_slot = full_entry_slot;
}
- ssresolve->state = FD_SSRESOLVE_STATE_DONE;
- return FD_SSRESOLVE_ADVANCE_SUCCESS;
+ if( FD_UNLIKELY( ssresolve->is_https ) ) ssresolve->state = FD_SSRESOLVE_STATE_SHUTTING_DOWN;
+ else ssresolve->state = FD_SSRESOLVE_STATE_DONE;
+ return FD_SSRESOLVE_ADVANCE_RESULT;
}
static int
fd_ssresolve_read_response( fd_ssresolve_t * ssresolve,
fd_ssresolve_result_t * result ) {
FD_TEST( ssresolve->state==FD_SSRESOLVE_STATE_RESP );
- long read = recvfrom( ssresolve->sockfd, ssresolve->response+ssresolve->response_len, sizeof(ssresolve->response)-ssresolve->response_len, 0, NULL, NULL );
- if( FD_UNLIKELY( -1==read && errno==EAGAIN ) ) return FD_SSRESOLVE_ADVANCE_AGAIN;
- else if( FD_UNLIKELY( -1==read ) ) {
- FD_LOG_WARNING(( "recvfrom() failed (%d-%s)", errno, fd_io_strerror( errno ) ));
- return FD_SSRESOLVE_ADVANCE_ERROR;
+
+ long read = 0L;
+ if( FD_LIKELY( ssresolve->is_https ) ) {
+#if FD_HAS_OPENSSL
+ int read_res = SSL_read( ssresolve->ssl, ssresolve->response+ssresolve->response_len, (int)(sizeof(ssresolve->response)-ssresolve->response_len) );
+ if( FD_UNLIKELY( read_res<=0 ) ) {
+ int ssl_err = SSL_get_error( ssresolve->ssl, read_res );
+
+ if( FD_UNLIKELY( ssl_err!=SSL_ERROR_WANT_READ && ssl_err!=SSL_ERROR_WANT_WRITE ) ) {
+ FD_LOG_WARNING(( "SSL_read failed (%d)", ssl_err ));
+ return FD_SSRESOLVE_ADVANCE_ERROR;
+ }
+
+ return FD_SSRESOLVE_ADVANCE_AGAIN;
+ }
+
+ read = (long)read_res;
+#else
+ FD_LOG_ERR(( "cannot use HTTPS without OpenSSL" ));
+#endif
+ } else {
+ read = recvfrom( ssresolve->sockfd, ssresolve->response+ssresolve->response_len, sizeof(ssresolve->response)-ssresolve->response_len, 0, NULL, NULL );
+ if( FD_UNLIKELY( -1==read && errno==EAGAIN ) ) return FD_SSRESOLVE_ADVANCE_AGAIN;
+ else if( FD_UNLIKELY( -1==read ) ) {
+ FD_LOG_WARNING(( "recvfrom() failed (%d-%s)", errno, fd_io_strerror( errno ) ));
+ return FD_SSRESOLVE_ADVANCE_ERROR;
+ }
}
ssresolve->response_len += (ulong)read;
@@ -254,10 +371,62 @@ fd_ssresolve_read_response( fd_ssresolve_t * ssresolve,
return FD_SSRESOLVE_ADVANCE_ERROR;
}
+#if FD_HAS_OPENSSL
+static int
+ssresolve_connect_ssl( fd_ssresolve_t * ssresolve ) {
+ FD_TEST( ssresolve->ssl );
+ SSL_set_fd( ssresolve->ssl, ssresolve->sockfd );
+ int ssl_err = SSL_connect( ssresolve->ssl );
+ if( FD_UNLIKELY( ssl_err!=1 ) ) {
+ int ssl_err_code = SSL_get_error( ssresolve->ssl, ssl_err );
+ if( FD_UNLIKELY( ssl_err_code!=SSL_ERROR_WANT_READ && ssl_err_code!=SSL_ERROR_WANT_WRITE ) ) {
+ FD_LOG_WARNING(( "SSL_connect failed (%d)", ssl_err_code ));
+ SSL_free( ssresolve->ssl );
+ ssresolve->ssl = NULL;
+ return FD_SSRESOLVE_ADVANCE_ERROR;
+ }
+ /* in progress */
+ return FD_SSRESOLVE_ADVANCE_AGAIN;
+ }
+
+ ssresolve->state = FD_SSRESOLVE_STATE_REQ;
+ return FD_SSRESOLVE_ADVANCE_AGAIN;
+}
+
+static int
+ssresolve_shutdown_ssl( fd_ssresolve_t * ssresolve ) {
+ int res = SSL_shutdown( ssresolve->ssl );
+ if( FD_LIKELY( res<=0 ) ) {
+ int ssl_err_code = SSL_get_error( ssresolve->ssl, res );
+ if( FD_UNLIKELY( ssl_err_code!=SSL_ERROR_WANT_READ && ssl_err_code!=SSL_ERROR_WANT_WRITE && res!=0 ) ) {
+ FD_LOG_WARNING(( "SSL_shutdown failed (%d)", ssl_err_code ));
+ SSL_free( ssresolve->ssl );
+ ssresolve->ssl = NULL;
+ return FD_SSRESOLVE_ADVANCE_ERROR;
+ }
+
+ return FD_SSRESOLVE_ADVANCE_AGAIN;
+ }
+
+ ssresolve->state = FD_SSRESOLVE_STATE_DONE;
+ return FD_SSRESOLVE_ADVANCE_SUCCESS;
+}
+#endif
+
int
fd_ssresolve_advance_poll_out( fd_ssresolve_t * ssresolve ) {
int res;
switch( ssresolve->state ) {
+#if FD_HAS_OPENSSL
+ case FD_SSRESOLVE_CONNECT: {
+ res = ssresolve_connect_ssl( ssresolve );
+ break;
+ }
+ case FD_SSRESOLVE_STATE_SHUTTING_DOWN: {
+ res = ssresolve_shutdown_ssl( ssresolve );
+ break;
+ }
+#endif
case FD_SSRESOLVE_STATE_REQ: {
res = fd_ssresolve_send_request( ssresolve );
break;
@@ -279,6 +448,16 @@ fd_ssresolve_advance_poll_in( fd_ssresolve_t * ssresolve,
fd_ssresolve_result_t * result ) {
int res;
switch( ssresolve->state ) {
+#if FD_HAS_OPENSSL
+ case FD_SSRESOLVE_CONNECT: {
+ res = ssresolve_connect_ssl( ssresolve );
+ break;
+ }
+ case FD_SSRESOLVE_STATE_SHUTTING_DOWN: {
+ res = ssresolve_shutdown_ssl( ssresolve );
+ break;
+ }
+#endif
case FD_SSRESOLVE_STATE_RESP: {
res = fd_ssresolve_read_response( ssresolve, result );
break;
@@ -287,6 +466,10 @@ fd_ssresolve_advance_poll_in( fd_ssresolve_t * ssresolve,
res = FD_SSRESOLVE_ADVANCE_AGAIN;
break;
}
+ case FD_SSRESOLVE_STATE_DONE: {
+ res = FD_SSRESOLVE_ADVANCE_SUCCESS;
+ break;
+ }
default: {
FD_LOG_ERR(( "unexpected state %d", ssresolve->state ));
return FD_SSRESOLVE_ADVANCE_ERROR;
@@ -300,3 +483,17 @@ int
fd_ssresolve_is_done( fd_ssresolve_t * ssresolve ) {
return ssresolve->state==FD_SSRESOLVE_STATE_DONE;
}
+
+void
+fd_ssresolve_cancel( fd_ssresolve_t * ssresolve ) {
+ if( FD_LIKELY( ssresolve->sockfd!=-1 ) ) {
+ if( FD_UNLIKELY( -1==close( ssresolve->sockfd ) ) ) FD_LOG_ERR(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
+ ssresolve->sockfd = -1;
+ }
+#if FD_HAS_OPENSSL
+ if( FD_LIKELY( ssresolve->ssl ) ) {
+ SSL_free( ssresolve->ssl );
+ ssresolve->ssl = NULL;
+ }
+#endif
+}
diff --git a/src/discof/restore/utils/fd_ssresolve.h b/src/discof/restore/utils/fd_ssresolve.h
index a5353a3003e..24238bb5e24 100644
--- a/src/discof/restore/utils/fd_ssresolve.h
+++ b/src/discof/restore/utils/fd_ssresolve.h
@@ -4,6 +4,10 @@
#include "../../../util/fd_util_base.h"
#include "../../../util/net/fd_net_headers.h"
+#if FD_HAS_OPENSSL
+#include
+#endif
+
#define FD_SSRESOLVE_MAGIC (0xF17EDA2CE55E510) /* FIREDANCER HTTP RESOLVE V0 */
#define FD_SSRESOLVE_ALIGN (8UL)
@@ -42,9 +46,20 @@ fd_ssresolve_init( fd_ssresolve_t * ssresolve,
int sockfd,
int full );
+#if FD_HAS_OPENSSL
+void
+fd_ssresolve_init_https( fd_ssresolve_t * ssresolve,
+ fd_ip4_port_t addr,
+ int sockfd,
+ int full,
+ char const * hostname,
+ SSL_CTX * ssl_ctx );
+#endif
+
#define FD_SSRESOLVE_ADVANCE_ERROR (-1) /* fatal error */
#define FD_SSRESOLVE_ADVANCE_AGAIN ( 0) /* try again */
-#define FD_SSRESOLVE_ADVANCE_SUCCESS ( 1) /* success */
+#define FD_SSRESOLVE_ADVANCE_SUCCESS ( 1) /* successful advance */
+#define FD_SSRESOLVE_ADVANCE_RESULT ( 2) /* successful advance with valid resolve result */
/* fd_ssresolve_advance_poll_out advances the ssresolve state machine
when its socket file descriptor is ready for sending data. */
@@ -63,6 +78,9 @@ fd_ssresolve_advance_poll_in( fd_ssresolve_t * ssresolve,
int
fd_ssresolve_is_done( fd_ssresolve_t * ssresolve );
+void
+fd_ssresolve_cancel( fd_ssresolve_t * ssresolve );
+
FD_PROTOTYPES_END
#endif /* HEADER_fd_src_discof_restore_utils_fd_ssresolve_h */
diff --git a/src/discof/tower/fd_tower_tile.c b/src/discof/tower/fd_tower_tile.c
index 422c8f11e23..da4b1274d5f 100644
--- a/src/discof/tower/fd_tower_tile.c
+++ b/src/discof/tower/fd_tower_tile.c
@@ -189,8 +189,7 @@ metrics_write( ctx_t * ctx ) {
FD_MCNT_SET( TOWER, HARD_FORKS_SEEN, ctx->metrics.hard_forks.seen );
FD_MCNT_SET( TOWER, HARD_FORKS_PRUNED, ctx->metrics.hard_forks.pruned );
- FD_MGAUGE_SET( TOWER, HARD_FORKS_ACTIVE, ctx->metrics.hard_forks.active );
- FD_MGAUGE_SET( TOWER, HARD_FORKS_MAX_WIDTH, ctx->metrics.hard_forks.max_width );
+ FD_MGAUGE_SET( TOWER, HARD_FORKS_ACTIVE, ctx->metrics.hard_forks.active );
}
static void
diff --git a/src/waltz/openssl/Local.mk b/src/waltz/openssl/Local.mk
index 0bf978e681b..69ff56f6266 100644
--- a/src/waltz/openssl/Local.mk
+++ b/src/waltz/openssl/Local.mk
@@ -1,4 +1,5 @@
$(call add-hdrs,fd_openssl.h)
ifdef FD_HAS_OPENSSL
$(call add-objs,fd_openssl,fd_waltz)
+$(call add-objs,fd_openssl_tile,fd_waltz)
endif
diff --git a/src/waltz/openssl/fd_openssl_tile.c b/src/waltz/openssl/fd_openssl_tile.c
new file mode 100644
index 00000000000..4ab84c1b625
--- /dev/null
+++ b/src/waltz/openssl/fd_openssl_tile.c
@@ -0,0 +1,155 @@
+#if FD_HAS_OPENSSL
+#include "../../util/bits/fd_bits.h"
+#include "fd_openssl_tile.h"
+
+#include
+#include
+#include
+
+/* Thread-local alloc object for each tile that uses OpenSSL. */
+FD_TL fd_alloc_t * fd_ossl_alloc = NULL;
+FD_TL ulong fd_ossl_alloc_errors = 0UL;
+
+/* OpenSSL tries to read files and allocate memory and other dumb things
+ on a thread local basis, so we need a special initializer process to
+ make OpenSSL use our custom allocators before seccomp kicks in.
+
+ OpenSSL allows us to specify custom memory allocation functions,
+ which we want to point to an fd_alloc_t, but it does not let us use a
+ context object. Instead we stash it in this thread local, which is
+ OK because the parent workspace exists for the duration of the SSL
+ context, and the process only has one thread.
+
+ Currently fd_alloc doesn't support realloc, so it's implemented on
+ top of malloc and free, and then also it doesn't support getting the
+ size of an allocation from the pointer, which we need for realloc, so
+ we pad each alloc by 8 bytes and stuff the size into the first 8
+ bytes. */
+
+static void *
+crypto_malloc( ulong num,
+ char const * file,
+ int line ) {
+ (void)file;
+ (void)line;
+ void * result = fd_alloc_malloc( fd_ossl_alloc, 8UL, num + 8UL );
+ if( FD_UNLIKELY( !result ) ) {
+ fd_ossl_alloc_errors++;
+ return NULL;
+ }
+ *(ulong*)result = num;
+ return (uchar*)result + 8UL;
+}
+
+static void
+crypto_free( void * addr,
+ char const * file,
+ int line ) {
+ (void)file;
+ (void)line;
+
+ if( FD_UNLIKELY( !addr ) ) return;
+ fd_alloc_free( fd_ossl_alloc, (uchar*)addr - 8UL );
+}
+
+static void *
+crypto_realloc( void * addr,
+ ulong num,
+ char const * file,
+ int line ) {
+ (void)file;
+ (void)line;
+
+ if( FD_UNLIKELY( !addr ) ) return crypto_malloc( num, file, line );
+ if( FD_UNLIKELY( !num ) ) {
+ crypto_free( addr, file, line );
+ return NULL;
+ }
+
+ void * new = fd_alloc_malloc( fd_ossl_alloc, 8UL, num + 8UL );
+ if( FD_UNLIKELY( !new ) ) return NULL;
+
+ ulong old_num = *(ulong*)( (uchar*)addr - 8UL );
+ fd_memcpy( (uchar*)new + 8, (uchar*)addr, fd_ulong_min( old_num, num ) );
+ fd_alloc_free( fd_ossl_alloc, (uchar*)addr - 8UL );
+ *(ulong*)new = num;
+ return (uchar*)new + 8UL;
+}
+
+void
+fd_ossl_tile_init( fd_alloc_t * alloc ) {
+ /* OpenSSL's CRYPTO_set_mem_functions is a global operation so it can
+ only be called once for all threads/processes. */
+ FD_ONCE_BEGIN {
+ if( FD_UNLIKELY( !CRYPTO_set_mem_functions( crypto_malloc, crypto_realloc, crypto_free ) ) ) {
+ FD_LOG_ERR(( "CRYPTO_set_mem_functions failed" ));
+ }
+ } FD_ONCE_END;
+
+ FD_TEST( alloc );
+ fd_ossl_alloc = alloc;
+
+ FD_ONCE_BEGIN {
+ OPENSSL_init_ssl(
+ OPENSSL_INIT_LOAD_SSL_STRINGS |
+ OPENSSL_INIT_LOAD_CRYPTO_STRINGS |
+ OPENSSL_INIT_NO_LOAD_CONFIG,
+ NULL );
+ } FD_ONCE_END;
+}
+
+void
+fd_ossl_load_certs( SSL_CTX * ssl_ctx ) {
+ X509_STORE * ca_certs = X509_STORE_new();
+ if( FD_UNLIKELY( !ca_certs ) ) {
+ FD_LOG_ERR(( "X509_STORE_new failed" ));
+ }
+
+ static char const default_dir[] = "/etc/ssl/certs/";
+ DIR * dir = opendir( default_dir );
+ if( FD_UNLIKELY( !dir ) ) {
+ FD_LOG_ERR(( "opendir(%s) failed (%i-%s)", default_dir, errno, fd_io_strerror( errno ) ));
+ }
+
+ struct dirent * entry;
+ errno = 0; // clear old value since entry can be NULL when reaching end of directory.
+ while( (entry = readdir( dir )) ) {
+ if( !strcmp( entry->d_name, "." ) || !strcmp( entry->d_name, ".." ) ) continue;
+
+ char cert_path[ PATH_MAX ];
+ char * p = fd_cstr_init( cert_path );
+ p = fd_cstr_append_text( p, default_dir, sizeof(default_dir)-1 );
+ p = fd_cstr_append_cstr_safe( p, entry->d_name, (ulong)(cert_path+sizeof(cert_path)-1) - (ulong)p );
+ fd_cstr_fini( p );
+
+ if( !X509_STORE_load_locations( ca_certs, cert_path, NULL ) ) {
+ /* Not all files in /etc/ssl/certs are valid certs, so ignore errors */
+ continue;
+ }
+ errno = 0;
+ }
+
+ if( FD_UNLIKELY( errno && errno!=ENOENT ) ) {
+ FD_LOG_ERR(( "readdir(%s) failed (%i-%s)", default_dir, errno, fd_io_strerror( errno ) ));
+ }
+
+ STACK_OF(X509) * cert_list = X509_STORE_get1_all_certs( ca_certs );
+ FD_LOG_INFO(( "Loaded %d CA certs from %s into OpenSSL", sk_X509_num( cert_list ), default_dir ));
+ if( fd_log_level_logfile()==0 ) {
+ for( int i=0; i
+
+#include "../../util/alloc/fd_alloc.h"
+
+/* Each tile that uses OpenSSL must initialize the thread-local
+ fd_ossl_alloc alloc object so that openSSL can allocate out of the
+ tile's wksp. The tile must also define a loose_footprint callback
+ function to allocate extra memory in the tile's workspace. */
+extern FD_TL fd_alloc_t * fd_ossl_alloc;
+
+/* Stores the number of ssl alloc errors per tile. Can be optionally
+ written back to a tile metric in METRICS_WRITE. */
+extern FD_TL ulong fd_ossl_alloc_errors;
+
+/* fd_ossl_tile_init is called in a tile's privileged init to
+ initialize OpenSSL. See fd_snapld_tile.c for reference. */
+void
+fd_ossl_tile_init( fd_alloc_t * alloc );
+
+/* fd_ossl_load_certs manually loads certificates into an SSL_CTX
+ object. This should be called right after calling SSL_CTX_new in
+ privileged init in a tile. */
+void
+fd_ossl_load_certs( SSL_CTX * ssl_ctx );
+
+#endif /* HEADER_fd_src_waltz_openssl_fd_openssl_tile_h */
+
+#endif /* FD_HAS_OPENSSL */