Feuerfest

Just the private blog of a Linux sysadmin

Test-NetConnection: A useful PowerShell function for basic network troubleshooting

Photo by Pixabay: https://www.pexels.com/photo/white-switch-hub-turned-on-159304/

In corporate networks you often encounter technologies likes proxies, SSL Man-in-the-middle (MITM) appliances (to scan HTTPS traffic) and NAT constructs. All can make it hard and cumbersome to troubleshoot certain problems. For example the common: "Why can I successfully connect to this server/service, while my colleague can't?"

This question is usually accompanied by a lack of useful troubleshooting tools like telnet, netcat, nmap and tcpdump/Wireshark. As they are deemed dangerous hacker tools. Luckily there is PowerShell and as I just learned the Test-NetConnection function, which allows us to troubleshoot using basic TCP-Connections - with this knowledge we can at least rule out or identify certain issues.

PS C:\Users\user> Test-NetConnection -ComputerName 192.168.0.1 -Port 443

ComputerName     : 192.168.0.1
RemoteAddress    : 192.168.0.1
RemotePort       : 443
InterfaceAlias   : Ethernet
SourceAddress    : 192.168.0.2
TcpTestSucceeded : True

Or if you prefer it a bit shorter, there is the tnc alias and the -ComputerName argument can be omitted too.

PS C:\Users\user> tnc 192.168.0.1 -Port 443

ComputerName     : 192.168.0.1
RemoteAddress    : 192.168.0.1
RemotePort       : 443
InterfaceAlias   : Ethernet
SourceAddress    : 192.168.0.2
TcpTestSucceeded : True

It's a bit annoying that you have to use the -Port argument. The common notations like IP:Port or IP Port don't work as expected. The reason is that there is a switch-statement in the function which sets the port based on four pre-defined keywords. Sadly not even HTTPS or SSH are in there.

PS C:\Users\user> (Get-Command Test-NetConnection).Definition
[...]
                switch ($CommonTCPPort)
                {
                ""      {$Return.RemotePort = $Port}
                "HTTP"  {$Return.RemotePort = 80}
                "RDP"   {$Return.RemotePort = 3389}
                "SMB"   {$Return.RemotePort = 445}
                "WINRM" {$Return.RemotePort = 5985}
                }
[...]

I don't know if a lookup based on the C:\Windows\System32\drivers\etc\services file is feasible due to Windows file rights, security, etc. But that certainly would be an improvement. Or add some logic like "If the second argument is an integer, use that as the port number".

Anyway, I now have an easy and convenient way of checking TCP-Connections and that is all I need.

Comments

Development of a custom Telegram notification mechanism for new Isso blog comments

Photo by Ehtiram Mammadov: https://www.pexels.com/photo/wooden-door-between-drawers-on-walls-23322329/

After integrating Isso into my Bludit blog, I am slowly starting to receive comments from my dear readers. As Bludit and Isso are separate, there is no easily visible notification of new comments that need to be approved.

As this is a fairly low traffic blog and I'm not constantly checking Isso manually, this has resulted in a comment being stuck in the moderation queue for 7 days. Only approved after the person contacted me directly to point this out.

Problem identified and the solution that immediately came to mind was the following:

  1. Write a script that will be executed every n minutes by a Systemd timer
  2. This script retrieves the number of Isso comments, pending approval, from the sqlite3 database file
  3. If the number is not zero, send a message via Telegram

This should be a feasible solution as long as currently I receive a somewhat low-amount of comments.

Database internals

Isso stores the comments in a sqlite3 database so our first task is to identify the structure (tables, columns) which store the data we need. With .table we get the tables and with .schema comments we get the SQL-Statement which was used to create the corresponding table.

However using PRAGMA table_info(comments); we get a cleaner list of all columns and the associated datatype. https://www.sqlite.org/pragma.html#toc lists all Pragmas in SQLite.

root@admin /opt/isso/db # cp comments.db testcomments.db

root@admin /opt/isso/db # sqlite3 testcomments.db
SQLite version 3.34.1 2021-01-20 14:10:07
Enter ".help" for usage hints.

sqlite> .table
comments     preferences  threads

