How to Monitor Ip Address Changes


Problem Situation

For work I have both a desktop (Mac Mini) and a laptop (MacBook Pro). As one would expect I use the laptop when I need to be away from my desk and the desktop computer. A considerable amount of my work happens in the terminal. By using tmux I’m able to create a session on the desktop and then remotely access it from my laptop.

This work fantastically, until the desktop gets a new IP address and I can’t remote in. If I’m at home I can walk to the other computer, and check its IP address. Annoying but no big deal. When I’m not at home, I’m stuck.

Solution

I created a bash script that checks the current IP address against a saved one. If they match nothing happens. If they are different the script creates a draft email that has the new IP address in it. And it posts a notification that the IP address has changed.

I used a draft email since I can access my mailbox from either computer; no need to send it, just open the draft and copy the new IP address.

The script is managed through a Launch Agent. It runs every five minutes. Worst case scenario is I’d have to wait 5 minutes to get the updated IP address. I think the only time I lose the current IP address is when my Aruba RAP (remote access point) loses power and reboots, so I’m not expecting to get IP address changes email drafts too often.

The script

Here’s the bash script. It needs to be on the PATH and executable for this to work.

 1#!/usr/bin/env bash
 2# vim: ft=bash
 3
 4# File to store previous IP
 5IP_FILE="$HOME/.current_ip"
 6
 7# Get current local IP (adjust interface if needed)
 8CURRENT_IP=$(ipconfig getifaddr en0)
 9
10# Fallback if en0 doesn’t work (e.g., on Ethernet it might be en1 or enX)
11if [ -z "$CURRENT_IP" ]; then
12  CURRENT_IP=$(ipconfig getifaddr en1)
13fi
14
15# Read stored IP
16if [ -f "$IP_FILE" ]; then
17  STORED_IP=$(cat "$IP_FILE")
18else
19  STORED_IP=""
20fi
21
22# Compare and notify
23if [ "$CURRENT_IP" != "$STORED_IP" ]; then
24  echo "$CURRENT_IP" > "$IP_FILE"
25
26  # Create and save a draft email with the IP address
27  osascript <<EOF
28tell application "Mail"
29    set newMessage to make new outgoing message with properties {subject:"Desktop IP Changed", content:"The new IP address is $CURRENT_IP", visible:true}
30    tell newMessage
31        make new to recipient at end of to recipients with properties {address:"mhn@ksu.edu"}
32    end tell
33end tell
34EOF
35
36  osascript -e "display notification \"IP changed to $CURRENT_IP\" with title \"IP Monitor\""
37fi

Launch Agent Plist

Instead of using a cron job to manage the running of the script, the MacOS preferred way is to use a Launch Agent.

  • It works reliable across sleep/wake cycles
  • It’s the Apple-recommended method
  • It runs in your user context (so Mail.app and notification work properly)
  • It persists across reboots

The Launch Agent requires a plist file to define it.

 1<?xml version="1.0" encoding="UTF-8"?>
 2<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertiesList-1.0.dtd">
 3<plist version="1.0">
 4<dict>
 5  <key>Label</key>
 6  <string>com.user.ipmonitor</string>
 7
 8  <key>ProgramArguments</key>
 9  <array>
10    <string>/Users/USERID/bin/bash/ip_monitor</string>
11  </array>
12
13  <key>StartInterval</key>
14  <integer>300</integer>
15
16  <key>RunAtLoad</key>
17  <true/>
18
19  <key>StandardOutPath</key>
20  <string>/tmp/ipmonitor.log</string>
21
22  <key>StandardErrorPath</key>
23  <string>/tmp/ipmonitor.err</string>
24</dict>
25</plist>

You’ll need to substitute your account ID for USERID on line 10.

The plist defines the script location, sets the interval for how often to execute it (5 minutes (300 seconds)), and defines locations for logging and error messages.

Managing the Launch Agent

The plist needs to be copied to the user’s Library/LaunchAgent directory. I had to create this directory on my computer.

cp com.user.ipmonitor.plist ~/Library/LaunchAgents/com.user.ipmonitor.plist

To launch the agent:

launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.user.ipmonitor.plist

The start/enable the service:

launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.user.ipmonitor.plist

To check if the service is running:

launchctl list | grep ipmonitor

To kick the service, if it is already loaded:

launchctl kickstart gui/$(id -u)/com.user.ipmonitor

