diff --git a/acs.coffee b/acs.coffee index 8658840..5097ab9 100644 --- a/acs.coffee +++ b/acs.coffee @@ -2,12 +2,14 @@ config = require './config' common = require './common' util = require 'util' http = require 'http' +https = require 'https' tr069 = require './tr-069' tasks = require './tasks' sanitize = require('./sanitize').sanitize db = require './db' presets = require './presets' mongodb = require 'mongodb' +fs = require 'fs' applyConfigurations = (currentRequest, taskList) -> @@ -106,7 +108,7 @@ runTask = (currentRequest, task, methodResponse) -> nextTask(currentRequest) ) when tasks.STATUS_FAULT - util.log("#{currentRequest.deviceId}: Fault response for task #{taskId}") + util.log("#{currentRequest.deviceId}: Fault response for task #{task._id}") db.saveTask(task, (err) -> # Faulty task. No more work to do until task is deleted. res = tr069.response(null, cwmpResponse) @@ -166,6 +168,94 @@ nextTask = (currentRequest) -> runTask(currentRequest, task, {}) ) +listener = (httpRequest, httpResponse) -> + if httpRequest.method != 'POST' + #console.log '>>> 405 Method Not Allowed' + httpResponse.writeHead 405, {'Allow': 'POST'} + httpResponse.end('405 Method Not Allowed') + return + + chunks = [] + bytes = 0 + cookies = {} + + httpRequest.addListener 'data', (chunk) -> + chunks.push(chunk) + bytes += chunk.length + + httpRequest.getBody = (encoding) -> + # Write all chunks into a Buffer + body = new Buffer(bytes) + offset = 0 + chunks.forEach((chunk) -> + chunk.copy(body, offset, 0, chunk.length) + offset += chunk.length + ) + + #Return encoded (default to UTF8) string + return body.toString(encoding || 'utf8', 0, body.byteLength) + + httpRequest.addListener 'end', () -> + currentRequest = {} + currentRequest.httpRequest = httpRequest + currentRequest.httpResponse = httpResponse + + cwmpResponse = {} + cwmpRequest = tr069.request(httpRequest) + + # get deviceId either from inform xml or cookie + if cwmpRequest.methodRequest? and cwmpRequest.methodRequest.type is 'Inform' + cookies.deviceId = currentRequest.deviceId = common.getDeviceId(cwmpRequest.methodRequest.deviceId) + else + currentRequest.deviceId = cwmpRequest.cookies.deviceId + + if config.DEBUG_DEVICES[currentRequest.deviceId] + dump = "# REQUEST #{new Date(Date.now())}\n" + JSON.stringify(httpRequest.headers) + "\n#{httpRequest.getBody()}\n\n" + require('fs').appendFile("debug/#{currentRequest.deviceId}.dump", dump, (err) -> + throw new Error(err) if err + ) + + if cwmpRequest.methodRequest? + if cwmpRequest.methodRequest.type is 'Inform' + cwmpResponse.methodResponse = {type : 'InformResponse'} + + if config.LOG_INFORMS + util.log("#{currentRequest.deviceId}: Inform (#{cwmpRequest.methodRequest.event}); retry count #{cwmpRequest.methodRequest.retryCount}") + + updateDevice(currentRequest, {'inform' : true, 'parameterValues' : cwmpRequest.methodRequest.parameterList}, (err) -> + res = tr069.response(cwmpRequest.id, cwmpResponse, cookies) + writeResponse(currentRequest, res) + ) + else if cwmpRequest.methodRequest.type is 'TransferComplete' + # do nothing + util.log("#{currentRequest.deviceId}: Transfer complete") + cwmpResponse.methodResponse = {type : 'TransferCompleteResponse'} + res = tr069.response(cwmpRequest.id, cwmpResponse, cookies) + writeResponse(currentRequest, res) + else + throw Error('ACS method not supported') + else if cwmpRequest.methodResponse? + taskId = cwmpRequest.id + + db.getTask(taskId, (task) -> + if not task + nextTask(currentRequest) + else + runTask(currentRequest, task, cwmpRequest.methodResponse) + ) + else if cwmpRequest.fault? + taskId = cwmpRequest.id + + db.getTask(taskId, (task) -> + if not task + nextTask(currentRequest) + else + runTask(currentRequest, task, cwmpRequest.fault) + ) + else + # cpe sent empty response. start sending acs requests + nextTask(currentRequest) + cluster = require 'cluster' numCPUs = require('os').cpus().length @@ -185,94 +275,14 @@ if cluster.isMaster for i in [1 .. numCPUs] cluster.fork() else - server = http.createServer (httpRequest, httpResponse) -> - if httpRequest.method != 'POST' - #console.log '>>> 405 Method Not Allowed' - httpResponse.writeHead 405, {'Allow': 'POST'} - httpResponse.end('405 Method Not Allowed') - return + options = { + key: fs.readFileSync('httpscert.key'), + cert: fs.readFileSync('httpscert.crt') + } - chunks = [] - bytes = 0 - cookies = {} + httpServer = http.createServer(listener) + httpsServer = https.createServer(options, listener) - httpRequest.addListener 'data', (chunk) -> - chunks.push(chunk) - bytes += chunk.length - - httpRequest.getBody = (encoding) -> - # Write all chunks into a Buffer - body = new Buffer(bytes) - offset = 0 - chunks.forEach((chunk) -> - chunk.copy(body, offset, 0, chunk.length) - offset += chunk.length - ) - - #Return encoded (default to UTF8) string - return body.toString(encoding || 'utf8', 0, body.byteLength) - - httpRequest.addListener 'end', () -> - currentRequest = {} - currentRequest.httpRequest = httpRequest - currentRequest.httpResponse = httpResponse - - cwmpResponse = {} - cwmpRequest = tr069.request(httpRequest) - - # get deviceId either from inform xml or cookie - if cwmpRequest.methodRequest? and cwmpRequest.methodRequest.type is 'Inform' - cookies.deviceId = currentRequest.deviceId = common.getDeviceId(cwmpRequest.methodRequest.deviceId) - else - currentRequest.deviceId = cwmpRequest.cookies.deviceId - - if config.DEBUG_DEVICES[currentRequest.deviceId] - dump = "# REQUEST #{new Date(Date.now())}\n" + JSON.stringify(httpRequest.headers) + "\n#{httpRequest.getBody()}\n\n" - require('fs').appendFile("debug/#{currentRequest.deviceId}.dump", dump, (err) -> - throw new Error(err) if err - ) - - if cwmpRequest.methodRequest? - if cwmpRequest.methodRequest.type is 'Inform' - cwmpResponse.methodResponse = {type : 'InformResponse'} - - if config.LOG_INFORMS - util.log("#{currentRequest.deviceId}: Inform (#{cwmpRequest.methodRequest.event}); retry count #{cwmpRequest.methodRequest.retryCount}") - - updateDevice(currentRequest, {'inform' : true, 'parameterValues' : cwmpRequest.methodRequest.parameterList}, (err) -> - res = tr069.response(cwmpRequest.id, cwmpResponse, cookies) - writeResponse(currentRequest, res) - ) - else if cwmpRequest.methodRequest.type is 'TransferComplete' - # do nothing - util.log("#{currentRequest.deviceId}: Transfer complete") - cwmpResponse.methodResponse = {type : 'TransferCompleteResponse'} - res = tr069.response(cwmpRequest.id, cwmpResponse, cookies) - writeResponse(currentRequest, res) - else - throw Error('ACS method not supported') - else if cwmpRequest.methodResponse? - taskId = cwmpRequest.id - - db.getTask(taskId, (task) -> - if not task - nextTask(currentRequest) - else - runTask(currentRequest, task, cwmpRequest.methodResponse) - ) - else if cwmpRequest.fault? - taskId = cwmpRequest.id - - db.getTask(taskId, (task) -> - if not task - nextTask(currentRequest) - else - runTask(currentRequest, task, cwmpRequest.fault) - ) - else - # cpe sent empty response. start sending acs requests - nextTask(currentRequest) - - - server.listen config.ACS_PORT, config.ACS_INTERFACE + httpServer.listen(config.ACS_PORT, config.ACS_INTERFACE) + httpsServer.listen(config.ACS_HTTPS_PORT, config.ACS_HTTPS_INTERFACE) #console.log "Server listening on port #{config.ACS_PORT}" diff --git a/config.coffee b/config.coffee index c8c353c..6c10c0e 100644 --- a/config.coffee +++ b/config.coffee @@ -1,6 +1,8 @@ exports.DATABASE_NAME = 'genie' exports.ACS_PORT = 7547 # CWMP port as assigned by IANA +exports.ACS_HTTPS_PORT = 7548 exports.ACS_INTERFACE = '0.0.0.0' +exports.ACS_HTTPS_INTERFACE = '0.0.0.0' exports.API_PORT = 7557 exports.API_INTERFACE = '0.0.0.0' exports.FILES_PORT = 7567 diff --git a/httpscert.crt b/httpscert.crt new file mode 100644 index 0000000..77af0ba --- /dev/null +++ b/httpscert.crt @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICqTCCAhICCQDSrolRw1qPBzANBgkqhkiG9w0BAQUFADCBmDELMAkGA1UEBhMC +SVExFTATBgNVBAgMDFN1bGF5bWFuaXlhaDEVMBMGA1UEBwwMU3VsYXltYW5peWFo +MQ8wDQYDVQQKDAZGYW5vb3MxEzARBgNVBAsMClRlY2hub2xvZ3kxDjAMBgNVBAMM +BWdlbmllMSUwIwYJKoZIhvcNAQkBFhZ6YWlkLmFiZHVsbGFAZmFub29zLmlxMB4X +DTEzMDIxNzEyNTYzN1oXDTE0MDIxNzEyNTYzN1owgZgxCzAJBgNVBAYTAklRMRUw +EwYDVQQIDAxTdWxheW1hbml5YWgxFTATBgNVBAcMDFN1bGF5bWFuaXlhaDEPMA0G +A1UECgwGRmFub29zMRMwEQYDVQQLDApUZWNobm9sb2d5MQ4wDAYDVQQDDAVnZW5p +ZTElMCMGCSqGSIb3DQEJARYWemFpZC5hYmR1bGxhQGZhbm9vcy5pcTCBnzANBgkq +hkiG9w0BAQEFAAOBjQAwgYkCgYEAxtHC3jlOoVsZQ9I8Wgd+8NkEaRfc01lRIAzj +eWuUO/xNY54EUDHecRxwolHtoGkkZAp4kKR3uUVdAo9uXmNT2CeeZ5lfRoa8WmgG +Yd6PExsdc4ZeKcw20XrKtQICqmU6rGlLERMFX97ejQh3eUmqwbzNaXiURxcKGdeK +2C/NxoUCAwEAATANBgkqhkiG9w0BAQUFAAOBgQAYFw6dy/z74ahnA5QpuJOjjTrt +AJaL9iuL1xS6TFfzne9UMIT+fFJsgSy6xx3TGkvbZJTnCzJN7I2uqmAhMoGFy7Ea +svCCkj8U5qkjqgwwi7IbwQ7fXxTVdPqUlkIdNB2YLDELksxCX+ZzGQPiFB8WrSoO +OBvB+hhPFpgp3aO2AQ== +-----END CERTIFICATE----- diff --git a/httpscert.key b/httpscert.key new file mode 100644 index 0000000..6493262 --- /dev/null +++ b/httpscert.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQDG0cLeOU6hWxlD0jxaB37w2QRpF9zTWVEgDON5a5Q7/E1jngRQ +Md5xHHCiUe2gaSRkCniQpHe5RV0Cj25eY1PYJ55nmV9GhrxaaAZh3o8TGx1zhl4p +zDbResq1AgKqZTqsaUsREwVf3t6NCHd5SarBvM1peJRHFwoZ14rYL83GhQIDAQAB +AoGAR4NpuW8ZhlZzNv7m8Gcj1NPqjzajGm5VDNc19xWoAw+UcpGC8amOXlcheHFJ +rNpE2asehMBzw/NcKjCXPWIy5LnGmttJMN2EbT2h/+uxBIM5IUc+joF744xF4C0t +5zrtqQYJxC7sBLX2vf7nY6iuovUM7fHEwACyV3Rpw3zdZf0CQQDiqW+ugLKcfS/c +6hkGTxeYWF4gUJTf3ke3au8nyMmUhyBwOuP4kpO72mK8bMLtjZRk3g6YChA4qH41 +nfXUXIh7AkEA4I2/zj4GDjjspDR+/tX0iUHQk1Rm2CRmRXXFJV1f688OLODCcOFK +Ms/+qnbe41wXo1NUxCqVrnPwEh3MVl88/wJBANUTpXqtX7s+8ETECTxmE+9Se0Hz +ntCJXG/v5d1Ho0Cueu8mXXMrEBiTpygtMl4xL2RXX+7L3w30T5lF4nh9eIsCQQDY +DmsbdL/81TaTc9MxPQlxOzsFVrMxiixA7uTGY8ZULD/2XDeZxprOsyPUPlWMquIv +ipFHwbWNSg4WUEd4X2BfAkEAytze+0mCd0WCsKbKwfTQnmJ3bK7JQywtC03llWyA +Om3Vl61Syaa7M2hl5rLvitZMvU1Wd0s8raOXN8RUuRXZBw== +-----END RSA PRIVATE KEY-----