diff options
Diffstat (limited to 'src/lease.c')
-rw-r--r-- | src/lease.c | 189 |
1 files changed, 112 insertions, 77 deletions
diff --git a/src/lease.c b/src/lease.c index 8adb605..5c33df7 100644 --- a/src/lease.c +++ b/src/lease.c @@ -1,4 +1,4 @@ -/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley +/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,94 +21,62 @@ static struct dhcp_lease *leases = NULL, *old_leases = NULL; static int dns_dirty, file_dirty, leases_left; -void lease_init(time_t now) +static int read_leases(time_t now, FILE *leasestream) { unsigned long ei; struct all_addr addr; struct dhcp_lease *lease; int clid_len, hw_len, hw_type; - FILE *leasestream; - - leases_left = daemon->dhcp_max; - - if (option_bool(OPT_LEASE_RO)) - { - /* run "<lease_change_script> init" once to get the - initial state of the database. If leasefile-ro is - set without a script, we just do without any - lease database. */ -#ifdef HAVE_SCRIPT - if (daemon->lease_change_command) - { - strcpy(daemon->dhcp_buff, daemon->lease_change_command); - strcat(daemon->dhcp_buff, " init"); - leasestream = popen(daemon->dhcp_buff, "r"); - } - else + int items; + char *domain = NULL; + + *daemon->dhcp_buff3 = *daemon->dhcp_buff2 = '\0'; + + /* client-id max length is 255 which is 255*2 digits + 254 colons + borrow DNS packet buffer which is always larger than 1000 bytes + + Check various buffers are big enough for the code below */ + +#if (DHCP_BUFF_SZ < 255) || (MAXDNAME < 64) || (PACKETSZ+MAXDNAME+RRFIXEDSZ < 764) +# error Buffer size breakage in leasefile parsing. #endif - { - file_dirty = dns_dirty = 0; - return; - } - } - else - { - /* NOTE: need a+ mode to create file if it doesn't exist */ - leasestream = daemon->lease_stream = fopen(daemon->lease_file, "a+"); - - if (!leasestream) - die(_("cannot open or create lease file %s: %s"), daemon->lease_file, EC_FILE); - - /* a+ mode leaves pointer at end. */ - rewind(leasestream); - } - - /* client-id max length is 255 which is 255*2 digits + 254 colons - borrow DNS packet buffer which is always larger than 1000 bytes */ - if (leasestream) - while (fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2) == 2) + while ((items=fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2)) == 2) { + *daemon->namebuff = *daemon->dhcp_buff = *daemon->packet = '\0'; + hw_len = hw_type = clid_len = 0; + #ifdef HAVE_DHCP6 if (strcmp(daemon->dhcp_buff3, "duid") == 0) { daemon->duid_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, 130, NULL, NULL); + if (daemon->duid_len < 0) + return 0; daemon->duid = safe_malloc(daemon->duid_len); memcpy(daemon->duid, daemon->dhcp_buff2, daemon->duid_len); continue; } #endif - - ei = atol(daemon->dhcp_buff3); if (fscanf(leasestream, " %64s %255s %764s", daemon->namebuff, daemon->dhcp_buff, daemon->packet) != 3) - break; + return 0; - clid_len = 0; - if (strcmp(daemon->packet, "*") != 0) - clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL); - - if (inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4) && - (lease = lease4_allocate(addr.addr.addr4))) + if (inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4)) { + if ((lease = lease4_allocate(addr.addr.addr4))) + domain = get_domain(lease->addr); + hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type); - /* For backwards compatibility, no explict MAC address type means ether. */ + /* For backwards compatibility, no explicit MAC address type means ether. */ if (hw_type == 0 && hw_len != 0) hw_type = ARPHRD_ETHER; - - lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, - hw_len, hw_type, clid_len, now, 0); - - if (strcmp(daemon->dhcp_buff, "*") != 0) - lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain(lease->addr), NULL); } #ifdef HAVE_DHCP6 else if (inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6)) { char *s = daemon->dhcp_buff2; int lease_type = LEASE_NA; - int iaid; if (s[0] == 'T') { @@ -116,23 +84,30 @@ void lease_init(time_t now) s++; } - iaid = strtoul(s, NULL, 10); - if ((lease = lease6_allocate(&addr.addr.addr6, lease_type))) { - lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, 0, clid_len, now, 0); - lease_set_iaid(lease, iaid); - if (strcmp(daemon->dhcp_buff, "*") != 0) - lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL); + lease_set_iaid(lease, strtoul(s, NULL, 10)); + domain = get_domain6((struct in6_addr *)lease->hwaddr); } } #endif else - break; + return 0; if (!lease) die (_("too many stored leases"), NULL, EC_MISC); - + + if (strcmp(daemon->packet, "*") != 0) + clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL); + + lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, + hw_len, hw_type, clid_len, now, 0); + + if (strcmp(daemon->dhcp_buff, "*") != 0) + lease_set_hostname(lease, daemon->dhcp_buff, 0, domain, NULL); + + ei = atol(daemon->dhcp_buff3); + #ifdef HAVE_BROKEN_RTC if (ei != 0) lease->expires = (time_t)ei + now; @@ -148,7 +123,62 @@ void lease_init(time_t now) /* set these correctly: the "old" events are generated later from the startup synthesised SIGHUP. */ lease->flags &= ~(LEASE_NEW | LEASE_CHANGED); + + *daemon->dhcp_buff3 = *daemon->dhcp_buff2 = '\0'; } + + return (items == 0 || items == EOF); +} + +void lease_init(time_t now) +{ + FILE *leasestream; + + leases_left = daemon->dhcp_max; + + if (option_bool(OPT_LEASE_RO)) + { + /* run "<lease_change_script> init" once to get the + initial state of the database. If leasefile-ro is + set without a script, we just do without any + lease database. */ +#ifdef HAVE_SCRIPT + if (daemon->lease_change_command) + { + strcpy(daemon->dhcp_buff, daemon->lease_change_command); + strcat(daemon->dhcp_buff, " init"); + leasestream = popen(daemon->dhcp_buff, "r"); + } + else +#endif + { + file_dirty = dns_dirty = 0; + return; + } + + } + else + { + /* NOTE: need a+ mode to create file if it doesn't exist */ + leasestream = daemon->lease_stream = fopen(daemon->lease_file, "a+"); + + if (!leasestream) + die(_("cannot open or create lease file %s: %s"), daemon->lease_file, EC_FILE); + + /* a+ mode leaves pointer at end. */ + rewind(leasestream); + } + + if (leasestream) + { + if (!read_leases(now, leasestream)) + my_syslog(MS_DHCP | LOG_ERR, _("failed to parse lease database, invalid line: %s %s %s %s ..."), + daemon->dhcp_buff3, daemon->dhcp_buff2, + daemon->namebuff, daemon->dhcp_buff); + + if (ferror(leasestream)) + die(_("failed to read lease file %s: %s"), daemon->lease_file, EC_FILE); + } #ifdef HAVE_SCRIPT if (!daemon->lease_stream) @@ -162,6 +192,7 @@ void lease_init(time_t now) errno = ENOENT; else if (WEXITSTATUS(rc) == 126) errno = EACCES; + die(_("cannot run lease-init script %s: %s"), daemon->lease_change_command, EC_FILE); } @@ -198,7 +229,7 @@ void lease_update_from_configs(void) else if ((name = host_from_dns(lease->addr))) lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */ } - + static void ourprintf(int *errp, char *format, ...) { va_list ap; @@ -406,7 +437,7 @@ void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *inte void lease_update_slaac(time_t now) { - /* Called when we contruct a new RA-names context, to add putative + /* Called when we construct a new RA-names context, to add putative new SLAAC addresses to existing leases. */ struct dhcp_lease *lease; @@ -776,7 +807,7 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now) { exp = now + (time_t)len; /* Check for 2038 overflow. Make the lease - inifinite in that case, as the least disruptive + infinite in that case, as the least disruptive thing we can do. */ if (difftime(exp, now) <= 0.0) exp = 0; @@ -1110,18 +1141,22 @@ int do_script_run(time_t now) } #ifdef HAVE_SCRIPT +/* delim == -1 -> delim = 0, but embedded 0s, creating extra records, are OK. */ void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim) { unsigned int i; - /* check for embeded NULLs */ - for (i = 0; i < len; i++) - if (data[i] == 0) - { - len = i; - break; - } - + if (delim == -1) + delim = 0; + else + /* check for embedded NULLs */ + for (i = 0; i < len; i++) + if (data[i] == 0) + { + len = i; + break; + } + if ((lease->extradata_size - lease->extradata_len) < (len + 1)) { size_t newsz = lease->extradata_len + len + 100; |