Therefore, I want to replace the current ipb_address field with a number of nullable fields, including address (username or IP address, as it is now), namespace, page, exempted groups, and permission. If all of the non-null fields match, the block will apply.
I like the idea. I don't think it is too complicated for core. It should be 100% backwards compatible if done correctly (just make namespace and page default to NULL, exempted groups default to ipblock-exempt [ok, that's a permission, not a group, but that shouldn't be too much of a problem] for ip blocks and NULL for username blocks and permission default to edit and move, or whatever the appropriate combination is). The new functionality can then be put on a new Special:AdvancedBlock page.
In the process of doing all this, the User::isBlocked() and User::isBlockedFrom() methods should be deprecated. It would make everything much simpler if it all went through userCan().