HTTP X-Forwarded-For/Z39.50 Client-IP support
authorAdam Dickmeiss <adam@indexdata.dk>
Wed, 5 Mar 2014 17:22:23 +0000 (18:22 +0100)
committerAdam Dickmeiss <adam@indexdata.dk>
Wed, 5 Mar 2014 17:22:23 +0000 (18:22 +0100)
virt_db, multi: relays Z39.50 client-IP.
sru_z3950: converts X-Forwarded-For header to Z39.50 client-IP.
zoom: uses Client-IP or origin address (prefer Client-IP).
frontend_net: Strips tcp: from peer address (so that it is no longer
printed and stripped in zoom filter).
z3950_client: builds client-IP list - combining immediate peer address
as returned by COMSTACK and existing client-IP list (if avaiable).
The Origin only printes first X-Forwarded address.

include/metaproxy/origin.hpp
src/filter_frontend_net.cpp
src/filter_multi.cpp
src/filter_sru_to_z3950.cpp
src/filter_virt_db.cpp
src/filter_z3950_client.cpp
src/filter_zoom.cpp
src/origin.cpp

index f902a8a..d129e71 100644 (file)
@@ -57,6 +57,7 @@ namespace metaproxy_1 {
         unsigned int m_origin_id;
         int m_max_sockets;
         std::string m_custom_session;
+        std::string get_forward_address() const;
     };
 }
 
index a1e1c01..9313411 100644 (file)
@@ -277,6 +277,12 @@ yf::FrontendNet::ZAssocChild::ZAssocChild(
     const char *peername = PDU_Observable->getpeername();
     if (!peername)
         peername = "unknown";
+    else
+    {
+        const char *cp = strchr(peername, ':');
+        if (cp)
+            peername = cp + 1;
+    }
     m_origin.set_tcpip_address(std::string(peername), m_session.id());
     timeout(m_p->m_session_timeout);
 }
index 5f7d1b5..3b1d6f3 100644 (file)
@@ -35,6 +35,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include <yaz/otherinfo.h>
 #include <yaz/diagbib1.h>
 #include <yaz/match_glob.h>
+#include <yaz/oid_db.h>
 
 #include <vector>
 #include <algorithm>
@@ -444,6 +445,13 @@ void yf::Multi::Frontend::init(mp::Package &package, Z_GDU *gdu)
         *breq->preferredMessageSize = *req->preferredMessageSize;
         *breq->maximumRecordSize = *req->maximumRecordSize;
 
+
+        const char *peer_name = yaz_oi_get_string_oid(
+            &req->otherInfo, yaz_oid_userinfo_client_ip, 1, 0);
+        if (peer_name)
+            yaz_oi_set_string_oid(&breq->otherInfo, odr,
+                                  yaz_oid_userinfo_client_ip, 1, peer_name);
+
         ODR_MASK_SET(breq->options, Z_Options_search);
         ODR_MASK_SET(breq->options, Z_Options_present);
         ODR_MASK_SET(breq->options, Z_Options_namedResultSets);
index fa12345..26a6ad2 100644 (file)
@@ -30,6 +30,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include <yaz/pquery.h>
 #include <yaz/oid_db.h>
 #include <yaz/log.h>
+#include <yaz/otherinfo.h>
 #if YAZ_VERSIONL >= 0x50000
 #include <yaz/facet.h>
 #endif
@@ -518,6 +519,19 @@ yf::SRUtoZ3950::Impl::z3950_init_request(mp::Package &package,
         mp_util::set_vhost_otherinfo(&init_req->otherInfo, odr_en, host, 1);
     }
 
+    Z_GDU *zgdu_req = package.request().get();
+    if (zgdu_req->which == Z_GDU_HTTP_Request)
+    {
+        Z_HTTP_Request *hreq = zgdu_req->u.HTTP_Request;
+        const char *peer_name =
+            z_HTTP_header_lookup(hreq->headers, "X-Forwarded-For");
+        if (peer_name)
+        {
+            yaz_oi_set_string_oid(&init_req->otherInfo, odr_en,
+                                  yaz_oid_userinfo_client_ip, 1, peer_name);
+        }
+    }
+
     z3950_package.request() = apdu;
 
     // send Z3950 package
index 094bf08..6849917 100644 (file)
@@ -32,6 +32,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include <yaz/diagbib1.h>
 #include <yaz/match_glob.h>
 #include <yaz/log.h>
+#include <yaz/oid_db.h>
 
 #include <map>
 #include <iostream>
