stun.go 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. package stun
  2. import (
  3. "fmt"
  4. "log"
  5. "net"
  6. "strconv"
  7. "strings"
  8. "github.com/gravitl/netmaker/nm-proxy/models"
  9. "gortc.io/stun"
  10. )
  11. type HostInfo struct {
  12. PublicIp net.IP
  13. PrivIp net.IP
  14. PubPort int
  15. PrivPort int
  16. }
  17. var Host HostInfo
  18. func GetHostInfo(stunHostAddr string) (info HostInfo) {
  19. s, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:3478", stunHostAddr))
  20. if err != nil {
  21. log.Println("Resolve: ", err)
  22. return
  23. }
  24. l := &net.UDPAddr{
  25. IP: net.ParseIP(""),
  26. Port: models.NmProxyPort,
  27. }
  28. conn, err := net.DialUDP("udp", l, s)
  29. if err != nil {
  30. log.Println(err)
  31. return
  32. }
  33. defer conn.Close()
  34. c, err := stun.NewClient(conn)
  35. if err != nil {
  36. log.Println(err)
  37. return
  38. }
  39. defer c.Close()
  40. re := strings.Split(conn.LocalAddr().String(), ":")
  41. info.PrivIp = net.ParseIP(re[0])
  42. info.PrivPort, _ = strconv.Atoi(re[1])
  43. // Building binding request with random transaction id.
  44. message := stun.MustBuild(stun.TransactionID, stun.BindingRequest)
  45. // Sending request to STUN server, waiting for response message.
  46. if err := c.Do(message, func(res stun.Event) {
  47. if res.Error != nil {
  48. log.Println("stun error: ", res.Error)
  49. return
  50. }
  51. // Decoding XOR-MAPPED-ADDRESS attribute from message.
  52. var xorAddr stun.XORMappedAddress
  53. if err := xorAddr.GetFrom(res.Message); err != nil {
  54. log.Println("stun error: ", res.Error)
  55. return
  56. }
  57. info.PublicIp = xorAddr.IP
  58. info.PubPort = xorAddr.Port
  59. }); err != nil {
  60. log.Println("stun error: ", err)
  61. }
  62. return
  63. }