OpenVPN 2.6.6 on Fedora 39: How to fix your connectivity to legacy OpenVPN servers!

Last week, Red Hat published their latest and greatest Fedora version, number 39. That means Fedora 38 will still be supported for about half a year. Fedora 37 even has nog more than a few more weeks of support left. So over the weekend, I updated my laptop. First I backupped my whole system to a USB stick and then updated using the well-known formula:

sudo dnf-y update && \
sudo dnf -y install dnf-plugin-system-upgrade && \
sudo dnf system-upgrade download –releasever=39 && \
sudo dnf system-upgrade reboot

Updating was a pretty smooth operation. But today, when I wanted to login to my servers in the datacenter, I found that OpenVPN could not connect anymore. While the configuration file hadn't changed even one letter. Time to investigate.

Problem 1: Ciphers

First, I found this message in the logs:

DEPRECATED OPTION: --cipher set to 'AES-256-CBC' but missing in --data-ciphers (AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305).
OpenVPN ignores --cipher for cipher negotiations.

The --data-ciphers option is something new to OpenVPN 2.5 and in version 2.6 it defaults to AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305. Because AES-256-CBC is not in there, OpenVPN cannot setup encryption anymore. To fix this, I added:

--data-ciphers AES-256-CBC:AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305

Problem 2: MTU

Then I found a message:

WARNING: 'tun-mtu' is used inconsistently, local='tun-mtu 1532', remote='tun-mtu 1500'
WARNING: 'link-mtu' is used inconsistently, local='link-mtu 1590', remote='link-mtu 1622'
Option inconsistency warnings triggering disconnect due to --opt-verify
SENT CONTROL [mekker]: 'AUTH_FAILED' (status=1)

I've seen both warning-messages combined, but also each separate, with dozens of different numbers. And always they were followed by a "opt-verify" and a AUTH_FAILED message. For me, the big solution was to fiddle a bit with the --tun-mtu option. Please note that the signature of this option used to be:

--tun-mtu n = Take the TUN device MTU to be n and derive the link MTU from it (default=1500).

But is now:

--tun-mtu args = tun-mtu [tun-mtu] [occ-mtu]

In my specific situation, I got all connections working using the following settings:

Server side VersionServer side SettingsClient side VersionClient side Settings
OpenVPN 2.4.7 arm-unknown-linux-gnueabihf [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on Feb 20 2019
library versions: OpenSSL 1.1.1d 10 Sep 2019, LZO 2.10

Running on a Raspbian 10.2 device
no mtu settings, just defaultsOpenVPN 2.6.6 x86_64-redhat-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] [DCO]
library versions: OpenSSL 3.1.1 30 May 2023, LZO 2.10
--tun-mtu 1500 1532
OpenVPN 2.5.9 x86_64-redhat-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on Feb 16 2023
library versions: OpenSSL 3.0.7 1 Nov 2022, LZO 2.10

Running on AlmaLinux 9.2
no mtu settings, just defaultsOpenVPN 2.6.6 x86_64-redhat-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] [DCO]
library versions: OpenSSL 3.1.1 30 May 2023, LZO 2.10
--tun-mtu 1500 1532
OpenVPN 2.4.9 x86_64-redhat-linux-gnu [Fedora EPEL patched] [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on Apr 24 2020
library versions: OpenSSL 1.0.1e-fips 11 Feb 2013, LZO 2.03

Running on CentOS 6.10
no mtu settings, just defaultsOpenVPN 2.6.6 x86_64-redhat-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] [DCO]
library versions: OpenSSL 3.1.1 30 May 2023, LZO 2.10
--tun-mtu 1500 1500
OpenVPN 2.4.7 mips-unknown-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on Apr 22 2022
library versions: OpenSSL 1.0.2u 20 Dec 2019, LZO 2.08

Running on a Ubiquiti EdgeRouter 12P
no mtu settings, just defaultsOpenVPN 2.6.6 x86_64-redhat-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] [DCO]
library versions: OpenSSL 3.1.1 30 May 2023, LZO 2.10
[yet to be tested]

© GeekLabInfo OpenVPN 2.6.6 on Fedora 39: How to fix your connectivity to legacy OpenVPN servers! is a post from GeekLab.info. You are free to copy materials from GeekLab.info, but you are required to link back to http://www.geeklab.info

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...

Allow RSA key size below 2048 bit to successfully establish SSH connections to legacy systems

The crypto-policy that comes with Red Hat Enterprise Linux 9 and AlmaLinux 9 does not allow RSA key sizes below 2048 bit. Some legacy SSH servers are configured with 1024 bit key sizes though which will result in connection failures:

# ssh username@servername.example.com
Bad server host key: Invalid key length

Trying to find the issue using ssh -vvv, you would get:

