File Allow-to-enforce-IPv4-or-IPv6-in-URL-like-connection.patch of Package firebird30
From: Michal Kubecek <mkubecek@suse.cz>
Date: Wed, 4 May 2016 21:38:36 +0200
Subject: Allow to enforce IPv4 or IPv6 in URL-like connection string.
Patch-mainline: submitted
Git-commit: 13aa5420f24546b99c25a8651d135133d18583f2
---
doc/README.IPv6 | 13 +++++++++++++
doc/README.connection_strings | 7 +++++++
src/remote/client/interface.cpp | 12 ++++++++++--
src/remote/inet.cpp | 26 +++++++++++++++++---------
src/remote/inet_proto.h | 5 +++--
5 files changed, 50 insertions(+), 13 deletions(-)
diff --git a/doc/README.IPv6 b/doc/README.IPv6
index 04ee9ae63060..86d533b26c95 100644
--- a/doc/README.IPv6
+++ b/doc/README.IPv6
@@ -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.
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
------
diff --git a/doc/README.connection_strings b/doc/README.connection_strings
index d23d50724b04..99e4753df2e7 100644
--- a/doc/README.connection_strings
+++ b/doc/README.connection_strings
@@ -107,6 +107,13 @@ Examples:
inet://myserver: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:
wnet://myserver/C:\db\mydb.fdb
diff --git a/src/remote/client/interface.cpp b/src/remote/client/interface.cpp
index bdfcedf3bb10..29ddb708398d 100644
--- a/src/remote/client/interface.cpp
+++ b/src/remote/client/interface.cpp
@@ -92,6 +92,8 @@
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_XNET = "xnet";
@@ -5419,6 +5421,7 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned
**************************************/
rem_port* port = NULL;
+ int inet_af = AF_UNSPEC;
cBlock.loadClnt(pb, &parSet);
authenticateStep0(cBlock);
@@ -5443,7 +5446,12 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned
else
#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))
{
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,
- 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,
diff --git a/src/remote/inet.cpp b/src/remote/inet.cpp
index 40f43bbfd9c0..7191db3d9c1f 100644
--- a/src/remote/inet.cpp
+++ b/src/remote/inet.cpp
@@ -453,7 +453,8 @@ static rem_port* inet_try_connect( PACKET*,
const TEXT*,
ClumpletReader&,
RefPtr<Config>*,
- const PathName*);
+ const PathName*,
+ int);
static bool inet_write(XDR*);
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,
ClumpletReader &dpb,
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;
switch (packet->p_operation)
@@ -708,7 +710,8 @@ rem_port* INET_connect(const TEXT* name,
PACKET* packet,
USHORT flag,
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;
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;
#if !defined(WIN_NT) && !defined(__clang__)
@@ -811,7 +817,7 @@ rem_port* INET_connect(const TEXT* name,
gai_hints.ai_flags =
#ifndef ANDROID
- AI_V4MAPPED |
+ ((af == AF_UNSPEC) ? AI_V4MAPPED : 0) |
#endif
AI_ADDRCONFIG | (packet ? 0 : AI_PASSIVE);
@@ -825,7 +831,8 @@ rem_port* INET_connect(const TEXT* name,
retry_gai = false;
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
gai_hints.ai_family = AF_UNSPEC;
@@ -2639,7 +2646,8 @@ static rem_port* inet_try_connect(PACKET* packet,
const TEXT* node_name,
ClumpletReader& dpb,
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;
try
{
- port = INET_connect(node_name, packet, false, &dpb, config);
+ port = INET_connect(node_name, packet, false, &dpb, config, af);
}
catch (const Exception&)
{
diff --git a/src/remote/inet_proto.h b/src/remote/inet_proto.h
index af00e8fa5ddb..6aeebace22bd 100644
--- a/src/remote/inet_proto.h
+++ b/src/remote/inet_proto.h
@@ -34,9 +34,10 @@ namespace Firebird
}
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*,
- Firebird::RefPtr<Config>*);
+ Firebird::RefPtr<Config>*, int af = AF_UNSPEC);
rem_port* INET_reconnect(SOCKET);
rem_port* INET_server(SOCKET);
void setStopMainThread(FPTR_INT func);
--
2.8.2