[CDRIVER-3818] Outbound connections bind to selective interface by source IP (Source routing feature) Created: 25/Nov/20  Updated: 23/May/22

Status: Backlog
Project: C Driver
Component/s: network
Affects Version/s: 1.17.0
Fix Version/s: None

Type: New Feature Priority: Major - P3
Reporter: Luke Prochazka Assignee: Unassigned
Resolution: Unresolved Votes: 4
Labels: FY22Q1
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
Epic Link: Improve Developer Experience
Case:

 Description   

This is a a request to validate and incorporate a custom source routing feature in the driver.  If possible we ask to incorporate this in the standard driver distribution for supportability purposes.

Based on mongocxx-driver version 3.6.0, the corresponding custom function was added to the driver the source.  The source IP binding was performed only in the mongoc_client_connect_tcp function and the mongoc_topology_scanner_tcp_initiate function.  Please validate if there are any other cases to consider.

extern char global_local_uri[16];

char global_local_uri[16];
 
void
mongoc_uri_set_local_uri (const char *local_uri)
{
   if (0 < strlen (local_uri)) {
      strcpy(global_local_uri, local_uri);
   } else {
      strcpy(global_local_uri, "");
   }
}
 
static bool
mongoc_uri_apply_options (mongoc_uri_t *uri,
                          const bson_t *options,
                          bool from_dns,
                          bson_error_t *error)
{
 
  ...
 
  } else if (!strcmp (key, MONGOC_URI_LOCALURI)) {
           mongoc_uri_set_local_uri (value);
 
  }
 
  ...
 
}

mongoc_stream_t *
mongoc_client_connect_tcp (int32_t connecttimeoutms,
                           const mongoc_host_list_t *host,
                           bson_error_t *error)
{
 
  ...
 
  if (strlen(global_local_uri) > 0)
  {
      struct sockaddr_in server_addr_in = {0};
      memset (&server_addr_in, 0, sizeof (server_addr_in));
      server_addr_in.sin_family = AF_INET;
      server_addr_in.sin_addr.s_addr = inet_addr(global_local_uri);
      mongoc_socket_bind (sock,
                          (struct sockaddr *) &server_addr_in,
                          sizeof (server_addr_in));
  }
 
  ...
 
}

mongoc_stream_t *
 
_mongoc_topology_scanner_tcp_initiate (mongoc_async_cmd_t *acmd)
{
   ...
 
   if (strlen(global_local_uri) > 0)
   {
     struct sockaddr_in server_addr_in = {0};
     memset (&server_addr_in, 0, sizeof (server_addr_in));
     server_addr_in.sin_family = AF_INET;
     server_addr_in.sin_addr.s_addr = inet_addr(global_local_uri);
     mongoc_socket_bind (sock,
                         (struct sockaddr *) &server_addr_in,
                         sizeof (server_addr_in));
   }
 
   ...
 
}



 Comments   
Comment by Kevin Albertson [ 25/Nov/20 ]

Thank you for providing the pseudocode, as that is helpful in understanding the desired behavior. This seems like a reasonable request if there is a need to bind to a non-primary network interface, and no way to do this without driver changes.

I'd like to explore other approaches to solving this. I do not think we'd want to add a new URI option. In general, URIs should be portable between applications of different drivers, and URI options are standardized in our URI Options Specification. Here are my current thoughts:

Option 1: Extend custom initiators
It is technically possible to implement this behavior for a single-threaded mongoc_client_t just using the public API. The C driver exposes a custom initiator: mongoc_client_set_stream_initiator which allows overriding the default behavior of creating a stream to a server. But mongoc_client_set_stream_initiator only works for single threaded clients currently. We could add support for a mongoc_client_pool_t. This would be a more general solution, and more consistent with existing precedent in other drivers. However, this might be less convenient.

Option 2: Add a setter on mongoc_client
Add a setter for a bind address mongoc_client_t like so:

bool ret;
bson_error_t err;
 
ret = mongoc_client_set_bind_address (client, "1.2.3.4", &err);

I think Option 2 is more convenient for this use case, but I think there is more precedent for Option 1. I am discussing with the drivers team to get more perspective.

Comment by Kevin Albertson [ 25/Nov/20 ]

Hi luke.prochazka, thank you for passing along the feature request! We'll look into this soon.

Generated at Wed Feb 07 21:19:07 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.