Skip to content

Commit 5521223

Browse files
authored
Merge pull request #6 from drahnieR/multi-interface
Add FireRouter.js
2 parents 5456225 + 2d1499a commit 5521223

File tree

10 files changed

+254
-152
lines changed

10 files changed

+254
-152
lines changed

extension/upnp/nat-upnp/client.js

Lines changed: 51 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
var nat = require('../nat-upnp');
2-
var async = require('async');
1+
const nat = require('../nat-upnp');
2+
const util = require('util')
33

44
var client = exports;
55

@@ -83,68 +83,65 @@ Client.prototype.getMappings = function getMappings(options, callback) {
8383
var end = false;
8484
var results = [];
8585

86-
async.whilst(function() {
87-
return !end;
88-
}, function(callback) {
89-
gateway.run('GetGenericPortMappingEntry', [
90-
[ 'NewPortMappingIndex', i++ ]
91-
], function(err, data) {
92-
if (err) {
86+
const asyncGatewayRun = util.promisify(gateway.run).bind(gateway);
87+
88+
(async () => {
89+
while (!end) {
90+
91+
let data
92+
try {
93+
data = await asyncGatewayRun('GetGenericPortMappingEntry', [
94+
[ 'NewPortMappingIndex', i++ ]
95+
])
96+
} catch(err) {
9397
// If we got an error on index 0, ignore it in case this router starts indicies on 1
9498
if (i !== 1) {
9599
end = true;
96100
}
97-
return callback(null);
101+
break
98102
}
99103

100104
if(data === null || data === undefined) {
101-
callback(null);
102-
return;
105+
continue
103106
}
104107

105108
try {
109+
var key;
110+
var match = Object.keys(data).some(function(k) {
111+
if (!/:GetGenericPortMappingEntryResponse/.test(k)) return false;
106112

107-
var key;
108-
var match = Object.keys(data).some(function(k) {
109-
if (!/:GetGenericPortMappingEntryResponse/.test(k)) return false;
113+
key = k;
114+
return true;
115+
});
110116

111-
key = k;
112-
return true;
113-
});
117+
// skip if there is no response in the payload
118+
if(!match) {
119+
continue
120+
}
114121

115-
// skip if there is no response in the payload
116-
if(!match) {
117-
callback(null)
118-
return
122+
data = data[key];
123+
124+
var result = {
125+
public: {
126+
host: typeof data.NewRemoteHost === 'string' &&
127+
data.NewRemoteHost || '',
128+
port: parseInt(data.NewExternalPort, 10)
129+
},
130+
private: {
131+
host: data.NewInternalClient,
132+
port: parseInt(data.NewInternalPort, 10)
133+
},
134+
protocol: data.NewProtocol.toLowerCase(),
135+
enabled: data.NewEnabled === '1',
136+
description: data.NewPortMappingDescription,
137+
ttl: parseInt(data.NewLeaseDuration, 10)
138+
};
139+
result.local = result.private.host === address;
140+
141+
results.push(result);
142+
} catch(e) {
119143
}
120-
121-
data = data[key];
122-
123-
var result = {
124-
public: {
125-
host: typeof data.NewRemoteHost === 'string' &&
126-
data.NewRemoteHost || '',
127-
port: parseInt(data.NewExternalPort, 10)
128-
},
129-
private: {
130-
host: data.NewInternalClient,
131-
port: parseInt(data.NewInternalPort, 10)
132-
},
133-
protocol: data.NewProtocol.toLowerCase(),
134-
enabled: data.NewEnabled === '1',
135-
description: data.NewPortMappingDescription,
136-
ttl: parseInt(data.NewLeaseDuration, 10)
137-
};
138-
result.local = result.private.host === address;
139-
140-
results.push(result);
141-
} catch(e) {
142-
}
143-
144-
callback(null);
145-
});
146-
}, function(err) {
147-
if (err) return callback(err);
144+
}
148145

149146
if (options.local) {
150147
results = results.filter(function(item) {
@@ -165,8 +162,10 @@ Client.prototype.getMappings = function getMappings(options, callback) {
165162
});
166163
}
167164

168-
callback(null, results);
169-
});
165+
callback(null, results)
166+
})().catch(err => {
167+
callback(err);
168+
})
170169
});
171170
};
172171

