How to get Linux to use DHCP information from Windows 95 Last revised: December 6, 1996 Dan Halbert halbert@world.std.com halbert@bbn.com Introduction ============ My Linux PC needs to get its IP address and other network information from a DHCP server. However, I have been unable to find a DHCP client that works well with the DHCP server I use. My PC normally boots up with Windows 95, and Linux is used less often. The Windows 95 DHCP client works fine for me. I could manually copy my IP address, nameservers, etc., over to the Linux side, but I wanted to automate that process. Win95 supplies a program (\Windows\Winipcfg.exe) that displays the DHCP info in a nice graphical way. By examining the strings in winipcfg.exe, I discovered that it has undocumented options that will also write the information to a file ("Winipcfg.out", by default). This allowed me to work out the following trick: 1. Boot Win95. Its DHCP client will get the necessary information from the DHCP server. 2. Run Winipcfg.exe, and write the results to a file. 3. Boot Linux. 4. Mount the Win95 file system. 5. Parse the file produced by Winipcfg. 6. Supply Linux with the appropriate networking information. Method ====== Now the details of how I do it, for my particular setup: 1. In my Win95 StartUp folder, I run this command. When Win95 boots, Winipcfg records the DHCP information Win95 has retrieved from the DHCP server: winipcfg -all -batch c:\winipcfg.out The options must be in given order. Omitting "-all" omits some of the information. Omitting the filename writes "winipcfg.out" to the current directory. A sample winipcfg.out file is attached below. 2. Immediately (or sometime later) after booting Win95, I boot Linux. I use loadlin, run from an MS-DOS-mode batch file. You might use that or something else. (It is not possible to combine the Winipcfg and the loadlin into a single batch file, because apparently the "winipcfg.out" file does not get flushed from the disk cache before loadlin runs. I haven't found out any way of flushing the cache from the command line.) 3. When Linux boots, the initial boot script runs "winipcfg.pl", a perl program supplied at the end of this mini-HOWTO. This program must be run after the Win95 file system has been mounted, but before running the "network" script. I use the Debian Linux distribution: attached below is an excerpt from Debian's /etc/init.d/boot, with my additions noted. Your distribution may have different boot scripts, so you may need to adapt this. The "winipcfg.pl" program writes new versions of /etc/hostname and /etc/resolv.conf, and the /etc/init.d/network script. The "network" script does an "ifconfig" with appropriate arguments. That's all there is to it. Note of course that you should not leave your Linux system up for longer than the duration of the DHCP lease. I only boot for a few hours at a time, so that's not a problem for me. You may need to alter the "winipcfg.pl" script if you have more than one network adapter or pseudo-adapter. For instance, AOL software sets up a fake network adapter, and you need to ignore its information. Attachments follow, one per page. ============================================================================== Sample winipcfg.out produced by Win95 "winipcfg -all -batch" (addresses changed to protect the innocent) ============================================================================== Windows 95 IP Configuration Host Name . . . . . . . . . : foo.bar.com DNS Servers . . . . . . . . : 11.222.33.8 11.222.33.9 Node Type . . . . . . . . . : Broadcast NetBIOS Scope ID. . . . . . : IP Routing Enabled. . . . . : No WINS Proxy Enabled. . . . . : No NetBIOS Resolution Uses DNS : Yes Ethernet adapter : Description . . . . . . . . : ELNK3 Ethernet Adapter Physical Address. . . . . . : 00-AA-BB-99-88-77 DHCP Enabled. . . . . . . . : Yes IP Address. . . . . . . . . : 11.222.33.222 Subnet Mask . . . . . . . . : 255.255.255.0 Default Gateway . . . . . . : 11.222.33.1 DHCP Server . . . . . . . . : 11.222.33.10 Primary WINS Server . . . . : Secondary WINS Server . . . : Lease Obtained. . . . . . . : Wed Oct 16 96 10:17:26 PM Lease Expires . . . . . . . : Wed Oct 30 96 10:17:26 PM ============================================================================== ============================================================================== Excerpt from Debian's /etc/init.d/boot, with my addition. ============================================================================== ... # Mount local file systems in /etc/fstab. echo "Mounting local file systems..." mount -avt nonfs # Execute swapon command again, in case we want to swap to # a file on a now mounted filesystem. swapon -a 2>/dev/null #### DHCP info addition #################################################### # Update network information files with info from Win95 DHCP client. if [ -f /c/winipcfg.out -a -x /usr/local/sbin/winipcfg.pl ] then echo "Setting network information from Windows 95 DHCP info." # This writes new versions of hostname, resolv.conf, and init.d/network. # /c/ is where I mount the Win95 file system. /usr/local/sbin/winipcfg.pl /c/winipcfg.out if [ $? != 0 ] then echo "Error getting network information. Using existing network info." fi else echo "** Windows 95 DHCP info not available. Using existing network info." fi #### end of DHCP info addition ############################################# # Setup the network interfaces. Note that /var/run and /var/lock # are cleaned up after this, so don't put anything in the "network" # script that leave a pidfile or a lockfile. if [ -x /etc/init.d/network ] then /etc/init.d/network fi # Set hostname. hostname --file /etc/hostname # Now that TCP/IP is configured, mount the NFS file systems in /etc/fstab. echo "Mounting remote file systems..." mount -a -t nfs ... ============================================================================== ============================================================================== /usr/local/sbin/winipcfg.pl: This is the perl program invoked from the boot script above. ============================================================================== #!/usr/bin/perl while (<>) { # Remove any trailing CR and LF. s/\r//g; s/\n//g; if (/^\tHost Name.*: (.*)$/i) { ($hostname, $domain) = split(/\./, $1, 2); } elsif (/^\tDNS Servers.*: *(.*)$/i) { push @nameservers, $1; } elsif (/^\t +([\.0-9]+)$/) { push @nameservers, $1; } elsif (/^\tIP Address.*: (.*)$/i) { $ip_address = $1; } elsif (/^\tSubnet Mask.*: (.*)$/i) { $netmask = $1; } elsif (/^\tDefault Gateway.*: (.*)$i/) { $gateway = $1; } } $hostname || die "Hostname not given"; $domain || die "Domain not given"; $ip_address || die "IP address not given"; $netmask || die "Netmask not given"; $gateway || die "Gateway not given"; $#nameservers != -1 || die "No nameservers given"; open(HOSTNAME, ">/etc/hostname") || die "Could not open /etc/hostname for writing\n"; open(RESOLV, ">/etc/resolv.conf") || die "Could not open /etc/resolv.conf for writing\n"; open(NETWORK, ">/etc/init.d/network") || die "Could not open /etc/init.d/network for writing\n"; chmod 0755, "/etc/init.d/network"; print HOSTNAME "$hostname\n"; print RESOLV "domain $domain\n"; print RESOLV "search $domain\n"; foreach (@nameservers) { print RESOLV "nameserver $_\n"; } @ip_address = split(/\./, $ip_address, 4); @netmask = split(/\./, $netmask, 4); $network = join(".", $ip_address[0]+0 & $netmask[0]+0, $ip_address[1]+0 & $netmask[1]+0, $ip_address[2]+0 & $netmask[2]+0, $ip_address[3]+0 & $netmask[3]+0); $broadcast = join(".", $ip_address[0]+0 | ~($netmask[0]+0) & 255, $ip_address[1]+0 | ~($netmask[1]+0) & 255, $ip_address[2]+0 | ~($netmask[2]+0) & 255, $ip_address[3]+0 | ~($netmask[3]+0) & 255); print NETWORK "ifconfig eth0 $ip_address netmask $netmask broadcast $broadcast route add -net $network netmask $netmask route add default gw $gateway metric 1 "; print "DHCP info: $hostname.$domain ($ip_address) netmask: $netmask broadcast: $broadcast gateway: $gateway nameservers: @nameservers "; exit(0); ==============================================================================