Isolating a Windows 98/2000 Network (While Still Using SMB Shares)

I gave myself an interesting problem to solve. How do I allow access to file shares from Windows 98 while still securing the rest of my network?

My Synology NAS has the ability to serve files via SMB (or CIFS - for the purpose of this post, these are the same.) But using an old version of the protocol, even with modern and up-to-date versions of Windows, is a very bad idea due to the ease of exploitation using techniques such as EternalBlue. (If you recall, this technique was used by the ransomware WannaCry, costing billions of dollars worldwide in cleanup.)

What I Needed

There were two things I wanted to get out of this:

  • Access to web resources via HTTP, even if the remote resource is HTTPS.
  • Access to file shares via SMBv1, even if the share itself does not accept SMBv1 connections.

What I Purchased

At first, I considered accomplishing this with a smart switch, a separate VLAN and a service that runs on my existing hardware. It's still a good solution, but traffic for that VLAN still has to travel over my home network. I decided that I didn't want the insecure traffic on my main network, even if it was on another VLAN.

Instead, I opted for physical separation. I searched Amazon for a mini PC with four ethernet ports. I figured any system that can run Linux should do, but I also wanted something newer than a system that uses DDR3 memory (yes, they still sell those new.)

The machine I went on to purchase was this Intel N100-based fanless mini PC from Amazon, with four Intel I226-V ethernet ports. I had to purchase my own DDR5 4800MT/S SODIMM memory (the SODIMM distinction is important) and 1TB M.2 NVME SSD for storage.

I discovered that the mini PC only had one memory slot, and that I'd mistakenly purchased a kit of 2 memory sticks. That's something to keep in mind while shopping for one of these.

The specs of the system would be overkill, but I wanted to plan for more services to run on the mini PC.

Installing Rocky Linux

My Linux distribution of choice these days is Rocky Linux. I found it to be a robust distribution while experimenting with Dell PowerEdge servers. I downloaded the Boot ISO, since I wouldn't need the full installation.

I used Rufus to install the boot image onto a USB drive, then booted the mini PC with the USB drive inserted.

The OS would not install as-is until I chose the network as the package source. I also set up a root password, plus an additional account with which I would use to do system administration. I choose the "Server" application profile, which already contains a lot of the services and software I would normally use.

Cockpit

I plan to operate this system without any attached keyboard or monitor after initial configuration, so the first thing I like to do is enable Cockpit, which will enable a control panel accessible via HTTPS port 9090:

sudo systemctl enable --now cockpit.socket

TailScale (Optional)

I like to install TailScale on my systems. The service operates much like a VPN, but the focus is connectivity among your configured devices. (Many other VPN services emphasize anonymity and changing your apparent geolocation. Consider these different.) This also works great for remote access to machines that are behind somewhat strict network firewalls.

Installing TailScale is (typically) as easy as this command:

sudo curl -fsSL https://tailscale.com/install.sh | sh

This configures the TailScale package repository and installs the service. Using the following command then initiates the VPN connection itself:

sudo tailscale up

The installer then prompts me to visit a URL and log in to my TailScale account to set it up. I assign a name and approve the new machine.

Configuring the Network

The machine I have has four ports. One of them will be used to connect to the rest of the home network, and the remaining three will be available for devices that need the old protocol support.

In order to set this up, I go into the Network tab of Cockpit, click Add Bridge, and check all but the first interface, which in my case was enp1s0.  This will create something to the effect of a "virtual network switch", replacing each interface I selected with a single one, bridge0.

I also assigned bridge0 a static IP address - this will be needed later. Feel free to use your own IP block, but these are the settings I used:

IP address: 192.168.33.1
Subnet: 255.255.255.0
Gateway: 192.168.33.254

Configuring the DHCP Server

Since the networked devices won't be directly connected to the rest of my network, I need a way to make sure they can still obtain an IP address and communicate with the other devices on the isolated network. Running a DHCP server is how that happens. I install it with:

sudo dnf install dhcp

It won't be configured for my purpose out of the box, so I add these lines to /etc/dhcp/dhcpd.conf:

subnet 192.168.33.0 netmask 255.255.255.0 {
  range 192.168.33.10 192.168.33.253;
  option routers 192.168.33.1;
}

A concern I had when setting this up was, will this attempt to act as a DHCP server for my main home network? The answer is no: after starting the service and looking at the logs, the subnet is ignored for the enp1s0 interface because its IP address (assigned by my home network) does not reside within the subnet's IP address range.

No subnet declaration for enp1s0 (no IPv4 addresses).
** Ignoring requests on enp1s0. If this is not what
you want, please write a subnet declaration
in your dhcpd.conf file for the network segment
to which interface enp1s0 is attached. **

That's precisely what I want. These lines then enable and start the service:

sudo systemctl enable --now dhcpd.service

Now, whenever a device on the isolated network asks for an IP address, it will be automatically assigned. This will allow the device to access resources on the mini PC.

Bridging the Web with WebOne

Link: The atauenis/webone repository on GitHub.

WebOne is only needed if access to HTTPS sites is needed.

