first init
This commit is contained in:
116
tls_utils.go
Normal file
116
tls_utils.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package modbus
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// LoadCertPool loads a certificate store from a file into a CertPool object.
|
||||
func LoadCertPool(filePath string) (cp *x509.CertPool, err error) {
|
||||
var buf []byte
|
||||
|
||||
// read the entire cert store, which may contain zero, one
|
||||
// or more certificates
|
||||
buf, err = ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(buf) == 0 {
|
||||
err = fmt.Errorf("%v: empty file", filePath)
|
||||
return
|
||||
}
|
||||
|
||||
// add these certs to the pool
|
||||
cp = x509.NewCertPool()
|
||||
cp.AppendCertsFromPEM(buf)
|
||||
|
||||
// let the caller know if no usable certificate was found
|
||||
if len(cp.Subjects()) == 0 {
|
||||
err = fmt.Errorf("%v: no certificate found", filePath)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// tlsSockWrapper wraps a TLS socket to work around odd error handling in
|
||||
// TLSConn on internal connection state corruption.
|
||||
// tlsSockWrapper implements the net.Conn interface to allow its
|
||||
// use by the modbus TCP transport.
|
||||
type tlsSockWrapper struct {
|
||||
sock net.Conn
|
||||
}
|
||||
|
||||
func newTLSSockWrapper(sock net.Conn) (tsw *tlsSockWrapper) {
|
||||
tsw = &tlsSockWrapper{
|
||||
sock: sock,
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (tsw *tlsSockWrapper) Read(buf []byte) (rlen int, err error) {
|
||||
rlen, err = tsw.sock.Read(buf)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (tsw *tlsSockWrapper) Write(buf []byte) (wlen int, err error) {
|
||||
wlen, err = tsw.sock.Write(buf)
|
||||
|
||||
// since write timeouts corrupt the internal state of TLS sockets,
|
||||
// any subsequent read/write operation will fail and return the same write
|
||||
// timeout error (see https://pkg.go.dev/crypto/tls#Conn.SetWriteDeadline).
|
||||
// this isn't all that helpful to clients, which may be tricked into
|
||||
// retrying forever, treating timeout errors as transient.
|
||||
// to avoid this, close the TLS socket after the first write timeout.
|
||||
// this ensures that clients 1) get a timeout error on the first write timeout
|
||||
// and 2) get an ErrNetClosing "use of closed network connection" on subsequent
|
||||
// operations.
|
||||
if err != nil && os.IsTimeout(err) {
|
||||
tsw.sock.Close()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (tsw *tlsSockWrapper) Close() (err error) {
|
||||
err = tsw.sock.Close()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (tsw *tlsSockWrapper) SetDeadline(deadline time.Time) (err error) {
|
||||
err = tsw.sock.SetDeadline(deadline)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (tsw *tlsSockWrapper) SetReadDeadline(deadline time.Time) (err error) {
|
||||
err = tsw.sock.SetReadDeadline(deadline)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (tsw *tlsSockWrapper) SetWriteDeadline(deadline time.Time) (err error) {
|
||||
err = tsw.sock.SetWriteDeadline(deadline)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (tsw *tlsSockWrapper) LocalAddr() (addr net.Addr) {
|
||||
addr = tsw.sock.LocalAddr()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (tsw *tlsSockWrapper) RemoteAddr() (addr net.Addr) {
|
||||
addr = tsw.sock.RemoteAddr()
|
||||
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user