Ubuntu 18.04LTS: Auto-Locking When YubiKey is Removed

It took me a while to piece this together, so I figured that I would write a handy “how-to”, in order to prevent someone else from losing the man-hours that it took to piecemeal this together.

The first thing that we’ll need to do is to create the monitoring rule. This rule is specifically used to key-off of the event that is trigged when the YubiKey is removed; however, we’ll need some information for that before we can write the rule.

You can use the below command to obtain the device-specific information:

udevadm monitor --environment --udev

With the command running, remove the YubiKey device from the system. I would suggest copying all of the properties that you see in the output to a text file. We’ll use some of these to define your rule.

Right. So, let’s create the rule. Run this command to start the text editor:

sudo nano /etc/udev/rules.d/85-yubikey.rules

In the text editor, you’ll add the rule. Below is mine, for an example:

# Yubikey Udev Rule: running a bash script in case your Yubikey is removed 
ACTION=="remove", ENV{ID_VENDOR_ID}=="1050", ENV{ID_MODEL_ID}=="0401", RUN+="/usr/local/bin/gnome-screensaver-lock"

The most specific piece that you’ll copy, verbatum, is the overloaded “Run” section.

Press Ctrl+X in the text editor window, when you’re done. Press your key for confirmation (‘Y’ in English, ‘J’ in Swedish, etc.). Then press ‘Enter’ (a.k.a.: carriage return) to confirm the path we specified when we started the text editor.

You should now be back at the terminal.

Now that the rule is in place, we need to define the action. We’ve already declared where it will go to fetch the action definition (see the overloaded “Run” declaration above) and now we need to create that file.

Run this command to start the text editor:

sudo nano /usr/local/bin/gnome-screensaver-lock

Add the following code in the editor:

# Double checking if the Yubikey is actually removed
if [ -z "$(lsusb | grep Yubico)" ]
        logger "YubiKey Removed or Changed"
        sessionids=`/bin/loginctl list-sessions | grep <userAccount> | awk '{print $1}'`
        for id in $sessionids
                        logger "Locking session id:" $id
                        /bin/loginctl lock-session $id

(Be sure to change <userAccount> to your actual user account.)

Again, press Ctrl+X to start exiting the text editor. Press the confirmation key. Press the enter key to confirm the path.

The script that we just made must be made an executable for udev to be able to leverage it:

sudo chmod +x /usr/local/bin/gnome-screensaver-lock

Now that we have the rule and the actions defined, we need to tell the udevd service to reload the rules, so it’ll work. Run the following in the terminal:

sudo udevadm control --reload-rules
sudo service udev reload

Now, we should be able to remove the YubiKey device and Ubuntu should auto-lock.

If it doesn’t, you can try to monitor the udev service:

sudo service udev status
 systemd-udevd.service - udev Kernel Device Manager
   Loaded: loaded (/lib/systemd/system/systemd-udevd.service; static; vendor preset: enabled)
   Active: active (running) since Mon 2019-02-25 23:11:28 CET; 4 days ago
     Docs: man:systemd-udevd.service(8)
 Main PID: 482 (systemd-udevd)
   Status: "Processing with 24 children at max"
    Tasks: 1
   CGroup: /system.slice/systemd-udevd.service
           └─482 /lib/systemd/systemd-udevd

mar 02 22:39:58 Tradgardsforeningen mtp-probe[15598]: checking bus 1, device 30: "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-3"
mar 02 22:39:58 Tradgardsforeningen mtp-probe[15598]: bus: 1, device: 30 was not an MTP device
mar 02 22:43:17 Tradgardsforeningen systemd-udevd[15742]: Process '/usr/local/bin/gnome-screensaver-lock' failed with exit code 2.
mar 02 22:43:17 Tradgardsforeningen systemd-udevd[15749]: Process '/usr/local/bin/gnome-screensaver-lock' failed with exit code 2.
mar 02 22:43:20 Tradgardsforeningen mtp-probe[15759]: checking bus 1, device 31: "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-3"
mar 02 22:43:20 Tradgardsforeningen mtp-probe[15759]: bus: 1, device: 31 was not an MTP device
mar 02 22:48:00 Tradgardsforeningen mtp-probe[15901]: checking bus 1, device 32: "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-3"
mar 02 22:48:00 Tradgardsforeningen mtp-probe[15901]: bus: 1, device: 32 was not an MTP device
mar 02 22:49:26 Tradgardsforeningen mtp-probe[16019]: checking bus 1, device 33: "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-3"
mar 02 22:49:26 Tradgardsforeningen mtp-probe[16019]: bus: 1, device: 33 was not an MTP device

