Author: fjgraf

  • Speedtest – ookla

    Download the official Linux x86_64 tarball

    curl -O https://install.speedtest.net/app/cli/ookla-speedtest-1.2.0-linux-x86_64.tgz

    Extract the binary

    tar -xvf ookla-speedtest-1.2.0-linux-x86_64.tgz

    Run it directly without root privileges

    ./speedtest
  • Genealogy Study

    Fernandez Family Lineage – Investigation

    Fernandez Family Lineage

    Research & Investigation Notes

    Compiled: June 30, 2026

    📋 Table of Contents

    1. Spanish Ancestors
    2. Don Alonso Fernandez de Cordoba (Founder in Chile)
    3. Anibal Fernandez Carrasco – Life & Career
    4. First Marriage: Adelaida Rivera Garrido
    5. Second Marriage: Remigia Herrera Soto
    6. All Children
    7. Cruzat Family Connection
    8. Migration to Temuco
    9. Research Resources

    Spanish Ancestors (Family Oral History)

    ⚠ NOTE: Take with grain of salt – only source is family oral history, may contain errors.
    Don Gonzalo Fernandez de Aguilar y Cordova
    • Born: 1453, Montilla, Spain
    • Died: December 2, 1515, Loja, Ecuador
    • Profession: Great soldier, military leader
    • Service: Won many battles for Isabella de Castilla and Fernando de Aragon (Queen and King)
    • Later life: After Queen Isabella died, King Fernando became afraid Gonzalo was more powerful than the King. After many vicissitudes, retired to Loja, granted to him by the King.
    Don Alonso Fernandez de Cordoba (Founder in Chile)
    • Relation: Descendant of Don Gonzalo Fernandez de Aguilar y Cordova
    • Profession: Spanish naval officer, captain of a Spanish ship
    • Arrival: Arrived in Talcahuano, Chile (seaport near Concepcion)
    • Love story: Fell in love with Dona Catalina Barraja
    • Settled: Dona Catalina was daughter of Governor of Talcahuano; they settled in Concepcion for life
    • Royal grant: King of Spain granted him a state (land) in La Florida (Chile), ~60 km from Concepcion, called “Fundo Provoque”

    Anibal Fernandez Carrasco – Life & Career

    Anibal Fernandez Carrasco
    • Born: At Fundo Provoque (family estate in La Florida)
    • Parents: Daniel Fernandez (son of Daniel Fernandez Cruzat + Cristina Rosalia Carrasco)
    • Profession: Farmer and Justice of the Peace
    • Family estate: Had his own farm called “Fundo Radal” (in Temuco area)
    • Marriages: First to Adelaida Rivera Garrido, second to Remigia Herrera Soto
    • Location: Lived in Temuco area, Araucanía region

    Migration to Temuco

    Until 1850: All Spanish descendants didn’t travel south of the Bio Bio river.
    After 1850: German immigration to the south triggered a frontier movement.
    Anibal’s move: Anibal Fernandez (married to Adelaida Rivera at the time) moved to Temuco and started working in partnership with his brother-in-law, Dr. Bautista Faundez, on the farm.
    Later: When Anibal became a widower (Adelaida died, date unknown), he lived and worked on his own farm “Fundo Radal”.

    First Marriage: Adelaida Rivera Garrido

    Adelaida Rivera Garrido
    • Married to: Anibal Fernandez Carrasco (~1894)
    • Death: Died (exact date unknown)
    • Children with Anibal: 4 children
    • Family: Connected to Rivera family in Chile (1829-1910 era)

    Children with Adelaida

    1. Anibal Fernandez Carrasco (Son, married)
    2. Federico Fernandez Carrasco (Lawyer/Abogado)
    3. Adelaida Fernandez Carrasco (Married)
    4. Aliro Fernandez Carrasco (Died of tuberculosis at 16 years old)

    Second Marriage: Remigia Herrera Soto

    Remigia Herrera Soto
    • Profession: Elementary school principal
    • Historic achievement: Formed the FIRST GYMNASTICS TEAM in Chile
    • Award: Received presidential award from President of Chile
    • Era: Active in 1920s-1940s
    Remigia Herrera Soto is a historically important figure in Chilean women’s sports and education history.

    All Children of Anibal Fernandez Carrasco

    Name Profession Education Marriage Notes
    Anibal Fernandez (Son) Married
    Federico Fernandez Lawyer (Abogado) Son of first marriage
    Adelaida Fernandez (Daughter) Married Son of first marriage
    Aliro Fernandez Died of tuberculosis at 16
    Adela Fernandez French Teacher Sorbonne, Paris Dr. Borgono Daughter of second marriage
    Julia Fernandez English Teacher Wheaton College (MA), Holland High School (MI), University of Reading (UK), Washington D.C. Daughter of second marriage. Exceptional education for Chilean woman of era
    Emilia Fernandez Music Teacher Bruno Farina (music teacher) Daughter of second marriage
    Daniel Fernandez General Studies Teacher Son of second marriage
    Elena Fernandez Herrera Social Worker Dr. Rene Graf Daughter of second marriage. Born Dec 12, 1920. Died March 5, 2018, Quilpue, Chile.
    Mario Fernandez Civil Constructor Engineer Sylvia Ernst Son of second marriage
    Ruth Fernandez Teacher of Childhood Development University of Fine Arts, Chile Daughter of second marriage

    Cruzat Family Connection

    CONFIRMED: Daniel Fernandez Cruzat (Anibal’s father) was from the Cruzat family.
    Daniel Fernandez Cruzat
    • Profession: Lawyer (Abogado)
    • Married: Cristina Rosalia Carrasco
    • Children: At least 10 children including Arturo, Carlos, Julio, Octavio, Solustio, Anibal, Aglae, Adela, Rosalia, Daniel
    • Family: Cruzat family – one of Chile’s FOUNDER FAMILIES

    Cruzat Family – Spanish Nobility Connection

    CONFIRMED: Cruzat family traces to Spanish nobility:
    • “Descendiente de Ruy Díaz de Vivar, el Cid Campeador”
    • “Desciende de Carlomagno” (Charlemagne)
    CONFIRMED: Cruzat family documented in “Familias Fundadoras de Chile” by Julio Retamal Favereau et al.
    Book: “Familias Fundadoras de Chile, 1656-1700”

    Authors: Julio Retamal Favereau, Carlos Celis Atria, José Miguel de la Cerda Merino, Carlos Ruiz Rodríguez, Francisco José Urzúa Prieto

    Publisher: Ediciones Universidad de la Frontera, Temuco, 1989

    CONFIRMED: Cruzat family members found in Temuco area by 1893.
    Online Resources:

    Temuco – Historical Context

    Temuco founded: 1876
    Spanish frontier: Up to 1850, all Spanish descendants didn’t travel south of the Bio Bio river.
    German immigration: After 1850, German immigration to the south triggered a frontier movement.
    Anibal’s migration: Anibal moved to Temuco with Adelaida Rivera and worked with brother-in-law Dr. Bautista Faundez.

    Research Resources

    Online Genealogy Sites

    genealog.cl (Chilean genealogy – FREE)
    FamilySearch.org (FREE)
    • Chile Civil Registration Records (1885-1932)
    • Temuco Parish Records (1892-1920)
    • Family Search Tree

    Note: Access may be blocked by security checks

    Geni.com (FREE)
    • 53 Cruzat Fernandez profiles
    • Search for “Anibal Fernandez Carrasco” or “Daniel Fernandez Cruzat”

    Note: CAPTCHA security may block access

    Chilean Government Resources

    Archivo Nacional de Chile
    • Civil registration records
    • Church records
    • Land grants and property records
    Chilean Bar Association (Colegio de Abogados de Chile)
    Chilean Medical Association
    • Search for physicians: Solustio Fernandez, Dr. Bautista Faundez

    International Education Records

    Wheaton College, Massachusetts
    University of Reading, Berkshire, England
    • International student records
    • Alumni records for Julia Fernandez

    Fernandez Family Lineage Investigation

    Research compiled: June 30, 2026

    Information sources: Family oral history, genealog.cl, historical records, academic research

    Note: Spanish ancestor information should be verified with historical records. Chilean family history information is confirmed by multiple sources.

  • Firejail Cheat Sheet

    ###############################################################################
    #                    COMPREHENSIVE FIREJAIL CLI CHEAT SHEET                   #
    ###############################################################################
    
    # 1. NETWORK CONTROL & BANDWIDTH SHAPING
    # -----------------------------------------------------------------------------
    firejail --net=none name-of-app                  # Run app with NO internet access
    firejail --net=lo name-of-app                    # Run app with local loopback interface only
    firejail --dns=1.1.1.1 name-of-app               # Force app to use a specific DNS server
    firejail --net=eth0 --bandwidth=eth0:down:1mbps  # Shape network; cap download speed at 1mbps
    
    # 2. FILE SYSTEM ISOLATION (EPHEMERAL VS. PERSISTENT)
    # -----------------------------------------------------------------------------
    firejail --private name-of-app                   # Ephemeral: Blank home directory (wiped on close)
    firejail --private=/home/user/isolated_folder/ \
             name-of-app                             # Persistent: Lock app data into a specific real folder
    firejail --read-only=~/Documents name-of-app     # Mount a target directory as read-only
    firejail --blacklist=~/.ssh name-of-app          # Hide a sensitive folder completely from the app
    firejail --whitelist=~/Downloads name-of-app     # Restrictive: ONLY allow access to Downloads, hide rest of home
    
    # 3. DISPLAY & HARDWARE GRAPHICS SECURITY
    # -----------------------------------------------------------------------------
    firejail --nodisplay name-of-app                 # Completely block access to X11/Wayland display servers
    firejail --x11=xpra name-of-app                  # Sandbox X11: Prevent app from keylogging other open windows
    firejail --nortcwd name-of-app                   # Mask the real current working directory from the app
    firejail --nou2f name-of-app                     # Disable access to U2F/Yubikey security keys
    
    # 4. RESOURCE LIMITS & PERFORMANCE (CGROUPS)
    # -----------------------------------------------------------------------------
    firejail --cpu=0,1 name-of-app                   # CPU Pinning: Force app to run ONLY on CPU cores 0 and 1
    firejail --rlimit-as=1g name-of-app              # RAM Cap: Kill the process if it uses more than 1GB of memory
    firejail --nice=10 name-of-app                   # Lower process priority so it doesn't slow down your PC
    
    # 5. ADVANCED SYSTEM LOCKDOWNS
    # -----------------------------------------------------------------------------
    firejail --noroot name-of-app                    # Strip app of any ability to gain root/sudo privileges
    firejail --seccomp name-of-app                   # Block dangerous, non-standard Linux system calls
    firejail --caps.drop=all name-of-app             # Drop all Linux kernel capabilities for the process
    firejail --net=none --private --noroot app-name  # Hardcore "prison" combo (No net, no home, no root)
    
    # 6. MONITORING & MANAGING ACTIVE SANDBOXES
    # -----------------------------------------------------------------------------
    firejail --list                                  # List all running sandboxes and their PIDs
    firejail --tree                                  # View a live process tree inside active sandboxes
    firejail --netstats                              # View real-time bandwidth/network stats
    firejail --shutdown=12345                        # Forcefully kill a sandbox by its PID
    
    # 7. INTEGRATION & PERMANENT CONFIGURATIONS
    # -----------------------------------------------------------------------------
    sudo firecfg                                     # Automatically route desktop shortcuts through firejail
    sudo firecfg --clean                             # Undo all permanent desktop firejail symlinks
  • App isolation with Namespace

    Isolation of firefox from the internet script to communicate only with openwebui.

    #!/bin/bash
    
    # --- CONFIGURATION ---
    NS_NAME="restricted_net"
    VETH_HOST="172.200.1.1"
    VETH_NS="172.200.1.2"
    TARGET_IP="192.168.1.100"
    
    # 1. CLEANUP (Wipe the slate clean)
    echo "Cleaning up..."
    sudo ip netns delete $NS_NAME 2>/dev/null
    sudo ip link delete veth-host 2>/dev/null
    # Clean old NAT/Forward rules to avoid "Rule already exists"
    sudo iptables -t nat -D POSTROUTING -s $VETH_NS/32 -j MASQUERADE 2>/dev/null
    sudo iptables -D FORWARD -s $VETH_NS/32 -j ACCEPT 2>/dev/null
    sudo iptables -D FORWARD -d $VETH_NS/32 -j ACCEPT 2>/dev/null
    
    # 2. CREATE NAMESPACE & LINK
    sudo ip netns add $NS_NAME
    sudo ip link add veth-host type veth peer name veth-ns
    sudo ip link set veth-ns netns $NS_NAME
    
    # 3. ADDRESSING
    sudo ip addr add $VETH_HOST/24 dev veth-host
    sudo ip netns exec $NS_NAME ip addr add $VETH_NS/24 dev veth-ns
    
    # 4. BRING UP INTERFACES
    sudo ip link set veth-host up
    sudo ip netns exec $NS_NAME ip link set veth-ns up
    sudo ip netns exec $NS_NAME ip link set lo up
    
    # 5. ROUTING: The "Precision" Path
    # We tell the bubble: "To reach your specific target, go through the host."
    sudo ip netns exec $NS_NAME ip route add $TARGET_IP/32 via $VETH_HOST dev veth-ns
    
    # 6. SYSTEM-WIDE FORWARDING (Kernel Level)
    sudo sysctl -w net.ipv4.ip_forward=1 > /dev/null
    
    # 7. FIREWALL: Open the "Gates"
    # This tells the Debian firewall to allow the traffic to pass through the host
    sudo iptables -A FORWARD -s $VETH_NS/32 -j ACCEPT
    sudo iptables -A FORWARD -d $VETH_NS/32 -m state --state ESTABLISHED,RELATED -j ACCEPT
    
    # 8. NAT (MASQUERADE)
    # This makes the target see your host's IP instead of the 10.200.x.x IP
    sudo iptables -t nat -A POSTROUTING -s $VETH_NS/32 -j MASQUERADE
    
    # 9. PERMISSION TO DRAW WINDOWS
    xhost +local: > /dev/null
    
    echo "-------------------------------------------------------"
    echo "Targeting: $TARGET_IP"
    echo "Testing path with 2 pings..."
    sudo ip netns exec $NS_NAME ping -c 2 -W 2 $TARGET_IP
    echo "-------------------------------------------------------"
    
    # 10. LAUNCH FIREFOX
    # --no-remote is CRITICAL
    # sudo ip netns exec $NS_NAME sudo -u $USER firefox --no-remote         # No Auto Redirection
    sudo ip netns exec $NS_NAME sudo -u $USER firefox --no-remote "http://192.168.1.100:8080"
    

    Now lets configure a new shortcut so that when firefox executes, the script to run the namespace configuration is initialised every time it’s launched leaving firefox in its own bubble. Your sudo password will be prompted.

    Save the following config in:

    .local/share/applications/vault-firefox.desktop
      GNU nano 8.4            .local/share/applications/vault-firefox.desktop                     
    [Desktop Entry]
    Categories=Network;WebBrowser;
    Comment=Isolated Firefox for VM Access
    Exec=kdesu /home/bee/namespace/LAN-only-Firefox.sh
    Icon=firefox-esr-symbolic
    Name=Firefox Vault
    NoDisplay=false
    Path=
    PrefersNonDefaultGPU=false
    StartupNotify=true
    Terminal=false
    TerminalOptions=
    Type=Application
    X-KDE-SubstituteUID=false
    X-KDE-Username=
    
  • QUIZ 4 – Intro to Linux


    As before, try to first answer ALL questions from memory.
    Only after that should you use internet, your notes, slides, or console to find the answer.

    SERIES 1

    1. Give commands to display:
      a) ip address of the machine
      ip a
      b) ip address of the default gateway
      ip route | grep default
      c) ip address of DNS server(s)
      cat /etc/resolv.conf or resolvectl status
    2. What is the contents of ~/.ssh/id_rsa file?
      The content is a string of characters representing the private key of a key-pair and which is specific to an specific public key.
    3. What is the contents of ~/.ssh/authorized_keys file?
      These are the public keys that are allowed in a server to permit the connection from a client machine that has the specific private key for secure connection (ssh).
    4. Give command to generata keys required for key-based SSH authentication:
      ssh-keygen -t ed25519 -f mykey
    5. Give command to setup key-based SSH authentication between current account and account jerry on machine 1.2.3.4. :
      ssh-copy-id jerry@1.2.3.4
    6. Recall UFW. Give a command to:
      a) display whether UFW is enabled or list all currently used rules:
      sudo ufw status, sudo ufw status numbered
      b) display all rules numbered:
      sudo ufw status numbered
      c) delete rule number 3:
      sudo ufw delete [rule number OR name]
      d) allow incoming connections to port 6667 via TCP protocol:
      sudo ufw allow 6667/tcp
      e) allow incoming connections for ntp service:
      sudo ufw allow ntp

    As before, try to first answer ALL questions from memory.
    Only after that should you use internet, your notes, slides, or console to find the answer.

    SERIES 2

    1. Give command to create a symbolic link named ‘followme’ pointing to /etc/network directory
    • ln -s /etc/network followme
    1. Give command to remove symbolic link ~/subdirlink
    • unlink ~/subdirlink
    1. Give 2 reasons why symbolic links are used, give 1 example of each
    • it creates a shortcut in the windows sense but it can do much more.
    • Backward compatibility by pointint the old standard dirs and files to new current location like in the example of folder /bin and /sbin that currently were moved to /usr/bin and /usr/sbin
    1. Give a command to view or change what possible programs can be used as ‘vi’ command in /usr/bin/vi.
    • sudo update-alternatives –config vi

    As before, try to first answer ALL questions from memory.
    Only after that should you use internet, your notes, slides, or console to find the answer.

    SERIES 3

    Write a command using sed (and other commands) to:

    1. display the first 5 lines of /etc/group file where all colons : have been replaced with commas ,
      • head -n5 /etc/group | sed ‘s/:/,/g’
    2. display the contents of /etc/hosts where any occurence of 127 is changed to word LOCAL
      • sed ‘s/127/LOCAL/g’ /etc/hosts
    3. take the output of ‘ls -l ~/’ command and replace any occurence of rwx in it with word ALL
      • ls -l ~/ | sed ‘s/rwx/ALL/g’
    4. display lines 5,6,7 of /etc/passwd
      head /etc/passwd -n7 | tail -n3 OR sed -n ‘5,7p’ /etc/passwd
      Hint: try head and tail
    5. Recall command ‘top’. If a computer has 8 cores and they’re all occupied at 75% what will be the value of ‘load’ displayed by command top?
      • is the number of cores times decimal percentage expression: 8 X 0.75 = 6
    6. Explain meaning of each of the following shell operators in one sentence and give one example of use

    > Write to OR overwrite to file

    >> Append to file

    2> send stderr code to
    &> send everything to
    2>&1 send stderr to ?
    < redirects standard input FROM a file
    | pipe is used to transfer stdout to the next command
    ; semicolon separator makes second command to execute regardless
    && AND operator only executes second command if first one succeeds
    || OR operator executes second command only when the first one failed

    As before, try to first answer ALL questions from memory.
    Only after that should you use internet, your notes, slides, or console to find the answer.

    SERIES 4

    1. Find out how many (approximately) programs named ‘bash’ are currently running on your system.
      ps -aux | grep bash
    2. Find out what is the program that takes most RAM or CPU
      ps aux –sort=%cpu
    3. Create a backup of entire /etc into a file saved in /tmp directory (you pick an appropriate file name in /tmp)
      tar -zvcf /tmp/etc_backup.tar.gz /etc
    4. Restore backup of /etc/ directory previously created into /tmp directory (do NOT override originals is /etc)
      tar -zxvf /tmp/etc_backup.tar.gz -C /tmp/etc2
    5. Run cp /etc/passwd /tmp/users.txt. Then use gzip to compress /tmp/users.txt
      cp /etc/passwd /tmp/users.txt
      gzip /tmp/users.txt
      Verify that compressing it worked and users.txt.gz exists.
      ls -l users.txt.gz
    6. Uncompress the file you compressed in previous step.
      gunzip /tmp/users.txt.gz /tmp
      ls -l users.txt
    7. [multiple answers] Start Firefox.
    • How can you find out what is the PID of that process? Do it.
      ps aux | grep firefox
    • How can you terminate the process? Do it.
      kill PID
    • How would you terminate the process forcefully?
      kill -9 PID
    1. How would you terminate all processes started from executable named ‘less’ ?
      killall less OR pkill less
    2. Write a command that will check if group named ‘admin’ exists in /etc/group. If the group exists – your command should display message “found it” and if not “no such group”. Make sure you don’t display anything else. Repeat the same command looking for group named ‘adm’.
      if cut -d: -f1 /etc/group | grep -q “^adm$”; then echo “found it”; else echo “is not there”; fi

    As before, try to first answer ALL questions from memory.
    Only after that should you use internet, your notes, slides, or console to find the answer.

    TASK 1.

    Create script called taller.sh.
    Script requires exactly 4 parameters.
    parameters 1 and 3 are names (any text).
    parameters 2 and 4 are heights (numbers).

    Script will compare heights and then say
    which person is taller.

    Note: do NOT worry about the case when they are the same height.

    Example console session:

    ./taller.sh JJ JJ JJ
    Error: 4 parameters required
    Usage exampe: taller.sh Jenny 165 Timmy 182

    ./taller.sh Jenny JJ Timmy 156
    Error: JJ is not a number

    ./taller.sh Eva 176 Martin 165
    Eva is 176 which is taller than Martin who is 165

    ./taller.sh Mimi 166 Maxim 172
    Maxim is 172 which is taller than Mimi who is 166

    #! /bin/bash
    
    echo "Provide name1 heught1 name 2 height2"
    
    # VALIDATE 4 PARAMETERS
    if [ "$#" -ne "4" ]; then
            echo "error: you must provide four parameters: name1, height1, name2, height2"
            exit
    fi
    
    # VALIDATE 2nd and 4th params are valid integers
    echo "$2$4" | grep -E "^[0-9]+$" &>/dev/null
    if [ "$?" -ne "0" ]; then
            echo "Error: Heights must be a positive valid integer in cms"
            exit
    fi
    
    # PART 3 DOIT
    
    if [ "$2" -eq "$4" ]; then
            echo "Both have the same height"
    else
            if [ "$2" -gt "$4" ]; then
                    echo "$1 is taller than $3"
            else
                    echo "$3 is taller than $1"
            fi
    fi
    

    TASK 2.

    Create script findline.sh.
    Script requires two parameters on command line.
    Parameter 1 must be a valid path to a regular file you can read.
    Parameter 2 is any text.
    The script will use grep to find out how many lines of file (Parameter 1) contain the word passed as Parameter 2.

    Example console session:

    ./findline.sh
    Error: invalid number of parameters.
    Usage: findline.sh pathtofile word

    ./findline.sh blah.txt jerry
    Error: file blah.txt is not a regular file.

    ./findline.sh /etc/passwd stud
    Word stud found in 1 line(s) in /etc/passwd

    #!/bin/bash
     
    # 1. Check if exactly two parameters are provided
    if [ "$#" -ne 2 ]; then
        echo "Error: invalid number of parameters."
        echo "Usage: findline.sh pathtofile word"
        exit 1
    fi
    
    # Assign parameters to descriptive variables
    FILE_PATH="$1"
    SEARCH_WORD="$2"
    
    # 2. Check if the file is a regular file (-f) and is readable (-r)
    if [ ! -f "$FILE_PATH" ] || [ ! -r "$FILE_PATH" ]; then
        echo "Error: file $FILE_PATH is not a regular file."
        exit 1
    fi
    
    # 3. Use grep to count the matching lines
    # -c counts matching lines, -w ensures it matches the exact word
    LINE_COUNT=$(grep -c "$SEARCH_WORD" "$FILE_PATH")
    
    # 4. Output the result
    echo "Word $SEARCH_WORD found in $LINE_COUNT line(s) in $FILE_PATH"
    

    TASK 3

    Create executable script santafriend.sh.
    Script takes multiple names of people as parameters.
    You do NOT have to verify the number of parameters passed or their values.

    For every name on the list of parameters say “Hello …” with the name.
    However, if the name is “Santa” do NOT say “Hello…” but instead say “WOW, you, really?”

    Example console session:

    ./santafriend.sh Jerry Terry Santa Marry
    Hello Jerry
    Hello Terry
    Wow, you, really?
    Hello Marry

    #! /bin/bash
    
    # set -x
    
    # 1 3 5 7 9
    
    # VALIDATION
    # if [ "$#" -eq 1 ]; then SAME RESULT
    if [ "$#" -lt 1 ]; then
            echo "Error: you must enter at least one parameter (name or names)"
            exit
    fi
    
    for NAME in "$@"; do
            if [ "$NAME" = "Santa" ] || [ "$NAME" = "santa" ]; then
                    echo "Wow, you, really?"
            else
                    echo "Hello $NAME"
            fi
    
    done
    

    TASK 4

    Create executable findlucy.sh
    Interactively ask user for a list of friends names.
    Require that the list is not empty.
    If the list is empty then terminate with error message.
    Print each friend’s name and if you find name “Lucy” as one of the name print out a special greeting.

    Example console session:

    ./findlucy.sh
    Enter list of names on one line

    Error: you must have some friends.

    ./findlucy.sh
    Enter list of names on one line
    Jerry Lucy Terry
    You’re friends with Jerry
    OMG, you know Lucy too!
    You’re friends with Terry

    Hint: to compare for empty use … = “”

    #! /bin/bash
    
    # set -x
    
    echo "Enter list of names on one line and press Enter"
    read LIST
    
    # Alternative you can use read -p to set the variable LIST
    #read -p "Enter list of names in one line and press Enter: " LIST
    
    
    # VALIDATION
    if [ "$LIST" == "" ]; then
            echo "Error: you must enter at least one name"
            exit 1
    fi
    
    for NAME in $LIST; do
            if [ "$NAME" == "Lucy" ]; then
                    echo "OMG, you know Lucy too!?"
            else
                    echo "Hello $NAME"
            fi
    
    done
    

  • Force QUAD9 DNS

    Network Configuration Summary: Dual-Interface DNS

    1. The Strategy

    • Uniform DNS: Force Quad9 on both Wired and Wireless profiles to prevent DNS “Race Conditions.”
    • Predictable Routing: Use Route Metrics to ensure the Wired connection is always preferred over Wi-Fi when both are active.
    • Isolation: Ignore ISP-provided DNS settings entirely.

    Verify from where NetworkManager is getting its DNS. Usually Netowrk Manager will get DNS configuration from DHCP server. If your secondary network adapter (in this case a wifi adapter connected to the ISP router) is getting ISP DNSs, that might conflict with the default configuration of the wired adapter and force it to use the ISP DNS. We dont want this as we want to use QUAD9 DNS.

    sudo ls /var/lib/NetworkManager/

    Verify current DNS configuration:

    cat /etc/resolv.conf 

    2. Implementation Commands

    A. Wired Connection (Primary)

    Goal: Highest priority, direct Quad9 access.

    # Set DNS and Ignore DHCP DNS
    nmcli con mod "Wired connection 1" ipv4.dns "9.9.9.9, 149.112.112.112"
    nmcli con mod "Wired connection 1" ipv4.ignore-auto-dns yes
    
    # Set Metric to 100 (Lower = Higher Priority)
    nmcli con mod "Wired connection 1" ipv4.route-metric 100
    
    # Apply
    nmcli con up "Wired connection 1"
    

    B. Wireless Connection (Backup)

    Secondary priority, still forced to Quad9.

    # Set DNS and Ignore DHCP DNS
    nmcli con mod "ISP_WiFi_Name" ipv4.dns "9.9.9.9, 149.112.112.112"
    nmcli con mod "ISP_WiFi_Name" ipv4.ignore-auto-dns yes
    
    # Set Metric to 600 (Higher = Lower Priority)
    nmcli con mod "ISP_WiFi_Name" ipv4.route-metric 600
    
    # Apply
    nmcli con up "ISP_WiFi_Name"
    

    3. Operational Behavior

    ScenarioData PathDNS ProviderLatency
    Only Wired ActiveOpenWRTQuad9Instant
    Only Wireless ActiveISP RouterQuad9Instant
    Both ActiveWired (via Metric 100)Quad9Instant

    4. Troubleshooting & Verification

    • Check DNS Order: cat /etc/resolv.confIf both interfaces are up, you should see only Quad9 IPs. If you see the ISP router IP, ipv4.ignore-auto-dns was not set correctly.
    • Check Active Metrics: ip route show defaultLook for the metric value. The interface with the lowest number is your active internet path.
    • Force Refresh: If settings don’t seem to apply:Bashsudo systemctl restart NetworkManager

    5. Key Parameters for Records

    • Quad9 Primary: 9.9.9.9
    • Quad9 Secondary: 149.112.112.112
    • Preferred Metric: 100 (Wired)
    • Failover Metric: 600 (Wireless)

    Note: Always use the specific connection names found in nmcli con show when running these commands. If your SSID has spaces, wrap it in quotes: "My ISP WiFi".

  • cpupower

    [Unit]
    Description=Set CPU governor at boot
    After=network.target

    [Service]
    Type=oneshot
    ExecStart=/usr/bin/cpupower frequency-set -g ondemand

    [Install]
    WantedBy=multi-user.target

    auto-cpufreq setup

    To get a “flawless” setup on an Intel-based Debian laptop, you should avoid the Snap version and use the Git Installer. This ensures you get the power_helper.py script and proper system integration that Snaps often lack.

    1. Full Installation Instructions
      Open your terminal and run these in order:

    Bash

    1. Install dependencies

    sudo apt update
    sudo apt install git python3-dev python3-pip python3-venv python3-setuptools dmidecode libcairo2-dev libgtk-3-dev gcc python3-gi

    2. Clone the repository

    git clone https://github.com/AdnanHodzic/auto-cpufreq.git
    cd auto-cpufreq

    3. Run the installer

    sudo ./auto-cpufreq-installer
    During installation, choose i to install the daemon.

    1. The Critical “Debian/Intel” Cleanup
      As you saw, your governor was stuck. This is because Debian/GNOME services are fighting auto-cpufreq.

    Step A: Disable the Conflict

    Bash
    sudo systemctl stop power-profiles-daemon
    sudo systemctl mask power-profiles-daemon
    Step B: Configure for Cooling (Your 800MHz Heat Issue)
    Create the config file to force powersave and kill turbo (the main cause of idle heat).

    Bash
    sudo nano /etc/auto-cpufreq.conf
    Paste this exactly:

    Ini, TOML
    [charger]
    governor = powersave
    turbo = never

    [battery]
    governor = powersave
    turbo = never
    Save and exit (Ctrl+O, Enter, Ctrl+X).

    Step C: Restart the Daemon

    Bash
    sudo systemctl restart auto-cpufreq

    1. Setup Questions (To refine your “Flawless” config)
      To tailor this specifically to your Intel hardware, answer these:

    What is the output of cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_driver?

    If it is intel_pstate, we should check your HWP (Hardware P-State) settings.

    If it is acpi-cpufreq, your CPU is older and might need different governor names.

    Does your laptop have a dedicated GPU (Nvidia)?

    If yes, the 800MHz heat is likely the GPU “leaking” heat to the shared CPU heatsink.

    Are you using a GNOME desktop environment?

    GNOME has a “Power” slider in the top right menu. If you touch that slider, it can sometimes override these settings.

    What is the age/generation of the Intel CPU? (e.g., i5-8250U, i7-12700H)

    12th gen and newer (Hybrid architecture) require specific handling of E-cores vs. P-cores.

    Would you like me to show you how to check your C-States now that we’ve (hopefully) forced the powersave governor?

  • Simple contact form with html and php


    This code is a PHP-based contact form processor that sends emails using the msmtp command. It validates and sanitizes user input, composes an email with the user’s input, and sends it to a hardcoded recipient email address. The code prioritizes security and includes error handling and debugging mechanisms. To use this code, you’ll need to have your own email account that can work with an msmtp configuration, as it relies on this setup to send emails. Overall, the code provides a solid foundation for a contact form processor, and with some customizations, it can become even more robust and feature-rich. Expansion opportunities include adding support for multiple recipient email addresses, implementing CAPTCHA or anti-spam measures, integrating with popular email services, and allowing file attachments.

    HTML

    <style>
        /* Set a max width for the form */<br />
        form {<br />
            width: 100%;<br />
            max-width: 600px;  /* Adjust the max-width as needed */<br />
            margin: 0 auto;  /* Center the form */<br />
            padding: 20px;<br />
            background-color: #f9f9f9;<br />
            border-radius: 8px;<br />
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);<br />
        }</p>
    <p>    /* Style the labels */<br />
        label {<br />
            display: block;<br />
            margin-bottom: 8px;<br />
            font-weight: bold;<br />
        }</p>
    <p>    /* Style the input fields */<br />
        input[type="text"],<br />
        input[type="email"] {<br />
            width: 100%;  /* Make input fields full width */<br />
            padding: 10px;<br />
            margin-bottom: 15px;<br />
            border: 1px solid #ccc;<br />
            border-radius: 4px;<br />
            box-sizing: border-box;  /* Include padding in the width calculation */<br />
        }</p>
    <p>    /* Style the textarea */<br />
        textarea {<br />
            width: 100%;  /* Make the textarea full width */<br />
            height: 150px;  /* Increase the height of the message box */<br />
            padding: 10px;<br />
            margin-bottom: 15px;<br />
            border: 1px solid #ccc;<br />
            border-radius: 4px;<br />
            box-sizing: border-box;  /* Include padding in the width calculation */<br />
        }</p>
    <p>    /* Style the submit button */<br />
        button {<br />
            padding: 12px 20px;<br />
            background-color: #4CAF50;  /* Green background */<br />
            color: white;<br />
            border: none;<br />
            border-radius: 4px;<br />
            cursor: pointer;<br />
            font-size: 16px;<br />
        }</p>
    <p>    button:hover {<br />
            background-color: #45a049;  /* Slightly darker green on hover */<br />
        }</p>
    <p>    /* Add small text for the message character limit */<br />
        .char-limit {<br />
            font-size: 14px;<br />
            color: #888;<br />
            margin-bottom: 10px;<br />
        }<br />
    </style>
    <form action="/contact-process-form.php" method="POST">
        <input type="hidden" name="nonce" value="<?php echo $nonce; ?>"></p>
    <p>    <label for="name">Name:</label><br />
        <input type="text" id="name" name="name" required maxlength="100"></p>
    <p>    <label for="email">Email:</label><br />
        <input type="email" id="email" name="email" required maxlength="100"></p>
    <p>    <label for="subject">Subject:</label><br />
        <input type="text" id="subject" name="subject" required maxlength="100"></p>
    <p>    <label for="message">Message:</label><br />
        <textarea id="message" name="message" required maxlength="6000"></textarea></p>
    <p>    <!-- Add a character limit notice --><br />
        <small class="char-limit">Maximum characters allowed in message: 6000</small><br /> <!-- Added line break --></p>
    <p>    <button type="submit">Send</button><br />
    </form>

    php contact-process-form.php in root folder of website.

    <?php
    // Load WordPress functions (adjust path if necessary)
    require_once('/var/www/bashing.life/wp-load.php');
    
    error_reporting(E_ALL);
    ini_set('display_errors', 1);
    
    // Log errors to a secure file instead of displaying
    ini_set('log_errors', 1);
    ini_set('error_log', '/var/log/php_errors.log');
    
    // Define the path to msmtp (adjust according to where msmtp is installed)
    $msmtp_path = '/usr/bin/msmtp';  // Replace with your msmtp path if it's different
    
    // Define the path to the msmtp configuration file
    $msmtp_config_file = '/etc/msmtprc';  // Replace with the correct path to the msmtp configuration file
    
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Sanitize and retrieve the form data
        $name = sanitize_text_field($_POST['name']);
        $email = sanitize_email($_POST['email']);
        $subject = sanitize_text_field($_POST['subject']);
        $message = wp_kses_post($_POST['message']);  // Sanitizing message further
    
        // Validate the email address
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            echo "Invalid email format.";
            exit;
        }
    
    // Escape each variable to prevent command injection
        $safe_name = escapeshellarg($name);
        $safe_email = escapeshellarg($email);
        $safe_subject = escapeshellarg($subject);
        $safe_message = escapeshellarg($message);
    
        $hardcoded_subject = "New Contact Form Submission";
    
        $email_content = "You have received a new contact form submission:\n\n";
        $email_content .= "Name: $safe_name\n";
        $email_content .= "Email: $safe_email\n";
        $email_content .= "Subject (from form): $safe_subject\n\n";
        $email_content .= "Message:\n$safe_message\n";
    
     // Escape the full email content (to ensure no issues with newlines, quotes, etc.)
        $escaped_email_content = escapeshellarg($email_content);
    
        // Send the email using msmtp
        $recipient = 'example@example.com';  // Your recipient email address
    
        // Properly escape the command to avoid injection
    
        $command = "echo \"Subject:$hardcoded_subject\nContent-Type: text/plain; charset=UTF-8\n\n$email_content\" | $msmtp_path --file=$msmtp_config_file -a default example@example.com";
    
    
        // Execute the command and capture the output
        $output = shell_exec($command . ' 2>&1');  // Capture both stdout and stderr
    
        // Debugging: Check if output is captured and display it
        if ($output === null) {
            echo "Failed to send the message. No output received from msmtp.";
        } else {
            //echo "Message sent successfully!<br>"; //for future debugging
            //echo "<strong>Debugging Output from msmtp:</strong><br>"; //for future debugging
            //echo "<pre>$output</pre>";  // Debugging output from msmtp
            // Redirect to the thank-you page after success
            header("Location: thank-you");
            exit;
        }
    
    } else {
        echo "Please fill in all fields.";
    }
    ?>
    
    

    The msmtprc system-wide configuration file must be in /etc

  • Fixing Proxmox SSL Certificates Behind HAProxy: Step-by-Step Tutorial

    This tutorial chronicles my troubleshooting and resolution process for SSL certificate issues with Proxmox when running behind an OpenWRT router with HAProxy. It includes all intermediate steps, challenges, and reasoning, as well as interactions with my assistant, which helped guide the solution.


    1. Network Context and Initial Problem

    My setup was as follows:

    ISP Router -> OpenWRT (DMZ) with HAProxy -> Proxmox
    • Proxmox listens on its default HTTPS port 8006.
    • Other internal web servers are served through HAProxy, which handles TLS for domains like aurispetreus.net.
    • My goal was to have valid, trusted TLS certificates for Proxmox while maintaining other web services on the same HAProxy instance.

    Problem Observed

    When attempting to access Proxmox through its domain (for example, using the Proxmox Android app), I encountered SSL protocol errors. Initially, I wasn’t sure whether:

    1. Proxmox was failing to pick up the manually uploaded certificates.
    2. HAProxy configuration was interfering with TLS termination.
    3. File permissions or certificate formats were incorrect.

    2. Generating and Copying Certificates

    Proxmox could not directly request Let’s Encrypt certificates because it wasn’t publicly accessible from the internet. Therefore, I generated certificates on a separate Debian server (debian) that could reach Let’s Encrypt:

    certbot certonly -d da3.aurispetreus.net

    This created:

    /etc/letsencrypt/archive/da3.aurispetreus.net/fullchain1.pem
    /etc/letsencrypt/archive/da3.aurispetreus.net/privkey1.pem

    I then manually copied these files to Proxmox (proxmox A) and renamed them to match Proxmox’s expected filenames:

    /etc/pve/local/pve-ssl.pem       # fullchain
    /etc/pve/local/pve-ssl.key       # private key

    I also set proper permissions for the private key:

    chmod 600 /etc/pve/local/pve-ssl.key

    At this point, I suspected that the certificates might not be correctly paired, so I decided to verify them.


    3. Verifying Certificate and Key Match

    To ensure the certificate and private key matched, I used OpenSSL to check the modulus:

    openssl x509 -noout -modulus -in fullchain1.pem | openssl md5
    openssl rsa -noout -modulus -in privkey1.pem | openssl md5

    Initially, I received:

    Not an RSA key

    This indicated a misuse of commands or possibly a non-RSA key (like EC). After adjusting the method (taking into account the correct type of key generated by Certbot), I confirmed that the modulus of the certificate and the private key matched, verifying they belonged together.


    4. HAProxy Configuration for Proxmox

    Since Proxmox sits behind HAProxy, it was important that TLS traffic be forwarded correctly. I started with the following principles:

    1. Use TCP mode on HAProxy for port 443 to allow end-to-end TLS (Proxmox manages its own certificates).
    2. Route traffic using SNI to direct specific domains to their respective backend servers.
    3. Keep the standard HTTPS port (443) public, without binding Proxmox’s internal port 8006 on HAProxy.

    Here’s the relevant HAProxy frontend for HTTPS:

    frontend https_in
        bind *:443
        mode tcp
        option tcplog
    
        # Inspect TLS handshake for SNI
        tcp-request inspect-delay 5s
        tcp-request content accept if { req_ssl_hello_type 1 }
    
        # Use backend based on requested SNI
        use_backend %[req.ssl_sni,lower]_tls if { req.ssl_sni -m found }

    And the Proxmox backend:

    backend da3.aurispetreus.net_tls
        mode tcp
        option tcp-check
        server da3.aurispetreus.net 192.168.3.144:8006 check
    # Note: No need to bind HAProxy to port 8006 externally

    Important detail: The assistant reminded me explicitly:
    “No, you do not bind port 8006 on HAProxy, because HAProxy is meant to expose a public listener on the standard HTTPS port (443).”
    This avoids exposing internal Proxmox ports directly and keeps the network cleaner.


    5. Initial Testing

    I tested the TLS handshake locally:

    curl -vk https://192.168.3.144:8006/

    Output confirmed that TLSv1.3 was being used, and the correct certificate was presented.

    Externally, trying to access 188.21.68.172:8006 failed because the ISP router blocked the direct connection, which was expected.


    6. Debugging “Wrong Version Number” Error

    When testing public access via HAProxy:

    curl -vk https://da3.aurispetreus.net:443

    I got:

    error:0A00010B:SSL routines::wrong version number

    Analysis:

    • The HAProxy frontend for port 443 was in HTTP mode.
    • TLS traffic to Proxmox requires TCP passthrough, not HTTP mode.

    Solution: Change the frontend to TCP mode. After doing so, the handshake worked correctly, and the Proxmox Android app could connect.

  • Cockpit via Apache Reverse Proxy

    I know, this is very unsafe if your login credentials are stolen but it serves as a proof of concept!!!

    1. The Goal

    To provide secure, external access to the Cockpit Web Console via https://example.site/cockpit/ without opening extra ports (like 9090) on the router and without managing separate SSL certificates for the dashboard.

    2. Architecture Flow

    1. User requests https://example.site/cockpit/.
    2. OpenWrt (HAProxy) receives traffic on port 443 and passes it to the Debian LXC (192.168.1.16:443).
    3. Apache (inside LXC) terminates the SSL using Let’s Encrypt certificates.
    4. Apache proxies the request internally to 127.0.0.1:9090.
    5. Cockpit processes the request and responds through the tunnel.

    3. Key Configurations

    A. Apache VirtualHost (/etc/apache2/sites-available/...)

    We used mod_proxy and mod_rewrite to handle both standard web traffic and the persistent WebSocket connections required for the Cockpit terminal.

    # WebSocket Upgrade (Fixes "Login then Blank Page" issue)
    RewriteEngine On
    RewriteCond %{HTTP:Upgrade} =websocket [NC]
    RewriteRule /cockpit/(.*) ws://127.0.0.1:9090/cockpit/$1 [P,L]
    
    # Subfolder Proxy
    <Location /cockpit/>
        ProxyPass http://127.0.0.1:9090/cockpit/
        ProxyPassReverse http://127.0.0.1:9090/cockpit/
    </Location>

    B. Cockpit Config (/etc/cockpit/cockpit.conf)

    Crucial for preventing CSRF (Cross-Site Request Forgery) security blocks and allowing the unencrypted internal “handshake.”

    [WebService]
    Origins = https://hissite.org
    ProtocolHeader = X-Forwarded-Proto
    AllowUnencrypted = true
    UrlRoot = /cockpit

    4. Troubleshoot Log & Fixes

    • Issue:sscg: command not found.
      • Fix: Installed sscg package to satisfy Cockpit dependencies.
    • Issue:gnutls_handshake failed: A TLS fatal alert.
      • Reason: Cockpit was expecting HTTPS but Apache was sending HTTP.
      • Fix: Added AllowUnencrypted = true and restarted cockpit.socket.
    • Issue: Blank page after login.
      • Reason: WebSockets (the “live” part of the site) were failing to tunnel through Apache.
      • Fix: Added specific RewriteRule for ws:// protocol.

    5. Security Hardening Applied

    • Consolidated SSL: All traffic uses the main site’s hardened TLS 1.2/1.3 settings.
    • Internal Communication: Apache talks to Cockpit over 127.0.0.1 (local loopback), meaning no unencrypted traffic ever touches your LAN or the WAN.

    6. Maintenance Commands

    If Cockpit ever stops responding, run these in order:

    1. sudo systemctl restart cockpit.socket (Restarts the listener)
    2. sudo systemctl restart apache2 (Restarts the proxy)
    3. sudo journalctl -u cockpit -f (To watch live logs if a crash occurs)