aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
blob: 75f3fae307b359a125915cb467e50ff9e9b3225b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# ipset-dns
#### Jason A. Donenfeld (<Jason@zx2c4.com>)

`ipset-dns` is a lightweight DNS forwarding server that adds all resolved IPs
to a given [netfilter ipset](http://ipset.netfilter.org/). It is designed to be
used in conjunction with [`dnsmasq`](http://www.thekelleys.org.uk/dnsmasq/doc.html)'s
upstream server directive.

Practical use cases include routing over a given gateway traffic for particular
web services or webpages that do not have a priori predictable IP addresses and
instead rely on dizzying arrays of DNS resolutions.

#### Upstream Dnsmasq Support

***This functionality has now been [written directly into `dnsmasq`](http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=13d86c7372e01392d1e3af7c90312b49e2a5c15d), which should be much easier to use than this project. See the `--ipset` option.***


### Why?

Some ISPs throttle connections to services like YouTube. Other times,
you live places where there's no Netflix/Pandora/Hulu, but you've got a VPN.

The problem is, you don't want to route *all* your internet traffic over VPN -- just
for YouTube and Pandora, say. It'd be nice to just whitelist a static IP range,
but some services, like YouTube, have a thousands of caching servers in a modicum
of IP ranges, and it's just too much of a hassle to compile the list beforehand.

So instead, you put `ipset-dns` on your router, and then everyone and every
XBox/PS3/whatever on your wifi network will benefit from the superior
bandwidth and/or geo-availability.

### Usage

    # ipset-dns name-of-v4-ipset name-of-v6-ipset listening-port upstream-dns-server

`ipset-dns` binds only to localhost. It will daemonize unless the `NO_DAEMONIZE`
environment variable is set. If either `name-of-v4-ipset` or `name-of-v6-ipset` are
empty strings, then the ipset for the respective address family will not be utilized.

### Building

Linux >= 2.6.32:

    $ make

Linux >= 2.6.16 or >= 2.4.36:

    $ make OLD_IPSET=1

### Example

In `dnsmasq.conf`:

	server=/c.youtube.com/127.0.0.1#1919

Make an ipset:

	# ipset -N youtube iphash

Start the `ipset-dns` server:

	# ipset-dns youtube 1919 8.8.8.8

Query a hostname:

	# host r4---bru02t12.c.youtube.com
	r4---bru02t12.c.youtube.com is an alias for r4.bru02t12.c.youtube.com.
	r4.bru02t12.c.youtube.com has address 74.125.216.51

Observe that it was added to the ipset:

	# ipset -L youtube
	Name: youtube
	Type: iphash
	References: 1
	Header: hashsize: 1024 probes: 8 resize: 50
	Members:
	74.125.216.51


### Sample Script

The following script routes youtube and netflix over two different repective
gateways. It assumes you're using `dnsmasq` or similar to manage caching and
selectively using upstream servers:

	server=/c.youtube.com/127.0.0.1#39128
	server=/netflix.com/127.0.0.1#39129

The network interfaces `tun11` and `tun12` are assumed to be OpenVPN tunnels,
though they may be any other kind of interface with a route. These devices are
assumed to have some form of masquerading and IP forwarding turned on already.

The `mangle` `iptables` table is used to set a firewall mark on packets that
match an ipset tended to by `ipset-dns`. A routing table is created and a rule
is entered that sends packets marked by `iptables` to the correct routing table.
Finally, a default route is given to the marked routing table.

Two `ipset-dns` daemons are started, one for each of the routes, using the ports
given by `dnsmasq`. Lastly, `SIGHUP` is sent to `dnsmasq` to flush its cache.

	sets() {
		iptables -t mangle -D PREROUTING -m set --set "$1" dst,src -j MARK --set-mark "$2" 2>/dev/null
		ipset -X "$1" 2>/dev/null
		ipset -N "$1" iphash
		iptables -t mangle -A PREROUTING -m set --set "$1" dst,src -j MARK --set-mark "$2"
	}

	sets youtube 1
	sets netflix 2

	routes() {
		echo 0 > /proc/sys/net/ipv4/conf/$2/rp_filter
		ip route flush table $1 2>/dev/null
		ip rule del table $1 2>/dev/null
		ip rule add fwmark $1 table $1 priority 1000
		ip route add default via "$(ip route show dev $2 | head -n 1 | cut -d ' ' -f 1)" table $1
	}

	routes 1 tun12
	routes 2 tun11

	killall ipset-dns 2>/dev/null
	ipset-dns youtube 39128 8.8.8.8
	ipset-dns netflix 39129 8.8.8.8

	killall -SIGHUP dnsmasq

### License

* Copyright (C) 2013, 2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.

DNS parsing code loosely based on uClibc's [resolv.c](http://git.uclibc.org/uClibc/tree/libc/inet/resolv.c):

* Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>, The Silver Hammer Group, Ltd.
* Copyright (C) 1985, 1993 The Regents of the University of California. All Rights Reserved.

This project is licensed under the GPLv2. Please see COPYING for more information.