github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/hypervisor/dhcpd/impl.go (about) 1 package dhcpd 2 3 import ( 4 "errors" 5 "net" 6 "os" 7 "sort" 8 "strings" 9 "time" 10 11 "github.com/Cloud-Foundations/Dominator/lib/fsutil" 12 "github.com/Cloud-Foundations/Dominator/lib/json" 13 "github.com/Cloud-Foundations/Dominator/lib/log" 14 "github.com/Cloud-Foundations/Dominator/lib/log/prefixlogger" 15 libnet "github.com/Cloud-Foundations/Dominator/lib/net" 16 "github.com/Cloud-Foundations/Dominator/lib/net/util" 17 proto "github.com/Cloud-Foundations/Dominator/proto/hypervisor" 18 dhcp "github.com/krolaw/dhcp4" 19 "golang.org/x/net/ipv4" 20 ) 21 22 const dynamicLeaseTime = time.Hour * 4 23 const staticLeaseTime = time.Hour * 48 24 25 type dynamicLeaseType struct { 26 ClientHostName string `json:",omitempty"` 27 Expires time.Time 28 proto.Address 29 } 30 31 type serveIfConn struct { 32 ifIndices map[int]string 33 conn *ipv4.PacketConn 34 cm *ipv4.ControlMessage 35 requestInterface *string 36 } 37 38 func listMyIPs() (map[string][]net.IP, []net.IP, error) { 39 interfaces, err := net.Interfaces() 40 if err != nil { 41 return nil, nil, err 42 } 43 ifMap := make(map[string][]net.IP) 44 ipMap := make(map[string]net.IP) 45 for _, iface := range interfaces { 46 if iface.Flags&net.FlagUp == 0 { 47 continue 48 } 49 if iface.Flags&net.FlagBroadcast == 0 { 50 continue 51 } 52 interfaceAddrs, err := iface.Addrs() 53 if err != nil { 54 return nil, nil, err 55 } 56 for _, addr := range interfaceAddrs { 57 IP, _, err := net.ParseCIDR(addr.String()) 58 if err != nil { 59 return nil, nil, err 60 } 61 if IP = IP.To4(); IP == nil { 62 continue 63 } 64 ifMap[iface.Name] = append(ifMap[iface.Name], IP) 65 ipMap[IP.String()] = IP 66 } 67 } 68 var IPs []net.IP 69 for _, IP := range ipMap { 70 IPs = append(IPs, IP) 71 } 72 return ifMap, IPs, nil 73 } 74 75 func newServer(interfaceNames []string, dynamicLeasesFile string, 76 logger log.DebugLogger) ( 77 *DhcpServer, error) { 78 logger = prefixlogger.New("dhcpd: ", logger) 79 cleanupTriggerChannel := make(chan struct{}, 1) 80 dhcpServer := &DhcpServer{ 81 dynamicLeasesFile: dynamicLeasesFile, 82 logger: logger, 83 cleanupTrigger: cleanupTriggerChannel, 84 ackChannels: make(map[string]chan struct{}), 85 interfaceSubnets: make(map[string][]*subnetType), 86 ipAddrToMacAddr: make(map[string]string), 87 staticLeases: make(map[string]leaseType), 88 requestChannels: make(map[string]chan net.IP), 89 routeTable: make(map[string]*util.RouteEntry), 90 dynamicLeases: make(map[string]*leaseType), 91 } 92 if interfaceIPs, myIPs, err := listMyIPs(); err != nil { 93 return nil, err 94 } else { 95 if len(myIPs) < 1 { 96 return nil, errors.New("no IP addresses found") 97 } 98 dhcpServer.interfaceIPs = interfaceIPs 99 dhcpServer.myIPs = myIPs 100 } 101 routeTable, err := util.GetRouteTable() 102 if err != nil { 103 return nil, err 104 } 105 for _, routeEntry := range routeTable.RouteEntries { 106 if len(routeEntry.GatewayAddr) < 1 || 107 routeEntry.GatewayAddr.Equal(net.IPv4zero) { 108 dhcpServer.routeTable[routeEntry.InterfaceName] = routeEntry 109 } 110 } 111 if len(interfaceNames) < 1 { 112 logger.Debugln(0, "Starting server on all broadcast interfaces") 113 interfaces, _, err := libnet.ListBroadcastInterfaces( 114 libnet.InterfaceTypeEtherNet| 115 libnet.InterfaceTypeBridge| 116 libnet.InterfaceTypeVlan, 117 logger) 118 if err != nil { 119 return nil, err 120 } else { 121 for _, iface := range interfaces { 122 interfaceNames = append(interfaceNames, iface.Name) 123 } 124 } 125 } else { 126 logger.Debugln(0, "Starting server on interfaces: "+ 127 strings.Join(interfaceNames, ",")) 128 } 129 serveConn := &serveIfConn{ 130 ifIndices: make(map[int]string, len(interfaceNames)), 131 requestInterface: &dhcpServer.requestInterface, 132 } 133 for _, interfaceName := range interfaceNames { 134 if iface, err := net.InterfaceByName(interfaceName); err != nil { 135 return nil, err 136 } else { 137 serveConn.ifIndices[iface.Index] = iface.Name 138 } 139 } 140 if err := dhcpServer.readDynamicLeases(); err != nil { 141 return nil, err 142 } 143 listener, err := net.ListenPacket("udp4", ":67") 144 if err != nil { 145 return nil, err 146 } 147 pktConn := ipv4.NewPacketConn(listener) 148 if err := pktConn.SetControlMessage(ipv4.FlagInterface, true); err != nil { 149 listener.Close() 150 return nil, err 151 } 152 serveConn.conn = pktConn 153 go func() { 154 if err := dhcp.Serve(serveConn, dhcpServer); err != nil { 155 logger.Println(err) 156 } 157 }() 158 go dhcpServer.cleanupDynamicLeasesLoop(cleanupTriggerChannel) 159 return dhcpServer, nil 160 } 161 162 func (s *DhcpServer) acknowledgeLease(ipAddr net.IP) { 163 ipStr := ipAddr.String() 164 s.mutex.Lock() 165 ackChan, ok := s.ackChannels[ipStr] 166 delete(s.ackChannels, ipStr) 167 s.mutex.Unlock() 168 if ok { 169 ackChan <- struct{}{} 170 close(ackChan) 171 } 172 } 173 174 func (s *DhcpServer) addLease(address proto.Address, doNetboot bool, 175 hostname string, protoSubnet *proto.Subnet) error { 176 address.Shrink() 177 if len(address.IpAddress) < 1 { 178 return errors.New("no IP address") 179 } 180 ipAddr := address.IpAddress.String() 181 var subnet *subnetType 182 s.mutex.Lock() 183 defer s.mutex.Unlock() 184 if protoSubnet == nil { 185 if subnet = s.findMatchingSubnet(address.IpAddress); subnet == nil { 186 return errors.New("no subnet found for " + ipAddr) 187 } 188 } else { 189 subnet = s.makeSubnet(protoSubnet) 190 } 191 if doNetboot { 192 if len(s.networkBootImage) < 1 { 193 return errors.New("no Network Boot Image name configured") 194 } 195 if _, ok := s.staticLeases[address.MacAddress]; ok { 196 return errors.New("already have lease for: " + address.MacAddress) 197 } 198 } 199 if lease, ok := s.dynamicLeases[address.MacAddress]; ok { 200 leaseIpAddr := lease.IpAddress.String() 201 s.logger.Printf("discarding {%s %s}: static lease\n", 202 leaseIpAddr, address.MacAddress) 203 delete(s.ipAddrToMacAddr, leaseIpAddr) 204 delete(s.dynamicLeases, address.MacAddress) 205 if err := s.writeDynamicLeases(); err != nil { 206 s.logger.Println(err) 207 } 208 } 209 if lease, ok := s.staticLeases[address.MacAddress]; ok { 210 leaseIpAddr := lease.IpAddress.String() 211 s.logger.Printf("replacing {%s %s}\n", leaseIpAddr, address.MacAddress) 212 delete(s.ipAddrToMacAddr, leaseIpAddr) 213 delete(s.staticLeases, address.MacAddress) 214 } 215 if macAddr, ok := s.ipAddrToMacAddr[ipAddr]; ok { 216 s.logger.Printf("replacing {%s %s}\n", ipAddr, macAddr) 217 delete(s.ipAddrToMacAddr, ipAddr) 218 delete(s.dynamicLeases, macAddr) 219 delete(s.staticLeases, macAddr) 220 } 221 s.ipAddrToMacAddr[ipAddr] = address.MacAddress 222 s.staticLeases[address.MacAddress] = leaseType{ 223 Address: address, 224 hostname: hostname, 225 doNetboot: doNetboot, 226 subnet: subnet, 227 } 228 return nil 229 } 230 231 func (s *DhcpServer) addSubnet(protoSubnet proto.Subnet) { 232 subnet := s.makeSubnet(&protoSubnet) 233 var ifaceName string 234 for name, ips := range s.interfaceIPs { 235 for _, ip := range ips { 236 if protoSubnet.IpGateway.Equal(ip) { 237 ifaceName = name 238 s.logger.Printf("attaching subnet GW: %s to interface: %s\n", 239 ip, name) 240 break 241 } 242 } 243 if ifaceName != "" { 244 break 245 } 246 } 247 s.mutex.Lock() 248 defer s.mutex.Unlock() 249 if ifaceName != "" { 250 s.interfaceSubnets[ifaceName] = append(s.interfaceSubnets[ifaceName], 251 subnet) 252 } 253 s.subnets = append(s.subnets, subnet) 254 } 255 256 func (s *DhcpServer) checkRouteOnInterface(addr net.IP, 257 interfaceName string) bool { 258 if route, ok := s.routeTable[interfaceName]; !ok { 259 return true 260 } else if route.Flags&util.RouteFlagUp == 0 { 261 return true 262 } else if addr.Mask(route.Mask).Equal(route.BaseAddr) { 263 return true 264 } 265 return false 266 } 267 268 func (s *DhcpServer) cleanupDynamicLeases() time.Duration { 269 numExpired := 0 270 waitTime := time.Hour 271 s.mutex.Lock() 272 defer s.mutex.Unlock() 273 for macAddr, lease := range s.dynamicLeases { 274 expiresIn := time.Until(lease.expires) 275 if expiresIn > 0 { 276 if expiresIn < waitTime { 277 waitTime = expiresIn 278 } 279 } else { 280 delete(s.ipAddrToMacAddr, lease.Address.IpAddress.String()) 281 delete(s.dynamicLeases, macAddr) 282 numExpired++ 283 } 284 } 285 if numExpired > 0 { 286 s.logger.Debugf(0, "expired %d dynamic leases\n", numExpired) 287 if err := s.writeDynamicLeases(); err != nil { 288 s.logger.Println(err) 289 } 290 } 291 return waitTime 292 } 293 294 func (s *DhcpServer) cleanupDynamicLeasesLoop(cleanupTrigger <-chan struct{}) { 295 timer := time.NewTimer(time.Second) 296 for { 297 select { 298 case <-cleanupTrigger: 299 if !timer.Stop() { 300 <-timer.C 301 } 302 timer.Reset(s.cleanupDynamicLeases()) 303 case <-timer.C: 304 timer.Reset(s.cleanupDynamicLeases()) 305 } 306 } 307 } 308 309 // This must be called with the lock held. 310 func (s *DhcpServer) computeLeaseTime(lease *leaseType, 311 offer bool) time.Duration { 312 if lease.expires.IsZero() { 313 return staticLeaseTime 314 } 315 if offer { 316 return time.Minute 317 } 318 lease.expires = time.Now().Add(dynamicLeaseTime) 319 select { 320 case s.cleanupTrigger <- struct{}{}: 321 default: 322 } 323 if err := s.writeDynamicLeases(); err != nil { 324 s.logger.Println(err) 325 } 326 return dynamicLeaseTime >> 1 327 } 328 329 // This must be called with the lock held. 330 func (s *DhcpServer) findDynamicLease(macAddr, iface string) ( 331 *leaseType, *subnetType) { 332 lease, ok := s.dynamicLeases[macAddr] 333 if !ok { 334 return nil, nil 335 } 336 if lease.subnet == nil { 337 if subnet := s.findMatchingSubnet(lease.IpAddress); subnet == nil { 338 s.logger.Printf("discarding {%s %s}: no subnet\n", 339 lease.IpAddress, lease.MacAddress) 340 delete(s.ipAddrToMacAddr, lease.IpAddress.String()) 341 delete(s.dynamicLeases, lease.MacAddress) 342 return nil, nil 343 } else { 344 lease.subnet = subnet 345 } 346 } 347 if !lease.subnet.dynamicOK() { 348 s.logger.Printf("discarding {%s %s}: no dynamic leases\n", 349 lease.IpAddress, lease.MacAddress) 350 delete(s.ipAddrToMacAddr, lease.IpAddress.String()) 351 delete(s.dynamicLeases, lease.MacAddress) 352 return nil, nil 353 } 354 for _, subnet := range s.interfaceSubnets[iface] { 355 if lease.subnet == subnet { 356 return lease, subnet 357 } 358 } 359 s.logger.Printf("discarding {%s %s}: no interface\n", 360 lease.IpAddress, lease.MacAddress) 361 delete(s.ipAddrToMacAddr, lease.IpAddress.String()) 362 delete(s.dynamicLeases, lease.MacAddress) 363 return nil, nil 364 } 365 366 // This must be called with the lock held. 367 func (s *DhcpServer) findLease(macAddr, iface string, reqIP net.IP) ( 368 *leaseType, *subnetType) { 369 if lease, subnet := s.findStaticLease(macAddr); lease != nil { 370 return lease, subnet 371 } 372 if lease, subnet := s.findDynamicLease(macAddr, iface); lease != nil { 373 return lease, subnet 374 } 375 for _, subnet := range s.interfaceSubnets[iface] { 376 if lease := s.makeDynamicLease(macAddr, subnet, reqIP); lease != nil { 377 return lease, subnet 378 } 379 } 380 return nil, nil 381 } 382 383 // This must be called with the lock held. 384 func (s *DhcpServer) findMatchingSubnet(ipAddr net.IP) *subnetType { 385 for _, subnet := range s.subnets { 386 subnetMask := net.IPMask(subnet.IpMask) 387 subnetAddr := subnet.IpGateway.Mask(subnetMask) 388 if ipAddr.Mask(subnetMask).Equal(subnetAddr) { 389 return subnet 390 } 391 } 392 return nil 393 } 394 395 // This must be called with the lock held. 396 func (s *DhcpServer) findStaticLease(macAddr string) (*leaseType, *subnetType) { 397 if lease, ok := s.staticLeases[macAddr]; ok { 398 if lease.subnet != nil { 399 return &lease, lease.subnet 400 } else { 401 return &lease, s.findMatchingSubnet(lease.IpAddress) 402 } 403 } 404 return nil, nil 405 } 406 407 func (s *DhcpServer) makeAcknowledgmentChannel(ipAddr net.IP) <-chan struct{} { 408 ipStr := ipAddr.String() 409 newChan := make(chan struct{}, 1) 410 s.mutex.Lock() 411 oldChan, ok := s.ackChannels[ipStr] 412 s.ackChannels[ipStr] = newChan 413 s.mutex.Unlock() 414 if ok { 415 close(oldChan) 416 } 417 return newChan 418 } 419 420 // This must be called with the lock held. 421 func (s *DhcpServer) makeDynamicLease(macAddr string, subnet *subnetType, 422 reqIP net.IP) *leaseType { 423 if !subnet.dynamicOK() { 424 return nil 425 } 426 stopIP := util.CopyIP(subnet.LastDynamicIP) 427 util.IncrementIP(stopIP) 428 if len(reqIP) == 4 { 429 reqIpString := reqIP.String() 430 if _, ok := s.ipAddrToMacAddr[reqIpString]; !ok { 431 lowIP := util.CopyIP(subnet.FirstDynamicIP) 432 util.DecrementIP(lowIP) 433 if util.CompareIPs(lowIP, reqIP) && util.CompareIPs(reqIP, stopIP) { 434 lease := leaseType{Address: proto.Address{ 435 IpAddress: reqIP, 436 MacAddress: macAddr, 437 }, 438 expires: time.Now().Add(time.Second * 10), 439 subnet: subnet, 440 } 441 s.dynamicLeases[macAddr] = &lease 442 s.ipAddrToMacAddr[reqIpString] = macAddr 443 select { 444 case s.cleanupTrigger <- struct{}{}: 445 default: 446 } 447 return &lease 448 } 449 } 450 } 451 if len(subnet.nextDynamicIP) < 4 { 452 subnet.nextDynamicIP = util.CopyIP(subnet.FirstDynamicIP) 453 } 454 initialIp := util.CopyIP(subnet.nextDynamicIP) 455 for { 456 testIp := util.CopyIP(subnet.nextDynamicIP) 457 testIpString := testIp.String() 458 util.IncrementIP(subnet.nextDynamicIP) 459 if _, ok := s.ipAddrToMacAddr[testIpString]; !ok { 460 lease := leaseType{Address: proto.Address{ 461 IpAddress: testIp, 462 MacAddress: macAddr, 463 }, 464 expires: time.Now().Add(time.Second * 10), 465 subnet: subnet, 466 } 467 s.dynamicLeases[macAddr] = &lease 468 s.ipAddrToMacAddr[testIpString] = macAddr 469 select { 470 case s.cleanupTrigger <- struct{}{}: 471 default: 472 } 473 return &lease 474 } 475 if subnet.nextDynamicIP.Equal(stopIP) { 476 copy(subnet.nextDynamicIP, subnet.FirstDynamicIP) 477 } 478 if initialIp.Equal(subnet.nextDynamicIP) { 479 break 480 } 481 } 482 return nil 483 } 484 485 func (s *DhcpServer) makeOptions(subnet *subnetType, 486 lease *leaseType) dhcp.Options { 487 dnsServers := make([]byte, 0) 488 for _, dnsServer := range subnet.DomainNameServers { 489 dnsServers = append(dnsServers, dnsServer...) 490 } 491 leaseOptions := dhcp.Options{ 492 dhcp.OptionSubnetMask: subnet.IpMask, 493 dhcp.OptionRouter: subnet.IpGateway, 494 dhcp.OptionDomainNameServer: dnsServers, 495 } 496 if subnet.DomainName != "" { 497 leaseOptions[dhcp.OptionDomainName] = []byte(subnet.DomainName) 498 } 499 if lease.hostname != "" { 500 leaseOptions[dhcp.OptionHostName] = []byte(lease.hostname) 501 } 502 if lease.doNetboot { 503 leaseOptions[dhcp.OptionBootFileName] = s.networkBootImage 504 } 505 return leaseOptions 506 } 507 508 func (s *DhcpServer) makeRequestChannel(macAddr string) <-chan net.IP { 509 s.mutex.Lock() 510 defer s.mutex.Unlock() 511 if oldChan, ok := s.requestChannels[macAddr]; ok { 512 return oldChan 513 } 514 newChan := make(chan net.IP, 16) 515 s.requestChannels[macAddr] = newChan 516 return newChan 517 } 518 519 func (s *DhcpServer) makeSubnet(protoSubnet *proto.Subnet) *subnetType { 520 subnet := &subnetType{Subnet: *protoSubnet, myIP: s.myIPs[0]} 521 for _, ip := range s.myIPs { 522 if ip.Equal(subnet.IpGateway) { 523 subnet.amGateway = true 524 } 525 subnetMask := net.IPMask(subnet.IpMask) 526 subnetAddr := subnet.IpGateway.Mask(subnetMask) 527 if ip.Mask(subnetMask).Equal(subnetAddr) { 528 subnet.myIP = ip 529 break 530 } 531 } 532 return subnet 533 } 534 535 func (s *DhcpServer) notifyRequest(address proto.Address) { 536 s.mutex.RLock() 537 requestChan, ok := s.requestChannels[address.MacAddress] 538 s.mutex.RUnlock() 539 if ok { 540 select { 541 case requestChan <- address.IpAddress: 542 default: 543 } 544 } 545 } 546 547 // This must be called with the lock held. 548 func (s *DhcpServer) readDynamicLeases() error { 549 var leases []dynamicLeaseType 550 if err := json.ReadFromFile(s.dynamicLeasesFile, &leases); err != nil { 551 if os.IsNotExist(err) { 552 return nil 553 } 554 return err 555 } 556 numExpiredLeases := 0 557 numValidLeases := 0 558 for _, lease := range leases { 559 if time.Until(lease.Expires) > 0 { 560 s.dynamicLeases[lease.Address.MacAddress] = &leaseType{ 561 Address: lease.Address, 562 expires: lease.Expires, 563 } 564 s.ipAddrToMacAddr[lease.Address.IpAddress.String()] = 565 lease.Address.MacAddress 566 numValidLeases++ 567 } else { 568 numExpiredLeases++ 569 } 570 } 571 if numExpiredLeases > 0 { 572 return s.writeDynamicLeases() 573 } 574 if numExpiredLeases > 0 || numValidLeases > 0 { 575 s.logger.Printf("read dynamic leases: %d valid and %d expired\n", 576 numValidLeases, numExpiredLeases) 577 } 578 return nil 579 } 580 581 func (s *DhcpServer) removeLease(ipAddr net.IP) { 582 if len(ipAddr) < 1 { 583 return 584 } 585 ipStr := ipAddr.String() 586 s.mutex.Lock() 587 delete(s.staticLeases, s.ipAddrToMacAddr[ipStr]) 588 delete(s.ipAddrToMacAddr, ipStr) 589 ackChan, ok := s.ackChannels[ipStr] 590 delete(s.ackChannels, ipStr) 591 s.mutex.Unlock() 592 if ok { 593 close(ackChan) 594 } 595 } 596 597 func (s *DhcpServer) removeSubnet(subnetId string) { 598 s.mutex.Lock() 599 defer s.mutex.Unlock() 600 subnets := make([]*subnetType, 0, len(s.subnets)-1) 601 var subnetToDelete *subnetType 602 for _, subnet := range s.subnets { 603 if subnet.Id == subnetId { 604 subnetToDelete = subnet 605 } else { 606 subnets = append(subnets, subnet) 607 } 608 } 609 s.subnets = subnets 610 if subnetToDelete == nil { 611 return 612 } 613 for name, subnets := range s.interfaceSubnets { 614 subnets := make([]*subnetType, 0, len(subnets)-1) 615 for _, subnet := range subnets { 616 if subnet == subnetToDelete { 617 s.logger.Printf("detaching subnet GW: %s from interface: %s\n", 618 subnet.IpGateway, name) 619 } else { 620 subnets = append(subnets, subnet) 621 } 622 } 623 s.interfaceSubnets[name] = subnets 624 } 625 } 626 627 func (s *DhcpServer) ServeDHCP(req dhcp.Packet, msgType dhcp.MessageType, 628 options dhcp.Options) dhcp.Packet { 629 switch msgType { 630 case dhcp.Discover: 631 macAddr := req.CHAddr().String() 632 s.logger.Debugf(1, "Discover from: %s on: %s\n", 633 macAddr, s.requestInterface) 634 s.mutex.Lock() 635 defer s.mutex.Unlock() 636 lease, subnet := s.findLease(macAddr, s.requestInterface, nil) 637 if lease == nil { 638 return nil 639 } 640 if subnet == nil { 641 s.logger.Printf("No subnet found for %s\n", lease.IpAddress) 642 return nil 643 } 644 if !s.checkRouteOnInterface(lease.IpAddress, s.requestInterface) { 645 s.logger.Printf( 646 "suppressing offer: %s for: %s, wrong interface: %s\n", 647 lease.IpAddress, macAddr, s.requestInterface) 648 return nil 649 } 650 s.logger.Debugf(0, "Offer: %s for: %s, server: %s\n", 651 lease.IpAddress, macAddr, subnet.myIP) 652 leaseOptions := s.makeOptions(subnet, lease) 653 packet := dhcp.ReplyPacket(req, dhcp.Offer, subnet.myIP, 654 lease.IpAddress, s.computeLeaseTime(lease, true), 655 leaseOptions.SelectOrderOrAll( 656 options[dhcp.OptionParameterRequestList])) 657 packet.SetSIAddr(subnet.myIP) 658 return packet 659 case dhcp.Request: 660 macAddr := req.CHAddr().String() 661 reqIP := net.IP(options[dhcp.OptionRequestedIPAddress]) 662 if reqIP == nil { 663 reqIP = net.IP(req.CIAddr()) 664 s.logger.Debugf(0, 665 "Request from: %s on: %s did not request an IP, using: %s\n", 666 macAddr, s.requestInterface, reqIP) 667 } 668 reqIP = util.ShrinkIP(reqIP) 669 s.notifyRequest(proto.Address{reqIP, macAddr}) 670 server, ok := options[dhcp.OptionServerIdentifier] 671 if ok { 672 serverIP := net.IP(server) 673 if !serverIP.IsUnspecified() { 674 isMe := false 675 for _, ip := range s.myIPs { 676 if serverIP.Equal(ip) { 677 isMe = true 678 break 679 } 680 } 681 if !isMe { 682 s.logger.Debugf(0, 683 "Request for: %s from: %s to: %s is not me\n", 684 reqIP, macAddr, serverIP) 685 return nil // Message not for this DHCP server. 686 } 687 } 688 } 689 hostname := string(options[dhcp.OptionHostName]) 690 if hostname != "" { 691 s.logger.Debugf(0, "Request for: %s from: %s on: %s HostName=%s\n", 692 reqIP, macAddr, s.requestInterface, hostname) 693 } else { 694 s.logger.Debugf(0, "Request for: %s from: %s on: %s\n", 695 reqIP, macAddr, s.requestInterface) 696 } 697 s.mutex.Lock() 698 defer s.mutex.Unlock() 699 lease, subnet := s.findLease(macAddr, s.requestInterface, reqIP) 700 if lease == nil { 701 s.logger.Printf("No lease found for %s\n", macAddr) 702 return nil 703 } 704 if subnet == nil { 705 s.logger.Printf("No subnet found for %s\n", lease.IpAddress) 706 return nil 707 } 708 if reqIP.Equal(lease.IpAddress) && 709 s.checkRouteOnInterface(lease.IpAddress, s.requestInterface) { 710 leaseOptions := s.makeOptions(subnet, lease) 711 go s.acknowledgeLease(lease.IpAddress) 712 lease.clientHostname = hostname 713 s.logger.Debugf(0, "ACK for: %s to: %s on: %s, server: %s\n", 714 reqIP, macAddr, s.requestInterface, subnet.myIP) 715 packet := dhcp.ReplyPacket(req, dhcp.ACK, subnet.myIP, reqIP, 716 s.computeLeaseTime(lease, false), leaseOptions.SelectOrderOrAll( 717 options[dhcp.OptionParameterRequestList])) 718 packet.SetSIAddr(subnet.myIP) 719 return packet 720 } else { 721 s.logger.Debugf(0, "NAK for: %s to: %s on: %s\n", 722 reqIP, macAddr, s.requestInterface) 723 return dhcp.ReplyPacket(req, dhcp.NAK, subnet.myIP, nil, 0, nil) 724 } 725 default: 726 s.logger.Debugf(0, "Unsupported message type: %s on: %s\n", 727 msgType, s.requestInterface) 728 } 729 return nil 730 } 731 732 // This must be called with the lock held. 733 func (s *DhcpServer) writeDynamicLeases() error { 734 var leases []dynamicLeaseType 735 for _, lease := range s.dynamicLeases { 736 if time.Until(lease.expires) > 0 { 737 leases = append(leases, 738 dynamicLeaseType{ 739 ClientHostName: lease.clientHostname, 740 Expires: lease.expires, 741 Address: lease.Address, 742 }) 743 } 744 } 745 if len(leases) < 1 { 746 os.Remove(s.dynamicLeasesFile) 747 return nil 748 } 749 sort.Slice(leases, func(left, right int) bool { 750 return leases[left].Address.IpAddress.String() < 751 leases[right].Address.IpAddress.String() 752 }) 753 return json.WriteToFile(s.dynamicLeasesFile, fsutil.PublicFilePerms, " ", 754 leases) 755 } 756 757 func (s *serveIfConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) { 758 for { 759 n, s.cm, addr, err = s.conn.ReadFrom(b) 760 if err != nil || s.cm == nil { 761 *s.requestInterface = "UNKNOWN" 762 break 763 } 764 if name, ok := s.ifIndices[s.cm.IfIndex]; ok { 765 *s.requestInterface = name 766 break 767 } 768 } 769 return 770 } 771 772 func (s *serveIfConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { 773 s.cm.Src = nil 774 return s.conn.WriteTo(b, s.cm, addr) 775 } 776 777 // This must be called with the lock held. 778 func (subnet *subnetType) dynamicOK() bool { 779 if !subnet.amGateway { 780 return false 781 } 782 if len(subnet.FirstDynamicIP) < 4 || len(subnet.LastDynamicIP) < 4 { 783 return false 784 } 785 return true 786 }