OpenSSH_8.8p1, OpenSSL 3.0.5 5 Jul 2022
debug1: Reading configuration data /home/geeklab/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Reading configuration data /etc/ssh/ssh_config.d/50-redhat.conf
debug1: Reading configuration data /etc/crypto-policies/back-ends/openssh.config
debug1: configuration requests final Match pass
debug1: re-parsing configuration
debug1: Reading configuration data /home/geeklab/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Reading configuration data /etc/ssh/ssh_config.d/50-redhat.conf
debug1: Reading configuration data /etc/crypto-policies/back-ends/openssh.config
debug1: Reading configuration data /etc/ssh/ssh_config.d/99-jxs.conf
debug1: Connecting to servername.example.com [1.2.3.4] port 22.
debug1: Connection established.
debug1: identity file /home/geeklab/.ssh/id_rsa type 0
debug1: identity file /home/geeklab/.ssh/id_rsa-cert type -1
debug1: identity file /home/geeklab/.ssh/id_dsa type -1
debug1: identity file /home/geeklab/.ssh/id_dsa-cert type -1
debug1: identity file /home/geeklab/.ssh/id_ecdsa type -1
debug1: identity file /home/geeklab/.ssh/id_ecdsa-cert type -1
debug1: identity file /home/geeklab/.ssh/id_ecdsa_sk type -1
debug1: identity file /home/geeklab/.ssh/id_ecdsa_sk-cert type -1
debug1: identity file /home/geeklab/.ssh/id_ed25519 type 3
debug1: identity file /home/geeklab/.ssh/id_ed25519-cert type -1
debug1: identity file /home/geeklab/.ssh/id_ed25519_sk type -1
debug1: identity file /home/geeklab/.ssh/id_ed25519_sk-cert type -1
debug1: identity file /home/geeklab/.ssh/id_xmss type -1
debug1: identity file /home/geeklab/.ssh/id_xmss-cert type -1
debug1: Local version string SSH-2.0-OpenSSH_8.8
debug1: Remote protocol version 2.0, remote software version OpenSSH_5.3
debug1: compat_banner: match: OpenSSH_5.3 pat OpenSSH_5* compat 0x0c000002
debug1: Authenticating to servername.example.com:22 as 'root'
debug1: load_hostkeys: fopen /home/geeklab/.ssh/known_hosts2: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: algorithm: diffie-hellman-group-exchange-sha256
debug1: kex: host key algorithm: ssh-rsa
debug1: kex: server->client cipher: aes256-ctr MAC: hmac-sha2-256 compression: none
debug1: kex: client->server cipher: aes256-ctr MAC: hmac-sha2-256 compression: none
debug1: kex: diffie-hellman-group-exchange-sha256 need=32 dh_need=32
debug1: kex: diffie-hellman-group-exchange-sha256 need=32 dh_need=32
debug1: SSH2_MSG_KEX_DH_GEX_REQUEST(2048<8192<8192) sent
debug1: expecting SSH2_MSG_KEX_DH_GEX_GROUP
debug1: SSH2_MSG_KEX_DH_GEX_GROUP received
debug1: SSH2_MSG_KEX_DH_GEX_INIT sent
debug1: expecting SSH2_MSG_KEX_DH_GEX_REPLY
debug1: SSH2_MSG_KEX_DH_GEX_REPLY received
Bad server host key: Invalid key length

While the best solution would be to fix the key size of the target server, this is not always possible on embedded devices. For those devices, you could alternatively make a change to your ~/.ssh/config file:

Host servername.example.com
     RSAMinSize 1024
© GeekLabInfo Allow RSA key size below 2048 bit to successfully establish SSH connections to legacy systems is a post from GeekLab.info. You are free to copy materials from GeekLab.info, but you are required to link back to http://www.geeklab.info

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...

chattr and lsattr in Python

Apart from changing the rwxr-xr-x like permissions, some Linux filesystems have another way of protecting files. You cam make them IMMUTABLE, after which no program can change them. Not even if you have the right permissions. Python however does not support reading or writing the immutable attribute.

Inspired by yellowcrescent, I just wrote the following code snippet for my own use:

# Code from geeklab.info
import fcntl
from array import array

# FS constants - see /uapi/linux/fs.h in kernel source
# or <elixir.free-electrons.com/linux/latest/source/include/uapi/linux/fs.h>
FS_IOC_GETFLAGS = 0x80086601
FS_IOC_SETFLAGS = 0x40086602
FS_IMMUTABLE_FL = 0x010

def chattri(filename: str, value: bool):
    with open(filename,'r') as f: 
        arg = array('L', [0])
        fcntl.ioctl(f.fileno(), FS_IOC_GETFLAGS, arg, True)
        if value:
            arg[0]=arg[0] | FS_IMMUTABLE_FL
        else:
            arg[0]=arg[0] &~ FS_IMMUTABLE_FL
        fcntl.ioctl(f.fileno(), FS_IOC_SETFLAGS, arg, True)

