8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 15:23:03 +01:00

Allow to enforce IPv4 or IPv6 in URL-like connection string.

This commit is contained in:
Michal Kubecek 2016-05-04 21:38:36 +02:00
parent 535a0e5204
commit 13aa5420f2
5 changed files with 50 additions and 13 deletions

View File

@ -22,6 +22,19 @@ If a domain name is used in connection string, all addresses (IPv4 and IPv6)
are tried in the order returned by resolver until a connection is established. are tried in the order returned by resolver until a connection is established.
Only if all attempts fail, the client fails to connect. Only if all attempts fail, the client fails to connect.
New URL-style connection string format (see README.connection_strings) allows
to restrict name lookup to only IPv4 or IPv6 addresses:
connect 'inet://server.example.org/test';
connect 'inet4://server.example.org/test';
connect 'inet6://server.example.org/test';
First example tries all addresses, second only IPv4 ones, third only IPv6
ones. This can be used to avoid connection delays on systems where name lookup
returns IPv6 addresses for some host names but attempts to connect to them
time out rather than failing immediatelly (as reported, this can happen even
for name "localhost" on some systems).
Server Server
------ ------

View File

@ -107,6 +107,13 @@ Examples:
inet://myserver:fb_db/mydb inet://myserver:fb_db/mydb
inet://localhost:fb_db/mydb inet://localhost:fb_db/mydb
The "inet" protocol can be replaced by "inet4" or "inet6" to restrict client
to IPv4 or IPv6 addresses corresponding to supplied name ("inet" protocol
tries all addresses in the order determined by OS):
inet4://myserver/mydb
inet6://myserver/mydb
Connect via named pipes: Connect via named pipes:
wnet://myserver/C:\db\mydb.fdb wnet://myserver/C:\db\mydb.fdb

View File

@ -92,6 +92,8 @@
const char* const PROTOCOL_INET = "inet"; const char* const PROTOCOL_INET = "inet";
const char* const PROTOCOL_INET4 = "inet4";
const char* const PROTOCOL_INET6 = "inet6";
const char* const PROTOCOL_WNET = "wnet"; const char* const PROTOCOL_WNET = "wnet";
const char* const PROTOCOL_XNET = "xnet"; const char* const PROTOCOL_XNET = "xnet";
@ -5419,6 +5421,7 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned
**************************************/ **************************************/
rem_port* port = NULL; rem_port* port = NULL;
int inet_af = AF_UNSPEC;
cBlock.loadClnt(pb, &parSet); cBlock.loadClnt(pb, &parSet);
authenticateStep0(cBlock); authenticateStep0(cBlock);
@ -5443,7 +5446,12 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned
else else
#endif #endif
if (ISC_analyze_protocol(PROTOCOL_INET, attach_name, node_name, INET_SEPARATOR) || if (ISC_analyze_protocol(PROTOCOL_INET4, attach_name, node_name, INET_SEPARATOR))
inet_af = AF_INET;
else if (ISC_analyze_protocol(PROTOCOL_INET6, attach_name, node_name, INET_SEPARATOR))
inet_af = AF_INET6;
if (inet_af != AF_UNSPEC ||
ISC_analyze_protocol(PROTOCOL_INET, attach_name, node_name, INET_SEPARATOR) ||
ISC_analyze_tcp(attach_name, node_name)) ISC_analyze_tcp(attach_name, node_name))
{ {
if (node_name.isEmpty()) if (node_name.isEmpty())
@ -5455,7 +5463,7 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned
} }
port = INET_analyze(&cBlock, attach_name, node_name.c_str(), flags & ANALYZE_UV, pb, port = INET_analyze(&cBlock, attach_name, node_name.c_str(), flags & ANALYZE_UV, pb,
cBlock.getConfig(), ref_db_name); cBlock.getConfig(), ref_db_name, inet_af);
} }
// We have a local connection string. If it's a file on a network share, // We have a local connection string. If it's a file on a network share,

View File

