github.com/mholt/caddy-l4@v0.0.0-20241104153248-ec8fae209322/modules/l4tls/alpn_matcher.go (about) 1 // Copyright 2020 Matthew Holt 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package l4tls 16 17 import ( 18 "crypto/tls" 19 20 "github.com/caddyserver/caddy/v2" 21 "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" 22 "github.com/caddyserver/caddy/v2/modules/caddytls" 23 ) 24 25 func init() { 26 caddy.RegisterModule(&MatchALPN{}) 27 } 28 29 type MatchALPN []string 30 31 // CaddyModule returns the Caddy module information. 32 func (*MatchALPN) CaddyModule() caddy.ModuleInfo { 33 return caddy.ModuleInfo{ 34 ID: "tls.handshake_match.alpn", 35 New: func() caddy.Module { return new(MatchALPN) }, 36 } 37 } 38 39 func (m *MatchALPN) Match(hello *tls.ClientHelloInfo) bool { 40 repl := hello.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer) 41 clientProtocols := hello.SupportedProtos 42 for _, alpn := range *m { 43 alpn = repl.ReplaceAll(alpn, "") 44 for _, clientProtocol := range clientProtocols { 45 if alpn == clientProtocol { 46 return true 47 } 48 } 49 } 50 return false 51 } 52 53 // UnmarshalCaddyfile sets up the MatchALPN from Caddyfile tokens. Syntax: 54 // 55 // alpn <values...> 56 func (m *MatchALPN) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { 57 for d.Next() { 58 wrapper := d.Val() 59 60 // At least one same-line option must be provided 61 if d.CountRemainingArgs() == 0 { 62 return d.ArgErr() 63 } 64 65 *m = append(*m, d.RemainingArgs()...) 66 67 // No blocks are supported 68 if d.NextBlock(d.Nesting()) { 69 return d.Errf("malformed TLS handshake matcher '%s': blocks are not supported", wrapper) 70 } 71 } 72 73 return nil 74 } 75 76 // Interface guards 77 var ( 78 _ caddytls.ConnectionMatcher = (*MatchALPN)(nil) 79 _ caddyfile.Unmarshaler = (*MatchALPN)(nil) 80 )