Netgear GS728TP CLI and scripting


It's been a long time between posts. I can assure you I'm not dead. At least not that I know of. I've been doing some neat stuff, but have been too lazy to post any of it - because as any dev will tell you - doing documentation is boring.

So, after upgrading my access points to use a Cisco Virtual Wireless Controller, I was using the web interface on my Netgear GS728TP - but it really sucks. It's slow. It's really slow - but it has a fully functioning CLI under the hood. However, the SSH server is old as well, so it needs a whole heap of legacy enablement in the SSH client to function. It is an EoL product, being first released in November 2017 from what I can tell. However they're cheap to find second hand, and have 8x POE+ ports - which means they'll run your high power PoE kit.

I did some work with expect - and came up with this script to do some pretty common functions.

Save as ~/bin/switch.

#!/usr/bin/expect
set switch_password "<switch password>"
set switch_login "admin@<switch ip>"
set TFTPSERVER "<tftp server ip>"
set switch_ssh_opts "-oPubKeyAcceptedAlgorithms=ssh-rsa -oRequiredRSASize=1024 -oKexAlgorithms=diffie-hellman-group1-sha1 -oHostKeyAlgorithms=ssh-rsa,ssh-dss -oCiphers=aes128-cbc,aes128-ctr,aes256-ctr"
set commands(0) "terminal datadump"
set commands(1) "terminal width 0"
set timeout 120

set func [lindex $argv 0]
switch $func {
    if {
        set arg [lindex $argv 1]
        switch $arg {
            description {
                append commands([array size commands]) "show interfaces description"
            }
            detail {
                set port [lindex $argv 2]
                append commands([array size commands]) "show interfaces switchport ge $port"
            }
            reset {
                set port [lindex $argv 2]
                append commands([array size commands]) "config"
                append commands([array size commands]) "interface GigabitEthernet $port"
                append commands([array size commands]) "shutdown"
                append commands([array size commands]) "no shutdown"
                append commands([array size commands]) "exit\rexit\r"
            }
            summary {
                append commands([array size commands]) "show interfaces status detailed"
            }
            default {
                puts "Subcommands:\r"
                puts "\tdescription\r"
                puts "\tdetail <port>\r"
                puts "\treset <port>\r"
                puts "\tsummary\r"
                exit 0
            }
        }
    }
    poe {
        set arg [lindex $argv 1]
        switch $arg {
            consumption {
                append commands([array size commands]) "show power inline consumption"
            }   
            off {
                set port [lindex $argv 2]
                append commands([array size commands]) "config"
                append commands([array size commands]) "interface GigabitEthernet $port"
                append commands([array size commands]) "power inline never"
                append commands([array size commands]) "exit\rexit\r"
            }
            on {
                set port [lindex $argv 2]
                append commands([array size commands]) "config"
                append commands([array size commands]) "interface GigabitEthernet $port"
                append commands([array size commands]) "power inline auto"
                append commands([array size commands]) "exit\rexit\r"
            }
            reset {
                set port [lindex $argv 2]
                append commands([array size commands]) "config"
                append commands([array size commands]) "interface GigabitEthernet $port"
                append commands([array size commands]) "power inline never"
                append commands([array size commands]) "power inline auto"
                append commands([array size commands]) "exit\rexit\r"
            }
            summary {
                append commands([array size commands]) "show power inline"
            }   
            default {
                puts "Subcommands:\r"
                puts "\tconsumption\r"
                puts "\toff <port>\r"
                puts "\ton <port>\r"
                puts "\treset <port>\r"
                puts "\tsummary\r"
                exit 0
            }
        }
    }
    reboot {
        send -- "reload\r"
        expect "(Y/N)"
        send -- "y\r"
        interact
    }
    saveconfig {
        set DATE [clock format [clock seconds] -format {%Y-%m-%d_%H%M}]
        append commands([array size commands]) "copy running-config tftp://$TFTPSERVER/gs728tp/running-config-$DATE.txt"
    }
    vlan {
        append commands([array size commands]) "show vlan"
    }
    default {
        puts "Commands:\r"
        puts "\tif <cmd>\r"
        puts "\tpoe <cmd>\r"
        puts "\treboot\r"
        puts "\tsaveconfig\r"
        puts "\tvlan\r"
        exit
    }
}

