conn.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  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. package dhcp
  29. import (
  30. "fmt"
  31. "io"
  32. "net"
  33. "syscall"
  34. "time"
  35. "golang.org/x/net/bpf"
  36. "yunion.io/x/pkg/errors"
  37. )
  38. // defined as a var so tests can override it.
  39. var (
  40. dhcpClientPort = 68
  41. )
  42. // txType describes how a Packet should be sent on the wire.
  43. type txType int
  44. // The various transmission strategies described in RFC 2131. "MUST",
  45. // "MUST NOT", "SHOULD" and "MAY" are as specified in RFC 2119.
  46. const (
  47. // Packet MUST be broadcast.
  48. txBroadcast txType = iota
  49. // Packet MUST be unicasted to port 67 of RelayAddr
  50. txRelayAddr
  51. // Packet MUST be unicasted to port 68 of ClientAddr
  52. txClientAddr
  53. // Packet SHOULD be unicasted to port 68 of YourAddr, with the
  54. // link-layer destination explicitly set to HardwareAddr. You MUST
  55. // NOT rely on ARP resolution to discover the link-layer
  56. // destination address.
  57. //
  58. // Conn implementations that cannot explicitly set the link-layer
  59. // destination address MAY instead broadcast the packet.
  60. txHardwareAddr
  61. )
  62. type conn interface {
  63. io.Closer
  64. Send(b []byte, addr *net.UDPAddr, destMac net.HardwareAddr) error
  65. Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, error)
  66. Send6(b []byte, addr *net.UDPAddr, destMac net.HardwareAddr) error
  67. Recv6(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, error)
  68. SetReadDeadline(t time.Time) error
  69. SetWriteDeadline(t time.Time) error
  70. SendRaw(b []byte, destMac net.HardwareAddr) error
  71. }
  72. // Conn is a DHCP-oriented packet socket.
  73. //
  74. // Multiple goroutines may invoke methods on a Conn simultaneously.
  75. type Conn struct {
  76. conn conn
  77. ifIndex int
  78. }
  79. func NewRawSocketConn(iface string, filter []bpf.RawInstruction, serverPort uint16) (*Conn, error) {
  80. conn, err := newRawSocketConn(iface, filter, serverPort)
  81. if err != nil {
  82. return nil, err
  83. }
  84. return &Conn{conn, 0}, nil
  85. }
  86. func NewSocketConn(addr string, port int) (*Conn, error) {
  87. conn, err := newSocketConn(net.ParseIP(addr), port, false)
  88. if err != nil {
  89. return nil, err
  90. }
  91. return &Conn{conn, 0}, nil
  92. }
  93. // NewConn creates a Conn bound to the given UDP ip:port.
  94. // func NewConn(addr string, disableBroadcast bool) (*Conn, error) {
  95. // return newConn(addr, disableBroadcast, newPortableConn)
  96. // }
  97. /*func newConn(addr string, disableBroadcast bool, n func(net.IP, int, bool) (conn, error)) (*Conn, error) {
  98. if addr == "" {
  99. addr = "0.0.0.0:67"
  100. }
  101. ifIndex := 0
  102. udpAddr, err := net.ResolveUDPAddr("udp4", addr)
  103. if err != nil {
  104. return nil, err
  105. }
  106. if !udpAddr.IP.To4().Equal(net.IPv4zero) {
  107. // Caller wants to listen only on one address. However, DHCP
  108. // packets are frequently broadcast, so we can't just listen
  109. // on the given address. Instead, we need to translate it to
  110. // an interface, and then filter incoming packets based on
  111. // their received interface.
  112. ifIndex, err = ipToIfindex(udpAddr.IP)
  113. if err != nil {
  114. return nil, err
  115. }
  116. }
  117. c, err := n(udpAddr.IP, udpAddr.Port, disableBroadcast)
  118. if err != nil {
  119. return nil, err
  120. }
  121. return &Conn{
  122. conn: c,
  123. ifIndex: ifIndex,
  124. }, nil
  125. }*/
  126. func ipToIfindex(ip net.IP) (int, error) {
  127. intfs, err := net.Interfaces()
  128. if err != nil {
  129. return 0, err
  130. }
  131. for _, intf := range intfs {
  132. addrs, err := intf.Addrs()
  133. if err != nil {
  134. return 0, err
  135. }
  136. for _, addr := range addrs {
  137. if ipnet, ok := addr.(*net.IPNet); ok {
  138. if ipnet.IP.Equal(ip) {
  139. return intf.Index, nil
  140. }
  141. }
  142. }
  143. }
  144. return 0, fmt.Errorf("IP %s not found on any local interface", ip)
  145. }
  146. // Close closes the DHCP socket.
  147. // Any blocked Read or Write operations will be unblocked and return errors.
  148. func (c *Conn) Close() error {
  149. return c.conn.Close()
  150. }
  151. // RecvDHCP reads a Packet from the connection. It returns the
  152. // packet and the interface it was received on.
  153. func (c *Conn) RecvDHCP() (Packet, *net.UDPAddr, net.HardwareAddr, error) {
  154. var buf [1500]byte
  155. b, addr, mac, err := c.conn.Recv(buf[:])
  156. if err != nil {
  157. return nil, nil, nil, err
  158. }
  159. pkt := Unmarshal(b)
  160. return pkt, addr, mac, nil
  161. }
  162. func (c *Conn) RecvDHCP6() (Packet, *net.UDPAddr, net.HardwareAddr, error) {
  163. var buf [1500]byte
  164. b, addr, mac, err := c.conn.Recv6(buf[:])
  165. if err != nil {
  166. return nil, nil, nil, err
  167. }
  168. pkt := Unmarshal(b)
  169. return pkt, addr, mac, nil
  170. }
  171. // SendDHCP sends pkt. The precise transmission mechanism depends
  172. // on pkt.txType(). intf should be the net.Interface returned by
  173. // RecvDHCP if responding to a DHCP client, or the interface for
  174. // which configuration is desired if acting as a client.
  175. func (c *Conn) SendDHCP(pkt Packet, addr *net.UDPAddr, mac net.HardwareAddr) error {
  176. b := pkt.Marshal()
  177. if addr.IP.Equal(net.IPv4zero) || pkt.txType() == txBroadcast {
  178. addr = &net.UDPAddr{IP: net.IPv4bcast, Port: addr.Port}
  179. }
  180. return c.conn.Send(b, addr, mac)
  181. }
  182. func (c *Conn) SendDHCP6(pkt Packet, addr *net.UDPAddr, mac net.HardwareAddr) error {
  183. b := pkt.Marshal()
  184. return c.conn.Send6(b, addr, mac)
  185. }
  186. func (c *Conn) SendRaw(pkt Packet, dstmac net.HardwareAddr) error {
  187. b := pkt.Marshal()
  188. return c.conn.SendRaw(b, dstmac)
  189. }
  190. // SetReadDeadline sets the deadline for future Read calls. If the
  191. // deadline is reached, Read will fail with a timeout (see net.Error)
  192. // instead of blocking. A zero value for t means Read will not time
  193. // out.
  194. func (c *Conn) SetReadDeadline(t time.Time) error {
  195. return c.conn.SetReadDeadline(t)
  196. }
  197. // SetWriteDeadline sets the deadline for future Write calls. If the
  198. // deadline is reached, Write will fail with a timeout (see net.Error)
  199. // instead of blocking. A zero value for t means Write will not time
  200. // out.
  201. func (c *Conn) SetWriteDeadline(t time.Time) error {
  202. return c.conn.SetWriteDeadline(t)
  203. }
  204. func interfaceToIPv4Addr(ifi *net.Interface) (net.IP, error) {
  205. if ifi == nil {
  206. return net.IPv4zero, nil
  207. }
  208. ifat, err := ifi.Addrs()
  209. if err != nil {
  210. return nil, err
  211. }
  212. for _, ifa := range ifat {
  213. switch v := ifa.(type) {
  214. case *net.IPAddr:
  215. if v.IP.To4() != nil {
  216. return v.IP, nil
  217. }
  218. case *net.IPNet:
  219. if v.IP.To4() != nil {
  220. return v.IP, nil
  221. }
  222. }
  223. }
  224. return nil, errors.Wrapf(errors.ErrNotFound, "no such network interface %s", ifi.Name)
  225. }
  226. type socketConn struct {
  227. sock int
  228. }
  229. func newSocketConn(addr net.IP, port int, disableBroadcast bool) (conn, error) {
  230. var broadcastOpt = 1
  231. if disableBroadcast {
  232. broadcastOpt = 0
  233. }
  234. sock, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, 0)
  235. if err != nil {
  236. return nil, err
  237. }
  238. err = syscall.SetsockoptInt(sock, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
  239. if err != nil {
  240. return nil, err
  241. }
  242. err = syscall.SetsockoptInt(sock, syscall.SOL_SOCKET, syscall.SO_BROADCAST, broadcastOpt)
  243. if err != nil {
  244. return nil, err
  245. }
  246. byteAddr := [4]byte{}
  247. copy(byteAddr[:], addr.To4()[:4])
  248. lsa := &syscall.SockaddrInet4{
  249. Port: port,
  250. Addr: byteAddr,
  251. }
  252. if err = syscall.Bind(sock, lsa); err != nil {
  253. return nil, err
  254. }
  255. if err = syscall.SetNonblock(sock, false); err != nil {
  256. return nil, err
  257. }
  258. // Its equal syscall.CloseOnExec
  259. // most file descriptors are getting set to close-on-exec
  260. // apart from syscall open, socket etc.
  261. syscall.Syscall(syscall.SYS_FCNTL, uintptr(sock), syscall.F_SETFD, syscall.FD_CLOEXEC)
  262. return &socketConn{sock}, nil
  263. }
  264. func (s *socketConn) Close() error {
  265. return syscall.Close(s.sock)
  266. }
  267. func (s *socketConn) Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, error) {
  268. n, a, err := syscall.Recvfrom(s.sock, b, 0)
  269. if err != nil {
  270. return nil, nil, nil, err
  271. }
  272. if addr, ok := a.(*syscall.SockaddrInet4); !ok {
  273. return nil, nil, nil, errors.Wrap(errors.ErrUnsupportedProtocol, "Recvfrom recevice address is not famliy Inet4")
  274. } else {
  275. ip := net.IP{addr.Addr[0], addr.Addr[1], addr.Addr[2], addr.Addr[3]}
  276. udpAddr := &net.UDPAddr{
  277. IP: ip,
  278. Port: addr.Port,
  279. }
  280. // there is no interface index info
  281. return b[:n], udpAddr, nil, nil
  282. }
  283. }
  284. func (s *socketConn) Send(b []byte, addr *net.UDPAddr, destMac net.HardwareAddr) error {
  285. destIp := [4]byte{}
  286. copy(destIp[:], addr.IP.To4()[:4])
  287. destAddr := &syscall.SockaddrInet4{
  288. Addr: destIp,
  289. Port: addr.Port,
  290. }
  291. return syscall.Sendto(s.sock, b, 0, destAddr)
  292. }
  293. func (s *socketConn) SetReadDeadline(t time.Time) error {
  294. return errors.ErrNotImplemented
  295. }
  296. func (s *socketConn) SetWriteDeadline(t time.Time) error {
  297. return errors.ErrNotImplemented
  298. }