From ca85a28241ef87919d68d52c843b6964b7070e11 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Wed, 13 May 2015 22:33:04 +0100 Subject: [PATCH] Allow T1 and T2 DHCPv4 options to be set. --- CHANGELOG | 3 ++ dnsmasq.conf.example | 8 +++++ src/dhcp-common.c | 4 +-- src/rfc2131.c | 71 +++++++++++++++++++++++++++++++------------- 4 files changed, 63 insertions(+), 23 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 94a521f..ef39a41 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -118,6 +118,9 @@ version 2.73 Check IPv4-mapped IPv6 addresses when --stop-rebind is active. Thanks to Jordan Milne for spotting this. + Allow DHCPv4 options T1 and T2 to be set using --dhcp-option. + Thanks to Kevin Benton for patches and work on this. + version 2.72 Add ra-advrouter mode, for RFC-3775 mobile IPv6 support. diff --git a/dnsmasq.conf.example b/dnsmasq.conf.example index 67be99a..1ae11df 100644 --- a/dnsmasq.conf.example +++ b/dnsmasq.conf.example @@ -345,6 +345,14 @@ # Ask client to poll for option changes every six hours. (RFC4242) #dhcp-option=option6:information-refresh-time,6h +# Set option 58 client renewal time (T1). Defaults to half of the +# lease time if not specified. (RFC2132) +#dhcp-option=option:T1:1m + +# Set option 59 rebinding time (T2). Defaults to 7/8 of the +# lease time if not specified. (RFC2132) +#dhcp-option=option:T2:2m + # Set the NTP time server address to be the same machine as # is running dnsmasq #dhcp-option=42,0.0.0.0 diff --git a/src/dhcp-common.c b/src/dhcp-common.c index ce11520..bc48f41 100644 --- a/src/dhcp-common.c +++ b/src/dhcp-common.c @@ -545,8 +545,8 @@ static const struct opttab_t { { "parameter-request", 55, OT_INTERNAL }, { "message", 56, OT_INTERNAL }, { "max-message-size", 57, OT_INTERNAL }, - { "T1", 58, OT_INTERNAL | OT_TIME}, - { "T2", 59, OT_INTERNAL | OT_TIME}, + { "T1", 58, OT_TIME}, + { "T2", 59, OT_TIME}, { "vendor-class", 60, 0 }, { "client-id", 61, OT_INTERNAL }, { "nis+-domain", 64, OT_NAME }, diff --git a/src/rfc2131.c b/src/rfc2131.c index 5552644..a10e499 100644 --- a/src/rfc2131.c +++ b/src/rfc2131.c @@ -52,7 +52,9 @@ static void do_options(struct dhcp_context *context, int null_term, int pxearch, unsigned char *uuid, int vendor_class_len, - time_t now); + time_t now, + unsigned int lease_time, + unsigned short fuzz); static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt); @@ -610,7 +612,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, clear_packet(mess, end); do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr), - netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now); + netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0); } } @@ -1042,13 +1044,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr)); option_put(mess, end, OPTION_LEASE_TIME, 4, time); /* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */ - if (time != 0xffffffff) - { - option_put(mess, end, OPTION_T1, 4, (time/2)); - option_put(mess, end, OPTION_T2, 4, (time*7)/8); - } do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr), - netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now); + netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz); return dhcp_packet_size(mess, agent_id, real_end); @@ -1367,15 +1364,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK); option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr)); option_put(mess, end, OPTION_LEASE_TIME, 4, time); - if (time != 0xffffffff) - { - while (fuzz > (time/16)) - fuzz = fuzz/2; - option_put(mess, end, OPTION_T1, 4, (time/2) - fuzz); - option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz); - } do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr), - netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now); + netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz); } return dhcp_packet_size(mess, agent_id, real_end); @@ -1440,7 +1430,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, } do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr), - netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now); + netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0); *is_inform = 1; /* handle reply differently */ return dhcp_packet_size(mess, agent_id, real_end); @@ -2137,7 +2127,9 @@ static void do_options(struct dhcp_context *context, int null_term, int pxe_arch, unsigned char *uuid, int vendor_class_len, - time_t now) + time_t now, + unsigned int lease_time, + unsigned short fuzz) { struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts; struct dhcp_boot *boot; @@ -2261,7 +2253,42 @@ static void do_options(struct dhcp_context *context, /* rfc3011 says this doesn't need to be in the requested options list. */ if (subnet_addr.s_addr) option_put(mess, end, OPTION_SUBNET_SELECT, INADDRSZ, ntohl(subnet_addr.s_addr)); - + + if (lease_time != 0xffffffff) + { + unsigned int t1val = lease_time/2; + unsigned int t2val = (lease_time*7)/8; + unsigned int hval; + + /* If set by user, sanity check, so not longer than lease. */ + if ((opt = option_find2(OPTION_T1))) + { + hval = ntohl(*((unsigned int *)opt->val)); + if (hval < lease_time && hval > 2) + t1val = hval; + } + + if ((opt = option_find2(OPTION_T2))) + { + hval = ntohl(*((unsigned int *)opt->val)); + if (hval < lease_time && hval > 2) + t2val = hval; + } + + while (fuzz > (t1val/8)) + fuzz = fuzz/2; + + t1val -= fuzz; + t2val -= fuzz; + + /* ensure T1 is still < T2 */ + if (t2val <= t1val) + t1val = t2val - 1; + + option_put(mess, end, OPTION_T1, 4, t1val); + option_put(mess, end, OPTION_T2, 4, t2val); + } + /* replies to DHCPINFORM may not have a valid context */ if (context) { @@ -2356,12 +2383,14 @@ static void do_options(struct dhcp_context *context, if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno)) continue; - /* prohibit some used-internally options */ + /* prohibit some used-internally options. T1 and T2 already handled. */ if (optno == OPTION_CLIENT_FQDN || optno == OPTION_MAXMESSAGE || optno == OPTION_OVERLOAD || optno == OPTION_PAD || - optno == OPTION_END) + optno == OPTION_END || + optno == OPTION_T1 || + optno == OPTION_T2) continue; if (optno == OPTION_SNAME && done_server) -- 2.47.3