2017-07-10 17:32:42 +02:00
|
|
|
package netutil
|
Publish the new version :airplane: | Look description please!
# FAQ
### Looking for free support?
http://support.iris-go.com
https://kataras.rocket.chat/channel/iris
### Looking for previous versions?
https://github.com/kataras/iris#version
### Should I upgrade my Iris?
Developers are not forced to upgrade if they don't really need it. Upgrade whenever you feel ready.
> Iris uses the [vendor directory](https://docs.google.com/document/d/1Bz5-UB7g2uPBdOx-rw5t9MxJwkfpx90cqG9AFL0JAYo) feature, so you get truly reproducible builds, as this method guards against upstream renames and deletes.
**How to upgrade**: Open your command-line and execute this command: `go get -u github.com/kataras/iris`.
For further installation support, please click [here](http://support.iris-go.com/d/16-how-to-install-iris-web-framework).
### About our new home page
http://iris-go.com
Thanks to [Santosh Anand](https://github.com/santoshanand) the http://iris-go.com has been upgraded and it's really awesome!
[Santosh](https://github.com/santoshanand) is a freelancer, he has a great knowledge of nodejs and express js, Android, iOS, React Native, Vue.js etc, if you need a developer to find or create a solution for your problem or task, please contact with him.
The amount of the next two or three donations you'll send they will be immediately transferred to his own account balance, so be generous please!
Read more at https://github.com/kataras/iris/blob/master/HISTORY.md
Former-commit-id: eec2d71bbe011d6b48d2526eb25919e36e5ad94e
2017-06-03 22:22:52 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/tls"
|
|
|
|
"net"
|
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/kataras/iris/core/errors"
|
|
|
|
"golang.org/x/crypto/acme/autocert"
|
|
|
|
)
|
|
|
|
|
|
|
|
// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
|
|
|
|
// connections. It's used by Run, ListenAndServe and ListenAndServeTLS so
|
|
|
|
// dead TCP connections (e.g. closing laptop mid-download) eventually
|
|
|
|
// go away.
|
|
|
|
//
|
|
|
|
// A raw copy of standar library.
|
|
|
|
type tcpKeepAliveListener struct {
|
|
|
|
*net.TCPListener
|
|
|
|
}
|
|
|
|
|
|
|
|
// Accept accepts tcp connections aka clients.
|
|
|
|
func (l tcpKeepAliveListener) Accept() (c net.Conn, err error) {
|
|
|
|
tc, err := l.AcceptTCP()
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
tc.SetKeepAlive(true)
|
|
|
|
tc.SetKeepAlivePeriod(3 * time.Minute)
|
|
|
|
return tc, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
errPortAlreadyUsed = errors.New("port is already used")
|
|
|
|
errRemoveUnix = errors.New("unexpected error when trying to remove unix socket file. Addr: %s | Trace: %s")
|
|
|
|
errChmod = errors.New("cannot chmod %#o for %q: %s")
|
|
|
|
errCertKeyMissing = errors.New("you should provide certFile and keyFile for TLS/SSL")
|
|
|
|
errParseTLS = errors.New("couldn't load TLS, certFile=%q, keyFile=%q. Trace: %s")
|
|
|
|
)
|
|
|
|
|
|
|
|
// TCP returns a new tcp(ipv6 if supported by network) and an error on failure.
|
|
|
|
func TCP(addr string) (net.Listener, error) {
|
|
|
|
l, err := net.Listen("tcp", addr)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return l, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// TCPKeepAlive returns a new tcp keep alive Listener and an error on failure.
|
|
|
|
func TCPKeepAlive(addr string) (ln net.Listener, err error) {
|
|
|
|
// if strings.HasPrefix(addr, "127.0.0.1") {
|
|
|
|
// // it's ipv4, use ipv4 tcp listener instead of the default ipv6. Don't.
|
|
|
|
// ln, err = net.Listen("tcp4", addr)
|
|
|
|
// } else {
|
|
|
|
// ln, err = TCP(addr)
|
|
|
|
// }
|
|
|
|
|
|
|
|
ln, err = TCP(addr)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return tcpKeepAliveListener{ln.(*net.TCPListener)}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// UNIX returns a new unix(file) Listener.
|
|
|
|
func UNIX(socketFile string, mode os.FileMode) (net.Listener, error) {
|
|
|
|
if errOs := os.Remove(socketFile); errOs != nil && !os.IsNotExist(errOs) {
|
|
|
|
return nil, errRemoveUnix.Format(socketFile, errOs.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
l, err := net.Listen("unix", socketFile)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errPortAlreadyUsed.AppendErr(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = os.Chmod(socketFile, mode); err != nil {
|
|
|
|
return nil, errChmod.Format(mode, socketFile, err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
return l, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// TLS returns a new TLS Listener and an error on failure.
|
|
|
|
func TLS(addr, certFile, keyFile string) (net.Listener, error) {
|
|
|
|
if certFile == "" || keyFile == "" {
|
|
|
|
return nil, errCertKeyMissing
|
|
|
|
}
|
|
|
|
|
|
|
|
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errParseTLS.Format(certFile, keyFile, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return CERT(addr, cert)
|
|
|
|
}
|
|
|
|
|
|
|
|
// CERT returns a listener which contans tls.Config with the provided certificate, use for ssl.
|
|
|
|
func CERT(addr string, cert tls.Certificate) (net.Listener, error) {
|
|
|
|
l, err := net.Listen("tcp", addr)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
tlsConfig := &tls.Config{
|
|
|
|
Certificates: []tls.Certificate{cert},
|
|
|
|
PreferServerCipherSuites: true,
|
|
|
|
}
|
|
|
|
return tls.NewListener(l, tlsConfig), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// LETSENCRYPT returns a new Automatic TLS Listener using letsencrypt.org service
|
|
|
|
// receives three parameters,
|
|
|
|
// the first is the host of the server,
|
|
|
|
// second can be the server name(domain) or empty if skip verification is the expected behavior (not recommended)
|
|
|
|
// and the third is optionally, the cache directory, if you skip it then the cache directory is "./certcache"
|
|
|
|
// if you want to disable cache directory then simple give it a value of empty string ""
|
|
|
|
//
|
|
|
|
// does NOT supports localhost domains for testing.
|
|
|
|
//
|
|
|
|
// this is the recommended function to use when you're ready for production state.
|
|
|
|
func LETSENCRYPT(addr string, serverName string, cacheDirOptional ...string) (net.Listener, error) {
|
|
|
|
if portIdx := strings.IndexByte(addr, ':'); portIdx == -1 {
|
|
|
|
addr += ":443"
|
|
|
|
}
|
|
|
|
|
|
|
|
l, err := TCP(addr)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
cacheDir := "./certcache"
|
|
|
|
if len(cacheDirOptional) > 0 {
|
|
|
|
cacheDir = cacheDirOptional[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
m := autocert.Manager{
|
|
|
|
Prompt: autocert.AcceptTOS,
|
|
|
|
} // HostPolicy is missing, if user wants it, then she/he should manually
|
|
|
|
|
|
|
|
if cacheDir == "" {
|
|
|
|
// then the user passed empty by own will, then I guess she/he doesnt' want any cache directory
|
|
|
|
} else {
|
|
|
|
m.Cache = autocert.DirCache(cacheDir)
|
|
|
|
}
|
|
|
|
tlsConfig := &tls.Config{GetCertificate: m.GetCertificate}
|
|
|
|
|
|
|
|
// use InsecureSkipVerify or ServerName to a value
|
|
|
|
if serverName == "" {
|
|
|
|
// if server name is invalid then bypass it
|
|
|
|
tlsConfig.InsecureSkipVerify = true
|
|
|
|
} else {
|
|
|
|
tlsConfig.ServerName = serverName
|
|
|
|
}
|
|
|
|
|
|
|
|
return tls.NewListener(l, tlsConfig), nil
|
|
|
|
}
|