You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by am...@apache.org on 2012/12/10 18:03:21 UTC

[2/2] TS-1422 TS-1307 : Update HostDB for better IPv6 handling.

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/lib/records/I_RecHttp.h
----------------------------------------------------------------------
diff --git a/lib/records/I_RecHttp.h b/lib/records/I_RecHttp.h
index 41da219..248c1dd 100644
--- a/lib/records/I_RecHttp.h
+++ b/lib/records/I_RecHttp.h
@@ -25,6 +25,7 @@
 #define _I_REC_HTTP_H
 
 #include <ts/ink_inet.h>
+#include <ts/ink_resolver.h>
 #include <ts/Vec.h>
 
 /// Load default inbound IP addresses from the configuration file.
@@ -95,6 +96,7 @@ public:
     TRANSPORT_BLIND_TUNNEL, ///< Blind tunnel (no processing).
     TRANSPORT_SSL ///< SSL connection.
   };
+
   int m_fd; ///< Pre-opened file descriptor if present.
   TransportType m_type; ///< Type of connection.
   int m_port; ///< Port on which to listen.
@@ -109,6 +111,12 @@ public:
   IpAddr m_outbound_ip4;
   /// Local address for outbound connections (to origin server).
   IpAddr m_outbound_ip6;
+  /// Ordered preference for DNS resolution family ( @c FamilyPrefence )
+  /// A value of @c PREFER_NONE indicates that entry and subsequent ones
+  /// are invalid.
+  HostResPreferenceOrder m_host_res_preference;
+  /// Static preference list that is the default value.
+  static HostResPreferenceOrder const DEFAULT_HOST_RES_PREFERENCE;
 
   /// Default constructor.
   HttpProxyPort();
@@ -254,8 +262,13 @@ public:
   static char const* const OPT_SSL; ///< SSL (experimental)
   static char const* const OPT_BLIND_TUNNEL; ///< Blind tunnel.
   static char const* const OPT_COMPRESSED; ///< Compressed.
+  static char const* const OPT_HOST_RES; ///< Set DNS family preference.
 
   static Vec<self>& m_global; ///< Global ("default") data.
+
+protected:
+  /// Process @a value for DNS resolution family preferences.
+  void processFamilyPreferences(char const* value);
 };
 
 inline bool HttpProxyPort::isSSL() const { return TRANSPORT_SSL == m_type; }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/lib/records/RecHttp.cc
----------------------------------------------------------------------
diff --git a/lib/records/RecHttp.cc b/lib/records/RecHttp.cc
index 31a6c12..45f1055 100644
--- a/lib/records/RecHttp.cc
+++ b/lib/records/RecHttp.cc
@@ -77,12 +77,14 @@ char const* const HttpProxyPort::OPT_TRANSPARENT_FULL = "tr-full";
 char const* const HttpProxyPort::OPT_SSL = "ssl";
 char const* const HttpProxyPort::OPT_BLIND_TUNNEL = "blind";
 char const* const HttpProxyPort::OPT_COMPRESSED = "compressed";
