func (s *Server) ListenAndServeUDPv4() { ipAddr := &net.IPAddr{IP: net.IPv4zero} conn, err := net.ListenIP("ip4:udp", ipAddr) if err != nil { l.Info(err.Error()) return } defer conn.Close() if err = bindToDevice(conn, "tap"+s.name); err != nil { l.Info(err.Error()) return } s.Lock() s.ipv4conn, err = ipv4.NewRawConn(conn) s.Unlock() if err != nil { l.Info(err.Error()) return } if err = s.ipv4conn.SetControlMessage(ipv4.FlagDst, true); err != nil { l.Warning(err.Error()) return } buffer := make([]byte, 1500) var gw net.IP for _, addr := range s.metadata.Network.IP { if addr.Family == "ipv4" && addr.Host == "true" && addr.Gateway == "true" { gw = net.ParseIP(addr.Address) } } iface, err := net.InterfaceByName("tap" + s.name) if err != nil { l.Info(fmt.Sprintf("failed to get iface: %s", err.Error())) return } for { select { case <-s.done: return default: s.ipv4conn.SetReadDeadline(time.Now().Add(time.Second)) hdr, _, _, err := s.ipv4conn.ReadFrom(buffer) if err != nil { switch v := err.(type) { case *net.OpError: if v.Timeout() { continue } case *net.AddrError: if v.Timeout() { continue } case *net.UnknownNetworkError: if v.Timeout() { continue } default: l.Warning(err.Error()) return } } var ip4 layers.IPv4 var udp layers.UDP var dhcp4req layers.DHCPv4 parser := gopacket.NewDecodingLayerParser(layers.LayerTypeIPv4, &ip4, &udp, &dhcp4req) decoded := []gopacket.LayerType{} err = parser.DecodeLayers(buffer, &decoded) for _, layerType := range decoded { switch layerType { case layers.LayerTypeDHCPv4: if dhcp4req.Operation == layers.DHCP_MSG_REQ { dhcp4res, err := s.ServeUDPv4(&dhcp4req) if err != nil { l.Warning(err.Error()) continue } if dhcp4res == nil { // ignore empty dhcp packets continue } buf := gopacket.NewSerializeBuffer() opts := gopacket.SerializeOptions{true, true} gopacket.SerializeLayers(buf, opts, &layers.UDP{SrcPort: 67, DstPort: 68}, dhcp4res) wcm := ipv4.ControlMessage{TTL: 255} wcm.Dst = net.IPv4bcast.To4() wcm.Src = gw.To4() wcm.IfIndex = iface.Index err = s.ipv4conn.WriteTo(&ipv4.Header{Len: 20, TOS: hdr.TOS, TotalLen: 20 + int(len(buf.Bytes())), FragOff: 0, TTL: 255, Protocol: int(layers.IPProtocolUDP), Src: gw.To4(), Dst: net.IPv4bcast.To4()}, buf.Bytes(), &wcm) if err != nil { l.Warning(err.Error()) continue } } else { continue } } } } } }