mn Stoner
mn Stoner

Reputation: 77

How do I get a client's IP address from inside a soap service?(nodejs)

I am written a soapService using the soap package, I'm passing an express server to it.

The problem is that the server can get requests from 2 different network interfaces, and I want which one the request came from.

My solution is to get client's IP and determine which interface it came from using

require("os").NetworkInterfaces()

but I couldn't find how to get a client's IP

I tried: this.req.ip, this.httpHeaders["x-forwarded-for"] || this.req.connection.remoteAddres but it comes as undefined

Edit: I want to add a minimal example for testing.

3 files are created: soapserver.js (that includes the soap service where I want to get the ip from inside of it) client.js (to call the soapservice) check_username.wsdl (used to create the service)

soapserver.js:

var soap = require('soap');
var http = require('http');
const util = require('util');
const app = require("express")()

var myService = {
    CheckUserName_Service: {
        CheckUserName_Port: {
            checkUserName: function(args, soapCallback) { 
                console.log('checkUserName: Entering function..');
                console.log(args);
                /*
                 * Where I'm trying to get clietn's IP address
                 */
                soapCallback("{'username found'}");
            }
        }
    }   
};


var xml = require('fs').readFileSync('check_username.wsdl', 'utf8');
var server = require("http").Server(app);    
app.get('/', (req, res) => {
    res.send("Hello World!");
    console.log(req);
    console.log(req.connection.remoteAddress);
    console.log(req.ip);
});

var port = 8000;
server.listen(port);

var soapServer = soap.listen(server, '/test', myService, xml);
soapServer.log = function(type, data) {
    console.log('Type: ' + type + ' data: ' + data);
};

console.log('SOAP service listening on port ' + port);

client.js:

"use strict";

var soap = require('strong-soap').soap;
var url = 'http://localhost:8000/test?wsdl';

var options = { endpoint: 'http://localhost:8000/test'};
var requestArgs = { userName: "TEST_USER" };
soap.createClient(url, options, function(err, client) {
  if (err) {
      console.error("An error has occurred creating SOAP client: " , err);  
  } else {
      var description = client.describe();
      console.log("Client description:" , description);
      var method = client.checkUserName;
      method(requestArgs, function(err, result, envelope, soapHeader) {
        //response envelope
        console.log('Response Envelope: \n' + envelope);
        //'result' is the response body
        console.log('Result: \n' + JSON.stringify(result));
      });
  }
});

check_username.wsdl

<definitions name = "CheckUserNameService"
   targetNamespace = "http://www.examples.com/wsdl/CheckUserNameService.wsdl"
   xmlns = "http://schemas.xmlsoap.org/wsdl/"
   xmlns:soap = "http://schemas.xmlsoap.org/wsdl/soap/"
   xmlns:tns = "http://www.examples.com/wsdl/CheckUserNameService.wsdl"
   xmlns:xsd = "http://www.w3.org/2001/XMLSchema">

   <message name = "CheckUserNameRequest">
      <part name = "userName" type = "xsd:string"/>
   </message>
   <message name = "CheckUserNameResponse">
      <part name = "status" type = "xsd:string"/>
   </message>
   <portType name = "CheckUserName_PortType">
      <operation name = "checkUserName">
         <input message = "tns:CheckUserNameRequest"/>
         <output message = "tns:CheckUserNameResponse"/>
      </operation>
   </portType>

   <binding name = "CheckUserName_Binding" type = "tns:CheckUserName_PortType">
      <soap:binding style = "rpc"
         transport = "http://schemas.xmlsoap.org/soap/http"/>
      <operation name = "checkUserName">
         <soap:operation soapAction = "checkUserName"/>
         <input>
            <soap:body encodingStyle = "http://schemas.xmlsoap.org/soap/encoding/" namespace = "urn:examples:CheckUserNameService" use = "encoded"/>
         </input>
         <output>
            <soap:body encodingStyle = "http://schemas.xmlsoap.org/soap/encoding/" namespace = "urn:examples:CheckUserNameService" use = "encoded"/>
         </output>
      </operation>
   </binding>

   <service name = "CheckUserName_Service">
      <documentation>WSDL File for CheckUserNameService</documentation>
      <port binding = "tns:CheckUserName_Binding" name = "CheckUserName_Port">
         <soap:address
            location = "http://www.examples.com/CheckUserName/" />
      </port>
   </service>
</definitions>

Upvotes: 0

Views: 494

Answers (2)

mn Stoner
mn Stoner

Reputation: 77

I found a solution that works for my case and probably would be of use for someone wanting to do something similar.

I have 2 potential solutions:

1/ I modified 'node-soap' package, in server.js I passed the IP (from req Object) to _process than have it included in argument that are going to be passed obj.Body[methodName]["ip"] = ip;

2/ The goal was to find which network interface is coming from, so the second solution involves binding the server to only one interface (instead of 0.0.0.0) and have one server by interface.

