Пример #1
0
func (h *DHCPHandler) ServeDHCP(p dhcp4.Packet, msgType dhcp4.MessageType, options dhcp4.Options) (d dhcp4.Packet) {
	dns, err := h.datasource.DNSAddresses()
	if err != nil {
		logging.Log(debugTag, "Failed to read dns addresses")
		return nil
	}

	dhcpOptions := dhcp4.Options{
		dhcp4.OptionSubnetMask:       h.settings.SubnetMask.To4(),
		dhcp4.OptionDomainNameServer: dns,
	}

	if h.settings.RouterAddr != nil {
		dhcpOptions[dhcp4.OptionRouter] = h.settings.RouterAddr.To4()
	}

	macAddress := strings.Join(strings.Split(p.CHAddr().String(), ":"), "")
	switch msgType {
	case dhcp4.Discover:
		ip, err := h.datasource.Assign(p.CHAddr().String())
		if err != nil {
			logging.Debug("DHCP", "err in lease pool - %s", err.Error())
			return nil // pool is full
		}
		replyOptions := dhcpOptions.SelectOrderOrAll(options[dhcp4.OptionParameterRequestList])
		packet := dhcp4.ReplyPacket(p, dhcp4.Offer, h.settings.ServerIP, ip, randLeaseDuration(), replyOptions)
		// this is a pxe request
		guidVal, isPxe := options[97]
		if isPxe {
			logging.Log("DHCP", "dhcp discover with PXE - CHADDR %s - IP %s - our ip %s", p.CHAddr().String(), ip.String(), h.settings.ServerIP.String())
			guid := guidVal[1:]
			packet.AddOption(60, []byte("PXEClient"))
			packet.AddOption(97, guid)
			packet.AddOption(43, h.fillPXE())
		} else {
			logging.Log("DHCP", "dhcp discover - CHADDR %s - IP %s", p.CHAddr().String(), ip.String())
		}
		return packet
	case dhcp4.Request:
		if server, ok := options[dhcp4.OptionServerIdentifier]; ok && !net.IP(server).Equal(h.settings.ServerIP) {
			return nil // this message is not ours
		}
		requestedIP := net.IP(options[dhcp4.OptionRequestedIPAddress])
		if requestedIP == nil {
			requestedIP = net.IP(p.CIAddr())
		}
		if len(requestedIP) != 4 || requestedIP.Equal(net.IPv4zero) {
			logging.Debug("DHCP", "dhcp request - CHADDR %s - bad request", p.CHAddr().String())
			return nil
		}
		_, err := h.datasource.Request(p.CHAddr().String(), requestedIP)
		if err != nil {
			logging.Debug("DHCP", "dhcp request - CHADDR %s - Requested IP %s - NO MATCH", p.CHAddr().String(), requestedIP.String())

			return dhcp4.ReplyPacket(p, dhcp4.NAK, h.settings.ServerIP, nil, 0, nil)
		}

		replyOptions := dhcpOptions.SelectOrderOrAll(options[dhcp4.OptionParameterRequestList])
		packet := dhcp4.ReplyPacket(p, dhcp4.ACK, h.settings.ServerIP, requestedIP, randLeaseDuration(), replyOptions)
		// this is a pxe request
		guidVal, isPxe := options[97]
		if isPxe {
			logging.Log("DHCP", "dhcp request with PXE - CHADDR %s - Requested IP %s - our ip %s - ACCEPTED", p.CHAddr().String(), requestedIP.String(), h.settings.ServerIP.String())
			guid := guidVal[1:]
			packet.AddOption(60, []byte("PXEClient"))
			packet.AddOption(97, guid)
			packet.AddOption(43, h.fillPXE())
		} else {
			logging.Log("DHCP", "dhcp request - CHADDR %s - Requested IP %s - ACCEPTED", p.CHAddr().String(), requestedIP.String())
		}
		packet.AddOption(12, []byte("node"+macAddress+"."+h.datasource.ClusterName())) // host name option
		return packet
	case dhcp4.Release, dhcp4.Decline:

		return nil
	}
	return nil
}
Пример #2
0
//ServeDHCP : function for every dhcp request
func (h *DHCPHandler) ServeDHCP(p dhcp.Packet, msgType dhcp.MessageType, options dhcp.Options) (d dhcp.Packet) {
	// options for booting device
	skinnyOptions := dhcp.Options{
		dhcp.OptionSubnetMask:       []byte(h.config.Subnet.To4()),
		dhcp.OptionBootFileName:     []byte("http://" + h.ip.String() + "/choose"),
		dhcp.OptionRouter:           []byte(h.config.Gateway.To4()),
		dhcp.OptionDomainNameServer: []byte(h.config.DNSServer.To4()),
		dhcp.OptionDomainName:       []byte(h.config.Domain),
	}
	// get an existing lease or make a new one
	TheLease, err := h.leases.GetLease(p.CHAddr())
	logger.Info("%s has an ip of %s ", TheLease.MAC, TheLease.IP)
	if err != nil {
		logger.Critical("lease get fail , %s", err)
		return nil
	}
	// handle the DHCP transactions
	switch msgType {
	case dhcp.Discover:
		logger.Debug("Discover %s", p.CHAddr())
		return dhcp.ReplyPacket(p, dhcp.Offer, h.config.BaseIP.To4(), TheLease.GetIP(), h.leaseDuration,
			h.options.SelectOrderOrAll(options[dhcp.OptionParameterRequestList]))
	case dhcp.Request:
		logger.Debug("Request %s", p.CHAddr())
		userClass := string(options[77])
		switch userClass {
		// initial hardware boot
		case "iPXE":
			logger.Notice("iPXE from %s on %v", TheLease.MAC, TheLease.Name)
			rp := dhcp.ReplyPacket(p, dhcp.ACK, h.config.BaseIP.To4(), net.IP(options[dhcp.OptionRequestedIPAddress]), h.leaseDuration,
				h.options.SelectOrderOrAll(options[dhcp.OptionParameterRequestList]))
			rp.SetSIAddr(h.ip)
			return rp
		// scondary iPXE boot from tftp server
		case "skinny":
			logger.Notice("Booting Machine %s into %s", TheLease.Name, TheLease.Class)
			if TheLease.Active == true {
				skinnyOptions[dhcp.OptionHostName] = []byte(TheLease.Name)
				skinnyOptions[dhcp.OptionBootFileName] = []byte("http://" + h.ip.String() + "/boot/" + TheLease.Distro + "/${net0/mac}")
			}
			rp := dhcp.ReplyPacket(p, dhcp.ACK, h.config.BaseIP.To4(), net.IP(options[dhcp.OptionRequestedIPAddress]), h.leaseDuration,
				skinnyOptions.SelectOrderOrAll(options[dhcp.OptionParameterRequestList]))
			return rp
		default:
			logger.Info("normal dhcp request")
			if TheLease.Active == true {
				skinnyOptions[dhcp.OptionHostName] = []byte(TheLease.Name)
			}
			rp := dhcp.ReplyPacket(p, dhcp.ACK, h.config.BaseIP.To4(), net.IP(options[dhcp.OptionRequestedIPAddress]), h.leaseDuration,
				h.options.SelectOrderOrAll(options[dhcp.OptionParameterRequestList]))
			return rp
		}
	case dhcp.Release:
		logger.Debug("Release")
		break
	case dhcp.Decline:
		logger.Debug("Decline")
		break
	}
	return nil
}
Пример #3
0
// ServeDHCP replies a dhcp request
func (h *Handler) ServeDHCP(p dhcp4.Packet, msgType dhcp4.MessageType, options dhcp4.Options) (d dhcp4.Packet) {

	switch msgType {
	case dhcp4.Discover, dhcp4.Request:
		if server, ok := options[dhcp4.OptionServerIdentifier]; ok && !net.IP(server).Equal(h.serverIP) {
			if msgType == dhcp4.Discover {
				log.WithField("where", "dhcp.ServeDHCP").Debugf(
					"identifying dhcp server in Discover?! (%v)", p)
			}
			return nil // this message is not ours
		}

		machineInterface := h.datasource.MachineInterface(p.CHAddr())
		machine, err := machineInterface.Machine(true, nil)
		if err != nil {
			log.WithField("where", "dhcp.ServeDHCP").WithError(err).Warn(
				"failed to get machine")
			return nil
		}

		netConfStr, err := machineInterface.GetVariable(datasource.SpecialKeyNetworkConfiguration)
		if err != nil {
			log.WithField("where", "dhcp.ServeDHCP").WithError(err).Warn(
				"failed to get network configuration")
			return nil
		}

		netConf, err := datasource.UnmarshalNetworkConfiguration(netConfStr)
		if err != nil {
			log.WithField("where", "dhcp.ServeDHCP").WithError(err).Warn(
				"failed to unmarshal network-configuration=%q", netConfStr)
			return nil
		}

		instanceInfos, err := h.datasource.Instances()
		if err != nil {
			log.WithField("where", "dhcp.ServeDHCP").WithError(err).Warn(
				"failed to get instances")
			return nil
		}

		hostname := strings.Join(strings.Split(p.CHAddr().String(), ":"), "")
		hostname += "." + h.datasource.ClusterName()

		dhcpOptions := dhcp4.Options{
			dhcp4.OptionSubnetMask:       netConf.Netmask.To4(),
			dhcp4.OptionDomainNameServer: dnsAddressesForDHCP(&instanceInfos),
			dhcp4.OptionHostName:         []byte(hostname),
		}

		if netConf.Router != nil {
			dhcpOptions[dhcp4.OptionRouter] = netConf.Router.To4()
		}
		if len(netConf.ClasslessRouteOption) != 0 {
			var res []byte
			for _, part := range netConf.ClasslessRouteOption {
				res = append(res, part.ToBytes()...)
			}
			dhcpOptions[dhcp4.OptionClasslessRouteFormat] = res
		}

		responseMsgType := dhcp4.Offer
		if msgType == dhcp4.Request {
			responseMsgType = dhcp4.ACK

			requestedIP := net.IP(options[dhcp4.OptionRequestedIPAddress])
			if requestedIP == nil {
				requestedIP = net.IP(p.CIAddr())
			}
			if len(requestedIP) != 4 || requestedIP.Equal(net.IPv4zero) {
				log.WithFields(log.Fields{
					"where":   "dhcp.ServeDHCP",
					"object":  p.CHAddr().String(),
					"subject": msgType,
				}).Debugf("bad request")
				return nil
			}
			if !requestedIP.Equal(machine.IP) {
				log.WithFields(log.Fields{
					"where":   "dhcp.ServeDHCP",
					"object":  p.CHAddr().String(),
					"subject": msgType,
				}).Debugf("requestedIP(%s) != assignedIp(%s)",
					requestedIP.String(), machine.IP.String())
				return nil
			}

			machineInterface.CheckIn()
		}

		guidVal, isPxe := options[97]

		log.WithFields(log.Fields{
			"where":   "dhcp.ServeDHCP",
			"action":  "debug",
			"object":  p.CHAddr().String(),
			"subject": msgType,
		}).Infof("assignedIp=%s isPxe=%v", machine.IP.String(), isPxe)

		replyOptions := dhcpOptions.SelectOrderOrAll(options[dhcp4.OptionParameterRequestList])

		if isPxe { // this is a pxe request
			guid := guidVal[1:]
			replyOptions = append(replyOptions,
				dhcp4.Option{
					Code:  dhcp4.OptionVendorClassIdentifier,
					Value: []byte("PXEClient"),
				},
				dhcp4.Option{
					Code:  97, // UUID/GUID-based Client Identifier
					Value: guid,
				},
				dhcp4.Option{
					Code:  dhcp4.OptionVendorSpecificInformation,
					Value: h.fillPXE(),
				},
			)

			hash, err := h.datasource.GetClusterVariable(datasource.ActiveWorkspaceHashKey)
			if err == nil {
				machineInterface.SetVariable("booted-workspace-hash", hash)
			}
		}
		packet := dhcp4.ReplyPacket(p, responseMsgType, h.serverIP, machine.IP,
			randLeaseDuration(), replyOptions)
		return packet

	case dhcp4.Release, dhcp4.Decline:
		return nil
	}
	return nil
}