github.com/influx6/npkg@v0.8.8/nnet/nnet.go (about)

     1  package nnet
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"crypto/tls"
     7  	"crypto/x509"
     8  	"encoding/binary"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  	"io/ioutil"
    13  	"log"
    14  	"net"
    15  	"net/http"
    16  	"net/url"
    17  	"regexp"
    18  	"strconv"
    19  	"strings"
    20  	"time"
    21  
    22  	"github.com/influx6/npkg/nerror"
    23  	"github.com/influx6/npkg/nunsafe"
    24  )
    25  
    26  var (
    27  	noTime = time.Time{}
    28  )
    29  
    30  // TimedConn implements a wrapper around a net.Conn which guards giving connection
    31  // with appropriate read/write timeout.
    32  type TimedConn struct {
    33  	net.Conn
    34  	readTimeout  time.Duration
    35  	writeTimeout time.Duration
    36  }
    37  
    38  // NewTimedConn returns a new instance of a TimedConn.
    39  func NewTimedConn(conn net.Conn, rd time.Duration, wd time.Duration) *TimedConn {
    40  	return &TimedConn{
    41  		Conn:         conn,
    42  		readTimeout:  rd,
    43  		writeTimeout: wd,
    44  	}
    45  }
    46  
    47  // Write calls the underline connection read with provided timeout.
    48  func (c *TimedConn) Write(b []byte) (int, error) {
    49  	var writeErr = c.Conn.SetWriteDeadline(time.Now().Add(c.writeTimeout))
    50  	if writeErr != nil {
    51  		return 0, writeErr
    52  	}
    53  
    54  	var writeCount, err = c.Conn.Write(b)
    55  	if err != nil {
    56  		return writeCount, err
    57  	}
    58  
    59  	var resetErr = c.Conn.SetWriteDeadline(noTime)
    60  	if resetErr != nil {
    61  		return writeCount, resetErr
    62  	}
    63  
    64  	return writeCount, nil
    65  }
    66  
    67  // Read calls the underline connection read with provided timeout.
    68  func (c *TimedConn) Read(b []byte) (int, error) {
    69  	var readErr = c.Conn.SetReadDeadline(time.Now().Add(c.readTimeout))
    70  	if readErr != nil {
    71  		return 0, readErr
    72  	}
    73  
    74  	var readCount, err = c.Conn.Read(b)
    75  	if err != nil {
    76  		return readCount, err
    77  	}
    78  
    79  	var resetErr = c.Conn.SetReadDeadline(noTime)
    80  	if resetErr != nil {
    81  		return readCount, resetErr
    82  	}
    83  
    84  	return readCount, nil
    85  }
    86  
    87  // GetAddr takes the giving address string and if it has no ip or use the
    88  // zeroth ip format, then modifies the ip with the current systems ip.
    89  func GetAddr(addr string) string {
    90  	if addr == "" {
    91  		if real, err := GetMainIP(); err == nil {
    92  			return real + ":0"
    93  		}
    94  	}
    95  
    96  	ip, port, err := net.SplitHostPort(addr)
    97  	if err == nil && (ip == "" || ip == "0.0.0.0") {
    98  		if realIP, err := GetMainIP(); err == nil {
    99  			return net.JoinHostPort(realIP, port)
   100  		}
   101  	}
   102  
   103  	return addr
   104  }
   105  
   106  var (
   107  	zeros = regexp.MustCompile("^0+")
   108  )
   109  
   110  // ResolveAddr returns an appropriate address by validating the
   111  // presence of the ip and port, if non is found, it uses the default
   112  // 0.0.0.0 address and assigns a port if non is found.
   113  func ResolveAddr(addr string) string {
   114  	var scheme string
   115  	host, port, err := net.SplitHostPort(addr)
   116  	if err != nil {
   117  		uri, err := url.Parse(addr)
   118  		if err != nil {
   119  			return "0.0.0.0:" + strconv.Itoa(FreePort())
   120  		}
   121  
   122  		if strings.Contains(uri.Host, ":") {
   123  			sub := strings.Index(uri.Host, ":")
   124  			uri.Host = uri.Host[0:sub]
   125  		}
   126  
   127  		scheme = uri.Scheme
   128  		host = uri.Host
   129  		port = uri.Port()
   130  	}
   131  
   132  	if host == "" {
   133  		host = "0.0.0.0"
   134  	}
   135  
   136  	if port == "" || zeros.MatchString(port) {
   137  		port = strconv.Itoa(FreePort())
   138  	}
   139  
   140  	if scheme == "" {
   141  		return host + ":" + port
   142  	}
   143  
   144  	return scheme + "://" + host + ":" + port
   145  }
   146  
   147  func IPDotNotation2LongNotation(ipAddr string) (uint32, error) {
   148  	ip := net.ParseIP(ipAddr)
   149  	if ip == nil {
   150  		return 0, errors.New("wrong ipAddr format")
   151  	}
   152  	ip = ip.To4()
   153  	return binary.BigEndian.Uint32(ip), nil
   154  }
   155  
   156  func IPLongNotation2IPFromString(ipLong string) (net.IP, error) {
   157  	var parsedVal, parseErr = strconv.ParseUint(ipLong, 10, 32)
   158  	if parseErr != nil {
   159  		return nil, nerror.WrapOnly(parseErr)
   160  	}
   161  	return IPLongNotation2IP(uint32(parsedVal)), nil
   162  }
   163  
   164  func IPLongNotation2IP(ipLong uint32) net.IP {
   165  	ipByte := make([]byte, 4)
   166  	binary.BigEndian.PutUint32(ipByte, ipLong)
   167  	return net.IP(ipByte)
   168  }
   169  
   170  func IPLongNotation2DotNotation(ipLong uint32) string {
   171  	ipByte := make([]byte, 4)
   172  	binary.BigEndian.PutUint32(ipByte, ipLong)
   173  	ip := net.IP(ipByte)
   174  	return ip.String()
   175  }
   176  
   177  func IntToIP(ip uint32) string {
   178  	result := make(net.IP, 4)
   179  	result[0] = byte(ip)
   180  	result[1] = byte(ip >> 8)
   181  	result[2] = byte(ip >> 16)
   182  	result[3] = byte(ip >> 24)
   183  	return result.String()
   184  }
   185  
   186  func IsTargetBetweenUsingCDIR(cdir string, to net.IP) (bool, error) {
   187  	if to == nil {
   188  		return false, nerror.New("target cant be nil")
   189  	}
   190  
   191  	var _, subnet, subErr = net.ParseCIDR(cdir)
   192  	if subErr != nil {
   193  		return false, nerror.WrapOnly(subErr)
   194  	}
   195  
   196  	return subnet.Contains(to), nil
   197  }
   198  
   199  func IsTargetBetween(target net.IP, from net.IP, to net.IP) bool {
   200  	if from == nil || to == nil || target == nil {
   201  		return false
   202  	}
   203  
   204  	from16 := from.To16()
   205  	to16 := to.To16()
   206  	test16 := target.To16()
   207  	if from16 == nil || to16 == nil || test16 == nil {
   208  		return false
   209  	}
   210  
   211  	if bytes.Compare(test16, from16) >= 0 && bytes.Compare(test16, to16) <= 0 {
   212  		return true
   213  	}
   214  	return false
   215  }
   216  
   217  // FreePort returns a random free port from the underline system for use in a network socket.
   218  func FreePort() int {
   219  	addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
   220  	if err != nil {
   221  		log.Fatal(err)
   222  		return 0
   223  	}
   224  
   225  	l, err := net.ListenTCP("tcp", addr)
   226  	if err != nil {
   227  		log.Fatal(err)
   228  		return 0
   229  	}
   230  
   231  	defer l.Close()
   232  
   233  	return l.Addr().(*net.TCPAddr).Port
   234  }
   235  
   236  //==============================================================================
   237  
   238  // UpgradeConnToTLS upgrades the giving tcp connection to use a tls based connection
   239  // encrypted by the giving tls.Config.
   240  func UpgradeConnToTLS(conn net.Conn, cm *tls.Config) (net.Conn, error) {
   241  	if cm == nil {
   242  		return conn, nil
   243  	}
   244  
   245  	if cm.ServerName == "" {
   246  		h, _, _ := net.SplitHostPort(conn.RemoteAddr().String())
   247  		cm.ServerName = h
   248  	}
   249  
   250  	tlsConn := tls.Client(conn, cm)
   251  
   252  	if err := tlsConn.Handshake(); err != nil {
   253  		return conn, err
   254  	}
   255  
   256  	return tlsConn, nil
   257  }
   258  
   259  //================================================================================
   260  
   261  //LoadTLS loads a tls.Config from a key and cert file path
   262  func LoadTLS(cert string, key string, ca string) (*tls.Config, error) {
   263  	var config *tls.Config
   264  	config.MinVersion = tls.VersionTLS12
   265  	config.Certificates = make([]tls.Certificate, 1)
   266  
   267  	c, err := tls.LoadX509KeyPair(cert, key)
   268  	if err != nil {
   269  		return nil, err
   270  	}
   271  
   272  	c.Leaf, err = x509.ParseCertificate(c.Certificate[0])
   273  	if err != nil {
   274  		return nil, err
   275  	}
   276  
   277  	if ca != "" {
   278  		rootPEM, err := ioutil.ReadFile(ca)
   279  		if err != nil {
   280  			return nil, err
   281  		}
   282  
   283  		if rootPEM == nil {
   284  			return nil, errors.New("Empty perm file")
   285  		}
   286  
   287  		pool := x509.NewCertPool()
   288  		if !pool.AppendCertsFromPEM(rootPEM) {
   289  			return nil, errors.New("Failed to append perm file data")
   290  		}
   291  
   292  		config.RootCAs = pool
   293  	}
   294  
   295  	config.Certificates[0] = c
   296  	return config, nil
   297  }
   298  
   299  // TLSVersion returns a string version number based on the tls version int.
   300  func TLSVersion(ver uint16) string {
   301  	switch ver {
   302  	case tls.VersionTLS10:
   303  		return "1.0"
   304  	case tls.VersionTLS11:
   305  		return "1.1"
   306  	case tls.VersionTLS12:
   307  		return "1.2"
   308  	}
   309  	return fmt.Sprintf("Unknown [%x]", ver)
   310  }
   311  
   312  // TLSCipher returns a cipher string version based on the supplied hex value.
   313  func TLSCipher(cs uint16) string {
   314  	switch cs {
   315  	case 0x0005:
   316  		return "TLS_RSA_WITH_RC4_128_SHA"
   317  	case 0x000a:
   318  		return "TLS_RSA_WITH_3DES_EDE_CBC_SHA"
   319  	case 0x002f:
   320  		return "TLS_RSA_WITH_AES_128_CBC_SHA"
   321  	case 0x0035:
   322  		return "TLS_RSA_WITH_AES_256_CBC_SHA"
   323  	case 0xc007:
   324  		return "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"
   325  	case 0xc009:
   326  		return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"
   327  	case 0xc00a:
   328  		return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"
   329  	case 0xc011:
   330  		return "TLS_ECDHE_RSA_WITH_RC4_128_SHA"
   331  	case 0xc012:
   332  		return "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"
   333  	case 0xc013:
   334  		return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"
   335  	case 0xc014:
   336  		return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"
   337  	case 0xc02f:
   338  		return "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
   339  	case 0xc02b:
   340  		return "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
   341  	case 0xc030:
   342  		return "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
   343  	case 0xc02c:
   344  		return "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
   345  	}
   346  	return fmt.Sprintf("Unknown [%x]", cs)
   347  }
   348  
   349  //==============================================================================
   350  
   351  // MakeListener returns a new net.Listener requests.
   352  func MakeListener(protocol string, addr string, conf *tls.Config) (net.Listener, error) {
   353  	var l net.Listener
   354  	var err error
   355  
   356  	if conf != nil {
   357  		l, err = tls.Listen(protocol, addr, conf)
   358  	} else {
   359  		l, err = net.Listen(protocol, addr)
   360  	}
   361  
   362  	if err != nil {
   363  		return nil, err
   364  	}
   365  
   366  	return l, nil
   367  }
   368  
   369  // TCPListener returns a new net.Listener requests.
   370  func TCPListener(addr string, conf *tls.Config) (net.Listener, error) {
   371  	var l net.Listener
   372  	var err error
   373  
   374  	if conf != nil {
   375  		l, err = tls.Listen("tcp", addr, conf)
   376  	} else {
   377  		l, err = net.Listen("tcp", addr)
   378  	}
   379  
   380  	if err != nil {
   381  		return nil, err
   382  	}
   383  
   384  	return NewKeepAliveListener(l), nil
   385  }
   386  
   387  //NewHTTPServer returns a new http.Server using the provided listener
   388  func NewHTTPServer(l net.Listener, handle http.Handler, c *tls.Config) (*http.Server, net.Listener, error) {
   389  	s := &http.Server{
   390  		Addr:           l.Addr().String(),
   391  		Handler:        handle,
   392  		ReadTimeout:    10 * time.Second,
   393  		WriteTimeout:   10 * time.Second,
   394  		MaxHeaderBytes: 1 << 20,
   395  		TLSConfig:      c,
   396  	}
   397  
   398  	log.Printf("Serving http connection on: %+q\n", s.Addr)
   399  	go func() {
   400  		if err := s.Serve(l); err != nil {
   401  			log.Fatal(err)
   402  		}
   403  	}()
   404  
   405  	return s, l, nil
   406  }
   407  
   408  type keepAliveListener struct {
   409  	net.Listener
   410  }
   411  
   412  // NewKeepAliveListener returns a new net.Listener from underline net.TCPListener
   413  // where produced net.Conns respect keep alive regulations.
   414  func NewKeepAliveListener(tl net.Listener) net.Listener {
   415  	return &keepAliveListener{
   416  		Listener: tl,
   417  	}
   418  }
   419  
   420  func (kl *keepAliveListener) Accept() (net.Conn, error) {
   421  	var tl, isTL = kl.Listener.(*net.TCPListener)
   422  	if !isTL {
   423  		return kl.Listener.Accept()
   424  	}
   425  
   426  	conn, err := tl.AcceptTCP()
   427  	if err != nil {
   428  		return nil, err
   429  	}
   430  
   431  	if err := conn.SetKeepAlive(true); err != nil {
   432  		return conn, err
   433  	}
   434  	if err := conn.SetKeepAlivePeriod(2 * time.Minute); err != nil {
   435  		return conn, err
   436  	}
   437  
   438  	return conn, nil
   439  }
   440  
   441  // NewConn returns a tls.Conn object from the provided parameters.
   442  func NewConn(protocol string, addr string) (net.Conn, error) {
   443  	newConn, err := net.Dial(protocol, addr)
   444  	if err != nil {
   445  		return nil, err
   446  	}
   447  
   448  	return newConn, nil
   449  }
   450  
   451  // TLSConn returns a tls.Conn object from the provided parameters.
   452  func TLSConn(protocol string, addr string, conf *tls.Config) (*tls.Conn, error) {
   453  	newTLS, err := tls.Dial(protocol, addr, conf)
   454  	if err != nil {
   455  		return nil, err
   456  	}
   457  
   458  	return newTLS, nil
   459  }
   460  
   461  // TLSFromConn returns a new tls.Conn using the address and the certicates from
   462  // the provided *tls.Conn.
   463  func TLSFromConn(tl *tls.Conn, addr string) (*tls.Conn, error) {
   464  	var conf *tls.Config
   465  
   466  	if err := tl.Handshake(); err != nil {
   467  		return nil, err
   468  	}
   469  
   470  	state := tl.ConnectionState()
   471  	pool := x509.NewCertPool()
   472  
   473  	for _, v := range state.PeerCertificates {
   474  		pool.AddCert(v)
   475  	}
   476  
   477  	conf = &tls.Config{RootCAs: pool}
   478  	newTLS, err := tls.Dial("tcp", addr, conf)
   479  	if err != nil {
   480  		return nil, err
   481  	}
   482  
   483  	return newTLS, nil
   484  }
   485  
   486  // ProxyHTTPRequest copies a http request from a src net.Conn connection to a
   487  // destination net.Conn.
   488  func ProxyHTTPRequest(src net.Conn, dest net.Conn) error {
   489  	reader := bufio.NewReader(src)
   490  	req, err := http.ReadRequest(reader)
   491  	if err != nil {
   492  		return err
   493  	}
   494  
   495  	if req == nil {
   496  		return errors.New("No Request Read")
   497  	}
   498  
   499  	if err = req.Write(dest); err != nil {
   500  		return err
   501  	}
   502  
   503  	resread := bufio.NewReader(dest)
   504  	res, err := http.ReadResponse(resread, req)
   505  	if err != nil {
   506  		return err
   507  	}
   508  
   509  	if res != nil {
   510  		return errors.New("No Response Read")
   511  	}
   512  
   513  	return res.Write(src)
   514  }
   515  
   516  // hop headers, These are removed when sent to the backend
   517  // http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html.
   518  var hopHeaders = []string{
   519  	"Connection",
   520  	"Keep-Alive",
   521  	"Proxy-Authenticate",
   522  	"Proxy-Authorization",
   523  	"Te", // canonicalized version of "TE"
   524  	"Trailers",
   525  	"Transfer-Encoding",
   526  	"Upgrade",
   527  }
   528  
   529  // ConnToHTTP proxies a requests from a net.Conn to a destination request, writing
   530  // the response to provided ResponseWriter.
   531  func ConnToHTTP(src net.Conn, destReq *http.Request, destRes http.ResponseWriter) error {
   532  	reader := bufio.NewReader(src)
   533  	req, err := http.ReadRequest(reader)
   534  	if err != nil {
   535  		return err
   536  	}
   537  
   538  	destReq.Method = req.Method
   539  
   540  	for key, val := range req.Header {
   541  		destReq.Header.Set(key, strings.Join(val, ","))
   542  	}
   543  
   544  	for _, v := range hopHeaders {
   545  		destReq.Header.Del(v)
   546  	}
   547  
   548  	ip, _, err := net.SplitHostPort(req.RemoteAddr)
   549  	if err != nil {
   550  		return err
   551  	}
   552  
   553  	//add us to the proxy list or makeone
   554  	hops, ok := req.Header["X-Forwarded-For"]
   555  	if ok {
   556  		ip = strings.Join(hops, ",") + "," + ip
   557  	}
   558  
   559  	destReq.Header.Set("X-Forwarded-For", ip)
   560  
   561  	var buf bytes.Buffer
   562  	if req.Body != nil {
   563  		io.Copy(&buf, req.Body)
   564  	}
   565  
   566  	if buf.Len() > 0 {
   567  		destReq.Body = ioutil.NopCloser(&buf)
   568  		destReq.ContentLength = int64(buf.Len())
   569  	}
   570  
   571  	res, err := http.DefaultClient.Do(destReq)
   572  	if err != nil {
   573  		return err
   574  	}
   575  
   576  	for k, v := range res.Header {
   577  		destRes.Header().Add(k, strings.Join(v, ","))
   578  	}
   579  
   580  	return res.Write(destRes)
   581  }
   582  
   583  // HTTPToConn proxies a src Request to a net.Con connection and writes back
   584  // the response to the src Response.
   585  func HTTPToConn(srcReq *http.Request, srcRes http.ResponseWriter, dest net.Conn) error {
   586  	if err := srcReq.Write(dest); err != nil {
   587  		return err
   588  	}
   589  
   590  	resRead := bufio.NewReader(dest)
   591  	res, err := http.ReadResponse(resRead, srcReq)
   592  	if err != nil {
   593  		return err
   594  	}
   595  
   596  	for key, val := range res.Header {
   597  		srcRes.Header().Set(key, strings.Join(val, ","))
   598  	}
   599  
   600  	srcRes.WriteHeader(res.StatusCode)
   601  
   602  	return res.Write(srcRes)
   603  }
   604  
   605  //==============================================================================
   606  
   607  // GetClustersFriends returns a giving set of routes from the provided port number.
   608  func GetClustersFriends(clusterPort int, routes []*url.URL) ([]*url.URL, error) {
   609  	var cleanRoutes []*url.URL
   610  	cport := strconv.Itoa(clusterPort)
   611  
   612  	selfIPs, err := GetInterfaceIPs()
   613  	if err != nil {
   614  		return nil, err
   615  	}
   616  
   617  	for _, r := range routes {
   618  		host, port, err := net.SplitHostPort(r.Host)
   619  		if err != nil {
   620  			return nil, err
   621  		}
   622  
   623  		ips, err := GetURLIP(host)
   624  		if err != nil {
   625  			return nil, err
   626  		}
   627  
   628  		if cport == port && IsIPInList(selfIPs, ips) {
   629  			continue
   630  		}
   631  
   632  		cleanRoutes = append(cleanRoutes, r)
   633  	}
   634  
   635  	return cleanRoutes, nil
   636  }
   637  
   638  // GetMainIP returns the giving system IP by attempting to connect to a imaginary
   639  // ip and returns the giving system ip.
   640  func GetMainIP() (string, error) {
   641  	udp, err := net.DialTimeout("udp", "8.8.8.8:80", 1*time.Millisecond)
   642  	if udp == nil {
   643  		return "", err
   644  	}
   645  
   646  	defer udp.Close()
   647  
   648  	localAddr := udp.LocalAddr().String()
   649  	ip, _, _ := net.SplitHostPort(localAddr)
   650  
   651  	return ip, nil
   652  }
   653  
   654  // GetExternalIP returns the actual internal external IP of the
   655  // calling system.
   656  func GetExternalIP() (string, error) {
   657  	var response, err = http.Get("http://ipv4bot.whatismyipaddress.com")
   658  	if err != nil {
   659  		return "", nerror.WrapOnly(err)
   660  	}
   661  	defer response.Body.Close()
   662  
   663  	body, err := ioutil.ReadAll(response.Body)
   664  	if err != nil {
   665  		return "", nerror.WrapOnly(err)
   666  	}
   667  
   668  	return nunsafe.Bytes2String(body), nil
   669  }
   670  
   671  // GetMainIPByInterface returns the giving ip of the current system by looping
   672  // through all interfaces returning the first ipv4 found that is not on the
   673  // loopback interface.
   674  func GetMainIPByInterface() (string, error) {
   675  	ifaces, err := net.Interfaces()
   676  	if err != nil {
   677  		return "", err
   678  	}
   679  
   680  	for _, iface := range ifaces {
   681  		if iface.Flags&net.FlagUp == 0 {
   682  			continue // interface down
   683  		}
   684  
   685  		if iface.Flags&net.FlagLoopback != 0 {
   686  			continue // loopback interface
   687  		}
   688  
   689  		addrs, err := iface.Addrs()
   690  		if err != nil {
   691  			continue
   692  		}
   693  
   694  		for _, addr := range addrs {
   695  			var ip net.IP
   696  
   697  			switch v := addr.(type) {
   698  			case *net.IPNet:
   699  				ip = v.IP
   700  			case *net.IPAddr:
   701  				ip = v.IP
   702  			}
   703  
   704  			if ip == nil || ip.IsLoopback() {
   705  				continue
   706  			}
   707  
   708  			ip = ip.To4()
   709  
   710  			if ip == nil {
   711  				continue
   712  			}
   713  
   714  			return ip.String(), nil
   715  		}
   716  	}
   717  
   718  	return "", errors.New("Error: No network connection found")
   719  }
   720  
   721  // IsIPInList returns true/false if the giving ip list were equal.
   722  func IsIPInList(list1 []net.IP, list2 []net.IP) bool {
   723  	for _, ip1 := range list1 {
   724  		for _, ip2 := range list2 {
   725  			if ip1.Equal(ip2) {
   726  				return true
   727  			}
   728  		}
   729  	}
   730  	return false
   731  }
   732  
   733  // GetURLIP returns a giving ip addres if the ip string is not an ip address.
   734  func GetURLIP(ipStr string) ([]net.IP, error) {
   735  	ipList := []net.IP{}
   736  
   737  	ip := net.ParseIP(ipStr)
   738  	if ip != nil {
   739  		ipList = append(ipList, ip)
   740  		return ipList, nil
   741  	}
   742  
   743  	hostAddr, err := net.LookupHost(ipStr)
   744  	if err != nil {
   745  		return nil, err
   746  	}
   747  
   748  	for _, addr := range hostAddr {
   749  		ip = net.ParseIP(addr)
   750  		if ip != nil {
   751  			ipList = append(ipList, ip)
   752  		}
   753  	}
   754  
   755  	return ipList, nil
   756  }
   757  
   758  // GetInterfaceIPs returns the list of IP of the giving interfaces found in the
   759  // system.
   760  func GetInterfaceIPs() ([]net.IP, error) {
   761  	var localIPs []net.IP
   762  
   763  	interfaceAddr, err := net.InterfaceAddrs()
   764  	if err != nil {
   765  		return nil, errors.New("Error getting self referencing addr")
   766  	}
   767  
   768  	for i := 0; i < len(interfaceAddr); i++ {
   769  		interfaceIP, _, _ := net.ParseCIDR(interfaceAddr[i].String())
   770  		if net.ParseIP(interfaceIP.String()) != nil {
   771  			localIPs = append(localIPs, interfaceIP)
   772  		} else {
   773  			err = errors.New("Error getting self referencing addr")
   774  		}
   775  	}
   776  
   777  	if err != nil {
   778  		return nil, err
   779  	}
   780  
   781  	return localIPs, nil
   782  }
   783  
   784  // CopyUDPAddr returns a new copy of a giving UDPAddr.
   785  func CopyUDPAddr(addr *net.UDPAddr) *net.UDPAddr {
   786  	newAddr := new(net.UDPAddr)
   787  	*newAddr = *addr
   788  	newAddr.IP = make(net.IP, len(addr.IP))
   789  	copy(newAddr.IP, addr.IP)
   790  	return newAddr
   791  }
   792  
   793  // Helper to move from float seconds to time.Duration
   794  func secondsToDuration(seconds float64) time.Duration {
   795  	ttl := seconds * float64(time.Second)
   796  	return time.Duration(ttl)
   797  }
   798  
   799  // Ascii numbers 0-9
   800  const (
   801  	asciiZero = 48
   802  	asciiNine = 57
   803  )
   804  
   805  // parseSize expects decimal positive numbers. We
   806  // return -1 to signal error
   807  func parseSize(d []byte) (n int) {
   808  	if len(d) == 0 {
   809  		return -1
   810  	}
   811  	for _, dec := range d {
   812  		if dec < asciiZero || dec > asciiNine {
   813  			return -1
   814  		}
   815  		n = n*10 + (int(dec) - asciiZero)
   816  	}
   817  	return n
   818  }
   819  
   820  // parseInt64 expects decimal positive numbers. We
   821  // return -1 to signal error
   822  func parseInt64(d []byte) (n int64) {
   823  	if len(d) == 0 {
   824  		return -1
   825  	}
   826  	for _, dec := range d {
   827  		if dec < asciiZero || dec > asciiNine {
   828  			return -1
   829  		}
   830  		n = n*10 + (int64(dec) - asciiZero)
   831  	}
   832  	return n
   833  }