net2/Discovery.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright 2016 Firewalla LLC
1+
/* Copyright 2016-2019 Firewalla Inc.
22
*
33
* This program is free software: you can redistribute it and/or modify
44
* it under the terms of the GNU Affero General Public License, version 3,
@@ -82,8 +82,6 @@ module.exports = class {
8282
this.publisher = new p(loglevel);
8383

8484
this.hostCache = {};
85-
86-
this.discoverInterfacesAsync = util.promisify(this.discoverInterfaces)
8785
}
8886

8987
return instances[name];
@@ -171,9 +169,6 @@ module.exports = class {
171169
}
172170
}
173171

174-
start() {
175-
}
176-
177172
/**
178173
* Only call release function when the SysManager instance is no longer
179174
* needed
@@ -184,6 +179,10 @@ module.exports = class {
184179
log.debug("Calling release function of Discovery");
185180
}
186181

182+
discoverInterfacesAsync() {
183+
return util.promisify(this.discoverInterfaces).bind(this)()
184+
}
185+
187186
discoverInterfaces(callback) {
188187
this.interfaces = {};
189188
const config = Config.getConfig(true);

net2/FireRouter.js

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/* Copyright 2019 Firewalla Inc.
2+
*
3+
* This program is free software: you can redistribute it and/or modify
4+
* it under the terms of the GNU Affero General Public License, version 3,
5+
* as published by the Free Software Foundation.
6+
*
7+
* This program is distributed in the hope that it will be useful,
8+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
9+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+
* GNU Affero General Public License for more details.
11+
*
12+
* You should have received a copy of the GNU Affero General Public License
13+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
14+
*/
15+
16+
'use strict';
17+
18+
// this module should be responsible for connecting firewalla and fireroute together
19+
// more specifically:
20+
// inquery and update regarding to
21+
// physical/bridge/virtual interfaces, DNS, NAT, DHCP
22+
// serving as FireRouter on RED & BLUE
23+
// create secondaryInterface
24+
// start bro, dnsmasq if necessary
25+
// generating compatible config
26+
27+
28+
// An Interface class?
29+
// {
30+
// name
31+
// gateway: {ipv4, ipv4}
32+
// subnet
33+
// dnsmasq as a pre-interface instance?
34+
// }
35+
36+
const log = require("./logger.js")(__filename, "info");
37+
38+
const DNSMASQ = require('../extension/dnsmasq/dnsmasq.js');
39+
const BroDetect = require('./BroDetect.js');
40+
const PlatformLoader = require('../platform/PlatformLoader.js')
41+
const fwConfig = require('../net2/config.js').getConfig();
42+
const pclient = require('../util/redis_manager.js').getPublishClient()
43+
44+
const util = require('util')
45+
const rp = util.promisify(require('request'))
46+
47+
class FireRouter {
48+
constructor() {
49+
this.platform = PlatformLoader.getPlatform()
50+
51+
if (!fwConfig.firerouter || !fwConfig.firerouter.interface) return null
52+
53+
const intf = fwConfig.firerouter.interface;
54+
this.routerInterface = `http://${intf.host}:${intf.port}/${intf.version}`;
55+
}
56+
57+
// let it crash
58+
async init() {
59+
if (this.platform.getName() == 'gold') {
60+
// fireroute
61+
this.config = await this.getConfig()
62+
63+
// router -> this.getLANInterfaces()
64+
65+
// simple -> this.getWANInterfaces()
66+
67+
} else {
68+
// make sure there is at least one usable ethernet
69+
const Discovery = require('./Discovery.js');
70+
const d = new Discovery("nmap", fwConfig, "info");
71+
72+
const intfList = await d.discoverInterfacesAsync()
73+
for (const intf of intfList) {
74+
this.interfaces[intf.name] = intf
75+
}
76+
77+
// TODO
78+
// create secondaryInterface
79+
// start dnsmasq
80+
// create fireroute compatible config
81+
82+
}
83+
84+
// TODO
85+
// start bro service
86+
87+
const bro = new BroDetect("bro_detector", fwConfig)
88+
bro.start()
89+
}
90+
91+
isReady() {
92+
if (!this.config || !this.config.interface || !this.config.interface.phy ||
93+
!Object.keys(this.config.interface.phy).length)
94+
return false
95+
else
96+
return true
97+
}
98+
99+
async getConfig() {
100+
const options = {
101+
method: "GET",
102+
headers: {
103+
"Accept": "application/json"
104+
},
105+
url: this.routerInterface + "/config/active",
106+
json: true
107+
};
108+
109+
const resp = await rp(options)
110+
if (resp.statusCode !== 200) {
111+
throw new Error("Error getting fireroute config");
112+
}
113+
114+
return resp.body
115+
}
116+
117+
async setConfig(config) {
118+
const options = {
119+
method: "POST",
120+
headers: {
121+
"Accept": "application/json"
122+
},
123+
url: this.routerInterface + "/config/set",
124+
json: true,
125+
body: config
126+
};
127+
128+
const resp = await rp(options)
129+
if (resp.statusCode !== 200) {
130+
throw new Error("Error getting fireroute config", resp.body);
131+
}
132+
133+
return resp.body
134+
}
135+
136+
async getWANInterfaces() {
137+
const options = {
138+
method: "GET",
139+
headers: {
140+
"Accept": "application/json"
141+
},
142+
url: this.routerInterface + "/config/wans",
143+
json: true
144+
};
145+
146+
const resp = await rp(options)
147+
if (resp.statusCode !== 200) {
148+
throw new Error("Error getting WAN interfaces");
149+
}
150+
151+
return resp.body
152+
}
153+
154+
async getLANInterfaces() {
155+
const options = {
156+
method: "GET",
157+
headers: {
158+
"Accept": "application/json"
159+
},
160+
url: this.routerInterface + "/config/lans",
161+
json: true
162+
};
163+
164+
const resp = await rp(options)
165+
if (resp.statusCode !== 200) {
166+
throw new Error("Error getting LAN interfaces");
167+
}
168+
169+
return resp.body
170+
}
171+
}
172+
173+
174+
module.exports = new FireRouter()

net2/config.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -630,5 +630,12 @@
630630
"naughty_monkey"
631631
],
632632
"pubKeys": [],
633-
"allowCustomizedProfiles": 1
633+
"allowCustomizedProfiles": 1,
634+
"firerouter": {
635+
"interface": {
636+
"host": "localhost",
637+
"port": 8837,
638+
"version": "v1"
639+
}
640+
}
634641
}

0 commit comments

Comments
 (0)