The rampart-net module¶
Preface¶
Acknowledgment¶
The rampart-net module makes extensive use of the libevent2 library embedded in the main rampart executable as well as the OpenSSL library, imported from the rampart-crypto module.
License¶
The rampart-net module is released under the MIT license.
What does it do?¶
The rampart-net module allows the creation of network connections and servers in a manner similar to (but with significant differences from) the node.js net module.
All of the callback functions in rampart-net are asynchronously executed in rampart’s event loop unless stated otherwise.
All functions return their parent object, for chainability, unless otherwise stated.
Loading and Using the Module¶
Loading¶
Loading the module is a simple matter of using the require()
function:
var net = require("rampart-net");
Socket Functions¶
new net.Socket()¶
In order to make a tcp connection to a server, a new Socket object must be created. The
new net.Socket()
statement returns functions to connect and communicate over tcp, with or without ssl/tls.Usage:
var net = require("rampart-net"); var socket = new net.Socket();
- Return Value:
- An object with the below listed function.
socket.connect()¶
Make a new tcp connection.
Usage:
var net = require("rampart-net"); var socket = new net.Socket(); socket.connect(options[, connect_callback]); /* or */ socket.connect(port[, host][, options][, connect_callback]);Where:
port
- Required. The port of the server to which a connection will be attempted.
host
- The hostname or ip address of the server. Default is127.0.0.1
.
connect_callback
is a callback Function` which is run after a connection is established and the “connect” event is emitted.
options
is an Object with the following optional properties:
host
- The hostname or ip address of the server. Default is127.0.0.1
.port
- Required. A Number. The port of the server to which a connection will be attempted.timeout
- How long in milliseconds before a connection is terminated for inactivity (both read and write). Default is forever.family
- A Number. Must be0
(the default),4
or6
to specify any ip family, ipv4 only or ipv6 only respectively. May be used ifhost
above resolves to both ipv4 and ipv6 addresses to force the use of a particular one.keepalive
- A Boolean. Iftrue
set tcp keepalive on the connection. Packets will be transparently sent to the server to aid in keeping the connection alive (should it be necessary). See this document for more information. Default isfalse
.keepAliveInitialDelay
- A Number. How many seconds to wait before sending the first keepalive packet. Has no effect unlesskeepalive
above istrue
. Default is1
.keepAliveInterval
- A Number. How many seconds between sending keepalive packets. Has no effect unlesskeepalive
above istrue
. Default is1
.keepAliveCount
- A Number. How many keepalive packets should be sent with no reply before disconnecting. Has no effect unlesskeepalive
above istrue
. Default is10
.tls
- A Boolean. Whether to use SSL/TLS for the connection. Default isfalse
.ssl
- Same astls
. If both set,ssl
is ignored.insecure
- A Boolean. Whether to skip verification of the server’s credentials when making a connection over SSL/TLS. The default isfalse
(i.e. check credentials and fail the connection if the server’s credentials are not verified).cacert
- A String. The path to the CA certificate store file, required to verify the server when using SSL/TLS. The default is system dependent (usually/etc/ssl/cert.pem
on MacOS or/etc/ssl/certs/ca-certificates.crt
on Linux).capath
- A String. The path to the CA directory. CA certificates need to be stored as individual PEM files in this directory. No Default.hostname
- A String. Name to use to verify the server if different than provided inhost
above or ifhost
is a numeric ip address. No Default.
socket.write()¶
Write data to the server. The parameter can be a String or a Buffer.
var net = require("rampart-net"); var socket = new net.Socket(); function mycallback(){ // now connected, so we can write to server socket.write("hello world"); } socket.on("connect", mycallback); socket.connect(port, host);
socket.on()¶
Register a callback Function to be run when an event on
socket
is emitted.Usage:
var net = require("rampart-net"); var socket = new net.Socket(); socket.on(event, callback);Where:
event
is one of the following possible events for a socket:
connect
- emitted after a connection has been established.data
- emitted after data has been received on the socket. The provided function takes one argument, the data received in a Buffer.ready
- For compatibility. Emitted immediately after “connect”.drain
- emitted when data has been written.end
- emitted when disconnected by the server. Note: “close” below will also be emitted.timeout
- emitted if the connection exceeds the provided timeout interval. Note: “close” below will also be emitted.close
- emitted whenever a connection is terminated.error
- emitted upon error. Note: if no error callback is registered for a socket, rampart will throw an error instead.
callback
is a function. Iferror
, function will have its first parameter be the error object/message. Ifdata
, function will have its first parameter be the received data in a Buffer.
socket.off()¶
Unregister a callback Function previously registered with
socket.on
. Function must be a named function.Usage example:
var net = require("rampart-net"); var socket = new net.Socket(); function mycallback(){ ... } function finishcb(){ this.off("connect", mycallback); this.off("close", finishcb); } socket.on("connect", mycallback); ... socket.on("close", finishcb);
socket.once()¶
Same as
socket.on
, except the event will be removed after being called once. This is equivalent to calling off at the beginning of a callback, except with once, the function may be anonymous (unnamed).Example:
var net = require("rampart-net"); var socket = new net.Socket(); /* with on() function mycallback(){ // 'socket' and 'this' are the same socket.off("connect", mycallback); ... } socket.on("connect", mycallback); */ /* with once */ socket.once("connect", function(){ ... });
socket.destroy()¶
Close the connection to server. The “close” event is emitted upon the actual disconnect.
socket.setTimeout()¶
Set a timeout and optional timeout event callback. This is a shortcut for setting timeout value (in milliseconds) in
socket.connect
and a callback usingsocket.on("timeout", mytimeoutfunc)
.Usage example:
var net = require("rampart-net"); var socket = new net.Socket(); function timedout(){ console.log("connection timed out"); } socket.setTimeout(5000, timedout); // five seconds
socket.setKeepAlive()¶
Set keepalive on or off, or adjust settings at any point while the socket is connected.
Usage:
socket.setKeepAlive(enable[, initialDelay[, interval[, count]]]);Where
enable
is a Boolean and the optional parameters are the same as in socket.connect().
socket.trigger()¶
Trigger functions registered with socket.on() for a named event.
Usage:
socket.trigger(event[, argument]);Where
event
is a String, the name of an event registered with socket.on(), andargument
is optionally an argument to pass to the registered callbacks for the event.Arbitarty events can be registered with socket.on(), and then called with this function.
socket.bytesWritten¶
A Number - the number of bytes written to the server for the current connection.
socket.bytesRead¶
A Number - the number of bytes read from the server for the current connection.
Other socket properties¶
The
socket
Object may include these possible status properties:
connecting
- Boolean. Whether the connection has been initiated, but not yet established.connected
- Boolean. Whether the connection has been established.tsl
- Boolean. Whether this is a secure connection.destroyed
- Boolean. Whether this connection has been closed or destroyed.pending
- Boolean. Whether a connection has not yet been attempted.true
beforeconnect
is called and afterclose
and/orend
event.false
after connection is established.readyState
- String. “open” when connected, “opening” aftersocket.connect()
is called andundefined
after close or beforesocket.connect()
is called._events
- Object. Registered callbacks for events.timeout
- Number. Timeout value, if set.remoteAddress
- String. IP address of the connected remote peer.remotePort
- Number. Port of the connected remote peer.remoteFamily
- String. IP version used for connection (ipv4
oripv6
)._hostPort
- Number. Same asremotePort
_hostAddrs
- Object. Host address used for this connection returned from a call to new net.Resolver() by socket.connect() internally.sslCipher
- String. Iftls
is true, the name of the openssl cipher being used for this connection.
Socket Full Example¶
/* simulate a https request to google.com */
rampart.globalize(rampart.utils);
var net = require('rampart-net');
var socket = new net.Socket();
socket.on("connect", function(){
console.log("CONNECTED");
this.write("GET / HTTP/1.0\r\nHost: google.com\r\n\r\n");
});
socket.on("ready", function(){
console.log("READY");
});
// http 1.0, server should disconnect us.
socket.on('end', function() {
console.log("END EVENT");;
});
/* just to demonstrate multiple callbacks */
socket.on('data', function(data) {
printf("\nlength=%d\n",data.length);
});
socket.on('data', function(data) {
printf("\ncontent:\n%s\n",data);
});
socket.on('close', function() {
printf("Close - written: %s, read: %s\n", this.bytesWritten, this.bytesRead);
});
socket.on('error', function(err) {
console.log("ERROR:", err);
});
socket.on('timeout', function(){
console.log("TIMEOUT")
});
socket.setTimeout(1000);
// now actually connect
socket.connect({
host: "google.com",
port: 443,
tls: true
});
/* end of script, event loop started, connection made, callbacks executed */
/*
Expected results:
CONNECTED
READY
length=703
content:
HTTP/1.0 301 Moved Permanently
Location: https://www.google.com/
Content-Type: text/html; charset=UTF-8
Date: Thu, 07 Jul 2022 06:19:02 GMT
Expires: Sat, 06 Aug 2022 06:19:02 GMT
Cache-Control: public, max-age=2592000
Server: gws
Content-Length: 220
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="https://www.google.com/">here</A>.
</BODY></HTML>
END EVENT
Close - written: 36, read: 703
*/
Server Functions¶
new net.Server()¶
In order to listen for tcp connections from clients, a new Server object must be created. The
new net.Server()
statement returns functions to listen and create sockets to communicate over tcp, with or without ssl/tls.Usage:
var net = require("rampart-net"); var server = new net.Server([options ][,connection_callback]);Where:
options
is an Object of options:
tls
- AKAsecure
- a Boolean - Whether to serve using ssl/tls. Default isfalse
. Iftrue
, thesslKeyFile
andsslCertFile
parameters must also be set.sslKeyFile
: A String, the location of the ssl key file for serving over ssl/tls. An example, if using letsencrypt for “example.com” might be"/etc/letsencrypt/live/example.com/privkey.pem"
. This setting has no effect unlesstls
orsecure
istrue
.sslCertFile
: A String, the location of the ssl cert file for serving over ssl/tls. An example, if using letsencrypt for “example.com” might be"/etc/letsencrypt/live/example.com/fullchain.pem"
. This setting has no effect unlesstls
orsecure
istrue
.sslMinVersion
: A String, the minimum SSL/TLS version to use. Possible values aressl3
,tls1
,tls1.1
ortls1.2
. The default istls1.2
. This setting has no effect unlesstls
orsecure
istrue
.
connection_callback
- a Function - a callback executed when theconnection
event is emitted (when the server accepts a new connection). The “connection” event calls registered functions with a single parameter (thesocket
object, representing the socket connection to the client).
- Return Value:
- An object with the below listed function.
server.listen()¶
Set server to listen on the given port, and optionally ip addresses.
Usage:
var net = require("rampart-net"); var server = new net.Server([ [options ][,connection_callback]]); server.listen(port[, host[, backlog]][, listen_callback]); /* or */ server.listen(options[, listen_callback]);Where:
port
- A Number. The port upon which to listen. Required.
host
- A String or Array of Strings. Hosts and/or IP addresses to bind. Default is"any"
If unset or set to"any"
, it will bind all available IPV4 and IPV6 addresses.
backlog
- A Number. The maximum length of the queue of pending connections. Default is511
.
listen_callback
- A Function. A function to be executed when the “listening” event is emitted (when server starts listening).
options
- An Object with the following properties:
port
- Same as above.host
- Same as above.backlog
- Same as above.maxConnections
- Same as server.maxConnections() below.family
- A Number. Must be0
(the default),4
or6
to specify any ip family, ipv4 only or ipv6 only respectively. May be used ifhost
above resolves to both ipv4 and ipv6 addresses to force the use of a particular one.
server.on()¶
Register a callback Function to be run when an event on
server
is emitted.Usage:
var net = require("rampart-net"); var server = new net.Server(); server.on(event, callback);Where:
event
is one of the following possible events for a socket:
connection
- emitted after a new connection has been established. The callback is provided asocket
object, connected to the client.listening
- emitted after server has binds to the given port and is ready to accept connection.close
- emitted when the server is terminated.error
- emitted upon error. Note: if no error callback is registered for the server, rampart will throw an error instead.
callback
is a function. Iferror
, function will have its first parameter be the error object/message. Ifdata
, function will have its first parameter be the received data in a Buffer.
server.off()¶
Unregister a callback Function previously registered withserver.on
. Function must be a named function.
server.once()¶
Same asserver.on
, except the event will be removed after being called once. This is equivalent to calling off at the beginning of the callback, except withonce
, the function may be anonymous (unnamed). See example for socket.once().
server.connectionCount()¶
Get the number of connected clients.
- Return Value:
- A Number, the number of connected clients.
server.maxConnections()¶
Set the maximum number of connections concurrently connected. The server will drop new connections if this number is reached. This function can be called at any time to set or adjust the connection limit.
Usage:
var net = require("rampart-net"); var server = new net.Server(); server.maxConnections([max]);Where
max
is a Number, the maximum allowed connections. Default is0
(meaning no max) if no value is provided. Setting to a number greater than 4,294,967,295 or less than 0 is equivalent to setting0
. Actual system maximum number of connections varies by platform and settings.
Other server properties¶
The
server
Object may include these possible status properties:
listening
- Boolean. Whether the connection has been initiated, but not yet established._events
- Object. Registered callbacks for events.tsl
- Boolean. Whether server accepts secure connections.sslKeyFile
- String. The SSL/TLS key file, if providedsslCertFil
- String. The SSL/TLS cert file, if provided.maxConnections
- Number.maxConnections
value, if set._hostAddrs
- Array of Objects. Host addresses that the server is listening on as returned from a call to resolver.resolve() by server.listen() internally._hostPort
- Number. The port used by the server.backlog
- Number.backlog
value, if set, or the default of511
.
Server Full Example¶
/* Simulate an https server, return request headers as text */ rampart.globalize(rampart.utils); var net = require('rampart-net'); var cert = "/etc/letsencrypt/live/example.com/fullchain.pem"; var key = "/etc/letsencrypt/live/example.com/privkey.pem"; var nc=0; var server = new net.Server( { "secure":true, sslKeyFile:key, sslCertFile:cert }, function(socket) { console.log("CONNECTED"); /* assuming all request data will be provided in a single callback */ socket.on('data', function(data){ var ind = bufferToString(data); printf("connection %s, open connections %s\n", ++nc, server.connectionCount()); socket.write( "HTTP/1.0 200 OK\r\n" + "Content-type: text/plain\r\n" + "Content-Length: " + ind.length + "\r\n\r\n" ); socket.write(ind); socket.destroy(); }) .on('end', function(){ console.log("peer ended connection ", this.remoteAddress); }) .on('error', console.log ) .on('close', function(){ console.log("closed connection to ", this.remoteAddress); }); } ); server.maxConnections(1200); server.on("error", function (err) { console.log("server err:",err); }) .on("close", function () { console.log("server closed"); }) .on("listening", function(){ printf("LISTENING. server properties:\n%3J\n", this); }) .listen({ port: 8888, maxConnections: 1200 }); /* Output upon Start: LISTENING. server properties: { "listening": true, "_events": { "connection": {}, "error": {}, "close": {}, "listening": {} }, "sslKeyFile": "/etc/letsencrypt/live/example.com/fullchain.pem", "sslCertFile": "/etc/letsencrypt/live/example.com/privkey.pem", "tls": true, "maxConnections": 1200, "_hostAddrs": [ { "host": "0.0.0.0", "ip4addrs": [ "0.0.0.0" ], "ip6addrs": [], "ipaddrs": [ "0.0.0.0" ], "canonName": "0.0.0.0", "ip": "0.0.0.0", "ipv4": "0.0.0.0" }, { "host": "::", "ip4addrs": [], "ip6addrs": [ "::" ], "ipaddrs": [ "::" ], "canonName": "::", "ip": "::", "ipv6": "::" } ], "_hostPort": 8888, "backlog": 511 } Request: curl https://example.com:8888/ GET / HTTP/1.1 Host: example.com:8888 User-Agent: curl/7.58.0 Accept: * /* Output after request: CONNECTED connection 1, open connections 1 closed connection to 2001:db8::1 */
Resolve functions¶
The following functions are used to resolve a host name to one or more ip addresses.
new net.Resolver()¶
Create a new resolve object.
Usage:
var net = require("rampart-net"); var resolver = new net.Resolver();
resolver.resolve()¶
Resolve a host name to ip address.
Usage:
var net = require("rampart-net"); var resolver = new net.Resolver(); resolver.resolve(host[, lookup_callback]);Where:
host
is a String - the host name to be resolved.lookup_callback
is a Function - an optional “lookup” event callback.
- NOTE:
resolver.resolve()
may be called multiple times at any time, however each time an anonymous function is provided as thelookup_callback
, that additional callback will be run for each “lookup” event. Note that duplicate named functions are only run once per event.var net = require("rampart-net"); var resolver = new net.Resolver(); /* console.log is run once per lookup */ resolver.resolve("google.com", console.log); resolver.resolve("rampart.dev", console.log);In contrast:
var net = require("rampart-net"); var resolver = new net.Resolver(); /* console.log is run TWICE per lookup since two different * functions call it. */ resolver.resolve("google.com", function(hobj){console.log(hobj);}); resolver.resolve("rampart.dev", function(hobj){console.log(hobj);});
resolver.reverse()¶
Resolve an ip address to host name.
Usage:
var net = require("rampart-net"); var resolver = new net.Resolver(); resolver.reverse(ip_addr[, lookup_callback]);Where:
ip_addr
is a String - the ip address to look up.lookup_callback
is a Function - an optional “lookup” event callback.
- NOTE:
- See above. Note applies to
resolver.reverse()
as well.
resolver.on()¶
Register a callback function for a resolver event. Currently, the only events are
lookup
anderror
.Usage example:
var net = require("rampart-net"); var resolver = new net.Resolver(); resolver.on("lookup", function(hobj){ rampart.utils.printf("%3J\n", hobj); }); resolver.on("error", function(emsg){ rampart.utils.printf("Resolver error: %s\n", emsg); }); resolver.resolve("rampart.dev"); resolver.resolve("google.com"); /* probable output: { "host": "google.com", "ip4addrs": [ "142.251.214.142" ], "ip6addrs": [ "2607:f8b0:4005:80f::200e" ], "ipaddrs": [ "142.251.214.142", "2607:f8b0:4005:80f::200e" ], "ip": "142.251.214.142", "ipv4": "142.251.214.142", "ipv6": "2607:f8b0:4005:80f::200e" } { "host": "rampart.dev", "ip4addrs": [ "184.105.177.37" ], "ip6addrs": [ "2001:470:1:393::37" ], "ipaddrs": [ "184.105.177.37", "2001:470:1:393::37" ], "ip": "184.105.177.37", "ipv4": "184.105.177.37", "ipv6": "2001:470:1:393::37" } */
net.resolve()¶
Resolve a host name. This function is not asynchronous. The lookup will occur immediately, potentially before the event loop starts, and block further execution while waiting for an answer.
Usage example:
var net = require("rampart-net"); var hostobj = net.resolve("yahoo.com"); /* hostobj = { "host": "yahoo.com", "ip4addrs": [ "74.6.231.21", "98.137.11.164", "98.137.11.163", "74.6.143.26", "74.6.231.20", "74.6.143.25" ], "ip6addrs": [ "2001:4998:24:120d::1:0", "2001:4998:44:3507::8000", "2001:4998:44:3507::8001", "2001:4998:124:1507::f000", "2001:4998:24:120d::1:1", "2001:4998:124:1507::f001" ], "ipaddrs": [ "2001:4998:24:120d::1:0", "2001:4998:44:3507::8000", "2001:4998:44:3507::8001", "2001:4998:124:1507::f000", "2001:4998:24:120d::1:1", "2001:4998:124:1507::f001", "74.6.231.21", "98.137.11.164", "98.137.11.163", "74.6.143.26", "74.6.231.20", "74.6.143.25" ], "ip": "2001:4998:24:120d::1:0", "ipv6": "2001:4998:24:120d::1:0", "ipv4": "74.6.231.21" } */
net.reverse()¶
Resolve an ip address to a hostname. This function is not asynchronous. The lookup will occur immediately, potentially before the event loop starts, and wait for an answer.
Usage example:
var net = require("rampart-net"); var hostname = net.reverse("1.1.1.1"); // hostname == "one.one.one.one"
Shortcut Functions¶
net.createConnection()¶
Short cut for
new net.Socket()
andsocket.connect()
. AKA -net.connect()
.Usage:
var net = require("rampart-net"); var socket = net.createConnection(options[, connect_callback]); /* or */ var socket = net.connect(options[, connect_callback]);Where:
options
is an Object of options, the same as found in new net.Socket() and socket.connect() above.connect_callback
is a Function, the connect callback function.This is equivalent to the following:
var net = require("rampart-net"); function netconnect(opt, cb) { var socket = new net.Socket(opt); socket.connect(opt, cb); return socket; } var socket = netconnect(options, connect_callback);Alternate usage with
port
:var net = require("rampart-net"); var socket = net.createConnection(port[, host][, connect_callback]); /* or */ var socket = net.connect(port[, host][, connect_callback]);
net.createServer()¶
Short cut for
new net.Server()
andserver.listen()
.Usage:
var net = require("rampart-net"); var server = net.createServer(options, connection_callback); /* or */ var server = net.createServer(port[, host[, backlog]][, connection_callback]);Where
options
is an Object of options, the same as found in new net.Server() and server.listen() above.connection_callback
is a Function, the connection callback function.This is roughly equivalent to the following (when using
options
above):var net = require("rampart-net"); function makeserver(opt, cb) { var server = new net.Server(opt, cb); server.listen(opt); return server; } var server = makeserver(options, connect_callback);
net.resolve_async()¶
Short cut for
new net.Resolver()
andresolver.resolve()
.Usage:
var net = require("rampart-net"); var resolver = net.resolve_async(host, lookup_callback);Where:
host
is a String - the host name to be resolved.lookup_calback
is a Function - the “lookup” event function.This is equivalent to the following:
var net = require("rampart-net"); function resolve_async(hn, cb) { var resolver = new net.Resolver(); resolver.resolve(hn, cb); return resolver; } var resolver = resolve_async(host, callback);
net.reverse_async()¶
Short cut for
new net.Resolver()
andresolver.reverse()
.Usage:
var net = require("rampart-net"); var resolver = net.reverse_async(ip_addr, lookup_callback);Where:
ip_addr
is a String - the ip address to look up.lookup_calback
is a Function - the “lookup” event function.This is equivalent to the following:
var net = require("rampart-net"); function reverse_async(ip, cb) { var resolver = new net.Resolver(); resolver.reverse(ip, cb); return resolver; } var resolver = reverse_async(ip, callback);