From 0188ac860b5bd5abf40ca7b686d3b8874ead6c86 Mon Sep 17 00:00:00 2001 From: Zaid Abdulla Date: Thu, 14 Oct 2021 18:51:25 -0700 Subject: [PATCH] Handle unsupported ACS methods gracefully --- lib/cwmp.ts | 36 ++++++++++++++++++++++++++++++++++++ lib/soap.ts | 19 ++++++++++++++++++- lib/types.ts | 1 + 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/lib/cwmp.ts b/lib/cwmp.ts index 1bece60..9b0fc8e 100644 --- a/lib/cwmp.ts +++ b/lib/cwmp.ts @@ -45,6 +45,7 @@ import { InformRequest, Preset, GetRPCMethodsResponse, + CpeFault, } from "./types"; import { IncomingMessage, ServerResponse } from "http"; import { Readable } from "stream"; @@ -1256,6 +1257,41 @@ async function processRequest( session.clearProvisions(sessionContext); } return nextRpc(sessionContext); + } else if (rpc.unknownMethod) { + if (sessionContext.state === 1) { + logger.accessWarn({ + sessionContext: sessionContext, + message: "Method not supported", + method: rpc.unknownMethod, + }); + + const f: CpeFault = { + faultCode: "Server", + faultString: "CWMP fault", + detail: { + faultCode: "8000", + faultString: "Method not supported", + }, + }; + + const res = soap.response({ + id: rpc.id, + acsFault: f, + cwmpVersion: sessionContext.cwmpVersion, + }); + + return writeResponse(sessionContext, res); + } else if (sessionContext.state === 2) { + const fault = { + code: "invalid_response", + message: "Response name does not match request name", + }; + recordFault(sessionContext, fault); + session.clearProvisions(sessionContext); + return nextRpc(sessionContext); + } else { + return reportBadState(sessionContext); + } } else { // CPE sent empty response if (sessionContext.state !== 1) return reportBadState(sessionContext); diff --git a/lib/soap.ts b/lib/soap.ts index 9a8cbbd..7894dc1 100644 --- a/lib/soap.ts +++ b/lib/soap.ts @@ -730,6 +730,18 @@ function RequestDownloadResponse(): string { return ""; } +function AcsFault(f: CpeFault): string { + return `${encodeEntities( + f.faultCode + )}${encodeEntities( + f.faultString + )}${encodeEntities( + f.detail.faultCode + )}${encodeEntities( + f.detail.faultString + )}`; +} + function faultStruct(xml: Element): FaultStruct { let faultCode: string, faultString: string, @@ -838,6 +850,7 @@ export function request( cpeRequest: null, cpeFault: null, cpeResponse: null, + unknownMethod: null, }; if (!body.length) return rpc; @@ -959,7 +972,8 @@ export function request( rpc.cpeFault = fault(methodElement); break; default: - throw new Error(`8000 Method not supported ${methodElement.localName}`); + rpc.unknownMethod = methodElement.localName; + break; } return rpc; @@ -987,6 +1001,7 @@ export function response(rpc: { id: string; acsRequest?: AcsRequest; acsResponse?: AcsResponse; + acsFault?: CpeFault; cwmpVersion?: string; }): { code: number; headers: Record; data: string } { const headers = { @@ -1055,6 +1070,8 @@ export function response(rpc: { `Unknown method request ${(rpc.acsRequest as AcsRequest).name}` ); } + } else if (rpc.acsFault) { + body = AcsFault(rpc.acsFault); } headers["Content-Type"] = 'text/xml; charset="utf-8"'; diff --git a/lib/types.ts b/lib/types.ts index 1f41836..90b2c84 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -526,6 +526,7 @@ export interface SoapMessage { cpeRequest?: CpeRequest; cpeFault?: CpeFault; cpeResponse?: CpeResponse; + unknownMethod?: string; } export interface ScriptResult {