sqlite> .schema comments
CREATE TABLE comments (     tid REFERENCES threads(id), id INTEGER PRIMARY KEY, parent INTEGER,     created FLOAT NOT NULL, modified FLOAT, mode INTEGER, remote_addr VARCHAR,     text VARCHAR, author VARCHAR, email VARCHAR, website VARCHAR,     likes INTEGER DEFAULT 0, dislikes INTEGER DEFAULT 0, voters BLOB NOT NULL,     notification INTEGER DEFAULT 0);
CREATE TRIGGER remove_stale_threads AFTER DELETE ON comments BEGIN     DELETE FROM threads WHERE id NOT IN (SELECT tid FROM comments); END;

sqlite> PRAGMA table_info(comments);
0|tid||0||0
1|id|INTEGER|0||1
2|parent|INTEGER|0||0
3|created|FLOAT|1||0
4|modified|FLOAT|0||0
5|mode|INTEGER|0||0
6|remote_addr|VARCHAR|0||0
7|text|VARCHAR|0||0
8|author|VARCHAR|0||0
9|email|VARCHAR|0||0
10|website|VARCHAR|0||0
11|likes|INTEGER|0|0|0
12|dislikes|INTEGER|0|0|0
13|voters|BLOB|1||0
14|notification|INTEGER|0|0|0

From the first look the column mode looks like what we want. To test this I created a new comment which is pending approvement.

user@host /opt/isso/db # sqlite3 testcomments.db <<< 'select * from comments where mode == 2;'
5|7||1724288099.62894||2|ip.ip.ip.ip|etertert|test||https://admin.brennt.net|0|0||0

And we got confirmation as only the new comment is listed. After approving the comment's mode changes to 1. Therefore we found a way to identify comments pending approval.

The check-isso-comments.sh script

Adding a bit of fail-safe and output we hack together the following script.

If you want to use it you need to fill in the values for TELEGRAM_CHAT_ID & TELEGRAM_BOT_TOKEN. Where TELEGRAM_CHAT_ID is the ID of the person who shall receive the messages and TELEGRAM_BOT_TOKEN takes your Bot's Token for accessing Telegrams HTTP-API.

Please always check https://github.com/ChrLau/scripts/blob/master/check-isso-comments.sh for the current version. I'm not going to update the script in this blogpost anymore.

#!/bin/bash
# vim: set tabstop=2 smarttab shiftwidth=2 softtabstop=2 expandtab foldmethod=syntax :

# Bash strict mode
#  read: http://redsymbol.net/articles/unofficial-bash-strict-mode/
set -euo pipefail
IFS=$'\n\t'

# Generic
VERSION="1.0"
#SOURCE="https://github.com/ChrLau/scripts/blob/master/check-isso-comments.sh"
# Values
TELEGRAM_CHAT_ID=""
TELEGRAM_BOT_TOKEN=""
ISSO_COMMENTS_DB=""
# Needed binaries
SQLITE3="$(command -v sqlite3)"
CURL="$(command -v curl)"
# Colored output
RED="\e[31m"
#GREEN="\e[32m"
ENDCOLOR="\e[0m"

# Check that variables are defined
if [ -z "$TELEGRAM_CHAT_ID" ] || [ -z "$TELEGRAM_BOT_TOKEN" ] || [ -z "$ISSO_COMMENTS_DB" ]; then
  echo "${RED}This script requires the variables TELEGRAM_CHAT_ID, TELEGRAM_BOT_TOKEN and ISSO_COMMENTS_DB to be set. Define them at the top of this script.${ENDCOLOR}"
  exit 1;
fi

# Test if sqlite3 is present and executeable
if [ ! -x "${SQLITE3}" ]; then
  echo "${RED}This script requires sqlite3 to connect to the database. Exiting.${ENDCOLOR}"
  exit 2;
fi

# Test if ssh is present and executeable
if [ ! -x "${CURL}" ]; then
  echo "${RED}This script requires curl to send the message via Telegram API. Exiting.${ENDCOLOR}"
  exit 2;
fi

# Test if the Isso comments DB file is readable
if [ ! -r "${ISSO_COMMENTS_DB}" ]; then
  echo "${RED}The ISSO sqlite3 database ${ISSO_COMMENTS_DB} is not readable. Exiting.${ENDCOLOR}"
  exit 3;