+char const* const HttpProxyPort::OPT_HOST_RES = "ip-resolve";
 
 // File local constants.
 namespace {
-size_t const OPT_FD_PREFIX_LEN = strlen(HttpProxyPort::OPT_FD_PREFIX);
-size_t const OPT_OUTBOUND_IP_PREFIX_LEN = strlen(HttpProxyPort::OPT_OUTBOUND_IP_PREFIX);
-size_t const OPT_INBOUND_IP_PREFIX_LEN = strlen(HttpProxyPort::OPT_INBOUND_IP_PREFIX);
+  size_t const OPT_FD_PREFIX_LEN = strlen(HttpProxyPort::OPT_FD_PREFIX);
+  size_t const OPT_OUTBOUND_IP_PREFIX_LEN = strlen(HttpProxyPort::OPT_OUTBOUND_IP_PREFIX);
+  size_t const OPT_INBOUND_IP_PREFIX_LEN = strlen(HttpProxyPort::OPT_INBOUND_IP_PREFIX);
+  size_t const OPT_HOST_RES_PREFIX_LEN = strlen(HttpProxyPort::OPT_HOST_RES);
 }
 
 namespace {
@@ -103,6 +105,7 @@ HttpProxyPort::HttpProxyPort()
   , m_inbound_transparent_p(false)
   , m_outbound_transparent_p(false)
 {
+  memcpy(m_host_res_preference, host_res_default_preference_order, sizeof(m_host_res_preference));
 }
 
 bool HttpProxyPort::hasSSL(Group const& ports) {
@@ -232,6 +235,7 @@ bool
 HttpProxyPort::processOptions(char const* opts) {
   bool zret = false; // no port found yet.
   bool af_set_p = false; // AF explicitly specified.
+  bool host_res_set_p = false; // Host resolution order set explicitly.
   bool bracket_p = false; // inside brackets during parse.
   Vec<char*> values; // Pointers to single option values.
 
@@ -342,13 +346,19 @@ HttpProxyPort::processOptions(char const* opts) {
       Warning("Transparency requested [%s] in port descriptor '%s' but TPROXY was not configured.", item, opts);
 # endif
     } else if (0 == strcasecmp(OPT_TRANSPARENT_FULL, item)||
-      0 == strcasecmp("=", item)) {
+               0 == strcasecmp("=", item)) {
 # if TS_USE_TPROXY
       m_inbound_transparent_p = true;
       m_outbound_transparent_p = true;
 # else
       Warning("Transparency requested [%s] in port descriptor '%s' but TPROXY was not configured.", item, opts);
 # endif
+    } else if (0 == strncasecmp(OPT_HOST_RES, item, OPT_HOST_RES_PREFIX_LEN)) {
+      item += OPT_HOST_RES_PREFIX_LEN; // skip prefix
+      if ('-' == *item || '=' == *item) // permit optional '-' or '='
+        ++item;
+      this->processFamilyPreferences(item);
+      host_res_set_p = true;
     } else {
       Warning("Invalid option '%s' in port configuration '%s'", item, opts);
     }
@@ -366,9 +376,30 @@ HttpProxyPort::processOptions(char const* opts) {
     m_family = m_inbound_ip.family(); // set according to address.
   }
 
+  // If the port is outbound transparent only CLIENT host resolution is possible.
+  if (m_outbound_transparent_p) {
+    if (host_res_set_p &&
+        (m_host_res_preference[0] != HOST_RES_PREFER_CLIENT ||
+         m_host_res_preference[1] != HOST_RES_PREFER_NONE
+    )) {
+      Warning("Outbound transparent ports require the IP address resolution ordering '%s,%s'. "
+              "This is set automatically and does not need to be set explicitly."
+              , HOST_RES_PREFERENCE_STRING[HOST_RES_PREFER_CLIENT]
+              , HOST_RES_PREFERENCE_STRING[HOST_RES_PREFER_NONE]
+        );
+    }
+    m_host_res_preference[0] = HOST_RES_PREFER_CLIENT;
+    m_host_res_preference[1] = HOST_RES_PREFER_NONE;
+  }
+
   return zret;
 }
 
+void
+HttpProxyPort::processFamilyPreferences(char const* value) {
+  parse_host_res_preferences(value, m_host_res_preference);
+}
+
 int
 HttpProxyPort::print(char* out, size_t n) {
   size_t zret = 0; // # of chars printed so far.
@@ -437,5 +468,30 @@ HttpProxyPort::print(char* out, size_t n) {
   else if (m_outbound_transparent_p)
     zret += snprintf(out+zret, n-zret, ":%s", OPT_TRANSPARENT_OUTBOUND);
 
+  /* Don't print the IP resolution preferences if the port is outbound
+   * transparent (which means the preference order is forced) or if
+   * the order is the same as the default.
+   */
+  if (!m_outbound_transparent_p &&
+      0 != memcmp(m_host_res_preference, host_res_default_preference_order, sizeof(m_host_res_preference))) {
+    zret += snprintf(out+zret, n-zret, ":%s=", OPT_HOST_RES);
+    zret += ts_host_res_order_to_string(m_host_res_preference, out+zret, n-zret);
+  }
+
   return min(zret,n);
 }
+
+void
+ts_host_res_global_init()
+{
+  // Global configuration values.
+  memcpy(host_res_default_preference_order,
+         HOST_RES_DEFAULT_PREFERENCE_ORDER,
+         sizeof(host_res_default_preference_order));
+
+  char* ip_resolve = REC_ConfigReadString("proxy.config.hostdb.ip_resolve");
+  if (ip_resolve) {
+    parse_host_res_preferences(ip_resolve, host_res_default_preference_order);
+  }
+  ats_free(ip_resolve);
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/lib/ts/INK_MD5.h
----------------------------------------------------------------------
diff --git a/lib/ts/INK_MD5.h b/lib/ts/INK_MD5.h
index 000d8a6..92b34ef 100644
--- a/lib/ts/INK_MD5.h
+++ b/lib/ts/INK_MD5.h
@@ -131,16 +131,16 @@ struct INK_MD5
     return buf;
   }
 
-  uint64_t fold()
+  uint64_t fold() const
   {
     return (b[0] ^ b[1]);
   }
 
-  uint64_t operator[] (int i)
+  uint64_t operator[] (int i) const
   {
     return b[i];
   }
-  bool operator==(INK_MD5 & md5)
+  bool operator==(INK_MD5 const& md5)
   {
     return b[0] == md5.b[0] && b[1] == md5.b[1];
   }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/lib/ts/ink_inet.h
----------------------------------------------------------------------
diff --git a/lib/ts/ink_inet.h b/lib/ts/ink_inet.h
index 7965496..52c64f1 100644
--- a/lib/ts/ink_inet.h
+++ b/lib/ts/ink_inet.h
@@ -1016,17 +1016,10 @@ struct IpAddr {
   explicit IpAddr(IpEndpoint const* addr) { this->assign(&addr->sa); }
 
   /// Assign sockaddr storage.
-  self& assign(sockaddr const* addr) {
-    _family = addr->sa_family;
-    if (ats_is_ip4(addr)) {
-      _addr._ip4 = ats_ip4_addr_cast(addr);
-    } else if (ats_is_ip6(addr)) {
-      _addr._ip6 = ats_ip6_addr_cast(addr);
-    } else {
-      _family = AF_UNSPEC;
-    }
-    return *this;
-  }
+  self& assign(
+	       sockaddr const* addr ///< May be @c NULL
+	       );
+
   /// Assign from end point.
   self& operator = (IpEndpoint const& ip) {
     return this->assign(&ip.sa);
@@ -1035,6 +1028,10 @@ struct IpAddr {
   self& operator = (
     in_addr_t ip ///< Network order IPv4 address.
   );
+  /// Assign from IPv6 raw address.
+  self& operator = (
+    in6_addr const& ip
+  );
 
   /** Load from string.
       The address is copied to this object if the conversion is successful,
@@ -1107,6 +1104,13 @@ IpAddr::operator = (in_addr_t ip) {
   return *this;
 }
 
+inline IpAddr&
+IpAddr::operator = (in6_addr const& ip) {
+  _family = AF_INET6;
+  _addr._ip6 = ip;
+  return *this;
+}
+
 inline uint16_t IpAddr::family() const { return _family; }
 
 inline bool
@@ -1116,6 +1120,23 @@ IpAddr::isCompatibleWith(self const& that) {
 
 inline bool IpAddr::isIp4() const { return AF_INET == _family; }
 inline bool IpAddr::isIp6() const { return AF_INET6 == _family; }
+  /// Assign sockaddr storage.
+inline IpAddr&
+IpAddr::assign(sockaddr const* addr) {
+  if (addr) {
+    _family = addr->sa_family;
+    if (ats_is_ip4(addr)) {
+      _addr._ip4 = ats_ip4_addr_cast(addr);
+    } else if (ats_is_ip6(addr)) {
+      _addr._ip6 = ats_ip6_addr_cast(addr);
+    } else {
+      _family = AF_UNSPEC;
+    }
+  } else {
+    _family = AF_UNSPEC;
+  }
+  return *this;
+}
 
 // Associated operators.
 bool operator == (IpAddr const& lhs, sockaddr const* rhs);

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/lib/ts/ink_res_init.cc
----------------------------------------------------------------------
diff --git a/lib/ts/ink_res_init.cc b/lib/ts/ink_res_init.cc
index f94b240..d52057f 100644
--- a/lib/ts/ink_res_init.cc
+++ b/lib/ts/ink_res_init.cc
@@ -87,11 +87,28 @@
 #include "ink_string.h"
 #include "ink_resolver.h"
 #include "ink_inet.h"
+#include "Tokenizer.h"
 
 #if !defined(isascii)           /* XXX - could be a function */
 # define isascii(c) (!(c & 0200))
 #endif
 
+HostResPreferenceOrder const HOST_RES_DEFAULT_PREFERENCE_ORDER = {
+  HOST_RES_PREFER_IPV4,
+  HOST_RES_PREFER_IPV6,
+  HOST_RES_PREFER_NONE
+};
+
+HostResPreferenceOrder host_res_default_preference_order;
+
+char const* const HOST_RES_PREFERENCE_STRING[N_HOST_RES_PREFERENCE] = {
+    "only", "client", "ipv4", "ipv6"
+};
+
+char const* const HOST_RES_STYLE_STRING[] = {
+  "invalid", "IPv4", "IPv4 only", "IPv6", "IPv6 only"
+};
+
 /*%
  * This routine is for closing the socket if a virtual circuit is used and
  * the program wants to close it.  This provides support for endhostent()
@@ -560,3 +577,70 @@ ink_res_init(
   statp->options |= INK_RES_INIT;
   return (statp->res_h_errno);
 }
+
+void
+parse_host_res_preferences(char const* value, HostResPreferenceOrder order) {
+  Tokenizer tokens(";/|");
+  // preference from the config string.
+  int np = 0; // index in to @a m_host_res_preference
+  bool found[N_HOST_RES_PREFERENCE];  // redundancy check array
+  int n; // # of tokens
+  int i; // index
+
+  n = tokens.Initialize(value);
+
+  for ( i = 0 ; i < N_HOST_RES_PREFERENCE ; ++i )
+    found[i] = false;
+
+  for ( i = 0 ; i < n && np < N_HOST_RES_PREFERENCE_ORDER ; ++i ) {
+    char const* elt = tokens[i];
+    // special case none/only because that terminates the sequence.
+    if (0 == strcasecmp(elt, HOST_RES_PREFERENCE_STRING[HOST_RES_PREFER_NONE])) {
+      found[HOST_RES_PREFER_NONE] = true;
+      order[np] = HOST_RES_PREFER_NONE;
+      break;
+    } else {
+      // scan the other types
+      HostResPreference ep = HOST_RES_PREFER_NONE;
+      for ( int ip = HOST_RES_PREFER_NONE + 1 ; ip < N_HOST_RES_PREFERENCE ; ++ip ) {
+        if (0 == strcasecmp(elt, HOST_RES_PREFERENCE_STRING[ip])) {
+          ep = static_cast<HostResPreference>(ip);
+          break;
+        }
+      }
+      if (HOST_RES_PREFER_NONE != ep && !found[ep]) { // ignore duplicates
+        found[ep] = true;
+        order[np++] = ep;
+      }
+    }
+  }
+
+  if (!found[HOST_RES_PREFER_NONE]) {
+    // If 'only' wasn't explicit, fill in the rest by default.
+    if (!found[HOST_RES_PREFER_IPV4])
+      order[np++] = HOST_RES_PREFER_IPV4;
+    if (!found[HOST_RES_PREFER_IPV6])
+      order[np++] = HOST_RES_PREFER_IPV6;
+    if (np < N_HOST_RES_PREFERENCE)
+      order[np++] = HOST_RES_PREFER_NONE;
+  }
+}      
+
+int
+ts_host_res_order_to_string(HostResPreferenceOrder const& order, char* out, int size)
+{
+  int zret = 0;
+  bool first = true;
+  for ( int i = 0 ; i < N_HOST_RES_PREFERENCE_ORDER ; ++i ) {
+    /* Note we use a semi-colon here because this must be compatible
+     * with the -httpport command line option which uses comma to
+     * separate port descriptors so we cannot use that to separate
+     * resolution key words.
+     */
+    zret += snprintf(out+zret, size-zret, "%s%s", !first ? ";" : "", HOST_RES_PREFERENCE_STRING[order[i]]);
+    if (HOST_RES_PREFER_NONE == order[i])
+      break;
+    first = false;
+  }
+  return zret;
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/lib/ts/ink_res_mkquery.cc
----------------------------------------------------------------------
diff --git a/lib/ts/ink_res_mkquery.cc b/lib/ts/ink_res_mkquery.cc
index 366c1d5..e0d5d7a 100644
--- a/lib/ts/ink_res_mkquery.cc
+++ b/lib/ts/ink_res_mkquery.cc
@@ -501,3 +501,38 @@ ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
 	*dn++ = '\0';
 	return (dn - dst);
 }
+
+HostResStyle
+ats_host_res_from(int family, HostResPreferenceOrder order)
+{
+  bool v4 = false, v6 = false;
+  HostResPreference client = AF_INET6 == family ? HOST_RES_PREFER_IPV6 : HOST_RES_PREFER_IPV4;
+
+  for ( int i = 0 ; i < N_HOST_RES_PREFERENCE_ORDER ; ++i ) {
+    HostResPreference p = order[i];
+    if (HOST_RES_PREFER_CLIENT == p) p = client; // CLIENT -> actual value
+    if (HOST_RES_PREFER_IPV4 == p) {
+      if (v6) return HOST_RES_IPV6;
+      else v4 = true;
+    } else if (HOST_RES_PREFER_IPV6 == p) {
+      if (v4) return HOST_RES_IPV4;
+      else v6 = true;
+    } else {
+      break;
+    }
+  }
+  if (v4) return HOST_RES_IPV4_ONLY;
+  else if (v6) return HOST_RES_IPV6_ONLY;
+  return HOST_RES_NONE;
+}
+
+HostResStyle
+ats_host_res_match(sockaddr const* addr)
+{
+  HostResStyle zret = HOST_RES_NONE;
+  if (ats_is_ip6(addr))
+    zret = HOST_RES_IPV6_ONLY;
+  else if (ats_is_ip4(addr))
+    zret = HOST_RES_IPV4_ONLY;
+  return zret;
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/lib/ts/ink_resolver.h
----------------------------------------------------------------------
diff --git a/lib/ts/ink_resolver.h b/lib/ts/ink_resolver.h
index 3ebcd9f..dd7b037 100644
--- a/lib/ts/ink_resolver.h
+++ b/lib/ts/ink_resolver.h
@@ -102,6 +102,7 @@
 
 /*%
  *  * Resolver options (keep these in synch with res_debug.c, please)
+ [amc] Most of these are never used. AFAICT it's RECURSE and DEBUG only.
  *   */
 #define INK_RES_INIT        0x00000001      /*%< address initialized */
 #define INK_RES_DEBUG       0x00000002      /*%< print debug messages */
@@ -147,6 +148,58 @@
 #define INK_NS_TYPE_ELT  0x40 /*%< EDNS0 extended label type */
 #define INK_DNS_LABELTYPE_BITSTRING 0x41
 
+/// IP family preference for DNS resolution.
+/// Used for configuration.
+enum HostResPreference {
+  HOST_RES_PREFER_NONE = 0, ///< Invalid / init value.
+  HOST_RES_PREFER_CLIENT, ///< Prefer family of client connection.
+  HOST_RES_PREFER_IPV4, ///< Prefer IPv4.
+  HOST_RES_PREFER_IPV6  ///< Prefer IPv6
+};
+/// # of preference values.
+static int const N_HOST_RES_PREFERENCE = HOST_RES_PREFER_IPV6+1;
+/// # of entries in a preference ordering.
+static int const N_HOST_RES_PREFERENCE_ORDER = 3;
+/// Storage for preference ordering.
+typedef HostResPreference HostResPreferenceOrder[N_HOST_RES_PREFERENCE_ORDER];
+/// Global, hard wired default value for preference ordering.
+extern HostResPreferenceOrder const HOST_RES_DEFAULT_PREFERENCE_ORDER;
+/// Global (configurable) default.
+extern HostResPreferenceOrder host_res_default_preference_order;
+/// String versions of @c FamilyPreference
+extern char const* const HOST_RES_PREFERENCE_STRING[N_HOST_RES_PREFERENCE];
+
+/// IP family to use in a DNS query for a host address.
+/// Used during DNS query operations.
+enum HostResStyle{
+  HOST_RES_NONE = 0, ///< No preference / unspecified / init value.
+  HOST_RES_IPV4, ///< Use IPv4 if possible.
+  HOST_RES_IPV4_ONLY, ///< Resolve on IPv4 addresses.
+  HOST_RES_IPV6, ///< Use IPv6 if possible.
+  HOST_RES_IPV6_ONLY ///< Resolve only IPv6 addresses.
+};
+
+/// Strings for host resolution styles
+extern char const* const HOST_RES_STYLE_STRING[];
+
+/// Caclulate the effective resolution preferences.
+extern HostResStyle
+ats_host_res_from(
+		   int family, ///< Connection family
+		   HostResPreferenceOrder ///< Preference ordering.
+		   );
+/// Calculate the host resolution style to force a family match to @a addr.
+extern HostResStyle
+ats_host_res_match(sockaddr const* addr);
+
+/** Parse a host resolution configuration string.
+ */
+extern void
+parse_host_res_preferences(
+			   char const* value, ///< [in] Configuration string.
+			   HostResPreferenceOrder order /// [out] Order to update.
+			   );
+
 #ifndef NS_GET16
 #define NS_GET16(s, cp) do { \
         register const u_char *t_cp = (const u_char *)(cp); \
@@ -237,5 +290,19 @@ int ink_res_mkquery(ink_res_state, int, const char *, int, int,
 
 int ink_ns_name_ntop(const u_char *src, char *dst, size_t dstsiz);
 
+/** Initialize global values for HttpProxyPort / Host Resolution.
+ */
+void ts_host_res_global_init();
+
+/** Generate a string representation of a host resolution preference ordering.
+    @return The length of the string.
+ */
+int
+ts_host_res_order_to_string(
+			    HostResPreferenceOrder const& order, ///< order to print
+			    char* out, ///< Target buffer for string.
+			    int size ///< Size of buffer.
+			    );
+
 #endif   /* _ink_resolver_h_ */
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/mgmt/Main.cc
----------------------------------------------------------------------
diff --git a/mgmt/Main.cc b/mgmt/Main.cc
index 87450dc..1f9c2ab 100644
--- a/mgmt/Main.cc
+++ b/mgmt/Main.cc
@@ -608,6 +608,7 @@ main(int argc, char **argv)
 #if TS_HAS_WCCP
   Init_Errata_Logging();
 #endif
+  ts_host_res_global_init();
   lmgmt = new LocalManager(mgmt_path, proxy_on);
   RecLocalInitMessage();
   lmgmt->initAlarm();

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/mgmt/RecordsConfig.cc
----------------------------------------------------------------------
diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc
index ba983b0..c940852 100644
--- a/mgmt/RecordsConfig.cc
+++ b/mgmt/RecordsConfig.cc
@@ -1035,6 +1035,8 @@ RecordElement RecordsConfig[] = {
   ,
   {RECT_CONFIG, "proxy.config.dns.dedicated_thread", RECD_INT, "0", RECU_RESTART_TS, RR_NULL, RECC_NULL, "[0-1]", RECA_NULL}
   ,
+  {RECT_CONFIG, "proxy.config.hostdb.ip_resolve", RECD_STRING, NULL, RECU_RESTART_TS, RR_NULL, RECC_STR, NULL, RECA_NULL} 
+  ,
 
   //##############################################################################
   //#

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/proxy/http/HttpAccept.cc
----------------------------------------------------------------------
diff --git a/proxy/http/HttpAccept.cc b/proxy/http/HttpAccept.cc
index 6a7d599..9e7dda8 100644
--- a/proxy/http/HttpAccept.cc
+++ b/proxy/http/HttpAccept.cc
@@ -68,6 +68,7 @@ HttpAccept::mainEvent(int event, void *data)
     new_session->outbound_ip4 = outbound_ip4;
     new_session->outbound_ip6 = outbound_ip6;
     new_session->outbound_port = outbound_port;
+    new_session->host_res_style = ats_host_res_from(client_ip->sa_family, host_res_preference);
     new_session->acl_method_mask = acl_method_mask;
 
     new_session->new_connection(netvc, backdoor);

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/proxy/http/HttpAccept.h
----------------------------------------------------------------------
diff --git a/proxy/http/HttpAccept.h b/proxy/http/HttpAccept.h
index 51592ad..d8e4160 100644
--- a/proxy/http/HttpAccept.h
+++ b/proxy/http/HttpAccept.h
@@ -61,8 +61,9 @@ namespace detail {
     IpAddr outbound_ip4;
     /// Local address to bind for outbound connections.
     IpAddr outbound_ip6;
-    /// Set the outbound IP address.
+    /// Set the outbound IP address to @a ip.
     self& setOutboundIp(IpAddr& ip);
+    /// Set the outbound IP address to @a ip.
     self& setOutboundIp(IpEndpoint* ip);
     /// Local port for outbound connection.
     uint16_t outbound_port;
@@ -76,6 +77,10 @@ namespace detail {
     bool backdoor;
     /// Set backdoor accept.
     self& setBackdoor(bool);
+    /// Host address resolution preference order.
+    HostResPreferenceOrder host_res_preference;
+    /// Set the host query preference.
+    self& setHostResPreference(HostResPreferenceOrder const);
   };
 
   inline HttpAcceptOptions::HttpAcceptOptions()
@@ -84,6 +89,7 @@ namespace detail {
     , f_outbound_transparent(false)
     , backdoor(false)
   {
+    memcpy(host_res_preference, host_res_default_preference_order, sizeof(host_res_preference));
   }
 
   inline HttpAcceptOptions&
@@ -123,6 +129,12 @@ namespace detail {
     backdoor = flag;
     return *this;
   }
+
+  inline HttpAcceptOptions&
+  HttpAcceptOptions::setHostResPreference(HostResPreferenceOrder const order) {
+    memcpy(host_res_preference, order, sizeof(host_res_preference));
+    return *this;
+  }
 }
 
 /**

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/proxy/http/HttpClientSession.cc
----------------------------------------------------------------------
diff --git a/proxy/http/HttpClientSession.cc b/proxy/http/HttpClientSession.cc
index b214482..72720d4 100644
--- a/proxy/http/HttpClientSession.cc
+++ b/proxy/http/HttpClientSession.cc
@@ -64,7 +64,10 @@ HttpClientSession::HttpClientSession()
     read_buffer(NULL), current_reader(NULL), read_state(HCS_INIT),
     ka_vio(NULL), slave_ka_vio(NULL),
     cur_hook_id(TS_HTTP_LAST_HOOK), cur_hook(NULL),
-    cur_hooks(0), proxy_allocated(false), backdoor_connect(false), hooks_set(0),
+    cur_hooks(0), proxy_allocated(false), backdoor_connect(false),
+    hooks_set(0),
+    outbound_port(0), f_outbound_transparent(false),
+    host_res_style(HOST_RES_IPV4), acl_method_mask(0),
     m_active(false), debug_on(false)
 {
   memset(user_args, 0, sizeof(user_args));

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/proxy/http/HttpClientSession.h
----------------------------------------------------------------------
diff --git a/proxy/http/HttpClientSession.h b/proxy/http/HttpClientSession.h
index 6978a17..ffaa367 100644
--- a/proxy/http/HttpClientSession.h
+++ b/proxy/http/HttpClientSession.h
@@ -151,6 +151,8 @@ public:
   uint16_t outbound_port;
   /// Set outbound connection to transparent.
   bool f_outbound_transparent;
+  /// DNS resolution preferences.
+  HostResStyle host_res_style;
   /// acl method mask - cache IpAllow::match() call
   uint32_t acl_method_mask;
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/proxy/http/HttpProxyServerMain.cc
----------------------------------------------------------------------
diff --git a/proxy/http/HttpProxyServerMain.cc b/proxy/http/HttpProxyServerMain.cc
index b48e0f2..b69a49d 100644
--- a/proxy/http/HttpProxyServerMain.cc
+++ b/proxy/http/HttpProxyServerMain.cc
@@ -166,6 +166,7 @@ start_HttpProxyPort(const HttpProxyPort& port, unsigned nthreads)
 
   http.f_outbound_transparent = port.m_outbound_transparent_p;
   http.transport_type = port.m_type;
+  http.setHostResPreference(port.m_host_res_preference);
 
   if (port.m_inbound_ip.isValid()) {
     net.local_ip = port.m_inbound_ip;

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/proxy/http/HttpSM.cc
----------------------------------------------------------------------
diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc
index c7deff1..dabaa9b 100644
--- a/proxy/http/HttpSM.cc
+++ b/proxy/http/HttpSM.cc
@@ -1971,22 +1971,16 @@ lookup:
 
   HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::state_hostdb_lookup);
 
+  HostDBProcessor::Options opt;
   if (t_state.api_txn_dns_timeout_value != -1) {
+    opt.timeout = t_state.api_txn_dns_timeout_value;
     DebugSM("http_timeout", "beginning DNS lookup. allowing %d mseconds for DNS", t_state.api_txn_dns_timeout_value);
   }
+  opt.flags = (t_state.cache_info.directives.does_client_permit_dns_storing) ? HostDBProcessor::HOSTDB_DO_NOT_FORCE_DNS : HostDBProcessor::HOSTDB_FORCE_DNS_RELOAD;
+  opt.port = server_port;
+  opt.host_res_style = ua_session->host_res_style;
 
-  Action *dns_lookup_action_handle = hostDBProcessor.getbyname_imm(this,
-                                                                   (process_hostdb_info_pfn) & HttpSM::
-                                                                   process_hostdb_info,
-                                                                   &new_host[0], 0,
-                                                                   server_port,
-                                                                   ((t_state.cache_info.directives.
-                                                                     does_client_permit_dns_storing) ? HostDBProcessor::
-                                                                    HOSTDB_DO_NOT_FORCE_DNS : HostDBProcessor::
-                                                                    HOSTDB_FORCE_DNS_RELOAD),
-                                                                   (t_state.api_txn_dns_timeout_value != -1) ? t_state.
-                                                                   api_txn_dns_timeout_value : 0);
-
+  Action *dns_lookup_action_handle = hostDBProcessor.getbyname_imm(this, (process_hostdb_info_pfn) & HttpSM::process_hostdb_info, &new_host[0], 0, opt);
 
   if (dns_lookup_action_handle != ACTION_RESULT_DONE) {
     ink_assert(!pending_action);
@@ -2001,7 +1995,7 @@ lookup:
 void
 HttpSM::process_hostdb_info(HostDBInfo * r)
 {
-  if (r) {
+  if (r && !r->failed()) {
     HostDBInfo *rr = NULL;
     t_state.dns_info.lookup_success = true;
 
@@ -3758,9 +3752,11 @@ HttpSM::do_hostdb_lookup()
     DebugSM("dns_srv", "Beginning lookup of SRV records for origin %s", d);
     HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::state_srv_lookup);
 
+    HostDBProcessor::Options opt;
+    if (t_state.api_txn_dns_timeout_value != -1)
+      opt.timeout = t_state.api_txn_dns_timeout_value;
     Action *srv_lookup_action_handle =
-      hostDBProcessor.getSRVbyname_imm(this, (process_srv_info_pfn) & HttpSM::process_srv_info, d,
-                                       (t_state.api_txn_dns_timeout_value != -1) ? t_state.api_txn_dns_timeout_value : 0);
+      hostDBProcessor.getSRVbyname_imm(this, (process_srv_info_pfn) & HttpSM::process_srv_info, d, 0, opt);
 
     if (srv_lookup_action_handle != ACTION_RESULT_DONE) {
       ink_assert(!pending_action);
@@ -3780,18 +3776,16 @@ HttpSM::do_hostdb_lookup()
             t_state.api_txn_dns_timeout_value);
     }
 
-    Action *dns_lookup_action_handle = hostDBProcessor.getbyname_imm(this,
-                                                                     (process_hostdb_info_pfn) & HttpSM::
-                                                                     process_hostdb_info,
-                                                                     t_state.dns_info.lookup_name, 0,
-                                                                     server_port,
-                                                                     ((t_state.cache_info.directives.
-                                                                       does_client_permit_dns_storing) ?
-                                                                      HostDBProcessor::
-                                                                      HOSTDB_DO_NOT_FORCE_DNS : HostDBProcessor::
-                                                                      HOSTDB_FORCE_DNS_RELOAD),
-                                                                     (t_state.api_txn_dns_timeout_value != -1) ? t_state.
-                                                                     api_txn_dns_timeout_value : 0);
+    HostDBProcessor::Options opt;
+    opt.port = server_port;
+    opt.flags = (t_state.cache_info.directives.does_client_permit_dns_storing)
+      ? HostDBProcessor::HOSTDB_DO_NOT_FORCE_DNS
+      : HostDBProcessor::HOSTDB_FORCE_DNS_RELOAD
+    ;
+    opt.timeout = (t_state.api_txn_dns_timeout_value != -1) ? t_state.api_txn_dns_timeout_value : 0;
+    opt.host_res_style = ua_session->host_res_style;
+
+    Action *dns_lookup_action_handle = hostDBProcessor.getbyname_imm(this, (process_hostdb_info_pfn) & HttpSM::process_hostdb_info, t_state.dns_info.lookup_name, 0, opt);
 
     if (dns_lookup_action_handle != ACTION_RESULT_DONE) {
       ink_assert(!pending_action);
@@ -4302,8 +4296,8 @@ HttpSM::do_cache_prepare_action(HttpCacheSM * c_sm, CacheHTTPInfo * object_read_
 void
 HttpSM::do_http_server_open(bool raw)
 {
-  DebugSM("http_track", "entered inside do_http_server_open");
   int ip_family = t_state.current.server->addr.sa.sa_family;
+  DebugSM("http_track", "entered inside do_http_server_open ][%s]", ats_ip_family_name(ip_family));
 
   ink_assert(server_entry == NULL);
 
@@ -4407,7 +4401,7 @@ HttpSM::do_http_server_open(bool raw)
 
     if (existing_ss) {
       // [amc] Is this OK? Should we compare ports? (not done by ats_ip_addr_cmp)
-      if (ats_ip_addr_cmp(&existing_ss->server_ip.sa, &t_state.current.server->addr.sa) == 0) {
+      if (ats_ip_addr_eq(&existing_ss->server_ip.sa, &t_state.current.server->addr.sa)) {
         ua_session->attach_server_session(NULL);
         existing_ss->state = HSS_ACTIVE;
         this->attach_server_session(existing_ss);
@@ -6691,15 +6685,19 @@ HttpSM::set_next_state()
         && !t_state.url_remap_success
         && t_state.parent_result.r != PARENT_SPECIFIED
         && t_state.client_info.is_transparent
+        && t_state.dns_info.os_addr_style == HttpTransact::DNSLookupInfo::OS_ADDR_TRY_DEFAULT
         && ats_is_ip(addr = t_state.state_machine->ua_session->get_netvc()->get_local_addr())
       ) {
-        ip_text_buffer ipb;
-        /* If the connection is client side transparent and the URL was not
-         * remapped/directed to parent proxy, we can use the client destination
-         * IP address instead of doing a DNS lookup. This is controlled by the
-         * 'use_client_target_addr' configuration parameter.
+        /* If the connection is client side transparent and the URL
+         * was not remapped/directed to parent proxy, we can use the
+         * client destination IP address instead of doing a DNS
+         * lookup. This is controlled by the 'use_client_target_addr'
+         * configuration parameter.
          */
-        DebugSM("dns", "[HttpTransact::HandleRequest] Skipping DNS lookup for client supplied target %s.\n", ats_ip_ntop(addr, ipb, sizeof(ipb)));
+        if (is_debug_tag_set("dns")) {
+          ip_text_buffer ipb;
+          DebugSM("dns", "[HttpTransact::HandleRequest] Skipping DNS lookup for client supplied target %s.\n", ats_ip_ntop(addr, ipb, sizeof(ipb)));
+        }
         ats_ip_copy(t_state.host_db_info.ip(), addr);
         /* Since we won't know the server HTTP version (no hostdb lookup), we assume it matches the
          * client request version. Seems to be the most correct thing to do in the transparent use-case.
@@ -6712,6 +6710,9 @@ HttpSM::set_next_state()
           t_state.host_db_info.app.http_data.http_version =  HostDBApplicationInfo::HTTP_VERSION_11;
 
         t_state.dns_info.lookup_success = true;
+        // cache this result so we don't have to unreliably duplicate the
+        // logic later if the connect fails.
+        t_state.dns_info.os_addr_style = HttpTransact::DNSLookupInfo::OS_ADDR_TRY_CLIENT;
         call_transact_and_set_next_state(NULL);
         break;
       } else if (t_state.parent_result.r == PARENT_UNDEFINED && t_state.dns_info.lookup_success) {

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/proxy/http/HttpTransact.cc
----------------------------------------------------------------------
diff --git a/proxy/http/HttpTransact.cc b/proxy/http/HttpTransact.cc
index ead53e6..a938545 100644
--- a/proxy/http/HttpTransact.cc
+++ b/proxy/http/HttpTransact.cc
@@ -1551,37 +1551,44 @@ HttpTransact::OSDNSLookup(State* s)
     case EXPANSION_NOT_ALLOWED:
     case EXPANSION_FAILED:
     case DNS_ATTEMPTS_EXHAUSTED:
-      if (host_name_expansion == EXPANSION_NOT_ALLOWED) {
-        // config file doesn't allow automatic expansion of host names
-        HTTP_RELEASE_ASSERT(!(s->http_config_param->enable_url_expandomatic));
-        DebugTxn("http_seq", "[HttpTransact::OSDNSLookup] DNS Lookup unsuccessful");
-      } else if (host_name_expansion == EXPANSION_FAILED) {
-        // not able to expand the hostname. dns lookup failed
-        DebugTxn("http_seq", "[HttpTransact::OSDNSLookup] DNS Lookup unsuccessful");
-      } else if (host_name_expansion == DNS_ATTEMPTS_EXHAUSTED) {
-        // retry attempts exhausted --- can't find dns entry for this host name
-        HTTP_RELEASE_ASSERT(s->dns_info.attempts >= max_dns_lookups);
-        DebugTxn("http_seq", "[HttpTransact::OSDNSLookup] DNS Lookup unsuccessful");
+      if (DNSLookupInfo::OS_ADDR_TRY_HOSTDB == s->dns_info.os_addr_style) {
+        // No HostDB data, just keep on with the CTA.
+        s->dns_info.lookup_success = true;
+        s->dns_info.os_addr_style = DNSLookupInfo::OS_ADDR_USE_CLIENT;
+        DebugTxn("http_seq", "[HttpTransact::OSDNSLookup] DNS lookup unsuccessful reverting to force client target address use");
+      } else {
+        if (host_name_expansion == EXPANSION_NOT_ALLOWED) {
+          // config file doesn't allow automatic expansion of host names
+          HTTP_RELEASE_ASSERT(!(s->http_config_param->enable_url_expandomatic));
+          DebugTxn("http_seq", "[HttpTransact::OSDNSLookup] DNS Lookup unsuccessful");
+        } else if (host_name_expansion == EXPANSION_FAILED) {
+          // not able to expand the hostname. dns lookup failed
+          DebugTxn("http_seq", "[HttpTransact::OSDNSLookup] DNS Lookup unsuccessful");
+        } else if (host_name_expansion == DNS_ATTEMPTS_EXHAUSTED) {
+          // retry attempts exhausted --- can't find dns entry for this host name
+          HTTP_RELEASE_ASSERT(s->dns_info.attempts >= max_dns_lookups);
+          DebugTxn("http_seq", "[HttpTransact::OSDNSLookup] DNS Lookup unsuccessful");
+        }
+        // output the DNS failure error message
+        SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_NO_FORWARD);
+        build_error_response(s, HTTP_STATUS_BAD_GATEWAY, "Cannot find server.", "connect#dns_failed",
+                             // The following is all one long string
+                             //("Unable to locate the server named \"<em>%s</em>\" --- "
+                             //"the server does not have a DNS entry.  Perhaps there is "
+                             //"a misspelling in the server name, or the server no "
+                             //"longer exists.  Double-check the name and try again."),
+                             ("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">"
+                              "<HTML><HEAD><TITLE>Unknown Host</TITLE></HEAD><BODY BGCOLOR=\"white\" FGCOLOR=\"black\">"
+                              "<H1>Unknown Host</H1><HR>"
+                              "<FONT FACE=\"Helvetica,Arial\"><B>"
+                              "Description: Unable to locate the server named \"<EM>%s (%d)</EM>\" --- "
+                              "the server does not have a DNS entry.  Perhaps there is a misspelling "
+                              "in the server name, or the server no longer exists.  Double-check the "
+                              "name and try again.</B></FONT><HR></BODY></HTML>")
+                             , s->server_info.name, host_name_expansion);
+        // s->cache_info.action = CACHE_DO_NO_ACTION;
+        TRANSACT_RETURN(PROXY_SEND_ERROR_CACHE_NOOP, NULL);
       }
-      // output the DNS failure error message
-      SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_NO_FORWARD);
-      build_error_response(s, HTTP_STATUS_BAD_GATEWAY, "Cannot find server.", "connect#dns_failed",
-                           // The following is all one long string
-                           //("Unable to locate the server named \"<em>%s</em>\" --- "
-                           //"the server does not have a DNS entry.  Perhaps there is "
-                           //"a misspelling in the server name, or the server no "
-                           //"longer exists.  Double-check the name and try again."),
-                          ("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">"
-                          "<HTML><HEAD><TITLE>Unknown Host</TITLE></HEAD><BODY BGCOLOR=\"white\" FGCOLOR=\"black\">"
-                          "<H1>Unknown Host</H1><HR>"
-                          "<FONT FACE=\"Helvetica,Arial\"><B>"
-                          "Description: Unable to locate the server named \"<EM>%s (%d)</EM>\" --- "
-                          "the server does not have a DNS entry.  Perhaps there is a misspelling "
-                          "in the server name, or the server no longer exists.  Double-check the "
-                          "name and try again.</B></FONT><HR></BODY></HTML>")
-                           , s->server_info.name, host_name_expansion);
-      // s->cache_info.action = CACHE_DO_NO_ACTION;
-      TRANSACT_RETURN(PROXY_SEND_ERROR_CACHE_NOOP, NULL);
       break;
     default:
       ink_debug_assert(!("try_to_expand_hostname returned an unsupported code"));
@@ -1593,6 +1600,27 @@ HttpTransact::OSDNSLookup(State* s)
   ink_debug_assert(s->dns_info.lookup_success);
   DebugTxn("http_seq", "[HttpTransact::OSDNSLookup] DNS Lookup successful");
 
+  if (DNSLookupInfo::OS_ADDR_TRY_HOSTDB == s->dns_info.os_addr_style) {
+    // We've backed off from a client supplied address and found some
+    // HostDB addresses. We use those if they're different from the CTA.
+    // In all cases we now commit to client or HostDB for our source.
+    if (s->dns_info.round_robin) {
+      HostDBInfo* cta = s->host_db_info.rr()->select_next(&s->current.server->addr.sa);
+      if (cta) {
+        // found another addr, lock in host DB.
+        s->host_db_info = *cta;
+        s->dns_info.os_addr_style = DNSLookupInfo::OS_ADDR_USE_HOSTDB;
+      } else {
+        // nothing else there, continue with CTA.
+        s->dns_info.os_addr_style = DNSLookupInfo::OS_ADDR_USE_CLIENT;
+      }
+    } else if (ats_ip_addr_eq(s->host_db_info.ip(), &s->server_info.addr.sa)) {
+      s->dns_info.os_addr_style = DNSLookupInfo::OS_ADDR_USE_CLIENT;
+    } else {
+      s->dns_info.os_addr_style = DNSLookupInfo::OS_ADDR_USE_HOSTDB;
+    }
+  }
+
   // Check to see if can fullfill expect requests based on the cached
   // update some state variables with hostdb information that has
   // been provided.
@@ -1615,7 +1643,8 @@ HttpTransact::OSDNSLookup(State* s)
   // hostname expansion, forward the request to the expanded hostname.
   // On the other hand, if the lookup succeeded on a www.<hostname>.com
   // expansion, return a 302 response.
-  if (s->dns_info.attempts == max_dns_lookups && s->dns_info.looking_up == ORIGIN_SERVER) {
+  // [amc] Also don't redirect if we backed off using HostDB instead of CTA.
+  if (s->dns_info.attempts == max_dns_lookups && s->dns_info.looking_up == ORIGIN_SERVER && DNSLookupInfo::OS_ADDR_USE_CLIENT != s->dns_info.os_addr_style) {
     DebugTxn("http_trans", "[OSDNSLookup] DNS name resolution on expansion");
     DebugTxn("http_seq", "[OSDNSLookup] DNS name resolution on expansion - returning");
     build_redirect_response(s);
@@ -1638,6 +1667,11 @@ HttpTransact::OSDNSLookup(State* s)
     HttpTransactHeaders::convert_request(s->current.server->http_version, &s->hdr_info.server_request);
     DebugTxn("cdn", "outgoing version -- (post conversion) %d", s->hdr_info.server_request.m_http->m_version);
     TRANSACT_RETURN(s->cdn_saved_next_action, NULL);
+  } else if (DNSLookupInfo::OS_ADDR_USE_CLIENT == s->dns_info.os_addr_style ||
+             DNSLookupInfo::OS_ADDR_USE_HOSTDB == s->dns_info.os_addr_style) {
+    // we've come back after already trying the server to get a better address
+    // and finished with all backtracking - return to trying the server.
+    TRANSACT_RETURN(how_to_open_connection(s), HttpTransact::HandleResponse);
   } else if (s->dns_info.lookup_name[0] <= '9' &&
              s->dns_info.lookup_name[0] >= '0' &&
              //(s->state_machine->authAdapter.needs_rev_dns() ||
@@ -3475,12 +3509,12 @@ HttpTransact::handle_response_from_server(State* s)
     s->current.server->connect_failure = 1;
     handle_server_connection_not_open(s);
     break;
-  case STATE_UNDEFINED:
-    /* fall through */
   case OPEN_RAW_ERROR:
     /* fall through */
   case CONNECTION_ERROR:
     /* fall through */
+  case STATE_UNDEFINED:
+    /* fall through */
   case INACTIVE_TIMEOUT:
     /* fall through */
   case PARSE_ERROR:
@@ -3504,7 +3538,19 @@ HttpTransact::handle_response_from_server(State* s)
 
       bool use_srv_records = HttpConfig::m_master.srv_enabled;
 
-      if (use_srv_records) {
+      if (DNSLookupInfo::OS_ADDR_TRY_CLIENT == s->dns_info.os_addr_style) {
+        // attempt was based on client supplied server address. Try again
+        // using HostDB.
+        // Allow DNS attempt
+        s->dns_info.lookup_success = false;
+        // See if we can get data from HostDB for this.
+        s->dns_info.os_addr_style = DNSLookupInfo::OS_ADDR_TRY_HOSTDB;
+        // Force host resolution to have the same family as the client.
+        // Because this is a transparent connection, we can't switch address
+        // families - that is locked in by the client source address.
+        s->state_machine->ua_session->host_res_style = ats_host_res_match(&s->current.server->addr.sa);
+        TRANSACT_RETURN(HttpTransact::DNS_LOOKUP, OSDNSLookup);
+      } else if (use_srv_records) {
         delete_srv_entry(s, max_connect_retries);
         return;
       } else if (s->server_info.dns_round_robin &&
@@ -3542,40 +3588,33 @@ void
 HttpTransact::delete_srv_entry(State* s, int max_retries)
 {
   /* we are using SRV lookups and this host failed -- lets remove it from the HostDB */
-  INK_MD5 md5;
+  HostDBMD5 md5;
   EThread *thread = this_ethread();
   //ProxyMutex *mutex = thread->mutex;
-  void *pDS = 0;
-
-  int len;
-  int port;
-  ProxyMutex *bucket_mutex = hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets));
+  md5.host_name = s->dns_info.srv_hostname;
+  if (!md5.host_name) {
+    TRANSACT_RETURN(OS_RR_MARK_DOWN, ReDNSRoundRobin);
+  }
+  md5.host_len = strlen(md5.host_name);
+  md5.db_mark = HOSTDB_MARK_SRV;
+  md5.refresh();
 
-  char *hostname = s->dns_info.srv_hostname;    /* of the form: _http._tcp.host.foo.bar.com */
+  ProxyMutex *bucket_mutex = hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets));
 
   s->current.attempts++;
 
   DebugTxn("http_trans", "[delete_srv_entry] attempts now: %d, max: %d", s->current.attempts, max_retries);
   DebugTxn("dns_srv", "[delete_srv_entry] attempts now: %d, max: %d", s->current.attempts, max_retries);
 
-  if (!hostname) {
-    TRANSACT_RETURN(OS_RR_MARK_DOWN, ReDNSRoundRobin);
-  }
-
-  len = strlen(hostname);
-  port = 0;
-
-  make_md5(md5, hostname, len, port, 0, 1);
-
   MUTEX_TRY_LOCK(lock, bucket_mutex, thread);
   if (lock) {
-    IpEndpoint ip;
-    HostDBInfo *r = probe(bucket_mutex, md5, hostname, len, ats_ip4_set(&ip.sa, INADDR_ANY, htons(port)), pDS, false, true);
+//    IpEndpoint ip;
+    HostDBInfo *r = probe(bucket_mutex, md5, false);
     if (r) {
       if (r->is_srv) {
-        DebugTxn("dns_srv", "Marking SRV records for %s [Origin: %s] as bad", hostname, s->dns_info.lookup_name);
+        DebugTxn("dns_srv", "Marking SRV records for %s [Origin: %s] as bad", md5.host_name, s->dns_info.lookup_name);
 
-        uint64_t folded_md5 = fold_md5(md5);
+        uint64_t folded_md5 = fold_md5(md5.hash);
 
         HostDBInfo *new_r = NULL;
 
@@ -3586,7 +3625,7 @@ HttpTransact::delete_srv_entry(State* s, int max_retries)
         hostDB.delete_block(r); //delete the original HostDB
 
         new_r = hostDB.insert_block(folded_md5, NULL, 0);       //create new entry
-        new_r->md5_high = md5[1];
+        new_r->md5_high = md5.hash[1];
 
         SortableQueue<SRV> *q = srv_hosts.getHosts();        //get the Queue of SRV entries
         SRV *srv_entry = NULL;
@@ -3658,7 +3697,7 @@ HttpTransact::delete_srv_entry(State* s, int max_retries)
         }
 
       } else {
-        DebugTxn("dns_srv", "Trying to delete a bad SRV for %s and something was wonky", hostname);
+        DebugTxn("dns_srv", "Trying to delete a bad SRV for %s and something was wonky", md5.host_name);
       }
     } else {
       DebugTxn("dns_srv", "No SRV data to remove. Ruh Roh Shaggy. Maxing out connection attempts...");

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/proxy/http/HttpTransact.h
----------------------------------------------------------------------
diff --git a/proxy/http/HttpTransact.h b/proxy/http/HttpTransact.h
index e70d1b2..cbc20a0 100644
--- a/proxy/http/HttpTransact.h
+++ b/proxy/http/HttpTransact.h
@@ -834,6 +834,25 @@ public:
   typedef struct _DNSLookupInfo
   {
     int attempts;
+    /** Origin server address source selection.
+
+	If config says to use CTA (client target addr) state is
+	OS_ADDR_TRY_CLIENT, otherwise it remains the default. If the
+	connect fails then we switch to a USE. We go to USE_HOSTDB if
+	(1) the HostDB lookup is successful and (2) some address other
+	than the CTA is available to try. Otherwise we keep retrying
+	on the CTA (USE_CLIENT) up to the max retry value.  In essence
+	we try to treat the CTA as if it were another RR value in the
+	HostDB record.
+     */ 
+    enum {
+      OS_ADDR_TRY_DEFAULT, ///< Initial state, use what config says.
+      OS_ADDR_TRY_HOSTDB, ///< Try HostDB data.
+      OS_ADDR_TRY_CLIENT, ///< Try client target addr.
+      OS_ADDR_USE_HOSTDB, ///< Force use of HostDB target address.
+      OS_ADDR_USE_CLIENT ///< Use client target addr, no fallback.
+    } os_addr_style;
+
     bool lookup_success;
     char *lookup_name;
     char srv_hostname[MAXDNAME];
@@ -841,7 +860,7 @@ public:
     bool round_robin;
 
     _DNSLookupInfo()
-      : attempts(0),
+    : attempts(0), os_addr_style(OS_ADDR_TRY_DEFAULT),
         lookup_success(false), lookup_name(NULL), looking_up(UNDEFINED_LOOKUP), round_robin(false)
     {
       memset(&srv_hostname, 0, sizeof(srv_hostname));

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/proxy/logging/LogCollationClientSM.cc
----------------------------------------------------------------------
diff --git a/proxy/logging/LogCollationClientSM.cc b/proxy/logging/LogCollationClientSM.cc
index 7f761a5..3af7bb4 100644
--- a/proxy/logging/LogCollationClientSM.cc
+++ b/proxy/logging/LogCollationClientSM.cc
@@ -302,7 +302,7 @@ LogCollationClientSM::client_dns(int event, HostDBInfo * hostdb_info)
     if (m_log_host->m_name == 0) {
       return client_done(LOG_COLL_EVENT_SWITCH, NULL);
     }
-    hostDBProcessor.getbyname_re(this, m_log_host->m_name, 0, HostDBProcessor::HOSTDB_FORCE_DNS_RELOAD);
+    hostDBProcessor.getbyname_re(this, m_log_host->m_name, 0, HostDBProcessor::Options().setFlags(HostDBProcessor::HOSTDB_FORCE_DNS_RELOAD));
     return EVENT_CONT;
 
   case EVENT_HOST_DB_LOOKUP: