Docker Images Not Starting

After updating my Linux host yesterday, the docker images failed to start with the following error:

Error starting userland proxy: listen tcp6 [::]:9091: socket: address family not supported by protocol

For some reason IPv6 (the hint is tcp6) is screwing things up. The problem is that I disabled IPv6 from the start on this host. Mainly because of some concerns in regards of routing and internet accessibility (I have a formal IPv6 subnet at home).

After about an hour of troubleshooting I changed the docker-compose.yaml file to include the actual IP address of the host instead of just the ports the container uses.

The old:

        ports:
          - '9091:9091'
          - '8888:8080'

New:

        ports:
          - '192.168.0.1:9091:9091'
          - '192.168.0.1:8888:8080'

Restarting the docker images went just fine after this. So I guess the update I ran yesterday included a docker update that basically thinks that you have IPv6 enabled by default. The problem is that I couldn’t find documentation on how to disable this globally.

Posted on April 14, 2021 and filed under Annoying, Linux.

My First Docker Deployment

About two weeks ago I had to get a crash-course in Docker technology at work. I had no idea what I was doing (following a YouTube video and an accompanying PDF. Eventually I got it to work but no idea what I was doing. So I wanted to change that.

NOTE: I’m not gonna build/create new docker containers yet. Just learning on how they are used, configured, and interact. This is also no tutorial on how to install Docker itself. There are more than enough websites for that.

The problem with learning new things is that they have to be practically and/or useful (for me). After some thought I ended up with a combination of Transmission and OpenVPN.

This Docker image gives you a Torrent client with a webgui, and all (torrent) traffic is directed through the OpenVPN connection. Making it safe to download Linux distro’s. As a bonus, it has a generic web proxy function with you can use to handle your web traffic. The latter is especially useful in combination with e.g. the browser extension/plugin FoxyProxy.

Deploying the docker container is pretty straight-forward (you do need a supported VPN provider). It basically works out of the box, but molding it to my wishes involved a bit more digging around. There are some things I wanted to add, or change;

  • Customer paths for the download locations (default = /data).

  • Use a watchfolder for transmission where the .torrent files can be picked-up.

  • Use an additional reverse proxy for the Transmission webGui so that all my internal services are accessible from 1 IP address without having to remember al their TCP ports.
    More info on that can be found here.

  • Since the Docker container runs under a/the root account, I needed to change that behavior since I don’t want to do everything with root permissions (involving experimentation with umask and UID/GID’s).

This resulted in the following docker-compose file (docker-compose.yaml):

UPDATE: I’ve added the Portainer image to the compose file. This gives you a web gui to manage the containers. The gui is accessible on port 9000 on the same docker host.

version: '2'
services:
    transmission-openvpn:
        restart: unless-stopped
        volumes:
            - '/mnt/data:/data'
            - '/mnt/stack/Watchfolder:/home/Watchfolder'
            - '/etc/localtime:/etc/localtime:ro'
        environment:
            - TZ=Europe/Amsterdam
            - OPENVPN_OPTS=--inactive 3600 --ping 10 --ping-exit 60
            - CREATE_TUN_DEVICE=true
            - OPENVPN_PROVIDER=NORDVPN 
            - OPENVPN_USERNAME=<VPN-USERNAME>
            - OPENVPN_PASSWORD=<VPN-PASSWORD>
            - NORDVPN_COUNTRY=CH
            - HEALTH_CHECK_HOST=google.com
            - TRANSMISSION_INCOMPLETE_DIR_ENABLED=true
            - TRANSMISSION_INCOMPLETE_DIR=/data/downloads/incomplete
            - TRANSMISSION_DOWNLOAD_DIR_ENABLED=true
            - TRANSMISSION_DOWNLOAD_DIR=/data/downloads/complete
            - TRANSMISSION_WATCH_DIR_ENABLED=true
            - TRANSMISSION_WATCH_DIR=/home/Watchfolder
            - TRANSMISSION_TRASH_ORIGINAL_TORRENT_FILES=true
#            - TRANSMISSION_UMASK=222
            - TRANSMISSION_SPEED_LIMIT_DOWN=5000
            - TRANSMISSION_SPEED_LIMIT_DOWN_ENABLED=true
            - TRANSMISSION_SPEED_LIMIT_UP=1000
            - TRANSMISSION_SPEED_LIMIT_UP_ENABLED=true
            - WEBPROXY_ENABLED=true
            - WEBPROXY_PORT=8080
            - LOCAL_NETWORK=192.168.0.0/16
            - PUID=1000
            - PGID=1000
        cap_add:
            - NET_ADMIN
        logging:
            driver: json-file
            options:
                max-size: 10m
        ports:
                - '9091:9091'
                - '8888:8080'
        image: haugene/transmission-openvpn
        container_name: openvpn
    portainer:
        image: portainer/portainer-ce
        container_name: portainer
        restart: always
        ports:
          - "9000:9000"
        command: -H unix:///var/run/docker.sock
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock
          - portainer_data:/data

volumes:
  portainer_data:

The thing that took the most amount of time to figure out was the PUID/PGID part of the config. This basically are the user id and group id which are used to run the container and also when creating directories and files on the physical filesystem of the host. In my case, the PUID, and PGID are the id’s corresponding to my username on the Linux host.

The important part is that all the path references in the environment part of the yaml file are local to the container. These are mapped/related to the physical locations in the volumes part of the config file.

Deploying/creating the Docker container is done through the following command (I use docker-compose instead of docker run):

docker-compose up -d

Configuring a webproxy in my browser pointing to the Linux host IP with port 8888 allows me to surf the web through the OpenVPN provider. Pointing my browser to the Linux host IP address with port 9091 gives the Transmission webGui (http://IP-ADDRESS>:9091). But as I mentioned earlier, I want to access this through my internal reverse proxy (NGINX).

To do this I have to create an additional location within the NGINX config and enable that. This resulted in the following NGINX location config file:

location /transmission/ {
      proxy_pass http://192.168.##.1:9091;

      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_set_header X-NginX-Proxy true;
      proxy_http_version 1.1;
      proxy_set_header Connection "";
      proxy_pass_header X-Transmission-Session-Id;
      add_header   Front-End-Https   on;

      satisfy any;
      allow 192.168.0.0/16;
      allow 172.16.16.0/24;
      allow 10.200.200.200/32;
      deny all;
      auth_basic "Restricted Content";
      auth_basic_user_file /etc/nginx/auth.d/auth.pwd;
}

Note that the bottom part are some directoves to limit the IP’s that can access the page. These are related to your internal IP networks.

Now I can access the tranmission webGui over https through my NGINX reverse proxy via https://internalhost/transmission

A small note on the use of FoxyProxy; This extension allows you to selectively use the proxy based on (parts of ) URL. You can configure patterns using wildcards and regular expressions to direct traffic directly or through a proxy.

So if e.g. your OpenVPN terminates in the the US, you can create a pattern that certain entertainment sites are being accessed through your proxy, while other traffic uses your regular ISP. This is especially useful if you have a capped monthly VPN account.

Posted on July 29, 2020 and filed under Linux, Programming, Security, Software, Tips'n Tricks.

Keepass Password Generator

With the increasing password complexity demands in both online and offline services, you basically can’t live without a password manager. Personally I use 1Password, but at work Keepass is recommended. Main reason is that it remains local (no passwords in the cloud). Downside is that you need to have a proper backup in case of emergencies (or rely on decent password reset mechanisms.

Since a generic password scheme is obvious highly overrated, you basicalle need a different password scheme for every website, application or service. The worst being password schemes that limit the amount of characters to between 6 and 10…. Seriously? Others limit the amount of special characters like @\/’”| because of some fear of SQL injection schemes. Which is not a problem if you implement the backend correctly…. But that’s for another day.

Due to all these password challenges I had to reconfigure my Keepass (default) password generator to be a bit more friendly. For those bad password scheme website I have specific generation algoritms, and in a few cases the demands on the password are so ridiculous that I had to make a generator just for that service.

Anyway, the latest ‘challenge’ was that a service demanded a letter at the start and finish of the password, so that resulted in the following pattern:

L[uullddss]{22}L

keepass_pswd_gen_01.png

This results in a password:

  • Starting with a mixed-case letter (L), followed by a 22 character mix of at least

  • 2 upper-case (uu) letters (ABCDEFGHIJKLMNOPQRSTUVWXYZ),

  • 2 lower-case (ll) letters (abcdefghijklmnopqrstuvwxyz),

  • 2 digits (dd) (1234567890),

  • 2 printable special characters (ss) ( !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ ),

  • and finishing with another mixed case letter (ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)

Note that the previous default password length was 22 character, so increasing it with 2 additional letters to 24, the password became a bit stronger. Otherwise the password would have weakened substantially, because the first and last character was one out of 52.

This results in the following preview:

When you need to communicate passwords, or manual type them (on another device) it might be helpful to exclude certain characters that (depending on the font) look alike (e.g. 1Il|, O0). This can be accomplished in the ‘Advanced’ tab of the password generator.

Note that excluding these characters reduce the complexity of the password (which can be corrected up to some extend by increasing the password length).

And in those weird cases where certain character are not allowed you can use the ‘exclude characters’ option in the screenshot above (make sure you increase the password length accordingly to maintain password security).

Posted on June 8, 2020 and filed under Security, Tips'n Tricks.

Xiaomi Xiaofang Wireless Camera Custom Firmware Hack

A colleague of mine demonstrated a Wyze webcam a couple of weeks before. A nifty little FullHD wireless IP camera that has a decent (iOS/Android) app and cloud connectivity to store the data.
I liked everything about it, except the cloud-storage part. I don’t like it when I don’t know where my private data resides. So I started a to search to see if these devices could be altered to benefit my needs, and guess what, they can be altered.

There’s a github project where they fabricated a firmware hack and with custom software the camera can be used for much more. So now I had to get my hands on the most inexpensive version of the camera. Since there are different brands that ship basically the same hardware with a different firmware, there’s more than enough choice.

Posted on November 19, 2019 and filed under Gadgets, Hardware, Security, Review, Tips'n Tricks.

Add Custom Python3 Modules Path (Windows / MacOS)

After installing Python on Windows or MacOS, the installer makes sure that everything works fine. All paths are available/accessible for Python. Adding modules through pip also works just fine.

The problem is that the paths used are hard to remember (e.g. Windows: c:\Users\<username>\AppData\Local\Programs\Python\Python37\), so if you want to use some custom modules you have to use the (complex) default structure, or you can use your own.

Using your own directories for custom modules requires adding the path(s) to the environment variable PYTHONPATH.

Windows

After installing Python, the installer add the PYTHONPATH environment variable to Windows. All you need to do is add your custom path to this variable.

The environment variables can be found through:

This PC -> Properties -> Advanced Settings -> Environment Variables

In screenshots:

MacOS

On my MacOS devices I had to add the path(s) to 2 different files because (regular) GUI based programs (like Pycharm and Python IDLE) use different environment variables than the terminal / console interpreter.

GUI-Based programs

Create a startup plist file (e.g. ~/Library/LaunchAgents/my.startup.plist) and add the following XML content:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>my.startup</string>
  <key>ProgramArguments</key>
  <array>
    <string>sh</string>
    <string>-c</string>
    <string>launchctl setenv PYTHONPATH ~/Python_Scripts/_my_modules</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
</dict>
</plist>

The string ‘~/Python_Scripts/my_modules/’ points to my custom module directory. Edit this to reflect your own directory structure. If you need multiple directories you can add these by seperating them by using a colon (:) e.g.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>my.startup</string>
  <key>ProgramArguments</key>
  <array>
    <string>sh</string>
    <string>-c</string>
    <string>launchctl setenv PYTHONPATH ~/Python_Scripts/_my_modules:~/Desktop/my_scripts</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
</dict>
</plist>

To makes these changes active you can either reboot, log-out/log-in or execute the following command:

launchctl load ~/Library/LaunchAgents/my.startup.plist

Terminal / Console

For the terminal / console based Python interpreter you need to add some lines to the ~/.bash_profile or ~/.zprofile file (depending wether you use bash or zsh as shell).

PYTHONPATH="~/Python_Scripts/_my_modules:$"
export PYTHONPATH

Multiple directories can (again) be added by using the colon seperator (:):

PYTHONPATH="~/Python_Scripts/_my_modules:~/Desktop/my_scripts:$"
export PYTHONPATH

To activate this, just quit the open terminal/console windows (CMD-q) and open it again.

Posted on November 7, 2019 and filed under Programming, Tips'n Tricks.

Cisco ISE MAC Addresss Database Clean Up

Imagine having 15.000+ MAC addresses in a Cisco ISE database. All these MAC addresses are used to gain access to wireless networks protected with WPA2-PSK and MAC-filtering. But how to make sure that they are all (still) valid?

Remove MAC Addresses After Change In Authentication

Finally, the time has come to implement 802.1x on the wireless network for a substantial amount of these devices. These devices are consist mainly of Windows machines or Thin Clients. Both of those are managed through either the Microsoft Active Directory or a Thin Client Management Suite. So, applying setting related to 802.1x are pretty straight forward to distribute. There are however some Windows / Thin client devices that will remain on the MAC-filtering wifi networks for numerous reasons.

After a few tests the migration of the new 802.1x devices has started, but is leaving us with a MAC Address database filled with addresses that can be removed, since they are no longer used…. But how to do that? Cisco ISE has a lot of features, and is capable of generating rich reports about almost everything. However it has no way of reporting on dot1x devices that might still remain in the MAC address database as well. That is where I had to become creative.

First I explored the Cisco ISE Monitoring API, but that only gives active connections. There’s no way of exploring past (successful) authentications/authorizations. I needed a way to get current and past successful dot1x authentications and compare the MAC addresses associated with those entries to the MAC address database, and remove those from that database.

Eventually, I found two paths to accomplish this; First through the reporting module. There you can export all RADIUS authentications to CSV. Filtering these results in Excel, or through Python scripting, you are able to extract the MAC Addresses that successfully authenticated with dot1x. Feed these MAC addresses to a script and remove them through the Cisco ISE ERS API. Or if you’ve got nothing else to do; do it by hand.

The other path is by following the syslog output and parsing that feed. The downside to this is that you have to have syslog file access or add an additional syslog server to Cisco ISE that you may access (e.g. your scripting machine). The syslog version makes a a bit more tricky, since the (syslog)log lines are very long and you have to combine the correct lines to get the full message. Parsing CSV is much easier, so I followed that path first.

Dormant/Obsolete MAC Addresses

Another issue with static MAC addresses (and even local accounts) is that they tend to remain indefinitely in the MAC database. Lang after devices have been decommissioned, the MAC address remains. Which leaves a security hole to be exploited.

By using the generated ‘RADIUS Authentications’ reports over a longer time (e.g. 90 days) you can do a cross reference with MAC addresses in the database and recent successful authentications of that MAC address.
There are some caveats though;

  1. you need a session-timeout on the network (either statically defined on the network device) or by RADIUS return attribute, so that devices have to re-authenticate periodically. Otherwise you might not see a valid device in the logging and removed it by mistake.

  2. RADIUS Reporting goes only 30 days back, so you have to combine several (scheduled) reports to achieve a longer time span. There used to be a custom time frame option, but seems to have disappeared in version 2.6

Increase Ubuntu VM Disk Space

I ran into a very familiar problem (for me anyway) on an Ubuntu 18 virtual machine today. It started with, what I thought was, a Cisco ISE issue. Cisco ISE reports that I wanted to write to a repository ended up as empty files (0 bytes). Initial thought was that I ran into an Cisco ISE bug related to repositories, but it turned out that my Ubuntu server had run out of disk space;

Err:2 http://archive.ubuntu.com/ubuntu bionic-updates InRelease
  Error writing to output file - write (28: No space left on device) [IP: 91.189.88.24 80]

A quick df -h revealed that my Ubuntu server had only 4GB (out of the 100GB I assigned in VMWare).

willem@ubuntu:~$ df -h
Filesystem                         Size  Used Avail Use% Mounted on
udev                               967M     0  967M   0% /dev
tmpfs                              200M  1.1M  199M   1% /run
/dev/mapper/ubuntu--vg-ubuntu--lv  3.9G  3.9G    0M 100% /
tmpfs                              997M     0  997M   0% /dev/shm
tmpfs                              5.0M     0  5.0M   0% /run/lock
tmpfs                              997M     0  997M   0% /sys/fs/cgroup
/dev/loop0                          90M   90M     0 100% /snap/core/7713
/dev/loop1                          90M   90M     0 100% /snap/core/7917
/dev/sda2                          976M  222M  688M  25% /boot
tmpfs                              200M     0  200M   0% /run/user/1000
ubuntuvm-disk-size.png

So, now I had to add the unassigned 96GB to the Ubuntu filesystem. Thankfully, askubuntu to the rescue.

root@ubuntu:~# lvm
lvm> lvextend -l +100%FREE /dev/mapper/ubuntu--vg-ubuntu--lv
  Size of logical volume ubuntu-vg/ubuntu-lv changed from 4.00 GiB (1024 extents) to <99.00 GiB (25343 extents).
  Logical volume ubuntu-vg/ubuntu-lv successfully resized.
lvm> exit
  Exiting.
root@ubuntu:~# resize2fs /dev/mapper/ubuntu--vg-ubuntu--lv
resize2fs 1.44.1 (24-Mar-2018)
Filesystem at /dev/mapper/ubuntu--vg-ubuntu--lv is mounted on /; on-line resizing required
old_desc_blocks = 1, new_desc_blocks = 13
The filesystem on /dev/mapper/ubuntu--vg-ubuntu--lv is now 25951232 (4k) blocks long.

root@ubuntu:~# df -h
Filesystem                         Size  Used Avail Use% Mounted on
udev                               967M     0  967M   0% /dev
tmpfs                              200M  1.1M  199M   1% /run
/dev/mapper/ubuntu--vg-ubuntu--lv   98G  3.4G   91G   4% /
tmpfs                              997M     0  997M   0% /dev/shm
tmpfs                              5.0M     0  5.0M   0% /run/lock
tmpfs                              997M     0  997M   0% /sys/fs/cgroup
/dev/loop0                          90M   90M     0 100% /snap/core/7713
/dev/loop1                          90M   90M     0 100% /snap/core/7917
/dev/sda2                          976M  222M  688M  25% /boot
tmpfs                              200M     0  200M   0% /run/user/1000
root@ubuntu:~# 
Posted on October 16, 2019 and filed under Linux, Tips'n Tricks.

Cisco ISE v2.6 and Google ChromeOS

While playing around with the new Cisco Identity Service Engine (ISE) v2.6 (patch2) I stumbled upon a security feature while testing Wireless 802.1x access with an Acer Chromebook (ChromeOS v75.0.3770.144). When connecting to the 802.1x enabled SSID the connection failed, while other devices (Windows 10, Apple iOS and MacOS) connected just fine.

The problem is the client EAP handshake and usually this relates to untrusted server certificates. This happens to me a lot since I use different RADIUS services for my testing SSID’s.
So after clearing the SSID settings (forget) on the Chromebook it should work, but it didn’t.

The logging showed that the EAP handshake failed because the client didn’t offer a suitable cipher to the ISE server.

Turns out that Cisco ISE v2.6 has SHA1 disabled by default, and you need to enable it in:

Administration -> System -> Settings -> Security Settings

With the setting ‘Allow SHA1 Ciphers’, and ‘Allow only TLS_RSA_WITH_AES_128_CBC_SHA’ the Chromebook was able to connect to the 802.1x enabled SSID using old/depricated ciphers.

Now I wonder why the Chromebook still uses SHA1 based ciphers for secure communications, since Google Chrome started to abandon SHA1 as one of the first browsers….

Even installing the ‘Powerwash for added security’ feature in ChromeOS didn’t enable or add stronger ciphers on the Chromebook.

Posted on July 31, 2019 and filed under Tips'n Tricks, Security.

Update Python Netaddr OUI Database

For a small project I needed to validate ~1500 MAC addresses on validity and their vendor Organizational Unique Identifier id (OUI). So a bit of Python scripting was in order.

I used a regular expression for basic MAC address validation, and the netaddr module to check the OUI of the MAC Address. A simple example of the code is shown below

#!/usr/bin/env python3

import netaddr as na
import re

_mac = '88-E9-FE-1F-65-7D'
if re.match('[0-9a-f]{2}([-:]?)[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$', _mac.lower()):
    print(f'{_mac} - {na.EUI(_mac).oui.registration().org}')

Checking this MAC address online gives a normal result.

macvendors.png

Python (or specifically netaddr) not so much, so there some work to be done. The error clearly shows that the OUI for that MAC address is not registered (in netaddr’s local database).

netaddr-error.png

The problem is that the OUI ‘database’ from netaddr is (extremely) out-dated, so recently assigned OUI’s are not available, and result in Python script errors.

Unfortunatelly, the netaddr documentation doesn’t give any hint on how to update this database. Some searching on the local filesystem showed that there is a oui.txt file within the directory structure of netaddr (which in my case can be seen in the error shown above).

The latest oui.txt (~0.5MB larger than the netaddr version) can be downloaded @ IEEE (the organization were hardware vendors can request new OUI’s). The file location is: http://standards-oui.ieee.org/oui.txt.
I downloaded the file and replaced the original netaddr version. Running the code again gave no solution, since I got the same error. So back to the drawing board.

In the same directory as the oui.txt is a file called oui.idx. This file contains the decimal value of the OUI, and an offset. It turns out that the netaddr codeused this idx file to quickly skip to the actual vendor information in the oui.txt file. And since my idx file was based on the old oui.txt the vendor could still not be found.

The idx file cannot be found on the internet. It’s not something IEEE provides. It’s a file generated from the information in the oui.txt file.

Solution: In the netaddr directory where the oui.txt and oui.idx is located is a ieee.py script. Run that script, and it creates a new idx file based on the oui.txt file in that directory (as shown in the following example).

myhost:eui myname$ pwd
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/netaddr/eui
myhost:eui myname$ ls -la
total 12856
drwxr-xr-x   9 myname  admin      288 Jan 26 13:37 .
drwxr-xr-x  11 myname  admin      352 Jan 26 13:37 ..
-rw-r--r--   1 myname  admin    24990 Jan 26 13:37 __init__.py
drwxr-xr-x   4 myname  admin      128 Jan 26 13:37 __pycache__
-rw-r--r--   1 myname  admin    95467 Jan 26 13:37 iab.idx
-rw-r--r--   1 myname  admin  2453271 Jan 26 13:37 iab.txt
-rw-r--r--   1 myname  admin     9500 Jan 26 13:37 ieee.py
-rw-r--r--   1 myname  admin   419098 Jan 26 13:37 oui.idx
-rw-r--r--   1 myname  admin  3566144 Jan 26 13:37 oui.txt

myhost:eui myname$ curl http://standards-oui.ieee.org/oui.txt --output oui.txt
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 4039k  100 4039k    0     0   370k      0  0:00:10  0:00:10 --:--:--  437k

myhost:eui myname$ python3 ieee.py 
myhost:eui myname$ ls -la
total 14336
drwxr-xr-x   9 myname  admin      288 Jan 26 13:37 .
drwxr-xr-x  11 myname  admin      352 Jan 26 13:37 ..
-rw-r--r--   1 myname  admin    24990 Jan 26 13:37 __init__.py
drwxr-xr-x   4 myname  admin      128 Jan 26 13:37 __pycache__
-rw-r--r--   1 myname  admin    95467 May 10 12:14 iab.idx
-rw-r--r--   1 myname  admin  2453271 Jan 26 13:37 iab.txt
-rw-r--r--   1 myname  admin     9500 Jan 26 13:37 ieee.py
-rw-r--r--   1 myname  admin   485973 May 10 12:14 oui.idx
-rw-r--r--   1 myname  admin  4136058 May 10 12:14 oui.txt
myhost:eui myname$ 

After that the output of my script was the following:

/usr/local/bin/python3.7 /Volumes/Python_Scripts/test.py
88-E9-FE-1F-65-7D - Apple, Inc.

Process finished with exit code 0
Posted on May 10, 2019 and filed under Programming, Annoying.

Install Cisco Identity Services Engine v2.4 From USB

The Cisco Identity Service Engine (ISE) is a NAC solution used for accessing the network. The version (while writing this post) is v2.4.

For a new implementation of Cisco ISE I had to re-image 2 SNS-3595 appliances with the latest software. This can be done in various ways;

  1. Write the ISE iso to USB and boot / install from the USB flash-drive

  2. Use the JAVA/HTML5 KVM option through the CICM interface

  3. Hookup a USB DVD player with a dual-layer DVD containing the appropriate ISO file

The preferred option is the USB flash-drive, since it’s the fastest, but only if you are able to boot from USB….. After trying several USB flash drives with the tool recommended in the Cisco manual I gave up. No way that the Boot menu saw the USB flash drive. So after wasting several hours doing that I opted for the KVM install method.