dhcp.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. // Package dhcpServer providers UDP listening and serving functionality.
  2. package server
  3. import (
  4. "context"
  5. "dhcp/data"
  6. "net"
  7. "github.com/go-logr/logr"
  8. "github.com/insomniacslk/dhcp/dhcpv4"
  9. "github.com/insomniacslk/dhcp/dhcpv4/server4"
  10. "golang.org/x/net/ipv4"
  11. )
  12. // Handler is a type that defines the handler function to be called every time a
  13. // valid DHCPv4 message is received
  14. // type Handler func(ctx context.Context, conn net.PacketConn, d data.Packet).
  15. type Handler interface {
  16. Handle(ctx context.Context, conn *ipv4.PacketConn, d data.Packet)
  17. }
  18. // DHCP represents a DHCPv4 server object.
  19. type DHCP struct {
  20. Conn net.PacketConn
  21. Handlers []Handler
  22. Logger logr.Logger
  23. }
  24. // Serve serves requests.
  25. func (s *DHCP) Serve(ctx context.Context) error {
  26. s.Logger.Info("Server listening on", "addr", s.Conn.LocalAddr())
  27. nConn := ipv4.NewPacketConn(s.Conn)
  28. if err := nConn.SetControlMessage(ipv4.FlagInterface, true); err != nil {
  29. s.Logger.Info("error setting control message", "err", err)
  30. return err
  31. }
  32. defer func() {
  33. _ = nConn.Close()
  34. }()
  35. for {
  36. // Max UDP packet size is 65535. Max DHCPv4 packet size is 576. An ethernet frame is 1500 bytes.
  37. // We use 4096 as a reasonable buffer size. dhcpv4.FromBytes will handle the rest.
  38. rbuf := make([]byte, 4096)
  39. n, cm, peer, err := nConn.ReadFrom(rbuf)
  40. if err != nil {
  41. select {
  42. case <-ctx.Done():
  43. return nil
  44. default:
  45. }
  46. s.Logger.Info("error reading from packet conn", "err", err)
  47. return err
  48. }
  49. m, err := dhcpv4.FromBytes(rbuf[:n])
  50. if err != nil {
  51. s.Logger.Info("error parsing DHCPv4 request", "err", err)
  52. continue
  53. }
  54. upeer, ok := peer.(*net.UDPAddr)
  55. if !ok {
  56. s.Logger.Info("not a UDP connection? Peer is", "peer", peer)
  57. continue
  58. }
  59. // Set peer to broadcast if the client did not have an IP.
  60. if upeer.IP == nil || upeer.IP.To4().Equal(net.IPv4zero) {
  61. upeer = &net.UDPAddr{
  62. IP: net.IPv4bcast,
  63. Port: upeer.Port,
  64. }
  65. }
  66. var ifName string
  67. if n, err := net.InterfaceByIndex(cm.IfIndex); err == nil {
  68. ifName = n.Name
  69. }
  70. for _, handler := range s.Handlers {
  71. go handler.Handle(ctx, nConn, data.Packet{Peer: upeer, Pkt: m, Md: &data.Metadata{IfName: ifName, IfIndex: cm.IfIndex}})
  72. }
  73. }
  74. }
  75. // Close sends a termination request to the server, and closes the UDP listener.
  76. func (s *DHCP) Close() error {
  77. return s.Conn.Close()
  78. }
  79. // NewServer initializes and returns a new Server object.
  80. func NewServer(ifname string, addr *net.UDPAddr, handler ...Handler) (*DHCP, error) {
  81. s := &DHCP{
  82. Handlers: handler,
  83. Logger: logr.Discard(),
  84. }
  85. if s.Conn == nil {
  86. var err error
  87. conn, err := server4.NewIPv4UDPConn(ifname, addr)
  88. if err != nil {
  89. return nil, err
  90. }
  91. s.Conn = conn
  92. }
  93. return s, nil
  94. }