dhcpd: remember and record hostnames; optimize get_option
authorDenis Vlasenko <vda.linux@googlemail.com>
Wed, 1 Apr 2009 12:36:09 +0000 (12:36 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Wed, 1 Apr 2009 12:36:09 +0000 (12:36 -0000)
dumpleases: show hostnames

function                                             old     new   delta
add_lease                                            230     292     +62
send_offer                                           403     421     +18
send_ACK                                             232     249     +17
read_leases                                          249     258      +9
dumpleases_main                                      604     609      +5
nobody_responds_to_arp                                84      86      +2
udhcp_end_option                                      32      30      -2
udhcp_get_option                                     222     171     -51
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 6/2 up/down: 113/-53)            Total: 60 bytes

networking/udhcp/dhcpd.h
networking/udhcp/dumpleases.c
networking/udhcp/files.c
networking/udhcp/leases.c
networking/udhcp/options.c
networking/udhcp/options.h
networking/udhcp/script.c
networking/udhcp/serverpacket.c

index 02e392aaf0e92ac8c7572898e37b68249bdd596d..b4e180882ad017a716eba9a90dad4b96ff4c85c5 100644 (file)
@@ -74,8 +74,6 @@ struct server_config_t {
 #define SERVER_PORT 67
 #endif
 
-extern struct dhcpOfferedAddr *leases;
-
 
 /*** leases.h ***/
 
@@ -92,9 +90,15 @@ struct dhcpOfferedAddr {
         * and optionally adjusted (current time subtracted)
         * if server_config.remaining = 1 */
        leasetime_t expires;
+       uint8_t hostname[20]; /* (size is a multiply of 4) */
 };
 
-struct dhcpOfferedAddr *add_lease(const uint8_t *chaddr, uint32_t yiaddr, leasetime_t leasetime) FAST_FUNC;
+extern struct dhcpOfferedAddr *leases;
+
+struct dhcpOfferedAddr *add_lease(
+               const uint8_t *chaddr, uint32_t yiaddr,
+               leasetime_t leasetime, uint8_t *hostname
+               ) FAST_FUNC;
 int lease_expired(struct dhcpOfferedAddr *lease) FAST_FUNC;
 struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr) FAST_FUNC;
 struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr) FAST_FUNC;
index c0d515d283d7cff0259cf6533fd36cac4a002ff5..1558f8848c8ea53ec1392da58a82153bdc6c55cb 100644 (file)
@@ -47,8 +47,9 @@ int dumpleases_main(int argc UNUSED_PARAM, char **argv)
 
        fd = xopen(file, O_RDONLY);
 
-       printf("Mac Address       IP-Address      Expires %s\n", (opt & OPT_a) ? "at" : "in");
-       /*     "00:00:00:00:00:00 255.255.255.255 Wed Jun 30 21:49:08 1993" */
+       printf("Mac Address       IP Address      Host Name           Expires %s\n", (opt & OPT_a) ? "at" : "in");
+       /*     "00:00:00:00:00:00 255.255.255.255 ABCDEFGHIJKLMNOPQRS Wed Jun 30 21:49:08 1993" */
+       /*     "123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 */
 
        if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at))
                return 0;
@@ -64,7 +65,9 @@ int dumpleases_main(int argc UNUSED_PARAM, char **argv)
                        fmt = ":%02x";
                }
                addr.s_addr = lease.yiaddr;
