github.com/gdamore/mangos@v1.4.0/transport/tlstcp/tlstcp.go (about) 1 // Copyright 2018 The Mangos Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use 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 tlstcp implements the TLS over TCP transport for mangos. 16 package tlstcp 17 18 import ( 19 "crypto/tls" 20 "net" 21 22 "nanomsg.org/go-mangos" 23 ) 24 25 type options map[string]interface{} 26 27 func (o options) get(name string) (interface{}, error) { 28 if v, ok := o[name]; ok { 29 return v, nil 30 } 31 return nil, mangos.ErrBadOption 32 } 33 34 func (o options) set(name string, val interface{}) error { 35 switch name { 36 case mangos.OptionTLSConfig: 37 switch v := val.(type) { 38 case *tls.Config: 39 o[name] = v 40 default: 41 return mangos.ErrBadValue 42 } 43 default: 44 return mangos.ErrBadOption 45 } 46 return nil 47 } 48 49 func (o options) configTCP(conn *net.TCPConn) error { 50 if v, ok := o[mangos.OptionNoDelay]; ok { 51 if err := conn.SetNoDelay(v.(bool)); err != nil { 52 return err 53 } 54 } 55 if v, ok := o[mangos.OptionKeepAlive]; ok { 56 if err := conn.SetKeepAlive(v.(bool)); err != nil { 57 return err 58 } 59 } 60 61 return nil 62 } 63 64 func newOptions(t *tlsTran) options { 65 o := make(map[string]interface{}) 66 o[mangos.OptionTLSConfig] = t.config 67 return options(o) 68 } 69 70 type dialer struct { 71 addr string 72 sock mangos.Socket 73 opts options 74 } 75 76 func (d *dialer) Dial() (_ mangos.Pipe, err error) { 77 var ( 78 addr *net.TCPAddr 79 config *tls.Config 80 ) 81 82 if addr, err = mangos.ResolveTCPAddr(d.addr); err != nil { 83 return nil, err 84 } 85 86 tconn, err := net.DialTCP("tcp", nil, addr) 87 if err != nil { 88 return nil, err 89 } 90 if err = d.opts.configTCP(tconn); err != nil { 91 tconn.Close() 92 return nil, err 93 } 94 if v, ok := d.opts[mangos.OptionTLSConfig]; ok { 95 config = v.(*tls.Config) 96 } 97 conn := tls.Client(tconn, config) 98 if err = conn.Handshake(); err != nil { 99 conn.Close() 100 return nil, err 101 } 102 return mangos.NewConnPipe(conn, d.sock, 103 mangos.PropTLSConnState, conn.ConnectionState()) 104 } 105 106 func (d *dialer) SetOption(n string, v interface{}) error { 107 return d.opts.set(n, v) 108 } 109 110 func (d *dialer) GetOption(n string) (interface{}, error) { 111 return d.opts.get(n) 112 } 113 114 type listener struct { 115 sock mangos.Socket 116 addr *net.TCPAddr 117 bound net.Addr 118 listener *net.TCPListener 119 opts options 120 config *tls.Config 121 } 122 123 func (l *listener) Listen() error { 124 var err error 125 v, ok := l.opts[mangos.OptionTLSConfig] 126 if !ok { 127 return mangos.ErrTLSNoConfig 128 } 129 l.config = v.(*tls.Config) 130 if l.config == nil { 131 return mangos.ErrTLSNoConfig 132 } 133 if l.config.Certificates == nil || len(l.config.Certificates) == 0 { 134 return mangos.ErrTLSNoCert 135 } 136 137 if l.listener, err = net.ListenTCP("tcp", l.addr); err != nil { 138 return err 139 } 140 141 l.bound = l.listener.Addr() 142 143 return nil 144 } 145 146 func (l *listener) Address() string { 147 if b := l.bound; b != nil { 148 return "tls+tcp://" + b.String() 149 } 150 return "tls+tcp://" + l.addr.String() 151 } 152 153 func (l *listener) Accept() (mangos.Pipe, error) { 154 155 tconn, err := l.listener.AcceptTCP() 156 if err != nil { 157 return nil, err 158 } 159 160 if err = l.opts.configTCP(tconn); err != nil { 161 tconn.Close() 162 return nil, err 163 } 164 165 conn := tls.Server(tconn, l.config) 166 if err = conn.Handshake(); err != nil { 167 conn.Close() 168 return nil, err 169 } 170 return mangos.NewConnPipe(conn, l.sock, 171 mangos.PropTLSConnState, conn.ConnectionState()) 172 } 173 174 func (l *listener) Close() error { 175 l.listener.Close() 176 return nil 177 } 178 179 func (l *listener) SetOption(n string, v interface{}) error { 180 return l.opts.set(n, v) 181 } 182 183 func (l *listener) GetOption(n string) (interface{}, error) { 184 return l.opts.get(n) 185 } 186 187 type tlsTran struct { 188 config *tls.Config 189 localAddr net.Addr 190 } 191 192 func (t *tlsTran) Scheme() string { 193 return "tls+tcp" 194 } 195 196 func (t *tlsTran) NewDialer(addr string, sock mangos.Socket) (mangos.PipeDialer, error) { 197 var err error 198 199 if addr, err = mangos.StripScheme(t, addr); err != nil { 200 return nil, err 201 } 202 203 // check to ensure the provided addr resolves correctly. 204 if _, err = mangos.ResolveTCPAddr(addr); err != nil { 205 return nil, err 206 } 207 208 d := &dialer{sock: sock, opts: newOptions(t), addr: addr} 209 210 return d, nil 211 } 212 213 // NewAccepter implements the Transport NewAccepter method. 214 func (t *tlsTran) NewListener(addr string, sock mangos.Socket) (mangos.PipeListener, error) { 215 var err error 216 l := &listener{sock: sock, opts: newOptions(t)} 217 218 if addr, err = mangos.StripScheme(t, addr); err != nil { 219 return nil, err 220 } 221 if l.addr, err = mangos.ResolveTCPAddr(addr); err != nil { 222 return nil, err 223 } 224 225 return l, nil 226 } 227 228 // NewTransport allocates a new inproc transport. 229 func NewTransport() mangos.Transport { 230 return &tlsTran{} 231 }