Axios Unable to make request to IP address (Error: connect ECONNREFUSED) - node.js

I am trying to make a request to a 3rd party SOAP API, provided an IP address http://XXX.XXX.XXX.XXX:40871
I get the following error:
{
"success": false,
"error": "connect ECONNREFUSED XXX.XXX.XXX.XXX:40871",
"trace": "Error: connect ECONNREFUSED XXX.XXX.XXX.XXX:40871\n at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1187:16)"
}
while testing locally I edited my hosts file and provided a host name to the IP
XXX.XXX.XXX.XXX my-host-name.com
then made a request to http://my-host-name.com:40871 and successfully got a response.
I can not do this in production since we are using heroku to deploy our app.
Our app is a middleware to make requests to the 3rd party API since they requires a static IP in its whitelist. we create a axios instance and recieve further options in the request body.
const agent = new HttpsProxyAgent(process.env.STATIC_URL!);
const baseOptions: AxiosRequestConfig = {
proxy: false,
httpsAgent: agent,
};
const instance = axios.create(baseOptions);
const response = await instance(req.body);
res.send({ success: true, response: response.data });
here is the request body:
{
"method": "POST",
"baseURL": "http://XXX.XXX.XXX.XXX:40871",
"url": "/IDORequestService/IDOWebService.asmx",
"data": {{xmlBody}},
"headers": {
"Content-type": "text/xml",
"SOAPAction": "http://frontstep.com/IDOWebService/CreateSessionToken",
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate, br",
"Connection": "keep-alive"
}
}
Expected behavior: it should work with IP addresses
Environment:
Axios v0.27.2
https-proxy-agent: v5.0.1
Node.js v16.16.0
OS: Windows 11/Linux Mint 19.3

The problem was I did not have an httpAgent so it was not using the proxy for http requests, which is why the API server was probably refusing connection. Since it has the static IP in its whitelist and not our server IP.
const agent = new HttpsProxyAgent(process.env.STATIC_URL!);
const baseOptions: AxiosRequestConfig = {
proxy: false,
httpsAgent: agent,
httpAgent: agent,
};
const instance = axios.create(baseOptions);
const response = await instance(req.body);
res.send({ success: true, response: response.data });
adding the httpAgent fixed the issue.

Related

tunneling socket could not be established, EPROTO 139829749196736

I am facing the issue while calling Node js application from server, "Error: tunneling socket could not be established, cause=write EPROTO 139829749196736:error:1408F10B:SSL routines:ssl3_get_record:wrong version"
I used this code snippet below:
var options = {
'method': "POST",
'url': process.env.QATAPIPATH + process.env.APIPATH + parameter,
'headers': {
'Content-Type': 'application/json'
},
ignoreTLS: true,
secure: false,
body: JSON.stringify({
"data": req.body.data
})
};
The above SSL errors are thrown because the client is not able to verify the trust chain of the self-signed server certificate
The easiest solution to resolve these errors is to use the “rejectUnauthorized”
> https.request({
> ....,
> rejectUnauthorized: false,
> }, ...)
or set it as an environment variable
NODE_TLS_REJECT_UNAUTHORIZED=0
for Linux
export NODE_TLS_REJECT_UNAUTHORIZED=0

Axios - Getting socket hang up error while running it on docker container

I am trying to get results from third party API by using Axios npm. Using nested request, first request is to get the token and another one is to get results.
Below code is working fine in my local machine but not in Docker container.
var config = {
method: 'post',
url: gsecConfig.tokenUrl,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: data
};
axios(config)
.then(function (response) {
if (response.data.access_token) {
const config = {
headers: { Accept: 'application/json', Authorization: `Bearer ${response.data.access_token}` }
};
axios.get(gsecConfig.gsecUrl + gsecid, config)
.then(function (response) {
let supplierData = response.data;
res.status(200).json({
"data": supplierData
});
}).catch(function (error) {
res.json({
"errors": error.message,
"name": error.name
});
});
}
})
.catch(function (tokenError) {
if (tokenError) {
res.json({
"errors": tokenError.message,
"name": tokenError.name
});
}
});
});
Getting error like below
"message": "socket hang up",
"name": "Error",
"stack": "Error: socket hang up\n at createHangUpError (_http_client.js:323:15)\n at Socket.socketOnEnd (_http_client.js:426:23)\n at Socket.emit (events.js:203:15)\n at endReadableNT (_stream_readable.js:1129:12)\n at process._tickCallback (internal/process/next_tick.js:63:19)",
"code": "ECONNRESET"
Thanks in advance!
If your server is not Kubernetes, you can change the publish mode to host (default is ingress), the problem will be solved. check this
You can change it in docker-stack like below:
ports:
- target: 3001
published: 3001
protocol: tcp
mode: host
But if this is Kubernetes with node clusters, you should use the ingress mode, I'm facing this issue and still stuck here. Hope someone can help.

