upnp.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. package upnp
  2. import (
  3. "errors"
  4. "log"
  5. "sync"
  6. "time"
  7. "gitlab.com/NebulousLabs/go-upnp"
  8. )
  9. /*
  10. uPNP Module
  11. This module handles uPNP Connections to the gateway router and create a port forward entry
  12. for the host system at the given port (set with -port paramter)
  13. */
  14. type UPnPClient struct {
  15. Connection *upnp.IGD //UPnP conenction object
  16. ExternalIP string //Storage of external IP address
  17. RequiredPorts []int //All the required ports will be recored
  18. PolicyNames sync.Map //Name for the required port nubmer
  19. }
  20. func NewUPNPClient() (*UPnPClient, error) {
  21. //Create uPNP forwarding in the NAT router
  22. log.Println("Discovering UPnP router in Local Area Network...")
  23. d, err := upnp.Discover()
  24. if err != nil {
  25. return &UPnPClient{}, err
  26. }
  27. // discover external IP
  28. ip, err := d.ExternalIP()
  29. if err != nil {
  30. return &UPnPClient{}, err
  31. }
  32. //Create the final obejcts
  33. newUPnPObject := &UPnPClient{
  34. Connection: d,
  35. ExternalIP: ip,
  36. RequiredPorts: []int{},
  37. }
  38. return newUPnPObject, nil
  39. }
  40. func (u *UPnPClient) ForwardPort(portNumber int, ruleName string) error {
  41. log.Println("UPnP forwarding new port: ", portNumber, "for "+ruleName+" service")
  42. //Check if port already forwarded
  43. _, ok := u.PolicyNames.Load(portNumber)
  44. if ok {
  45. //Port already forward. Ignore this request
  46. return errors.New("Port already forwarded")
  47. }
  48. // forward a port
  49. err := u.Connection.Forward(uint16(portNumber), ruleName)
  50. if err != nil {
  51. return err
  52. }
  53. u.RequiredPorts = append(u.RequiredPorts, portNumber)
  54. u.PolicyNames.Store(portNumber, ruleName)
  55. return nil
  56. }
  57. func (u *UPnPClient) ClosePort(portNumber int) error {
  58. //Check if port is opened
  59. portOpened := false
  60. newRequiredPort := []int{}
  61. for _, thisPort := range u.RequiredPorts {
  62. if thisPort != portNumber {
  63. newRequiredPort = append(newRequiredPort, thisPort)
  64. } else {
  65. portOpened = true
  66. }
  67. }
  68. if portOpened {
  69. //Update the port list
  70. u.RequiredPorts = newRequiredPort
  71. // Close the port
  72. log.Println("Closing UPnP Port Forward: ", portNumber)
  73. err := u.Connection.Clear(uint16(portNumber))
  74. //Delete the name registry
  75. u.PolicyNames.Delete(portNumber)
  76. if err != nil {
  77. log.Println(err)
  78. return err
  79. }
  80. }
  81. return nil
  82. }
  83. // Renew forward rules, prevent router lease time from flushing the Upnp config
  84. func (u *UPnPClient) RenewForwardRules() {
  85. portsToRenew := u.RequiredPorts
  86. for _, thisPort := range portsToRenew {
  87. ruleName, ok := u.PolicyNames.Load(thisPort)
  88. if !ok {
  89. continue
  90. }
  91. u.ClosePort(thisPort)
  92. time.Sleep(100 * time.Millisecond)
  93. u.ForwardPort(thisPort, ruleName.(string))
  94. }
  95. log.Println("UPnP Port Forward rule renew completed")
  96. }
  97. func (u *UPnPClient) Close() {
  98. //Shutdown the default UPnP Object
  99. if u != nil {
  100. for _, portNumber := range u.RequiredPorts {
  101. err := u.Connection.Clear(uint16(portNumber))
  102. if err != nil {
  103. log.Println(err)
  104. }
  105. }
  106. }
  107. }