From 98b9b434c6bc7fdd5b77cdfd53ca88d6c30a3c53 Mon Sep 17 00:00:00 2001 From: Eric Kohl Date: Sun, 12 Apr 2026 14:35:48 +0200 Subject: [PATCH] [DHCPCSVC] Implement alternate configuration - Set the ip address, subnet mask and default gateway when an alternate configuration has been configured. - Set registry values for the alternate configuration and APIPA. --- base/services/dhcpcsvc/dhcp/dhclient.c | 196 +++++++++++++++++++++---- 1 file changed, 165 insertions(+), 31 deletions(-) diff --git a/base/services/dhcpcsvc/dhcp/dhclient.c b/base/services/dhcpcsvc/dhcp/dhclient.c index 59a6eb9bcfc..e8127db5b93 100644 --- a/base/services/dhcpcsvc/dhcp/dhclient.c +++ b/base/services/dhcpcsvc/dhcp/dhclient.c @@ -1213,53 +1213,187 @@ send_discover(void *ipp) void state_panic(void *ipp) { - struct interface_info *ip = ipp; - uint16_t address_low; - int i; + CHAR szKeyNameBuffer[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\"; + CHAR Server[] = "255.255.255.255"; + CHAR SubnetMask[] = "255.255.0.0"; + CHAR AddressBuffer[32]; + struct interface_info *ip = ipp; + uint16_t address_low; + int i; IPAddr IpAddress; ULONG Buffer[20]; ULONG BufferSize; DWORD ret; + HKEY hKey = NULL; PDHCP_ADAPTER Adapter = AdapterFindInfo(ip); + NTSTATUS Status; + DWORD lease = 0; + time_t cur_time, never_time = 0x7FFFFFFF; + struct in_addr addr; - note("No DHCPOFFERS received."); + note("No DHCPOFFERS received."); + + time(&cur_time); + + strcat(szKeyNameBuffer, Adapter->DhclientInfo.name); + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, szKeyNameBuffer, 0, KEY_WRITE, &hKey) != ERROR_SUCCESS) + hKey = NULL; if (Adapter && !Adapter->NteContext) { - /* Generate an automatic private address */ - DbgPrint("DHCPCSVC: Failed to receive a response from a DHCP server. An automatic private address will be assigned.\n"); - - /* FIXME: The address generation code sucks */ - srand(0); - - for (;;) + DH_DbgPrint(MID_TRACE,("DHCPCSVC: Failed to receive a response from a DHCP server\n")); + if ((Adapter->AlternateConfiguration != NULL) && + (Adapter->AlternateConfiguration->IpAddress != 0)) { - address_low = rand(); - for (i = 0; i < ip->hw_address.hlen; i++) - address_low += ip->hw_address.haddr[i]; + /* Use the alternate configuration */ + DH_DbgPrint(MID_TRACE,("DHCPCSVC: The alternate configuration will be used.\n")); - IpAddress = htonl(0xA9FE0000 | address_low); // 169.254.X.X + /* IPAddress & SubnetMask */ + Status = AddIPAddress(htonl(Adapter->AlternateConfiguration->IpAddress), + htonl(Adapter->AlternateConfiguration->SubnetMask), + Adapter->IfMib.dwIndex, + &Adapter->NteContext, + &Adapter->NteInstance); + if (!NT_SUCCESS(Status)) + DH_DbgPrint(MID_TRACE,("AddIPAddress: %lx\n", Status)); - /* Send an ARP request to check if the IP address is already in use */ - BufferSize = sizeof(Buffer); - ret = SendARP(IpAddress, - IpAddress, - Buffer, - &BufferSize); - DH_DbgPrint(MID_TRACE,("DHCPCSVC: SendARP returned %lu\n", ret)); - if (ret != 0) + /* DefaultGateway */ + if (Adapter->AlternateConfiguration->DefaultGateway != 0) { - /* The IP address is not in use */ - DH_DbgPrint(MID_TRACE,("DHCPCSVC: Using automatic private address\n")); - AddIPAddress(IpAddress, - htonl(0xFFFF0000), // 255.255.0.0 - Adapter->IfMib.dwIndex, - &Adapter->NteContext, - &Adapter->NteInstance); - return; + Adapter->RouterMib.dwForwardDest = 0; /* Default route */ + Adapter->RouterMib.dwForwardMask = 0; + Adapter->RouterMib.dwForwardMetric1 = 1; + Adapter->RouterMib.dwForwardIfIndex = Adapter->IfMib.dwIndex; + + if (Adapter->RouterMib.dwForwardNextHop) + { + /* If we set a default route before, delete it before continuing */ + DeleteIpForwardEntry(&Adapter->RouterMib); + } + + Adapter->RouterMib.dwForwardNextHop = htonl(Adapter->AlternateConfiguration->DefaultGateway); + + Status = CreateIpForwardEntry(&Adapter->RouterMib); + if (!NT_SUCCESS(Status)) + DH_DbgPrint(MID_TRACE,("CreateIpForwardEntry: %lx\n", Status)); + } + + if (hKey) + { + addr.S_un.S_addr = htonl(Adapter->AlternateConfiguration->IpAddress); + RtlIpv4AddressToStringA(&addr, AddressBuffer); + RegSetValueExA(hKey, "DhcpIPAddress", 0, REG_SZ, (LPBYTE)AddressBuffer, strlen(AddressBuffer) + 1); + addr.S_un.S_addr = htonl(Adapter->AlternateConfiguration->SubnetMask); + RtlIpv4AddressToStringA(&addr, AddressBuffer); + RegSetValueExA(hKey, "DhcpSubnetMask", 0, REG_SZ, (LPBYTE)AddressBuffer, strlen(AddressBuffer) + 1); + if (Adapter->AlternateConfiguration->DefaultGateway != 0) + { + addr.S_un.S_addr = htonl(Adapter->AlternateConfiguration->DefaultGateway); + RtlIpv4AddressToStringA(&addr, AddressBuffer); + RegSetValueExA(hKey, "DhcpDefaultGateway", 0, REG_SZ, (LPBYTE)AddressBuffer, strlen(AddressBuffer) + 1); + } + else + { + RegDeleteValueA(hKey, "DhcpDefaultGateway"); + } + RegSetValueExA(hKey, "DhcpServer", 0, REG_SZ, (LPBYTE)Server, strlen(Server) + 1); + RegDeleteValueA(hKey, "DhcpDomain"); + + if (Adapter->AlternateConfiguration->DnsServer1 != 0) + { + char *pPtr; + addr.S_un.S_addr = htonl(Adapter->AlternateConfiguration->DnsServer1); + pPtr = RtlIpv4AddressToStringA(&addr, AddressBuffer); + if (Adapter->AlternateConfiguration->DnsServer2 != 0) + { + *pPtr = ' '; + pPtr++; + addr.S_un.S_addr = htonl(Adapter->AlternateConfiguration->DnsServer2); + RtlIpv4AddressToStringA(&addr, pPtr); + } + + RegSetValueExA(hKey, "DhcpNameServer", 0, REG_SZ, (LPBYTE)AddressBuffer, strlen(AddressBuffer) + 1); + } + else + { + RegDeleteValueA(hKey, "DhcpNameServer"); + } + + RegDeleteValueA(hKey, "IPAutoconfigurationAddress"); + RegDeleteValueA(hKey, "IPAutoconfigurationMask"); + + RegSetValueExA(hKey, "Lease", 0, REG_DWORD, (LPBYTE)&lease, sizeof(DWORD)); + RegSetValueExA(hKey, "LeaseObtainedTime", 0, REG_DWORD, (LPBYTE)&cur_time, sizeof(DWORD)); + RegSetValueExA(hKey, "LeaseTerminatesTime", 0, REG_DWORD, (LPBYTE)&never_time, sizeof(DWORD)); + RegSetValueExA(hKey, "T1", 0, REG_DWORD, (LPBYTE)&cur_time, sizeof(DWORD)); + RegSetValueExA(hKey, "T2", 0, REG_DWORD, (LPBYTE)&cur_time, sizeof(DWORD)); + } + } + else + { + /* Generate an automatic private address */ + DH_DbgPrint(MID_TRACE,("DHCPCSVC: An automatic private address will be assigned.\n")); + + /* FIXME: The address generation code sucks */ + srand(0); + + for (;;) + { + address_low = rand(); + for (i = 0; i < ip->hw_address.hlen; i++) + address_low += ip->hw_address.haddr[i]; + + IpAddress = htonl(0xA9FE0000 | address_low); // 169.254.X.X + + /* Send an ARP request to check if the IP address is already in use */ + BufferSize = sizeof(Buffer); + ret = SendARP(IpAddress, + IpAddress, + Buffer, + &BufferSize); + DH_DbgPrint(MID_TRACE,("DHCPCSVC: SendARP returned %lu\n", ret)); + if (ret != 0) + { + /* The IP address is not in use */ + DH_DbgPrint(MID_TRACE,("DHCPCSVC: Using automatic private address\n")); + Status = AddIPAddress(IpAddress, + htonl(0xFFFF0000), // 255.255.0.0 + Adapter->IfMib.dwIndex, + &Adapter->NteContext, + &Adapter->NteInstance); + if (!NT_SUCCESS(Status)) + DH_DbgPrint(MID_TRACE,("AddIPAddress: %lx\n", Status)); + + if (hKey) + { + addr.S_un.S_addr = IpAddress; + RtlIpv4AddressToStringA(&addr, AddressBuffer); + RegSetValueExA(hKey, "DhcpIPAddress", 0, REG_SZ, (LPBYTE)AddressBuffer, strlen(AddressBuffer) + 1); + RegSetValueExA(hKey, "DhcpSubnetMask", 0, REG_SZ, (LPBYTE)SubnetMask, strlen(SubnetMask) + 1); + RegSetValueExA(hKey, "DhcpServer", 0, REG_SZ, (LPBYTE)Server, strlen(Server) + 1); + RegDeleteValueA(hKey, "DhcpDefaultGateway"); + RegDeleteValueA(hKey, "DhcpDomain"); + RegDeleteValueA(hKey, "DhcpNameServer"); + + RegSetValueExA(hKey, "IPAutoconfigurationAddress", 0, REG_SZ, (LPBYTE)AddressBuffer, strlen(AddressBuffer) + 1); + RegSetValueExA(hKey, "IPAutoconfigurationMask", 0, REG_SZ, (LPBYTE)SubnetMask, strlen(SubnetMask) + 1); + + RegSetValueExA(hKey, "Lease", 0, REG_DWORD, (LPBYTE)&lease, sizeof(DWORD)); + RegSetValueExA(hKey, "LeaseObtainedTime", 0, REG_DWORD, (LPBYTE)&cur_time, sizeof(DWORD)); + RegSetValueExA(hKey, "LeaseTerminatesTime", 0, REG_DWORD, (LPBYTE)&never_time, sizeof(DWORD)); + RegSetValueExA(hKey, "T1", 0, REG_DWORD, (LPBYTE)&cur_time, sizeof(DWORD)); + RegSetValueExA(hKey, "T2", 0, REG_DWORD, (LPBYTE)&cur_time, sizeof(DWORD)); + } + + goto done; + } } } } + +done: + if (hKey) + RegCloseKey(hKey); } void