123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- // Package dhcpServer providers UDP listening and serving functionality.
- package server
- import (
- "context"
- "dhcp/internal/dhcpServer/data"
- "net"
- "github.com/go-logr/logr"
- "github.com/insomniacslk/dhcp/dhcpv4"
- "github.com/insomniacslk/dhcp/dhcpv4/server4"
- "golang.org/x/net/ipv4"
- )
- // Handler is a type that defines the handler function to be called every time a
- // valid DHCPv4 message is received
- // type Handler func(ctx context.Context, conn net.PacketConn, d data.Packet).
- type Handler interface {
- Handle(ctx context.Context, conn *ipv4.PacketConn, d data.Packet)
- }
- // DHCP represents a DHCPv4 server object.
- type DHCP struct {
- Conn net.PacketConn
- Handlers []Handler
- Logger logr.Logger
- }
- // Serve serves requests.
- func (s *DHCP) Serve(ctx context.Context) error {
- s.Logger.Info("Server listening on", "addr", s.Conn.LocalAddr())
- nConn := ipv4.NewPacketConn(s.Conn)
- if err := nConn.SetControlMessage(ipv4.FlagInterface, true); err != nil {
- s.Logger.Info("error setting control message", "err", err)
- return err
- }
- defer func() {
- _ = nConn.Close()
- }()
- for {
- // Max UDP packet size is 65535. Max DHCPv4 packet size is 576. An ethernet frame is 1500 bytes.
- // We use 4096 as a reasonable buffer size. dhcpv4.FromBytes will handle the rest.
- rbuf := make([]byte, 4096)
- n, cm, peer, err := nConn.ReadFrom(rbuf)
- if err != nil {
- select {
- case <-ctx.Done():
- return nil
- default:
- }
- s.Logger.Info("error reading from packet conn", "err", err)
- return err
- }
- m, err := dhcpv4.FromBytes(rbuf[:n])
- if err != nil {
- s.Logger.Info("error parsing DHCPv4 request", "err", err)
- continue
- }
- upeer, ok := peer.(*net.UDPAddr)
- if !ok {
- s.Logger.Info("not a UDP connection? Peer is", "peer", peer)
- continue
- }
- // Set peer to broadcast if the client did not have an IP.
- if upeer.IP == nil || upeer.IP.To4().Equal(net.IPv4zero) {
- upeer = &net.UDPAddr{
- IP: net.IPv4bcast,
- Port: upeer.Port,
- }
- }
- var ifName string
- if n, err := net.InterfaceByIndex(cm.IfIndex); err == nil {
- ifName = n.Name
- }
- for _, handler := range s.Handlers {
- go handler.Handle(ctx, nConn, data.Packet{Peer: upeer, Pkt: m, Md: &data.Metadata{IfName: ifName, IfIndex: cm.IfIndex}})
- }
- }
- }
- // Close sends a termination request to the server, and closes the UDP listener.
- func (s *DHCP) Close() error {
- return s.Conn.Close()
- }
- // NewServer initializes and returns a new Server object.
- func NewServer(ifname string, addr *net.UDPAddr, handler ...Handler) (*DHCP, error) {
- s := &DHCP{
- Handlers: handler,
- Logger: logr.Discard(),
- }
- if s.Conn == nil {
- var err error
- conn, err := server4.NewIPv4UDPConn(ifname, addr)
- if err != nil {
- return nil, err
- }
- s.Conn = conn
- }
- return s, nil
- }
|