Logs can be viewed:

tail -f /tmp/ipmonitor.log /tmp/ipmonitor.err

Troubleshooting

Make sure the plist file path is correct. Verify with:

ls -la ~/Library/LaunchAgents/com.user.ipmonitor.plist

Verify you updated the user name in the plist.

Check plist syntax

plutil -lint ~/Library/LaunchAgents/com.user.ipmonitor.plist

Ensure the script is executable:

chmod +x ip_monitor

If you still get errors after bootstrap, run:

launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.user.ipmonitor.plist 2>&1

This will show the actual error message, which will help troubleshoot the issue.

Repository

I have a Git repository with the script, plist, and a detailed README: ip_monitor


Git Dual Remotes


I am using both GitHub and Codeberg for my Git repositories. It is possible to setup multiple push URLs for a given repository. This allows you to interact with both remotes with a single command. Here’s how.

# Set up origin at GitHub
git remote add origin git@github.com:zanshin/repo.git

# Add Codeberg as a second push URL to origin
git remote set-url --add --push origin ssh://git@codeberg.org/zanshin/repo.git
git remote set-url --add --push origin git@github.com:zanshin/repo.git

Once the push URLs are set, running git remote -v will show one remote as the fetch remote and both as push remotes.

origin  git@github.com:zanshin/repo.git (fetch)
origin  git@github.com:zanshin/repo.git (push)
origin  git@codeberg.org/zanshin/repo.git (push)

With this configuration, git pull will only pull from the fetch remote, in the example above, GitHub. git push will push to both remotes.

Using Jujutsu, jj, you can push to all URLs using

jj git push --all-remotes

Using git for repository interactions there may be drift between the remotes, since pulls are only from the fetch remote. Periodic pulls from the other remote will be necessary to stay in sync.

Using Jujutsu, jj, for repository interactions allows you to use

jj git fetch --all-remotes

which will fetch from multiple remotes simultaneously.

The key point is that git pull only uses the fetch URL, while git push uses all push URLs.


64 Albums


An Album per Year

I’m 64 years old, so 64 albums. In no particular order.

Genesis - The Lamb Lies Down on Broadway
The Beatles - Let It Be
Rush - Moving Pictures
Boston - Boston
Marillion - Script for a Jester’s Tear

John Denver - Live
Phil Collins - In the Air Tonight
Peter Gabriel - Security
Tony Banks - Curious
Mike Rutherford - Mike and the Mechanics

Pablo Casals - Bach Cello Suites
Yo-Yo Ma - Bach Cello Suites
Truls Mørk - Bach Cello Suites
Janos Starker - Bach Cello Suites
Mistislav Rostropovich - Bach Cello Suites

Zöe Keating - Into the Trees
Styx - Suite Madam Blue
Yes - Yesshows
Led Zeppelin - How the West was Won
Peter Gabriel - i/o

Evanescence - The Open Door
Mike Oldfield - Tubular Bells
Kate Bush - Hounds of Love
Sol Gabetta - Prayer
Johnny Cash - American IV: The Man Comes Around

Film & the BBs - Tricycle
The Beatles - Let It Be (Naked)
Alannah Myles - Alannah Myles
Steve Winwood - Back in the High Life
Supertramp - Crime of the Century

Paul Simon - Graceland
The Nylons - Happy Together
Martin Page - In the House of Light and Stone
Michael Penn - March
Yes - Fragile

ZZ Top - Antenna
Boston - Boston
Melissa Etheridge - Brave and Crazy
Dire Straits- Brothers in Arms
Pink Floyd - Delicate Sound of Thunder

Anthony Phillips - The Geese and the Ghost
Fleetwood Mac - Greatest Hits
Rodrigo y Gabriela - Rodrigo y Gabriela
U2 - Songs of Innocence
Jethro Tull - Thick as a Brick

Queen - Classic Queen
Eagles - The Very Best Of
Heart - The Essential Heart
Styx - The Grand Illusion
The Police - Synchronicity

Atomic Blonde - Atomic Blond Soundtrack
The Beatles - Love
Oblivion - Oblivion Soundtrack
Daft Punk - Iron Legacy Soundtrack
Tracy Chapman - Tracy Chapman

Nigel Stanford - Automatica
Massive Attack - Mezzanine
Afro Celt Sound System - Further in Time
Lorenna McKennitt - Nights from the Alhambra (Live)
Nancy Griffith - One Fair Summer Evening (Live)

