Can I request a specific IP address via DHCP without rejecting an offer of a different address from the DHCP server?

Using isc-dhcp-client on ubuntu server 16.04, there's an option that sounds like it should do what i want:

send dhcp-requested-address 10.23.33.254;

When this option is present in my dhclient.conf file, my client does exactly what I want: always gets a lease for the requested address from the DHCP server on my private network where the DHCP range is 10.23.33.0/24. However, if i connect the computer to a network where the requested address is not in the server's DHCP address range, the server offers a different address and isc-dhcp-client just sends a NAK because it isn't being given the requested address.

Essentially, what i want is

client: "hello, can i have 10.23.33.254"
server: "no, you can't. here, have 192.168.1.23 instead"
client: "okay, thanks"

Instead, what's happening is

client: "hello, can i have 10.23.33.254"
server: "no, you can't. here, have 192.168.1.23 instead"
client: "that's not what i want. can i have 10.23.33.254?"
server: "no, you can't..." (repeat this cycle forever)

anybody know if what I want is possible, short of writing my own DHCP client?


Use the lease block instead. From trial and errors, this configuration block is ignored from the dhclient.conf file but used in the leases file (default /var/lib/dhcp/dhclient.leases unless overriden with -lf, like when run from NetworkManager)

Just build a minimal leases file that have an expired renew and rebind (to avoid a few retries) but still a future expire date (to not immediately forget it and immediately attempt a DISCOVER instead of a REQUEST, and to use this IP if there's no DHCP server answer at all). Keep this file unchanged and copy it each time before running dhclient.

Here's such a minimal file, from my stretch-amd64 container, working as long as the DHCP server (dnsmasq here) doesn't have an other lease for this client already set. Just copy it over the lease file before running dhclient.

lease {
  interface "eth0";
  fixed-address 10.0.3.222;
  renew 0 2000/1/1 00:00:01;
  rebind 0 2000/01/01 00:00:01;
  expire 0 2038/1/1 00:00:01;
}

Attempt in a LAN with a DHCP server serving 10.0.3.0/24 and which doesn't know this client already:

# dhclient -v eth0
Internet Systems Consortium DHCP Client 4.3.5
Copyright 2004-2016 Internet Systems Consortium.
All rights reserved.
For info, please visit https://www.isc.org/software/dhcp/

Listening on LPF/eth0/xx:xx:xx:xx:xx:xx
Sending on   LPF/eth0/xx:xx:xx:xx:xx:xx
Sending on   Socket/fallback
DHCPREQUEST of 10.0.3.222 on eth0 to 255.255.255.255 port 67
DHCPACK of 10.0.3.222 from 10.0.3.1
bound to 10.0.3.222 -- renewal in 1486 seconds.

new lease file /var/lib/dhcp/dhclient.leases:

lease {
  interface "eth0";
  fixed-address 10.0.3.222;
  renew 6 2000/01/01 00:00:01;
  rebind 6 2000/01/01 00:00:01;
  expire never;
}
lease {
  interface "eth0";
  fixed-address 10.0.3.222;
  option subnet-mask 255.255.255.0;
  option routers 10.0.3.1;
  option dhcp-lease-time 3600;
  option dhcp-message-type 5;
  option domain-name-servers 10.0.3.1;
  option dhcp-server-identifier 10.0.3.1;
  option dhcp-renewal-time 1800;
  option broadcast-address 10.0.3.255;
  option dhcp-rebinding-time 3150;
  option host-name "stretch-amd64";
  renew 0 2017/10/29 19:57:41;
  rebind 0 2017/10/29 20:24:34;
  expire 0 2017/10/29 20:32:04;
}

Attempt when outside of the IP range:

Listening on LPF/eth0/xx:xx:xx:xx:xx:xx
Sending on   LPF/eth0/xx:xx:xx:xx:xx:xx
Sending on   Socket/fallback
DHCPREQUEST of 10.0.4.222 on eth0 to 255.255.255.255 port 67
DHCPREQUEST of 10.0.4.222 on eth0 to 255.255.255.255 port 67
DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 4
DHCPREQUEST of 10.0.3.249 on eth0 to 255.255.255.255 port 67
DHCPOFFER of 10.0.3.249 from 10.0.3.1
DHCPACK of 10.0.3.249 from 10.0.3.1
bound to 10.0.3.249 -- renewal in 1411 seconds.

This DHCP server doesn't seem to send NAKs, but anyway I'm sure you get the point, it works.

If there's no DHCP server, after some time, dhclient will configure the IP because it has not expired in the lease and daemonize. Without the other options (broadcast...) this will be a /32 because the information is not available. Add the other values in the "template" lease file if needed. Here that would be:

option subnet-mask 255.255.255.0;
option routers 10.0.3.1;
option domain-name-servers 10.0.3.1;
option broadcast-address 10.0.3.255;

In such case when running dhclient:

[...]

DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 12
No DHCPOFFERS received.
Trying recorded lease 10.0.3.222
PING 10.0.3.1 (10.0.3.1) 56(84) bytes of data.

--- 10.0.3.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.240/0.240/0.240/0.000 ms
bound: immediate renewal.
DHCPREQUEST of 10.0.3.222 on eth0 to 255.255.255.255 port 67
root@stretch-amd64:~#