leases.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Russ Dill <Russ.Dill@asu.edu> July 2001
  4. *
  5. * Licensed under GPLv2, see file LICENSE in this tarball for details.
  6. */
  7. #include "common.h"
  8. #include "dhcpd.h"
  9. /* Find the oldest expired lease, NULL if there are no expired leases */
  10. static struct dyn_lease *oldest_expired_lease(void)
  11. {
  12. struct dyn_lease *oldest_lease = NULL;
  13. leasetime_t oldest_time = time(NULL);
  14. unsigned i;
  15. /* Unexpired leases have g_leases[i].expires >= current time
  16. * and therefore can't ever match */
  17. for (i = 0; i < server_config.max_leases; i++) {
  18. if (g_leases[i].expires < oldest_time) {
  19. oldest_time = g_leases[i].expires;
  20. oldest_lease = &g_leases[i];
  21. }
  22. }
  23. return oldest_lease;
  24. }
  25. /* Clear out all leases with matching nonzero chaddr OR yiaddr.
  26. * If chaddr == NULL, this is a conflict lease.
  27. */
  28. static void clear_leases(const uint8_t *chaddr, uint32_t yiaddr)
  29. {
  30. unsigned i;
  31. for (i = 0; i < server_config.max_leases; i++) {
  32. if ((chaddr && memcmp(g_leases[i].lease_mac, chaddr, 6) == 0)
  33. || (yiaddr && g_leases[i].lease_nip == yiaddr)
  34. ) {
  35. memset(&g_leases[i], 0, sizeof(g_leases[i]));
  36. }
  37. }
  38. }
  39. /* Add a lease into the table, clearing out any old ones.
  40. * If chaddr == NULL, this is a conflict lease.
  41. */
  42. struct dyn_lease* FAST_FUNC add_lease(
  43. const uint8_t *chaddr, uint32_t yiaddr,
  44. leasetime_t leasetime,
  45. const char *hostname, int hostname_len)
  46. {
  47. struct dyn_lease *oldest;
  48. /* clean out any old ones */
  49. clear_leases(chaddr, yiaddr);
  50. oldest = oldest_expired_lease();
  51. if (oldest) {
  52. memset(oldest, 0, sizeof(*oldest));
  53. if (hostname) {
  54. char *p;
  55. hostname_len++; /* include NUL */
  56. if (hostname_len > sizeof(oldest->hostname))
  57. hostname_len = sizeof(oldest->hostname);
  58. p = safe_strncpy(oldest->hostname, hostname, hostname_len);
  59. /* sanitization (s/non-ASCII/^/g) */
  60. while (*p) {
  61. if (*p < ' ' || *p > 126)
  62. *p = '^';
  63. p++;
  64. }
  65. }
  66. if (chaddr)
  67. memcpy(oldest->lease_mac, chaddr, 6);
  68. oldest->lease_nip = yiaddr;
  69. oldest->expires = time(NULL) + leasetime;
  70. }
  71. return oldest;
  72. }
  73. /* True if a lease has expired */
  74. int FAST_FUNC is_expired_lease(struct dyn_lease *lease)
  75. {
  76. return (lease->expires < (leasetime_t) time(NULL));
  77. }
  78. /* Find the first lease that matches MAC, NULL if no match */
  79. struct dyn_lease* FAST_FUNC find_lease_by_mac(const uint8_t *mac)
  80. {
  81. unsigned i;
  82. for (i = 0; i < server_config.max_leases; i++)
  83. if (memcmp(g_leases[i].lease_mac, mac, 6) == 0)
  84. return &g_leases[i];
  85. return NULL;
  86. }
  87. /* Find the first lease that matches IP, NULL is no match */
  88. struct dyn_lease* FAST_FUNC find_lease_by_nip(uint32_t nip)
  89. {
  90. unsigned i;
  91. for (i = 0; i < server_config.max_leases; i++)
  92. if (g_leases[i].lease_nip == nip)
  93. return &g_leases[i];
  94. return NULL;
  95. }
  96. /* Check if the IP is taken; if it is, add it to the lease table */
  97. static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac)
  98. {
  99. struct in_addr temp;
  100. int r;
  101. r = arpping(nip, safe_mac,
  102. server_config.server_nip,
  103. server_config.server_mac,
  104. server_config.interface);
  105. if (r)
  106. return r;
  107. temp.s_addr = nip;
  108. bb_info_msg("%s belongs to someone, reserving it for %u seconds",
  109. inet_ntoa(temp), (unsigned)server_config.conflict_time);
  110. add_lease(NULL, nip, server_config.conflict_time, NULL, 0);
  111. return 0;
  112. }
  113. /* Find a new usable (we think) address */
  114. uint32_t FAST_FUNC find_free_or_expired_nip(const uint8_t *safe_mac)
  115. {
  116. uint32_t addr;
  117. struct dyn_lease *oldest_lease = NULL;
  118. addr = server_config.start_ip; /* addr is in host order here */
  119. for (; addr <= server_config.end_ip; addr++) {
  120. uint32_t nip;
  121. struct dyn_lease *lease;
  122. /* ie, 192.168.55.0 */
  123. if ((addr & 0xff) == 0)
  124. continue;
  125. /* ie, 192.168.55.255 */
  126. if ((addr & 0xff) == 0xff)
  127. continue;
  128. nip = htonl(addr);
  129. /* is this a static lease addr? */
  130. if (is_nip_reserved(server_config.static_leases, nip))
  131. continue;
  132. lease = find_lease_by_nip(nip);
  133. if (!lease) {
  134. //TODO: DHCP servers do not always sit on the same subnet as clients: should *ping*, not arp-ping!
  135. if (nobody_responds_to_arp(nip, safe_mac))
  136. return nip;
  137. } else {
  138. if (!oldest_lease || lease->expires < oldest_lease->expires)
  139. oldest_lease = lease;
  140. }
  141. }
  142. if (oldest_lease
  143. && is_expired_lease(oldest_lease)
  144. && nobody_responds_to_arp(oldest_lease->lease_nip, safe_mac)
  145. ) {
  146. return oldest_lease->lease_nip;
  147. }
  148. return 0;
  149. }