Leonard Bernstein, Wiener Philharmoniker - Beethoven Ninth Symphony
REO Speedwagon - The Hits
Mike Oldfield - The Songs of a Distance Earth
K. D. Lang - Absolute Torch and Twang


Amazon Is Hard to Resist


There are many areas of my life where I am privileged. One is disposable income. I can afford to buy the things I want, usually without much thought to the price. I would love to support smaller, independent book sellers, but there are times when the price and convenience of Amazon is very hard to resist.

Case in point. I learned about a new book, “Notes for Cellists: A Guide to the Repertoire” by Miranda Wilson" today. The original link the book was to the Juilliard Store. I also looked for it on Bookshop.org, and on Amazon.

Juilliard Store - $ 34.95 for the book. Least expensive shipping: $ 22.95. Total cost $ 57.14. Yes 71% of the purchase price to ship a paperback book.

Bookshop.org - $ 40.19 for the book. Shipping is $ 3.99, and tax is $ 3.68, for a total of $ 47.86. 4-10 days for delivery.

Amazon.com - $ 28.38. Shipping - free(-ish). Arrives in two days. Amazon’s search results had another book that looked interesting, “Digital Grace Notes: One Cellist’s Journey” by Greg Fiocca, for $12.99. I’m getting both books from Amazon for $ 45.16.

I am buying more and more books via Bookshop.org these days, but being able to get two spur-of-the-moment books for less than one costs elsewhere was impossible to resist today.

(Amazon shipping is $138 per year. Or, $138 shipping for the first purchase of the year, then the rest are free.)


How to Use Homebrew `bash` in Macos


Out of the box, MacOS Sequoia uses an older version of bash, to use an up-to-date version install bash via Homebrew and then set your shell to the Homebrew version.

Install Homebrew bash

brew install `bash`

Locate the Homebrew bash executable

ls "$(brew --prefix)/bin/bash"

On Apple Silicone this will return something like

/opt/homebrew/bin/bash

Preview current list of shells

cat /etc/shells

Which will show a list like

# List of acceptable shells for chpass(1).
# Ftpd will not allow users to connect who are not using
# one of these shells.

/bin/bash
/bin/csh
/bin/dash
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh

Append Homebrew bash to shells list

echo "$(brew --prefix)/bin/bash" | sudo tee -a /etc/shells;

Verify that the append worked

cat /etc/shells
# List of acceptable shells for chpass(1).
# Ftpd will not allow users to connect who are not using
# one of these shells.

/bin/bash
/bin/csh
/bin/dash
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh
/opt/homebrew/bin/bash

Set your shell to the Homebrew version of bash

chsh -s "$(brew --prefix)/bin/bash"

Enter your password when prompted.

Restart your terminal

In order for the new shell to be used, you will have to quit and restart your terminal. Afterward you can verify your new bash version.

echo $BASH_VERSION


Separating Work and Personal Computing


A few days ago I wrote about my adventures with Apple IDs. I was able to resolve the situation by resetting the original work Apple ID I had created.

After resetting the password, I signed into the account.apple.com page. There I setup new security questions, and I set up the shipping address and added a phone number. I couldn’t reuse my cell phone number but I was able to use a freshly created Google Voice number.

Then I signed into the Apple ID in the Settings app in MacOS. Finally I opened up the App Store, and when I was asked to review my account information, it was pre-filled, and the form worked as expected. Previous the form had not be pre-filled, leading me to think I had inadvertently done something out of order.

With a working Apple ID based on my work email address, I am one step closer to separating my work and personal computing personas. I am not done, however.

I have two work provided computers: a M2 14" MacBook Pro, and the new M4 Mac Mini. The MacBook Pro still has the previous generation JAMF remote management software in place, which has less strict policies. I can use Passwords on that machine. I expect JAMF to be replaced at some point (likely with little or no warning), so I want to migrate it to the new Apple ID. Lots of things are tied to ones Apple ID, so I need to make sure I have back ups, and know which settings and apps will need to be redone following an Apple ID switch.

The other place where my work and personal worlds collide is GitHub. I’ve been using my personal account for work. I added my work email address, and I use that when doing any Git related work for my employer, but it is still my personal account.