eval spawn ssh $switch_ssh_opts $switch_login

expect "assword:"
send -- "$switch_password\r"
for { set index 0 }  { $index < [array size commands] }  { incr index } {
    expect "#"
    send -- "$commands($index)\r"
}
expect "\r\nconsole#"
send -- "exit\r"
expect eof

This gives me a nice little easy to use command set for some very basic stuff - however, if you're like me with a million scripts, I also forget the options :)

As such, I took a dive into the bash-completion universe and managed to come up with this.

Save as ~/.bash_completion.

#/usr/bin/env bash
_switch_completions()
{
  local cur prev

  COMPREPLY=()
  cur=${COMP_WORDS[COMP_CWORD]}
  prev=${COMP_WORDS[COMP_CWORD-1]}

  if [ $COMP_CWORD -eq 1 ]; then
    COMPREPLY=( $(compgen -W "if poe reboot saveconfig vlan" -- $cur) )
  elif [ $COMP_CWORD -eq 2 ]; then
    case "$prev" in
      "if")
        COMPREPLY=( $(compgen -W "description detail reset summary" -- $cur) )
        ;;
      "poe")
        COMPREPLY=( $(compgen -W "consumption off on reset summary" -- $cur) )
        ;;
      *)
        ;;
    esac
  fi

  return 0
} &&
complete -F _switch_completions switch

As an example, if I run switch if summary, I'll get the following output:

spawn ssh -oPubKeyAcceptedAlgorithms=ssh-rsa -oRequiredRSASize=1024 -oKexAlgorithms=diffie-hellman-group1-sha1 -oHostKeyAlgorithms=ssh-rsa,ssh-dss -oCiphers=aes128-cbc,aes128-ctr,aes256-ctr admin@<switch-ip>
admin@<switch-ip>'s password:

console#terminal datadump
console#terminal width 0
console#show interfaces status detailed
                                             Flow Link          Back   Mdix
Port     Type         Duplex  Speed Neg      ctrl State       Pressure Mode
-------- ------------ ------  ----- -------- ---- ----------- -------- -------
g1       1G-Copper    Full    1000  Disabled Off  Up          Disabled On     
g2       1G-Copper      --      --     --     --  Down           --     --    
g3       1G-Copper      --      --     --     --  Down           --     --    
g4       1G-Copper      --      --     --     --  Down           --     --    
g5       1G-Copper      --      --     --     --  Down           --     --    
g6       1G-Copper      --      --     --     --  Down           --     --    
g7       1G-Copper      --      --     --     --  Down           --     --    
g8       1G-Copper      --      --     --     --  Down           --     --    
g9       1G-Copper    Full    1000  Disabled Off  Up          Disabled On     
g10      1G-Copper    Full    1000  Disabled Off  Up          Disabled On     
g11      1G-Copper    Full    1000  Disabled Off  Up          Disabled On     
g12      1G-Copper    Full    1000  Disabled Off  Up          Disabled On     
g13      1G-Copper    Full    100   Enabled  Off  Up          Disabled On     
g14      1G-Copper    Full    100   Enabled  Off  Up          Disabled Off    
g15      1G-Copper      --      --     --     --  Down           --     --    
g16      1G-Copper      --      --     --     --  Down           --     --    
g17      1G-Copper      --      --     --     --  Down           --     --    
g18      1G-Copper      --      --     --     --  Down           --     --    
g19      1G-Copper      --      --     --     --  Down           --     --    
g20      1G-Copper      --      --     --     --  Down           --     --    
g21      1G-Copper      --      --     --     --  Down           --     --    
g22      1G-Copper      --      --     --     --  Down           --     --    
g23      1G-Copper    Full    1000  Enabled  Off  Up          Disabled On     
g24      1G-Copper    Full    100   Enabled  Off  Up          Disabled Off    
g25      1G-Fiber       --      --     --     --  Down           --     --    
g26      1G-Fiber       --      --     --     --  Down           --     --    
g27      1G-Fiber       --      --     --     --  Down           --     --    
g28      1G-Fiber       --      --     --     --  Down           --     --    

                                          Flow    Link        
