@achingbrain/nat-port-mapper
Version:
Port mapping with UPnP and NAT-PMP
76 lines • 3.77 kB
JavaScript
import { DEFAULT_AUTO_REFRESH, DEFAULT_PORT_MAPPING_TTL, DEVICE_WAN_IP_CONNECTION_2 } from './constants.js';
import { InternetGatewayService } from './internet-gateway-service.js';
import { findNamespacedKey } from './utils.js';
export class InternetGatewayService4 extends InternetGatewayService {
async mapPort(localPort, localHost, options = {}) {
const mapping = {
remoteHost: options.remoteHost ?? '',
externalPort: `${options.externalPort ?? localPort}`,
internalClient: localHost,
protocol: options.protocol?.toUpperCase() === 'UDP' ? 'UDP' : 'TCP',
description: options.description ?? this.options.description ?? '@achingbrain/nat-port-mapper',
ttl: Math.max(Math.round((options.ttl ?? this.options.ttl ?? DEFAULT_PORT_MAPPING_TTL) / 1000), 3600)
};
this.log('creating mapping for local port %d to %j', localPort, mapping);
const gateway = await this.getGateway(options);
const response = await gateway.run(DEVICE_WAN_IP_CONNECTION_2, 'AddAnyPortMapping', [
['NewRemoteHost', mapping.remoteHost],
['NewExternalPort', mapping.externalPort],
['NewProtocol', mapping.protocol],
['NewInternalPort', localPort],
['NewInternalClient', mapping.internalClient],
['NewEnabled', 1],
['NewPortMappingDescription', mapping.description],
['NewLeaseDuration', mapping.ttl]
], options);
// UPnP2 will resolve port mapping conflicts for us so we need to read the
// mapped port from the response
const key = findNamespacedKey('AddAnyPortMappingResponse', response);
if (options.autoRefresh ?? this.options.autoRefresh ?? DEFAULT_AUTO_REFRESH) {
this.configureRefresh(localPort, mapping, options);
}
this.addMapping(localPort, mapping);
return Number(response[key].NewReservedPort);
}
async refreshPort(localPort, options) {
const mappings = this.mappings.get(localPort) ?? [];
for (const mapping of mappings) {
try {
const gateway = await this.getGateway(options);
await gateway.run(DEVICE_WAN_IP_CONNECTION_2, 'AddAnyPortMapping', [
['NewRemoteHost', mapping.remoteHost],
['NewExternalPort', mapping.externalPort],
['NewProtocol', mapping.protocol],
['NewInternalPort', localPort],
['NewInternalClient', mapping.internalClient],
['NewEnabled', 1],
['NewPortMappingDescription', mapping.description],
['NewLeaseDuration', mapping.ttl]
], options);
}
catch (err) {
this.log.error('could not refresh port %d mapping - %e', localPort, err);
}
this.configureRefresh(localPort, mapping, options);
}
}
async unmap(localPort, options) {
const mappings = this.mappings.get(localPort) ?? [];
for (const mapping of mappings) {
try {
clearTimeout(mapping.refreshTimeout);
const gateway = await this.getGateway(options);
await gateway.run(DEVICE_WAN_IP_CONNECTION_2, 'DeletePortMapping', [
['NewRemoteHost', ''],
['NewExternalPort', localPort],
['NewProtocol', '']
], options);
}
catch (err) {
this.log.error('could not unmap port %d - %e', localPort, err);
}
}
this.mappings.delete(localPort);
}
}
//# sourceMappingURL=internet-gateway-service-4.js.map