github.com/mholt/caddy-l4@v0.0.0-20241104153248-ec8fae209322/modules/l4proxyprotocol/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 l4proxyprotocol 16 17 import ( 18 "bytes" 19 "io" 20 21 "github.com/caddyserver/caddy/v2" 22 "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" 23 24 "github.com/mholt/caddy-l4/layer4" 25 ) 26 27 // https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt 28 var ( 29 headerV1Prefix = []byte("PROXY") 30 headerV2Prefix = []byte{0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A} 31 ) 32 33 func init() { 34 caddy.RegisterModule(&MatchProxyProtocol{}) 35 } 36 37 type MatchProxyProtocol struct{} 38 39 // CaddyModule returns the Caddy module information. 40 func (*MatchProxyProtocol) CaddyModule() caddy.ModuleInfo { 41 return caddy.ModuleInfo{ 42 ID: "layer4.matchers.proxy_protocol", 43 New: func() caddy.Module { return new(MatchProxyProtocol) }, 44 } 45 } 46 47 // Match returns true if the connection looks like it is using the Proxy Protocol. 48 func (m *MatchProxyProtocol) Match(cx *layer4.Connection) (bool, error) { 49 buf := make([]byte, len(headerV2Prefix)) 50 _, err := io.ReadFull(cx, buf) 51 if err != nil { 52 return false, err 53 } 54 55 if bytes.HasPrefix(buf, headerV1Prefix) { 56 return true, nil 57 } 58 if bytes.Equal(buf, headerV2Prefix) { 59 return true, nil 60 } 61 62 return false, nil 63 } 64 65 // UnmarshalCaddyfile sets up the MatchProxyProtocol from Caddyfile tokens. Syntax: 66 // 67 // proxy_protocol 68 func (m *MatchProxyProtocol) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { 69 _, wrapper := d.Next(), d.Val() // consume wrapper name 70 71 // No same-line options are supported 72 if d.CountRemainingArgs() > 0 { 73 return d.ArgErr() 74 } 75 76 // No blocks are supported 77 if d.NextBlock(d.Nesting()) { 78 return d.Errf("malformed layer4 connection matcher '%s': blocks are not supported", wrapper) 79 } 80 81 return nil 82 } 83 84 // Interface guards 85 var ( 86 _ layer4.ConnMatcher = (*MatchProxyProtocol)(nil) 87 _ caddyfile.Unmarshaler = (*MatchProxyProtocol)(nil) 88 )