Here is what I did in a VM (192.168.1.128) to demonstrate. I am blocking outgoing ICMP packets here, but the principle is the same. Block all packets which match specific parameters, and allow select IP addresses through.
root@box:~# ping -c 1 192.168.1.1
PING 192.168.1.1 (192.168.1.1): 56 data bytes
64 bytes from 192.168.1.1: seq=0 ttl=128 time=1.252ms
root@box:~# iptables -I OUTPUT -p icmp -j DROP
root@box:~# ping -c 1 192.168.1.1
PING 192.168.1.1 (192.168.1.1): 56 data bytes
ping: sendto: operation not permitted
root@box:~# iptables -I OUTPUT -p icmp -d 192.168.1.1 -j ACCEPT
root@box:~# ping -c 1 192.168.1.1
PING 192.168.1.1 (192.168.1.1): 56 data bytes
64 bytes from 192.168.1.1: seq=0 ttl=128 time=1.252ms
root@box:~# ping -c 1 192.168.1.129
PING 192.168.1.129 (192.168.1.129): 56 data bytes
ping: sendto: operation not permitted
how do you allow IP ranges instead of individual IPs?
From the iptables man page:
iprange
This matches on a given arbitrary range of IPv4 addresses
[!]--src-range ip-ip
Match source IP in the specified range.
[!]--dst-range ip-ip
Match destination IP in the specified range.
Also,
Address can be either a network name, a hostname (please note that specifying any name to be resolved with a remote query such as DNS is a really bad idea), a network IP address (with /mask), or a plain IP address. The mask can be either a network mask or a plain number, specifying the number of 1's at the left side of the network mask. Thus, a mask of 24 is equivalent to 255.255.255.0. A "!" argument before the address specification inverts the sense of the address.