dhcprelay.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package hostdhcp
  15. import (
  16. "fmt"
  17. "net"
  18. "sync"
  19. "time"
  20. "yunion.io/x/log"
  21. "yunion.io/x/onecloud/pkg/util/dhcp"
  22. )
  23. type recvFunc func(pkt *dhcp.Packet)
  24. type SRelayCache struct {
  25. mac net.HardwareAddr
  26. srcPort int
  27. // dstPort int
  28. timer time.Time
  29. }
  30. type SDHCPRelay struct {
  31. server *dhcp.DHCPServer
  32. OnRecv recvFunc
  33. guestDHCPConn *dhcp.Conn
  34. ipv4srcAddr net.IP
  35. destaddr net.IP
  36. destport int
  37. cache sync.Map
  38. }
  39. func NewDHCPRelay(guestDHCPConn *dhcp.Conn, config *SDHCPRelayUpstream) (*SDHCPRelay, error) {
  40. relay := new(SDHCPRelay)
  41. relay.guestDHCPConn = guestDHCPConn
  42. log.Infof("Set Relay To Address: %s, %d", config.IP, config.Port)
  43. relay.destaddr = net.ParseIP(config.IP)
  44. relay.destport = config.Port
  45. relay.cache = sync.Map{}
  46. return relay, nil
  47. }
  48. func (r *SDHCPRelay) Setup(addr string) error {
  49. r.ipv4srcAddr = net.ParseIP(addr)
  50. if len(r.ipv4srcAddr) == 0 {
  51. return fmt.Errorf("Wrong ip address %s", addr)
  52. }
  53. log.Infof("DHCP Relay Setup on %s %d", addr, DEFAULT_DHCP_RELAY_PORT)
  54. var err error
  55. r.server, err = dhcp.NewDHCPServer3(addr, DEFAULT_DHCP_RELAY_PORT)
  56. if err != nil {
  57. return err
  58. }
  59. go r.server.ListenAndServe(r)
  60. return nil
  61. }
  62. func (r *SDHCPRelay) ServeDHCP(pkt dhcp.Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (dhcp.Packet, []string, error) {
  63. pkg, err := r.serveDHCPInternal(pkt, addr)
  64. return pkg, nil, err
  65. }
  66. func (r *SDHCPRelay) serveDHCPInternal(pkt dhcp.Packet, _ *net.UDPAddr) (dhcp.Packet, error) {
  67. log.Infof("DHCP Relay Reply TO %s", pkt.CHAddr())
  68. v, ok := r.cache.Load(pkt.TransactionID())
  69. if ok {
  70. r.cache.Delete(pkt.TransactionID())
  71. val := v.(*SRelayCache)
  72. udpAddr := &net.UDPAddr{
  73. IP: pkt.CIAddr(),
  74. Port: val.srcPort,
  75. }
  76. if err := r.guestDHCPConn.SendDHCP(pkt, udpAddr, pkt.CHAddr()); err != nil {
  77. log.Errorln(err)
  78. }
  79. }
  80. return nil, nil
  81. }
  82. func (r *SDHCPRelay) Relay(pkt dhcp.Packet, addr *net.UDPAddr) (dhcp.Packet, error) {
  83. if addr.IP.Equal(r.ipv4srcAddr) {
  84. return nil, nil
  85. }
  86. log.Infof("Receive DHCP Relay Rquest FROM %s %s", addr.IP, pkt.CHAddr())
  87. // clean cache first
  88. var now = time.Now().Add(time.Second * -30)
  89. r.cache.Range(func(key, value interface{}) bool {
  90. v := value.(*SRelayCache)
  91. if v.timer.Before(now) {
  92. r.cache.Delete(key)
  93. }
  94. return true
  95. })
  96. // cache pkt info
  97. r.cache.Store(pkt.TransactionID(), &SRelayCache{
  98. mac: pkt.CHAddr(),
  99. srcPort: addr.Port,
  100. timer: time.Now(),
  101. })
  102. pkt.SetGIAddr(r.ipv4srcAddr)
  103. err := r.server.GetConn().SendDHCP(pkt, &net.UDPAddr{IP: r.destaddr, Port: r.destport}, nil)
  104. return nil, err
  105. }