The above snippet is from when the executing script looked quite different and, thus, it was failing to execute. Keep in mind that you may need to define different parameters in your monitoring rule, for example, if your device has a different vendor or model id and the removal isn’t creating the logging event:

mar 02 23:00:15 Tradgardsforeningen root[16941]: YubiKey Removed or Changed

If you can see the event being logged, then verify that you specified the correct username in the script.

If all else fails, there’s Ask Ubuntu. 🙂

Thanks for coming to this TEDTalk and I hope that it helps prevent someone losing the hours that I lost. 🙂

Beskrivning Om Uppdaterar

SV: Kund vi talar om “update descriptions” för en minut? Jag har sett att updates för Windows inte hade en bra beskrivning under lång tid. Jad hade söker för den beskrivning att förstår vad var fel och varför det var behöver.

Men nu… Väl… Se för din själva.

apt-listchanges: Förändringslogg

signal-desktop (1.22.0) whatever; urgency=medium

  * Package created with FPM.

 -- Open Whisper Systems <[email protected]>  Wed, 20 Feb 2019 18:25:24 -0800

Varför kunde inte dom skriver något? Och varför behöver jag den uppdater? Jag vet jag kunde besöker för den beskrivning, om den app är open-source (som Signal), men varför ska jag det? Och jag ska inte vill gör det för varje app…

Pull Request


I en värld, där implicit förtroende var förlorade (tack dåliga regeringar), jag kan inte förstår varför någon kunde inte skriver något som så enkelt som, “Fixed max-width calculation“.

Detta var den slut om min rant. Tack för att kommer till min TEDTalk.

EN: Can we talk about “update descriptions” for a minute? I have seen updates for Windows didn’t have a good description for a long time. I had to look for a description to understand what was wrong (broken) and why it was needed.

But now… Well… See for yourselves.

apt-listchanges: Förändringslogg

signal-desktop (1.22.0) whatever; urgency=medium

  * Package created with FPM.

 -- Open Whisper Systems <[email protected]>  Wed, 20 Feb 2019 18:25:24 -0800

Why couldn’t they write anything? And why do I need the update? I know I could look for a description, if the application is open-source (like Signal), but why should I? And I’m not going to want to do it for every app…

Pull Request


In a world, where implicit trust was lost (thanks bad governments), I cannot understand why anyone couldn’t write something as simple as, “Fixed max-width calculation“.

That’s the end of my rant. Tanks for coming to my TEDTalk.

Glad Och Sorgligt

SV: Jag tror att jag ska har en nytt jobbet snart. Jag kan inte säga med vem det är men jag är lycklig att jag kunde hittar det. Väl… Jag säga, “jag hittade det,” men min vän visste om det jobbet och han ville att jag kunde kommer och arbeta med honom.

Jag hade skrivit en program medan jag var vänta. Den program har mer än 3,000 rader med kod – allt att jag skrivit. Det var svårt att skriver och den program är inte färdiga; så jag har mycket mer att jag har skriver… Den program har en problem med SQL Server och jag vet inte vad jag kunde göra att åtgärda det. Talar du SQL Server? 🙂

Jag måste går till Sverige snart, att besöka med min advokat och därefter jag måste går till USA att se min vän, vem har cancer. Hon har varit min vän för mer än tjugo år och jag har älskade henne hela den tiden. Jag tänka att jag har känt henne sedan jag hade tretton år? Jag är sorgligt (mer sorgligt än jag vill någon att vet) att jag kan göra inte ingenting om det. Men det är liv också: glad och sorgligt.

In other news… Jag hittade min första svenska film som jag gillar inte. Gräns. I borjän det var okej men jag gillar inte där det gick.