@@ -211,6 +212,13 @@ yf::VirtualDB::BackendPtr yf::VirtualDB::Frontend::init_backend(
     Z_GDU *org_gdu = m_init_gdu.get();
     Z_InitRequest *org_init = org_gdu->u.z3950->u.initRequest;
 
+
+    const char *peer_name = yaz_oi_get_string_oid(
+        &org_init->otherInfo, yaz_oid_userinfo_client_ip, 1, 0);
+    if (peer_name)
+        yaz_oi_set_string_oid(&init_apdu->u.initRequest->otherInfo, odr,
+                              yaz_oid_userinfo_client_ip, 1, peer_name);
+
     req->idAuthentication = org_init->idAuthentication;
     req->implementationId = org_init->implementationId;
     req->implementationName = org_init->implementationName;
index 12fcb8c..6ea58e4 100644 (file)
@@ -35,6 +35,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include <yaz/log.h>
 #include <yaz/otherinfo.h>
 #include <yaz/diagbib1.h>
+#include <yaz/oid_db.h>
 
 #include <yazpp/socket-manager.h>
 #include <yazpp/pdu-assoc.h>
@@ -486,6 +487,8 @@ void yf::Z3950Client::Rep::send_and_receive(Package &package,
     if (gdu->u.z3950->which == Z_APDU_close)
         c->m_has_closed = true;
 
+    Z_APDU *apdu = gdu->u.z3950;
+
     // prepare connect
     c->m_time_elapsed = 0;
     c->m_waiting = true;
@@ -510,7 +513,27 @@ void yf::Z3950Client::Rep::send_and_receive(Package &package,
     {
         return;
     }
-
+    const char *peer_name2 = package.origin().get_address().c_str();
+    mp::odr odr;
+    if (apdu->which == Z_APDU_initRequest && peer_name2)
+    {
+        Z_OtherInformation **oi = &apdu->u.initRequest->otherInfo;
+        char *peer_name1 =
+            yaz_oi_get_string_oid(oi, yaz_oid_userinfo_client_ip, 1, 1);
+        char *pcomb = (char *)
+            odr_malloc(odr, (peer_name1 ? strlen(peer_name1) : 0)
+                       + strlen(peer_name2) + 4);
+        strcpy(pcomb, "");
+        if (peer_name1)
+        {
+            strcat(pcomb, peer_name1);
+            strcat(pcomb, ", ");
+        }
+        strcat(pcomb, peer_name2);
+        yaz_oi_set_string_oid(&apdu->u.initRequest->otherInfo,
+                              odr, yaz_oid_userinfo_client_ip,
+                              1, pcomb);
+    }
     // prepare response
     c->m_time_elapsed = 0;
     c->m_waiting = true;
index 968b96b..2062b1c 100644 (file)
@@ -51,6 +51,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include <yaz/sortspec.h>
 #include <yaz/tokenizer.h>
 #include <yaz/zoom.h>
+#include <yaz/otherinfo.h>
 
 namespace mp = metaproxy_1;
 namespace yf = mp::filter;
@@ -2614,8 +2615,13 @@ void yf::Zoom::Frontend::auth(mp::Package &package, Z_InitRequest *req,
         }
     }
 
-    std::string ip = package.origin().get_address();
-    yaz_log(YLOG_LOG, "IP=%s", ip.c_str());
+    Z_OtherInformation **oi = &req->otherInfo;
+    const char *ip =
+        yaz_oi_get_string_oid(oi, yaz_oid_userinfo_client_ip, 1, 0);
+    if (!ip)
+        ip = package.origin().get_address().c_str();
+
+    yaz_log(YLOG_LOG, "IP=%s", ip);
 
     std::string torus_query;
     int failure_code;
@@ -2628,13 +2634,8 @@ void yf::Zoom::Frontend::auth(mp::Package &package, Z_InitRequest *req,
     }
     else
     {
-        const char *ip_cstr = ip.c_str();
-        const char *cp = strchr(ip_cstr, ':');
-        if (cp)
-            ip_cstr = cp + 1;
-
         torus_query = "ip encloses/net.ipaddress \"";
-        torus_query += escape_cql_term(std::string(ip_cstr));
+        torus_query += escape_cql_term(std::string(ip));
         torus_query += "\"";
         failure_code = YAZ_BIB1_INIT_AC_BLOCKED_NETWORK_ADDRESS;
     }
index 8f150b1..e4f9415 100644 (file)
@@ -18,7 +18,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 #include "config.hpp"
 #include <metaproxy/origin.hpp>
-
+#include <yaz/log.h>
 #include <iostream>
 
 namespace mp = metaproxy_1;
@@ -39,7 +39,15 @@ int mp::Origin::get_max_sockets()
 
 void mp::Origin::set_tcpip_address(std::string addr, unsigned long s)
 {
+    // assume first call is immediate reverse IP: cs_addrstr(COMSTACK)
+    // 2nd call might be X-Forwarded .. we use that for logging
+    std::string tmp = m_address;
     m_address = addr;
+    if (tmp.length())
+    {
+        m_address.append(" ");
+        m_address.append(tmp);
+    }
     m_origin_id = s;
 }
 
@@ -48,15 +56,33 @@ void mp::Origin::set_custom_session(const std::string &s)
     m_custom_session = s;
 }
 
+std::string mp::Origin::get_forward_address() const
+{
+    // return first component of address
+    // That's either first part of X-Forwarded component
+    size_t pos = m_address.find(' ');
+    if (pos != std::string::npos)
+        return m_address.substr(0, pos);
+    else
+        return m_address;
+}
+
 std::string mp::Origin::get_address()
 {
-    return m_address;
+    // return last component of address
+    size_t pos = m_address.rfind(' ');
+    if (pos != std::string::npos)
+        return m_address.substr(pos + 1);
+    else
+        return m_address;
 }
 
 std::ostream& std::operator<<(std::ostream& os, const mp::Origin& o)
 {
-    if (o.m_address.length())
-        os << o.m_address;
+    // print first component of address
+    std::string a = o.get_forward_address();
+    if (a.length())
+        os << a;
     else
         os << "0";
     os << ":" << o.m_origin_id;