You need a graph walking algorithm for that. Consider the following pseudocode:
GraphWalker(connection)
If hub.visited = false
hub.visited = true
Loop for each connectedHub in hub.connectedHubs do
GraphWalker(connectedHub)
Yep. I knew I needed something like it. It was just too late at night to want to think about it.
I figured out a different way to do it this morning that doesn't require knowing the whole network. Instead each node knows all of its child nodes, and when it loses supply it first checks to see if it can get supply back from another hub (using the main hub list), if not it sets all of its children to not having supply and clears its children list.
Turrets already had code to seek a new hub if they lost supply, so I borrowed that code and added it to hubs.
Took a couple hours to get it to work right (kept forgetting to do one thing or another, so my 2nd tier hubs weren't in the main hub list, etc.) but it works great.
I also put in the more turrets -> less supply range. It only applies to hubs. There's a base 3.2 multiplier on supply distance from another hub, and each turret on that hub reduces the multiplier by 0.2--so it starts at 192 pixels and drops down to 120.
I haven't tested anything complex yet, but it does appear to be working correctly.