I, too, wanted more control over nat and my subnets and ended up getting it to work by using a bridge, divert, natd and a cloned route. This is now what my network looks like:
And here's how I did it:
# Create a bridge, add the Ethernet device
gwdev=en1
ifconfig bridge0 create
ifconfig bridge0 up
ifconfig bridge0 addm en0
# Give it an IP, route bridge0's traffic to bridge0
ifconfig bridge0 172.20.0.1
route add default -interface bridge0 -ifscope bridge0 -cloning
# Enable IP forwarding, add a firewall rule to send all natd traffic to the real gateway
# Start natd with a whole bunch of options
sysctl -w net.inet.ip.forwarding=1
/sbin/ipfw add 100 divert natd ip from any to any via $gwdev
/usr/sbin/natd -interface $gwdev -use_sockets -same_ports -unregistered_only -dynamic -clamp_mss -enable_natportmap -natportmap_interface en0
If you'd like more info, you can check out the blog post I wrote that details my setup. You may notice that I don't address DHCP or DNS.. I'm having servers on my guest network handle that.
I'm not a network admin so if you see any ways to improve this, please let me know so I can update the post.