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

Added root CA config #5

Merged
merged 1 commit into from
Feb 6, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions kindling.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package kindling

import (
"context"
"crypto/x509"
"embed"
"encoding/pem"
"fmt"
"io"
"log/slog"
Expand Down Expand Up @@ -31,6 +33,7 @@ type httpDialer func(ctx context.Context, addr string) (http.RoundTripper, error
type kindling struct {
httpDialers []httpDialer
logWriter io.Writer
rootCA string
}

// Make sure that kindling implements the Kindling interface.
Expand Down Expand Up @@ -75,10 +78,10 @@ func WithDomainFronting(configURL, countryCode string) Option {
}
}

// WithDoHTunnel is a functional option that enables DNS over HTTPS (DoH) tunneling for the Kindling.
func WithDoHTunnel() Option {
// WithRootCA pins the root CA to use for TLS.
func WithRootCA(rootCA string) Option {
return func(k *kindling) {

k.rootCA = rootCA
}
}

Expand Down Expand Up @@ -149,7 +152,7 @@ func (k *kindling) newSmartHTTPDialer(domains ...string) (httpDialer, error) {
}
return k.newTransportWithDialContext(func(ctx context.Context, network, addr string) (net.Conn, error) {
return streamConn, nil
}), nil
})
}, nil
}

Expand All @@ -165,18 +168,31 @@ func (k *kindling) newSmartHTTPTransport(domains ...string) (*http.Transport, er
return nil, fmt.Errorf("failed to dial stream: %v", err)
}
return streamConn, nil
}), nil
})
}

func (k *kindling) newTransportWithDialContext(dialContext func(ctx context.Context, network, addr string) (net.Conn, error)) *http.Transport {
return &http.Transport{
func (k *kindling) newTransportWithDialContext(dialContext func(ctx context.Context, network, addr string) (net.Conn, error)) (*http.Transport, error) {
tr := &http.Transport{
DialContext: dialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 20 * time.Second,
ExpectContinueTimeout: 4 * time.Second,
}
if k.rootCA != "" {
block, _ := pem.Decode([]byte(k.rootCA))
if block == nil {
return nil, fmt.Errorf("failed to decode root CA PEM block")
}
certPool := x509.NewCertPool()
if !certPool.AppendCertsFromPEM(block.Bytes) {
log.Error("Failed to append root CA to pool")
return nil, fmt.Errorf("failed to append root CA to pool")
}
tr.TLSClientConfig.RootCAs = certPool
}
return tr, nil
}

//go:embed smart_dialer_config.yml
Expand Down