fi

COMMENT_COUNT=$(echo "select count(*) from comments where mode == 2" | sqlite3 "${ISSO_COMMENTS_DB}")

TEMPLATE=$(cat <<TEMPLATE
<strong>ISSO Comment checker</strong>

<pre>${COMMENT_COUNT} comments need approval</pre>
TEMPLATE
)

if [ "${COMMENT_COUNT}" -gt 0 ]; then

  ${CURL} --silent --output /dev/null \
    --data-urlencode "chat_id=${TELEGRAM_CHAT_ID}" \
    --data-urlencode "text=${TEMPLATE}" \
    --data-urlencode "parse_mode=HTML" \
    --data-urlencode "disable_web_page_preview=true" \
    "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage"

fi

Executing this script on the command-line will already sent a notification to me via Telegram. However I do want this to be automated hence I make use of a Systemd timer.

Systemd configuration

I use the following timer to get notified between 10 to 22 o'clock as there is no need to spam me with message when I can't do anything. I create the files as /etc/systemd/system/isso-comments.timer and /etc/systemd/system/isso-comments.service.

user@host ~ # systemctl cat isso-comments.timer
# /etc/systemd/system/isso-comments.timer
[Unit]
Description=Checks for new, unapproved Isso comments

[Timer]
# Documentation: https://www.freedesktop.org/software/systemd/man/latest/systemd.time.html#Calendar%20Events
OnCalendar=*-*-* 10..22:00:00
Unit=isso-comments.service

[Install]
WantedBy=default.target

The actual script is started by the following service unit file.

user@host ~ # systemctl cat isso-comments.service
# /etc/systemd/system/isso-comments.service
[Unit]
Description=Check for new unapproved Isso comments
After=network-online.target
Wants=network-online.target

[Service]
# Allows the execution of multiple ExecStart parameters in sequential order
Type=oneshot
# Show status "dead" after commands are executed (this is just commands being run)
RemainAfterExit=no
ExecStart=/usr/local/bin/check-isso-comments.sh

[Install]
WantedBy=default.target

After that it's the usual way of activating & starting a new Systemd unit and timer:

user@host ~ # systemctl daemon-reload

user@host ~ # systemctl enable isso-comments.service
Created symlink /etc/systemd/system/default.target.wants/isso-comments.service → /etc/systemd/system/isso-comments.service.
user@host ~ # systemctl enable isso-comments.timer
Created symlink /etc/systemd/system/default.target.wants/isso-comments.timer → /etc/systemd/system/isso-comments.timer.

user@host ~ # systemctl start isso-comments.timer
user@host ~ # systemctl status isso-comments.timer
● isso-comments.timer - Checks for new, unapproved Isso comments
     Loaded: loaded (/etc/systemd/system/isso-comments.timer; enabled; vendor preset: enabled)
     Active: active (waiting) since Mon 2024-09-09 19:33:45 CEST; 2s ago
    Trigger: Mon 2024-09-09 20:00:00 CEST; 26min left
   Triggers: ● isso-comments.service

Sep 09 19:33:45 admin systemd[1]: Started Checks for new, unapproved Isso comments.
user@host ~ # systemctl start isso-comments.service
user@host ~ # systemctl status isso-comments.service
● isso-comments.service - Check for new unapproved Isso comments
     Loaded: loaded (/etc/systemd/system/isso-comments.service; enabled; vendor preset: enabled)
     Active: inactive (dead) since Mon 2024-09-09 19:33:58 CEST; 14s ago
TriggeredBy: ● isso-comments.timer
    Process: 421812 ExecStart=/usr/local/bin/check-isso-comments.sh (code=exited, status=0/SUCCESS)
   Main PID: 421812 (code=exited, status=0/SUCCESS)
        CPU: 23ms

Sep 09 19:33:58 admin systemd[1]: Starting Check for new unapproved Isso comments...
Sep 09 19:33:58 admin systemd[1]: isso-comments.service: Succeeded.
Sep 09 19:33:58 admin systemd[1]: Finished Check for new unapproved Isso comments.