Ch       Type    Duplex  Speed  Neg      control  State       
-------- ------- ------  -----  -------- -------  ----------- 
po 1        --     --      --      --       --    Not Present 
po 2        --     --      --      --       --    Not Present 
po 3        --     --      --      --       --    Not Present 
po 4        --     --      --      --       --    Not Present 
po 5        --     --      --      --       --    Not Present 
po 6        --     --      --      --       --    Not Present 
po 7        --     --      --      --       --    Not Present 
po 8        --     --      --      --       --    Not Present 
console#exit

So now, not only do I have an easy way to bring up basic details of the switch, when I forget what options do what, you can just use the TAB auto-completion in bash. Yay, yet another thing I don't have to remember in the day-to-day :)

Upgrading an Ender 3 hotbed


For a long time now, I've been annoyed at how long it takes for the stock 24v / 120W hotbed to get to 100C to start printing ABS.

Normally, you set the bed heating up, then wait a while, then download your model, slice it, send it to the printer and you'd be almost at printing temperature.

This needs to be faster.

I got a 500W 240v AC powered heater and to control it, some SSR-D3808 solid state relays.

The SSR-D3808 is good for 8A at 24-380vAC - which is waaaaay more than what the hotbed will ever draw - but its only $0.10USD more expensive than the 5A version. More is better.

Before I go any further, I have to give this warning. This modification plays with mains voltage power. It can kill you. It can also hurt you the entire time that its killing you. If you're not comfortable with that, read the rest of this page, go "huh, that's cool" and get someone else to do it for you.

To wire this up, we want to run the + / - from the output of the control board to the + / - terminals on the solid state relay. In a nutshell, this:

Basic Circuit Diagram

You'll then need to do some modifications in Marlin's Configuration - or use my trusty Firmware Builder!

Set:

  • Hotbed Thermistor Type (TEMP_SENSOR_BED) to 11 (100k beta 3950 1% thermistor)
  • Enable PIDTEMPBED

This will ensure you are able to accurately control temperatures with the additional power. Using the stock BANG BANG method, I overshot target temperatures by 6 or more degrees.

When you've flashed that firmware, make sure you do a PID Tune on the bed using M303 E-1 C10 S100. This will cycle around the 100C target temperature 10 times and then give you some Kp, Ki, and Kd values. Set these in Marlin via M304 P35.63 I6.94 D121.86 - but remember to replace the values here with ones for your setup.

Finally, save your configuration to EEPROM using M500.

Enjoy the faster heating speeds :)

Octoprint

Training SpamAssassin's Bayes filter with Proxmox Mail Gateway


One of the problems with bayes filters is that you need to train them on both ham and spam. As Proxmox Mail Gateway only uses the Bayes filter for messages that pass originally, there is no way to force it to learn spam - leaving a hole in how to train.

Here are the steps for adding that feedback loop for sa-learn.

1) On the PMG Server, create the following script as /root/bin/remote-commands, then chmod +x /root/bin/remote-commands to make it executable:

#!/bin/sh
case "$SSH_ORIGINAL_COMMAND" in
        report)
                sa-learn --spam
                ;;
        revoke)
                sa-learn --ham
                ;;
        *)
                echo "Invalid command?"
                ;;
esac

2) Create an SSH Key, put the private part on the end mail server, then add the public part to /root/.ssh/authorized_keys and force it to use the restricted command:

command="/root/bin/remote-commands" ssh-rsa AAAA....rest-of-key... root@mail

You can further restrict this to a set of IP addresses by using the from= command as documented.

3) On the mail server, add the following script to /root/bin/spam-reporter. This assumes a number of things. The mail directories on the target system are listed as /mail/username in Maildir format. The end user IMAP mail directory will be "Spam". You can change these as required for your install. This handles multiple message formats that Dovecot uses - plain, gz or bz2 compressed. It could also be expanded if needed.

#!/bin/bash
MAILFILTER=<ip of PMG install>

