Esempio n. 1
0
// Assumes RWLock is held
func (subnet *Subnet) getFreeIP() (*net.IP, bool) {
	bit, success := firstClearBit(subnet.ActiveBits)
	if success {
		subnet.ActiveBits.Set(bit)
		ip := dhcp.IPAdd(subnet.ActiveStart, int(bit))
		return &ip, true
	}

	// Free invalid or expired leases
	save_me := false
	now := time.Now()
	for k, lease := range subnet.Leases {
		if now.After(lease.ExpireTime) {
			if dhcp.IPInRange(subnet.ActiveStart, subnet.ActiveEnd, lease.Ip) {
				subnet.ActiveBits.Clear(uint(dhcp.IPRange(lease.Ip, subnet.ActiveStart) - 1))
			}
			delete(subnet.Leases, k)
			save_me = true
		}
	}

	bit, success = firstClearBit(subnet.ActiveBits)
	if success {
		subnet.ActiveBits.Set(bit)
		ip := dhcp.IPAdd(subnet.ActiveStart, int(bit))
		return &ip, true
	}

	// We got nothin'
	return nil, save_me
}
Esempio n. 2
0
func (subnet *Subnet) free_lease(dt *DataTracker, nic string) {
	subnet.lock.Lock()
	lease := subnet.Leases[nic]
	if lease != nil {
		if dhcp.IPInRange(subnet.ActiveStart, subnet.ActiveEnd, lease.Ip) {
			subnet.ActiveBits.Clear(uint(dhcp.IPRange(lease.Ip, subnet.ActiveStart) - 1))
		}
		delete(subnet.Leases, nic)
		subnet.lock.Unlock()
		dt.save_data()
	} else {
		subnet.lock.Unlock()
	}
}
Esempio n. 3
0
func (dt *DataTracker) AddBinding(subnetName string, binding Binding) (error, int) {
	lsubnet := dt.Subnets[subnetName]
	if lsubnet == nil {
		return errors.New("Not Found"), http.StatusNotFound
	}

	// If existing, clear the reservation for IP
	b := lsubnet.Bindings[binding.Mac]
	if b != nil {
		if dhcp.IPInRange(lsubnet.ActiveStart, lsubnet.ActiveEnd, b.Ip) {
			lsubnet.ActiveBits.Clear(uint(dhcp.IPRange(lsubnet.ActiveStart, b.Ip) - 1))
		}
	}

	// Reserve the IP if in Active range
	if dhcp.IPInRange(lsubnet.ActiveStart, lsubnet.ActiveEnd, binding.Ip) {
		lsubnet.ActiveBits.Set(uint(dhcp.IPRange(lsubnet.ActiveStart, binding.Ip) - 1))
	}

	lsubnet.Bindings[binding.Mac] = &binding
	dt.save_data()
	return nil, http.StatusOK
}
Esempio n. 4
0
func (h *DHCPHandler) ServeDHCP(p dhcp.Packet, msgType dhcp.MessageType, options dhcp.Options) (d dhcp.Packet) {
	switch msgType {

	case dhcp.Discover:
		free, nic := -1, p.CHAddr().String()
		for i, v := range h.leases { // Find previous lease
			if v.nic == nic {
				free = i
				goto reply
			}
		}
		if free = h.freeLease(); free == -1 {
			return
		}
	reply:
		return dhcp.ReplyPacket(p, dhcp.Offer, h.ip, dhcp.IPAdd(h.start, free), h.leaseDuration,
			h.options.SelectOrderOrAll(options[dhcp.OptionParameterRequestList]))

	case dhcp.Request:
		if server, ok := options[dhcp.OptionServerIdentifier]; ok && !net.IP(server).Equal(h.ip) {
			return nil // Message not for this dhcp server
		}
		reqIP := net.IP(options[dhcp.OptionRequestedIPAddress])
		if reqIP == nil {
			reqIP = net.IP(p.CIAddr())
		}

		if len(reqIP) == 4 && !reqIP.Equal(net.IPv4zero) {
			if leaseNum := dhcp.IPRange(h.start, reqIP) - 1; leaseNum >= 0 && leaseNum < h.leaseRange {
				if l, exists := h.leases[leaseNum]; !exists || l.nic == p.CHAddr().String() {
					h.leases[leaseNum] = lease{nic: p.CHAddr().String(), expiry: time.Now().Add(h.leaseDuration)}
					return dhcp.ReplyPacket(p, dhcp.ACK, h.ip, net.IP(options[dhcp.OptionRequestedIPAddress]), h.leaseDuration,
						h.options.SelectOrderOrAll(options[dhcp.OptionParameterRequestList]))
				}
			}
		}
		return dhcp.ReplyPacket(p, dhcp.NAK, h.ip, nil, 0, nil)

	case dhcp.Release, dhcp.Decline:
		nic := p.CHAddr().String()
		for i, v := range h.leases {
			if v.nic == nic {
				delete(h.leases, i)
				break
			}
		}
	}
	return nil
}
Esempio n. 5
0
func (dt *DataTracker) DeleteBinding(subnetName, mac string) (error, int) {
	lsubnet := dt.Subnets[subnetName]
	if lsubnet == nil {
		return errors.New("Subnet Not Found"), http.StatusNotFound
	}

	b := lsubnet.Bindings[mac]
	if b == nil {
		return errors.New("Binding Not Found"), http.StatusNotFound
	}

	if dhcp.IPInRange(lsubnet.ActiveStart, lsubnet.ActiveEnd, b.Ip) {
		lsubnet.ActiveBits.Clear(uint(dhcp.IPRange(lsubnet.ActiveStart, b.Ip) - 1))
	}

	delete(lsubnet.Bindings, mac)
	dt.save_data()
	return nil, http.StatusOK
}
Esempio n. 6
0
func convertApiSubnetToSubnet(as *ApiSubnet, subnet *Subnet) (*Subnet, error) {
	if subnet == nil {
		subnet = NewSubnet()
	}
	subnet.Name = as.Name

	_, netdata, err := net.ParseCIDR(as.Subnet)
	if err != nil {
		return nil, err
	}

	subnet.Subnet = &MyIPNet{netdata}
	subnet.ActiveStart = net.ParseIP(as.ActiveStart).To4()
	subnet.ActiveEnd = net.ParseIP(as.ActiveEnd).To4()
	subnet.ActiveLeaseTime = time.Duration(as.ActiveLeaseTime) * time.Second
	subnet.ReservedLeaseTime = time.Duration(as.ReservedLeaseTime) * time.Second
	subnet.ActiveBits = bitset.New(uint(dhcp.IPRange(subnet.ActiveStart, subnet.ActiveEnd)))

	if as.NextServer != nil {
		ip := net.ParseIP(*as.NextServer).To4()
		subnet.NextServer = &ip
	}

	if subnet.ActiveLeaseTime == 0 {
		subnet.ActiveLeaseTime = 30 * time.Second
	}
	if subnet.ReservedLeaseTime == 0 {
		subnet.ReservedLeaseTime = 2 * time.Hour
	}

	for _, v := range as.Leases {
		subnet.Leases[v.Mac] = v
		if dhcp.IPInRange(subnet.ActiveStart, subnet.ActiveEnd, v.Ip) {
			subnet.ActiveBits.Set(uint(dhcp.IPRange(subnet.ActiveStart, v.Ip) - 1))
		}
	}

	for _, v := range as.Bindings {
		subnet.Bindings[v.Mac] = v
		if dhcp.IPInRange(subnet.ActiveStart, subnet.ActiveEnd, v.Ip) {
			subnet.ActiveBits.Set(uint(dhcp.IPRange(subnet.ActiveStart, v.Ip) - 1))
		}
	}

	// Seed initial options
	subnet.Options[dhcp.OptionSubnetMask] = []byte(net.IP(netdata.Mask).To4())
	m := binary.BigEndian.Uint32(subnet.Options[dhcp.OptionSubnetMask])
	n := binary.BigEndian.Uint32(netdata.IP)
	b := n | ^m
	result := make([]byte, 4)
	binary.BigEndian.PutUint32(result, b)
	subnet.Options[dhcp.OptionBroadcastAddress] = result

	for _, o := range as.Options {
		subnet.Options[o.Code], err = convertOptionValueToByte(o.Code, o.Value)
		if err != nil {
			return nil, err
		}
	}

	if !netdata.Contains(subnet.ActiveStart) {
		return nil, errors.New("ActiveStart not in Subnet")
	}
	if !netdata.Contains(subnet.ActiveEnd) {
		return nil, errors.New("ActiveEnd not in Subnet")
	}

	if dhcp.IPLess(subnet.ActiveEnd, subnet.ActiveStart) {
		return nil, errors.New("ActiveEnd less than ActiveStart")
	}

	return subnet, nil
}