Skip to content

Commit

Permalink
control-service: Fix reliability on CoreDevice systems
Browse files Browse the repository at this point in the history
Where having a single transport broker listening on all interfaces may
result in an early TCP RST when trying to communicate with it from
inside a tunnel. The exact cause of this is not known, but we have
confirmed that having one broker per dynamic interface/tunnel does
resolve the issue. We also observed that listening on all interfaces,
but restricted to IPv6, also avoids the issue.

Co-authored-by: Håvard Sørbø <havard@hsorbo.no>
  • Loading branch information
oleavr and hsorbo committed Oct 10, 2024
1 parent dcdfcf5 commit 364bf65
Show file tree
Hide file tree
Showing 3 changed files with 322 additions and 172 deletions.
58 changes: 43 additions & 15 deletions lib/base/socket.vala
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ namespace Frida {
}

public class WebService : Object {
public signal void incoming (IOStream connection, SocketAddress remote_address);
public signal void incoming (IOStream connection, SocketAddress remote_address, DynamicInterface? dynamic_iface);

public EndpointParameters endpoint_params {
get;
Expand Down Expand Up @@ -315,7 +315,7 @@ namespace Frida {
}

private async SocketAddress do_start (Cancellable? cancellable) throws Error, IOError {
main_handler = make_connection_handler ();
main_handler = make_connection_handler (null);
SocketAddress? first_effective_address = null;
SocketConnectable connectable = (flavor == CONTROL)
? parse_control_address (endpoint_params.address, endpoint_params.port)
Expand Down Expand Up @@ -356,35 +356,37 @@ namespace Frida {
return first_effective_address;
}

private void on_dynamic_interface_attached (string name, InetAddress ip) {
private void on_dynamic_interface_attached (DynamicInterface iface) {
unowned string name = iface.name;

uint16 port = endpoint_params.port;
if (port == 0)
port = (flavor == CONTROL) ? DEFAULT_CONTROL_PORT : DEFAULT_CLUSTER_PORT;

var handler = make_connection_handler ();
var handler = make_connection_handler (iface);
try {
handler.listen_on_inet_address (new InetSocketAddress (ip, port));
handler.listen_on_inet_address (new InetSocketAddress (iface.ip, port));
} catch (Error e) {
return;
}
dynamic_interface_handlers[name] = handler;
}

private void on_dynamic_interface_detached (string name, InetAddress ip) {
private void on_dynamic_interface_detached (DynamicInterface iface) {
ConnectionHandler handler;
if (dynamic_interface_handlers.unset (name, out handler))
if (dynamic_interface_handlers.unset (iface.name, out handler))
handler.close ();
}

private ConnectionHandler make_connection_handler () {
var handler = new ConnectionHandler (endpoint_params, on_port_conflict);
private ConnectionHandler make_connection_handler (DynamicInterface? dynamic_iface) {
var handler = new ConnectionHandler (dynamic_iface, endpoint_params, on_port_conflict);
handler.incoming.connect (on_incoming_connection);
return handler;
}

private void on_incoming_connection (IOStream connection, SocketAddress remote_address) {
private void on_incoming_connection (ConnectionHandler handler, IOStream connection, SocketAddress remote_address) {
schedule_on_frida_thread (() => {
incoming (connection, remote_address);
incoming (connection, remote_address, handler.dynamic_iface);
return Source.REMOVE;
});
}
Expand Down Expand Up @@ -431,6 +433,11 @@ namespace Frida {
private class ConnectionHandler : Object {
public signal void incoming (IOStream connection, SocketAddress remote_address);

public DynamicInterface? dynamic_iface {
get;
construct;
}

public EndpointParameters endpoint_params {
get;
construct;
Expand All @@ -446,8 +453,13 @@ namespace Frida {
private Gee.Set<WebConnection> connections = new Gee.HashSet<WebConnection> ();
private Cancellable io_cancellable = new Cancellable ();

public ConnectionHandler (EndpointParameters endpoint_params, PortConflictBehavior on_port_conflict) {
Object (endpoint_params: endpoint_params, on_port_conflict: on_port_conflict);
public ConnectionHandler (DynamicInterface? dynamic_iface, EndpointParameters endpoint_params,
PortConflictBehavior on_port_conflict) {
Object (
dynamic_iface: dynamic_iface,
endpoint_params: endpoint_params,
on_port_conflict: on_port_conflict
);
}

construct {
Expand Down Expand Up @@ -834,12 +846,28 @@ namespace Frida {
}

public interface DynamicInterfaceObserver : Object {
public signal void interface_attached (string name, InetAddress ip);
public signal void interface_detached (string name, InetAddress ip);
public signal void interface_attached (DynamicInterface iface);
public signal void interface_detached (DynamicInterface iface);

public abstract void start ();
}

public class DynamicInterface : Object {
public string name {
get;
construct;
}

public InetAddress ip {
get;
construct;
}

public DynamicInterface (string name, InetAddress ip) {
Object (name: name, ip: ip);
}
}

public extern static unowned string _version_string ();

private class WebConnection : IOStream {
Expand Down
14 changes: 8 additions & 6 deletions lib/netif/tunnel-interface-observer.vala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
public class Frida.TunnelInterfaceObserver : Object, DynamicInterfaceObserver {
#if IOS || TVOS
private Gee.Map<string, InetAddress> interfaces = new Gee.HashMap<string, InetAddress> ();
private Gee.Map<string, DynamicInterface> interfaces = new Gee.HashMap<string, DynamicInterface> ();

private Darwin.SystemConfiguration.DynamicStore? store;
private Darwin.GCD.DispatchQueue event_queue =
Expand Down Expand Up @@ -62,9 +62,9 @@ public class Frida.TunnelInterfaceObserver : Object, DynamicInterfaceObserver {
foreach (var key in CFArray.wrap<CoreFoundation.String> (changed_keys)) {
string name = key.to_string ().split ("/")[3];

InetAddress? address = null;
var val = (CoreFoundation.Dictionary) store.copy_value (key);
if (val != null) {
InetAddress? address = null;
foreach (var raw_address in CFArray.wrap<CoreFoundation.String> (val[addresses_str])) {
var str = raw_address.to_string ();
bool is_reserved_ipv6_range = str.has_prefix ("fc") || str.has_prefix ("fd");
Expand All @@ -75,12 +75,14 @@ public class Frida.TunnelInterfaceObserver : Object, DynamicInterfaceObserver {
}
}
if (address != null && !interfaces.has_key (name)) {
interfaces[name] = address;
interface_attached (name, address);
var iface = new DynamicInterface (name, address);
interfaces[name] = iface;
interface_attached (iface);
}
} else {
if (interfaces.unset (name, out address))
interface_detached (name, address);
DynamicInterface iface;
if (interfaces.unset (name, out iface))
interface_detached (iface);
}
}
}
Expand Down
Loading

0 comments on commit 364bf65

Please sign in to comment.