Where this gets messy is two-factor authorization. What started all this was the inability to use the MacOS Passwords app under the Intune remote management policies in place. Passwords is where the 2FA token for my GitHub account is generated. (Yeah. Using the same software to store both the password and 2FA token for an account defeats the purposed. That’s a problem for another day.)

If I don’t create a work GitHub account, that has its own 2FA token, then I’ll have to use my iPhone or personal laptop anytime I need to provide GitHub with a 2FA token. Cumbersome, but doable.

If I do create a new work GitHub account, there is some work to be done to get me added to the organization, and setup on all the teams and repositories I have access to. Not much work, but some.

My configuration for Git (and most other tools I use), is stored in a “dotfiles” repository. Recently I read Configuring SSH Keys for Multiple GitHub Accounts, which shows how to setup your Git configuration to seamlessly switch between GitHub accounts. By employing that, I could keep a unified Git configuration in my dotfiles repository, and use separate accounts for my personal and work Git activities.

All of this may seem like a lot of work for very little gain. It may even seem unnecessary, but as security concerns at work are generating more and more controls and checks, I want to have as much separation between my stuff and their stuff.


AppleID Adventures


Two days ago I received a new work computer, an M4 Mac Mini with 32GB memory and 1 TB storage. Yay me. Getting it setup and configured as been surprisingly difficult.

Remote Management

My employer is using remote management software on all computers. This is the only sane way to ensure that devices are kept up-to-date, and that unwanted or unsafe software and configurations aren’t employed.

Getting the policies fine tuned is the tricky part.

During the initial boot of the Mac Mini, I created a user account for myself. Since it was the only account on the machine, by default, is was an Admin account. During the initial startup following that there was a notification about Intune running. Intune is the remote management software being used. Unbeknownst to me, one of the policies it applied converted my account from Admin to Standard. More on this later.

iCloud

Another policy blocks using iCloud, in particular the syncing of the Passwords app. Without iCloud, Passwords won’t work. The answer from our help desk was to use the officially supported LastPass.

In order to not have to copy and paste passwords all day, I’d need to either (a) install the LastPass extension in Safari (my browser of choice), or (2) use a different browser, like Firefox.

Firefox

After downloading Firefox I tried to install it and was blocked. When I put my password in I wasn’t allowed to add the program. After trying a couple times, and even re-downloading the app in case it was corrupt, I stated poking around. Eventually I looked at my user account and saw that it was set to Standard.

With a call from my boss, and a trouble ticket I was given an id and password I could use to elevate my account to Admin. Once I did that I could install Firefox.

AppleID

The mistake I made many, many years ago, was not creating a separate AppleID for work. Instead, I, like I suspect many people, simply used my personal AppleID for work. This has not been an issue.

The issue now is not wanting to have the LastPass extension in Safari on my personal machines. Thanks to my AppleID that’s exactly what will happen if I add the extension on my work computer.

So I created a new AppleID. At first I tried to resurrect an old, unused AppleID created with my work email address years ago, that I never did anything with. Unfortunately it doesn’t have two-factor authorization setup and I wasn’t able to authenticate it. So a new AppleID. I work for (perhaps) the only University that has two .edu domains. Normally I use the shorter one, but by using the other one, I could create a new AppleID that still used my work email.

After creating the AppleID I was able to sign in to my account inside the Settings app. However, when I tried to apply app updates via the AppStore, I needed to sign in again, and provide an optional payment method, a shipping address, and a phone number.

Every time I filled in the form and hit submit it would highlight the address fields, and the phone number field and tell me to fill them in. Which they were already.

Support Chat

This led to the first of several Apple Support Chats. We tried signing into music.apple.com and into icloud.com. The iCloud sign in worked, but music.apple.com just displays a blank dialog with a spinner that never completes.

I was told to clear the cache and cookies, and erase the browser history. Which killed that chat session. I was told to try from a different WiFi access point. I said, “Really? How many access points do you think I have at home? And, by the way, I’m connected via Ethernet.”

After being passed around to different advisers, I was told to try updating my shipping address and phone number through icloud.com. That dialog gave an error message that said it couldn’t verify that phone number as it was already in use. Which is true. It’s my only phone number and is associated with my personal AppleID.

While the adviser was talking to someone else about this, I pulled up Google Voice and created a new phone number. Entering that phone number did not solve the issue. The phone number is updated in icloud.com, but trying to update apps via the AppStore still pulls up the account review dialog, which still insists I haven’t filled in the address and phone number fields.