Nest js - httpservice add proxy

I have the next proxy configuration (I just tested it in postman and its working)
host: 'http://tsl.proxyurl.com/standard.pac', port: 8080, protocol: https, no username, no password.
And this is my code:
const options = {
data,
'proxy': {
host: 'http://tsl.proxyurl.com/standard.pac',
port: 8080
},
'headers': {
'Authorization': `Basic ${base64Auth}`,
'Content-Type': 'application/x-www-form-urlencoded',
},
};
const endpoint = `https://api.myrurl.com/st/token`;
const response = await this.httpService.post(endpoint, data, options).toPromise();
But every time, I try, I get:
message:'Client network socket disconnected before secure TLS
connection was established'
Someone had a similar issue? How can I fix it?

One signal create notification REST API fails sometimes

I am using oneSignal for push notifications node.js. I am using the create notification api to send notification to the users, but i dont know why it works some times and sometimes gives timeout error
sendNotificationToUser(data) {
try {
var notificationData = {}
notificationData.app_id = oneSignalAppId
notificationData.headings = {
en: "Heading"
}
notificationData.contents = {
en: data.message
}
notificationData.include_player_ids = [data.deviceId]
var headers = {
"Content-Type": "application/json; charset=utf-8"
}
var options = {
host: "onesignal.com",
port: 443,
path: "/api/v1/notifications",
method: "POST",
headers: headers
}
var https = require("https")
var req = https.request(options, function (res) {
res.on("data", function (data1) {
console.log("Response:")
console.log(JSON.parse(data1))
})
})
req.on("error", function (e) {
console.log("ERROR:")
console.log(e)
})
req.write(JSON.stringify(notificationData))
req.end()
} catch (err) {
console.log("err in notification", err)
}
}
this api works 50% of times and 50% of times it responds with time out error, even all the inputs are correct
ERROR:
{
Error: connect ETIMEDOUT 104.18.225.52:443
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1107:14)
errno: 'ETIMEDOUT',
code: 'ETIMEDOUT',
syscall: 'connect',
address: '104.18.225.52',
port: 443
}
one simple solution is to directly hit the working ip, you can do this by including
host: 'onesignal.con' in headers and
host: '104.18.226.52' in options
this resolved my issue
to know more about how you can specify ip with host in https request
go here HTTPS request, specifying hostname and specific IP address

Ignore invalid self-signed ssl certificate in node.js with https.request?