user@host ~ # systemctl list-timers
NEXT                         LEFT          LAST                         PASSED        UNIT                         ACTIVATES
Mon 2024-09-09 20:00:00 CEST 22min left    n/a                          n/a           isso-comments.timer          isso-comments.service
Tue 2024-09-10 00:00:00 CEST 4h 22min left Mon 2024-09-09 00:00:00 CEST 19h ago       logrotate.timer              logrotate.service
Tue 2024-09-10 00:00:00 CEST 4h 22min left Mon 2024-09-09 00:00:00 CEST 19h ago       man-db.timer                 man-db.service
Tue 2024-09-10 06:10:34 CEST 10h left      Mon 2024-09-09 06:06:10 CEST 13h ago       apt-daily-upgrade.timer      apt-daily-upgrade.service
Tue 2024-09-10 11:42:59 CEST 16h left      Mon 2024-09-09 19:33:17 CEST 4min 28s ago  apt-daily.timer              apt-daily.service
Tue 2024-09-10 14:22:35 CEST 18h left      Mon 2024-09-09 14:22:35 CEST 5h 15min ago  systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
Sun 2024-09-15 03:10:04 CEST 5 days left   Sun 2024-09-08 03:10:27 CEST 1 day 16h ago e2scrub_all.timer            e2scrub_all.service
Mon 2024-09-16 01:21:39 CEST 6 days left   Mon 2024-09-09 00:45:54 CEST 18h ago       fstrim.timer                 fstrim.service

9 timers listed.
Pass --all to see loaded but inactive timers, too.

And now I'm getting informed in time of new comments. Yai!

Comments

Choose your passphrases carefully!

Photo by Keira Burton: https://www.pexels.com/photo/unrecognizable-friends-gossiping-together-on-street-6147138/

I am walking down a street behind a building and notice a person leaving said building. Suddenly an alarm sounds.

Person: "Ah man! Damn it!"
Person picks up their phone and makes a call
Person: "Yes hi, this is first name last name from company X. I'm calling because I triggered a false alarm."
*Short pause*
Person: "Gross income."
*Short pause*
Person (visibly relieved): "Alright, thank you! Bye"

Your task: Identify the passphrase that will allow you to flag the security alarms as false-positive.

Please! Take the place, time and situation in which a passphrase is used into account! Especially when you must account for passers-by!

Thanks and make sure to visit my TED-Talk. 😉

Comments

Get the damn memo already: Java11 reached end-of-life years ago

Photo by Chevanon Photography: https://www.pexels.com/photo/person-performing-coffee-art-302899/

EDIT: The issue of Rundeck requiring an outdated Java version has been fixed since March 2025. However, the general statements and assumptions I made in this text remain valid.

I really dislike the uninformed attitude of some companies to the dependencies of their software. In this case: Rundeck
They actually state the following in their installation documentation:

Rundeck depends on Java 11. The Java 14 packages will satisfy this dependency however Rundeck will not function properly with them. It is recommended to install the openjdk-11-jre-headless package manually.
Source: https://docs.rundeck.com/docs/administration/install/linux-deb.html

In case Pagerduty (who owns Rundeck) didn't get the memo: Java11 reached end-of-life years ago! And some Linux distributions don't have packages for it any more. The latest Java version is Java22. And the current LTS version is Java21.

Utilizing https://endoflife.date/ we can easily get an overview of the respective dates.

Free builds from Oracle: https://endoflife.date/openjdk-builds-from-oracle: End of life reached: 19th March, 2019.

Paid builds from Oracle: https://endoflife.date/oracle-jdk: Premier Support reached end-of-life on 30th September 2023. Extended Support last until 31th January 2032.

RedHat builds of OpenJDK: https://endoflife.date/redhat-build-of-openjdk: Support ends 30th October 2024. With paid extended life-cycle support 1 it ends 31th October 2027.

However this is just for the OpenJDK packages!

The really important part is: Are there any Java11 packages for the operating system being used?

RedHat Linux Enterprise Server 9 contains Java1.8, Java11 and Java17.

SuSE Linux Enterprise Server 15 SP6 contains Java1.8, Java11 and Java17.

Ubuntu 24.04 - the current LTS version, provides OpenJDK packages for version 11, 17 and 21.

