gofiber / fiber

⚡️ Express inspired web framework written in Go

Home Page:https://gofiber.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

🐛 [Bug]: setting a Logger that access TLSConnectionState() will break when `app.Server().MaxConnsPerIP` is set to a value

rabarar opened this issue · comments

Bug Description

There is a condition where the TLSConnectionState from Context( ) is nil - only when app.Server( ).MaxConnPerIP is set to a value.

How to Reproduce

  1. Create a new app
  2. Set the app.Server( ).MaxConnPerIP = 1
  3. use a custom logger
        DisableColors: false,
        Format:        "${date} ${time} ${ip} ${status} - ${method} ${path} ${yellow}SerialNo[${serialNumber}]\n",
        TimeFormat:    "2006-01-02 15:04:05",
        TimeZone:      "Local",
        CustomTags: map[string]logger.LogFunc{
            "serialNumber": func(output logger.Buffer, c *fiber.Ctx, data *logger.Data, extraParam string) (int, error) {
                return output.WriteString(outputSerialFromContext(c))

            },
        },
    }))
  1. receive an incoming route ...
  2. boom

Expected Behavior

no sigsegv

Fiber Version

v2@v2.52.4

Code Snippet (optional)

package main

import "github.com/gofiber/fiber/v3"
import "log"

func main() {
  app := fiber.New()

  // Steps to reproduce

  log.Fatal(app.Listen(":3000"))
}

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my problem prior to opening this one.
  • I understand that improperly formatted bug reports may be closed without explanation.
commented

Pls share the code for outputSerialFromContext

And the error message

here's a small example that demonstrates the bug:

package main

import (
        "crypto"
        "crypto/tls"
        "fmt"
        "os"

        "github.com/gofiber/fiber/v2"
        //"golang.org/x/crypto/pkcs12"

        "github.com/gofiber/fiber/v2/log"
        "github.com/gofiber/fiber/v2/middleware/logger"
        "software.sslmate.com/src/go-pkcs12"
)

func initFiberApp() *fiber.App {
        app := fiber.New()
        app.Server().MaxConnsPerIP = 1

        app.Use(logger.New(logger.Config{
                DisableColors: false,
                Format:        "${date} ${time} ${ip} ${status} - ${method} ${path} ${yellow}SerialNo[${serialNumber}]\n",
                TimeFormat:    "2006-01-02 15:04:05",
                TimeZone:      "Local",
                CustomTags: map[string]logger.LogFunc{
                        "serialNumber": func(output logger.Buffer, c *fiber.Ctx, data *logger.Data, extraParam string) (int, error) {
                                return output.WriteString(c.Context().TLSConnectionState().PeerCertificates[0].SerialNumber.String())

                        },
                },
        }))

        app.Get("/", func(c *fiber.Ctx) error {
                if c.Context().TLSConnectionState() != nil && len(c.Context().TLSConnectionState().PeerCertificates) == 0 {
                        log.Warn("no peer certs")
                } else {
                        log.Info("peer certs exist")
                }
                return c.SendString(fmt.Sprintf("This page is being served over TLS using a PKCS12 store type: %s",
                        c.Context().TLSConnectionState().PeerCertificates[0].SerialNumber.String()))
        })

        return app
}

func initTLSConfig(path string, password string) (*tls.Certificate, error) {
        pkcs12Data, err := os.ReadFile(path)
        if err != nil {
                return nil, err
        }

        key, cert, _, err := pkcs12.DecodeChain(pkcs12Data, password)

        if err != nil {
                return nil, err
        }

        tlsCert := tls.Certificate{
                Certificate: [][]byte{cert.Raw},
                PrivateKey:  key.(crypto.PrivateKey),
                Leaf:        cert,
        }

        return &tlsCert, nil
}

func main() {
        path := "./security/server.p12"
        password := "foobar"

        tlsCert, error := initTLSConfig(path, password)

        if error != nil {
                fmt.Printf("Unable to initialize TLS configuration object. Check your configuration and try again. Program will STOP: %s", error)
        } else {
                config := &tls.Config{
                        Certificates: []tls.Certificate{*tlsCert},
                        ClientAuth:   tls.RequireAndVerifyClientCert,
                }

                app := initFiberApp()
                ln, err := tls.Listen("tcp", ":5443", config)
                if err != nil {
                        panic(err)
                }

                log.Fatal(app.Listener(ln))
        }
}

if you set MaxConnsPerIP > 0 you'll get a sigseg violation - the issue is in the worker pool implementation for fasthttps...

I think you can close this out and I should open it with their package...

FYI - from valyala/fasthttp "I have pushed a fix. I'll tag a release next week probably."