]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: resolve hostname dns cname record
authorYehuda Sadeh <yehuda@inktank.com>
Mon, 29 Oct 2012 23:46:21 +0000 (16:46 -0700)
committerYehuda Sadeh <yehuda@inktank.com>
Tue, 6 Nov 2012 23:19:47 +0000 (15:19 -0800)
Implements #3206
This allows using vanity domains. A CNAME record can now
be set for the domain that would point at the rgw instance,
with or without a bucket set as a subdomain.

Signed-off-by: Yehuda Sadeh <yehuda@inktank.com>
src/Makefile.am
src/common/config_opts.h
src/rgw/rgw_main.cc
src/rgw/rgw_resolve.cc [new file with mode: 0644]
src/rgw/rgw_resolve.h [new file with mode: 0644]
src/rgw/rgw_rest.cc

index dbb37df5fe22addcd29166db7fa2b555f17fb04b..5e86d03c966ba628d7b481cc5e08f45e621689c7 100644 (file)
@@ -339,6 +339,7 @@ my_radosgw_ldadd = \
        $(PTHREAD_LIBS) -lm $(CRYPTO_LIBS) $(EXTRALIBS)
 
 radosgw_SOURCES = \
+       rgw/rgw_resolve.cc \
         rgw/rgw_rest.cc \
         rgw/rgw_rest_swift.cc \
         rgw/rgw_rest_s3.cc \
index c95af92b58b5434ee42671b3821ed6acaa36a475..07149bef07921fb52818cab357df46663960a632 100644 (file)
@@ -449,6 +449,7 @@ OPTION(rgw_gc_max_objs, OPT_INT, 32)
 OPTION(rgw_gc_obj_min_wait, OPT_INT, 2 * 3600)    // wait time before object may be handled by gc
 OPTION(rgw_gc_processor_max_time, OPT_INT, 3600)  // total run time for a single gc processor work
 OPTION(rgw_gc_processor_period, OPT_INT, 3600)  // gc processor cycle time
+OPTION(rgw_resolve_cname, OPT_BOOL, false)  // should rgw try to resolve hostname as a dns cname record
 
 // This will be set to true when it is safe to start threads.
 // Once it is true, it will never change.
index a2cf9e13b8178204915b29fdcbdeb7855f7a3ba9..5d9efee3cd4aeea06e5aa682c7e995a19d22129d 100644 (file)
@@ -42,6 +42,7 @@
 #include "rgw_swift.h"
 #include "rgw_log.h"
 #include "rgw_tools.h"
+#include "rgw_resolve.h"
 
 #include <map>
 #include <string>
@@ -419,6 +420,7 @@ int main(int argc, const char **argv)
 
   rgw_tools_init(g_ceph_context);
 
+  rgw_init_resolver();
   rgw_rest_init();
   
   curl_global_init(CURL_GLOBAL_ALL);
