traefik/pkg/server/router/tcp/router.go
Jean-Baptiste Doumenjou 85ce16b34f Define TLS options on the Router configuration
Co-authored-by: juliens <julien@containo.us>
2019-06-17 18:14:08 +02:00

176 lines
5.2 KiB
Go

package tcp
import (
"context"
"fmt"
"net/http"
"github.com/containous/traefik/pkg/config"
"github.com/containous/traefik/pkg/log"
"github.com/containous/traefik/pkg/rules"
"github.com/containous/traefik/pkg/server/internal"
tcpservice "github.com/containous/traefik/pkg/server/service/tcp"
"github.com/containous/traefik/pkg/tcp"
"github.com/containous/traefik/pkg/tls"
)
// NewManager Creates a new Manager
func NewManager(conf *config.RuntimeConfiguration,
serviceManager *tcpservice.Manager,
httpHandlers map[string]http.Handler,
httpsHandlers map[string]http.Handler,
tlsManager *tls.Manager,
) *Manager {
return &Manager{
serviceManager: serviceManager,
httpHandlers: httpHandlers,
httpsHandlers: httpsHandlers,
tlsManager: tlsManager,
conf: conf,
}
}
// Manager is a route/router manager
type Manager struct {
serviceManager *tcpservice.Manager
httpHandlers map[string]http.Handler
httpsHandlers map[string]http.Handler
tlsManager *tls.Manager
conf *config.RuntimeConfiguration
}
func (m *Manager) getTCPRouters(ctx context.Context, entryPoints []string) map[string]map[string]*config.TCPRouterInfo {
if m.conf != nil {
return m.conf.GetTCPRoutersByEntrypoints(ctx, entryPoints)
}
return make(map[string]map[string]*config.TCPRouterInfo)
}
func (m *Manager) getHTTPRouters(ctx context.Context, entryPoints []string, tls bool) map[string]map[string]*config.RouterInfo {
if m.conf != nil {
return m.conf.GetRoutersByEntrypoints(ctx, entryPoints, tls)
}
return make(map[string]map[string]*config.RouterInfo)
}
// BuildHandlers builds the handlers for the given entrypoints
func (m *Manager) BuildHandlers(rootCtx context.Context, entryPoints []string) map[string]*tcp.Router {
entryPointsRouters := m.getTCPRouters(rootCtx, entryPoints)
entryPointsRoutersHTTP := m.getHTTPRouters(rootCtx, entryPoints, true)
entryPointHandlers := make(map[string]*tcp.Router)
for _, entryPointName := range entryPoints {
entryPointName := entryPointName
routers := entryPointsRouters[entryPointName]
ctx := log.With(rootCtx, log.Str(log.EntryPointName, entryPointName))
handler, err := m.buildEntryPointHandler(ctx, routers, entryPointsRoutersHTTP[entryPointName], m.httpHandlers[entryPointName], m.httpsHandlers[entryPointName])
if err != nil {
log.FromContext(ctx).Error(err)
continue
}
entryPointHandlers[entryPointName] = handler
}
return entryPointHandlers
}
func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string]*config.TCPRouterInfo, configsHTTP map[string]*config.RouterInfo, handlerHTTP http.Handler, handlerHTTPS http.Handler) (*tcp.Router, error) {
router := &tcp.Router{}
router.HTTPHandler(handlerHTTP)
defaultTLSConf, err := m.tlsManager.Get("default", "default")
if err != nil {
return nil, err
}
router.HTTPSHandler(handlerHTTPS, defaultTLSConf)
for routerHTTPName, routerHTTPConfig := range configsHTTP {
if len(routerHTTPConfig.TLS.Options) == 0 || routerHTTPConfig.TLS.Options == "default" {
continue
}
ctxRouter := log.With(internal.AddProviderInContext(ctx, routerHTTPName), log.Str(log.RouterName, routerHTTPName))
logger := log.FromContext(ctxRouter)
domains, err := rules.ParseDomains(routerHTTPConfig.Rule)
if err != nil {
routerErr := fmt.Errorf("invalid rule %s, error: %v", routerHTTPConfig.Rule, err)
routerHTTPConfig.Err = routerErr.Error()
logger.Debug(routerErr)
continue
}
if len(domains) == 0 {
logger.Warnf("The 'default' TLS options will be applied instead of %q as no domain has been found in the rule", routerHTTPConfig.TLS.Options)
}
for _, domain := range domains {
if routerHTTPConfig.TLS != nil {
tlsConf, err := m.tlsManager.Get("default", routerHTTPConfig.TLS.Options)
if err != nil {
routerHTTPConfig.Err = err.Error()
logger.Debug(err)
continue
}
router.AddRouteHTTPTLS(domain, tlsConf)
}
}
}
for routerName, routerConfig := range configs {
ctxRouter := log.With(internal.AddProviderInContext(ctx, routerName), log.Str(log.RouterName, routerName))
logger := log.FromContext(ctxRouter)
handler, err := m.serviceManager.BuildTCP(ctxRouter, routerConfig.Service)
if err != nil {
routerConfig.Err = err.Error()
logger.Error(err)
continue
}
domains, err := rules.ParseHostSNI(routerConfig.Rule)
if err != nil {
routerErr := fmt.Errorf("unknown rule %s", routerConfig.Rule)
routerConfig.Err = routerErr.Error()
logger.Debug(routerErr)
continue
}
for _, domain := range domains {
logger.Debugf("Adding route %s on TCP", domain)
switch {
case routerConfig.TLS != nil:
if routerConfig.TLS.Passthrough {
router.AddRoute(domain, handler)
} else {
configName := "default"
if len(routerConfig.TLS.Options) > 0 {
configName = routerConfig.TLS.Options
}
tlsConf, err := m.tlsManager.Get("default", configName)
if err != nil {
routerConfig.Err = err.Error()
logger.Debug(err)
continue
}
router.AddRouteTLS(domain, handler, tlsConf)
}
case domain == "*":
router.AddCatchAllNoTLS(handler)
default:
logger.Warn("TCP Router ignored, cannot specify a Host rule without TLS")
}
}
}
return router, nil
}