dhcprelay6.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  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/pkg/errors"
  22. "yunion.io/x/onecloud/pkg/util/dhcp"
  23. )
  24. type SRelayCache6 struct {
  25. peerMac net.HardwareAddr
  26. peerUdp *net.UDPAddr
  27. linkAddr net.IP
  28. peerAddr net.IP
  29. timer time.Time
  30. }
  31. type SDHCP6Relay struct {
  32. server *dhcp.DHCP6Server
  33. OnRecv recvFunc
  34. guestDHCPConn *dhcp.Conn
  35. ipv6srcAddr net.IP
  36. destaddr net.IP
  37. destport int
  38. cache sync.Map
  39. }
  40. func NewDHCP6Relay(guestDHCPConn *dhcp.Conn, config *SDHCPRelayUpstream) (*SDHCP6Relay, error) {
  41. relay := new(SDHCP6Relay)
  42. relay.guestDHCPConn = guestDHCPConn
  43. log.Infof("Set Relay To Address: %s, %d", config.IP, config.Port)
  44. relay.destaddr = net.ParseIP(config.IP)
  45. relay.destport = config.Port
  46. relay.cache = sync.Map{}
  47. return relay, nil
  48. }
  49. func (r *SDHCP6Relay) Setup(addr string) error {
  50. r.ipv6srcAddr = net.ParseIP(addr)
  51. if len(r.ipv6srcAddr) == 0 {
  52. return fmt.Errorf("wrong ip address %s", addr)
  53. }
  54. log.Infof("DHCP6 Relay Setup on %s %d", addr, DEFAULT_DHCP6_RELAY_PORT)
  55. var err error
  56. r.server, err = dhcp.NewDHCP6Server3(addr, DEFAULT_DHCP6_RELAY_PORT)
  57. if err != nil {
  58. return errors.Wrapf(err, "NewDHCP6Server3")
  59. }
  60. go r.server.ListenAndServe(r)
  61. return nil
  62. }
  63. func (r *SDHCP6Relay) ServeDHCP(pkt dhcp.Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (dhcp.Packet, []string, error) {
  64. pkg, err := r.serveDHCPInternal(pkt, addr)
  65. return pkg, nil, err
  66. }
  67. func (r *SDHCP6Relay) OnRecvICMP6(pkt dhcp.Packet) error {
  68. // null operation
  69. return nil
  70. }
  71. func getSessionKey(tid uint32, clientID []byte) string {
  72. return fmt.Sprintf("%x-%x", tid, clientID)
  73. }
  74. func (r *SDHCP6Relay) serveDHCPInternal(pkt dhcp.Packet, _ *net.UDPAddr) (dhcp.Packet, error) {
  75. if pkt.Type6() != dhcp.DHCPV6_RELAY_REPL {
  76. return nil, errors.Wrapf(errors.ErrInvalidFormat, "not a valid relay reply message")
  77. }
  78. hopCount := pkt.HopCount()
  79. decapPkt, err := dhcp.DecapDHCP6RelayMsg(pkt)
  80. if err != nil {
  81. return nil, errors.Wrapf(err, "DecapDHCP6RelayMsg")
  82. }
  83. tid, err := decapPkt.TID6()
  84. if err != nil {
  85. return nil, errors.Wrapf(err, "TID6")
  86. }
  87. cliID, err := decapPkt.ClientID()
  88. if err != nil {
  89. return nil, errors.Wrapf(err, "ClientID")
  90. }
  91. key := getSessionKey(tid, cliID)
  92. v, ok := r.cache.Load(key)
  93. if ok {
  94. r.cache.Delete(key)
  95. val := v.(*SRelayCache6)
  96. if hopCount > 1 {
  97. pkt.SetHopCount(hopCount - 1)
  98. pkt.SetLinkAddr(val.linkAddr)
  99. pkt.SetPeerAddr(val.peerAddr)
  100. if err := r.server.GetConn().SendDHCP(pkt, val.peerUdp, val.peerMac); err != nil {
  101. log.Errorf("send relay packet to client %s %s failed: %s", val.peerUdp, val.peerMac, err)
  102. }
  103. } else {
  104. pkt = decapPkt
  105. if err := r.guestDHCPConn.SendDHCP(pkt, val.peerUdp, val.peerMac); err != nil {
  106. log.Errorf("last hop send dhcp packet to client %s %s failed: %s", val.peerUdp, val.peerMac, err)
  107. }
  108. }
  109. }
  110. return nil, nil
  111. }
  112. func (r *SDHCP6Relay) Relay(pkt dhcp.Packet, cliMac net.HardwareAddr, cliAddr *net.UDPAddr) (dhcp.Packet, error) {
  113. if cliAddr.IP.Equal(r.ipv6srcAddr) {
  114. // come from local? ignore it
  115. return nil, nil
  116. }
  117. log.Infof("Receive IPv6 DHCPRequest FROM %s, relay to upstream %s:%d", cliAddr.IP, r.destaddr, r.destport)
  118. if pkt.Type6() == dhcp.DHCPV6_RELAY_REPL {
  119. return nil, errors.Wrapf(errors.ErrInvalidFormat, "cannot relay a reply message")
  120. }
  121. session := &SRelayCache6{
  122. peerMac: cliMac,
  123. peerUdp: cliAddr,
  124. timer: time.Now(),
  125. }
  126. hopCount := uint8(0)
  127. if pkt.Type6() == dhcp.DHCPV6_RELAY_FORW {
  128. hopCount = pkt.HopCount()
  129. session.linkAddr = pkt.LinkAddr()
  130. session.peerAddr = pkt.PeerAddr()
  131. } else {
  132. pkt = dhcp.EncapDHCP6RelayMsg(pkt)
  133. }
  134. pkt.SetHopCount(hopCount + 1)
  135. pkt.SetLinkAddr(r.ipv6srcAddr)
  136. pkt.SetPeerAddr(cliAddr.IP)
  137. tid, err := pkt.TID6()
  138. if err != nil {
  139. return nil, errors.Wrapf(err, "TID6")
  140. }
  141. cliID, err := pkt.ClientID()
  142. if err != nil {
  143. return nil, errors.Wrapf(err, "ClientID")
  144. }
  145. sessionKey := getSessionKey(tid, cliID)
  146. r.cache.Store(sessionKey, session)
  147. err = r.server.GetConn().SendDHCP(pkt, &net.UDPAddr{IP: r.destaddr, Port: r.destport}, nil)
  148. if err != nil {
  149. return nil, errors.Wrapf(err, "SendDHCP to upstream %s:%d", r.destaddr, r.destport)
  150. }
  151. return nil, nil
  152. }