I went with the former in my case.

Upvotes: 0

Jishan Shaikh
Jishan Shaikh

Reputation: 1806

There you go, the code. Working on Localhost as well as remoteProd (cloud hosted).

Edit: Code now tested and modified for remote client IPs as well.

server.js

var soap = require('soap');
var http = require('http');
const util = require('util');
const fetch = require('node-fetch');
const app = require("express")()
var myService;

newApp = app;
var server = http.Server(app);
var port = 8000;
server.listen(port);
console.log("http server started listtening on " + port);

newApp.get('/', (req, res) => {
    res.send("Hello World!");
    var clientIP = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
    //console.log(req.connection.remoteAddress); // will always give server ip on remote connections
    myService = {
        CheckUserName_Service: {
            CheckUserName_Port: {
                checkUserName: function (args, soapCallback) {
                    console.log('checkUserName: Entering function..');
                    console.log(args);
                    //console.log(this.request.connection.remoteAddress)
                    /*
                     * Where I'm trying to get clietn's IP address
                     */
                    console.log("***")
                    console.log("IP of client: " + clientIP);
                    console.log("***")
                    //console.log(request.connection.remoteAddress);
                    // res = this.request.connection.remoteAddress;
                    //console.log(args)
                    soapCallback("{'username found'}");
                }
            }
        }
    };
    var xml = require('fs').readFileSync('myservice.wsdl', 'utf8');


    var soapServer = soap.listen(server, '/test', myService, xml);
    soapServer.log = function (type, data) {
        console.log('Type: ' + type + ' data: ' + data);
    };
    console.log('SOAP service listening on port ' + port);
});

// Need first request to boot up soapservice
fetch('http://localhost:8000/', {
        method: 'GET'
    })
    .then((response) => {
        console.log("fetch then + first from server");
    })
    .catch((error) => {
        console.log("fetch error + first from server: " + error);
    })

client.js

"use strict";

var soap = require('strong-soap').soap;
var fetch = require('node-fetch');
var url = 'http://localhost:8000/test?wsdl';

var options = {
    endpoint: 'http://localhost:8000/test'
};
var requestArgs = {
    userName: "TEST_USER"
};

// If you comment out this request, server will log server's IP (first fetch)
fetch('http://localhost:8000/', {
        method: 'GET'
    })
    .then((response) => {
        console.log("fetch then from client");
    })
    .catch((error) => {
        console.log("fetch error from client: " + error);
    })

soap.createClient(url, options, function (err, client) {
    if (err) {
        console.error("An error has occurred creating SOAP client: ", err);
    } else {
        var description = client.describe();
        console.log("Client description:", description);
        var method = client.checkUserName;
        method(requestArgs, function (err, result, envelope, soapHeader) {
            console.log('Result: \n' + JSON.stringify(result));
        });
    }
});

myservice.wsdl: Notice that I renamed it, idk why.

<definitions name = "CheckUserNameService"
   targetNamespace = "http://www.examples.com/wsdl/CheckUserNameService.wsdl"
   xmlns = "http://schemas.xmlsoap.org/wsdl/"
   xmlns:soap = "http://schemas.xmlsoap.org/wsdl/soap/"
   xmlns:tns = "http://www.examples.com/wsdl/CheckUserNameService.wsdl"
   xmlns:xsd = "http://www.w3.org/2001/XMLSchema">

   <message name = "CheckUserNameRequest">
      <part name = "userName" type = "xsd:string"/>
   </message>
   <message name = "CheckUserNameResponse">
      <part name = "status" type = "xsd:string"/>
   </message>
   <portType name = "CheckUserName_PortType">
      <operation name = "checkUserName">
         <input message = "tns:CheckUserNameRequest"/>
         <output message = "tns:CheckUserNameResponse"/>
      </operation>
   </portType>

   <binding name = "CheckUserName_Binding" type = "tns:CheckUserName_PortType">
      <soap:binding style = "rpc"
         transport = "http://schemas.xmlsoap.org/soap/http"/>
      <operation name = "checkUserName">
         <soap:operation soapAction = "checkUserName"/>
         <input>
            <soap:body encodingStyle = "http://schemas.xmlsoap.org/soap/encoding/" namespace = "urn:examples:CheckUserNameService" use = "encoded"/>
         </input>
         <output>
            <soap:body encodingStyle = "http://schemas.xmlsoap.org/soap/encoding/" namespace = "urn:examples:CheckUserNameService" use = "encoded"/>
         </output>
      </operation>
   </binding>

   <service name = "CheckUserName_Service">
      <documentation>WSDL File for CheckUserNameService</documentation>
      <port binding = "tns:CheckUserName_Binding" name = "CheckUserName_Port">
         <soap:address
            location = "http://www.examples.com/CheckUserName/" />
      </port>
   </service>
</definitions>

Upvotes: 0

Related Questions