conn_linux6.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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. // Copyright 2019 Yunion
  15. // Copyright 2016 Google Inc.
  16. //
  17. // Licensed under the Apache License, Version 2.0 (the "License");
  18. // you may not use this file except in compliance with the License.
  19. // You may obtain a copy of the License at
  20. //
  21. // http://www.apache.org/licenses/LICENSE-2.0
  22. //
  23. // Unless required by applicable law or agreed to in writing, software
  24. // distributed under the License is distributed on an "AS IS" BASIS,
  25. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  26. // See the License for the specific language governing permissions and
  27. // limitations under the License.
  28. //go:build linux
  29. // +build linux
  30. package dhcp
  31. import (
  32. "net"
  33. "github.com/google/gopacket"
  34. "github.com/google/gopacket/layers"
  35. "github.com/mdlayher/packet"
  36. "golang.org/x/net/bpf"
  37. "golang.org/x/sys/unix"
  38. "yunion.io/x/log"
  39. "yunion.io/x/pkg/errors"
  40. )
  41. func newRawSocketConn6(iface string, filter []bpf.RawInstruction, serverPort uint16) (conn, error) {
  42. ifi, err := net.InterfaceByName(iface)
  43. if err != nil {
  44. return nil, errors.Wrap(err, "interface by name")
  45. }
  46. ip, err := interfaceToIPv6Addr(ifi)
  47. if err != nil {
  48. return nil, errors.Wrap(err, "interfaceToIPv6Addr")
  49. }
  50. // unix.ETH_P_ALL
  51. conn, err := packet.Listen(ifi, packet.Raw, unix.ETH_P_IPV6, &packet.Config{
  52. Filter: filter,
  53. })
  54. if err != nil {
  55. return nil, errors.Wrap(err, "packet.Listen")
  56. }
  57. log.Debugf("newRawSocketConn6 on %s %s", ifi.Name, ip)
  58. return &rawSocketConn{
  59. conn: conn,
  60. iface: ifi,
  61. ip: ip,
  62. serverPort: serverPort,
  63. }, nil
  64. }
  65. func (s *rawSocketConn) Recv6(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, error) {
  66. // read packet
  67. n, addr, err := s.conn.ReadFrom(b)
  68. if err != nil {
  69. return nil, nil, nil, errors.Wrap(err, "Read from errror")
  70. }
  71. b = b[:n]
  72. srcMac, err := net.ParseMAC(addr.String())
  73. if err != nil {
  74. return nil, nil, nil, errors.Wrap(err, "Parse mac error")
  75. }
  76. p := gopacket.NewPacket(b, layers.LayerTypeEthernet, gopacket.Default)
  77. if p.ErrorLayer() != nil {
  78. return nil, nil, nil, errors.Wrap(p.ErrorLayer().Error(), "Failed to decode packet")
  79. }
  80. var srcIp net.IP
  81. {
  82. ipLayer := p.Layer(layers.LayerTypeIPv6)
  83. if ipLayer != nil {
  84. // ipv6
  85. ip6 := ipLayer.(*layers.IPv6)
  86. srcIp = ip6.SrcIP
  87. } else {
  88. return nil, nil, nil, errors.Wrap(p.ErrorLayer().Error(), "Expect IPv6 packet")
  89. }
  90. }
  91. icmpLayer := p.Layer(layers.LayerTypeICMPv6)
  92. if icmpLayer != nil {
  93. // receive icmp packet
  94. return b, &net.UDPAddr{IP: srcIp, Port: icmpRAFakePort}, srcMac, nil
  95. }
  96. var srcPort uint16
  97. udpLayer := p.Layer(layers.LayerTypeUDP)
  98. if udpLayer != nil {
  99. udpInfo := udpLayer.(*layers.UDP)
  100. srcPort = uint16(udpInfo.SrcPort)
  101. } else {
  102. return nil, nil, nil, errors.Wrap(p.ErrorLayer().Error(), "expect UDP packet")
  103. }
  104. dhcpLayer := p.Layer(layers.LayerTypeDHCPv6)
  105. if dhcpLayer != nil {
  106. // dhcpv6
  107. dhcp6 := dhcpLayer.(*layers.DHCPv6)
  108. sbf := gopacket.NewSerializeBuffer()
  109. if err := dhcp6.SerializeTo(sbf, gopacket.SerializeOptions{}); err != nil {
  110. return nil, nil, nil, errors.Wrap(err, "Serialize dhcp6 packet error")
  111. }
  112. return sbf.Bytes(), &net.UDPAddr{IP: srcIp, Port: int(srcPort)}, srcMac, nil
  113. } else {
  114. return nil, nil, nil, errors.Wrap(p.ErrorLayer().Error(), "Fetch dhcp layer failed")
  115. }
  116. }
  117. func (s *rawSocketConn) SendRaw(b []byte, destMac net.HardwareAddr) error {
  118. // s.conn.SetWriteDeadline(time.Now().Add(DefaultWriteTimeout)) // 2 second
  119. if _, err := s.conn.WriteTo(b, &packet.Addr{HardwareAddr: destMac}); err != nil {
  120. return errors.Wrap(err, "Send icmp packet error")
  121. }
  122. return nil
  123. }
  124. func (s *rawSocketConn) Send6(b []byte, addr *net.UDPAddr, destMac net.HardwareAddr) error {
  125. var dhcp = new(layers.DHCPv6)
  126. if err := dhcp.DecodeFromBytes(b, gopacket.NilDecodeFeedback); err != nil {
  127. return errors.Wrap(err, "Decode dhcp bytes error")
  128. }
  129. var eth = &layers.Ethernet{
  130. EthernetType: layers.EthernetTypeIPv6,
  131. SrcMAC: s.iface.HardwareAddr,
  132. DstMAC: destMac,
  133. }
  134. var ip = &layers.IPv6{
  135. Version: 6,
  136. HopLimit: 64,
  137. SrcIP: s.ip,
  138. DstIP: addr.IP,
  139. NextHeader: layers.IPProtocolUDP,
  140. }
  141. var (
  142. srcPort = layers.UDPPort(s.serverPort)
  143. dstPort = layers.UDPPort(addr.Port)
  144. )
  145. var udp = &layers.UDP{
  146. SrcPort: srcPort,
  147. DstPort: dstPort,
  148. }
  149. udp.SetNetworkLayerForChecksum(ip)
  150. var (
  151. buf = gopacket.NewSerializeBuffer()
  152. opts = gopacket.SerializeOptions{ComputeChecksums: true, FixLengths: true}
  153. )
  154. if err := gopacket.SerializeLayers(buf, opts, eth, ip, udp, dhcp); err != nil {
  155. return errors.Wrap(err, "SerializeLayers error")
  156. }
  157. // s.conn.SetWriteDeadline(time.Now().Add(DefaultWriteTimeout)) // 2 second
  158. if _, err := s.conn.WriteTo(buf.Bytes(), &packet.Addr{HardwareAddr: destMac}); err != nil {
  159. return errors.Wrap(err, "Send dhcp packet error")
  160. }
  161. return nil
  162. }