<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Andy Dixon: Blog</title>
  <subtitle>Daily technical writing by Andy Dixon: Go and Rust internals, Linux and security how-tos, cryptography and UK privacy law, checked against source.</subtitle>
  <link href="https://dixon.cx/blog/feed.xml" rel="self" type="application/atom+xml"></link>
  <link href="https://dixon.cx/blog" rel="alternate" type="text/html"></link>
  <id>https://dixon.cx/blog</id>
  <updated>2026-09-17T03:39:30Z</updated>
  <author>
    <name>Andy Dixon</name>
    <uri>https://dixon.cx/</uri>
  </author>
  <rights>Copyright 2026 Andy Dixon</rights>
  <entry>
    <title>Go&#39;s log/slog: Structured Logging Without Reaching for a Third-Party Logger</title>
    <link href="https://dixon.cx/blog/go-slog-structured-logging.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-slog-structured-logging.html</id>
    <published>2026-09-17T03:39:30Z</published>
    <updated>2026-09-17T03:39:30Z</updated>
    <summary>How Go&#39;s log/slog package gives you structured, leveled logging with context propagation, without adding zap or zerolog to go.mod.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="slog"></category>
    <category term="structured-logging"></category>
    <category term="logging"></category>
    <category term="context"></category>
    <category term="observability"></category>
  </entry>
  <entry>
    <title>Go&#39;s GOMEMLIMIT: Keeping the OOM Killer Away From a Container</title>
    <link href="https://dixon.cx/blog/go-gomemlimit-oom-killer-containers.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-gomemlimit-oom-killer-containers.html</id>
    <published>2026-09-16T23:40:07Z</published>
    <updated>2026-09-16T23:40:07Z</updated>
    <summary>Why a Go service can be OOM-killed inside a memory-limited container despite having a garbage collector, and how GOMEMLIMIT fixes the pacing.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="gomemlimit"></category>
    <category term="garbage-collection"></category>
    <category term="containers"></category>
    <category term="kubernetes"></category>
    <category term="cgroups"></category>
  </entry>
  <entry>
    <title>Digital Forensics 101: Why dd and a Hash Beat cp When Imaging a Drive</title>
    <link href="https://dixon.cx/blog/forensic-disk-imaging-dd-vs-cp.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/forensic-disk-imaging-dd-vs-cp.html</id>
    <published>2026-09-16T19:39:25Z</published>
    <updated>2026-09-16T19:39:25Z</updated>
    <summary>Why bit-for-bit disk imaging with dd, a write blocker and a SHA-256 checksum beats a filesystem copy when acquiring a drive for forensic analysis.</summary>
    <category term="Security"></category>
    <category term="forensics"></category>
    <category term="dd"></category>
    <category term="disk-imaging"></category>
    <category term="sha256"></category>
    <category term="chain-of-custody"></category>
    <category term="linux"></category>
  </entry>
  <entry>
    <title>Go&#39;s io.Copy Can Write Gigabytes Before Reporting an Error</title>
    <link href="https://dixon.cx/blog/go-io-copy-partial-writes-errors.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-io-copy-partial-writes-errors.html</id>
    <published>2026-09-16T15:41:30Z</published>
    <updated>2026-09-16T15:41:30Z</updated>
    <summary>Learn why io.Copy can partially mutate a destination before failing, how its byte count helps, and when to stage writes for an atomic result.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="io-copy"></category>
    <category term="error-handling"></category>
    <category term="files"></category>
    <category term="streaming"></category>
    <category term="debugging"></category>
  </entry>
  <entry>
    <title>TOTP From Scratch in Go: Implementing RFC 6238 Without a Library</title>
    <link href="https://dixon.cx/blog/totp-from-scratch-in-go-rfc6238.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/totp-from-scratch-in-go-rfc6238.html</id>
    <published>2026-09-16T03:39:49Z</published>
    <updated>2026-09-16T03:39:49Z</updated>
    <summary>How the six digits in your authenticator app are actually produced: HMAC-SHA1, dynamic truncation and time steps, built in plain Go.</summary>
    <category term="Cryptography"></category>
    <category term="go"></category>
    <category term="totp"></category>
    <category term="hotp"></category>
    <category term="rfc6238"></category>
    <category term="hmac-sha1"></category>
    <category term="mfa"></category>
  </entry>
  <entry>
    <title>OAuth 2.0 Device Authorization Grant: How CLI Tools Log In Without a Browser Redirect</title>
    <link href="https://dixon.cx/blog/oauth-device-authorization-grant-cli-login.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/oauth-device-authorization-grant-cli-login.html</id>
    <published>2026-09-15T23:39:35Z</published>
    <updated>2026-09-15T23:39:35Z</updated>
    <summary>RFC 8628 explained: how tools like gh, docker and kubectl authenticate on headless machines by polling a token endpoint instead of a browser redirect.</summary>
    <category term="Security"></category>
    <category term="oauth2"></category>
    <category term="device-authorization-grant"></category>
    <category term="rfc8628"></category>
    <category term="cli"></category>
    <category term="authentication"></category>
    <category term="go"></category>
  </entry>
  <entry>
    <title>Go&#39;s errgroup: Cancelling Goroutines Without Reinventing sync.WaitGroup</title>
    <link href="https://dixon.cx/blog/go-errgroup-cancelling-goroutines.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-errgroup-cancelling-goroutines.html</id>
    <published>2026-09-15T19:39:26Z</published>
    <updated>2026-09-15T19:39:26Z</updated>
    <summary>How golang.org/x/sync/errgroup collects errors, cancels sibling goroutines on first failure, and bounds concurrency without a semaphore channel.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="errgroup"></category>
    <category term="concurrency"></category>
    <category term="goroutines"></category>
    <category term="context"></category>
    <category term="sync-waitgroup"></category>
  </entry>
  <entry>
    <title>Go&#39;s errors.Join: Combining Errors Without Losing errors.Is</title>
    <link href="https://dixon.cx/blog/go-errors-join-combining-errors.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-errors-join-combining-errors.html</id>
    <published>2026-09-15T17:22:11Z</published>
    <updated>2026-09-15T17:22:11Z</updated>
    <summary>How errors.Join builds a tree of errors that still works with errors.Is and errors.As, and where the abstraction leaks.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="error-handling"></category>
    <category term="errors-join"></category>
    <category term="errors-is"></category>
    <category term="multierror"></category>
    <category term="debugging"></category>
  </entry>
  <entry>
    <title>DKIM, SPF and DMARC for Self-Hosted Mail: A Practical Setup</title>
    <link href="https://dixon.cx/blog/dkim-spf-dmarc-self-hosted-mail.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/dkim-spf-dmarc-self-hosted-mail.html</id>
    <published>2026-09-15T12:25:10Z</published>
    <updated>2026-09-15T12:25:10Z</updated>
    <summary>A step-by-step guide to configuring SPF, DKIM and DMARC for a self-hosted mail server, and why the DNS records alone will not stop spam folders.</summary>
    <category term="Security"></category>
    <category term="spf"></category>
    <category term="dkim"></category>
    <category term="dmarc"></category>
    <category term="email"></category>
    <category term="postfix"></category>
    <category term="self-hosting"></category>
  </entry>
  <entry>
    <title>Shamir&#39;s Secret Sharing in Go: Splitting a Key So No Single Person Holds It</title>
    <link href="https://dixon.cx/blog/shamirs-secret-sharing-in-go.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/shamirs-secret-sharing-in-go.html</id>
    <published>2026-09-15T11:42:55Z</published>
    <updated>2026-09-15T11:42:55Z</updated>
    <summary>How Shamir&#39;s Secret Sharing splits a key into shares using polynomial interpolation over GF(256), with a working Go implementation.</summary>
    <category term="Cryptography"></category>
    <category term="go"></category>
    <category term="cryptography"></category>
    <category term="secret-sharing"></category>
    <category term="key-management"></category>
    <category term="finite-fields"></category>
    <category term="threshold-cryptography"></category>
  </entry>
  <entry>
    <title>Age Verification Under the Online Safety Act: What &#39;Highly Effective&#39; Actually Means in Practice</title>
    <link href="https://dixon.cx/blog/age-verification-online-safety-act-highly-effective.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/age-verification-online-safety-act-highly-effective.html</id>
    <published>2026-09-15T03:40:40Z</published>
    <updated>2026-09-15T03:40:40Z</updated>
    <summary>Ofcom&#39;s &#39;highly effective&#39; age assurance rests on four criteria, not a fixed toolset, and 2026 enforcement shows what that means for real services.</summary>
    <category term="Privacy Law"></category>
    <category term="uk-law"></category>
    <category term="online-safety-act"></category>
    <category term="age-verification"></category>
    <category term="ofcom"></category>
    <category term="privacy"></category>
    <category term="ico"></category>
  </entry>
  <entry>
    <title>Encrypted Client Hello: The TLS Extension That Finally Hides Which Site You&#39;re Visiting</title>
    <link href="https://dixon.cx/blog/encrypted-client-hello-tls-sni-privacy.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/encrypted-client-hello-tls-sni-privacy.html</id>
    <published>2026-09-14T23:42:01Z</published>
    <updated>2026-09-14T23:42:01Z</updated>
    <summary>TLS 1.3 still leaks the hostname you&#39;re connecting to in plaintext. Here&#39;s how Encrypted Client Hello fixes that, and where it still falls short.</summary>
    <category term="Security"></category>
    <category term="tls"></category>
    <category term="ech"></category>
    <category term="sni"></category>
    <category term="encryption"></category>
    <category term="networking"></category>
    <category term="privacy"></category>
  </entry>
  <entry>
    <title>seccomp-bpf in Go: Restricting Syscalls Without a Container</title>
    <link href="https://dixon.cx/blog/seccomp-bpf-go-restricting-syscalls-without-a-container.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/seccomp-bpf-go-restricting-syscalls-without-a-container.html</id>
    <published>2026-09-14T19:41:29Z</published>
    <updated>2026-09-14T19:41:29Z</updated>
    <summary>How to build and install a seccomp-bpf syscall filter from a plain Go binary with golang.org/x/net/bpf, and why goroutines need the TSYNC flag.</summary>
    <category term="Systems Programming"></category>
    <category term="go"></category>
    <category term="seccomp"></category>
    <category term="linux"></category>
    <category term="security"></category>
    <category term="bpf"></category>
    <category term="syscalls"></category>
  </entry>
  <entry>
    <title>The UK-US Data Bridge: Where GDPR Adequacy Actually Stands in 2026</title>
    <link href="https://dixon.cx/blog/uk-us-data-bridge-gdpr-adequacy-2026.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/uk-us-data-bridge-gdpr-adequacy-2026.html</id>
    <published>2026-09-14T15:42:48Z</published>
    <updated>2026-09-14T15:42:48Z</updated>
    <summary>A status check on the UK-US Data Bridge: PCLOB&#39;s quorum collapse, the Latombe appeal at the CJEU, and the UK&#39;s own EU adequacy renewal.</summary>
    <category term="Privacy Law"></category>
    <category term="uk-law"></category>
    <category term="gdpr"></category>
    <category term="data-protection"></category>
    <category term="data-privacy-framework"></category>
    <category term="privacy"></category>
    <category term="ico"></category>
  </entry>
  <entry>
    <title>Go&#39;s testing/synctest: Testing Concurrent Code Without Sleeping in Tests</title>
    <link href="https://dixon.cx/blog/go-synctest-testing-concurrent-code.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-synctest-testing-concurrent-code.html</id>
    <published>2026-09-14T11:40:51Z</published>
    <updated>2026-09-14T11:40:51Z</updated>
    <summary>How Go 1.25&#39;s testing/synctest package lets you test timers, retries and debounce logic deterministically, without real time.Sleep calls.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="testing"></category>
    <category term="synctest"></category>
    <category term="concurrency"></category>
    <category term="goroutines"></category>
    <category term="timers"></category>
  </entry>
  <entry>
    <title>Go&#39;s rate.Limiter: Token Buckets Explained by Reading the Source</title>
    <link href="https://dixon.cx/blog/go-rate-limiter-token-buckets-source.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-rate-limiter-token-buckets-source.html</id>
    <published>2026-09-14T03:40:19Z</published>
    <updated>2026-09-14T03:40:19Z</updated>
    <summary>A walk through golang.org/x/time/rate&#39;s actual source to see how Go&#39;s token bucket limiter tracks tokens without a background goroutine.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="rate-limiting"></category>
    <category term="token-bucket"></category>
    <category term="concurrency"></category>
    <category term="golang-x-time"></category>
    <category term="networking"></category>
  </entry>
  <entry>
    <title>Linux pidfds: Closing the PID Reuse Race in Supervisors</title>
    <link href="https://dixon.cx/blog/linux-pidfds-closing-pid-reuse-race.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/linux-pidfds-closing-pid-reuse-race.html</id>
    <published>2026-09-13T23:42:01Z</published>
    <updated>2026-09-13T23:42:01Z</updated>
    <summary>Learn how Linux pidfds provide a stable handle for polling, signalling and waiting without accidentally targeting a reused PID.</summary>
    <category term="Systems Programming"></category>
    <category term="linux"></category>
    <category term="pidfd"></category>
    <category term="process-supervision"></category>
    <category term="signals"></category>
    <category term="epoll"></category>
    <category term="systems-programming"></category>
  </entry>
  <entry>
    <title>Go&#39;s comparable Constraint: Why a Struct with a Slice Field Can&#39;t Satisfy It</title>
    <link href="https://dixon.cx/blog/go-comparable-constraint-slice-field.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-comparable-constraint-slice-field.html</id>
    <published>2026-09-13T19:39:23Z</published>
    <updated>2026-09-13T19:39:23Z</updated>
    <summary>Why Go&#39;s generics compiler rejects structs containing slices as comparable, the reasoning behind it, and how to work around it.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="generics"></category>
    <category term="comparable"></category>
    <category term="slices"></category>
    <category term="type-constraints"></category>
    <category term="maps"></category>
  </entry>
  <entry>
    <title>Right to Erasure vs Backups: What UK GDPR Actually Requires</title>
    <link href="https://dixon.cx/blog/right-to-erasure-vs-backups-uk-gdpr.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/right-to-erasure-vs-backups-uk-gdpr.html</id>
    <published>2026-09-13T15:40:39Z</published>
    <updated>2026-09-13T15:40:39Z</updated>
    <summary>Why UK GDPR&#39;s right to erasure doesn&#39;t mean scrubbing every backup tape immediately, and what the ICO actually expects organisations to do instead.</summary>
    <category term="Privacy Law"></category>
    <category term="uk-law"></category>
    <category term="gdpr"></category>
    <category term="data-protection"></category>
    <category term="backups"></category>
    <category term="privacy"></category>
    <category term="ico"></category>
  </entry>
  <entry>
    <title>What &#39;Authorisation&#39; Actually Means Under the Computer Misuse Act</title>
    <link href="https://dixon.cx/blog/computer-misuse-act-penetration-testing-authorisation.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/computer-misuse-act-penetration-testing-authorisation.html</id>
    <published>2026-09-13T11:39:55Z</published>
    <updated>2026-09-13T11:39:55Z</updated>
    <summary>The Computer Misuse Act has no good-faith defence, so a pentest&#39;s legality rests entirely on paperwork. Here&#39;s what that paperwork actually needs to say.</summary>
    <category term="Privacy Law"></category>
    <category term="uk-law"></category>
    <category term="computer-misuse-act"></category>
    <category term="penetration-testing"></category>
    <category term="security"></category>
    <category term="privacy"></category>
    <category term="ico"></category>
  </entry>
  <entry>
    <title>Go&#39;s sync.Map: When It Actually Beats a Mutex-Protected Map</title>
    <link href="https://dixon.cx/blog/sync-map-vs-mutex-map-go.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/sync-map-vs-mutex-map-go.html</id>
    <published>2026-09-13T03:40:51Z</published>
    <updated>2026-09-13T03:40:51Z</updated>
    <summary>Why sync.Map only wins for two specific access patterns, how Go 1.24&#39;s trie-based rewrite changed the numbers, and when a plain mutex wins instead.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="sync-map"></category>
    <category term="concurrency"></category>
    <category term="mutex"></category>
    <category term="performance"></category>
    <category term="benchmarking"></category>
  </entry>
  <entry>
    <title>ESP32 Deep Sleep Power Budgeting: Why &#39;Low Power&#39; Mode Still Drains a Battery in Days</title>
    <link href="https://dixon.cx/blog/esp32-deep-sleep-power-budgeting.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/esp32-deep-sleep-power-budgeting.html</id>
    <published>2026-09-12T23:39:30Z</published>
    <updated>2026-09-12T23:39:30Z</updated>
    <summary>Deep sleep current specs look great on paper, but wake-up current spikes and a board&#39;s regulator usually decide the real battery life.</summary>
    <category term="Embedded"></category>
    <category term="esp32"></category>
    <category term="embedded"></category>
    <category term="low-power"></category>
    <category term="battery"></category>
    <category term="iot"></category>
    <category term="power-management"></category>
  </entry>
  <entry>
    <title>Postgres Advisory Locks in Go: Cheaper Than a Distributed Lock Service</title>
    <link href="https://dixon.cx/blog/postgres-advisory-locks-go.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/postgres-advisory-locks-go.html</id>
    <published>2026-09-12T19:39:52Z</published>
    <updated>2026-09-12T19:39:52Z</updated>
    <summary>How to use Postgres advisory locks from Go for cron dedup and leader election, and the connection-pooling pitfall that breaks them silently.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="postgresql"></category>
    <category term="distributed-locks"></category>
    <category term="pgx"></category>
    <category term="concurrency"></category>
    <category term="database"></category>
  </entry>
  <entry>
    <title>Hybrid Post-Quantum TLS 1.3: Why ML-KEM Rides Alongside ECDHE</title>
    <link href="https://dixon.cx/blog/hybrid-post-quantum-tls-mlkem-ecdhe.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/hybrid-post-quantum-tls-mlkem-ecdhe.html</id>
    <published>2026-09-12T15:40:54Z</published>
    <updated>2026-09-12T15:40:54Z</updated>
    <summary>Why TLS 1.3&#39;s post-quantum key exchange combines ML-KEM with ECDHE instead of replacing it, and what that costs in handshake size.</summary>
    <category term="Cryptography"></category>
    <category term="tls"></category>
    <category term="post-quantum-cryptography"></category>
    <category term="ml-kem"></category>
    <category term="ecdhe"></category>
    <category term="key-exchange"></category>
    <category term="go"></category>
  </entry>
  <entry>
    <title>Rural Broadband and CGNAT: Why Self-Hosting Needs a Reverse Tunnel</title>
    <link href="https://dixon.cx/blog/rural-broadband-cgnat-reverse-tunnel.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/rural-broadband-cgnat-reverse-tunnel.html</id>
    <published>2026-09-12T03:31:23Z</published>
    <updated>2026-09-12T03:31:23Z</updated>
    <summary>Starlink and most 4G home routers hide you behind CGNAT, so port forwarding does nothing. Here&#39;s how a reverse WireGuard tunnel fixes it.</summary>
    <category term="Systems Programming"></category>
    <category term="cgnat"></category>
    <category term="wireguard"></category>
    <category term="starlink"></category>
    <category term="networking"></category>
    <category term="self-hosting"></category>
    <category term="vpn"></category>
  </entry>
  <entry>
    <title>Ed25519 vs ECDSA: How Deterministic Nonces Ended a Recurring Bug</title>
    <link href="https://dixon.cx/blog/ed25519-vs-ecdsa-deterministic-nonces.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/ed25519-vs-ecdsa-deterministic-nonces.html</id>
    <published>2026-09-11T19:01:36Z</published>
    <updated>2026-09-11T19:01:36Z</updated>
    <summary>How a reused ECDSA nonce leaks a private key, why Sony and Android wallets fell to it, and how Ed25519 designs the whole bug class out.</summary>
    <category term="Cryptography"></category>
    <category term="cryptography"></category>
    <category term="ed25519"></category>
    <category term="ecdsa"></category>
    <category term="go"></category>
    <category term="nonce-reuse"></category>
    <category term="digital-signatures"></category>
  </entry>
  <entry>
    <title>Flipper Blue++: Giving the Flipper Zero the Bluetooth Stack It Was Built For</title>
    <link href="https://dixon.cx/blog/flipper-bluepp-full-bluetooth-stack.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/flipper-bluepp-full-bluetooth-stack.html</id>
    <published>2026-09-11T16:29:13Z</published>
    <updated>2026-09-11T16:29:13Z</updated>
    <summary>Why stock Flipper Zero firmware cannot scan or connect over BLE, the three patches that unlock the full stack, and how to drive it from your own app.</summary>
    <category term="Embedded"></category>
    <category term="flipper-zero"></category>
    <category term="bluetooth"></category>
    <category term="ble"></category>
    <category term="firmware"></category>
    <category term="stm32wb55"></category>
    <category term="embedded"></category>
  </entry>
  <entry>
    <title>Go HTTP Response Bodies: Why Close Alone Loses Connections</title>
    <link href="https://dixon.cx/blog/go-http-response-bodies-close-connection-reuse.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-http-response-bodies-close-connection-reuse.html</id>
    <published>2026-09-11T03:35:40Z</published>
    <updated>2026-09-11T03:35:40Z</updated>
    <summary>Closing a Go HTTP response body prevents leaks, but HTTP/1 connection reuse depends on reaching EOF. Learn when to drain, cap or abandon a body.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="net-http"></category>
    <category term="http"></category>
    <category term="connection-pooling"></category>
    <category term="networking"></category>
    <category term="performance"></category>
  </entry>
  <entry>
    <title>Go&#39;s iter.Seq and Range-over-Func: What the New Iterator Protocol Actually Costs You</title>
    <link href="https://dixon.cx/blog/go-iter-seq-range-over-func-cost.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-iter-seq-range-over-func-cost.html</id>
    <published>2026-09-10T03:33:57Z</published>
    <updated>2026-09-10T03:33:57Z</updated>
    <summary>How range-over-func actually compiles in Go 1.23, why non-local control flow needs hidden state, and where iter.Seq stops being free.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="iterators"></category>
    <category term="iter-seq"></category>
    <category term="range-over-func"></category>
    <category term="generics"></category>
    <category term="performance"></category>
  </entry>
  <entry>
    <title>Go&#39;s DisallowUnknownFields: Catching Silent JSON Typos</title>
    <link href="https://dixon.cx/blog/go-json-disallowunknownfields.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-json-disallowunknownfields.html</id>
    <published>2026-09-09T03:31:18Z</published>
    <updated>2026-09-09T03:31:18Z</updated>
    <summary>encoding/json ignores JSON fields it doesn&#39;t recognise by default. DisallowUnknownFields turns that into an error, but only if you use it correctly.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="encoding-json"></category>
    <category term="api-design"></category>
    <category term="error-handling"></category>
    <category term="debugging"></category>
    <category term="net-http"></category>
  </entry>
  <entry>
    <title>Rust&#39;s Pin and Self-Referential Futures: Why async Needs It At All</title>
    <link href="https://dixon.cx/blog/rust-pin-self-referential-futures.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/rust-pin-self-referential-futures.html</id>
    <published>2026-09-08T10:38:18Z</published>
    <updated>2026-09-08T10:38:18Z</updated>
    <summary>Why compiling an async fn into a state machine makes the result self-referential, and how Rust&#39;s Pin type stops the compiler from moving it unsafely.</summary>
    <category term="Rust"></category>
    <category term="rust"></category>
    <category term="async"></category>
    <category term="pin"></category>
    <category term="futures"></category>
    <category term="unsafe"></category>
    <category term="tokio"></category>
  </entry>
  <entry>
    <title>Rust&#39;s mpsc Backpressure: tokio vs std Under Load</title>
    <link href="https://dixon.cx/blog/rust-mpsc-backpressure-tokio-vs-std.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/rust-mpsc-backpressure-tokio-vs-std.html</id>
    <published>2026-09-07T03:33:02Z</published>
    <updated>2026-09-07T03:33:02Z</updated>
    <summary>Why tokio::sync::mpsc suspends a task while std::sync::mpsc blocks an OS thread, and why mixing the two on one runtime causes stalls.</summary>
    <category term="Rust"></category>
    <category term="rust"></category>
    <category term="tokio"></category>
    <category term="mpsc"></category>
    <category term="concurrency"></category>
    <category term="async"></category>
    <category term="backpressure"></category>
  </entry>
  <entry>
    <title>Go http.Server Timeouts: Why Slowloris Still Gets Through</title>
    <link href="https://dixon.cx/blog/go-http-server-timeouts-slowloris.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-http-server-timeouts-slowloris.html</id>
    <published>2026-09-06T12:31:08Z</published>
    <updated>2026-09-06T12:31:08Z</updated>
    <summary>Learn which Go HTTP timeouts cover slow headers, request bodies and keep-alive gaps, and which mistakes leave connections exposed.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="net-http"></category>
    <category term="security"></category>
    <category term="slowloris"></category>
    <category term="timeouts"></category>
    <category term="networking"></category>
  </entry>
  <entry>
    <title>Go&#39;s time.After: The Timer Leak Hiding in Every select Loop</title>
    <link href="https://dixon.cx/blog/time-after-timer-leak-select-loop.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/time-after-timer-leak-select-loop.html</id>
    <published>2026-09-06T03:33:24Z</published>
    <updated>2026-09-06T03:33:24Z</updated>
    <summary>How a select loop that calls time.After every iteration quietly piles up timers on old Go, and why Go 1.23 changed the rules.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="concurrency"></category>
    <category term="time-after"></category>
    <category term="timers"></category>
    <category term="select"></category>
    <category term="debugging"></category>
  </entry>
  <entry>
    <title>Why Your Go Worker Pool Deadlocks: An Unbuffered Channel Post-Mortem</title>
    <link href="https://dixon.cx/blog/go-worker-pool-unbuffered-channel-deadlock.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-worker-pool-unbuffered-channel-deadlock.html</id>
    <published>2026-09-05T06:55:27Z</published>
    <updated>2026-09-05T06:55:27Z</updated>
    <summary>A Go worker pool that deadlocks under load, traced back to an unbuffered results channel, with the fix and why bigger buffers only postpone the problem.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="concurrency"></category>
    <category term="channels"></category>
    <category term="debugging"></category>
    <category term="worker-pool"></category>
  </entry>
  <entry>
    <title>A Practical Guide to Hardening SSH: Ciphers, MACs and Key Exchange Algorithms Worth Disabling</title>
    <link href="https://dixon.cx/blog/hardening-ssh-ciphers-macs-kex-algorithms.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/hardening-ssh-ciphers-macs-kex-algorithms.html</id>
    <published>2026-09-04T10:16:03Z</published>
    <updated>2026-09-04T10:16:03Z</updated>
    <summary>A walkthrough of sshd_config&#39;s KexAlgorithms, Ciphers and MACs directives: what to strip out, why, and how to verify the change without locking yourself out.</summary>
    <category term="Security"></category>
    <category term="ssh"></category>
    <category term="cryptography"></category>
    <category term="linux"></category>
    <category term="security"></category>
    <category term="openssh"></category>
    <category term="hardening"></category>
  </entry>
  <entry>
    <title>Go&#39;s sync.Once Isn&#39;t a Mutex: What Actually Happens When f() Panics</title>
    <link href="https://dixon.cx/blog/go-sync-once-panic-behaviour.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-sync-once-panic-behaviour.html</id>
    <published>2026-09-03T10:16:03Z</published>
    <updated>2026-09-03T10:16:03Z</updated>
    <summary>sync.Once does not retry after f() panics: it quietly marks itself done, while OnceValue re-panics forever. Verified against the Go source.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="concurrency"></category>
    <category term="sync-once"></category>
    <category term="panic"></category>
    <category term="error-handling"></category>
    <category term="debugging"></category>
  </entry>
  <entry>
    <title>Certificate Transparency Logs: What They Actually Prove About a TLS Certificate, and What They Don&#39;t</title>
    <link href="https://dixon.cx/blog/certificate-transparency-logs-what-they-prove.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/certificate-transparency-logs-what-they-prove.html</id>
    <published>2026-09-02T10:16:03Z</published>
    <updated>2026-09-02T10:16:03Z</updated>
    <summary>CT logs make TLS certificate issuance publicly auditable, but they do not validate domain control, check revocation or stop mis-issuance. The actual guarantee.</summary>
    <category term="Security"></category>
    <category term="tls"></category>
    <category term="certificate-transparency"></category>
    <category term="security"></category>
    <category term="pki"></category>
    <category term="cryptography"></category>
    <category term="x509"></category>
  </entry>
  <entry>
    <title>How to Set Up Secure Boot with Your Own Keys Using sbctl</title>
    <link href="https://dixon.cx/blog/secure-boot-own-keys-sbctl-linux.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/secure-boot-own-keys-sbctl-linux.html</id>
    <published>2026-09-01T10:16:03Z</published>
    <updated>2026-09-01T10:16:03Z</updated>
    <summary>Create, enrol and maintain your own UEFI Secure Boot signing keys on Linux with sbctl, without turning the next reboot into a recovery exercise.</summary>
    <category term="Security"></category>
    <category term="linux"></category>
    <category term="secure-boot"></category>
    <category term="uefi"></category>
    <category term="sbctl"></category>
    <category term="key-management"></category>
    <category term="security"></category>
  </entry>
  <entry>
    <title>Rust&#39;s Async Drop Doesn&#39;t Exist: Why You Can&#39;t Await Inside a Destructor</title>
    <link href="https://dixon.cx/blog/rust-async-drop-doesnt-exist.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/rust-async-drop-doesnt-exist.html</id>
    <published>2026-08-31T10:16:03Z</published>
    <updated>2026-08-31T10:16:03Z</updated>
    <summary>Rust has no async destructor, and it isn&#39;t an oversight. Why Drop::drop can&#39;t await, and the spawn/block_on/explicit-close patterns people use instead.</summary>
    <category term="Rust"></category>
    <category term="rust"></category>
    <category term="async"></category>
    <category term="drop"></category>
    <category term="tokio"></category>
    <category term="raii"></category>
    <category term="resource-management"></category>
  </entry>
  <entry>
    <title>Go&#39;s %w Error Wrapping: Why errors.Is Silently Breaks the Moment You Forget One Verb</title>
    <link href="https://dixon.cx/blog/go-errorf-w-verb-errors-is-silent-break.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-errorf-w-verb-errors-is-silent-break.html</id>
    <published>2026-08-30T10:16:03Z</published>
    <updated>2026-08-30T10:16:03Z</updated>
    <summary>A single %v where you meant %w compiles cleanly and passes go vet, but it quietly severs the error chain that errors.Is depends on.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="error-handling"></category>
    <category term="errors-is"></category>
    <category term="fmt-errorf"></category>
    <category term="debugging"></category>
    <category term="static-analysis"></category>
  </entry>
  <entry>
    <title>How to Set Up Borg Backup with Append-Only Repositories for Ransomware-Resistant Backups</title>
    <link href="https://dixon.cx/blog/borg-backup-append-only-ransomware-resistant.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/borg-backup-append-only-ransomware-resistant.html</id>
    <published>2026-08-29T10:16:03Z</published>
    <updated>2026-08-29T10:16:03Z</updated>
    <summary>Configure BorgBackup with a server-enforced append-only repository, so a compromised client can add backups but never delete or rewrite them.</summary>
    <category term="Systems Programming"></category>
    <category term="borgbackup"></category>
    <category term="backups"></category>
    <category term="ransomware"></category>
    <category term="ssh"></category>
    <category term="linux"></category>
    <category term="systemd"></category>
  </entry>
  <entry>
    <title>Go&#39;s GOMAXPROCS Ignores Container CPU Limits: Why a Pod&#39;s Go Service Still Thrashes the Scheduler</title>
    <link href="https://dixon.cx/blog/go-gomaxprocs-container-cpu-limits.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-gomaxprocs-container-cpu-limits.html</id>
    <published>2026-08-28T10:16:03Z</published>
    <updated>2026-08-28T10:16:03Z</updated>
    <summary>A Go service capped at 0.5 CPU in Kubernetes still spins up dozens of OS threads and gets throttled. Why GOMAXPROCS cannot see the limit, and how to fix it.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="containers"></category>
    <category term="kubernetes"></category>
    <category term="linux"></category>
    <category term="performance"></category>
    <category term="cgroups"></category>
  </entry>
  <entry>
    <title>Subject Access Requests Under UK GDPR: What Organisations Can Legally Redact, and Where They Routinely Overreach</title>
    <link href="https://dixon.cx/blog/subject-access-requests-redaction-overreach-uk-gdpr.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/subject-access-requests-redaction-overreach-uk-gdpr.html</id>
    <published>2026-08-27T10:16:03Z</published>
    <updated>2026-08-27T10:16:03Z</updated>
    <summary>The DPA 2018 exemptions that let organisations lawfully redact a subject access request, and the patterns of overreach that turn a redaction into a breach.</summary>
    <category term="Privacy Law"></category>
    <category term="uk-law"></category>
    <category term="gdpr"></category>
    <category term="data-protection"></category>
    <category term="subject-access-request"></category>
    <category term="privacy"></category>
    <category term="ico"></category>
  </entry>
  <entry>
    <title>How to Set Up Remote LUKS Unlocking on a Headless Linux Server with Dropbear in initramfs</title>
    <link href="https://dixon.cx/blog/remote-luks-unlock-dropbear-initramfs.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/remote-luks-unlock-dropbear-initramfs.html</id>
    <published>2026-08-26T10:16:03Z</published>
    <updated>2026-08-26T10:16:03Z</updated>
    <summary>A step-by-step guide to embedding a minimal Dropbear SSH server in initramfs so you can type a LUKS passphrase over the network on a headless server reboot.</summary>
    <category term="Security"></category>
    <category term="linux"></category>
    <category term="luks2"></category>
    <category term="dropbear"></category>
    <category term="initramfs"></category>
    <category term="cryptsetup"></category>
    <category term="ssh"></category>
  </entry>
  <entry>
    <title>Linux Capabilities vs setuid Root: Why CAP_NET_BIND_SERVICE Is the Better Way to Bind Port 80 in Go</title>
    <link href="https://dixon.cx/blog/linux-capabilities-vs-setuid-root-cap-net-bind-service-go.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/linux-capabilities-vs-setuid-root-cap-net-bind-service-go.html</id>
    <published>2026-08-25T10:16:03Z</published>
    <updated>2026-08-25T10:16:03Z</updated>
    <summary>Binding to port 80 as a non-root Go process without setuid tricks, using Linux capabilities, CAP_NET_BIND_SERVICE, setcap and systemd&#39;s AmbientCapabilities.</summary>
    <category term="Systems Programming"></category>
    <category term="go"></category>
    <category term="linux"></category>
    <category term="security"></category>
    <category term="capabilities"></category>
    <category term="setuid"></category>
    <category term="networking"></category>
  </entry>
  <entry>
    <title>bcrypt&#39;s 72-Byte Truncation: The Password Hashing Bug Hiding in Plain Sight</title>
    <link href="https://dixon.cx/blog/bcrypt-72-byte-truncation.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/bcrypt-72-byte-truncation.html</id>
    <published>2026-08-24T10:16:03Z</published>
    <updated>2026-08-24T10:16:03Z</updated>
    <summary>bcrypt silently ignores everything past the 72nd byte of a password. Why the limit exists, how it produces real collisions, and how to handle it properly in Go.</summary>
    <category term="Cryptography"></category>
    <category term="go"></category>
    <category term="cryptography"></category>
    <category term="bcrypt"></category>
    <category term="password-hashing"></category>
    <category term="security"></category>
    <category term="blowfish"></category>
  </entry>
  <entry>
    <title>How to Set Up FIDO2 Hardware Key Authentication for SSH with Resident Keys</title>
    <link href="https://dixon.cx/blog/fido2-ssh-resident-keys.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/fido2-ssh-resident-keys.html</id>
    <published>2026-08-23T10:16:03Z</published>
    <updated>2026-08-23T10:16:03Z</updated>
    <summary>A practical guide to generating resident FIDO2 SSH keys with ssh-keygen, setting a PIN, and recovering the credential onto a new machine with ssh-keygen -K.</summary>
    <category term="Security"></category>
    <category term="ssh"></category>
    <category term="fido2"></category>
    <category term="webauthn"></category>
    <category term="security"></category>
    <category term="hardware-key"></category>
    <category term="linux"></category>
  </entry>
  <entry>
    <title>Timing Side Channels in Go: Why == on a MAC Verification Is a Security Bug</title>
    <link href="https://dixon.cx/blog/timing-side-channels-go-mac-verification.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/timing-side-channels-go-mac-verification.html</id>
    <published>2026-08-22T10:16:03Z</published>
    <updated>2026-08-22T10:16:03Z</updated>
    <summary>Comparing a computed HMAC with == looks correct and compiles fine, but it leaks timing information an attacker can use to forge a valid MAC byte by byte.</summary>
    <category term="Cryptography"></category>
    <category term="go"></category>
    <category term="cryptography"></category>
    <category term="timing-attack"></category>
    <category term="hmac"></category>
    <category term="constant-time"></category>
    <category term="security"></category>
  </entry>
  <entry>
    <title>SCM_RIGHTS and File Descriptor Passing: The Unix Socket Trick systemd Uses to Hand Off Privileged Sockets</title>
    <link href="https://dixon.cx/blog/scm-rights-file-descriptor-passing-systemd.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/scm-rights-file-descriptor-passing-systemd.html</id>
    <published>2026-08-21T10:16:03Z</published>
    <updated>2026-08-21T10:16:03Z</updated>
    <summary>How SCM_RIGHTS lets one Unix process hand an open file descriptor to another, with a working Go example and a look at where systemd genuinely uses it.</summary>
    <category term="Systems Programming"></category>
    <category term="linux"></category>
    <category term="unix-sockets"></category>
    <category term="systemd"></category>
    <category term="file-descriptors"></category>
    <category term="go"></category>
    <category term="security"></category>
  </entry>
</feed>
