# Guava SMB Incident — 2026-03-14

**Affected host:** guava (TrueNAS SCALE, `100.75.252.64` / `192.168.0.100`)
**Affected client:** shinku-ryuu (Windows, `192.168.0.3`)
**Symptoms:** All SMB shares on guava unreachable from shinku after guava reboot

---

## Root Causes (two separate issues)

### 1. Tailscale app was STOPPED after reboot

Guava's Tailscale was running as an **orphaned host process** rather than the managed TrueNAS app. On reboot the orphan was gone and the app didn't start because it was in `STOPPED` state.

**Why it was stopped:** The app had been upgraded from v1.3.30 → v1.4.2. The new version's startup script ran `tailscale up` but failed because the stored state had `--accept-dns=false` while the app config had `accept_dns: true` — a mismatch that requires `--reset`. The app exited, leaving the old manually-started daemon running until the next reboot.

### 2. Tailscale `accept_routes: true` caused SMB replies to route via tunnel

After fixing the app startup, shinku still couldn't reach guava on the LAN. The cause:

- **Calypso** advertises `192.168.0.0/24` as a subnet route via Tailscale
- Guava had `accept_routes: true` — it installed Calypso's `192.168.0.0/24` route into Tailscale's policy routing table (table 52, priority 5270)
- When shinku sent a TCP SYN to guava port 445, it arrived on `enp1s0f0np0`
- Guava's reply looked up `192.168.0.3` in the routing table — hit table 52 first — and sent the reply **out via `tailscale0`** instead of the LAN
- The reply never reached shinku; the connection timed out

This also affected shinku: it had `accept_routes: true` as well, so it was routing traffic destined for `192.168.0.100` via Calypso's Tailscale tunnel rather than its local Ethernet interface.

---

## Fixes Applied

### Fix 1 — Tailscale app startup config

Updated the TrueNAS app config to match the node's actual desired state:

```bash
sudo midclt call app.update tailscale '{"values": {"tailscale": {
  "accept_dns": false,
  "accept_routes": false,
  "advertise_exit_node": true,
  "advertise_routes": [],
  "auth_key": "...",
  "auth_once": true,
  "hostname": "truenas-scale",
  "reset": true
}}}'
```

Key changes:
- `accept_dns: false` — matches the running state stored in Tailscale's state dir
- `accept_routes: false` — prevents guava from pulling in subnet routes from other nodes (see Fix 2)
- `reset: true` — clears the flag mismatch that was causing `tailscale up` to fail

**Saved in:** `/mnt/.ix-apps/app_configs/tailscale/versions/1.4.2/user_config.yaml`

### Fix 2 — Remove stale subnet routes from guava's routing table

After updating the app config the stale routes persisted in table 52. Removed manually:

```bash
sudo ip route del 192.168.0.0/24 dev tailscale0 table 52
sudo ip route del 192.168.12.0/24 dev tailscale0 table 52
sudo ip route del 192.168.68.0/22 dev tailscale0 table 52
sudo ip route del 192.168.69.0/24 dev tailscale0 table 52
```

With `accept_routes: false` now saved, these routes will not reappear on next reboot.

### Fix 3 — Disable accept_routes on shinku

Shinku was also accepting Calypso's `192.168.0.0/24` route (metric 0 via Tailscale, beating Ethernet 3's metric 256):

```
# Before fix — traffic to 192.168.0.100 went via Tailscale
192.168.0.0/24    100.100.100.100    0    Tailscale

# After fix — traffic goes via local LAN
192.168.0.0/24    0.0.0.0    256    Ethernet 3
```

Fixed by running on shinku:
```
tailscale up --accept-routes=false --login-server=https://headscale.vish.gg:8443
```

### Fix 4 — SMB password reset and credential cache

The SMB password for `vish` on guava was changed via the TrueNAS web UI. Windows had stale credentials cached. Fixed by:

1. Clearing Windows Credential Manager entry for `192.168.0.100`
2. Re-mapping shares from an interactive PowerShell session on shinku

---

## SMB Share Layout on Guava

| Windows drive | Share | Path on guava |
|--------------|-------|---------------|
| I: | `guava_turquoise` | `/mnt/data/guava_turquoise` |
| J: | `photos` | `/mnt/data/photos` |
| K: | `data` | `/mnt/data/passionfruit` |
| L: | `website` | `/mnt/data/website` |
| M: | `jellyfin` | `/mnt/data/jellyfin` |
| N: | `truenas-exporters` | `/mnt/data/truenas-exporters` |
| Q: | `iso` | `/mnt/data/iso` |

All shares use `vish` as the SMB user. Credentials stored in Windows Credential Manager under `192.168.0.100`.

---

## Diagnosis Commands

```bash
# Check Tailscale app state on guava
ssh guava "sudo midclt call app.query '[[\"name\",\"=\",\"tailscale\"]]' | python3 -c 'import sys,json; a=json.load(sys.stdin)[0]; print(a[\"name\"], a[\"state\"])'"

# Check for rogue subnet routes in Tailscale's routing table
ssh guava "ip route show table 52 | grep 192.168"

# Check tailscale container logs
ssh guava "sudo docker logs \$(sudo docker ps | grep tailscale | awk '{print \$1}' | head -1) 2>&1 | tail -20"

# Check SMB audit log for auth failures on guava
ssh guava "sudo journalctl -u smbd --since '1 hour ago' --no-pager | grep -i 'wrong_password\|STATUS'"

# Check which Tailscale peer is advertising a given subnet (run on any node)
tailscale status --json | python3 -c "
import sys, json
d = json.load(sys.stdin)
for peer in d.get('Peer', {}).values():
    routes = peer.get('PrimaryRoutes') or []
    if routes:
        print(peer['HostName'], routes)
"
```

---

## Prevention

- **Guava:** `accept_routes: false` is now saved in the TrueNAS app config — will survive reboots
- **Shinku:** `--accept-routes=false` set via `tailscale up` — survives reboots
- **General rule:** Hosts on the same LAN as the subnet-advertising node (Calypso → `192.168.0.0/24`) should have `accept_routes: false`, or the advertised subnet should be scoped to only nodes that need remote access to that LAN
- **TrueNAS app upgrades:** After upgrading the Tailscale app version, always check the new `user_config.yaml` to ensure `accept_dns`, `accept_routes`, and other flags match the node's actual running state. If unsure, set `reset: true` once to clear any stale state, then set it back to `false`