Debian Stable (Bookworm currently) ships with OpenJDK 17 only.

Sure, there are backports available for Debian, or you can just build your own packages. But that is not what bothers me. Java11 was released in September 2018. That is about 6 years ago. Java14 was released in March 2020. Four years ago.

And in all these years, they haven't been able to update their commercial application to depend on a more recent version of Java? Which is included in more recently released distributions? Or least make it work with them? This annoys me. Yes, it's nice that you offer free community packages for non-commercial distributions - but if I can't install your software because of missing dependencies, it doesn't help at all.

Especially as many business customers run commercial Linux distributions such as RedHat Linux Enterprise Server (RHEL) or SuSE Linux Enterprise Server (SLES) and are required to update regularly. Either by their own processes & standards or by law/insurances.

They literally can't install or even run older, unsupported versions of Java11 packages. This effectively forces them to purchase additional support packages for older versions of Java. Great! Not to mention if RHEL or SLES were to drop Java11 support. (Well, at least OpenJDK11 is already somewhat confirmed for RHEL10. Though I don't know if only with a valid ELS subscription or not. SuSE has not said anything about Java11 and SLES16 as far as I know).

Or they run one of the big non-commercial distributions like Debian or Ubuntu. Sure, Ubuntu 24.04 would be a viable alternative. But what if the customer doesn't have any Ubuntu servers? Should there be one or two Ubuntu servers out of thousands, just for one meagre application?

Create completely new Ansible playbooks and/or Puppet modules just for a handful of servers running a completely different OS? Maybe even use different software for other basic tasks like backup, LDAP integration, etc. in case the current software doesn't support Ubuntu LTS? This can easily lead to a long (and expensive) software chain reaction. Not to mention the new skills required at staff level.

"Just use docker."

You do understand that Docker is no solution to security risks when the container runs the same outdated software, yes? Sure it's good for mitigation/reduction of the attack surface but it doesn't fix the underlying problem.

And this annoys me. We really should hold enterprise software accountable to higher standards.

I do understand fairly well that someone at Pagerduty must have thought: "Well, all major (commercial) Linux distributions still support Java11, so there is no business risk for us. And for the rest we just provide container images via Docker." Yep, this is the reason why we sometimes can't have nice things. Total neglect of the wider responsibility while additionally ignoring the fact that Java11 needs to be included in all these commercial distributions as still too many software products rely on it.

If you sell software, every process involved in creating that piece of software should be treated as part of your core business and main revenue stream. Giving it the attention it deserves. If you don't, I'm going to make a few assumptions about your business. And those assumptions won't be favourable.

Unfortunately, this form of critical thinking about software dependencies is eroding as "Just use Docker" becomes the new norm among the next generation of IT professionals.

Comments

Little helper scripts - Part 1: no-screenlock-during-meeting.ps1

Photo by Markus Spiske: https://www.pexels.com/photo/internet-technology-computer-display-360591/

Part 2 of this series is here: Little helper scripts - Part 2: automation.sh / automation2.sh or use the following tag-link: https://admin.brennt.net/tag/littlehelperscripts

I decided to make some posts about smaller helper scripts I created. Just to brag about them. 😁 Well.. And maybe they help others solve a problem of their own too or serve as inspiration.

First script in this series is my: no-screenlock-during-meeting.ps1 (GitHub)

As the file extension reveals it's a Powershell script. It use is to press the ScrollLock key every 280 seconds. This effectively prevents Windows from automatically locking the screen after 5 minutes of inactivity.

I came up with this rather quickly as this seems to be a non-changeable standard setting of all clients I was working at so far. And yes, that setting makes sense and really enhances workplace security. I don't argue that.

However.. When you are in a meeting and easily spent several minutes listening, watching a demo/presentation or discuss topics.. Those 5 minutes are up rather quickly. And I got annoyed of constantly typing in my password when I just wanted to add 1-2 small sentences to my meeting notes.

This is what this script is for. It even checks if the computer is locked already and doesn't press a key if it is. As I also got annoyed of my laptop screen activating when locked and showing the password prompt every time the script would press a key.