Okej… Jag är trött. Jag tänkta att jag skulle har mer att skriver om men jag tänkte fel. Eller kanske jag vill inte att skriver mer… Vilken. Både är sanningen. Kvantmekaniska påstår. Är jag katten? Kanske…
EN: I think that I’m going to have a new job, soon. I can’t say who its with but I am happy/lucky that I could find it. Well… I say, “I found it,” but my friend knew of the job and he wanted that I could come and work with him.

I have written a program while I was waiting (looking for a job). The program has more than 3,000 lines of code – all written by me. It was difficult to write and it isn’t finished; so, I have more that I have write… The program (itself) has a problem with SQL Server and I don’t know what I could do to fix it. Do you speak SQL (Server)? 🙂

I have to go to Sweden, soon, to visit with my lawyer and, afterwards, I have to go to the USA to see my friend, who has cancer. She has been my friend for more than twenty years and I have loved her that whole time. I think that I have known her since I was 13? I’m sad (more sad than I want anyone to know) that I can do nothing about it. But that is life: happiness and sadness.

In other news… I found my first Swedish movie that I didn’t like. Borders. In the beginngin it was o.k. but I didn’t like hwere it went.

O.k…. I’m tired. I thought that I would have more to write about but I was wrong. Or maybe I don’t want to write more… Whichever. Both are the truth. Quantum states. Am I the cat? Maybe…


I hardly ever post photos, anymore (unless it’s on Instagram), so here’s the test pattern from Sveriges Television. Note the 2.0 and 5.1 surround-sound test on the left-hand side.


Vi (Miller Family, Cara, och jag) är i Cork just nu. En semester på helgen, jag tänka det är kallade i engelska (U.K. English).

Jag kunde inte söva igår kväll, igen. Jag tänka att det är därför jag har mycket bekymmer om min visa.

Vad menar jag? Tja, jag har att ansök en nytt visa i Irland på ende av Juli och jag har har en jobb med pengar minst två eller tre månader innan jag kunde gör det.

Nej. Jag skulle inte att oroa mig om det just nu. Jag vet det.

Fredagsmysa (theme song) är nu och jag vill har en bra natt (jag hoppas). Jag skulle tittar på en bra film och har mysa.

Jag tänka att jag ska gjör denna just nu.

(Förlåt att det post är inte så bra. Jag tänka att, med mer söva, det kunde bli mycket bättre. Kanske imorgon? Vi ska se….)

Min första post i Svenska. Och, just nu, varför inte?

Första, min svenska är inte så bra och jag vet att. Jag vet att eftersom svenska är inte min förstaspråk. Jag hoppas det är okej och om du är svensk och läser denna post nu, du kan förstår att jag endaste öva min svenska. Om du vill hjälpa mig med, din hjälp kan blir trevlig för att lara mig svenska. =]

Jag vet inte vad jag skulle att skriver om. Ljus? Musik? Ljud?

Skulle vi talar om vad jag läste? Kirunasvenskarna. Jag visste inte om dem innan och vi lärde oss inte om det i skola. Vi lärde oss inte om mycet utanför. För att vara rättvis, vi lärde inte mycket om utomlands.

Jag tänka att jag förstår inte allt att det var med dem men jag förstår att de lämnade för Sovjetunionen. Jag kan förstår värfor: De trodde att de kunde har en bättre liv. Jag tänka att det var inte rätt men jag kan förtår den varför.

Jag kan inte söver mer än fem timmer, nyligen. Jag söver inte i går kväll och kaffe är min vän just nu. Det är en mycket lång historia och ska tar mer tid att skriver än jag har just nu. Jag hoppas att jag kan hålla mig vaken til 2000. Vi kommer att se, ja?

Jag vet inte vad mer jag skulle skriver om. Jag är mycket trött. Jag är ledsen.

Så… Denna är min första post i svenska. Jag hoppas att skriver (och söver) mer senare.

Mass-Configuring OVPN in NetworkManager (on Ubuntu 18.04LTS)

So, I had a pretty large problem to figure out: How to configure 170+ different OVPN (Swedish/English) configurations in NetworkManager, without having to enter my username and password over 170 friggin’, fraggin’ times.

(NOTE: If you’re highly security conscious, then this probably isn’t going to be very palatable for you. You have been warned.)

I use [REDACTED] VPN service and they offer a zip file that you can download with containing multiple OVPN configuration files; a unique file for each server that you can use. After filtering the list down to my targets, I had a resultant list to import into Network Manager.

