I originally deployed an old Cisco Catalyst 2970 switch in my new home lab environment however it was insufficient for my needs in a number of ways, such as no being able to act as NTP or DNS server and not supporting SSH for remote management. I also had a 3560, although the model I have has 48 ports (as opposed to the 24 on the 2970 I used) and is physically much longer (both being standard 1U 19” rack-mount height and width) which I why I initially tried the smaller, lower power, 2970.

Initial migration

Migrating began with copying over the existing configuration. This was made easy by looking at the current configuration on the existing switch (show running-config in enable mode) and duplicating what was necessary on the new switch. I skipped the telnet options (line vty…), as I will be setting up the more secure SSH on this switch. After factory-resetting the new switch (same method as the 2970) I opted not to follow the configuration wizard and first set the enable password (in configuration mode):

Switch(config)#enable secret 5 md5_password_from_old_switch

Next I copied over the DHCP configuration, including static leases:

Switch(config)#ip dhcp excluded-address 192.168.100.200 192.168.100.254
Switch(dhcp-config)#dns-server 192.168.100.201
Switch(dhcp-config)#domain-name lab.some.domain.tld
Switch(dhcp-config)#exit
Switch(config)ip dhcp pool readynas-static
Switch(dhcp-config)#host 192.168.100.200 /24
Switch(dhcp-config)#client-identifier 01aa.bbcc.ddee.ff
Switch(dhcp-config)#exit
Switch(config)ip dhcp pool w2k19-dc1-static
Switch(dhcp-config)#host 192.168.100.201 /24
Switch(dhcp-config)#client-identifier 01aa.bbcc.ddee.ff
Switch(dhcp-config)#exit
Switch(config)ip dhcp pool pve1-static
Switch(dhcp-config)#host 192.168.100.210 /24
Switch(dhcp-config)#client-identifier 01aa.bbcc.ddee.ff
Switch(dhcp-config)#exit
Switch(config)ip dhcp pool pve2-static
Switch(dhcp-config)#host 192.168.100.211 /24
Switch(dhcp-config)#client-identifier 01aa.bbcc.ddee.ff
Switch(dhcp-config)#exit
Switch(config)ip dhcp pool pve3-static
Switch(dhcp-config)#host 192.168.100.212 /24
Switch(dhcp-config)#client-identifier 01aa.bbcc.ddee.ff
Switch(dhcp-config)#exit

Finally, I coped over the switch’s IP configuration:

Switch(config)#interface vlan 1
Switch(config-if)#ip address 192.168.100.1 255.255.255.0
Switch(config-if)#exit

Disabling web configuration

One thing I did that I had not done on the old switch is disable the web-configuration interface:

Switch(config)#no ip http server
Switch(config)#no ip http secure-server

Enabling SSH (and disabling telnet)

To enable SSH on all 16 possible vty “lines”, tell it to use the local authentication database (as opposed to a static password set on the line, which is what login along does with telnet) and disable telnet, I did this:

Switch(config)#line vty 0 15
Switch(config-line)#transport input ssh
Swtich(conifg-line)#login local
Switch(config-line)#exit

If you want to enable telnet use transport input telnet ssh instead but I did not do this (despite being an air-gapped network, I have no need to use the less-secure telnet once SSH is setup).

Before connecting via SSH, the switch also needs its host keys generating and I disabled ssh version 1:

Switch(config)#ip domain-name lab.some.domain.tld
Switch(config)#crypto key generate rsa
The name for the keys will be: Switch.lab.some.domain.tld
Choose the size of the key modulus in the range of 360 to 4096 for your
  General Purpose Keys. Choosing a key modulus greater than 512 may take
  a few minutes.

How many bits in the modulus [512]: 4096
% Generating 4096 bit RSA keys, keys will be non-exportable...
[OK] (elapsed time was 333 seconds)
Switch(config)#ip ssh version 2

And finally, add a user to be able to login:

Switch(config)#username laurence password some_secure_password