-               printf(" %-15s ", inet_ntoa(addr));
+               /* actually, 15+1 and 19+1, +1 is a space between columns */
+               /* lease.hostname is char[20] and is always NUL terminated */
+               printf(" %-16s%-20s", inet_ntoa(addr), lease.hostname);
                expires_abs = ntohl(lease.expires) + written_at;
                if (expires_abs <= curr) {
                        puts("expired");
index fb6fe01ae6158792d1c687809d8da6180c5ec600..a061a9c9bb469e0ef91c370c3b7e1dd2d4edfc19 100644 (file)
@@ -420,7 +420,7 @@ void FAST_FUNC read_leases(const char *file)
                                continue;
                        /* NB: add_lease takes "relative time", IOW,
                         * lease duration, not lease deadline. */
-                       if (!(add_lease(lease.chaddr, lease.yiaddr, expires))) {
+                       if (!(add_lease(lease.chaddr, lease.yiaddr, expires, lease.hostname))) {
                                bb_error_msg("too many leases while loading %s", file);
                                break;
                        }
index 3044c204083d9ec3caabd61ff447061bdfec4186..d62f324710b463053042f1f3ce5695375cd145fa 100644 (file)
@@ -48,9 +48,12 @@ static void clear_lease(const uint8_t *chaddr, uint32_t yiaddr)
 
 
 /* Add a lease into the table, clearing out any old ones */
-struct dhcpOfferedAddr* FAST_FUNC add_lease(const uint8_t *chaddr, uint32_t yiaddr, leasetime_t leasetime)
+struct dhcpOfferedAddr* FAST_FUNC add_lease(
+               const uint8_t *chaddr, uint32_t yiaddr,
+               leasetime_t leasetime, uint8_t *hostname)
 {
        struct dhcpOfferedAddr *oldest;
+       uint8_t hostname_length;
 
        /* clean out any old ones */
        clear_lease(chaddr, yiaddr);
@@ -58,6 +61,19 @@ struct dhcpOfferedAddr* FAST_FUNC add_lease(const uint8_t *chaddr, uint32_t yiad
        oldest = oldest_expired_lease();
 
        if (oldest) {
+               oldest->hostname[0] = '\0';
+               if (hostname) {
+                       hostname_length = hostname[-1]; /* look at option size byte */
+                       if (hostname_length > sizeof(oldest->hostname))
+                               hostname_length = sizeof(oldest->hostname);
+                       hostname = (uint8_t*) safe_strncpy((char*)oldest->hostname, (char*)hostname, hostname_length);
+                       /* sanitization (s/non-ACSII/^/g) */
+                       while (*hostname) {
+                               if (*hostname < ' ' || *hostname > 126)
+                                       *hostname = '^';
+                               hostname++;
+                       }
+               }
                memcpy(oldest->chaddr, chaddr, 16);
                oldest->yiaddr = yiaddr;
                oldest->expires = time(NULL) + leasetime;
@@ -117,7 +133,7 @@ static int nobody_responds_to_arp(uint32_t addr)
        temp.s_addr = addr;
        bb_info_msg("%s belongs to someone, reserving it for %u seconds",
                inet_ntoa(temp), (unsigned)server_config.conflict_time);
-       add_lease(blank_chaddr, addr, server_config.conflict_time);
+       add_lease(blank_chaddr, addr, server_config.conflict_time, NULL);
        return 0;
 }
 
index 581a7b67134f7efcafd2a21c249d32921bc269d0..143a1fd1ca557a4adc948aa5fe9f359b393cd65b 100644 (file)
@@ -119,58 +119,61 @@ const uint8_t dhcp_option_lengths[] ALIGN1 = {
 };
 
 
-/* get an option with bounds checking (warning, not aligned). */
+/* get an option with bounds checking (warning, result is not aligned). */
 uint8_t* FAST_FUNC get_option(struct dhcpMessage *packet, int code)
 {
-       int i, length;
        uint8_t *optionptr;
-       int over = 0;
-       int curr = OPTION_FIELD;
-
+       int len;
+       int rem;
+       int overload = 0;
+       enum {
+               FILE_FIELD101  = FILE_FIELD  * 0x101,
+               SNAME_FIELD101 = SNAME_FIELD * 0x101,
+       };
+
+       /* option bytes: [code][len][data1][data2]..[dataLEN] */
        optionptr = packet->options;
-       i = 0;
-       length = sizeof(packet->options);
+       rem = sizeof(packet->options);
        while (1) {
-               if (i >= length) {
-                       bb_error_msg("bogus packet, option fields too long");
+               if (rem <= 0) {
+                       bb_error_msg("bogus packet, malformed option field");
                        return NULL;
                }
-               if (optionptr[i + OPT_CODE] == code) {
-                       if (i + 1 + optionptr[i + OPT_LEN] >= length) {
-                               bb_error_msg("bogus packet, option fields too long");
-                               return NULL;
-                       }
-                       return optionptr + i + 2;
+               if (optionptr[OPT_CODE] == DHCP_PADDING) {
+                       rem--;
+                       optionptr++;
+                       continue;
                }
-               switch (optionptr[i + OPT_CODE]) {
-               case DHCP_PADDING:
-                       i++;
-                       break;
-               case DHCP_OPTION_OVER:
-                       if (i + 1 + optionptr[i + OPT_LEN] >= length) {
-                               bb_error_msg("bogus packet, option fields too long");
-                               return NULL;
-                       }
-                       over = optionptr[i + 3];
-                       i += optionptr[OPT_LEN] + 2;
-                       break;
-               case DHCP_END:
-                       if (curr == OPTION_FIELD && (over & FILE_FIELD)) {
+               if (optionptr[OPT_CODE] == DHCP_END) {
+                       if ((overload & FILE_FIELD101) == FILE_FIELD) {
+                               /* can use packet->file, and didn't look at it yet */
+                               overload |= FILE_FIELD101; /* "we looked at it" */
                                optionptr = packet->file;
-                               i = 0;
-                               length = sizeof(packet->file);
-                               curr = FILE_FIELD;
-                       } else if (curr == FILE_FIELD && (over & SNAME_FIELD)) {
+                               rem = sizeof(packet->file);
+                               continue;
+                       }
+                       if ((overload & SNAME_FIELD101) == SNAME_FIELD) {
+                               /* can use packet->sname, and didn't look at it yet */
+                               overload |= SNAME_FIELD101; /* "we looked at it" */
                                optionptr = packet->sname;
-                               i = 0;
-                               length = sizeof(packet->sname);
-                               curr = SNAME_FIELD;
-                       } else
-                               return NULL;
-                       break;
-               default:
-                       i += optionptr[OPT_LEN + i] + 2;
+                               rem = sizeof(packet->sname);
+                               continue;
+                       }
+                       return NULL;
+               }
+               len = 2 + optionptr[OPT_LEN];
+               rem -= len;
+               if (rem < 0)
+                       continue; /* complain and return NULL */
+
+               if (optionptr[OPT_CODE] == code)
+                       return optionptr + OPT_DATA;
+
+               if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) {
+                       overload |= optionptr[OPT_DATA];
+                       /* fall through */
                }
+               optionptr += len;
        }
        return NULL;
 }
@@ -182,17 +185,16 @@ int FAST_FUNC end_option(uint8_t *optionptr)
        int i = 0;
 
        while (optionptr[i] != DHCP_END) {
-               if (optionptr[i] == DHCP_PADDING)
-                       i++;
-               else
-                       i += optionptr[i + OPT_LEN] + 2;
+               if (optionptr[i] != DHCP_PADDING)
+                       i += optionptr[i + OPT_LEN] + 1;
+               i++;
        }
        return i;
 }
 
 
-/* add an option string to the options (an option string contains an option code,
- * length, then data) */
+/* add an option string to the options */
+/* option bytes: [code][len][data1][data2]..[dataLEN] */
 int FAST_FUNC add_option_string(uint8_t *optionptr, uint8_t *string)
 {
        int end = end_option(optionptr);
index d18a353d0dcfeecb8c626165a5f1054ece866e52..87440c30cfa9b7b2287b2e2a0fd50d40092c0717 100644 (file)
@@ -7,7 +7,7 @@
 # pragma GCC visibility push(hidden)
 #endif
 
-#define TYPE_MASK      0x0F
+#define TYPE_MASK       0x0F
 
 enum {
        OPTION_IP = 1,
@@ -24,8 +24,8 @@ enum {
        OPTION_S32
 };
 
-#define OPTION_REQ     0x10 /* have the client request this option */
-#define OPTION_LIST    0x20 /* There can be a list of 1 or more of these */
+#define OPTION_REQ      0x10 /* have the client request this option */
+#define OPTION_LIST     0x20 /* There can be a list of 1 or more of these */
 
 /*****************************************************************/
 /* Do not modify below here unless you know what you are doing!! */
@@ -34,67 +34,64 @@ enum {
 /* DHCP protocol -- see RFC 2131 */
 #define DHCP_MAGIC             0x63825363
 
-
 /* DHCP option codes (partial list) */
-#define DHCP_PADDING           0x00
-#define DHCP_SUBNET            0x01
-#define DHCP_TIME_OFFSET       0x02
-#define DHCP_ROUTER            0x03
-#define DHCP_TIME_SERVER       0x04
-#define DHCP_NAME_SERVER       0x05
-#define DHCP_DNS_SERVER                0x06
-#define DHCP_LOG_SERVER                0x07
-#define DHCP_COOKIE_SERVER     0x08
-#define DHCP_LPR_SERVER                0x09
-#define DHCP_HOST_NAME         0x0c
-#define DHCP_BOOT_SIZE         0x0d
-#define DHCP_DOMAIN_NAME       0x0f
-#define DHCP_SWAP_SERVER       0x10
-#define DHCP_ROOT_PATH         0x11
-#define DHCP_IP_TTL            0x17
-#define DHCP_MTU               0x1a
-#define DHCP_BROADCAST         0x1c
-#define DHCP_NTP_SERVER                0x2a
-#define DHCP_WINS_SERVER       0x2c
-#define DHCP_REQUESTED_IP      0x32
-#define DHCP_LEASE_TIME                0x33
-#define DHCP_OPTION_OVER       0x34
-#define DHCP_MESSAGE_TYPE      0x35
-#define DHCP_SERVER_ID         0x36
-#define DHCP_PARAM_REQ         0x37
-#define DHCP_MESSAGE           0x38
-#define DHCP_MAX_SIZE          0x39
-#define DHCP_T1                        0x3a
-#define DHCP_T2                        0x3b
-#define DHCP_VENDOR            0x3c
-#define DHCP_CLIENT_ID         0x3d
-#define DHCP_FQDN              0x51
-#define DHCP_END               0xFF
-
-
-#define BOOTREQUEST            1
-#define BOOTREPLY              2
-
-#define ETH_10MB               1
-#define ETH_10MB_LEN           6
-
-#define DHCPDISCOVER           1 /* client -> server */
-#define DHCPOFFER              2 /* client <- server */
-#define DHCPREQUEST            3 /* client -> server */
-#define DHCPDECLINE            4 /* client -> server */
-#define DHCPACK                        5 /* client <- server */
-#define DHCPNAK                        6 /* client <- server */
-#define DHCPRELEASE            7 /* client -> server */
-#define DHCPINFORM             8 /* client -> server */
-
-#define OPTION_FIELD           0
-#define FILE_FIELD             1
-#define SNAME_FIELD            2
-
-/* miscellaneous defines */
-#define OPT_CODE 0
-#define OPT_LEN 1
-#define OPT_DATA 2
+#define DHCP_PADDING            0x00
+#define DHCP_SUBNET             0x01
+#define DHCP_TIME_OFFSET        0x02
+#define DHCP_ROUTER             0x03
+#define DHCP_TIME_SERVER        0x04
+#define DHCP_NAME_SERVER        0x05
+#define DHCP_DNS_SERVER         0x06
+#define DHCP_LOG_SERVER         0x07
+#define DHCP_COOKIE_SERVER      0x08
+#define DHCP_LPR_SERVER         0x09
+#define DHCP_HOST_NAME          0x0c
+#define DHCP_BOOT_SIZE          0x0d
+#define DHCP_DOMAIN_NAME        0x0f
+#define DHCP_SWAP_SERVER        0x10
+#define DHCP_ROOT_PATH          0x11
+#define DHCP_IP_TTL             0x17
+#define DHCP_MTU                0x1a
+#define DHCP_BROADCAST          0x1c
+#define DHCP_NTP_SERVER         0x2a
+#define DHCP_WINS_SERVER        0x2c
+#define DHCP_REQUESTED_IP       0x32
+#define DHCP_LEASE_TIME         0x33
+#define DHCP_OPTION_OVERLOAD    0x34
+#define DHCP_MESSAGE_TYPE       0x35
+#define DHCP_SERVER_ID          0x36
+#define DHCP_PARAM_REQ          0x37
+#define DHCP_MESSAGE            0x38
+#define DHCP_MAX_SIZE           0x39
+#define DHCP_T1                 0x3a
+#define DHCP_T2                 0x3b
+#define DHCP_VENDOR             0x3c
+#define DHCP_CLIENT_ID          0x3d
+#define DHCP_FQDN               0x51
+#define DHCP_END                0xFF
+/* Offsets in option byte sequence */
+#define OPT_CODE                0
+#define OPT_LEN                 1
+#define OPT_DATA                2
+/* Bits in "overload" option */
+#define OPTION_FIELD            0
+#define FILE_FIELD              1
+#define SNAME_FIELD             2
+
+#define BOOTREQUEST             1
+#define BOOTREPLY               2
+
+#define ETH_10MB                1
+#define ETH_10MB_LEN            6
+
+#define DHCPDISCOVER            1 /* client -> server */
+#define DHCPOFFER               2 /* client <- server */
+#define DHCPREQUEST             3 /* client -> server */
+#define DHCPDECLINE             4 /* client -> server */
+#define DHCPACK                 5 /* client <- server */
+#define DHCPNAK                 6 /* client <- server */
+#define DHCPRELEASE             7 /* client -> server */
+#define DHCPINFORM              8 /* client -> server */
 
 struct dhcp_option {
        uint8_t flags;
index 5d42a45db49cc291c45679c9cf27d9f21a5bd25d..3029b13670512c25bfe2f5703b0e37a232be8d8c 100644 (file)
@@ -135,7 +135,7 @@ static char **fill_envp(struct dhcpMessage *packet)
        char **envp, **curr;
        const char *opt_name;
        uint8_t *temp;
-       char over = 0;
+       uint8_t over = 0;
 
        if (packet) {
                for (i = 0; dhcp_options[i].code; i++) {
@@ -147,7 +147,7 @@ static char **fill_envp(struct dhcpMessage *packet)
                }
                if (packet->siaddr)
                        num_options++;
-               temp = get_option(packet, DHCP_OPTION_OVER);
+               temp = get_option(packet, DHCP_OPTION_OVERLOAD);
                if (temp)
                        over = *temp;
                if (!(over & FILE_FIELD) && packet->file[0])
index afc0fb40d61b97ef74503f18f1b84bb62f517609..8b0f1856bf05258cf095f212075df2b39fbdc44c 100644 (file)
@@ -105,7 +105,7 @@ int FAST_FUNC send_offer(struct dhcpMessage *oldpacket)
        uint32_t req_align;
        uint32_t lease_time_aligned = server_config.lease;
        uint32_t static_lease_ip;
-       uint8_t *req, *lease_time;
+       uint8_t *req, *lease_time, *p_host_name;
        struct option_set *curr;
        struct in_addr addr;
 
@@ -146,7 +146,8 @@ int FAST_FUNC send_offer(struct dhcpMessage *oldpacket)
                        bb_error_msg("no IP addresses to give - OFFER abandoned");
                        return -1;
                }
-               if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time)) {
+               p_host_name = get_option(oldpacket, DHCP_HOST_NAME);
+               if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time, p_host_name)) {
                        bb_error_msg("lease pool is full - OFFER abandoned");
                        return -1;
                }
@@ -201,6 +202,7 @@ int FAST_FUNC send_ACK(struct dhcpMessage *oldpacket, uint32_t yiaddr)
        uint8_t *lease_time;
        uint32_t lease_time_aligned = server_config.lease;
        struct in_addr addr;
+       uint8_t *p_host_name;
 
        init_packet(&packet, oldpacket, DHCPACK);
        packet.yiaddr = yiaddr;
@@ -232,7 +234,8 @@ int FAST_FUNC send_ACK(struct dhcpMessage *oldpacket, uint32_t yiaddr)
        if (send_packet(&packet, 0) < 0)
                return -1;
 
-       add_lease(packet.chaddr, packet.yiaddr, lease_time_aligned);
+       p_host_name = get_option(oldpacket, DHCP_HOST_NAME);
+       add_lease(packet.chaddr, packet.yiaddr, lease_time_aligned, p_host_name);
        if (ENABLE_FEATURE_UDHCPD_WRITE_LEASES_EARLY) {
                /* rewrite the file with leases at every new acceptance */
                write_leases();