But you have to keep in mind: I only use this script when I am in front of my laptop. Therefore I deemed this to be okay - if used in a responsible manner. As yes, I am circumventing a clients security measure. This is something you have to keep in mind. If I mess up by using this script - for example by keeping it running and leaving the room - my fault, my responsibility.

The script can be found on GitHub here: https://github.com/ChrLau/scripts/blob/master/no-screenlock-during-meeting.ps1

# If the computer isn't locked:
# Press the Scrolllock-Key every 280 seconds to prevent the automatic screen locking
$WShell = New-Object -Com "Wscript.shell"
while (1) {
  # Check if the logonui process is running - which is only the case when the Lockscreen is up
  if ( Get-Process logonui -ErrorAction SilentlyContinue ) {
    # Computer is locked, do nothing
  } else {
    # Computer is unlocked, press SCOLLLOCK key
    $WShell.SendKeys("{SCROLLLOCK}");
  }
  # Sleep for 280 seconds
  sleep 280;
}

I gladly take improvements as comment here or merge request on GitHub. Or just send a link to your version and I'll copy over the stuff I deem useful. 😜

Comments

Why I'm on #TeamKeePassUltras

Photo by Paula: https://www.pexels.com/photo/grey-metal-lockers-is-open-170453/

Recently I got into a discussion about cloud password managers like LastPass, 1Password and the like. People argued that they were great because they offer flexibility, synchronisation, and enable users to automatically choose secure passwords. And while I concurred to these arguments, I still took the position of the opposite side.

I am strongly against any form of online/cloud/managed password managers where I (or an entity I trust) don't control everything in a transparent way. Why?

First let me make my, the what I call, "the conspiracy theory argument": It's the least important argument for me, but is suited just right for paving the way to my main arguments. Most companies are US based. National security letters are a fact. And companies like Lavabit and, presumably, the Open Source Drive/File encryption project Truecrypt had their fair share of experience with them. The US and especially the NSA shows that it has no sane moral limits on what type of data to access, accumulate, and analyse. Would they stop at companies offering password managers? I don't think so. Others take the stance: "Why should they send a NSL to LastPass, if they can access the data they are after directly through others means?" but enough on that point.

My main argument is the following: "If I can't trust them, why should I use them?" A cloud password manager is a blackbox. I put my credentials in, hit save, and that's it. What happens in the background? Is the data stored secure? Are the algorithms used still considered secure? Are there no unencrypted backup copies? How does their security concept look like? Are the servers patched regularly? Am I being informed to re-generate my passwords in case the password-generation algorithm had a flaw and was, for example, tied to the systems date and time (wired.com)? I can't know.

Just search for the name of your cloud password provider and add the lovely word "breach". They were already dozens of it for all online password managers out there. Despite people ironically choosing or recommending them as to be "more secure".

But more secure in comparison to what?

You don't have to use an online/cloud password manager. A locally installed password manager like KeePass works the same way.

"But it doesn't synchronize automatically with all my devices!" - Ah, so it's comfort you are after? Yeah, well that is the common trade-off you have to choose: Comfort, or security. However, you do know KeePass has a build in sync which allows to sync two KeePass database files? I use that and it works fine.

Or I just copy over the file from my Linux workstation onto my Smartphone when I know that I had added no new entry on my smartphone. There are enough tools to allow the accessing of Windows/NFS/whatever file shares from Smartphones. Even via SSH utilizing SCP.

Additionally online password managers with sync-features who do allow to host your own instance do exist! Take for example Bitwarden: https://bitwarden.com/help/install-on-premise-linux/
This would give you the security of hosting it yourself and automatic sync-feature so many people desire. If not made accessable to the internet, but online in your local network you can still sync your smartphone, without opening your crucial application to the biggest security risk in human history: The internet.

Sure, not everybody has the knowledge to selfhost such an application. That's a fair point which Jürgen Geuter aka tante pointed out years ago in his writing "Host your own is cynical". But that's exactly the reason why I make this blogpost about me and my viewpoint. I have the knowledge, and I constantly observe broken promises by the very companies who gave them. And yet I still use KeePass. As I like the simplicity.

That's why I'm on #TeamKeePassUltras. An OpenSource application available for all operating systems out there. A simple file, a key, a passphrase and that's it.

Comments