@ -453,7 +453,8 @@ static rem_port* inet_try_connect( PACKET*,
const TEXT*, const TEXT*,
ClumpletReader&, ClumpletReader&,
RefPtr<Config>*, RefPtr<Config>*,
const PathName*); const PathName*,
int);
static bool inet_write(XDR*); static bool inet_write(XDR*);
static rem_port* listener_socket(rem_port* port, USHORT flag, const addrinfo* pai); static rem_port* listener_socket(rem_port* port, USHORT flag, const addrinfo* pai);
@ -532,7 +533,8 @@ rem_port* INET_analyze(ClntAuthBlock* cBlock,
bool uv_flag, bool uv_flag,
ClumpletReader &dpb, ClumpletReader &dpb,
RefPtr<Config>* config, RefPtr<Config>* config,
const PathName* ref_db_name) const PathName* ref_db_name,
int af)
{ {
/************************************** /**************************************
* *
@ -624,7 +626,7 @@ rem_port* INET_analyze(ClntAuthBlock* cBlock,
} }
} }
rem_port* port = inet_try_connect(packet, rdb, file_name, node_name, dpb, config, ref_db_name); rem_port* port = inet_try_connect(packet, rdb, file_name, node_name, dpb, config, ref_db_name, af);
P_ACPT* accept = NULL; P_ACPT* accept = NULL;
switch (packet->p_operation) switch (packet->p_operation)
@ -708,7 +710,8 @@ rem_port* INET_connect(const TEXT* name,
PACKET* packet, PACKET* packet,
USHORT flag, USHORT flag,
ClumpletReader* dpb, ClumpletReader* dpb,
RefPtr<Config>* config) RefPtr<Config>* config,
int af)
{ {
/************************************** /**************************************
* *
@ -800,7 +803,10 @@ rem_port* INET_connect(const TEXT* name,
struct addrinfo gai_hints; struct addrinfo gai_hints;
memset(&gai_hints, 0, sizeof(gai_hints)); memset(&gai_hints, 0, sizeof(gai_hints));
gai_hints.ai_family = ((packet || host.hasData() || !ipv6) ? AF_UNSPEC : AF_INET6); if (packet)
gai_hints.ai_family = af;
else
gai_hints.ai_family = ((host.hasData() || !ipv6) ? AF_UNSPEC : AF_INET6);
gai_hints.ai_socktype = SOCK_STREAM; gai_hints.ai_socktype = SOCK_STREAM;
#if !defined(WIN_NT) && !defined(__clang__) #if !defined(WIN_NT) && !defined(__clang__)
@ -811,7 +817,7 @@ rem_port* INET_connect(const TEXT* name,
gai_hints.ai_flags = gai_hints.ai_flags =
#ifndef ANDROID #ifndef ANDROID
AI_V4MAPPED | ((af == AF_UNSPEC) ? AI_V4MAPPED : 0) |
#endif #endif
AI_ADDRCONFIG | (packet ? 0 : AI_PASSIVE); AI_ADDRCONFIG | (packet ? 0 : AI_PASSIVE);
@ -825,7 +831,8 @@ rem_port* INET_connect(const TEXT* name,
retry_gai = false; retry_gai = false;
n = getaddrinfo(host_str, protocol.c_str(), &gai_hints, &gai_result); n = getaddrinfo(host_str, protocol.c_str(), &gai_hints, &gai_result);
if ((n == EAI_FAMILY || (!host_str && n == EAI_NONAME)) && (gai_hints.ai_family == AF_INET6)) if ((n == EAI_FAMILY || (!host_str && n == EAI_NONAME)) &&
(gai_hints.ai_family == AF_INET6) && (af != AF_INET6))
{ {
// May be on a system without IPv6 support, try IPv4 // May be on a system without IPv6 support, try IPv4
gai_hints.ai_family = AF_UNSPEC; gai_hints.ai_family = AF_UNSPEC;
@ -2639,7 +2646,8 @@ static rem_port* inet_try_connect(PACKET* packet,
const TEXT* node_name, const TEXT* node_name,
ClumpletReader& dpb, ClumpletReader& dpb,
RefPtr<Config>* config, RefPtr<Config>* config,
const PathName* ref_db_name) const PathName* ref_db_name,
int af)
{ {
/************************************** /**************************************
* *
@ -2671,7 +2679,7 @@ static rem_port* inet_try_connect(PACKET* packet,
rem_port* port = NULL; rem_port* port = NULL;
try try
{ {
port = INET_connect(node_name, packet, false, &dpb, config); port = INET_connect(node_name, packet, false, &dpb, config, af);
} }
catch (const Exception&) catch (const Exception&)
{ {

View File

@ -34,9 +34,10 @@ namespace Firebird
} }
rem_port* INET_analyze(ClntAuthBlock*, const Firebird::PathName&, const TEXT*, rem_port* INET_analyze(ClntAuthBlock*, const Firebird::PathName&, const TEXT*,
bool, Firebird::ClumpletReader&, Firebird::RefPtr<Config>*, const Firebird::PathName*); bool, Firebird::ClumpletReader&, Firebird::RefPtr<Config>*,
const Firebird::PathName*, int af = AF_UNSPEC);
rem_port* INET_connect(const TEXT*, struct packet*, USHORT, Firebird::ClumpletReader*, rem_port* INET_connect(const TEXT*, struct packet*, USHORT, Firebird::ClumpletReader*,
Firebird::RefPtr<Config>*); Firebird::RefPtr<Config>*, int af = AF_UNSPEC);
rem_port* INET_reconnect(SOCKET); rem_port* INET_reconnect(SOCKET);
rem_port* INET_server(SOCKET); rem_port* INET_server(SOCKET);
void setStopMainThread(FPTR_INT func); void setStopMainThread(FPTR_INT func);