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 }