Maybe it’s a timing issue. That not enough time as elapsed from changing the phone number in iCloud to accessing the AppStore. The fact that iCloud had a shipping address previously, and the AppStore didn’t pick up on it, makes me think it’s not a timing issue. But who knows?

The Apple support adviser wants me to make a screen capture of my trying to update apps, and send that to them. They are also going to contact me to capture some diagnostics. Apparently the diagnostic level of support could take up to 5 business day. Effectively a week from today. Which is nuts. And unacceptable.

Pending

The whole thing is now in a pending state. I can setup and install software that dos not come via the AppStore. But there are several apps I need from that source.

In the past my Apple “out of box” experiences have been far superior to this. Some of the issue is on Apple (why doesn’t their form work?) and some of it is on me (does separation of my personal AppleID and work AppleID really matter?). I know (hope) it will all be resolved, and soon.

If I could send a message to me in 1993, I’d say, “Create a separation between your computing and your employer’s. Don’t reuse accounts or share resources.” Sounds like common sense, but not having to create separate accounts for the same resources is that path of less resistance.

The epilogue to all this is my work laptop. Until now it has used my personal AppleID. Once I get the Mini sorted out, and the new work AppleID is working, I’ll sign out of the personal account and into the work one on that machine. Fingers crossed that this doesn’t result in another day and a half of frustration.


Forty Years of Flying


For Thanksgiving 1984 I traveled from Decatur IL to Orlando FL. It was my first commercial airline flight. Turboprop plane on Ozark Airlines. I vaguely remember getting breakfast on the flight. It was new, exciting, and made me feel like an adult.

Today, more or less forty years to the day later, my wife and I traveled from Manhattan KS to Las Vegas NV via Dallas. Flying has changed a lot in forty years, some things are better perhaps, others are worse.

For only the second time in my life, we flew first class. We upgraded a couple weeks ago, deciding that we could splurge a bit. This morning when we got up it was snowing, fairly heavily. As we were about to depart the house I got an email saying our flight had been delayed. Our connection time in Dallas was already short enough that our boarding passes had a warning on them about minimal time to get from gate to gate.

When we checked in at the Manhattan airport the agent said we would certainly miss our connection in Dallas. She booked us on a later flight, but wasn’t able to put us in 1st class. Instead we were in rows 34 and 36, on the aisle.

Our delayed flight made up lots of time and we landed in time to get to our original flight. But we weren’t on that flight any more, and there was no room for us. We hiked to the nearest service desk, where we were able to get two seats in 1st class on the replacement flight, again in different rows.

When we got to the gate I was ready to pounce on the agent to see if someone would trade, allowing my wife and I to sit together. With about 30 minutes to go we noticed that sign at the gate had changed, our flight was now in a different terminal. Since we had switched flights we weren’t getting delay notifications on our phones. Fortunately we were able to get to the changed gate in time.

We were able to swap seats with someone, which allowed us to sit together for the 3 hour flight to Las Vegas. The extra space was marvelous.

Both of us were pleasantly surprised to learn we got a meal. Not just half a can of soda and some stale pretzels, an actual meal. On plates. With metal silverware. A surprisingly good meal– chicken enchilada with rice, a little salad, and some cheesecake. Outstanding.

In the end it was a good day, we arrived safely, all our bags arrived with us, and we got to ride in 1st class. Flying does save time. It would have been a 17 hour drive to get from Manhattan to Las Vegas. This being the first week of December, an extended road trip through the Rockies, seemed like a bad idea. Door to door was 11 hours flying.

We were both exhausted by the end of the day, partly due to traveling, but also due to not being used to so many people, and so much stimulus. We live a quiet life, and, especially since the pandemic, we have lost our ability to “be out among the English”.

We both enjoy going places and seeing things, but we are aware that it is costly, and not only monetarily but emotionally and mentally.


MomBoard E-Ink Display for Parent With Amnesia


A moving article about using ingenuity and software, with an e-ink display, to vastly improve a parents quality of life.


Reading or About to Read


The greatest gift my parents gave me was a love of reading. I read every day. Most of the time I am reading several books at once. Here’s a list of what I’m currently in the middle of, and what is in the “to be read” pile.

Reading

Listening

To Be Read

Note: In my book (ha!) an audiobook counts as reading the book. You hear every word, no skipping around. A well read audiobook is a delight.