[DHCPCSVC] Implement the dhcp release message and fix the dhcp registry values

- Do not modify the EnableDHCP value as it should not be changed by the service.
This commit is contained in:
Eric Kohl
2025-08-12 23:25:38 +02:00
parent 51ee32f5f8
commit 0f4e223ce7
3 changed files with 253 additions and 20 deletions

View File

@@ -144,24 +144,12 @@ Server_ReleaseParameters(
DPRINT("Adapter: %p\n", Adapter);
if (Adapter->NteContext)
{
DeleteIPAddress(Adapter->NteContext);
Adapter->NteContext = 0;
}
if (Adapter->RouterMib.dwForwardNextHop)
{
DeleteIpForwardEntry(&Adapter->RouterMib);
Adapter->RouterMib.dwForwardNextHop = 0;
}
state_release(&Adapter->DhclientInfo);
proto = find_protocol_by_adapter(&Adapter->DhclientInfo);
if (proto)
remove_protocol(proto);
Adapter->DhclientInfo.client->active = NULL;
Adapter->DhclientInfo.client->state = S_INIT;
if (hAdapterStateChangedEvent != NULL)
SetEvent(hAdapterStateChangedEvent);

View File

@@ -227,6 +227,28 @@ state_init(void *ipp)
send_discover(ip);
}
void
state_release(void *ipp)
{
struct interface_info *ip = ipp;
ULONG foo = (ULONG) GetTickCount();
ASSERT_STATE(state, S_BOUND);
/* Make a DHCPRELEASE packet, and set appropriate per-interface
flags. */
make_release(ip, ip->client->active);
/* make_request doesn't initialize xid because it normally comes
from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
so pick an xid now. */
ip->client->xid = RtlRandom(&foo);
send_release(ip);
ip->client->state = S_RELEASED;
unbind_lease(ip);
}
/*
* state_selecting is called when one or more DHCPOFFER packets
* have been received and a configurable period of time has passed.
@@ -379,6 +401,7 @@ dhcpack(struct packet *packet)
ip->client->new->renewal / 2 + ip->client->new->renewal / 4;
#ifdef __REACTOS__
ip->client->new->lease = ip->client->new->expiry;
ip->client->new->obtained = cur_time;
#endif
ip->client->new->expiry += cur_time;
@@ -439,6 +462,23 @@ void set_name_servers( PDHCP_ADAPTER Adapter, struct client_lease *new_lease ) {
}
void
unset_name_servers(
PDHCP_ADAPTER Adapter)
{
CHAR Buffer[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
HKEY RegKey;
strcat(Buffer, Adapter->DhclientInfo.name);
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer, 0, KEY_WRITE, &RegKey ) != ERROR_SUCCESS)
return;
RegDeleteValueW( RegKey, L"DhcpNameServer" );
RegCloseKey( RegKey );
}
void
set_domain(PDHCP_ADAPTER Adapter,
struct client_lease *new_lease)
@@ -489,12 +529,40 @@ set_domain(PDHCP_ADAPTER Adapter,
}
void
unset_domain(
PDHCP_ADAPTER Adapter)
{
CHAR Buffer1[MAX_PATH] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
CHAR Buffer2[MAX_PATH] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters";
HKEY RegKey1, RegKey2;
strcat(Buffer1, Adapter->DhclientInfo.name);
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer1, 0, KEY_WRITE, &RegKey1 ) != ERROR_SUCCESS)
{
return;
}
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer2, 0, KEY_WRITE, &RegKey2 ) != ERROR_SUCCESS)
{
RegCloseKey(RegKey1);
return;
}
RegDeleteValueW(RegKey1, L"DhcpDomain");
RegDeleteValueW(RegKey2, L"DhcpDomain");
RegCloseKey(RegKey1);
RegCloseKey(RegKey2);
}
void setup_adapter( PDHCP_ADAPTER Adapter, struct client_lease *new_lease ) {
CHAR Buffer[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
struct iaddr netmask;
HKEY hkey;
int i;
DWORD dwEnableDHCP;
strcat(Buffer, Adapter->DhclientInfo.name);
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer, 0, KEY_WRITE, &hkey) != ERROR_SUCCESS)
@@ -530,12 +598,13 @@ void setup_adapter( PDHCP_ADAPTER Adapter, struct client_lease *new_lease ) {
strcat(Buffer, ".");
}
RegSetValueExA(hkey, "DhcpSubnetMask", 0, REG_SZ, (LPBYTE)Buffer, strlen(Buffer)+1);
dwEnableDHCP = 1;
RegSetValueExA(hkey, "EnableDHCP", 0, REG_DWORD, (LPBYTE)&dwEnableDHCP, sizeof(DWORD));
RegSetValueExA(hkey, "DhcpServer", 0, REG_SZ, (LPBYTE)piaddr(new_lease->serveraddress), strlen(piaddr(new_lease->serveraddress))+1);
RegSetValueExA(hkey, "Lease", 0, REG_DWORD, (LPBYTE)&new_lease->lease, sizeof(DWORD));
RegSetValueExA(hkey, "LeaseObtainedTime", 0, REG_DWORD, (LPBYTE)&new_lease->obtained, sizeof(DWORD));
RegSetValueExA(hkey, "LeaseTerminatesTime", 0, REG_DWORD, (LPBYTE)&new_lease->expiry, sizeof(DWORD));
RegSetValueExA(hkey, "DhcpServer", 0, REG_SZ, (LPBYTE)piaddr(new_lease->serveraddress), strlen(piaddr(new_lease->serveraddress))+1);
RegSetValueExA(hkey, "T1", 0, REG_DWORD, (LPBYTE)&new_lease->renewal, sizeof(DWORD));
RegSetValueExA(hkey, "T2", 0, REG_DWORD, (LPBYTE)&new_lease->rebind, sizeof(DWORD));
}
if( !NT_SUCCESS(Status) )
@@ -579,6 +648,56 @@ void setup_adapter( PDHCP_ADAPTER Adapter, struct client_lease *new_lease ) {
RegCloseKey(hkey);
}
void
reset_adapter( PDHCP_ADAPTER Adapter) {
CHAR Buffer[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
CHAR IpAddress[] = "0.0.0.0";
CHAR SubnetMask[] = "255.0.0.0";
CHAR Server[] = "255.255.255.255";
HKEY hkey;
DWORD lease;
time_t cur_time, new_time;
time(&cur_time);
strcat(Buffer, Adapter->DhclientInfo.name);
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer, 0, KEY_WRITE, &hkey) != ERROR_SUCCESS)
hkey = NULL;
if( Adapter->NteContext )
{
DeleteIPAddress( Adapter->NteContext );
Adapter->NteContext = 0;
}
if (hkey) {
RegSetValueExA(hkey, "DhcpIPAddress", 0, REG_SZ, (LPBYTE)IpAddress, strlen(IpAddress)+1);
RegSetValueExA(hkey, "DhcpSubnetMask", 0, REG_SZ, (LPBYTE)SubnetMask, strlen(SubnetMask)+1);
RegSetValueExA(hkey, "DhcpServer", 0, REG_SZ, (LPBYTE)Server, strlen(Server)+1);
lease = 3600;
RegSetValueExA(hkey, "Lease", 0, REG_DWORD, (LPBYTE)&lease, sizeof(DWORD));
RegSetValueExA(hkey, "LeaseObtainedTime", 0, REG_DWORD, (LPBYTE)&cur_time, sizeof(DWORD));
new_time = cur_time + lease;
RegSetValueExA(hkey, "LeaseTerminatesTime", 0, REG_DWORD, (LPBYTE)&new_time, sizeof(DWORD));
new_time = cur_time + (lease / 2);
RegSetValueExA(hkey, "T1", 0, REG_DWORD, (LPBYTE)&new_time, sizeof(DWORD));
new_time = cur_time + lease - (lease / 8);
RegSetValueExA(hkey, "T2", 0, REG_DWORD, (LPBYTE)&new_time, sizeof(DWORD));
}
if( Adapter->RouterMib.dwForwardNextHop ) {
DeleteIpForwardEntry( &Adapter->RouterMib );
}
if (hkey) {
RegDeleteValueA(hkey, "DhcpDefaultGateway");
}
if (hkey)
RegCloseKey(hkey);
}
void
bind_lease(struct interface_info *ip)
@@ -622,6 +741,28 @@ bind_lease(struct interface_info *ip)
set_domain( Adapter, new_lease );
}
void
unbind_lease(struct interface_info *ip)
{
PDHCP_ADAPTER Adapter;
if (ip->client->active) {
free_client_lease(ip->client->active);
ip->client->active = NULL;
}
Adapter = AdapterFindInfo( ip );
if (Adapter) {
reset_adapter(Adapter);
unset_name_servers(Adapter);
unset_domain(Adapter);
}
else {
warning("Could not find adapter for info %p\n", ip);
return;
}
}
/*
* state_bound is called when we've successfully bound to a particular
* lease, but the renewal time on that lease has expired. We are
@@ -874,8 +1015,16 @@ packet_to_lease(struct packet *packet)
lease->address.len = sizeof(packet->raw->yiaddr);
memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len);
#ifdef __REACTOS__
lease->serveraddress.len = sizeof(packet->raw->siaddr);
memcpy(lease->serveraddress.iabuf, &packet->raw->siaddr, lease->address.len);
if (packet->raw->siaddr.S_un.S_addr == 0)
{
lease->serveraddress.len = packet->client_addr.len;
memcpy(lease->serveraddress.iabuf, &packet->client_addr.iabuf, packet->client_addr.len);
}
else
{
lease->serveraddress.len = sizeof(packet->raw->siaddr);
memcpy(lease->serveraddress.iabuf, &packet->raw->siaddr, lease->serveraddress.len);
}
#endif
/* If the server name was filled out, copy it. */
@@ -1256,6 +1405,31 @@ send_decline(void *ipp)
inaddr_any, &sockaddr_broadcast, NULL);
}
void
send_release(void *ipp)
{
struct interface_info *ip = ipp;
struct sockaddr_in destination;
struct in_addr from;
memset(&destination, 0, sizeof(destination));
memcpy(&destination.sin_addr.s_addr,
ip->client->destination.iabuf,
sizeof(destination.sin_addr.s_addr));
destination.sin_port = htons(REMOTE_PORT);
destination.sin_family = AF_INET;
memcpy(&from, ip->client->active->address.iabuf,
sizeof(from));
note("DHCPRELEASE on %s to %s port %d", ip->name,
inet_ntoa(destination.sin_addr), ntohs(destination.sin_port));
/* Send out a packet. */
(void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
from, &destination, NULL);
}
void
make_discover(struct interface_info *ip, struct client_lease *lease)
{
@@ -1515,6 +1689,70 @@ make_decline(struct interface_info *ip, struct client_lease *lease)
ip->hw_address.haddr, ip->hw_address.hlen);
}
void
make_release(struct interface_info *ip, struct client_lease *lease)
{
struct tree_cache *options[256], message_type_tree;
struct tree_cache server_id_tree, client_id_tree;
unsigned char release = DHCPRELEASE;
int i;
memset(options, 0, sizeof(options));
memset(&ip->client->packet, 0, sizeof(ip->client->packet));
/* Set DHCP_MESSAGE_TYPE to DHCPRELEASE */
i = DHO_DHCP_MESSAGE_TYPE;
options[i] = &message_type_tree;
options[i]->value = &release;
options[i]->len = sizeof(release);
options[i]->buf_size = sizeof(release);
options[i]->timeout = 0xFFFFFFFF;
/* Send back the server identifier... */
i = DHO_DHCP_SERVER_IDENTIFIER;
options[i] = &server_id_tree;
options[i]->value = lease->options[i].data;
options[i]->len = lease->options[i].len;
options[i]->buf_size = lease->options[i].len;
options[i]->timeout = 0xFFFFFFFF;
/* Send the uid if the user supplied one. */
i = DHO_DHCP_CLIENT_IDENTIFIER;
if (ip->client->config->send_options[i].len)
{
options[i] = &client_id_tree;
options[i]->value = ip->client->config->send_options[i].data;
options[i]->len = ip->client->config->send_options[i].len;
options[i]->buf_size = ip->client->config->send_options[i].len;
options[i]->timeout = 0xFFFFFFFF;
}
/* Set up the option buffer... */
ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0, options);
if (ip->client->packet_length < BOOTP_MIN_LEN)
ip->client->packet_length = BOOTP_MIN_LEN;
ip->client->packet.op = BOOTREQUEST;
ip->client->packet.htype = ip->hw_address.htype;
ip->client->packet.hlen = ip->hw_address.hlen;
ip->client->packet.hops = 0;
ip->client->packet.xid = 0;
ip->client->packet.secs = 0;
ip->client->packet.flags = 0;
/* ciaddr is the address to be released */
memcpy(&ip->client->packet.ciaddr,
lease->address.iabuf, lease->address.len);
memset(&ip->client->packet.yiaddr, 0,
sizeof(ip->client->packet.yiaddr));
memset(&ip->client->packet.siaddr, 0,
sizeof(ip->client->packet.siaddr));
memset(&ip->client->packet.giaddr, 0,
sizeof(ip->client->packet.giaddr));
memcpy(ip->client->packet.chaddr,
ip->hw_address.haddr, ip->hw_address.hlen);
}
void
free_client_lease(struct client_lease *lease)
{

View File

@@ -156,6 +156,7 @@ struct client_lease {
struct iaddr address;
char *server_name;
#ifdef __REACTOS__
u_int32_t lease;
time_t obtained;
struct iaddr serveraddress;
#endif
@@ -175,7 +176,8 @@ enum dhcp_state {
S_BOUND,
S_RENEWING,
S_REBINDING,
S_STATIC
S_STATIC,
S_RELEASED
};
struct client_config {
@@ -203,6 +205,7 @@ struct client_config {
bootp_policy;
struct string_list *medium;
struct iaddrlist *reject_list;
char *user_class;
};
struct client_state {
@@ -405,19 +408,23 @@ void dhcpnak(struct packet *);
void send_discover(void *);
void send_request(void *);
void send_decline(void *);
void send_release(void *);
void state_reboot(void *);
void state_init(void *);
void state_release(void *);
void state_selecting(void *);
void state_requesting(void *);
void state_bound(void *);
void state_panic(void *);
void bind_lease(struct interface_info *);
void unbind_lease(struct interface_info *);
void make_discover(struct interface_info *, struct client_lease *);
void make_request(struct interface_info *, struct client_lease *);
void make_decline(struct interface_info *, struct client_lease *);
void make_release(struct interface_info *, struct client_lease *);
void free_client_lease(struct client_lease *);
void rewrite_client_leases(struct interface_info *);