2018-08-09 18:34:09 +00:00
|
|
|
// Package mnet extends the standard package with extra functionality which is
|
|
|
|
// commonly useful
|
|
|
|
package mnet
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net"
|
2019-01-11 22:47:30 +00:00
|
|
|
|
|
|
|
"github.com/mediocregopher/mediocre-go-lib/mcfg"
|
|
|
|
"github.com/mediocregopher/mediocre-go-lib/mctx"
|
|
|
|
"github.com/mediocregopher/mediocre-go-lib/mlog"
|
|
|
|
"github.com/mediocregopher/mediocre-go-lib/mrun"
|
2018-08-09 18:34:09 +00:00
|
|
|
)
|
|
|
|
|
2019-01-13 02:01:16 +00:00
|
|
|
type listener struct {
|
|
|
|
net.Listener
|
|
|
|
log *mlog.Logger
|
|
|
|
}
|
|
|
|
|
2019-01-13 01:11:22 +00:00
|
|
|
// MListen returns a Listener which will be initialized when the start event is
|
|
|
|
// triggered on ctx (see mrun.Start), and closed when the stop event is
|
|
|
|
// triggered on ctx (see mrun.Stop).
|
2019-01-11 22:47:30 +00:00
|
|
|
//
|
|
|
|
// network defaults to "tcp" if empty. defaultAddr defaults to ":0" if empty,
|
|
|
|
// and will be configurable via mcfg.
|
2019-01-13 01:11:22 +00:00
|
|
|
func MListen(ctx mctx.Context, network, defaultAddr string) net.Listener {
|
2019-01-11 22:47:30 +00:00
|
|
|
if network == "" {
|
|
|
|
network = "tcp"
|
|
|
|
}
|
|
|
|
if defaultAddr == "" {
|
|
|
|
defaultAddr = ":0"
|
|
|
|
}
|
|
|
|
addr := mcfg.String(ctx, "addr", defaultAddr, network+" address to listen on in format [host]:port. If port is 0 then a random one will be chosen")
|
|
|
|
|
2019-01-13 02:01:16 +00:00
|
|
|
l := new(listener)
|
|
|
|
l.log = mlog.From(ctx).WithKV(l)
|
|
|
|
|
2019-01-11 22:47:30 +00:00
|
|
|
mrun.OnStart(ctx, func(mctx.Context) error {
|
|
|
|
var err error
|
|
|
|
if l.Listener, err = net.Listen(network, *addr); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-01-13 02:01:16 +00:00
|
|
|
l.log.Info("listening")
|
2019-01-11 22:47:30 +00:00
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
2019-01-13 01:11:22 +00:00
|
|
|
// TODO track connections and wait for them to complete before shutting
|
|
|
|
// down?
|
|
|
|
mrun.OnStop(ctx, func(mctx.Context) error {
|
2019-01-13 02:01:16 +00:00
|
|
|
l.log.Info("stopping listener")
|
2019-01-13 01:11:22 +00:00
|
|
|
return l.Close()
|
|
|
|
})
|
|
|
|
|
2019-01-13 02:01:16 +00:00
|
|
|
return l
|
|
|
|
}
|
|
|
|
|
2019-01-15 03:32:26 +00:00
|
|
|
func (l *listener) KV() map[string]interface{} {
|
|
|
|
return map[string]interface{}{"addr": l.Addr().String()}
|
2019-01-11 22:47:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2018-08-09 18:34:09 +00:00
|
|
|
func mustGetCIDRNetwork(cidr string) *net.IPNet {
|
|
|
|
_, n, err := net.ParseCIDR(cidr)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return n
|
|
|
|
}
|
|
|
|
|
|
|
|
// https://en.wikipedia.org/wiki/Reserved_IP_addresses
|
|
|
|
|
|
|
|
var reservedCIDRs4 = []*net.IPNet{
|
|
|
|
mustGetCIDRNetwork("0.0.0.0/8"), // current network
|
|
|
|
mustGetCIDRNetwork("10.0.0.0/8"), // private network
|
|
|
|
mustGetCIDRNetwork("100.64.0.0/10"), // private network
|
|
|
|
mustGetCIDRNetwork("127.0.0.0/8"), // localhost
|
|
|
|
mustGetCIDRNetwork("169.254.0.0/16"), // link-local
|
|
|
|
mustGetCIDRNetwork("172.16.0.0/12"), // private network
|
|
|
|
mustGetCIDRNetwork("192.0.0.0/24"), // IETF protocol assignments
|
|
|
|
mustGetCIDRNetwork("192.0.2.0/24"), // documentation and examples
|
|
|
|
mustGetCIDRNetwork("192.88.99.0/24"), // 6to4 Relay
|
|
|
|
mustGetCIDRNetwork("192.168.0.0/16"), // private network
|
|
|
|
mustGetCIDRNetwork("198.18.0.0/15"), // private network
|
|
|
|
mustGetCIDRNetwork("198.51.100.0/24"), // documentation and examples
|
|
|
|
mustGetCIDRNetwork("203.0.113.0/24"), // documentation and examples
|
|
|
|
mustGetCIDRNetwork("224.0.0.0/4"), // IP multicast
|
|
|
|
mustGetCIDRNetwork("240.0.0.0/4"), // reserved
|
|
|
|
mustGetCIDRNetwork("255.255.255.255/32"), // limited broadcast address
|
|
|
|
}
|
|
|
|
|
|
|
|
var reservedCIDRs6 = []*net.IPNet{
|
|
|
|
mustGetCIDRNetwork("::/128"), // unspecified address
|
|
|
|
mustGetCIDRNetwork("::1/128"), // loopback address
|
|
|
|
mustGetCIDRNetwork("100::/64"), // discard prefix
|
|
|
|
mustGetCIDRNetwork("2001::/32"), // Teredo tunneling
|
|
|
|
mustGetCIDRNetwork("2001:20::/28"), // ORCHID v2
|
|
|
|
mustGetCIDRNetwork("2001:db8::/32"), // documentation and examples
|
|
|
|
mustGetCIDRNetwork("2002::/16"), // 6to4 addressing
|
|
|
|
mustGetCIDRNetwork("fc00::/7"), // unique local
|
|
|
|
mustGetCIDRNetwork("fe80::/10"), // link local
|
|
|
|
mustGetCIDRNetwork("ff00::/8"), // multicast
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsReservedIP returns true if the given valid IP is part of a reserved IP
|
|
|
|
// range.
|
|
|
|
func IsReservedIP(ip net.IP) bool {
|
|
|
|
containedBy := func(cidrs []*net.IPNet) bool {
|
|
|
|
for _, cidr := range cidrs {
|
|
|
|
if cidr.Contains(ip) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if ip.To4() != nil {
|
|
|
|
return containedBy(reservedCIDRs4)
|
|
|
|
}
|
|
|
|
return containedBy(reservedCIDRs6)
|
|
|
|
}
|