In order to have NetworkManager leverage ovpn, though, you need to install two packages, first.

sudo apt-get install network-manager-openvpn network-manager-openvpn-gnome

Bes sure to restart NetworkManager, afterwards, so you don’t end-up in a dissonant state.

sudo service network-manager restart

So, how do we do that? Well, it’s not as complicated as one my think and you needn’t go crafting anyting in Python or the like to do so.

for i in <location of your ovpn files>; do sudo nmcli connection import type openvpn file "$i"; done

Now that we have the files imported, we need to modify them. To do this, the easiest way is to use Python to read in the files and write our changes. Modify the script below to include your username and password.

#!/usr/bin/env python
"""Changes the exported OVPN configurations in NetworkManager to contain the username and password and autoconnect.

When mass-importing OVPN configuration files, it's necessary to overcome the hurdle of the prompt for passwords. This
script looks for the exported configuration files in NetworkManager. It writes the password configuration and the
username/password to the file. You will need to restart NetworkManager for the changes to be imported; however, it's
easier/better just to bounce the machine. (sudo init 6)

    sudo python3 ModifyOvpnConfigurations.py

__author__ = "felsokning"
__copyright__ = "Copyright 2019"
__license__ = "MIT"

import os
import re

source_directory = "/etc/NetworkManager/system-connections"
ovpn_files = os.listdir(source_directory)
i = 0
for ovpn in ovpn_files:
    opened_file = open(source_directory + "/" + ovpn, "r+")
    file_content = opened_file.read()
    if file_content.__contains__("mssfix=1450\n"):
        output = re.sub(r"mssfix=1450", r"mssfix=1450\npassword-flags=0", file_content)
        # TODO: Change '*' to be your username
        output2 = re.sub(r"tunnel-mtu=1500", "tunnel-mtu=1500\nusername=*", output)
        output3 = re.sub(r"service-type=org.freedesktop.NetworkManager.openvpn", r"service-type=org."
                                                                                 # TODO: Change '*' to your VPN password
        output4 = re.sub(r"password-flags=1", r"", output3)

        # Indents are important, m'kay? Without them, you do things like overwrite your wireless config files.
        # Take it from me: You do NOT want to do that.

Now that the files are modified, we need to restart NetworkManager to allow the configurations to be re-read on the connection’s instantiation.

sudo service network-manager restart

(Personally, bouncing the machine was more of a formidable option, here, but that’s because I messed-up the initial script – due to indenting – and wiped all of my configuration files; thus, the warning in the script.)

Now that this has been configured, I needed a way to randomly choose which VPN connection to use, so as to not always land on a static connection. To do this, I used Python again and randomised the choice of which VPN server to connect to. (You’ll note that I’m using a pretty large seed and that’s because the default random.random() method isn’t random in a secure manner [read: it’s predictable].)

#!/usr/bin/env python
"""Randomly connections to a random VPN profile (if any are found).

