upnp.go 2.6 KB

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