def lsattri(filename: str) -> bool:
    with open(filename,'r') as f:
        arg = array('L', [0])
        fcntl.ioctl(f.fileno(), FS_IOC_GETFLAGS, arg, True)
    return bool(arg[0] & FS_IMMUTABLE_FL)
    
f="/root/testfile"
print("Yes" if lsattri(f) else "No")
chattri(f,False)
print("Yes" if lsattri(f) else "No")
chattri(f,False)
print("Yes" if lsattri(f) else "No")

Use it as you like, at your own risk. If possible please link my website.

Keep in mind that only users with root-access can change file attributes.

© GeekLabInfo chattr and lsattr in Python is a post from GeekLab.info. You are free to copy materials from GeekLab.info, but you are required to link back to http://www.geeklab.info

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...

iptables and dynamic DNS – part 3

This is an updated post for this updated article.

I just found back an old note about using iptables in combination with dyndns to open up access from a remote location. For instance, if you have a laptop that you take everywhere and you want to connect to your home or office. The script the other site suggested was broken, so let's write a new one.

Step 1: Create a new chain in the firewall

Create a new chain in the firewall where we can plug in the dynamic rules. On my Fedora machine, the firewall is located in /etc/sysconfig/iptables. I added the bold lines to this example.


*nat
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
<b>:DYNAMICPARENT - [0:0]
-A INPUT -j DYNAMICPARENT</b>
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

Step 2: Write a script

#!/bin/bash
 
HOSTNAME=myname.dyndns.org
CHECK_INTERVAL=60 #once a minute
 
IP="" #initialize $IP
while [ true ]; do
        OIP=$IP
        IP=$(dig +short $HOSTNAME | grep -iE "^[0-9]+.[0-9]+.[0-9]+.[0-9]+$"|head -n 1)
        if [ "$OIP" != "$IP" -a "$IP" != "" ]; then
                echo "Changing ip to $IP"
                /sbin/iptables -N DYNAMICNEW                    # create new rule
                /sbin/iptables -I DYNAMICNEW -s $IP -j ACCEPT   # allow new ip
                /sbin/iptables -I DYNAMICPARENT -j DYNAMICNEW   # attach new rule to its parent
 
                while [ true ]; do  # unlink old rule - if multiple exist, remove all
                        /sbin/iptables -D DYNAMICPARENT -j DYNAMICCHILD 2>/dev/null || break
                done
                /sbin/iptables -F DYNAMICCHILD #flush all old rules
                /sbin/iptables -X DYNAMICCHILD #flush all old rules
 
                /sbin/iptables -E DYNAMICNEW DYNAMICCHILD #rename new to "current"
        fi
        sleep $CHECK_INTERVAL
done

In this case, the firewall accepts all traffic from $IP, but of course you could restrict it to 1 port. Also, I focussed on IPv4, but you could easily rewrite this script to IPv6 using ip6tables. I saved the file to /usr/local/bin/dynfirewall.sh

Step 3: Run the script

I'd prefer running the script from inittab, but since Fedora doesn't work like this anymore, I put the following line in /etc/rc.d/rc.local:

/usr/local/bin/dynfirewall.sh >>/var/log/dynfirewall 2>>/var/log/dynfirewall &

Please don't forget the ampersand at the end to fork the script!!

Why is this script better than previous version?

- This script can handle cnames
- The old script used to delete old rules, before creating new ones. This one does not. Therefore, it will never leave a second where you cannot connect.© GeekLabInfo
iptables and dynamic DNS - part 3 is a post from GeekLab.info. You are free to copy materials from GeekLab.info, but you are required to link back to http://www.geeklab.info

1 Star2 Stars3 Stars4 Stars5 Stars (2 votes, average: 5.00 out of 5)
Loading...

iptables and dynamic DNS – part 2

In 2011, I wrote this post on Dynamic DNS: https://www.geeklab.info/2011/02/iptables-and-dynamic-dns. While this is still useful, I found a newer, cooler way to do Dynamic DNS in combination with iptables. It's called libnetfilter_queue.

iptables is used to change the inner netfilter tables of the kernel. And because the kernel has no internal resolver, it is impossible for the kernel to do on-the-fly dns lookups. But by offloading this decision to userspace, it is possible. The libnetfilter_queue lib offers that functionality.

libnetfilter_queue is a userspace library providing an API to packets that have been queued by the kernel packet filter. It has bindings for Python and several other languages.

Requirements for my setup

python-NetfilterQueue - https://github.com/kti/python-netfilterqueue

