527
}
528
529
// tidy things up a bit
530
- srv.TLSConnPolicies = consolidateConnPolicies(srv.TLSConnPolicies)
530
+ var err error
531
+ srv.TLSConnPolicies, err = consolidateConnPolicies(srv.TLSConnPolicies)
532
+ if err != nil {
533
+ return nil, fmt.Errorf("consolidating TLS connection policies for server %d: %v", i, err)
534
+ }
535
srv.Routes = consolidateRoutes(srv.Routes)
536
537
servers[fmt.Sprintf("srv%d", i)] = srv
542
543
// consolidateConnPolicies combines TLS connection policies that are the same,
544
// for a cleaner overall output.
541
-func consolidateConnPolicies(cps caddytls.ConnectionPolicies) caddytls.ConnectionPolicies {
545
+func consolidateConnPolicies(cps caddytls.ConnectionPolicies) (caddytls.ConnectionPolicies, error) {
546
for i := 0; i < len(cps); i++ {
547
for j := 0; j < len(cps); j++ {
548
if j == i {
555
i--
556
break
557
}
558
+
559
+ // if they have the same matcher, try to reconcile each field: either they must
560
+ // be identical, or we have to be able to combine them safely
561
+ if reflect.DeepEqual(cps[i].MatchersRaw, cps[j].MatchersRaw) {
562
+ if len(cps[i].ALPN) > 0 &&
563
+ len(cps[j].ALPN) > 0 &&
564
+ !reflect.DeepEqual(cps[i].ALPN, cps[j].ALPN) {
565
+ return nil, fmt.Errorf("two policies with same match criteria have conflicting ALPN: %v vs. %v",
566
+ cps[i].ALPN, cps[j].ALPN)
567
+ }
568
+ if len(cps[i].CipherSuites) > 0 &&
569
+ len(cps[j].CipherSuites) > 0 &&
570
+ !reflect.DeepEqual(cps[i].CipherSuites, cps[j].CipherSuites) {
571
+ return nil, fmt.Errorf("two policies with same match criteria have conflicting cipher suites: %v vs. %v",
572
+ cps[i].CipherSuites, cps[j].CipherSuites)
573
+ }
574
+ if cps[i].ClientAuthentication == nil &&
575
+ cps[j].ClientAuthentication != nil &&
576
+ !reflect.DeepEqual(cps[i].ClientAuthentication, cps[j].ClientAuthentication) {
577
+ return nil, fmt.Errorf("two policies with same match criteria have conflicting client auth configuration: %+v vs. %+v",
578
+ cps[i].ClientAuthentication, cps[j].ClientAuthentication)
579
+ }
580
+ if len(cps[i].Curves) > 0 &&
581
+ len(cps[j].Curves) > 0 &&
582
+ !reflect.DeepEqual(cps[i].Curves, cps[j].Curves) {
583
+ return nil, fmt.Errorf("two policies with same match criteria have conflicting curves: %v vs. %v",
584
+ cps[i].Curves, cps[j].Curves)
585
+ }
586
+ if cps[i].DefaultSNI != "" &&
587
+ cps[j].DefaultSNI != "" &&
588
+ cps[i].DefaultSNI != cps[j].DefaultSNI {
589
+ return nil, fmt.Errorf("two policies with same match criteria have conflicting default SNI: %s vs. %s",
590
+ cps[i].DefaultSNI, cps[j].DefaultSNI)
591
+ }
592
+ if cps[i].ProtocolMin != "" &&
593
+ cps[j].ProtocolMin != "" &&
594
+ cps[i].ProtocolMin != cps[j].ProtocolMin {
595
+ return nil, fmt.Errorf("two policies with same match criteria have conflicting min protocol: %s vs. %s",
596
+ cps[i].ProtocolMin, cps[j].ProtocolMin)
597
+ }
598
+ if cps[i].ProtocolMax != "" &&
599
+ cps[j].ProtocolMax != "" &&
600
+ cps[i].ProtocolMax != cps[j].ProtocolMax {
601
+ return nil, fmt.Errorf("two policies with same match criteria have conflicting max protocol: %s vs. %s",
602
+ cps[i].ProtocolMax, cps[j].ProtocolMax)
603
+ }
604
+ if cps[i].CertSelection != nil && cps[j].CertSelection != nil {
605
+ // merging fields other than AnyTag is not implemented
606
+ if !reflect.DeepEqual(cps[i].CertSelection.SerialNumber, cps[j].CertSelection.SerialNumber) ||
607
+ !reflect.DeepEqual(cps[i].CertSelection.SubjectOrganization, cps[j].CertSelection.SubjectOrganization) ||
608
+ cps[i].CertSelection.PublicKeyAlgorithm != cps[j].CertSelection.PublicKeyAlgorithm ||
609
+ !reflect.DeepEqual(cps[i].CertSelection.AllTags, cps[j].CertSelection.AllTags) {
610
+ return nil, fmt.Errorf("two policies with same match criteria have conflicting cert selections: %+v vs. %+v",
611
+ cps[i].CertSelection, cps[j].CertSelection)
612
+ }
613
+ }
614
+
615
+ // by now we've decided that we can merge the two -- we'll keep i and drop j
616
+
617
+ if len(cps[i].ALPN) == 0 && len(cps[j].ALPN) > 0 {
618
+ cps[i].ALPN = cps[j].ALPN
619
+ }
620
+ if len(cps[i].CipherSuites) == 0 && len(cps[j].CipherSuites) > 0 {
621
+ cps[i].CipherSuites = cps[j].CipherSuites
622
+ }
623
+ if cps[i].ClientAuthentication == nil && cps[j].ClientAuthentication != nil {
624
+ cps[i].ClientAuthentication = cps[j].ClientAuthentication
625
+ }
626
+ if len(cps[i].Curves) == 0 && len(cps[j].Curves) > 0 {
627
+ cps[i].Curves = cps[j].Curves
628
+ }
629
+ if cps[i].DefaultSNI == "" && cps[j].DefaultSNI != "" {
630
+ cps[i].DefaultSNI = cps[j].DefaultSNI
631
+ }
632
+ if cps[i].ProtocolMin == "" && cps[j].ProtocolMin != "" {
633
+ cps[i].ProtocolMin = cps[j].ProtocolMin
634
+ }
635
+ if cps[i].ProtocolMax == "" && cps[j].ProtocolMax != "" {
636
+ cps[i].ProtocolMax = cps[j].ProtocolMax
637
+ }
638
+
639
+ if cps[i].CertSelection == nil && cps[j].CertSelection != nil {
640
+ // if j is the only one with a policy, move it over to i
641
+ cps[i].CertSelection = cps[j].CertSelection
642
+ } else if cps[i].CertSelection != nil && cps[j].CertSelection != nil {
643
+ // if both have one, then combine AnyTag
644
+ for _, tag := range cps[j].CertSelection.AnyTag {
645
+ if !sliceContains(cps[i].CertSelection.AnyTag, tag) {
646
+ cps[i].CertSelection.AnyTag = append(cps[i].CertSelection.AnyTag, tag)
647
+ }
648
+ }
649
+ }
650
+
651
+ cps = append(cps[:j], cps[j+1:]...)
652
+ i--
653
+ break
654
+ }
655
}
656
}
556
- return cps
657
+ return cps, nil
658
}
659
660
// appendSubrouteToRouteList appends the routes in subroute