There are browsers available for old systems, but they will only go so far, and only support so much. Still, there is some software that connects to the internet for some rudimentary purpose (checking for updates, synchronizing data, so on), but the servers have been updated to require HTTPS and TLS versions that are no longer supported. If the software supports connecting via a proxy, then WebOne will work as an appropriate solution to do the translation from new protocol to old.

Before installing WebOne, it is important to note its dependencies, which don't automatically get installed using this method. That's because we have to install it from the Git repository directly. The primary dependency is the .NET runtime:

sudo dnf install dotnet-runtime-6.0

Installing WebOne on Rocky Linux then goes like this:

sudo dnf -y install https://github.com/atauenis/webone/releases/download/v0.15.3/webone.0.15.3.linux-amd64.rpm

Then, make sure the service is going to run all the time, and start it now:

sudo systemctl enable --now webone

At this point, the proxy will be available on port 8080.

Configuring Windows to Use the HTTP Proxy

These are the steps to use the proxy service on Windows 98:

  • Click Start, go into Settings and click Control Panel.
  • Double-click Internet Options.
  • Click the Connection tab at the top of the window.
  • Click the LAN Settings near the bottom of the window.
  • Check the box that says to use a proxy server.
  • Enter the IP address of the mini PC into the text box (in my case, it is 192.168.33.1 .
  • Click OK.
  • Close out of the Internet Options and Control Panel windows.

Bridging SMB Shares with Samba

Samba is only needed if access to file shares is needed.

This one required a lot of patience, but I figured out a configuration that works for me. It is in part inspired by a post on Andy's Tech Blog, but deviates in one important aspect: no passwords are required to access the share hosted by the mini PC on the isolated network. (A password is still required to access shares on the NAS from the mini PC, however.)

Two things are needed for bridging SMB shares:

  • A server that will provide access via SMBv1 to devices using old protocols
  • A client that will access my home NAS.

Firstly, the Samba server and CIFS client must be installed.

sudo dnf install samba cifs-utils

Next, I create a credentials file which will store a username/password combination that will be used by the mini PC to access the NAS. This new file will live at at /etc/smb-proxy-credsand contain two lines, which will be the username and password to access the NAS. Using retro as an example username and abc123 as an example password, the file contents will be:

username=retro
password=abc123

Now, I need to configure Samba. Inside /etc/samba/smb.conf I have the following contents at the top:

[global]
        bind interfaces only = yes
        interfaces = lo bridge0
        security = user
        passdb backend = smbpasswd
        server string = Samba %v
        map to guest = bad user
        public = yes
        guest only = yes
        min protocol = NT1
        lanman auth = yes
        client lanman auth = yes
        client plaintext auth = yes
        log file = /var/log/samba/%m.log
        max log size = 10000
        log level = 1
        force user = root
        create mask = 0644
        directory mask = 0755
        browseable = yes
        writeable = yes
        ntlm auth = ntlmv1-permitted
        mangled names = yes

If Windows 98 throws "sharing violation" errors or some programs lock up when attempting to write files to the share, adding oplocks = off will turn off opportunistic locking, which may resolve this issue. The caveat to doing this is, there will be data corruption if multiple clients are attempting to write to the same file.

Mounting a Share

The first step for each share is to create a directory that will be our mount point. For example, if I want my mount point to be called retro-pc I would run this command:

sudo mkdir /mnt/retro-pc

Next, to make it so the share is actually mounted, I add a line to /etc/fstab. Assuming my NAS is located at 192.168.0.10 and my NAS share is an SMB/CIFS share called RetroPc:

//192.168.0.10/RetroPc   /mnt/retro-pc   cifs   rw,noperm,vers=3.11,credentials=/etc/smb-proxy-creds,auto,file_mode=0777,dir_mode=0777 0 0

If the file share on the NAS is a different protocol, such as NFS, this fstab entry will be quite different. (If this is the case, search the internet for how to configure fstab for your particular protocol.)

After making this change, I run this to make sure everything in the system is aware of the new mount point:

sudo systemctl daemon-reload

Now, I add the share to Samba. These lines are added to /etc/samba/smb.conf:

[RetroPc]
        comment = Windows 98 and 2000 Share
        path = /mnt/retro-pc

After making these changes, I restart Samba.

sudo systemctl restart smb

I want all Samba related services to start when the system starts, so I also enable them with a couple commands.

sudo systemctl enable --now smb
sudo systemctl enable --now nmb

Configuring Windows to Use the New Share

Assuming the name of the share I configured is RetroPc, and the IP address of the server is 192.168.33.1, these are the steps to map it on Windows 98:

  • On the desktop, right-click My Computer and select Map Network Drive from the menu.
  • Select a drive letter that this network drive will use.
  • Fill in the address/location box with \\192.168.33.1\RetroPc.
  • Make sure the checkbox to reconnect at system start is checked.
  • Click next through all the following dialogs.

Adding TFTP Connectivity

TFTP, or the Trivial File Transfer Protocol, is a necessary service in order for network boot to work. Getting this started on Rocky was as simple as following a guide written by Prateek Jangid on LinuxHint, but there are more steps to getting network boot to run. I will reproduce those steps here.

First, I install tftp-server with the following command.

sudo dnf install tftp-server

There are some post-install steps that I need to run for Rocky. Firstly, the services need to be copied over from the systemd configuration:

sudo cp /usr/lib/systemd/system/tftp.service /etc/systemd/system/tftp-server.service
sudo cp /usr/lib/systemd/system/tftp.socket /etc/systemd/system/tftp-server.socket

Next, we will need to edit the service file. In the /etc/systemd/system/tftp-server.service file, the contents should be modified to read:

[Unit]
Description=Tftp Server
Requires=tftp-server.socket
Documentation=man:in.tftpd

[Service]
ExecStart=/usr/sbin/in.tftpd -c -p -s /var/lib/tftpboot
StandardInput=socket

[Install]
Also=tftp.socket

The only changes that should be needed are in the Requires and ExecStart lines. Once the modifications are saved out, the service can then be enabled and started:

sudo systemctl daemon-reload
sudo systemctl enable --now tftp-server

Setting these permissions should enable reading via TFTP:

chmod 755 /var/lib/tftpboot

Configuring the DHCP Server For Network Boot

Each client is going to need to know where to look for the files necessary to do a network boot. The DHCP server is the source of truth for this information. So, inside /etc/dhcp/dhcpd.conf, inside the subnet block, the following line needs to be added. (Use the mini PC's IP address in place of mine, according to the internal network.)

next-server 192.168.33.1;
filename "netboot.xyz.kpxe";

Adding Boot Images to TFTP

There's a page on kentie.net that gave guidance on booting Windows 98 boot disks via the network.

Inside /var/lib/tftpboot, I add files from SysLinux. At the time of this writing, version 6.03 is the latest available. Downloads can be found via kernel.org. The files from the archive that need to be extracted are:

/bios/com32/elflink/ldlinux/ldlinux.c32
/bios/com32/libutil/libutil.c32
/bios/com32/menu/menu.c32
/bios/core/pxelinux.0
/bios/memdisk/memdisk

Additionally, a Windows 98 boot disk floppy image (named boot98.ima) and a boot disk with appropriate network drivers for my NIC (named netboot.ima) will need to be placed in the same directory.

Now, a configuration file should be created at /var/lib/tftpboot/pxelinux.cfg/default with the following contents:

default menu.c32
prompt 0
menu title Boot

 LABEL Network boot disk
  LINUX memdisk
  INITRD netboot.ima
  APPEND keeppxe

For each other disk image I want to make available, a new entry needs to be added to the file, to a similar pattern to:

 LABEL Windows boot disk
  LINUX memdisk
  INITRD boot98.ima

The reason we can't keep the PXE boot image loaded during install is, Windows 98 Setup doesn't have enough memory to keep network images around.

The procedure to install Windows 98 with no media whatsoever looks like:

  • Boot into the network boot disk
  • Partition hard drive, copy Windows CD contents to the drive
  • Reboot into the Windows 98 boot disk
  • Run Windows 98 setup

(work in progress)

Configuring the Firewall

I don't want to expose many of these services to my home network, and I don't want to allow unwanted traffic to cross over between the networks. Cockpit makes it a little easier to open ports to certain interfaces, and deny access to others. firewalld handles firewall operations on the device.

Moving interfaces between zones is a little cumbersome via the UI, so there are a few commands I run in the terminal. (More information on managing interfaces within firewalld can be found on this article at freekb.net.)

Before doing anything, I like to make sure that cockpit and ssh will be available in the new zone that I am using to manage the connections. I will be putting my home network connections in the work zone.

sudo firewall-cmd --zone=work --add-service=ssh --permanent
sudo firewall-cmd --zone=work --add-service=cockpit --permanent

The next few lines move the primary interface that connects my home network to a different zone, and ensures that the rest of my interfaces are within their own zone.

sudo firewall-cmd --permanent --zone=work --add-interface="enp1s0"
sudo firewall-cmd --permanent --zone=public --add-interface="enp2s0"
sudo firewall-cmd --permanent --zone=public --add-interface="enp3s0"
sudo firewall-cmd --permanent --zone=public --add-interface="enp4s0"
sudo firewall-cmd --permanent --zone=public --add-interface="bridge0"

While logged into Cockpit, under Networking, inside the Firewall section, I click on the Edit rules and zones button to get into the firewall configuration. I should see that there are two zones in use: public and work.

Inside the public zone, I make sure that the samba, tftp, and http-proxy services are all available, and make sure that they are not available in the work zone.

Inside the work zone, I make sure that the ssh and cockpit services are still there.

Finally, I make sure that the runtime firewall configuration is reloaded with the following command:

sudo firewall-cmd --reload

Conclusion

In this post, I described how I isolated my Windows 98/2000 machines to a network separate from my home network. This should also work for giving access to Windows 98/2000 machines if the NAS uses a different protocol, such as NFS - although the fstab entry will be different.