Configure NTP

The final piece of the puzzle, before swapping the existing switch out, was to configure it to act as a timesource for the air-gapped network. The first thing I did was to set the clock (in enable mode):

Switch#clock set 20:08:00 23 February 2022

Then I set the switch to act as an NTP server, first configuring the timezone (configure mode):

Switch(config)#clock timezone UTC 0
Switch(config)#clock summer-time BST recurring last Sun Mar 01:00 last Sun Oct 01:00
Switch(config)#ntp master 5

I do not know how good at timekeeping the switch will be (one of the reasons I gave it a low stratum, of 5) but I now have a single place to set the time for the entire network.

I subsequently discovered that if the switches loses power, it’s clock resets - I presume there is a dead battery somewhere inside. It is a very old switch.

Saving the config and testing

Finally, I saved the configuration (in enable mode) and then swapped the switch over with the one I had been using:

Switch#copy running-config startup-config
Destination filename [startup-config]?
Building configuration...
[OK]

Like my ReadyNAS it only supports older (deprecated) key-exchange algorithms so I had to explicitly enable one when connecting. I found that, unlike the NAS, the switch also only has vulnerable -cbc cipers too:

ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 -oCiphers=+aes256-cbc -l laurence 192.168.100.1

For some reason the password I set had not taken, so I had to reconnect with a serial console cable (this is why I left the console without authentication - insecure but requires physical switch access and provides a route in if authentication breaks) to reset it to something with only alphanumerics (not sure which character was tripping it up - the original password had both an underscore and hyphen).

Configuring NTP clients

I tested ntp with ntpdate (ntpdate -d 192.168.100.1), this is when I found that the switch’s clock had lost its time and reset to its default (midnight on 1 March 1993) during the swap over (when it was briefly unplugged from the mains) but it did prove the switch was available as a time source. Due to the SSH password issue I had to sort that out before I could set the clock back and configure the clients.

Vanilla Debian 11 (Bullseye)

On my Debian 11 “desktop” in the lab, out of the box it uses systemd’s timesyncd service. This is configured in /etc/systemd/timesyncd.conf and changing it to use the switch required adding/uncommenting these two lines:

[Time]
NTP=192.168.100.1

To get it to re-read the configuration I restarted the daemon:

systemctl restart systemd-timesyncd

and then checked it said it had synchronised with timedatectl status

Proxmox

Proxmox uses chrony for network time synchronisation (as does Red Hat Enterprise Linux 8 so it is a useful tool to know how to configure). Proxmox provide documentation on configuring time synchronisation which boils down to “configure chrony directly”.

Deviating slightly from Proxmox’s documentation I created a new file local-ntp-server.conf in /etc/chrony/conf.d (which is included in the default /etc/chrony/chrony.conf) rather than tamper with the provided main configuration:

server 192.168.100.1 iburst

And restart the daemon for the settings to take effect:

systemctl restart chrony

The status can be checked with journalctl, as suggested in the Proxmox documentation, or in standard log files:

journalctl --since -1h -u chrony
grep chrony /var/log/daemon.log | tail
grep chrony /var/log/syslog | tail

Windows 2019 (Domain Controller)

I was slightly surprised this has to be done from the command line using the w32tm tool but recommend ignoring any websites that suggest editing the registry directly (I found many of those): “Windows registry keys are used by W32Time to store critical information. Don’t change these values.”.

w32tm /config /manualpeerlist:192.168.100.1,0x8 /syncfromflags:manual /update

N.B. manualpeerlist is a space separated list of peers - to add more than one peer it needs to be quoted (e.g. /manualpeerlist:"peer1 peer2"). 0x8 is a peer option required to synchronise with non-Windows time sources.

To see the list of peers being used:

w32tm /query /peers

Force a resync with the new configuration:

w32tm /resync

Verify it is now syncing from the NTP server (if it says “Free running system clock” or “Local CMOS clock” it is not synchronised with NTP):

w32tm /query /source