for i in /mail/*/.Spam/cur/* /mail/*/.Spam/new/*; do
        if [ -f "$i" ]; then
                STATUS=`file "$i"`
                if [[ $STATUS == *"gzip"* ]]; then
                        gunzip -d -c "$i" > /tmp/tempmail.$$
                fi
                if [[ $STATUS == *"bzip2"* ]]; then
                        bzip2 -d -c "$i" > /tmp/tempmail.$$
                fi
                if [[ $STATUS == *"SMTP mail"* ]]; then
                        cp "$i" /tmp/tempmail.$$
                fi

                cat /tmp/tempmail.$$ | ssh root@$MAILFILTER report
                if [ $? != 0 ]; then
                        echo "Error running sa-learn. Aborting."
                        exit 1
                fi
                rm -f "$i"
                rm -f /tmp/tempmail.$$
        fi
done

4) If you're going to use SystemD's timer specs, create /etc/systemd/system/spam-reporter.service with the following:

[Unit]
Description=This service automatically reports spam.

[Service]
Type=oneshot
ExecStart=/root/bin/spam-reporter

Then the timer unit as /etc/systemd/system/spam-reporter.timer:

[Unit]
Description=This is the timer to check for spam and report it.

[Timer]
OnCalendar=*:0/5
Persistent=true

[Install]
WantedBy=timers.target

Then enable the timer with systemctl daemon-reload && systemctl enable spam-reporter.timer --now.

That's it! Now if your users throw mail in the Spam IMAP folder, it'll get fed back into PMG's bayes filter as spam.

New Guide - Changing fans in a CyberPower UPS


Just a quick update. I recently wrote a guide on how to replace dead fans in a CyberPower UPS. They use high speed (4000RPM+) fans in the factory, which you just can't easily get.

This guide shows you how to fool the UPS into thinking it has a high speed fan and still operate.

Be careful though, this is messing with mains voltage and reducing airflow - you might burn your house down.

Grandstream phones, APD-80 and 85638-01 cables


A number of months ago, I deployed a new SIP network using Grandstream GXP-1782 phones. For some of the folks that are always on the phone, we got a couple of Plantronics DECT headsets - which are specificially listed on the compatible headset list published by Grandstream.

The headset plugged into a APD-80 adapter cable. The Plantronics documentation states that a "85638-01 adapter" cable is required - although this is listed as an adapter to extend the APD-80 cable. When you look at the length of the APD-80 cable, this seems nuts - however the 85638-01 cable holds a secret.

Without the special 85638-01 cable, pickup and hangup of the phone was very unreliable. Lots of sites have this documented as a straight through cable - but it is not. The pins on this are actually reversed - ie:

End One

End Two

1

4

2

3

3

2

4

1

See example photo:

/images/85638-01/cable.jpg

Using this cable, you should find that the hangup and pickup functions work correctly without spending $15 per cable.

Credits to Michael Schneider for discovering this

Migration from Wordpress to Nikola


A new year, a new blog engine.

While Wordpress is quite useful, its a heavy, hunking bit of software for those who just post occasionally and don't really need any dynamic content at all. This is where Nikola comes into play.

Nikola takes posts in reST, Jupyter Notebook, YAML, TOML, Markdown or HTML and runs them through the theming engine to get plain, static HTML.

The benefit of this is almost zero load on your web server - as there is no dynamic data to process. Especially good for cheap VPS packages from the many online providers.

So far, I'm impressed!

New page - converting PWM hubs to voltage controlled


New guide up - right here. My Xen servers main board didn't have a second PWM controlled fan header to use with a PWM fan hub for the 3 case fans. Its a 4RU case - which has server grade 140mm fans that can draw up to 0.9A each and get up to around 3600 RPM. So here's how I used an ATTiny85 to generate a PWM signal from the variable 'Speed Control' voltage on pin 2 of the SYS_FAN header.

Enabling BBR Congestion-Based Congestion Control on kernel-xen


With the release of kernel-xen version 4.9.40, I have enabled CONFIG_TCP_CONG_BBR. This adds support for using BBR to improve the throughput from your servers (mostly web servers) to your clients. If you run my kernel-xen package on your Xen guests, you can also take advantage of this new feature. To enable, ensure you are running kernel-xen version 4.9.40 or above, then create a file called /etc/sysctl.d/enable-bbr.conf containing:

net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr
You can activate this by typing: $ sysctl -p The changes will automatically apply at the next system boot. To read more about BBR and why it makes such a difference, head on over to acmqueue for a far more in-depth analysis than I could provide.