Uses NetworkManager (https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.html#) to
enumerate the devices and connections. First, we enumerate the wireless devices to ensure that we have one. Next, we
enumerate the VPN connections and put them into a list. After that, we randomly select one of the VPN connections to
connect to. Once we've accomplished this, we disconnect the current VPN connection (if one is found) and connect to
the randomly chosen VPN connection.


    python NetworkManager_VPN.py

__author__ = "felsokning"
__copyright__ = "Copyright 2019"
__license__ = "MIT"

import os
import random
import time
# Externals
import NetworkManager

# Find all of the VPN connections on the machine.
vpns = list()
current_vpn = None
wireless_device = None
connections = NetworkManager.Settings.ListConnections()
for c in connections:
    if "vpn" in c.GetSettings()['connection']['type']:
        path = c.object_path

# If there are no VPN connections, there's no point in proceeding.
if vpns.__len__() > 0:
    # We find the Wireless Network Interface.
    # If you're running some kind of weird, three wireless network cards situation, then...
    # Change this code to work in your use-case scenario.
    devices = NetworkManager.Device.all()
    for d in devices:
        if "wifi" in d.Driver:
            wireless_device = d

    # Validate that we found a wireless network interface
    if wireless_device is not None:
        # Get the currently active VPN connection.
        # If you're running some kind of weird, three active VPNs scenario, then...
        # Change this code to work in your use-case.
        active = NetworkManager.NetworkManager.ActiveConnections
        for a in active:
            if "vpn" in a.Type:
                current_vpn = a

        # Choose a random one to connect to. We use the far more secure random method, with a larger seed,
        # to try and prevent the random generation from being a predictable pattern (well, to try to make
        # it far less predictable with our sample, at least).
        rand = random.SystemRandom(os.urandom(99999999))
        random_int = rand.randint(0, (vpns.__len__() - 1))
        random_vpn = vpns.__getitem__(random_int)
        new_connection = NetworkManager.Connection(random_vpn)

        # Validate that we have a current VPN connection to disconnect from before we do.
        if current_vpn is not None:

            # Disconnect the old & busted.

            # To prevent collision in NetworkManager, we allow background clean-up before reconnecting.

        # Connect the new hotness.
        print("Connecting to: {}".format(random_vpn))
        NetworkManager.NetworkManager.ActivateConnection(new_connection, wireless_device, "/")

    # No wireless interfaces were found, so let's abort.
        raise Exception("No wireless interfaces were found.")

# No VPN connections were found, so let's abort.
    raise Exception("The hull has been breached and the science is leaking out! "
                    "(We didn't find any valid VPN connections on this machine via NetworkManager.)")

That should just about do it. …but WAIT! That’s not all! If you act now…

I’ve also written a script to remove all of the OVPN configurations from NetworkManager, in case you made a mistake somewhere (I know that I did and this came in pretty useful.)

#!/usr/bin/env python
"""Removes all VPN profiles found in NetworkManager.

Uses NetworkManager (https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.html#) to
enumerate the connections that are specifically VPN connections. Then, we delete them, with righteous retribution and


    python3 RemoveVPNs.py

__author__ = "felsokning"
__copyright__ = "Copyright 2019"
__license__ = "MIT"

import NetworkManager

# Find all of the VPN connections on the machine.
vpn_list = list()
connections = NetworkManager.Settings.ListConnections()
for c in connections:
    if "vpn" in c.GetSettings()['connection']['type']:

# We make sure we'e not spinning our wheels and/or calling delete on null.
if len(vpn_list) > 0:
    for v in vpn_list:
        print("Deleting: {}".format(v.object_path))

Now, you should have of the tools you need to mass-configure OVPN on your *nix (debian-based, probably) machine. 🙂

Happy coding!

Lessons in X-Language Implementations of the Same Action

It is, by no small irony, that it’s been some time that I’ve written a post. A lot’s been going on – including, but not limited to, travelling betwixt Ireland and Sweden. As a result of that, I haven’t – quite – had the free time nor desire to really sit down and dedicate time solely to creating a post but, after my recent ventures in programming for the same resultant set in multiple languages, I have a bit more of a reason and desire to make one.

I should preface that the idea came from multiple facets:

Sweden organises calendar years by weeks, which correlates with the ISO standard. You can see this evidenced by restaurant menus in Sweden.

Someone made a website that you can refer to, to look at what the week number is.

My friend/previous manager in Sweden suggested the idea, since I was already working on creating a variation of the week number site in Docker/Python.

The Idea

Since week numbers are a prominent feature, it would be worthwhile to write reusable code, which could be imported, to save others the time of having to write it – themselves.


The first problem was that the implementation, to achieve the same desired net-effect result, would – obviously – be different between languages. So, for example, C# has the premise of extension methods but Rust requires Trait and Implementation to extend a given type.

To do this, it required a lot of research, trials, and much errors but, first, the pseudo-code needed to be defined so that I had a blueprint to use across the languages.

if($obj -eq date from datetime){obtain week number from the object via method}

With the pseudo-code defined, it was time for the implementation via code. Most of the development occurred on an Ubuntu 18.04LTS machine – save for the C#/C++ code, which occurred on a Windows 10 machine.

I’m only going to show two of the four implementations, here, so as to save on space.


/// <summary>
///     Extends the System.DateTime class to include a method to return the week number.
/// </summary>
/// <param name="dateTime">The System.DateTime object to process.</param>
/// <returns>An integer signifying the current week number of the year.</returns>
public static int Veckan(this DateTime dateTime)
    // Jag behöver att säga tack till Peter Saverman för denna idé.
    Calendar calendar = CultureInfo.InvariantCulture.Calendar;
    DayOfWeek dayOfWeek = calendar.GetDayOfWeek(dateTime);
    if (dayOfWeek >= DayOfWeek.Monday && dayOfWeek <= DayOfWeek.Wednesday)
        dateTime = dateTime.AddDays(3);

    // Vi behöver att använda måndag för den första dagen på veckan
    // Se: https://en.wikipedia.org/wiki/ISO_week_date#Calculating_the_week_number_of_a_given_date
    return calendar.GetWeekOfYear(dateTime, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);


from datetime import date

# Vi har att skapa en ny klass eftersom python har inte "extensions methods"
class SwedishDate(date):
    # Vi skulle heter det på svenska, nej?
    def veckan(self):
        return self.isocalendar()[1]


So, the lessons learned weren’t very numerous but I suppose that the most prevalent is that documentation is quite worthwhile but it can oft be extremely difficult to find. Even if you find the documentation, it isn’t going to be as implicitly straightforward as one might think. For example, defining the return-type in Rust is vastly different than any other language that I’ve ever programmed in.

    fn veckan(&self) -> u32
        let now = self.date().iso_week().week();
        return now;

As you can see, the return-type (u32) is strongly-typed and appears after the initial function (read: method) definition and is always on the right of an arrow.

Also, while languages might seem different, the conceps behind their implementations have the same underlying concepts. Take the concept of ‘this‘ in C# and of ‘self‘ in Python. While, syntatically, they’re different in definition and use, their end-goal is effectively the same thing: Effect a specific instance of the type, which – at runtime – is the instance in question (well, any instance, in scope really but I’m cluttering this with abstraction).


Programming the same action across multiple languages causes us to learn more about those languages (it was my second program in Rust) and, while it can be a pain, the net result could be that it’s more of a benefit to the overall open-source community.

Outlook.com: Leveraging O365’s Geo-DNS for Outlook Accounts

If you’ve ever used Office 365, then you’ll be aware of how the Geo-DNS feature and protocol proxy can benefit users, when connecting to their mailboxes from different regions than where the tenant resides. I don’t want to rehash what’s already been written, so if you’re not familiar with Geo-DNS, I suggest perusing this blog post for more information on it.

O.k., so, what matters to this story is that my account in Outlook.com was once a [email protected] account that got split when Microsoft merged [email protected] into Office 365. I’ve lost the Office 365 account but the Live account stuck around – and I’m glad that it did because all of my purchases were associated with it.

So, that being said, the account (and, thus, the mailbox) has been around for a hot minute. I don’t know if this will work with new Outlook.com accounts but I can’t fathom any reason why it shouldn’t.

First, the problem.

The issue with Outlook.com is pretty straightforward. A DNS query from any server outside of North America will provide an group of IP addresses, like this:

:~$ dig a outlook.com

; <<>> DiG 9.11.3-1ubuntu1.3-Ubuntu <<>> a outlook.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1787
;; flags: qr rd ra; QUERY: 1, ANSWER: 8, AUTHORITY: 0, ADDITIONAL: 1

; EDNS: version: 0, flags:; udp: 65494
;outlook.com.			IN	A

outlook.com.		300	IN	A
outlook.com.		300	IN	A
outlook.com.		300	IN	A
outlook.com.		300	IN	A
outlook.com.		300	IN	A
outlook.com.		300	IN	A
outlook.com.		300	IN	A
outlook.com.		300	IN	A

;; Query time: 218 msec
;; WHEN: Thu Dec 27 18:15:17 CET 2018
;; MSG SIZE  rcvd: 168

If we trace the troute to the first IP address, we can see that we traverse from Stockholm to Amsterdam to London to New York City to Washington to Chicago to… (first two hops removed for privacy):

:~$ traceroute --resolve-hostnames
traceroute to (, 64 hops max
  1 (_gateway)  87,450ms  58,492ms  55,662ms 
  2 (  54,839ms  64,758ms  59,640ms 
  3 (as8075-10g-sk1.sthix.net)  52,795ms  53,058ms  55,475ms 
  4 (ae1-0.sto-96cbe-1b.ntwk.msn.net)  53,841ms  53,710ms  50,792ms 
  5 (be-8-0.ibr01.ams.ntwk.msn.net)  190,862ms  188,583ms  290,228ms 
  6 (be-7-0.ibr01.amb.ntwk.msn.net)  186,894ms  189,178ms  364,440ms 
  7 (be-5-0.ibr01.lts.ntwk.msn.net)  184,531ms  188,188ms  322,957ms 
  8 (be-2-0.ibr01.lon30.ntwk.msn.net)  237,432ms  186,584ms  367,246ms 
  9 (be-11-0.ibr01.nyc30.ntwk.msn.net)  187,837ms  359,796ms  188,780ms 
 10 (be-7-0.ibr01.was02.ntwk.msn.net)  186,431ms  372,950ms  183,982ms 
 11 (be-3-0.ibr01.ch2.ntwk.msn.net)  185,136ms  372,724ms  185,883ms 
 12 (be-6-0.ibr01.cnr02.dsm05.ntwk.msn.net)  188,245ms  187,203ms  186,946ms 
 13 (ae121-0.icr03.dsm05.ntwk.msn.net)  187,622ms  187,722ms  188,690ms

All of these hops are wholly unnecessary. After all, if I look at a message header from a mail I received, I can see that my mailbox is in Helsinki (and, even though it’s an Outlook.com account, serviced in the same forests as Office 365):


This, of course, also meant that I was landing on a Cafe in North America, being protocol proxied from North America to Helsinki, and then the response would traverse back the reverse path to me. As you can tell from the latency, it wasn’t a very fast response.

What was the resolution?

Since I’m using EWS in Evolution on Ubuntu 180.04LTS, I simply changed the server name from “outlook.com” to “outlook.office365.com”. This means that I leverage Geo-DNS and this will land my requests on front-end server within Europe, which would then protocol-proxy the request to my mailbox hosted (currently) in Helsinki.

I can’t promise that this will work for you but it’s definitely worth a shot; especially, to avoid network degredation, by not having your traffic routed through North America.

It’s not much, I’m aware, but it’s a small piece of help that I hope might benefit someone, some day.

Happy Holidays!

Wait-Chain Traversal: Or, How We Can Use PowerShell to JIT C# to Load an Unmanaged Assembly (C++), InterOping With Windows APIs, Returning that Data Back to PowerShell

So, as the long-winded title infers, today I’ll be covering something that I wrote a long time ago and have recently re-written (albeit, probably badly) for you to use and/or learn from.

In this case, we’re using a PowerShell script, which JITs C# code, the C# code calls into an unmanaged DLL (C++), and that calls into an Windows API. Once the data has been obtained from the Windows API, we pass the data back from the unmanaged assembly to the managed code (via Marshal) and then return that back to the PowerShell instance to be displayed to the user.

Before we dive into the what we’re doing, we should cover some key concepts. The first is JIT’ing. JIT stands for “Just-In-Time” (Compilation) and the name is slightly a misnomer but we’ll cover that in a second. So, in JIT, what happens is that the run time precompiles the code before it’s ran. This is important because a key-concept in exception handling is the runtime’s seek operation to find a handler for an exception that is thrown. You’ll often see this as a FirstChanceException in a dump file. In PowerShell, we have the added ability to leverage the JIT compilation by passing source code as a type into the App’s Domain. It’s important to distinguish that once the App Domain has been disposed of, the type specified is lost and has to be re-instantiated again.

So, what – exactly – is this code going to be doing? Well, since Windows Vista, the Windows Operating System exposes the Wait Chain Traversal API. You can see a demonstration of this API in Task Manager: Go to the Details tab, right click on a process and click “Analyze Wait Chain”.

Since Windows Server 2016 Core doesn’t include a desktop or any GUI interfaces, a more robust way was needed to obtain the same information in production, to determine if the reason an application wasn’t responding or performing work was because the threads were blocked.

When you run the code, you can tell if this is the case or not by something like the following:

12972   [7464:12972:blocked]->[ThreadWait]->[7464:12968:blocked]->[End]

Where the first thread is blocked by a thread wait on the the second thread, which is also (itself) blocked.

So, first things first, the PowerShell code. Take a peek here to see that. Note that the Source code is contained with a specific character-delimited string @”<code>”@. After that we add a Type, pointing it to the source code we’ve defined and referencing the assemblies that we’ll need for this type to work. Worthy of noting is that when we add this type, it is exposed in PowerShell the same way any normal .NET type is, via the []:: convention.

Note that in the C# source we import the unmanaged DLL and reference the exposed method. In the body of the code, we also construct an IntPtr to reference for the return. So, now, we get to Marshalling.

An IntPtr is, quite literally, a pointer or handle to an object. A pointer is a reference to memory where an object exists and the object is typically delimited by characters to signify the termination of it (e.g.: the end of a string is null-terminated). A handle is roughly the same premise but the handle abstracts memory management from the caller. So, at 200 ticks, the handle could point to address 0x000001 and at 369 ticks, it could point to 0x34778.

Alright, so why this matters is because when we pass from unmanaged code back to managed code, there’s nothing that implicitly tells the managed code where to find the object in native memory; so, we have to pass a pointer to the object back to managed (I believe managed creates it’s own copy and creates an address for that object) and, using that, we can then try to convert the passed object from a native string into a managed string (via Marshalling).

What about this unmanaged code I keep hearing about? Oh, well… You can find that here. Don’t forget to add the headers referenced in stdafx.h, or your compiler will cry bloody murder.

So, how this works is: The script is called via PowerShell. After some magic to verify that we weren’t given junk data, then PowerShell JIT’s the C# code and performs the runtime operations. The compiler loads the unmanaged DLL into memory. The C# code then calls into the unmanaged DLL via the exposed method (declspec/dllexport/cdecl). The unmanaged code performs it’s work and returns the string back to the caller – unaware that the caller is managed code. The managed code creates an IntPtr to reference the return and then Marshal is called to convert the native string into a managed string. This is then returned back to the user. In the case of multiple instances of a process, the managed string is added to an array and that array is returned.

While it may not seem like much and seem like overglorified complication just to check for threads on wait chaings, it was code that was written to be used in production where we had no desktop environments and we had to determine if this was the case.

I hope that someone gets some kind of use out of it. 🙂

Until next time.

En promenad på Sondag

Was a late night, last night, and that makes for a late to rise and slow moving, lazy Sunday morning.

I haven’t a way to describe the why and to preserve the anonymity of those involved, I won’t go into great detail, but I face today with a sundry of emotions.

On the positive side of things, my bestie and my roommate (and fam) are all on the same flight back to Dublin from Seattle. They’re still in the air (it isn’t a short flight, considering it’s direct from Seattle to Dublin, to be sure) but I hope to hear from them, soon, that they’re all safe and sound back in the land of Ire.

My roommate got a job working with my bestie; so, it’s funny how happenstances collide to conspire to make good things happen. Sadly, I didn’t impress one of the managers during my own interview gauntlet with said company, so I won’t be working there with them. As the French say, c’est la vie.

Luckily, the clouds stayed away today, so it’s a bright and sunny day.

So, having thoroughly explored Linköping and Norrköping, I hopped on the commuter train and went to Motala. It’s about the size of the largest city near where I grew up, so I figured it was worth a visit.

I’d been to Linghem, before, (which is also on the way) when I had the bout with abscess, and from what I saw, there wasn’t much to it.

So, Motala was the only one left.

Did I mention I like the Swedish countryside? It’s not as good as the English countryside, to be sure, but it has its own charms.

And then: A wild ladybug appeared.

No idea where it got off to, though.

My initial impression of Motala is that I like it. I’m not a fan of Sweden Mobile putting me on the Edge network, though, but what is one to do, yeah?

Everything was closed because it was Sunday. Sure, the Pressbyrån and the Subway restaurant were open but everything else was closed. It was kind of like how you’d imagine it being if some cataclysmic event happened. Remember the stand? Yeah, kind of like that.

So, hoped back on the train towards Norrköping and discovered I didn’t have enough to get back. Enter the Östgötatrafiken app to save the day. A 24-hour ticket? 125SEK (about €12.50).

Well, I think that will be it, for now. A lot on my mind and my heart, plus, I got this other thing I’m trying to get sorted by Monday. Le sigh.

Thanks for stopping by, dear reader.

As Jim Carey’s character says in Bruce Almighty, “And that’s the way the cookie crumbles.”