I'm working on a little app that logs into my local wireless router (Linksys) but I'm running into a problem with the router's self-signed ssl certificate.
I ran wget 192.168.1.1 and get:
ERROR: cannot verify 192.168.1.1's certificate, issued by `/C=US/ST=California/L=Irvine/O=Cisco-Linksys, LLC/OU=Division/CN=Linksys/emailAddress=support#linksys.com':
Self-signed certificate encountered.
ERROR: certificate common name `Linksys' doesn't match requested host name `192.168.1.1'.
To connect to 192.168.1.1 insecurely, use `--no-check-certificate'.
In node, the error being caught is:
{ [Error: socket hang up] code: 'ECONNRESET' }
My current sample code is:
var req = https.request({
host: '192.168.1.1',
port: 443,
path: '/',
method: 'GET'
}, function(res){
var body = [];
res.on('data', function(data){
body.push(data);
});
res.on('end', function(){
console.log( body.join('') );
});
});
req.end();
req.on('error', function(err){
console.log(err);
});
How can I go about getting node.js to do the equivalent of "--no-check-certificate"?
Cheap and insecure answer:
Add
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
in code, before calling https.request()
A more secure way (the solution above makes the whole node process insecure) is answered in this question
In your request options, try including the following:
var req = https.request({
host: '192.168.1.1',
port: 443,
path: '/',
method: 'GET',
rejectUnauthorized: false,
requestCert: true,
agent: false
},
Don't believe all those who try to mislead you.
In your request, just add:
ca: [fs.readFileSync([certificate path], {encoding: 'utf-8'})]
If you turn on unauthorized certificates, you will not be protected at all (exposed to MITM for not validating identity), and working without SSL won't be a big difference. The solution is to specify the CA certificate that you expect as shown in the next snippet. Make sure that the common name of the certificate is identical to the address you called in the request(As specified in the host):
What you will get then is:
var req = https.request({
host: '192.168.1.1',
port: 443,
path: '/',
ca: [fs.readFileSync([certificate path], {encoding: 'utf-8'})],
method: 'GET',
rejectUnauthorized: true,
requestCert: true,
agent: false
},
Please read this article (disclosure: blog post written by this answer's author) here in order to understand:
How CA Certificates work
How to generate CA Certs for testing easily in order to simulate production environment
Add the following environment variable:
NODE_TLS_REJECT_UNAUTHORIZED=0
e.g. with export:
export NODE_TLS_REJECT_UNAUTHORIZED=0
(with great thanks to Juanra)
Adding to #Armand answer:
Add the following environment variable:
NODE_TLS_REJECT_UNAUTHORIZED=0 e.g. with export:
export NODE_TLS_REJECT_UNAUTHORIZED=0 (with great thanks to Juanra)
If you on windows usage:
set NODE_TLS_REJECT_UNAUTHORIZED=0
Thanks to: #weagle08
You can also create a request instance with default options:
require('request').defaults({ rejectUnauthorized: false })
For meteorJS you can set with npmRequestOptions.
HTTP.post(url, {
npmRequestOptions: {
rejectUnauthorized: false // TODO remove when deploy
},
timeout: 30000, // 30s
data: xml
}, function(error, result) {
console.log('error: ' + error);
console.log('resultXml: ' + result);
});
try
export NODE_TLS_REJECT_UNAUTHORIZED=0
Or you can try to add in local name resolution (hosts file found in the directory etc in most operating systems, details differ) something like this:
192.168.1.1 Linksys
and next
var req = https.request({
host: 'Linksys',
port: 443,
path: '/',
method: 'GET'
...
will work.
So, my company just switched to Node.js v12.x.
I was using NODE_TLS_REJECT_UNAUTHORIZED, and it stopped working.
After some digging, I started using NODE_EXTRA_CA_CERTS=A_FILE_IN_OUR_PROJECT that has a PEM format of our self signed cert and all my scripts are working again.
So, if your project has self signed certs, perhaps this env var will help you.
Ref: https://nodejs.org/api/cli.html#cli_node_extra_ca_certs_file
In case you are looking for posting using #nestjs/axios,
here is the syntax without certificate (Non Production Solution):
const token = Buffer.from(`${user}:${password}`,'utf8').toString('base64')
const config = {
headers: {
'Content-Type': 'application/json',
Authorization: `Basic ${token}`,
},
httpsAgent: new https.Agent({
rejectUnauthorized: false
}),
};
const responseData = await firstValueFrom(
this.httpService.post(url, data, config).pipe(map((response) => response.data)),
);
here is the syntax with certificate (Production Solution):
const token = Buffer.from(`${user}:${password}`,'utf8').toString('base64')
const config = {
headers: {
'Content-Type': 'application/json',
Authorization: `Basic ${token}`,
},
httpsAgent: new https.Agent({
rejectUnauthorized: true,
ca: fs.readFileSync(path.join(__dirname, './resources/certificateName'))
}),
};
const responseData = await firstValueFrom(
this.httpService.post(url, data, config).pipe(map((response) => response.data)),
);
When you cannot control the request creation
When using packages you sometimes don't have the option to set the correct settings on the request call, nor does the package offer you a way to inject a request.
However you might still want to avoid the insecure NODE_TLS_REJECT_UNAUTHORIZED=0 and opt for only having an insecure connection to a specified target.
This is how I solved the issue:
// check if host and port fit your application
function isSelf(host, port) {
return host === myHost && port === myPort;
}
// get the built in tls module and overwrite the default connect behavior
const tls = require("tls");
const _connect = tls.connect;
function wrappedConnect(options, secureConnectListener) {
if (isSelf(options.host, options.port)) {
options.rejectUnauthorized = false;
}
return _connect(options, secureConnectListener);
}
tls.connect = wrappedConnect;

Resources