libnfnetlink

libnetfilter_queue

libmnl

You may need to build the first dependency yourself. The other 3 are available in Fedora 20 by default. If you're running RHEL/CentOS, the Fedora packages can be recompiled for your setup.

iptables rule

First, you need to get iptables to enqueue specific packets to your queue.

iptables -I INPUT -p tcp --dport 631 -m state --state NEW -j NFQUEUE --queue-num 6789 -m comment --comment "Remote CUPS printer"

Queue handler

Then we write a script that handles the queue. A quick-and-dirty implementation:

#!/usr/bin/python
 
import socket
from netfilterqueue import NetfilterQueue
 
def getIP(d):
    """
    This method returns the first IP address string
    that responds as the given domain name
    """
    try:
        data = socket.gethostbyname(d)
        #ip = repr(data)
        return data
    except Exception:
        # fail gracefully!
        return False
 
def dnsfilter(pkt):
        if pkt.get_payload_len() < 0x10:
                "Don't know how to handle this too small packet"
                pkt.drop()
                return False
 
        payload=pkt.get_payload()
        srcip=".".join("{:d}".format(ord(c)) for c in payload[0x0c:0x10])
        allowedip=getIP('localhost')
        print "Debug: SRC="+srcip+" ALLOWED="+allowedip+" RESULT=",
        if srcip==allowedip:
                print "Accept"
                pkt.accept()
        else:
                print "Drop"
                pkt.drop()
 
nfqueue = NetfilterQueue()
nfqueue.bind(6789, dnsfilter)
try:
        nfqueue.run()
except KeyboardInterrupt:
        print

This is a quick-and-dirty implementation that misses basic features such as caching the result of gethostbyname. This may introduce terrible delays if used wrong.

Ubuntu/Debian

I'm running RedHat-based software on all of my machines. Above information may be useful for Ubuntu/Debian users, but it's not tested and I'm not supporting it.

Servers: RedHat Enterprise Linux/CentOS is more suitable for servers, as there's a lot of professional level support available. I think that's important, because if I say, get a car accident, I want the servers to be managable by another professional.

Desktops/Laptops: RPM packages are pretty exchangable between RedHat-based platforms. That's a good reason to run Fedora on the desktop.

© GeekLabInfo
iptables and dynamic DNS - part 2 is a post from GeekLab.info. You are free to copy materials from GeekLab.info, but you are required to link back to http://www.geeklab.info

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...

Bash: download and execute shell scripts

Sometimes, when running 1 bash script repeatedly on several different machines, I found that being able to download and immediately execute a script is very handy.

The following command will download a script and immediately execute it:

bash <(curl -s http://geeklab.info/my-script.sh)

This command uses Bash's Process Substitution to do it's job. command2 <(command) means for bash to put the output of command in a pipe and then run command2 [tempfile]. So above statement does the same as:

TMPFILE=$(mktemp /tmp/my.XXXXX)
curl -s http://geeklab.info/my-script.sh > $TMPFILE
bash $TMPFILE
rm $TMPFILE

Process substitution is also very useful when you want to know the difference between the output of two commands:

diff <( command1 ) <( command2 )

Furthermore, it's possible to pipe the contents of the temporary file into command2. For instance:
bash < <(curl http://geeklab.info/my-script.sh) would do the same as:

TMPFILE=$(mktemp /tmp/my.XXXXX)
curl -s http://geeklab.info/my-script.sh > $TMPFILE
bash < $TMPFILE
rm $TMPFILE

With bash, this difference is small, but with other commands, it may not be.© GeekLabInfo
Bash: download and execute shell scripts is a post from GeekLab.info. You are free to copy materials from GeekLab.info, but you are required to link back to http://www.geeklab.info

1 Star2 Stars3 Stars4 Stars5 Stars (1 votes, average: 5.00 out of 5)
Loading...

How to decrypt a PDF file on Linux

Sometimes, I receive digital invoices in PDF format with a password. That way I shouldn't be able to modify them and commit fraud. Unfortunately, this also makes it impossible to perform normal operations on them, such as removing unneeded specifications or merging all invoices into one single file.

Luckily, most Linux distributions come with a tool that can be used to remove these passwords: ghostscript.

In order to remove the password, simply run:

gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=unencrypted.pdf -c .setpdfwrite -f encrypted.pdf

While this does remove the password, I'm not sure if it does not degrade the quality of the file a little (I don't notice any quality difference, but if you use highres files, you may lose quality).© GeekLabInfo
How to decrypt a PDF file on Linux is a post from GeekLab.info. You are free to copy materials from GeekLab.info, but you are required to link back to http://www.geeklab.info

1 Star2 Stars3 Stars4 Stars5 Stars (3 votes, average: 4.67 out of 5)
Loading...