Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

opentelemetry-instrumentation-http throws on requests with malformed Forwarded headers #5095

Open
pmlanger opened this issue Oct 28, 2024 · 4 comments · May be fixed by #5099
Open

opentelemetry-instrumentation-http throws on requests with malformed Forwarded headers #5095

pmlanger opened this issue Oct 28, 2024 · 4 comments · May be fixed by #5099
Assignees
Labels
bug Something isn't working priority:p1 Bugs which cause problems in end-user applications such as crashes, data inconsistencies, etc

Comments

@pmlanger
Copy link

pmlanger commented Oct 28, 2024

What happened?

Steps to Reproduce

I used the minimal/standard setup from the repository README to reproduce.
Then, ran the server with node -r ./tracing.js app.js.
Then, ran two requests against the server:

$ curl http://localhost:9654
Hello World!%                                                                                                                                                                                                                                                 

$ curl http://localhost:9654 -H "Forwarded: malformed"
curl: (52) Empty reply from server

Expected Result

For the server not to crash/still being able to handle the request; and the open-telemetry-instrumentation-http plugin to handle bad requests gracefully.

Actual Result

Server/node process crashed with uncaughtException:

$ node -r ./tracing.js app.js
Example app listening on port 9654

/Users/philipp.langer/dev/otel-minimal/node_modules/forwarded-parse/index.js:146
    throw new ParseError('Unexpected end of input', header);
    ^
ParseError: Unexpected end of input
    at parse (/Users/philipp.langer/dev/otel-minimal/node_modules/forwarded-parse/index.js:146:11)
    at getServerAddress (/Users/philipp.langer/dev/otel-minimal/node_modules/@opentelemetry/instrumentation-http/build/src/utils.js:419:29)
    at getIncomingRequestAttributes (/Users/philipp.langer/dev/otel-minimal/node_modules/@opentelemetry/instrumentation-http/build/src/utils.js:497:27)
    at Server.incomingRequest (/Users/philipp.langer/dev/otel-minimal/node_modules/@opentelemetry/instrumentation-http/build/src/http.js:363:77)
    at parserOnIncoming (node:_http_server:1140:12)
    at HTTPParser.parserOnHeadersComplete (node:_http_common:119:17) {
  input: 'malformed'
}

Additional Details

The error thrown comes from forward-parse, in this line: https://github.com/lpinca/forwarded-parse/blob/master/index.js#L146
which is called by open-telemetry-instrumentation-http in getIncomingRequestAttributes (

const serverAddress = getServerAddress(request, options.component);
) -> getServerAddress -> usage of forwarded-parse

It feels like the open-telemetry-instrumentation-http should handle errors in the plugin itself, i.e., the error should not "leave" the plugin. It is quite expected that a client may send a malformed request, and the server should not crash on those. I could not find a really good way to prevent these errors. That is why I filed this as a bug report.

But also happy to be educated whether there's a way to handle errors from plugins that I am not aware of.

Workaround

You might laugh at this, but for completeness: calling getIncomingRequestAttributes from ignoreIncomingRequestHook like this is a hacky way to fix the issue for clients:

  ignoreIncomingRequestHook: (request: IncomingMessage) => {
    try {
      getIncomingRequestAttributes(request, {
        component: 'http',
        semconvStability: SemconvStability.STABLE,
      })
      return false
    } catch {
      return true
    }

Possible fix

A possible fix could be wrapping this part of the code

for (const entry of forwardedParse(forwardedHeader)) {
(and the other occurrence in getRemoteClientAddress) into a try / catch and treating a parsing error gracefully in the same way as an absent Forwarded header. This seems to be in line with how the other x-forwarded-* headers are handled.

Happy to take care of that and submit a PR, should you agree about the problem and suggestion.

OpenTelemetry Setup Code

"use strict";

const process = require("process");
const opentelemetry = require("@opentelemetry/sdk-node");
const {
  getNodeAutoInstrumentations,
} = require("@opentelemetry/auto-instrumentations-node");
const { ConsoleSpanExporter } = require("@opentelemetry/sdk-trace-base");
const { Resource } = require("@opentelemetry/resources");
const {
  SEMRESATTRS_SERVICE_NAME,
} = require("@opentelemetry/semantic-conventions");

// configure the SDK to export telemetry data to the console
// enable all auto-instrumentations from the meta package
const traceExporter = new ConsoleSpanExporter();
const sdk = new opentelemetry.NodeSDK({
  resource: new Resource({
    [SEMRESATTRS_SERVICE_NAME]: "my-service",
  }),
  traceExporter,
  instrumentations: [getNodeAutoInstrumentations()],
});

// initialize the SDK and register with the OpenTelemetry API
// this enables the API to record telemetry
sdk.start();

// gracefully shut down the SDK on process exit
process.on("SIGTERM", () => {
  sdk
    .shutdown()
    .then(() => console.log("Tracing terminated"))
    .catch((error) => console.log("Error terminating tracing", error))
    .finally(() => process.exit(0));
});

package.json

{
  "name": "my-app",
  "dependencies": {
    "@opentelemetry/api": "^1.9.0",
    "@opentelemetry/auto-instrumentations-node": "^0.52.0",
    "@opentelemetry/sdk-node": "^0.54.0",
    "express": "^4.21.1"
  }
}

Relevant log output

/Users/philipp.langer/dev/otel-minimal/node_modules/forwarded-parse/index.js:146
    throw new ParseError('Unexpected end of input', header);
    ^
ParseError: Unexpected end of input
    at parse (/Users/philipp.langer/dev/otel-minimal/node_modules/forwarded-parse/index.js:146:11)
    at getServerAddress (/Users/philipp.langer/dev/otel-minimal/node_modules/@opentelemetry/instrumentation-http/build/src/utils.js:419:29)
    at getIncomingRequestAttributes (/Users/philipp.langer/dev/otel-minimal/node_modules/@opentelemetry/instrumentation-http/build/src/utils.js:497:27)
    at Server.incomingRequest (/Users/philipp.langer/dev/otel-minimal/node_modules/@opentelemetry/instrumentation-http/build/src/http.js:363:77)
    at parserOnIncoming (node:_http_server:1140:12)
    at HTTPParser.parserOnHeadersComplete (node:_http_common:119:17) {
  input: 'malformed'
}
@pmlanger pmlanger added bug Something isn't working triage labels Oct 28, 2024
@dyladan dyladan added priority:p1 Bugs which cause problems in end-user applications such as crashes, data inconsistencies, etc and removed triage labels Oct 30, 2024
@dyladan dyladan self-assigned this Oct 30, 2024
@dyladan
Copy link
Member

dyladan commented Oct 30, 2024

Happy to take care of that and submit a PR, should you agree about the problem and suggestion.

That would be great if you could. I'm happy to help shepherd the PR if needed. We shouldn't be crashing end user apps so I'd like to get this fixed ASAP.

@pmlanger
Copy link
Author

@dyladan I gave it a shot: #5099

@LuiFerPereira
Copy link

We have the same problem. I would like to solve it as soon as possible. How to help?

@pmlanger
Copy link
Author

@LuiFerPereira #5099 has the fix; you can test it out if you like to. The PR is missing approval of workflow/reviews from maintainers and me addressing any comments (I am in CET timezone) :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working priority:p1 Bugs which cause problems in end-user applications such as crashes, data inconsistencies, etc
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants