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