Skip to content

Commit

Permalink
Merge pull request #1367 from xinnige/3647_add_ncid
Browse files Browse the repository at this point in the history
Add network ncid
  • Loading branch information
jasonlyc authored Sep 23, 2024
2 parents eae116b + b3bd798 commit 55fb115
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 1 deletion.
12 changes: 12 additions & 0 deletions core/network_config_mgr.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const { spawn } = require('child_process')
const readline = require('readline');
const {Address4, Address6} = require('ip-address');
const _ = require('lodash');
const uuid = require('uuid');
const pl = require('../platform/PlatformLoader.js');
const platform = pl.getPlatform();
const r = require('../util/firerouter.js');
Expand Down Expand Up @@ -671,7 +672,18 @@ class NetworkConfigManager {
return errors;
}

async validateNcid(networkConfig, inTransaction = false, skipNcid = false) {
const originConfig = await this.getActiveConfig(inTransaction);
if (originConfig && originConfig.ncid && networkConfig.ncid && originConfig.ncid !== networkConfig.ncid) {
if (!skipNcid) return ["ncid not match"];
}
}

async saveConfig(networkConfig, transaction = false) {
// do not generate ncid in transaction
if (!networkConfig.ncid && !transaction) {
networkConfig.ncid = util.generateUUID();
}
const configString = JSON.stringify(networkConfig);
if (configString) {
await rclient.setAsync(transaction ? "sysdb:transaction:networkConfig" : "sysdb:networkConfig", configString);
Expand Down
3 changes: 3 additions & 0 deletions sensors/wlan_conf_update_sensor.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const fs = require('fs');
const ncm = require('../core/network_config_mgr.js');
const platform = require('../platform/PlatformLoader.js').getPlatform();
const r = require('../util/firerouter.js');
const util = require('../util/util.js');

class WlanConfUpdateSensor extends Sensor {
async run() {
Expand Down Expand Up @@ -72,6 +73,8 @@ class WlanConfUpdateSensor extends Sensor {
this.log.error(`Error occured while applying updated config`, errors);
return;
}
currentConfig.ncid = util.generateUUID();
log.info("New ncid generated", currentConfig.ncid);
await ncm.saveConfig(currentConfig, false);
}
}
Expand Down
27 changes: 26 additions & 1 deletion service/routes/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ const bodyParser = require('body-parser');
const log = require('../../util/logger.js')(__filename);
const ncm = require('../../core/network_config_mgr.js');
const ns = require('../../core/network_setup.js');

const util = require('../../util/util.js');
const AsyncLock = require('async-lock');
const lock = new AsyncLock();

const WLAN_FLAG_WEP = 0b1
const WLAN_FLAG_WPA = 0b10
Expand All @@ -32,6 +34,7 @@ const WLAN_FLAG_SAE = 0b100000
const WLAN_FLAG_PSK_SHA256 = 0b1000000
const WLAN_FLAG_EAP_SHA256 = 0b10000000

const LOCK_NETWORK_CONFIG_NCID = "LOCK_NETWORK_CONFIG_NCID";

const _ = require('lodash');
const { exec } = require('child-process-promise');
Expand Down Expand Up @@ -254,6 +257,8 @@ router.post('/set',
const transID = newConfig.transID;
delete newConfig.transactionOp; // do not leave transactionOp in the saved config
delete newConfig.transID;
const ignoreNcid = newConfig.ignoreNcid || false;
delete newConfig.ignoreNcid;
if (transactionOp && !validTransactionOps.includes(transactionOp)) {
const errMsg = `Unrecognized transactionOp in config: ${transactionOp}`;
log.error(errMsg);
Expand Down Expand Up @@ -308,6 +313,15 @@ router.post('/set',
}
}
let errors = await ncm.validateConfig(newConfig);
if (errors && errors.length != 0) {
log.error("Invalid network config", errors);
res.status(400).json({errors: errors});
return;
}

await lock.acquire(LOCK_NETWORK_CONFIG_NCID, async () => {
try {
errors = await ncm.validateNcid(newConfig, inTransaction, ignoreNcid);
if (errors && errors.length != 0) {
log.error("Invalid network config", errors);
res.status(400).json({errors: errors});
Expand Down Expand Up @@ -336,10 +350,21 @@ router.post('/set',
currentTransID = null;
}, T_REVERT_TIMEOUT);
}
newConfig.ncid = util.generateUUID();
log.info("New ncid generated", newConfig.ncid);
await ncm.saveConfig(newConfig, inTransaction);

res.status(200).json({errors: errors});
}
}
} catch (err) {
log.error("Cannot set network config", err.message);
res.status(500).json({errors: [err.message]});
}
}).catch((err) => {
log.error("Cannot acquire LOCK_NETWORK_CONFIG_NCID", err.message);
res.status(500).json({errors: [err.message]});
});
});

