It turns out that the "IPv4 Only" mode that the cable modem is in has nothing to do with the availability of IPv6 on the connection. Someone somewhere on the internet mentioned discovering their IPv6 via tcpdump, and so I tried it on my connection and, sure enough, there were IPv6 packets coming over the modem.
It was a bit difficult to get it to work, but only because of changes I'd made to my computer to support the Hurricane Electric tunnel, and firewall rules I'd added. Linux won't accept router advertisements when it is configured as a router itself, and it won't accept DHCPv6 responses without the port being open as it doesn't realize they're related to the DHCPv6 request. After restoring everything back to its default settings and opening the firewall a bit, it finds the IPv6 automatically, though it does take it ten seconds after it gets an IPv4 address to set it up.
Since I want to make this computer function as the router for the house, I added a second network card and disabled the automatic network connections, as they lack options to choose which interface they apply to.
Since then I've spent about 12 hours trying to get it set up correctly and sharing my connection with the other computers in the house, but thanks to Linux being a bitch, it's incredibly difficult and it still isn't working correctly.
There's a sysctl setting that tells the kernel whether to accept router advertisements. Somehow it keeps getting disabled, and so Linux ignores the advertisements, then forgets its default route when it expires. I'm going to have to write a script to monitor it so that I can figure out what is disabling it.
The radvd daemon refuses to start if net.ipv6.conf.all.forwarding isn't set to 1, but the kernel will not accept router advertisements on an interface where net.ipv6.conf.eth_.forwarding is set to 1. So you have to set net.ipv6.conf.all.forwarding to 1, which sets the flag on all interfaces, then disable it again on the WAN interface, just to make radvd happy. Setting net.ipv6.conf.all.accept_ra to 2 is also supposed to solve the problem, but it doesn't seem to work.
TWC's servers respond to multiple types of DHCPv6 requests. I can request a single address (a /128), or a /64 routing prefix, or a /60 routing prefix, and possibly more but I haven't tried. You can also request that single IP and a routing prefix at the same time, which is necessary since your WAN IP has to be on a different subnet than your LAN, so you can't just pick an IP out of your routing prefix. (Although, you probably could in TWC's case, as your default route is a link-local address and so technically your WAN interface doesn't need a publicly-addressible IP.)
I've been using dhclient, but it seems a bit broken. The documentation doesn't even claim it's possible to request both a single IP and a routing prefix simultaneously. I only discovered it was (by combining the -P and -N options) when I found a bug tracker entry where someone submitted a patch to enable it, much to the confusion of the authors who didn't understand why anyone would want to do that.
TWC's servers rarely respond to dhclient's attempts to release the IP, which causes dhclient to continually grow its leases file with multiple copies of identical leases.
At one point it just wasn't able to obtain IPv6 addresses anymore, and after an hour of trying to figure out why, I restarted the cable modem and it started working again.
It never records IPv6 name servers. I don't know if TWC just isn't sending any, or if dhclient isn't requesting them, or simply isn't logging the responses. The verbose output unsurprisingly isn't that verbose. I may have to use tcpdump and compare packet contents with RFCs to figure out what is going on.
...but first I think I'll just look into some other DHCPv6 client.
Using radvd requires a config file that lists the routing prefix, so I had to write a script to read the lease file and create the radvd.conf file, and fuck with the sysctl settings so that radvd will actually start.
I haven't even gotten to trying to set up a DHCPv6 server for my LAN, or a DNS server so that I can access my computers by hostname.
I also tried pfSense which I managed to get working in a VM, then I tried it on a real computer but found that one of my network cards was broken, so I tried it on another computer and, after reading a web site for five minutes while it booted, I checked it's progress only to find I had one second left of the ten second countdown before it merely runs the live CD rather than the installer. I didn't feel like waiting another five minutes, so I went back to the VM solution, but couldn't get it to work again. Then I noticed that pfSense refuses to do DHCPv6 without a static address. It has no sympathy for the fact that my address likely is rather static and merely handed out via DHCPv6 for convenience. I can't think of why it shouldn't be possible to do it with a routing prefix obtained via DHCPv6, but pfSense refuses to do it.
It almost makes me want to just buy an IPv6-compatible wireless router, but I expect that if I did it would likely be just as fucked up and with less possibility of resolving its issues.
If I ever figure out how to get the kernel, the two DHCP clients (IPv4 and IPv6), the two DHCP servers, radvd, and my firewall rules to all work together to do what I want, I'll have to make another post about it. Seven fucking pieces of software you have to learn to use just to route packets on your LAN, and I'm sure they won't all work together without an eighth, a Perl script to parse all their fucking files, write new fucking files, constantly restart the things, and monitor for when any part of it stops working so that it can start all over again. In particular, the automatic network connection tool, despite being disabled, seems to kill the connection about 20 seconds after boot, when it displays a "you are no longer connected to the internet" pop-up message.
...and some people don't think Linux is hard to use.