diff --git a/src/rgw/rgw_resolve.cc b/src/rgw/rgw_resolve.cc
new file mode 100644 (file)
index 0000000..80d94f7
--- /dev/null
@@ -0,0 +1,172 @@
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include "rgw_common.h"
+#include "rgw_resolve.h"
+
+#define dout_subsys ceph_subsys_rgw
+
+class RGWDNSResolver {
+  list<res_state> states;
+  Mutex lock;
+
+  int get_state(res_state *ps);
+  void put_state(res_state s);
+
+
+public:
+  ~RGWDNSResolver();
+  RGWDNSResolver() : lock("RGWDNSResolver") {}
+  int resolve_cname(const string& hostname, string& cname, bool *found);
+};
+
+RGWDNSResolver::~RGWDNSResolver()
+{
+  list<res_state>::iterator iter;
+  for (iter = states.begin(); iter != states.end(); ++iter) {
+    struct __res_state *s = *iter;
+    delete s;
+  }
+}
+
+
+int RGWDNSResolver::get_state(res_state *ps)
+{
+  lock.Lock();
+  if (!states.empty()) {
+    res_state s = states.front();
+    states.pop_front();
+    lock.Unlock();
+    *ps = s;
+    return 0;
+  }
+  lock.Unlock();
+  struct __res_state *s = new struct __res_state;
+  s->options = 0;
+  if (res_ninit(s) < 0) {
+    delete s;
+    dout(0) << "ERROR: failed to call res_ninit()" << dendl;
+    return -EINVAL;
+  }
+  *ps = s;
+  return 0;
+}
+
+void RGWDNSResolver::put_state(res_state s)
+{
+  Mutex::Locker l(lock);
+  states.push_back(s);
+}
+
+
+int RGWDNSResolver::resolve_cname(const string& hostname, string& cname, bool *found)
+{
+  res_state res;
+
+  *found = false;
+
+  int r = get_state(&res);
+  if (r < 0) {
+    return r;
+  }
+
+  int ret;
+
+#define LARGE_ENOUGH_DNS_BUFSIZE 1024
+  unsigned char buf[LARGE_ENOUGH_DNS_BUFSIZE];
+
+#define MAX_FQDN_SIZE 255
+  char host[MAX_FQDN_SIZE + 1];
+  const char *origname = hostname.c_str();
+  unsigned char *pt, *answer;
+  unsigned char *answend;
+  int len = res_nquery(res, origname, C_IN, T_CNAME, buf, sizeof(buf));
+  if (len < 0) {
+    dout(20) << "res_query() failed" << dendl;
+    ret = 0;
+    goto done;
+  }
+
+  answer = buf;
+  pt = answer + sizeof(HEADER);
+  answend = answer + len;
+
+  /* read query */
+  if((len = dn_expand(answer, answend, pt, host, sizeof(host))) < 0) {
+    dout(0) << "ERROR: dn_expand() failed" << dendl;
+    ret = -EINVAL;
+    goto done;
+  }
+  pt += len;
+
+  if (pt + 4 > answend) {
+    dout(0) << "ERROR: bad reply" << dendl;
+    ret = -EIO;
+    goto done;
+  }
+
+  int type;
+  GETSHORT(type, pt);
+
+  if (type != T_CNAME) {
+    dout(0) << "ERROR: failed response type: type=%d (was expecting " << T_CNAME << ")" << dendl;
+    ret = -EIO;
+    goto done;
+  }
+
+  pt += INT16SZ; /* class */
+
+  /* read answer */
+
+  if((len = dn_expand(answer, answend, pt, host, sizeof(host))) < 0) {
+    ret = 0;
+    goto done;
+  }
+  pt += len;
+  dout(20) << "name=" << host << dendl;
+
+  if (pt + 10 > answend) {
+    dout(0) << "ERROR: bad reply" << dendl;
+    ret = -EIO;
+    goto done;
+  }
+
+  GETSHORT(type, pt);
+  pt += INT16SZ; /* class */
+  pt += INT32SZ; /* ttl */
+  pt += INT16SZ; /* size */
+
+  if((len = dn_expand(answer, answend, pt, host, sizeof(host))) < 0) {
+    ret = 0;
+    goto done;
+  }
+  dout(20) << "cname host=" << host << dendl;
+  cname = host;
+
+  *found = true;
+  ret = 0;
+done:
+  put_state(res);
+  return ret;
+}
+
+RGWResolver::~RGWResolver() {
+  delete resolver;
+}
+RGWResolver::RGWResolver() {
+  resolver = new RGWDNSResolver;
+}
+
+int RGWResolver::resolve_cname(const string& hostname, string& cname, bool *found) {
+  return resolver->resolve_cname(hostname, cname, found);
+};
+
+RGWResolver *rgw_resolver;
+
+
+void rgw_init_resolver()
+{
+  rgw_resolver = new RGWResolver();
+}
diff --git a/src/rgw/rgw_resolve.h b/src/rgw/rgw_resolve.h
new file mode 100644 (file)
index 0000000..164a31a
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef CEPH_RGW_RESOLVE_H
+#define CEPH_RGW_RESOLVE_H
+
+#include "rgw_common.h"
+
+class RGWDNSResolver;
+
+class RGWResolver {
+  RGWDNSResolver *resolver;
+
+  ~RGWResolver();
+public:
+  RGWResolver();
+  int resolve_cname(const string& hostname, string& cname, bool *found);
+};
+
+
+extern void rgw_init_resolver(void);
+extern RGWResolver *rgw_resolver;
+
+#endif
index 3612a9e67521d0d681c52786c9886020a7a8469f..e30778c4c20923a03f100139f19b9318cde24d6b 100644 (file)
@@ -15,6 +15,7 @@
 #include "rgw_formats.h"
 
 #include "rgw_client_io.h"
+#include "rgw_resolve.h"
 
 #define dout_subsys ceph_subsys_rgw
 
@@ -993,6 +994,20 @@ int RGWREST::preprocess(struct req_state *s, RGWClientIO *cio)
     ldout(s->cct, 10) << "host=" << s->host << " rgw_dns_name=" << g_conf->rgw_dns_name << dendl;
     pos = h.find(g_conf->rgw_dns_name);
 
+    if (g_conf->rgw_resolve_cname && pos < 0) {
+      string cname;
+      bool found;
+      int r = rgw_resolver->resolve_cname(h, cname, &found);
+      if (r < 0) {
+       dout(0) << "WARNING: rgw_resolver->resolve_cname() returned r=" << r << dendl;
+      }
+      if (found) {
+        dout(0) << "resolved host cname " << h << " -> " << cname << dendl;
+       h = cname;
+        pos = h.find(g_conf->rgw_dns_name);
+      }
+    }
+
     if (pos > 0 && h[pos - 1] == '.') {
       string encoded_bucket = "/";
       encoded_bucket.append(h.substr(0, pos-1));