router.post('/prepare_env',
Expand Down
62 changes: 62 additions & 0 deletions tests/core/test_ncm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/* Copyright 2016-2024 Firewalla Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

'use strict'

let chai = require('chai');
let expect = chai.expect;

const ncm = require('../../core/network_config_mgr.js');
let log = require('../../util/logger.js')(__filename, 'info');
const rclient = require('../../util/redis_manager').getRedisClient();

describe('Test network config manager', function(){
this.timeout(30000);
beforeEach((done) => (
async() => {
this.testkey = "sysdb:transaction:networkConfig";
this.origin = await rclient.getAsync(this.testkey);
this.nwkey = "sysdb:networkConfig";
this.nw = await rclient.getAsync(this.nwkey);
done();
})()
);

afterEach((done) => (
async() => {
await rclient.setAsync(this.testkey, this.origin);
await rclient.setAsync(this.nwkey, this.nw);
done();
})()
);

it('should validate network ncid', async()=> {
const nwConfig = {"version":1,"interface":{"phy":{"eth0":{}}},"ts":1726648571944};
expect(await ncm.validateNcid(nwConfig, true)).to.be.undefined;

await rclient.setAsync(this.testkey, `{"version":1,"interface":{"phy":{"eth0":{}}},"ts":1726648571944, "ncid":"test"}`);
expect(await ncm.validateNcid(nwConfig, true)).to.be.undefined;
});

it('should fail to validate network ncid', async()=> {
await rclient.setAsync(this.testkey, `{"version":1,"interface":{"phy":{"eth0":{}}},"ts":1726648571944, "ncid":"test"}`);

const nwConfig = {"version":1,"interface":{"phy":{"eth0":{}}},"ts":1726648571944, ncid: "2df97f9efb0ad09b7201726801377449"};
expect(await ncm.validateNcid(nwConfig, true)).to.be.eql(["ncid not match"]);

expect(await ncm.validateNcid(nwConfig, true, true)).to.be.undefined;
});

});
47 changes: 47 additions & 0 deletions tests/util/test_util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/* Copyright 2016-2024 Firewalla Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

'use strict'

let chai = require('chai');
let expect = chai.expect;

let util = require('../../util/util.js');
let log = require('../../util/logger.js')(__filename, 'info');

describe('Test util', function(){
this.timeout(30000);

before((done) => (
async() => {
done();
})()
);

after((done) => (
async() => {
done();
})()
);


it('should generate uuid', async()=> {
const u = util.generateUUID();
log.debug("generate uuid", u);
expect(u.length).to.be.equal(32);
});


});
7 changes: 7 additions & 0 deletions util/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
const Promise = require('bluebird');
const { exec } = require('child-process-promise');
const log = require('../util/logger.js')('util');
const uuid = require('uuid');

const _ = require('lodash')

Expand Down Expand Up @@ -257,6 +258,11 @@ function parseNumList(str) {
return result.filter(n => !isNaN(n))
}

function generateUUID() {
const ts = Date.now() + '';
return uuid.v4().replace(/-/g,"").substring(ts.length) + ts;
}

module.exports = {
extend: extend,
getPreferredBName: getPreferredBName,
Expand All @@ -266,6 +272,7 @@ module.exports = {
getHexStrArray: getHexStrArray,
generatePSK: generatePSK,
generateWpaSupplicantConfig: generateWpaSupplicantConfig,
generateUUID,
parseEscapedString,
parseHexString,
freqToChannel,
Expand Down

0 comments on commit 55fb115

Please sign in to comment.