Compare commits
540 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e22cf28f8 | ||
|
|
3b1b3e9d50 | ||
|
|
ab72091de2 | ||
|
|
66f57867d8 | ||
|
|
6375838445 | ||
|
|
82a14af5e7 | ||
|
|
97dce08ed7 | ||
|
|
198d940af6 | ||
|
|
1d7e0a36e3 | ||
|
|
10068600f8 | ||
|
|
b7639d5815 | ||
|
|
49752b90d5 | ||
|
|
e98bd52e25 | ||
|
|
8a8bbad0cf | ||
|
|
fec216df32 | ||
|
|
4e1fe44428 | ||
|
|
51967f9807 | ||
|
|
b37f8b99ae | ||
|
|
fc2833f172 | ||
|
|
490f90758d | ||
|
|
56618c31f6 | ||
|
|
604f7598c2 | ||
|
|
2a7a2b84ec | ||
|
|
3e21a1a6fa | ||
|
|
2b29191e7c | ||
|
|
03431d6373 | ||
|
|
cc1a29e250 | ||
|
|
e62e9b6187 | ||
|
|
19c51cfa49 | ||
|
|
d5082158ee | ||
|
|
3f7483e816 | ||
|
|
0c8584eabc | ||
|
|
f00690f93e | ||
|
|
89b12ed35b | ||
|
|
1a9a3489ec | ||
|
|
c8a80487cd | ||
|
|
4ea8e80dd9 | ||
|
|
c07d30dcb1 | ||
|
|
d588ab54d4 | ||
|
|
f8b422a7b6 | ||
|
|
29fe922b14 | ||
|
|
8707019237 | ||
|
|
d1fbb77e0f | ||
|
|
1fbe4d2f5f | ||
|
|
0575610fa1 | ||
|
|
e3f1455850 | ||
|
|
bd9b3cf55b | ||
|
|
14db4212ab | ||
|
|
00a5b5d477 | ||
|
|
b8eac19177 | ||
|
|
b47b04c846 | ||
|
|
613ad15d02 | ||
|
|
24187530fb | ||
|
|
a857daa351 | ||
|
|
f01d7be6c6 | ||
|
|
d387380a25 | ||
|
|
f2e4c277c4 | ||
|
|
5107ace14a | ||
|
|
7b1eae4f50 | ||
|
|
c152dc8492 | ||
|
|
7bcca0060f | ||
|
|
d68c2ca2b7 | ||
|
|
de73a497ca | ||
|
|
e3ec15af10 | ||
|
|
dac74312da | ||
|
|
2ecd9bd5c0 | ||
|
|
a0ab18f6eb | ||
|
|
ebe95a831f | ||
|
|
ee4158678a | ||
|
|
83349b8aa4 | ||
|
|
7fa836e105 | ||
|
|
1633e30834 | ||
|
|
c8ca33f810 | ||
|
|
e243c072b5 | ||
|
|
da4f372271 | ||
|
|
610e782a29 | ||
|
|
854cf26907 | ||
|
|
bb201c211a | ||
|
|
12fae49fff | ||
|
|
fd372273bd | ||
|
|
b98d22c191 | ||
|
|
160f6507c3 | ||
|
|
613d6c5249 | ||
|
|
81a883fda3 | ||
|
|
40b695c1f1 | ||
|
|
5f938534a9 | ||
|
|
8d718cbb3e | ||
|
|
f6a2b79310 | ||
|
|
82e3f45a9f | ||
|
|
072e81b3c5 | ||
|
|
1d97ac4fd2 | ||
|
|
db73746620 | ||
|
|
97bc798b05 | ||
|
|
edc231bc58 | ||
|
|
b85e092e23 | ||
|
|
583043f527 | ||
|
|
8f6213cce9 | ||
|
|
00ec693db8 | ||
|
|
70b4a818ef | ||
|
|
7c28612a59 | ||
|
|
6f4681034e | ||
|
|
6938f3476e | ||
|
|
17fb9ea763 | ||
|
|
7d23a66ff0 | ||
|
|
703c7ff429 | ||
|
|
8a9be9e493 | ||
|
|
c92f0083a2 | ||
|
|
b5dbfd142a | ||
|
|
cbf13a2a6d | ||
|
|
5b3bf92101 | ||
|
|
0744ca66ad | ||
|
|
2d33bda2e6 | ||
|
|
32f90c0fad | ||
|
|
bce6e1bc6d | ||
|
|
824202ef54 | ||
|
|
9ebfca1e84 | ||
|
|
6429e421b3 | ||
|
|
c9bfa948c3 | ||
|
|
e7829aefd8 | ||
|
|
51ea3ca254 | ||
|
|
57ab36e77d | ||
|
|
dd0e0a3995 | ||
|
|
6fd6dacb39 | ||
|
|
39048ad10b | ||
|
|
979cdf9b64 | ||
|
|
dbf721235b | ||
|
|
c979fa04a4 | ||
|
|
c5f4ec7d23 | ||
|
|
5d3b87a484 | ||
|
|
72ae2f3d56 | ||
|
|
6c0cb858c1 | ||
|
|
e0c0ad3b5e | ||
|
|
4619d94622 | ||
|
|
0975a58e9b | ||
|
|
a25720a34a | ||
|
|
cc111e0bab | ||
|
|
86bec2d399 | ||
|
|
a59ff5f3df | ||
|
|
c3a04081ff | ||
|
|
ae76242fdf | ||
|
|
4f04476e3b | ||
|
|
1486a9c7f2 | ||
|
|
5ada888507 | ||
|
|
5f8e58f49b | ||
|
|
b8071a849a | ||
|
|
b6e9e7c32d | ||
|
|
0435d041ea | ||
|
|
795501bc86 | ||
|
|
c2207688c0 | ||
|
|
98c098bfc7 | ||
|
|
c47e3ba446 | ||
|
|
f1668d2786 | ||
|
|
7d7b7b31e5 | ||
|
|
3ddacb86e9 | ||
|
|
60b68069cf | ||
|
|
871417d45d | ||
|
|
65d1e3bb9b | ||
|
|
0fc2f31368 | ||
|
|
c3e0b9b6e7 | ||
|
|
6ea1f23b3f | ||
|
|
963c380d13 | ||
|
|
00238fb019 | ||
|
|
74e6b52011 | ||
|
|
875b8160f6 | ||
|
|
76ff440ebe | ||
|
|
8db957dfbf | ||
|
|
9d633048fe | ||
|
|
a9b55837dc | ||
|
|
c352dd8f1a | ||
|
|
3a2371527f | ||
|
|
1ee9be4c3f | ||
|
|
56ad6c9be1 | ||
|
|
fa04c83d86 | ||
|
|
4c82efc5ac | ||
|
|
5f45d6a715 | ||
|
|
2329bef5ba | ||
|
|
62ab3ccd3d | ||
|
|
71aaa5a791 | ||
|
|
08619211f8 | ||
|
|
3dffbc3ebf | ||
|
|
0d6eb134f5 | ||
|
|
50db3492e2 | ||
|
|
3b19596122 | ||
|
|
d082faf3e4 | ||
|
|
99e8891f85 | ||
|
|
532066ee2d | ||
|
|
254390644a | ||
|
|
241fa9c6c8 | ||
|
|
e142a83296 | ||
|
|
f7029f5c08 | ||
|
|
c50f25a3ea | ||
|
|
65c9b48921 | ||
|
|
f25e6c6d33 | ||
|
|
587ad4f271 | ||
|
|
4452292064 | ||
|
|
e597dba7ec | ||
|
|
dd9d9ce54c | ||
|
|
06e54b823e | ||
|
|
32b4e4cb7c | ||
|
|
376d48c7f1 | ||
|
|
6586e8352a | ||
|
|
3511a92869 | ||
|
|
44de649e5c | ||
|
|
29c122af83 | ||
|
|
6dbdc972c4 | ||
|
|
7b174c250d | ||
|
|
50d7f721ee | ||
|
|
5a4120dbfb | ||
|
|
eec5c1e21c | ||
|
|
1f776a4aa2 | ||
|
|
227ddad9b5 | ||
|
|
a9bf81ad91 | ||
|
|
6008bdbbc1 | ||
|
|
93bafe619d | ||
|
|
8ab91e9f7f | ||
|
|
5731050062 | ||
|
|
fb63dd1345 | ||
|
|
5f8002fcd7 | ||
|
|
19b1689161 | ||
|
|
b485ed97aa | ||
|
|
53c4c5c859 | ||
|
|
dc27e148a1 | ||
|
|
45cca58592 | ||
|
|
e136725c5b | ||
|
|
486479e943 | ||
|
|
3bb51da835 | ||
|
|
806cf78797 | ||
|
|
3b3f441189 | ||
|
|
24b5a5d50b | ||
|
|
d56a604a96 | ||
|
|
8c0b73d3a8 | ||
|
|
6bd3a09fb8 | ||
|
|
f65b0e546b | ||
|
|
8584c502d3 | ||
|
|
c3edf383ff | ||
|
|
c4cd95df68 | ||
|
|
ed4c0767b1 | ||
|
|
043c271f8a | ||
|
|
d4da20f064 | ||
|
|
903650af67 | ||
|
|
ef1d7425e3 | ||
|
|
1d1c795601 | ||
|
|
889d8a156f | ||
|
|
b7f666ff09 | ||
|
|
e4e9b342a7 | ||
|
|
d5c35a59b0 | ||
|
|
2f9fd1dcc5 | ||
|
|
8f3194f7ac | ||
|
|
10bd29265b | ||
|
|
42b44a591b | ||
|
|
a810559b24 | ||
|
|
861c89141a | ||
|
|
8939c95fd6 | ||
|
|
408c368fa5 | ||
|
|
b5d9a362b4 | ||
|
|
f1af2bb485 | ||
|
|
1b55190d3f | ||
|
|
f373a15b62 | ||
|
|
91543f4831 | ||
|
|
d81b42d067 | ||
|
|
724789de13 | ||
|
|
8f51a29137 | ||
|
|
c845f6eda5 | ||
|
|
89500e31f1 | ||
|
|
c8f2dd8b53 | ||
|
|
ceae52df15 | ||
|
|
c2d8d3ffc4 | ||
|
|
aa985beeef | ||
|
|
65e7912d31 | ||
|
|
02ed24d351 | ||
|
|
6acef73052 | ||
|
|
10ae7b50f2 | ||
|
|
831b5ba12b | ||
|
|
0932f9c08b | ||
|
|
397542b213 | ||
|
|
0c38719fe0 | ||
|
|
ff7eea27e7 | ||
|
|
687bac22db | ||
|
|
8d41ebd8a3 | ||
|
|
4631dbf68c | ||
|
|
4f9aefc753 | ||
|
|
4b5287005f | ||
|
|
5c32841934 | ||
|
|
ccd1d32c3a | ||
|
|
75ffc9bf15 | ||
|
|
3af1ea8cbc | ||
|
|
1f0dc5835b | ||
|
|
ed1fc98595 | ||
|
|
b58fb39f24 | ||
|
|
0304d28f7e | ||
|
|
f5adbb90a1 | ||
|
|
32b826e2a0 | ||
|
|
0937692dc6 | ||
|
|
785ee80b93 | ||
|
|
f119ed382e | ||
|
|
da23c4f960 | ||
|
|
4885d57c58 | ||
|
|
0db0e0c216 | ||
|
|
ec2962eacb | ||
|
|
0ca895f585 | ||
|
|
6299ffbe60 | ||
|
|
7f0485cf53 | ||
|
|
02bff4f109 | ||
|
|
d1ca25ca7e | ||
|
|
23c2176681 | ||
|
|
e83297d0f6 | ||
|
|
41de7442d2 | ||
|
|
0852d76b58 | ||
|
|
a55ce08cc0 | ||
|
|
dd090561bf | ||
|
|
28f04fd647 | ||
|
|
50a96b62f1 | ||
|
|
00b963ab72 | ||
|
|
79333a2498 | ||
|
|
32f82c62c8 | ||
|
|
4e076d746f | ||
|
|
13e435ebca | ||
|
|
4b0eecbb44 | ||
|
|
0360a524df | ||
|
|
262ac85107 | ||
|
|
4c70046d93 | ||
|
|
458824dcb4 | ||
|
|
a7338645d7 | ||
|
|
776fd04754 | ||
|
|
20bccd499f | ||
|
|
708bcd2dd3 | ||
|
|
d0edff7d6e | ||
|
|
ccca70cb33 | ||
|
|
0d829ebc69 | ||
|
|
4137b84e4e | ||
|
|
e6c2a670fe | ||
|
|
47f99dd2b3 | ||
|
|
6759b99e28 | ||
|
|
3471f18130 | ||
|
|
2ef843dd16 | ||
|
|
ce2a0f5a6a | ||
|
|
adca3e9c4b | ||
|
|
366dfcb907 | ||
|
|
28c625572b | ||
|
|
02f9b76418 | ||
|
|
ba8badd6df | ||
|
|
0decc869ae | ||
|
|
b573aebc09 | ||
|
|
d31d057aa3 | ||
|
|
6445c8ed73 | ||
|
|
382e38f494 | ||
|
|
9940aba9f6 | ||
|
|
7e846b9858 | ||
|
|
d322de0613 | ||
|
|
b98f771519 | ||
|
|
c7a93f6e4e | ||
|
|
970ce22b68 | ||
|
|
e292e93d35 | ||
|
|
fa164d459f | ||
|
|
f53c79c01b | ||
|
|
7dbe193bee | ||
|
|
a669f012dd | ||
|
|
237724c0c7 | ||
|
|
53f84c7f62 | ||
|
|
6692a1a53f | ||
|
|
a37cd7aaf5 | ||
|
|
e4cdbbf521 | ||
|
|
4568a6f842 | ||
|
|
5c72bb9e33 | ||
|
|
8c3bdb4ffc | ||
|
|
ffbad34b31 | ||
|
|
f086d39641 | ||
|
|
cc4baaab0d | ||
|
|
66409193dc | ||
|
|
2937f8a040 | ||
|
|
edf0bde0c6 | ||
|
|
8d03046269 | ||
|
|
9f48ffa1e8 | ||
|
|
871d4562f1 | ||
|
|
0f371f9e1a | ||
|
|
6bd109aa2f | ||
|
|
f7a40ec650 | ||
|
|
ff1b41dc57 | ||
|
|
fc4c4fda05 | ||
|
|
ef1a94abaa | ||
|
|
d9fb0be8c7 | ||
|
|
3f3adae6bc | ||
|
|
1ecbaaa382 | ||
|
|
d859ca2f9b | ||
|
|
3953dcc7f2 | ||
|
|
625ac28c61 | ||
|
|
b4b9308079 | ||
|
|
e2ba0df2d4 | ||
|
|
921360ce62 | ||
|
|
429805dbbc | ||
|
|
0da5e8979b | ||
|
|
baa80ae512 | ||
|
|
3e8ed78bf1 | ||
|
|
48493329d6 | ||
|
|
76dd75de77 | ||
|
|
63fd27e35f | ||
|
|
115ac3e4d7 | ||
|
|
cfcad42ff1 | ||
|
|
3f2873d42c | ||
|
|
ab915f837c | ||
|
|
ddd9a6b499 | ||
|
|
7abb69b5dc | ||
|
|
d5052fb24f | ||
|
|
b5a7ff42bb | ||
|
|
48fd1c4dd6 | ||
|
|
2bb73af7d1 | ||
|
|
86e92f9983 | ||
|
|
1c10b9de11 | ||
|
|
a66d36ea11 | ||
|
|
aa63a21ce0 | ||
|
|
797a7afba4 | ||
|
|
4b5ea12e90 | ||
|
|
2b6390fdc9 | ||
|
|
bd08ae67f9 | ||
|
|
4582c0efe7 | ||
|
|
834f36fe6d | ||
|
|
6f130def07 | ||
|
|
3931a7bd85 | ||
|
|
d9ee9c0872 | ||
|
|
0b0a73c1c9 | ||
|
|
81925ab73a | ||
|
|
9de1aa9b7f | ||
|
|
6f9aaa93e9 | ||
|
|
7e5664bdbc | ||
|
|
83f28bef6c | ||
|
|
96c727fda6 | ||
|
|
49dc570a72 | ||
|
|
cd1e04a234 | ||
|
|
27cb314e54 | ||
|
|
56a1142f03 | ||
|
|
5b37aa8c19 | ||
|
|
8ac9787350 | ||
|
|
9f9bd08af8 | ||
|
|
4c985dac39 | ||
|
|
3d77c0460d | ||
|
|
3ddad24608 | ||
|
|
6e37ab595c | ||
|
|
a1a79edaea | ||
|
|
49333cbdbe | ||
|
|
de92b479d9 | ||
|
|
0f128eb58c | ||
|
|
c630924d66 | ||
|
|
ff59fc82b3 | ||
|
|
52a1ae72f0 | ||
|
|
3a654c506f | ||
|
|
2763d4b51a | ||
|
|
e28836bf45 | ||
|
|
a6ebfacf7b | ||
|
|
c7961075c4 | ||
|
|
ab6ede7e04 | ||
|
|
b3538f1100 | ||
|
|
3b323bda58 | ||
|
|
13d86c7372 | ||
|
|
208fb610a6 | ||
|
|
4038ae2005 | ||
|
|
dd1721c799 | ||
|
|
a21e27bc99 | ||
|
|
b0ff858e78 | ||
|
|
54dae552b1 | ||
|
|
25c4198f7c | ||
|
|
4ead40cf67 | ||
|
|
04a0612e8a | ||
|
|
aa608c84b4 | ||
|
|
38365ff040 | ||
|
|
9c4270bcd9 | ||
|
|
46b066565e | ||
|
|
4dc9c657ad | ||
|
|
39595cfe31 | ||
|
|
ffa3d7d6a2 | ||
|
|
aa67fe7a8c | ||
|
|
bb2509fd2c | ||
|
|
61744359de | ||
|
|
095f62551f | ||
|
|
e25db1f273 | ||
|
|
79cb46c0e9 | ||
|
|
22ce550e53 | ||
|
|
30393100c1 | ||
|
|
459380965a | ||
|
|
21bac1bccd | ||
|
|
b1a1b6def5 | ||
|
|
baeb3adf21 | ||
|
|
39f6a04ca4 | ||
|
|
37c9ccebd1 | ||
|
|
71c73ac17c | ||
|
|
c6cb7407b3 | ||
|
|
333b2ceb97 | ||
|
|
b456b9fdfe | ||
|
|
34d0a36a1d | ||
|
|
355736f36f | ||
|
|
771287be11 | ||
|
|
dc9476b670 | ||
|
|
1e14cc0f48 | ||
|
|
55b548ae2b | ||
|
|
3b43646a08 | ||
|
|
3bc0d932d0 | ||
|
|
60225f4e75 | ||
|
|
1962446269 | ||
|
|
be37986a0f | ||
|
|
d7346a1e8c | ||
|
|
87d346f6a7 | ||
|
|
f0dd7f807d | ||
|
|
0c0502426f | ||
|
|
7f035f58c6 | ||
|
|
81e84f8dac | ||
|
|
55b42f6de3 | ||
|
|
ed8b68ad06 | ||
|
|
bad7b875eb | ||
|
|
5d162f20a9 | ||
|
|
9d29949440 | ||
|
|
1b75c1e61f | ||
|
|
293fd0f700 | ||
|
|
c1be917782 | ||
|
|
bb86e858b6 | ||
|
|
8445f5d2e2 | ||
|
|
72c9c3b11b | ||
|
|
6e3dba3fde | ||
|
|
7558ecd9ac | ||
|
|
1f776932a1 | ||
|
|
4820dce97a | ||
|
|
f8abe0c566 | ||
|
|
9def963c65 | ||
|
|
990123a937 | ||
|
|
1d6c639310 | ||
|
|
429798fd08 | ||
|
|
b5a8dd1dec | ||
|
|
95a0bd3701 | ||
|
|
8ff556739e | ||
|
|
496787677e | ||
|
|
e1ff419cf9 | ||
|
|
ee86ce68fc | ||
|
|
b75e936372 | ||
|
|
aa79235194 | ||
|
|
7c305be1bd | ||
|
|
f7fe362721 | ||
|
|
36bec089f7 | ||
|
|
45dd1fece4 | ||
|
|
5c0bd5b112 | ||
|
|
86e3b9a026 | ||
|
|
8273ea5a19 | ||
|
|
4f7b304f53 |
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
src/*.o
|
||||
src/*.mo
|
||||
src/dnsmasq.pot
|
||||
src/dnsmasq
|
||||
src/dnsmasq_baseline
|
||||
src/.configured
|
||||
contrib/wrt/dhcp_lease_time
|
||||
contrib/wrt/dhcp_release
|
||||
debian/base/
|
||||
debian/daemon/
|
||||
debian/files
|
||||
debian/substvars
|
||||
debian/utils-substvars
|
||||
debian/utils/
|
||||
416
CHANGELOG
416
CHANGELOG
@@ -1,3 +1,419 @@
|
||||
version 2.70
|
||||
Fix crash, introduced in 2.69, on TCP request when dnsmasq
|
||||
compiled with DNSSEC support, but running without DNSSEC
|
||||
enabled. Thanks to Manish Sing for spotting that one.
|
||||
|
||||
Fix regression which broke ipset functionality. Thanks to
|
||||
Wang Jian for the bug report.
|
||||
|
||||
|
||||
version 2.69
|
||||
Implement dynamic interface discovery on *BSD. This allows
|
||||
the contructor: syntax to be used in dhcp-range for DHCPv6
|
||||
on the BSD platform. Thanks to Matthias Andree for
|
||||
valuable research on how to implement this.
|
||||
|
||||
Fix infinite loop associated with some --bogus-nxdomain
|
||||
configs. Thanks fogobogo for the bug report.
|
||||
|
||||
Fix missing RA RDNS option with configuration like
|
||||
--dhcp-option=option6:23,[::] Thanks to Tsachi Kimeldorfer
|
||||
for spotting the problem.
|
||||
|
||||
Add [fd00::] and [fe80::] as special addresses in DHCPv6
|
||||
options, analogous to [::]. [fd00::] is replaced with the
|
||||
actual ULA of the interface on the machine running
|
||||
dnsmasq, [fe80::] with the link-local address.
|
||||
Thanks to Tsachi Kimeldorfer for championing this.
|
||||
|
||||
DNSSEC validation and caching. Dnsmasq needs to be
|
||||
compiled with this enabled, with
|
||||
|
||||
make dnsmasq COPTS=-DHAVE_DNSSEC
|
||||
|
||||
this add dependencies on the nettle crypto library and the
|
||||
gmp maths library. It's possible to have these linked
|
||||
statically with
|
||||
|
||||
make dnsmasq COPTS='-DHAVE_DNSSEC -DHAVE_DNSSEC_STATIC'
|
||||
|
||||
which bloats the dnsmasq binary, but saves the size of
|
||||
the shared libraries which are much bigger.
|
||||
|
||||
To enable, DNSSEC, you will need a set of
|
||||
trust-anchors. Now that the TLDs are signed, this can be
|
||||
the keys for the root zone, and for convenience they are
|
||||
included in trust-anchors.conf in the dnsmasq
|
||||
distribution. You should of course check that these are
|
||||
legitimate and up-to-date. So, adding
|
||||
|
||||
conf-file=/path/to/trust-anchors.conf
|
||||
dnssec
|
||||
|
||||
to your config is all thats needed to get things
|
||||
working. The upstream nameservers have to be DNSSEC-capable
|
||||
too, of course. Many ISP nameservers aren't, but the
|
||||
Google public nameservers (8.8.8.8 and 8.8.4.4) are.
|
||||
When DNSSEC is configured, dnsmasq validates any queries
|
||||
for domains which are signed. Query results which are
|
||||
bogus are replaced with SERVFAIL replies, and results
|
||||
which are correctly signed have the AD bit set. In
|
||||
addition, and just as importantly, dnsmasq supplies
|
||||
correct DNSSEC information to clients which are doing
|
||||
their own validation, and caches DNSKEY, DS and RRSIG
|
||||
records, which significantly improve the performance of
|
||||
downstream validators. Setting --log-queries will show
|
||||
DNSSEC in action.
|
||||
|
||||
If a domain is returned from an upstream nameserver without
|
||||
DNSSEC signature, dnsmasq by default trusts this. This
|
||||
means that for unsigned zone (still the majority) there
|
||||
is effectively no cost for having DNSSEC enabled. Of course
|
||||
this allows an attacker to replace a signed record with a
|
||||
false unsigned record. This is addressed by the
|
||||
--dnssec-check-unsigned flag, which instructs dnsmasq
|
||||
to prove that an unsigned record is legitimate, by finding
|
||||
a secure proof that the zone containing the record is not
|
||||
signed. Doing this has costs (typically one or two extra
|
||||
upstream queries). It also has a nasty failure mode if
|
||||
dnsmasq's upstream nameservers are not DNSSEC capable.
|
||||
Without --dnssec-check-unsigned using such an upstream
|
||||
server will simply result in not queries being validated;
|
||||
with --dnssec-check-unsigned enabled and a
|
||||
DNSSEC-ignorant upstream server, _all_ queries will fail.
|
||||
|
||||
Note that DNSSEC requires that the local time is valid and
|
||||
accurate, if not then DNSSEC validation will fail. NTP
|
||||
should be running. This presents a problem for routers
|
||||
without a battery-backed clock. To set the time needs NTP
|
||||
to do DNS lookups, but lookups will fail until NTP has run.
|
||||
To address this, there's a flag, --dnssec-no-timecheck
|
||||
which disables the time checks (only) in DNSSEC. When dnsmasq
|
||||
is started and the clock is not synced, this flag should
|
||||
be used. As soon as the clock is synced, SIGHUP dnsmasq.
|
||||
The SIGHUP clears the cache of partially-validated data and
|
||||
resets the no-timecheck flag, so that all DNSSEC checks
|
||||
henceforward will be complete.
|
||||
|
||||
The development of DNSSEC in dnsmasq was started by
|
||||
Giovanni Bajo, to whom huge thanks are owed. It has been
|
||||
supported by Comcast, whose techfund grant has allowed for
|
||||
an invaluable period of full-time work to get it to
|
||||
a workable state.
|
||||
|
||||
Add --rev-server. Thanks to Dave Taht for suggesting this.
|
||||
|
||||
Add --servers-file. Allows dynamic update of upstream servers
|
||||
full access to configuration.
|
||||
|
||||
Add --local-service. Accept DNS queries only from hosts
|
||||
whose address is on a local subnet, ie a subnet for which
|
||||
an interface exists on the server. This option
|
||||
only has effect if there are no --interface --except-interface,
|
||||
--listen-address or --auth-server options. It is intended
|
||||
to be set as a default on installation, to allow
|
||||
unconfigured installations to be useful but also safe from
|
||||
being used for DNS amplification attacks.
|
||||
|
||||
Fix crashes in cache_get_cname_target() when dangling CNAMEs
|
||||
encountered. Thanks to Andy and the rt-n56u project for
|
||||
find this and helping to chase it down.
|
||||
|
||||
Fix wrong RCODE in authoritative DNS replies to PTR queries. The
|
||||
correct answer was included, but the RCODE was set to NXDOMAIN.
|
||||
Thanks to Craig McQueen for spotting this.
|
||||
|
||||
Make statistics available as DNS queries in the .bind TLD as
|
||||
well as logging them.
|
||||
|
||||
|
||||
version 2.68
|
||||
Use random addresses for DHCPv6 temporary address
|
||||
allocations, instead of algorithmically determined stable
|
||||
addresses.
|
||||
|
||||
Fix bug which meant that the DHCPv6 DUID was not available
|
||||
in DHCP script runs during the lifetime of the dnsmasq
|
||||
process which created the DUID de-novo. Once the DUID was
|
||||
created and stored in the lease file and dnsmasq
|
||||
restarted, this bug disappeared.
|
||||
|
||||
Fix bug introduced in 2.67 which could result in erroneous
|
||||
NXDOMAIN returns to CNAME queries.
|
||||
|
||||
Fix build failures on MacOS X and openBSD.
|
||||
|
||||
Allow subnet specifications in --auth-zone to be interface
|
||||
names as well as address literals. This makes it possible
|
||||
to configure authoritative DNS when local address ranges
|
||||
are dynamic and works much better than the previous
|
||||
work-around which exempted contructed DHCP ranges from the
|
||||
IP address filtering. As a consequence, that work-around
|
||||
is removed. Under certain circumstances, this change wil
|
||||
break existing configuration: if you're relying on the
|
||||
contructed-range exception, you need to change --auth-zone
|
||||
to specify the same interface as is used to construct your
|
||||
DHCP ranges, probably with a trailing "/6" like this:
|
||||
--auth-zone=example.com,eth0/6 to limit the addresses to
|
||||
IPv6 addresses of eth0.
|
||||
|
||||
Fix problems when advertising deleted IPv6 prefixes. If
|
||||
the prefix is deleted (rather than replaced), it doesn't
|
||||
get advertised with zero preferred time. Thanks to Tsachi
|
||||
for the bug report.
|
||||
|
||||
Fix segfault with some locally configured CNAMEs. Thanks
|
||||
to Andrew Childs for spotting the problem.
|
||||
|
||||
Fix memory leak on re-reading /etc/hosts and friends,
|
||||
introduced in 2.67.
|
||||
|
||||
Check the arrival interface of incoming DNS and TFTP
|
||||
requests via IPv6, even in --bind-interfaces mode. This
|
||||
isn't possible for IPv4 and can generate scary warnings,
|
||||
but as it's always possible for IPv6 (the API always
|
||||
exists) then we should do it always.
|
||||
|
||||
Tweak the rules on prefix-lengths in --dhcp-range for
|
||||
IPv6. The new rule is that the specified prefix length
|
||||
must be larger than or equal to the prefix length of the
|
||||
corresponding address on the local interface.
|
||||
|
||||
|
||||
version 2.67
|
||||
Fix crash if upstream server returns SERVFAIL when
|
||||
--conntrack in use. Thanks to Giacomo Tazzari for finding
|
||||
this and supplying the patch.
|
||||
|
||||
Repair regression in 2.64. That release stopped sending
|
||||
lease-time information in the reply to DHCPINFORM
|
||||
requests, on the correct grounds that it was a standards
|
||||
violation. However, this broke the dnsmasq-specific
|
||||
dhcp_lease_time utility. Now, DHCPINFORM returns
|
||||
lease-time only if it's specifically requested
|
||||
(maintaining standards) and the dhcp_lease_time utility
|
||||
has been taught to ask for it (restoring functionality).
|
||||
|
||||
Fix --dhcp-match, --dhcp-vendorclass and --dhcp-userclass
|
||||
to work with BOOTP and well as DHCP. Thanks to Peter
|
||||
Korsgaard for spotting the problem.
|
||||
|
||||
Add --synth-domain. Thanks to Vishvananda Ishaya for
|
||||
suggesting this.
|
||||
|
||||
Fix failure to compile ipset.c if old kernel headers are
|
||||
in use. Thanks to Eugene Rudoy for pointing this out.
|
||||
|
||||
Handle IPv4 interface-address labels in Linux. These are
|
||||
often used to emulate the old IP-alias addresses. Before,
|
||||
using --interface=eth0 would service all the addresses of
|
||||
eth0, including ones configured as aliases, which appear
|
||||
in ifconfig as eth0:0. Now, only addresses with the label
|
||||
eth0 are active. This is not backwards compatible: if you
|
||||
want to continue to bind the aliases too, you need to add
|
||||
eg. --interface=eth0:0 to the config.
|
||||
|
||||
Fix "failed to set SO_BINDTODEVICE on DHCP socket: Socket
|
||||
operation on non-socket" error on startup with
|
||||
configurations which have exactly one --interface option
|
||||
and do RA but _not_ DHCPv6. Thanks to Trever Adams for the
|
||||
bug report.
|
||||
|
||||
Generalise --interface-name to cope with IPv6 addresses
|
||||
and multiple addresses per interface per address family.
|
||||
|
||||
Fix option parsing for --dhcp-host, which was generating a
|
||||
spurious error when all seven possible items were
|
||||
included. Thanks to Zhiqiang Wang for the bug report.
|
||||
|
||||
Remove restriction on prefix-length in --auth-zone. Thanks
|
||||
to Toke Hoiland-Jorgensen for suggesting this.
|
||||
|
||||
Log when the maximum number of concurrent DNS queries is
|
||||
reached. Thanks to Marcelo Salhab Brogliato for the patch.
|
||||
|
||||
If wildcards are used in --interface, don't assume that
|
||||
there will only ever be one available interface for DHCP
|
||||
just because there is one at start-up. More may appear, so
|
||||
we can't use SO_BINDTODEVICE. Thanks to Natrio for the bug
|
||||
report.
|
||||
|
||||
Increase timeout/number of retries in TFTP to accomodate
|
||||
AudioCodes Voice Gateways doing streaming writes to flash.
|
||||
Thanks to Damian Kaczkowski for spotting the problem.
|
||||
|
||||
Fix crash with empty DHCP string options when adding zero
|
||||
terminator. Thanks to Patrick McLean for the bug report.
|
||||
|
||||
Allow hostnames to start with a number, as allowed in
|
||||
RFC-1123. Thanks to Kyle Mestery for the patch.
|
||||
|
||||
Fixes to DHCP FQDN option handling: don't terminate FQDN
|
||||
if domain not known and allow a FQDN option with blank
|
||||
name to request that a FQDN option is returned in the
|
||||
reply. Thanks to Roy Marples for the patch.
|
||||
|
||||
Make --clear-on-reload apply to setting upstream servers
|
||||
via DBus too.
|
||||
|
||||
When the address which triggered the construction of an
|
||||
advertised IPv6 prefix disappears, continue to advertise
|
||||
the prefix for up to 2 hours, with the preferred lifetime
|
||||
set to zero. This satisfies RFC 6204 4.3 L-13 and makes
|
||||
things work better if a prefix disappears without being
|
||||
deprecated first. Thanks to Uwe Schindler for persuasively
|
||||
arguing for this.
|
||||
|
||||
Fix MAC address enumeration on *BSD. Thanks to Brad Smith
|
||||
for the bug report.
|
||||
|
||||
Support RFC-4242 information-refresh-time options in the
|
||||
reply to DHCPv6 information-request. The lease time of the
|
||||
smallest valid dhcp-range is sent. Thanks to Uwe Schindler
|
||||
for suggesting this.
|
||||
|
||||
Make --listen-address higher priority than --except-interface
|
||||
in all circumstances. Thanks to Thomas Hood for the bugreport.
|
||||
|
||||
Provide independent control over which interfaces get TFTP
|
||||
service. If enable-tftp is given a list of interfaces, then TFTP
|
||||
is provided on those. Without the list, the previous behaviour
|
||||
(provide TFTP to the same interfaces we provide DHCP to)
|
||||
is retained. Thanks to Lonnie Abelbeck for the suggestion.
|
||||
|
||||
Add --dhcp-relay config option. Many thanks to vtsl.net
|
||||
for sponsoring this development.
|
||||
|
||||
Fix crash with empty tag: in --dhcp-range. Thanks to
|
||||
Kaspar Schleiser for the bug report.
|
||||
|
||||
Add "baseline" and "bloatcheck" makefile targets, for
|
||||
revealing size changes during development. Thanks to
|
||||
Vladislav Grishenko for the patch.
|
||||
|
||||
Cope with DHCPv6 clients which send REQUESTs without
|
||||
address options - treat them as SOLICIT with rapid commit.
|
||||
|
||||
Support identification of clients by MAC address in
|
||||
DHCPv6. When using a relay, the relay must support RFC
|
||||
6939 for this to work. It always works for directly
|
||||
connected clients. Thanks to Vladislav Grishenko
|
||||
for prompting this feature.
|
||||
|
||||
Remove the rule for constructed DHCP ranges that the local
|
||||
address must be either the first or last address in the
|
||||
range. This was originally to avoid SLAAC addresses, but
|
||||
we now explicitly autoconfig and privacy addresses instead.
|
||||
|
||||
Update Polish translation. Thanks to Jan Psota.
|
||||
|
||||
Fix problem in DHCPv6 vendorclass/userclass matching
|
||||
code. Thanks to Tanguy Bouzeloc for the patch.
|
||||
|
||||
Update Spanish transalation. Thanks to Vicente Soriano.
|
||||
|
||||
Add --ra-param option. Thanks to Vladislav Grishenko for
|
||||
inspiration on this.
|
||||
|
||||
Add --add-subnet configuration, to tell upstream DNS
|
||||
servers where the original client is. Thanks to DNSthingy
|
||||
for sponsoring this feature.
|
||||
|
||||
Add --quiet-dhcp, --quiet-dhcp6 and --quiet-ra. Thanks to
|
||||
Kevin Darbyshire-Bryant for the initial patch.
|
||||
|
||||
Allow A/AAAA records created by --interface-name to be the
|
||||
target of --cname. Thanks to Hadmut Danisch for the
|
||||
suggestion.
|
||||
|
||||
Avoid treating a --dhcp-host which has an IPv6 address
|
||||
as eligable for use with DHCPv4 on the grounds that it has
|
||||
no address, and vice-versa. Thanks to Yury Konovalov for
|
||||
spotting the problem.
|
||||
|
||||
Do a better job caching dangling CNAMEs. Thanks to Yves
|
||||
Dorfsman for spotting the problem.
|
||||
|
||||
|
||||
version 2.66
|
||||
Add the ability to act as an authoritative DNS
|
||||
server. Dnsmasq can now answer queries from the wider 'net
|
||||
with local data, as long as the correct NS records are set
|
||||
up. Only local data is provided, to avoid creating an open
|
||||
DNS relay. Zone transfer is supported, to allow secondary
|
||||
servers to be configured.
|
||||
|
||||
Add "constructed DHCP ranges" for DHCPv6. This is intended
|
||||
for IPv6 routers which get prefixes dynamically via prefix
|
||||
delegation. With suitable configuration, stateful DHCPv6
|
||||
and RA can happen automatically as prefixes are delegated
|
||||
and then deprecated, without having to re-write the
|
||||
dnsmasq configuration file or restart the daemon. Thanks to
|
||||
Steven Barth for extensive testing and development work on
|
||||
this idea.
|
||||
|
||||
Fix crash on startup on Solaris 11. Regression probably
|
||||
introduced in 2.61. Thanks to Geoff Johnstone for the
|
||||
patch.
|
||||
|
||||
Add code to make behaviour for TCP DNS requests that same
|
||||
as for UDP requests, when a request arrives for an allowed
|
||||
address, but via a banned interface. This change is only
|
||||
active on Linux, since the relevant API is missing (AFAIK)
|
||||
on other platforms. Many thanks to Tomas Hozza for
|
||||
spotting the problem, and doing invaluable discovery of
|
||||
the obscure and undocumented API required for the solution.
|
||||
|
||||
Don't send the default DHCP option advertising dnsmasq as
|
||||
the local DNS server if dnsmasq is configured to not act
|
||||
as DNS server, or it's configured to a non-standard port.
|
||||
|
||||
Add DNSMASQ_CIRCUIT_ID, DNSMASQ_SUBCRIBER_ID,
|
||||
DNSMASQ_REMOTE_ID variables to the environment of the
|
||||
lease-change script (and the corresponding Lua). These hold
|
||||
information inserted into the DHCP request by a DHCP relay
|
||||
agent. Thanks to Lakefield Communications for providing a
|
||||
bounty for this addition.
|
||||
|
||||
Fixed crash, introduced in 2.64, whilst handling DHCPv6
|
||||
information-requests with some common configurations.
|
||||
Thanks to Robert M. Albrecht for the bug report and
|
||||
chasing the problem.
|
||||
|
||||
Add --ipset option. Thanks to Jason A. Donenfeld for the
|
||||
patch.
|
||||
|
||||
Don't erroneously reject some option names in --dhcp-match
|
||||
options. Thanks to Benedikt Hochstrasser for the bug report.
|
||||
|
||||
Allow a trailing '*' wildcard in all interface-name
|
||||
configurations. Thanks to Christian Parpart for the patch.
|
||||
|
||||
Handle the situation where libc headers define
|
||||
SO_REUSEPORT, but the kernel in use doesn't, to cope with
|
||||
the introduction of this option to Linux. Thanks to Rich
|
||||
Felker for the bug report.
|
||||
|
||||
Update Polish translation. Thanks to Jan Psota.
|
||||
|
||||
Fix crash if the configured DHCP lease limit is
|
||||
reached. Regression occurred in 2.61. Thanks to Tsachi for
|
||||
the bug report.
|
||||
|
||||
Update the French translation. Thanks to Gildas le Nadan.
|
||||
|
||||
|
||||
version 2.65
|
||||
Fix regression which broke forwarding of queries sent via
|
||||
TCP which are not for A and AAAA and which were directed to
|
||||
non-default servers. Thanks to Niax for the bug report.
|
||||
|
||||
Fix failure to build with DHCP support excluded. Thanks to
|
||||
Gustavo Zacarias for the patch.
|
||||
|
||||
Fix nasty regression in 2.64 which completely broke cacheing.
|
||||
|
||||
|
||||
version 2.64
|
||||
Handle DHCP FQDN options with all flag bits zero and
|
||||
--dhcp-client-update set. Thanks to Bernd Krumbroeck for
|
||||
|
||||
4
FAQ
4
FAQ
@@ -22,7 +22,7 @@ A: The high ports that dnsmasq opens are for replies from the upstream
|
||||
now uses a new, randomly selected, port for each query. The old
|
||||
default behaviour (use one port allocated by the OS) is available by
|
||||
setting --query-port=0, and setting the query port to a positive
|
||||
value is still works. You should think hard and know what you are
|
||||
value still works. You should think hard and know what you are
|
||||
doing before using either of these options.
|
||||
|
||||
Q: Why doesn't dnsmasq support DNS queries over TCP? Don't the RFC's specify
|
||||
@@ -112,7 +112,7 @@ A: Resolver code sometime does strange things when given names without
|
||||
hostname will fix things. (ie "ping myhost" fails, but "ping
|
||||
myhost." works. The solution is to make sure that all your hosts
|
||||
have a domain set ("domain" in resolv.conf, or set a domain in
|
||||
your DHCP server, see below fr Windows XP and Mac OS X).
|
||||
your DHCP server, see below for Windows XP and Mac OS X).
|
||||
Any domain will do, but "localnet" is traditional. Now when you
|
||||
resolve "myhost" the resolver will attempt to look up
|
||||
"myhost.localnet" so you need to have dnsmasq reply to that name.
|
||||
|
||||
66
Makefile
66
Makefile
@@ -1,4 +1,4 @@
|
||||
# dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
# dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -51,36 +51,44 @@ top!=pwd
|
||||
# GNU make way.
|
||||
top?=$(CURDIR)
|
||||
|
||||
dbus_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
|
||||
dbus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
|
||||
idn_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`
|
||||
idn_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
|
||||
ct_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --cflags libnetfilter_conntrack`
|
||||
ct_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
|
||||
lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.1`
|
||||
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.1`
|
||||
sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi`
|
||||
dbus_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
|
||||
dbus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
|
||||
idn_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`
|
||||
idn_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
|
||||
ct_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --cflags libnetfilter_conntrack`
|
||||
ct_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
|
||||
lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.1`
|
||||
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.1`
|
||||
nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --cflags nettle hogweed`
|
||||
nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --libs nettle hogweed`
|
||||
gmp_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --copy -lgmp`
|
||||
sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi`
|
||||
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
|
||||
|
||||
objs = cache.o rfc1035.o util.o option.o forward.o network.o \
|
||||
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
|
||||
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
|
||||
dhcp-common.o outpacket.o radv.o slaac.o
|
||||
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
|
||||
domain.o dnssec.o blockdata.o
|
||||
|
||||
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||
dns-protocol.h radv-protocol.h
|
||||
dns-protocol.h radv-protocol.h ip6addr.h
|
||||
|
||||
all : $(BUILDDIR)
|
||||
@cd $(BUILDDIR) && $(MAKE) \
|
||||
top="$(top)" \
|
||||
build_cflags="$(version) $(dbus_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags)" \
|
||||
build_libs="$(dbus_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs)" \
|
||||
build_cflags="$(version) $(dbus_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
|
||||
build_libs="$(dbus_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs)" \
|
||||
-f $(top)/Makefile dnsmasq
|
||||
|
||||
clean :
|
||||
rm -f *~ $(BUILDDIR)/*.mo contrib/*/*~ */*~ $(BUILDDIR)/*.pot
|
||||
mostly_clean :
|
||||
rm -f $(BUILDDIR)/*.mo $(BUILDDIR)/*.pot
|
||||
rm -f $(BUILDDIR)/.configured $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq
|
||||
rm -rf core */core
|
||||
|
||||
clean : mostly_clean
|
||||
rm -f $(BUILDDIR)/dnsmasq_baseline
|
||||
rm -f core */core
|
||||
rm -f *~ contrib/*/*~ */*~
|
||||
|
||||
install : all install-common
|
||||
|
||||
@@ -93,8 +101,8 @@ all-i18n : $(BUILDDIR)
|
||||
@cd $(BUILDDIR) && $(MAKE) \
|
||||
top="$(top)" \
|
||||
i18n=-DLOCALEDIR=\'\"$(LOCALEDIR)\"\' \
|
||||
build_cflags="$(version) $(dbus_cflags) $(ct_cflags) $(lua_cflags) `$(PKG_CONFIG) --cflags libidn`" \
|
||||
build_libs="$(dbus_libs) $(ct_libs) $(lua_libs) $(sunos_libs) `$(PKG_CONFIG) --libs libidn`" \
|
||||
build_cflags="$(version) $(dbus_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags) `$(PKG_CONFIG) --cflags libidn`" \
|
||||
build_libs="$(dbus_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) `$(PKG_CONFIG) --libs libidn`" \
|
||||
-f $(top)/Makefile dnsmasq
|
||||
for f in `cd $(PO); echo *.po`; do \
|
||||
cd $(top) && cd $(BUILDDIR) && $(MAKE) top="$(top)" -f $(top)/Makefile $${f%.po}.mo; \
|
||||
@@ -110,9 +118,24 @@ merge :
|
||||
echo -n msgmerge $(PO)/$$f && $(MSGMERGE) --no-wrap -U $(PO)/$$f $(BUILDDIR)/dnsmasq.pot; \
|
||||
done
|
||||
|
||||
# Cannonicalise .po file.
|
||||
%.po :
|
||||
@cd $(BUILDDIR) && $(MAKE) -f $(top)/Makefile dnsmasq.pot
|
||||
mv $(PO)/$*.po $(PO)/$*.po.orig && $(MSGMERGE) --no-wrap $(PO)/$*.po.orig $(BUILDDIR)/dnsmasq.pot >$(PO)/$*.po;
|
||||
|
||||
$(BUILDDIR):
|
||||
mkdir -p $(BUILDDIR)
|
||||
|
||||
# rules below are helpers for size tracking
|
||||
|
||||
baseline : mostly_clean all
|
||||
@cd $(BUILDDIR) && \
|
||||
mv dnsmasq dnsmasq_baseline
|
||||
|
||||
bloatcheck : $(BUILDDIR)/dnsmasq_baseline mostly_clean all
|
||||
@cd $(BUILDDIR) && \
|
||||
$(top)/bld/bloat-o-meter dnsmasq_baseline dnsmasq; \
|
||||
size dnsmasq_baseline dnsmasq
|
||||
|
||||
# rules below are targets in recusive makes with cwd=$(BUILDDIR)
|
||||
|
||||
@@ -126,7 +149,7 @@ $(objs:.o=.c) $(hdrs):
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $(COPTS) $(i18n) $(build_cflags) $(RPM_OPT_FLAGS) -c $<
|
||||
|
||||
dnsmasq : .configured $(hdrs) $(objs)
|
||||
dnsmasq : .configured $(hdrs) $(objs)
|
||||
$(CC) $(LDFLAGS) -o $@ $(objs) $(build_libs) $(LIBS)
|
||||
|
||||
dnsmasq.pot : $(objs:.o=.c) $(hdrs)
|
||||
@@ -135,5 +158,4 @@ dnsmasq.pot : $(objs:.o=.c) $(hdrs)
|
||||
%.mo : $(top)/$(PO)/%.po dnsmasq.pot
|
||||
$(MSGMERGE) -o - $(top)/$(PO)/$*.po dnsmasq.pot | $(MSGFMT) -o $*.mo -
|
||||
|
||||
|
||||
.PHONY : all clean install install-common all-i18n install-i18n merge
|
||||
.PHONY : all clean mostly_clean install install-common all-i18n install-i18n merge baseline bloatcheck
|
||||
|
||||
@@ -8,7 +8,8 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
||||
netlink.c network.c option.c rfc1035.c \
|
||||
rfc2131.c tftp.c util.c conntrack.c \
|
||||
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
|
||||
radv.c slaac.c
|
||||
radv.c slaac.c auth.c ipset.c domain.c \
|
||||
dnssec.c dnssec-openssl.c blockdata.c
|
||||
|
||||
LOCAL_MODULE := dnsmasq
|
||||
|
||||
|
||||
130
bld/bloat-o-meter
Executable file
130
bld/bloat-o-meter
Executable file
@@ -0,0 +1,130 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2004 Matt Mackall <mpm@selenic.com>
|
||||
#
|
||||
# Inspired by perl Bloat-O-Meter (c) 1997 by Andi Kleen
|
||||
#
|
||||
# This software may be used and distributed according to the terms
|
||||
# of the GNU General Public License, incorporated herein by reference.
|
||||
|
||||
import sys, os#, re
|
||||
|
||||
def usage():
|
||||
sys.stderr.write("usage: %s [-t] file1 file2\n" % sys.argv[0])
|
||||
sys.exit(-1)
|
||||
|
||||
f1, f2 = (None, None)
|
||||
flag_timing, dashes = (False, False)
|
||||
|
||||
for f in sys.argv[1:]:
|
||||
if f.startswith("-"):
|
||||
if f == "--": # sym_args
|
||||
dashes = True
|
||||
break
|
||||
if f == "-t": # timings
|
||||
flag_timing = True
|
||||
else:
|
||||
if not os.path.exists(f):
|
||||
sys.stderr.write("Error: file '%s' does not exist\n" % f)
|
||||
usage()
|
||||
if f1 is None:
|
||||
f1 = f
|
||||
elif f2 is None:
|
||||
f2 = f
|
||||
if flag_timing:
|
||||
import time
|
||||
if f1 is None or f2 is None:
|
||||
usage()
|
||||
|
||||
sym_args = " ".join(sys.argv[3 + flag_timing + dashes:])
|
||||
def getsizes(file):
|
||||
sym, alias, lut = {}, {}, {}
|
||||
for l in os.popen("readelf -W -s %s %s" % (sym_args, file)).readlines():
|
||||
l = l.strip()
|
||||
if not (len(l) and l[0].isdigit() and len(l.split()) == 8):
|
||||
continue
|
||||
num, value, size, typ, bind, vis, ndx, name = l.split()
|
||||
if ndx == "UND": continue # skip undefined
|
||||
if typ in ["SECTION", "FILES"]: continue # skip sections and files
|
||||
if "." in name: name = "static." + name.split(".")[0]
|
||||
value = int(value, 16)
|
||||
size = int(size, 16) if size.startswith('0x') else int(size)
|
||||
if vis != "DEFAULT" and bind != "GLOBAL": # see if it is an alias
|
||||
alias[(value, size)] = {"name" : name}
|
||||
else:
|
||||
sym[name] = {"addr" : value, "size": size}
|
||||
lut[(value, size)] = 0
|
||||
for addr, sz in iter(alias.keys()):
|
||||
# If the non-GLOBAL sym has an implementation elsewhere then
|
||||
# it's an alias, disregard it.
|
||||
if not (addr, sz) in lut:
|
||||
# If this non-GLOBAL sym does not have an implementation at
|
||||
# another address, then treat it as a normal symbol.
|
||||
sym[alias[(addr, sz)]["name"]] = {"addr" : addr, "size": sz}
|
||||
for l in os.popen("readelf -W -S " + file).readlines():
|
||||
x = l.split()
|
||||
if len(x)<6: continue
|
||||
# Should take these into account too!
|
||||
#if x[1] not in [".text", ".rodata", ".symtab", ".strtab"]: continue
|
||||
if x[1] not in [".rodata"]: continue
|
||||
sym[x[1]] = {"addr" : int(x[3], 16), "size" : int(x[5], 16)}
|
||||
return sym
|
||||
|
||||
if flag_timing:
|
||||
start_t1 = int(time.time() * 1e9)
|
||||
old = getsizes(f1)
|
||||
if flag_timing:
|
||||
end_t1 = int(time.time() * 1e9)
|
||||
start_t2 = int(time.time() * 1e9)
|
||||
new = getsizes(f2)
|
||||
if flag_timing:
|
||||
end_t2 = int(time.time() * 1e9)
|
||||
start_t3 = int(time.time() * 1e9)
|
||||
grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0
|
||||
delta, common = [], {}
|
||||
|
||||
for name in iter(old.keys()):
|
||||
if name in new:
|
||||
common[name] = 1
|
||||
|
||||
for name in old:
|
||||
if name not in common:
|
||||
remove += 1
|
||||
sz = old[name]["size"]
|
||||
down += sz
|
||||
delta.append((-sz, name))
|
||||
|
||||
for name in new:
|
||||
if name not in common:
|
||||
add += 1
|
||||
sz = new[name]["size"]
|
||||
up += sz
|
||||
delta.append((sz, name))
|
||||
|
||||
for name in common:
|
||||
d = new[name].get("size", 0) - old[name].get("size", 0)
|
||||
if d>0: grow, up = grow+1, up+d
|
||||
elif d<0: shrink, down = shrink+1, down-d
|
||||
else:
|
||||
continue
|
||||
delta.append((d, name))
|
||||
|
||||
delta.sort()
|
||||
delta.reverse()
|
||||
if flag_timing:
|
||||
end_t3 = int(time.time() * 1e9)
|
||||
|
||||
print("%-48s %7s %7s %+7s" % ("function", "old", "new", "delta"))
|
||||
for d, n in delta:
|
||||
if d:
|
||||
old_sz = old.get(n, {}).get("size", "-")
|
||||
new_sz = new.get(n, {}).get("size", "-")
|
||||
print("%-48s %7s %7s %+7d" % (n, old_sz, new_sz, d))
|
||||
print("-"*78)
|
||||
total="(add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s)%%sTotal: %s bytes"\
|
||||
% (add, remove, grow, shrink, up, -down, up-down)
|
||||
print(total % (" "*(80-len(total))))
|
||||
if flag_timing:
|
||||
print("\n%d/%d; %d Parse origin/new; processing nsecs" %
|
||||
(end_t1-start_t1, end_t2-start_t2, end_t3-start_t3))
|
||||
print("total nsecs: %d" % (end_t3-start_t1))
|
||||
@@ -12,12 +12,12 @@
|
||||
# first. This favours, eg v2.63 over 2.63rc6.
|
||||
|
||||
if which git >/dev/null 2>&1 && [ -d $1/.git ]; then
|
||||
cd $1; git describe
|
||||
cd $1; git describe | sed 's/^v//'
|
||||
elif grep '\$Format:%d\$' $1/VERSION >/dev/null 2>&1; then
|
||||
# unsubstituted VERSION, but no git available.
|
||||
echo UNKNOWN
|
||||
else
|
||||
vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep $v[0-9]`
|
||||
vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep ^v[0-9]`
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "${vers}" | sort | head -n 1 | sed 's/^v//'
|
||||
|
||||
@@ -2,10 +2,34 @@
|
||||
|
||||
search=$1
|
||||
shift
|
||||
pkg=$1
|
||||
shift
|
||||
op=$1
|
||||
shift
|
||||
|
||||
in=`cat`
|
||||
|
||||
if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
|
||||
grep $search >/dev/null 2>&1; then
|
||||
exec $*
|
||||
echo $in | grep $search >/dev/null 2>&1; then
|
||||
|
||||
if [ $op = "--copy" ]; then
|
||||
pkg="$*"
|
||||
elif grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
|
||||
echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
|
||||
pkg=`$pkg --static $op $*`
|
||||
else
|
||||
pkg=`$pkg $op $*`
|
||||
fi
|
||||
|
||||
if grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
|
||||
echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
|
||||
if [ $op = "--libs" ] || [ $op = "--copy" ]; then
|
||||
echo "-Wl,-Bstatic $pkg -Wl,-Bdynamic"
|
||||
else
|
||||
echo "$pkg"
|
||||
fi
|
||||
else
|
||||
echo "$pkg"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
|
||||
36
contrib/mactable/macscript
Executable file
36
contrib/mactable/macscript
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
|
||||
STATUS_FILE="/tmp/dnsmasq-ip-mac.status"
|
||||
|
||||
# Script for dnsmasq lease-change hook.
|
||||
# Maintains the above file with a IP address/MAC address pairs,
|
||||
# one lease per line. Works with IPv4 and IPv6 leases, file is
|
||||
# atomically updated, so no races for users of the data.
|
||||
|
||||
action="$1"
|
||||
mac="$2" # IPv4
|
||||
ip="$3"
|
||||
|
||||
# ensure it always exists.
|
||||
|
||||
if [ ! -f "$STATUS_FILE" ]; then
|
||||
touch "$STATUS_FILE"
|
||||
fi
|
||||
|
||||
if [ -n "$DNSMASQ_IAID" ]; then
|
||||
mac="$DNSMASQ_MAC" # IPv6
|
||||
fi
|
||||
|
||||
# worry about an add or old action when the MAC address is not known:
|
||||
# leave any old one in place in that case.
|
||||
|
||||
if [ "$action" = "add" -o "$action" = "old" -o "$action" = "del" ]; then
|
||||
if [ -n "$mac" -o "$action" = "del" ]; then
|
||||
sed "/^${ip//./\.} / d" "$STATUS_FILE" > "$STATUS_FILE".new
|
||||
|
||||
if [ "$action" = "add" -o "$action" = "old" ]; then
|
||||
echo "$ip $mac" >> "$STATUS_FILE".new
|
||||
fi
|
||||
mv "$STATUS_FILE".new "$STATUS_FILE" # atomic update.
|
||||
fi
|
||||
fi
|
||||
29
contrib/try-all-ns/dnsmasq-2.68-try-all-ns
Normal file
29
contrib/try-all-ns/dnsmasq-2.68-try-all-ns
Normal file
@@ -0,0 +1,29 @@
|
||||
From: Jesse Glick <jglick@cloudbees.com>
|
||||
To: dnsmasq-discuss@lists.thekelleys.org.uk
|
||||
Subject: Re: [Dnsmasq-discuss] Ability to delegate to one server but fall
|
||||
back to another after NXDOMAIN?
|
||||
|
||||
|
||||
On Wed, Jan 15, 2014 at 12:30 PM, Simon Kelley <simon@thekelleys.org.uk> wrote:
|
||||
> > There's a (very old) patch in contrib/try-all-ns that would make a starting point
|
||||
This does not apply against trunk, so I tried to rework it. The
|
||||
following appears to do what I expect:
|
||||
|
||||
diff --git a/src/forward.c b/src/forward.c
|
||||
index 8167229..76070b5 100644
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -610,7 +610,11 @@ void reply_query(int fd, int family, time_t now)
|
||||
|
||||
if ((RCODE(header) == SERVFAIL || RCODE(header) == REFUSED) &&
|
||||
!option_bool(OPT_ORDER) &&
|
||||
- forward->forwardall == 0)
|
||||
+ forward->forwardall == 0 ||
|
||||
+ /* try each in turn */
|
||||
+ RCODE(header) == NXDOMAIN &&
|
||||
+ option_bool(OPT_ORDER) &&
|
||||
+ server->next != NULL)
|
||||
/* for broken servers, attempt to send to another one. */
|
||||
{
|
||||
unsigned char *pheader;
|
||||
|
||||
@@ -12,9 +12,11 @@ If an error occurs or no lease exists for the given address,
|
||||
nothing is sent to stdout a message is sent to stderr and a
|
||||
non-zero error code is returned.
|
||||
|
||||
Requires dnsmasq 2.40 or later and may not work with other DHCP servers.
|
||||
Requires dnsmasq 2.67 or later and may not work with other DHCP servers.
|
||||
|
||||
The address argument is a dotted-quad IP addresses and mandatory.
|
||||
The address argument is a dotted-quad IP addresses and mandatory.
|
||||
.SH LIMITATIONS
|
||||
Only works with IPv4 addresses and DHCP leases.
|
||||
.SH SEE ALSO
|
||||
.BR dnsmasq (8)
|
||||
.SH AUTHOR
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
nothing is sent to stdout a message is sent to stderr and a
|
||||
non-zero error code is returned.
|
||||
|
||||
Requires dnsmasq 2.40 or later.
|
||||
This version requires dnsmasq 2.67 or later.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
@@ -46,6 +46,7 @@
|
||||
#define OPTION_LEASE_TIME 51
|
||||
#define OPTION_OVERLOAD 52
|
||||
#define OPTION_MESSAGE_TYPE 53
|
||||
#define OPTION_REQUESTED_OPTIONS 55
|
||||
#define OPTION_END 255
|
||||
#define DHCPINFORM 8
|
||||
#define DHCP_SERVER_PORT 67
|
||||
@@ -167,6 +168,12 @@ int main(int argc, char **argv)
|
||||
*(p++) = 1;
|
||||
*(p++) = DHCPINFORM;
|
||||
|
||||
/* Explicity request the lease time, it won't be sent otherwise:
|
||||
this is a dnsmasq extension, not standard. */
|
||||
*(p++) = OPTION_REQUESTED_OPTIONS;
|
||||
*(p++) = 1;
|
||||
*(p++) = OPTION_LEASE_TIME;
|
||||
|
||||
*(p++) = OPTION_END;
|
||||
|
||||
dest.sin_family = AF_INET;
|
||||
|
||||
@@ -27,6 +27,8 @@ for ethernet. This encoding is the one used in dnsmasq lease files.
|
||||
The client-id is optional. If it is "*" then it treated as being missing.
|
||||
.SH NOTES
|
||||
MUST be run as root - will fail otherwise.
|
||||
.SH LIMITATIONS
|
||||
Only usable on IPv4 DHCP leases.
|
||||
.SH SEE ALSO
|
||||
.BR dnsmasq (8)
|
||||
.SH AUTHOR
|
||||
|
||||
@@ -255,10 +255,6 @@ int main(int argc, char **argv)
|
||||
struct ifreq ifr;
|
||||
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
int nl = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
struct iovec iov;
|
||||
|
||||
iov.iov_len = 200;
|
||||
iov.iov_base = malloc(iov.iov_len);
|
||||
|
||||
if (argc < 4 || argc > 5)
|
||||
{
|
||||
|
||||
64
debian/changelog
vendored
64
debian/changelog
vendored
@@ -1,3 +1,67 @@
|
||||
dnsmasq (2.70-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 23 Apr 2014 15:14:42 +0000
|
||||
|
||||
dnsmasq (2.69-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
* Set --local-service. (closes: #732610)
|
||||
This tells dnsmasq to ignore DNS requests that don't come
|
||||
from a local network. It's automatically ignored if
|
||||
--interface --except-interface, --listen-address or
|
||||
--auth-server exist in the configuration, so for most
|
||||
installations, it will have no effect, but for
|
||||
otherwise-unconfigured installations, it stops dnsmasq
|
||||
from being vulnerable to DNS-reflection attacks.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 4 Feb 2014 16:28:12 +0000
|
||||
|
||||
dnsmasq (2.68-1) unstable; urgency=low
|
||||
|
||||
* New upstream. (closes: #730553)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 8 Dec 2013 15:57:32 +0000
|
||||
|
||||
dnsmasq (2.67-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
* Update resolvconf script. (closes: #720732)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 4 Aug 2013 14:53:22 +0000
|
||||
|
||||
dnsmasq (2.66-4) unstable; urgency=low
|
||||
|
||||
* Update resolvconf script. (closes: #716908)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 4 Aug 2013 14:48:21 +0000
|
||||
|
||||
dnsmasq (2.66-3) unstable; urgency=low
|
||||
|
||||
* Update resolvconf script for dnscrypt-proxy integration. (closes: #709179)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 28 May 2013 14:39:51 +0000
|
||||
|
||||
dnsmasq (2.66-2) unstable; urgency=low
|
||||
|
||||
* Fix error on startup with some configs. (closes: #709010)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Mon, 20 May 2013 11:46:11 +0000
|
||||
|
||||
dnsmasq (2.66-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
* Add support for noipset in DEB_BUILD_OPTIONS.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 22 Feb 2013 21:52:13 +0000
|
||||
|
||||
dnsmasq (2.65-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 14 Dec 2012 11:34:12 +0000
|
||||
|
||||
dnsmasq (2.64-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
|
||||
5
debian/control
vendored
5
debian/control
vendored
@@ -1,13 +1,14 @@
|
||||
Source: dnsmasq
|
||||
Section: net
|
||||
Priority: optional
|
||||
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any], libidn11-dev, libdbus-1-dev (>=0.61)
|
||||
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any],
|
||||
libidn11-dev, libdbus-1-dev (>=0.61), libgmp-dev, nettle-dev (>=2.4-3)
|
||||
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Standards-Version: 3.9.3
|
||||
|
||||
Package: dnsmasq
|
||||
Architecture: all
|
||||
Depends: netbase, dnsmasq-base(>= ${source:Version})
|
||||
Depends: netbase, dnsmasq-base(>= ${binary:Version})
|
||||
Suggests: resolvconf
|
||||
Conflicts: resolvconf (<<1.15)
|
||||
Description: Small caching DNS proxy and DHCP/TFTP server
|
||||
|
||||
2
debian/copyright
vendored
2
debian/copyright
vendored
@@ -1,4 +1,4 @@
|
||||
dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
dnsmasq is Copyright (c) 2000-2013 Simon Kelley
|
||||
|
||||
It was downloaded from: http://www.thekelleys.org.uk/dnsmasq/
|
||||
|
||||
|
||||
2
debian/default
vendored
2
debian/default
vendored
@@ -27,7 +27,7 @@ CONFIG_DIR=/etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new
|
||||
# If the resolvconf package is installed, dnsmasq will use its output
|
||||
# rather than the contents of /etc/resolv.conf to find upstream
|
||||
# nameservers. Uncommenting this line inhibits this behaviour.
|
||||
# Not that including a "resolv-file=<filename>" line in
|
||||
# Note that including a "resolv-file=<filename>" line in
|
||||
# /etc/dnsmasq.conf is not enough to override resolvconf if it is
|
||||
# installed: the line below must be uncommented.
|
||||
#IGNORE_RESOLVCONF=yes
|
||||
|
||||
8
debian/init
vendored
8
debian/init
vendored
@@ -90,6 +90,14 @@ if [ ! "$DNSMASQ_USER" ]; then
|
||||
DNSMASQ_USER="dnsmasq"
|
||||
fi
|
||||
|
||||
# This tells dnsmasq to ignore DNS requests that don't come from a local network.
|
||||
# It's automatically ignored if --interface --except-interface, --listen-address
|
||||
# or --auth-server exist in the configuration, so for most installations, it will
|
||||
# have no effect, but for otherwise-unconfigured installations, it stops dnsmasq
|
||||
# from being vulnerable to DNS-reflection attacks.
|
||||
|
||||
DNSMASQ_OPTS="$DNSMASQ_OPTS --local-service"
|
||||
|
||||
start()
|
||||
{
|
||||
# Return
|
||||
|
||||
5
debian/readme
vendored
5
debian/readme
vendored
@@ -59,11 +59,14 @@ Notes on configuring dnsmasq as packaged for Debian.
|
||||
noipv6 : omit IPv6 support.
|
||||
nodbus : omit DBus support.
|
||||
noconntrack : omit connection tracking support.
|
||||
noipset : omit IPset support.
|
||||
nortc : compile alternate mode suitable for systems without an RTC.
|
||||
noi18n : omit translations and internationalisation support.
|
||||
noidn : omit international domain name support, must be
|
||||
combined with noi18n to be effective.
|
||||
|
||||
gitversion : set the version of the produced packages from the
|
||||
git-derived versioning information on the source,
|
||||
rather the the debian changelog.
|
||||
|
||||
(9) Dnsmasq comes as three packages - dnsmasq-utils, dnsmasq-base and
|
||||
dnsmasq. Dnsmasq-base provides the dnsmasq executable and
|
||||
|
||||
38
debian/resolvconf
vendored
38
debian/resolvconf
vendored
@@ -1,16 +1,14 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
#
|
||||
# Script to update the resolver list for dnsmasq
|
||||
#
|
||||
# N.B. Resolvconf may run us even if dnsmasq is not running.
|
||||
# If dnsmasq is installed then we go ahead and update
|
||||
# the resolver list in case dnsmasq is started later.
|
||||
# N.B. Resolvconf may run us even if dnsmasq is not (yet) running.
|
||||
# If dnsmasq is installed then we go ahead and update the resolver list
|
||||
# in case dnsmasq is started later.
|
||||
#
|
||||
# Assumption: On entry, PWD contains the resolv.conf-type files
|
||||
# Assumption: On entry, PWD contains the resolv.conf-type files.
|
||||
#
|
||||
# Requires bash because it uses a non-POSIX printf extension.
|
||||
#
|
||||
# Licensed under the GNU GPL. See /usr/share/common-licenses/GPL.
|
||||
# This file is part of the dnsmasq package.
|
||||
#
|
||||
|
||||
set -e
|
||||
@@ -18,6 +16,7 @@ set -e
|
||||
RUN_DIR="/var/run/dnsmasq"
|
||||
RSLVRLIST_FILE="${RUN_DIR}/resolv.conf"
|
||||
TMP_FILE="${RSLVRLIST_FILE}_new.$$"
|
||||
MY_NAME_FOR_RESOLVCONF="dnsmasq"
|
||||
|
||||
[ -x /usr/sbin/dnsmasq ] || exit 0
|
||||
[ -x /lib/resolvconf/list-records ] || exit 1
|
||||
@@ -27,7 +26,7 @@ PATH=/bin:/sbin
|
||||
report_err() { echo "$0: Error: $*" >&2 ; }
|
||||
|
||||
# Stores arguments (minus duplicates) in RSLT, separated by spaces
|
||||
# Doesn't work properly if an argument itself contain whitespace
|
||||
# Doesn't work properly if an argument itself contains whitespace
|
||||
uniquify()
|
||||
{
|
||||
RSLT=""
|
||||
@@ -45,7 +44,22 @@ if [ ! -d "$RUN_DIR" ] && ! mkdir --parents --mode=0755 "$RUN_DIR" ; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RSLVCNFFILES="$(/lib/resolvconf/list-records | sed -e '/^lo.dnsmasq$/d')"
|
||||
RSLVCNFFILES=""
|
||||
for F in $(/lib/resolvconf/list-records --after "lo.$MY_NAME_FOR_RESOLVCONF") ; do
|
||||
case "$F" in
|
||||
"lo.$MY_NAME_FOR_RESOLVCONF")
|
||||
# Omit own record
|
||||
;;
|
||||
lo.*)
|
||||
# Include no more records after one for a local nameserver
|
||||
RSLVCNFFILES="${RSLVCNFFILES:+$RSLVCNFFILES }$F"
|
||||
break
|
||||
;;
|
||||
*)
|
||||
RSLVCNFFILES="${RSLVCNFFILES:+$RSLVCNFFILES }$F"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
NMSRVRS=""
|
||||
if [ "$RSLVCNFFILES" ] ; then
|
||||
@@ -56,8 +70,8 @@ fi
|
||||
# Dnsmasq uses the mtime of $RSLVRLIST_FILE, with a resolution of one second,
|
||||
# to detect changes in the file. This means that if a resolvconf update occurs
|
||||
# within one second of the previous one then dnsmasq may fail to notice the
|
||||
# more recent change. To work around this problem we sleep here to ensure
|
||||
# that the new mtime is different.
|
||||
# more recent change. To work around this problem we sleep one second here
|
||||
# if necessary in order to ensure that the new mtime is different.
|
||||
if [ -f "$RSLVRLIST_FILE" ] && [ "$(ls -go --time-style='+%s' "$RSLVRLIST_FILE" | { read p h s t n ; echo "$t" ; })" = "$(date +%s)" ] ; then
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
53
debian/rules
vendored
53
debian/rules
vendored
@@ -17,55 +17,72 @@ CFLAGS += -Wall -W
|
||||
|
||||
LDFLAGS = $(shell dpkg-buildflags --get LDFLAGS)
|
||||
|
||||
COPTS =
|
||||
DEB_COPTS = $(COPTS)
|
||||
|
||||
# The nettle library in Debian is too old to include
|
||||
# ECC support.
|
||||
DEB_COPTS += -DNO_NETTLE_ECC
|
||||
|
||||
TARGET = install-i18n
|
||||
|
||||
DEB_BUILD_ARCH_OS := $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS)
|
||||
|
||||
# Force package version based on git tags.
|
||||
ifneq (,$(filter gitversion,$(DEB_BUILD_OPTIONS)))
|
||||
PACKAGE_VERSION = $(shell bld/get-version `pwd` | sed 's/test/~&/; s/[a-z]/~&/; s/-/./g; s/$$/-1/; s/^/-v/';)
|
||||
endif
|
||||
|
||||
ifeq (,$(filter nodbus,$(DEB_BUILD_OPTIONS)))
|
||||
COPTS += -DHAVE_DBUS
|
||||
DEB_COPTS += -DHAVE_DBUS
|
||||
endif
|
||||
|
||||
ifeq (,$(filter noconntrack,$(DEB_BUILD_OPTIONS)))
|
||||
ifeq ($(DEB_BUILD_ARCH_OS),linux)
|
||||
COPTS += -DHAVE_CONNTRACK
|
||||
DEB_COPTS += -DHAVE_CONNTRACK
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(filter noipset,$(DEB_BUILD_OPTIONS)))
|
||||
DEB_COPTS += -DNO_IPSET
|
||||
endif
|
||||
|
||||
ifneq (,$(filter nodhcp6,$(DEB_BUILD_OPTIONS)))
|
||||
COPTS += -DNO_DHCP6
|
||||
DEB_COPTS += -DNO_DHCP6
|
||||
endif
|
||||
|
||||
ifneq (,$(filter noipv6,$(DEB_BUILD_OPTIONS)))
|
||||
COPTS += -DNO_IPV6
|
||||
DEB_COPTS += -DNO_IPV6
|
||||
endif
|
||||
|
||||
ifneq (,$(filter notftp,$(DEB_BUILD_OPTIONS)))
|
||||
COPTS += -DNO_TFTP
|
||||
DEB_COPTS += -DNO_TFTP
|
||||
endif
|
||||
|
||||
ifneq (,$(filter nodhcp,$(DEB_BUILD_OPTIONS)))
|
||||
COPTS += -DNO_DHCP
|
||||
DEB_COPTS += -DNO_DHCP
|
||||
endif
|
||||
|
||||
ifneq (,$(filter noscript,$(DEB_BUILD_OPTIONS)))
|
||||
COPTS += -DNO_SCRIPT
|
||||
DEB_COPTS += -DNO_SCRIPT
|
||||
endif
|
||||
|
||||
ifneq (,$(filter nortc,$(DEB_BUILD_OPTIONS)))
|
||||
COPTS += -DHAVE_BROKEN_RTC
|
||||
DEB_COPTS += -DHAVE_BROKEN_RTC
|
||||
endif
|
||||
|
||||
ifneq (,$(filter noi18n,$(DEB_BUILD_OPTIONS)))
|
||||
TARGET = install
|
||||
ifeq (,$(filter noidn, $(DEB_BUILD_OPTIONS)))
|
||||
COPTS += -DHAVE_IDN
|
||||
DEB_COPTS += -DHAVE_IDN
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(filter uselua,$(DEB_BUILD_OPTIONS)))
|
||||
COPTS += -DHAVE_LUASCRIPT
|
||||
DEB_COPTS += -DHAVE_LUASCRIPT
|
||||
endif
|
||||
|
||||
ifeq (,$(filter nodnssec,$(DEB_BUILD_OPTIONS)))
|
||||
DEB_COPTS += -DHAVE_DNSSEC
|
||||
endif
|
||||
|
||||
clean:
|
||||
@@ -99,7 +116,7 @@ binary-indep: checkroot
|
||||
install -m 644 debian/insserv debian/daemon/etc/insserv.conf.d/dnsmasq
|
||||
ln -s $(package) debian/daemon/usr/share/doc/dnsmasq
|
||||
cd debian/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-gencontrol -pdnsmasq -Pdebian/daemon
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -T -pdnsmasq -Pdebian/daemon
|
||||
chown -R root.root debian/daemon
|
||||
chmod -R g-ws debian/daemon
|
||||
dpkg --build debian/daemon ..
|
||||
@@ -113,12 +130,14 @@ binary-arch: checkroot
|
||||
-d debian/base/usr/share/doc/$(package) \
|
||||
-d debian/base/usr/share/doc/$(package)/examples \
|
||||
-d debian/base/var/run \
|
||||
-d debian/base/usr/share/$(package) \
|
||||
-d debian/base/var/lib/misc
|
||||
make $(TARGET) PREFIX=/usr DESTDIR=`pwd`/debian/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(COPTS)" CC=gcc
|
||||
make $(TARGET) PREFIX=/usr DESTDIR=`pwd`/debian/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=gcc
|
||||
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
|
||||
install -m 644 doc.html debian/base/usr/share/doc/$(package)/.
|
||||
install -m 644 setup.html debian/base/usr/share/doc/$(package)/.
|
||||
install -m 644 dnsmasq.conf.example debian/base/usr/share/doc/$(package)/examples/.
|
||||
install -m 644 trust-anchors.conf debian/base/usr/share/$(package)/.
|
||||
install -m 644 FAQ debian/base/usr/share/doc/$(package)/.
|
||||
gzip -9 debian/base/usr/share/doc/$(package)/FAQ
|
||||
install -m 644 CHANGELOG debian/base/usr/share/doc/$(package)/changelog
|
||||
@@ -146,8 +165,8 @@ ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
strip -R .note -R .comment debian/base/usr/sbin/dnsmasq
|
||||
endif
|
||||
cd debian/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-shlibdeps debian/base/usr/sbin/dnsmasq
|
||||
dpkg-gencontrol -pdnsmasq-base -Pdebian/base
|
||||
dpkg-shlibdeps --warnings=1 debian/base/usr/sbin/dnsmasq
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq-base -Pdebian/base
|
||||
chown -R root.root debian/base
|
||||
chmod -R g-ws debian/base
|
||||
dpkg --build debian/base ..
|
||||
@@ -158,7 +177,7 @@ ifeq ($(DEB_BUILD_ARCH_OS),linux)
|
||||
-d debian/utils/usr/share/man/man1 \
|
||||
-d debian/utils/usr/bin \
|
||||
-d debian/utils/usr/share/doc/dnsmasq-utils
|
||||
make -C contrib/wrt PREFIX=/usr DESTDIR=`pwd`/debian/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(COPTS)" CC=gcc
|
||||
make -C contrib/wrt PREFIX=/usr DESTDIR=`pwd`/debian/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=gcc
|
||||
install -m 755 contrib/wrt/dhcp_release debian/utils/usr/bin/dhcp_release
|
||||
install -m 644 contrib/wrt/dhcp_release.1 debian/utils/usr/share/man/man1/dhcp_release.1
|
||||
gzip -9 debian/utils/usr/share/man/man1/dhcp_release.1
|
||||
@@ -174,7 +193,7 @@ ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
endif
|
||||
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-shlibdeps -Tdebian/utils-substvars debian/utils/usr/bin/dhcp_release debian/utils/usr/bin/dhcp_lease_time
|
||||
dpkg-gencontrol -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/utils
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/utils
|
||||
chown -R root.root debian/utils
|
||||
chmod -R g-ws debian/utils
|
||||
dpkg --build debian/utils ..
|
||||
|
||||
@@ -20,6 +20,18 @@
|
||||
# Never forward addresses in the non-routed address spaces.
|
||||
#bogus-priv
|
||||
|
||||
# Uncomment these to enable DNSSEC validation and caching:
|
||||
# (Requires dnsmasq to be built with DNSSEC option.)
|
||||
#conf-file=%%PREFIX%%/share/dnsmasq/trust-anchors.conf
|
||||
#dnssec
|
||||
|
||||
# Replies which are not DNSSEC signed may be legitimate, because the domain
|
||||
# is unsigned, or may be forgeries. Setting this option tells dnsmasq to
|
||||
# check that an unsigned reply is OK, by finding a secure proof that a DS
|
||||
# record somewhere between the root and the domain does not exist.
|
||||
# The cost of setting this is that even queries in unsigned domains will need
|
||||
# one or more extra DNS queries to verify.
|
||||
#dnssec-check-unsigned
|
||||
|
||||
# Uncomment this to filter useless windows-originated DNS requests
|
||||
# which can trigger dial-on-demand links needlessly.
|
||||
@@ -69,6 +81,10 @@
|
||||
# --address (and --server) work with IPv6 addresses too.
|
||||
#address=/www.thekelleys.org.uk/fe80::20d:60ff:fe36:f83
|
||||
|
||||
# Add the IPs of all queries to yahoo.com, google.com, and their
|
||||
# subdomains to the vpn and search ipsets:
|
||||
#ipset=/yahoo.com/google.com/vpn,search
|
||||
|
||||
# You can control how dnsmasq talks to a server: this forces
|
||||
# queries to 10.1.2.3 to be routed via eth1
|
||||
# server=10.1.2.3@eth1
|
||||
|
||||
130
doc.html
130
doc.html
@@ -1,6 +1,6 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE> Dnsmasq - a DNS forwarder for NAT firewalls.</TITLE>
|
||||
<TITLE> Dnsmasq - network services for small networks.</TITLE>
|
||||
<link rel="icon"
|
||||
href="http://www.thekelleys.org.uk/dnsmasq/images/favicon.ico">
|
||||
</HEAD>
|
||||
@@ -11,82 +11,48 @@
|
||||
<td align="middle" valign="middle"><h1>Dnsmasq</h1></td>
|
||||
<td align="right" valign="middle"><img border="0" src="http://www.thekelleys.org.uk/dnsmasq/images/icon.png" /></td></tr>
|
||||
</table>
|
||||
Dnsmasq provides network infrastructure for small networks: DNS, DHCP, router advertisement and network boot. It is designed to be
|
||||
lightweight and have a small footprint, suitable for resource constrained routers and firewalls. It has also been widely used
|
||||
for tethering on smartphones and portable hotspots, and to support virtual networking in virtualisation frameworks.
|
||||
Supported platforms include Linux (with glibc and uclibc), Android, *BSD, and Mac OS X. Dnsmasq is included in most
|
||||
Linux distributions and the ports systems of FreeBSD, OpenBSD and NetBSD. Dnsmasq provides full IPv6 support.
|
||||
|
||||
Dnsmasq is a lightweight, easy to configure DNS forwarder and DHCP
|
||||
server. It is designed to provide DNS and, optionally, DHCP, to a
|
||||
small network. It can serve the names of local machines which are
|
||||
not in the global DNS. The DHCP server integrates with the DNS
|
||||
server and allows machines with DHCP-allocated addresses
|
||||
to appear in the DNS with names configured either in each host or
|
||||
in a central configuration file. Dnsmasq supports static and dynamic
|
||||
DHCP leases and BOOTP/TFTP/PXE for network booting of diskless machines.
|
||||
<P>
|
||||
Dnsmasq is targeted at home networks using NAT and
|
||||
connected to the internet via a modem, cable-modem or ADSL
|
||||
connection but would be a good choice for any smallish network (up to
|
||||
1000 clients is known to work) where low
|
||||
resource use and ease of configuration are important.
|
||||
<P>
|
||||
Supported platforms include Linux (with glibc and uclibc), Android, *BSD,
|
||||
Solaris and Mac OS X.
|
||||
Dnsmasq is included in at least the following Linux distributions:
|
||||
Gentoo, Debian, Slackware, Suse, Fedora,
|
||||
Smoothwall, IP-Cop, floppyfw, Firebox, LEAF, Freesco, fli4l,
|
||||
CoyoteLinux, Endian Firewall and
|
||||
Clarkconnect. It is also available as FreeBSD, OpenBSD and NetBSD ports and is used in
|
||||
Linksys wireless routers (dd-wrt, openwrt and the stock firmware) and the m0n0wall project.
|
||||
<P>
|
||||
Dnsmasq provides the following features:
|
||||
The DNS subsystem provides a local DNS server for the network, with forwarding of all query types to upstream recursive DNS servers and
|
||||
cacheing of common record types (A, AAAA, CNAME and PTR, also DNSKEY and DS when DNSSEC is enabled).
|
||||
<DIR>
|
||||
|
||||
<LI>
|
||||
The DNS configuration of machines behind the firewall is simple and
|
||||
doesn't depend on the details of the ISP's dns servers
|
||||
<LI>
|
||||
Clients which try to do DNS lookups while a modem link to the
|
||||
internet is down will time out immediately.
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq will serve names from the /etc/hosts file on the firewall
|
||||
machine: If the names of local machines are there, then they can all
|
||||
be addressed without having to maintain /etc/hosts on each machine.
|
||||
</LI>
|
||||
<LI>
|
||||
The integrated DHCP server supports static and dynamic DHCP leases and
|
||||
multiple networks and IP ranges. It works across BOOTP relays and
|
||||
supports DHCP options including RFC3397 DNS search lists.
|
||||
Machines which are configured by DHCP have their names automatically
|
||||
included in the DNS and the names can specified by each machine or
|
||||
centrally by associating a name with a MAC address in the dnsmasq
|
||||
config file.
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq caches internet addresses (A records and AAAA records) and address-to-name
|
||||
mappings (PTR records), reducing the load on upstream servers and
|
||||
improving performance (especially on modem connections).
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq can be configured to automatically pick up the addresses of
|
||||
its upstream nameservers from ppp or dhcp configuration. It will
|
||||
automatically reload this information if it changes. This facility
|
||||
will be of particular interest to maintainers of Linux firewall
|
||||
distributions since it allows dns configuration to be made automatic.
|
||||
</LI>
|
||||
<LI>
|
||||
On IPv6-enabled boxes, dnsmasq can both talk to upstream servers via IPv6
|
||||
and offer DNS service via IPv6. On dual-stack (IPv4 and IPv6) boxes it talks
|
||||
both protocols and can even act as IPv6-to-IPv4 or IPv4-to-IPv6 forwarder.
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq can be configured to send queries for certain domains to
|
||||
upstream servers handling only those domains. This makes integration
|
||||
with private DNS systems easy.
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq supports MX and SRV records and can be configured to return MX records
|
||||
for any or all local machines.
|
||||
</LI>
|
||||
<LI>Local DNS names can be defined by reading /etc/hosts, by importing names from the DHCP subsystem, or by configuration of a wide range of useful record types.</LI>
|
||||
<LI>Upstream servers can be configured in a variety of convenient ways, including dynamic configuration as these change on moving upstream network.
|
||||
<LI>Authoritative DNS mode allows local DNS names may be exported to zone in the global DNS. Dnsmasq acts as authoritative server for this zone, and also provides
|
||||
zone transfer to secondaries for the zone, if required.</LI>
|
||||
<LI>DNSSEC validation may be performed on DNS replies from upstream nameservers, providing security against spoofing and cache poisoning.</LI>
|
||||
<LI>Specified sub-domains can be directed to their own upstream DNS servers, making VPN configuration easy.</LI>
|
||||
<LI>Internationalised domain names are supported.
|
||||
</DIR>
|
||||
<P>
|
||||
The DHCP subsystem supports DHCPv4, DHCPv6, BOOTP and PXE.
|
||||
<DIR>
|
||||
<LI> Both static and dynamic DHCP leases are supported, along with stateless mode in DHCPv6.</LI>
|
||||
<LI> The PXE system is a full PXE server, supporting netboot menus and multiple architecture support. It
|
||||
includes proxy-mode, where the PXE system co-operates with another DHCP server.</LI>
|
||||
<LI> There is a built in read-only TFTP server to support netboot.</LI>
|
||||
<LI> Machines which are configured by DHCP have their names automatically
|
||||
included in the DNS and the names can specified by each machine or
|
||||
centrally by associating a name with a MAC address or UID in the dnsmasq
|
||||
configuration file.</LI>
|
||||
</DIR>
|
||||
<P>
|
||||
The Router Advertisement subsystem provides basic autoconfiguration for IPv6 hosts. It can be used stand-alone or in conjunction with DHCPv6.
|
||||
<DIR>
|
||||
<LI> The M and O bits are configurable, to control hosts' use of DHCPv6.</LI>
|
||||
<LI> Router advertisements can include the RDNSS option.</LI>
|
||||
<LI> There is a mode which uses name information from DHCPv4 configuration to provide DNS entries
|
||||
for autoconfigured IPv6 addresses which would otherwise be anonymous.</LI>
|
||||
</DIR>
|
||||
<P>
|
||||
|
||||
For extra compactness, unused features may be omitted at compile time.
|
||||
|
||||
|
||||
<H2>Get code.</H2>
|
||||
|
||||
@@ -102,7 +68,7 @@ the repo, or get a copy using git protocol with the command
|
||||
<PRE><TT>git clone git://thekelleys.org.uk/dnsmasq.git </TT></PRE>
|
||||
|
||||
<H2>License.</H2>
|
||||
Dnsmasq is distributed under the GPL. See the file COPYING in the distribution
|
||||
Dnsmasq is distributed under the GPL, version 2 or version 3 at your discretion. See the files COPYING and COPYING-v3 in the distribution
|
||||
for details.
|
||||
|
||||
<H2>Contact.</H2>
|
||||
@@ -110,7 +76,21 @@ There is a dnsmasq mailing list at <A
|
||||
HREF="http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss">
|
||||
http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss</A> which should be the
|
||||
first location for queries, bugreports, suggestions etc.
|
||||
Dnsmasq was written by Simon Kelley. You can contact me at <A
|
||||
You can contact me at <A
|
||||
HREF="mailto:simon@thekelleys.org.uk">simon@thekelleys.org.uk</A>.
|
||||
|
||||
<H2>Donations.</H2>
|
||||
Dnsmasq is mainly written and maintained by Simon Kelley. For most of its life, dnsmasq has been a spare-time project.
|
||||
These days I'm working on it as my main activity.
|
||||
I don't have an employer or anyone who pays me regularly to work on dnsmasq. If you'd like to make
|
||||
a contribution towards my expenses, please use the donation button below.
|
||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
|
||||
<input type="hidden" name="cmd" value="_s-xclick">
|
||||
<input type="hidden" name="hosted_button_id" value="V3X9GVW5GX6DA">
|
||||
<input type="image" src="https://www.paypalobjects.com/en_US/GB/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal – The safer, easier way to pay online.">
|
||||
<img alt="" border="0" src="https://www.paypalobjects.com/en_GB/i/scr/pixel.gif" width="1" height="1">
|
||||
</form>
|
||||
|
||||
|
||||
</BODY>
|
||||
|
||||
|
||||
550
man/dnsmasq.8
550
man/dnsmasq.8
@@ -6,24 +6,31 @@ dnsmasq \- A lightweight DHCP and caching DNS server.
|
||||
.I [OPTION]...
|
||||
.SH "DESCRIPTION"
|
||||
.BR dnsmasq
|
||||
is a lightweight DNS, TFTP and DHCP server. It is intended to provide
|
||||
is a lightweight DNS, TFTP, PXE, router advertisement and DHCP server. It is intended to provide
|
||||
coupled DNS and DHCP service to a LAN.
|
||||
.PP
|
||||
Dnsmasq accepts DNS queries and either answers them from a small, local,
|
||||
cache or forwards them to a real, recursive, DNS server. It loads the
|
||||
contents of /etc/hosts so that local hostnames
|
||||
which do not appear in the global DNS can be resolved and also answers
|
||||
DNS queries for DHCP configured hosts.
|
||||
DNS queries for DHCP configured hosts. It can also act as the
|
||||
authoritative DNS server for one or more domains, allowing local names
|
||||
to appear in the global DNS. It can be configured to do DNSSEC
|
||||
validation.
|
||||
.PP
|
||||
The dnsmasq DHCP server supports static address assignments and multiple
|
||||
networks. It automatically
|
||||
sends a sensible default set of DHCP options, and can be configured to
|
||||
send any desired set of DHCP options, including vendor-encapsulated
|
||||
options. It includes a secure, read-only,
|
||||
TFTP server to allow net/PXE boot of DHCP hosts and also supports BOOTP.
|
||||
TFTP server to allow net/PXE boot of DHCP hosts and also supports BOOTP. The PXE support is full featured, and includes a proxy mode which supplies PXE information to clients whilst DHCP address allocation is done by another server.
|
||||
.PP
|
||||
Dnsmasq
|
||||
supports IPv6 for all functions and a minimal router-advertisement daemon.
|
||||
The dnsmasq DHCPv6 server provides the same set of features as the
|
||||
DHCPv4 server, and in addition, it includes router advertisements and
|
||||
a neat feature which allows nameing for clients which use DHCPv4 and
|
||||
stateless autoconfiguration only for IPv6 configuration. There is support for doing address allocation (both DHCPv6 and RA) from subnets which are dynamically delegated via DHCPv6 prefix delegation.
|
||||
.PP
|
||||
Dnsmasq is coded with small embedded systems in mind. It aims for the smallest possible memory footprint compatible with the supported functions, and allows uneeded functions to be omitted from the compiled binary.
|
||||
.SH OPTIONS
|
||||
Note that in general missing parameters are allowed and switch off
|
||||
functions, for instance "--pid-file" disables writing a PID file. On
|
||||
@@ -74,6 +81,9 @@ the upstream DNS servers.
|
||||
.B --max-cache-ttl=<time>
|
||||
Set a maximum TTL value for entries in the cache.
|
||||
.TP
|
||||
.B --auth-ttl=<time>
|
||||
Set the TTL value returned in answers from the authoritative server.
|
||||
.TP
|
||||
.B \-k, --keep-in-foreground
|
||||
Do not go into the background at startup but otherwise run as
|
||||
normal. This is intended for use when dnsmasq is run under daemontools
|
||||
@@ -167,7 +177,12 @@ options. IP alias interfaces (eg "eth1:0") cannot be used with
|
||||
.B --interface
|
||||
or
|
||||
.B --except-interface
|
||||
options, use --listen-address instead.
|
||||
options, use --listen-address instead. A simple wildcard, consisting
|
||||
of a trailing '*', can be used in
|
||||
.B \--interface
|
||||
and
|
||||
.B \--except-interface
|
||||
options.
|
||||
.TP
|
||||
.B \-I, --except-interface=<interface name>
|
||||
Do not listen on the specified interface. Note that the order of
|
||||
@@ -178,6 +193,29 @@ and
|
||||
options does not matter and that
|
||||
.B --except-interface
|
||||
options always override the others.
|
||||
.TP
|
||||
.B --auth-server=<domain>,<interface>|<ip-address>
|
||||
Enable DNS authoritative mode for queries arriving at an interface or address. Note that the interface or address
|
||||
need not be mentioned in
|
||||
.B --interface
|
||||
or
|
||||
.B --listen-address
|
||||
configuration, indeed
|
||||
.B --auth-server
|
||||
will overide these and provide a different DNS service on the
|
||||
specified interface. The <domain> is the "glue record". It should
|
||||
resolve in the global DNS to a A and/or AAAA record which points to
|
||||
the address dnsmasq is listening on. When an interface is specified,
|
||||
it may be qualified with "/4" or "/6" to specify only the IPv4 or IPv6
|
||||
addresses associated with the interface.
|
||||
.TP
|
||||
.B --local-service
|
||||
Accept DNS queries only from hosts whose address is on a local subnet,
|
||||
ie a subnet for which an interface exists on the server. This option
|
||||
only has effect is there are no --interface --except-interface,
|
||||
--listen-address or --auth-server options. It is intended to be set as
|
||||
a default on installation, to allow unconfigured installations to be
|
||||
useful but also safe from being used for DNS amplification attacks.
|
||||
.TP
|
||||
.B \-2, --no-dhcp-interface=<interface name>
|
||||
Do not provide DHCP or TFTP on the specified interface, but do provide DNS service.
|
||||
@@ -316,7 +354,8 @@ by '/', like the --server syntax, eg.
|
||||
Don't poll /etc/resolv.conf for changes.
|
||||
.TP
|
||||
.B --clear-on-reload
|
||||
Whenever /etc/resolv.conf is re-read, clear the DNS cache.
|
||||
Whenever /etc/resolv.conf is re-read or the upstream servers are set
|
||||
via DBus, clear the DNS cache.
|
||||
This is useful when new nameservers may have different
|
||||
data than that held in cache.
|
||||
.TP
|
||||
@@ -384,6 +423,14 @@ source address specified but the port may be specified directly as
|
||||
part of the source address. Forcing queries to an interface is not
|
||||
implemented on all platforms supported by dnsmasq.
|
||||
.TP
|
||||
.B --rev-server=<ip-address>/<prefix-len>,<ipaddr>[#<port>][@<source-ip>|<interface>[#<port>]]
|
||||
This is functionally the same as
|
||||
.B --server,
|
||||
but provides some syntactic sugar to make specifying address-to-name queries easier. For example
|
||||
.B --rev-server=1.2.3.0/24,192.168.0.1
|
||||
is exactly equivalent to
|
||||
.B --server=/3.2.1.in-addr.arpa/192.168.0.1
|
||||
.TP
|
||||
.B \-A, --address=/<domain>/[domain/]<ipaddr>
|
||||
Specify an IP address to return for any host in the given domains.
|
||||
Queries in the domains are never forwarded and always replied to
|
||||
@@ -398,6 +445,12 @@ additional facility that /#/ matches any domain. Thus
|
||||
answered from /etc/hosts or DHCP and not sent to an upstream
|
||||
nameserver by a more specific --server directive.
|
||||
.TP
|
||||
.B --ipset=/<domain>/[domain/]<ipset>[,<ipset>]
|
||||
Places the resolved IP addresses of queries for the specified domains
|
||||
in the specified netfilter ip sets. Domains and subdomains are matched
|
||||
in the same way as --address. These ip sets must already exist. See
|
||||
ipset(8) for more details.
|
||||
.TP
|
||||
.B \-m, --mx-host=<mx name>[[,<hostname>],<preference>]
|
||||
Return an MX record named <mx name> pointing to the given hostname (if
|
||||
given), or
|
||||
@@ -468,7 +521,7 @@ Return an NAPTR DNS record, as specified in RFC3403.
|
||||
Return a CNAME record which indicates that <cname> is really
|
||||
<target>. There are significant limitations on the target; it must be a
|
||||
DNS name which is known to dnsmasq from /etc/hosts (or additional
|
||||
hosts files), from DHCP or from another
|
||||
hosts files), from DHCP, from --interface-name or from another
|
||||
.B --cname.
|
||||
If the target does not satisfy this
|
||||
criteria, the whole cname is ignored. The cname must be unique, but it
|
||||
@@ -480,17 +533,35 @@ record (which is always in the C_IN class). The value of the record is
|
||||
given by the hex data, which may be of the form 01:23:45 or 01 23 45 or
|
||||
012345 or any mixture of these.
|
||||
.TP
|
||||
.B --interface-name=<name>,<interface>
|
||||
.B --interface-name=<name>,<interface>[/4|/6]
|
||||
Return a DNS record associating the name with the primary address on
|
||||
the given interface. This flag specifies an A record for the given
|
||||
the given interface. This flag specifies an A or AAAA record for the given
|
||||
name in the same way as an /etc/hosts line, except that the address is
|
||||
not constant, but taken from the given interface. If the interface is
|
||||
not constant, but taken from the given interface. The interface may be
|
||||
followed by "/4" or "/6" to specify that only IPv4 or IPv6 addresses
|
||||
of the interface should be used. If the interface is
|
||||
down, not configured or non-existent, an empty record is returned. The
|
||||
matching PTR record is also created, mapping the interface address to
|
||||
the name. More than one name may be associated with an interface
|
||||
address by repeating the flag; in that case the first instance is used
|
||||
for the reverse address-to-name mapping.
|
||||
.TP
|
||||
.B --synth-domain=<domain>,<address range>[,<prefix>]
|
||||
Create artificial A/AAAA and PTR records for an address range. The
|
||||
records use the address, with periods (or colons for IPv6) replaced
|
||||
with dashes.
|
||||
|
||||
An example should make this clearer.
|
||||
.B --synth-domain=thekelleys.org.uk,192.168.0.0/24,internal-
|
||||
will result in a query for internal-192-168-0-56.thekelleys.org.uk returning
|
||||
192.168.0.56 and a reverse query vice versa. The same applies to IPv6,
|
||||
but IPv6 addresses may start with '::'
|
||||
but DNS labels may not start with '-' so in this case if no prefix is
|
||||
configured a zero is added in front of the label. ::1 becomes 0--1.
|
||||
|
||||
The address range can be of the form
|
||||
<ip address>,<ip address> or <ip address>/<netmask>
|
||||
.TP
|
||||
.B --add-mac
|
||||
Add the MAC address of the requestor to DNS queries which are
|
||||
forwarded upstream. This may be used to DNS filtering by the upstream
|
||||
@@ -498,7 +569,20 @@ server. The MAC address can only be added if the requestor is on the same
|
||||
subnet as the dnsmasq server. Note that the mechanism used to achieve this (an EDNS0 option)
|
||||
is not yet standardised, so this should be considered
|
||||
experimental. Also note that exposing MAC addresses in this way may
|
||||
have security and privacy implications.
|
||||
have security and privacy implications. The warning about caching
|
||||
given for --add-subnet applies to --add-mac too.
|
||||
.TP
|
||||
.B --add-subnet[[=<IPv4 prefix length>],<IPv6 prefix length>]
|
||||
Add the subnet address of the requestor to the DNS queries which are
|
||||
forwarded upstream. The amount of the address forwarded depends on the
|
||||
prefix length parameter: 32 (128 for IPv6) forwards the whole address,
|
||||
zero forwards none of it but still marks the request so that no
|
||||
upstream nameserver will add client address information either. The
|
||||
default is zero for both IPv4 and IPv6. Note that upstream nameservers
|
||||
may be configured to return different results based on this
|
||||
information, but the dnsmasq cache does not take account. If a dnsmasq
|
||||
instance is configured such that different results may be encountered,
|
||||
caching should be disabled.
|
||||
.TP
|
||||
.B \-c, --cache-size=<cachesize>
|
||||
Set the size of dnsmasq's cache. The default is 150 names. Setting the cache size to zero disables caching.
|
||||
@@ -514,20 +598,106 @@ Set the maximum number of concurrent DNS queries. The default value is
|
||||
where this needs to be increased is when using web-server log file
|
||||
resolvers, which can generate large numbers of concurrent queries.
|
||||
.TP
|
||||
.B --proxy-dnssec
|
||||
A resolver on a client machine can do DNSSEC validation in two ways: it
|
||||
can perform the cryptograhic operations on the reply it receives, or
|
||||
it can rely on the upstream recursive nameserver to do the validation
|
||||
and set a bit in the reply if it succeeds. Dnsmasq is not a DNSSEC
|
||||
validator, so it cannot perform the validation role of the recursive nameserver,
|
||||
but it can pass through the validation results from its own upstream
|
||||
nameservers. This option enables this behaviour. You should only do
|
||||
this if you trust all the configured upstream nameservers
|
||||
.I and the network between you and them.
|
||||
If you use the first DNSSEC mode, validating resolvers in clients,
|
||||
this option is not required. Dnsmasq always returns all the data
|
||||
needed for a client to do validation itself.
|
||||
.B --dnssec
|
||||
Validate DNS replies and cache DNSSEC data. When forwarding DNS queries, dnsmasq requests the
|
||||
DNSSEC records needed to validate the replies. The replies are validated and the result returned as
|
||||
the Authenticated Data bit in the DNS packet. In addition the DNSSEC records are stored in the cache, making
|
||||
validation by clients more efficient. Note that validation by clients is the most secure DNSSEC mode, but for
|
||||
clients unable to do validation, use of the AD bit set by dnsmasq is useful, provided that the network between
|
||||
the dnsmasq server and the client is trusted. Dnsmasq must be compiled with HAVE_DNSSEC enabled, and DNSSEC
|
||||
trust anchors provided, see
|
||||
.B --trust-anchor.
|
||||
Because the DNSSEC validation process uses the cache, it is not
|
||||
permitted to reduce the cache size below the default when DNSSEC is
|
||||
enabled. The nameservers upstream of dnsmasq must be DNSSEC-capable,
|
||||
ie capable of returning DNSSEC records with data. If they are not,
|
||||
then dnsmasq will not be able to determine the trusted status of
|
||||
answers. In the default mode, this menas that all replies will be
|
||||
marked as untrusted. If
|
||||
.B --dnssec-check-unsigned
|
||||
is set and the upstream servers don't support DNSSEC, then DNS service will be entirely broken.
|
||||
.TP
|
||||
.B --trust-anchor=[<class>],<domain>,<key-tag>,<algorithm>,<digest-type>,<digest>
|
||||
Provide DS records to act a trust anchors for DNSSEC
|
||||
validation. Typically these will be the DS record(s) for Zone Signing
|
||||
key(s) of the root zone,
|
||||
but trust anchors for limited domains are also possible. The current
|
||||
root-zone trust anchors may be donwloaded from https://data.iana.org/root-anchors/root-anchors.xml
|
||||
.TP
|
||||
.B --dnssec-check-unsigned
|
||||
As a default, dnsmasq does not check that unsigned DNS replies are
|
||||
legitimate: they are assumed to be valid and passed on (without the
|
||||
"authentic data" bit set, of course). This does not protect against an
|
||||
attacker forging unsigned replies for signed DNS zones, but it is
|
||||
fast. If this flag is set, dnsmasq will check the zones of unsigned
|
||||
replies, to ensure that unsigned replies are allowed in those
|
||||
zones. The cost of this is more upstream queries and slower
|
||||
performance. See also the warning about upstream servers in the
|
||||
section on
|
||||
.B --dnssec
|
||||
.TP
|
||||
.B --dnssec-no-timecheck
|
||||
DNSSEC signatures are only valid for specified time windows, and should be rejected outside those windows. This generates an
|
||||
interesting chicken-and-egg problem for machines which don't have a hardware real time clock. For these machines to determine the correct
|
||||
time typically requires use of NTP and therefore DNS, but validating DNS requires that the correct time is already known. Setting this flag
|
||||
removes the time-window checks (but not other DNSSEC validation.) only until the dnsmasq process receives SIGHUP. The intention is
|
||||
that dnsmasq should be started with this flag when the platform determines that reliable time is not currently available. As soon as
|
||||
reliable time is established, a SIGHUP should be sent to dnsmasq, which enables time checking, and purges the cache of DNS records
|
||||
which have not been throughly checked.
|
||||
.TP
|
||||
.B --proxy-dnssec
|
||||
Copy the DNSSEC Authenticated Data bit from upstream servers to downstream clients and cache it. This is an
|
||||
alternative to having dnsmasq validate DNSSEC, but it depends on the security of the network between
|
||||
dnsmasq and the upstream servers, and the trustworthiness of the upstream servers.
|
||||
.TP
|
||||
.B --dnssec-debug
|
||||
Set debugging mode for the DNSSEC validation, set the Checking Disabled bit on upstream queries,
|
||||
and don't convert replies which do not validate to responses with
|
||||
a return code of SERVFAIL. Note that
|
||||
setting this may affect DNS behaviour in bad ways, it is not an
|
||||
extra-logging flag and should not be set in production.
|
||||
.TP
|
||||
.B --auth-zone=<domain>[,<subnet>[/<prefix length>][,<subnet>[/<prefix length>].....]]
|
||||
Define a DNS zone for which dnsmasq acts as authoritative server. Locally defined DNS records which are in the domain
|
||||
will be served. If subnet(s) are given, A and AAAA records must be in one of the
|
||||
specified subnets.
|
||||
|
||||
As alternative to directly specifying the subnets, it's possible to
|
||||
give the name of an interface, in which case the subnets implied by
|
||||
that interface's configured addresses and netmask/prefix-length are
|
||||
used; this is useful when using constructed DHCP ranges as the actual
|
||||
address is dynamic and not known when configuring dnsmasq. The
|
||||
interface addresses may be confined to only IPv6 addresses using
|
||||
<interface>/6 or to only IPv4 using <interface>/4. This is useful when
|
||||
an interface has dynamically determined global IPv6 addresses which should
|
||||
appear in the zone, but RFC1918 IPv4 addresses which should not.
|
||||
Interface-name and address-literal subnet specifications may be used
|
||||
freely in the same --auth-zone declaration.
|
||||
|
||||
The subnet(s) are also used to define in-addr.arpa and
|
||||
ip6.arpa domains which are served for reverse-DNS queries. If not
|
||||
specified, the prefix length defaults to 24 for IPv4 and 64 for IPv6.
|
||||
For IPv4 subnets, the prefix length should be have the value 8, 16 or 24
|
||||
unless you are familiar with RFC 2317 and have arranged the
|
||||
in-addr.arpa delegation accordingly. Note that if no subnets are
|
||||
specified, then no reverse queries are answered.
|
||||
.TP
|
||||
.B --auth-soa=<serial>[,<hostmaster>[,<refresh>[,<retry>[,<expiry>]]]]
|
||||
Specify fields in the SOA record associated with authoritative
|
||||
zones. Note that this is optional, all the values are set to sane defaults.
|
||||
.TP
|
||||
.B --auth-sec-servers=<domain>[,<domain>[,<domain>...]]
|
||||
Specify any secondary servers for a zone for which dnsmasq is
|
||||
authoritative. These servers must be configured to get zone data from
|
||||
dnsmasq by zone transfer, and answer queries for the same
|
||||
authoritative zones as dnsmasq.
|
||||
.TP
|
||||
.B --auth-peer=<ip-address>[,<ip-address>[,<ip-address>...]]
|
||||
Specify the addresses of secondary servers which are allowed to
|
||||
initiate zone transfer (AXFR) requests for zones for which dnsmasq is
|
||||
authoritative. If this option is not given, then AXFR requests will be
|
||||
accepted from any secondary.
|
||||
.TP
|
||||
.B --conntrack
|
||||
Read the Linux connection track mark associated with incoming DNS
|
||||
queries and set the same mark value on upstream traffic used to answer
|
||||
@@ -538,9 +708,9 @@ compiled in and the kernel must have conntrack support
|
||||
included and configured. This option cannot be combined with
|
||||
--query-port.
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag],]<start-addr>[,<end-addr>][,<mode>][,<netmask>[,<broadcast>]][,<lease time>]
|
||||
.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag>,]<start-addr>[,<end-addr>][,<mode>][,<netmask>[,<broadcast>]][,<lease time>]
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag],]<start-IPv6addr>[,<end-IPv6addr>][,<mode>][,<prefix-len>][,<lease time>]
|
||||
.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag>,]<start-IPv6addr>[,<end-IPv6addr>|constructor:<interface>][,<mode>][,<prefix-len>][,<lease time>]
|
||||
|
||||
Enable the DHCP server. Addresses will be given out from the range
|
||||
<start-addr> to <end-addr> and from statically defined addresses given
|
||||
@@ -567,11 +737,33 @@ always optional. It is always
|
||||
allowed to have more than one dhcp-range in a single subnet.
|
||||
|
||||
For IPv6, the parameters are slightly different: instead of netmask
|
||||
and broadcast address, there is an optional prefix length. If not
|
||||
and broadcast address, there is an optional prefix length which must
|
||||
be equal to or larger then the prefix length on the local interface. If not
|
||||
given, this defaults to 64. Unlike the IPv4 case, the prefix length is not
|
||||
automatically derived from the interface configuration. The mimimum
|
||||
size of the prefix length is 64.
|
||||
|
||||
IPv6 (only) supports another type of range. In this, the start address and optional end address contain only the network part (ie ::1) and they are followed by
|
||||
.B constructor:<interface>.
|
||||
This forms a template which describes how to create ranges, based on the addresses assigned to the interface. For instance
|
||||
|
||||
.B --dhcp-range=::1,::400,constructor:eth0
|
||||
|
||||
will look for addresses on
|
||||
eth0 and then create a range from <network>::1 to <network>::400. If
|
||||
the interface is assigned more than one network, then the
|
||||
corresponding ranges will be automatically created, and then
|
||||
deprecated and finally removed again as the address is deprecated and
|
||||
then deleted. The interface name may have a final "*" wildcard. Note
|
||||
that just any address on eth0 will not do: it must not be an
|
||||
autoconfigured or privacy address, or be deprecated.
|
||||
|
||||
If a dhcp-range is only being used for stateless DHCP and/or SLAAC,
|
||||
then the address can be simply ::
|
||||
|
||||
.B --dhcp-range=::,constructor:eth0
|
||||
|
||||
|
||||
The optional
|
||||
.B set:<tag>
|
||||
sets an alphanumeric label which marks this network so that
|
||||
@@ -590,7 +782,7 @@ or from /etc/ethers will be served. A static-only subnet with address
|
||||
all zeros may be used as a "catch-all" address to enable replies to all
|
||||
Information-request packets on a subnet which is provided with
|
||||
stateless DHCPv6, ie
|
||||
.B --dhcp=range=::,static
|
||||
.B --dhcp-range=::,static
|
||||
|
||||
For IPv4, the <mode> may be
|
||||
.B proxy
|
||||
@@ -661,7 +853,8 @@ the same subnet as some valid dhcp-range. For
|
||||
subnets which don't need a pool of dynamically allocated addresses,
|
||||
use the "static" keyword in the dhcp-range declaration.
|
||||
|
||||
It is allowed to use client identifiers rather than
|
||||
It is allowed to use client identifiers (called client
|
||||
DUID in IPv6-land rather than
|
||||
hardware addresses to identify hosts by prefixing with 'id:'. Thus:
|
||||
.B --dhcp-host=id:01:02:03:04,.....
|
||||
refers to the host with client identifier 01:02:03:04. It is also
|
||||
@@ -672,9 +865,16 @@ A single
|
||||
.B dhcp-host
|
||||
may contain an IPv4 address or an IPv6 address, or both. IPv6 addresses must be bracketed by square brackets thus:
|
||||
.B --dhcp-host=laptop,[1234::56]
|
||||
Note that in IPv6 DHCP, the hardware address is not normally available, so a client must be identified by client-id (called client DUID in IPv6-land) or hostname.
|
||||
IPv6 addresses may contain only the host-identifier part:
|
||||
.B --dhcp-host=laptop,[::56]
|
||||
in which case they act as wildcards in constructed dhcp ranges, with
|
||||
the appropriate network part inserted.
|
||||
Note that in IPv6 DHCP, the hardware address may not be
|
||||
available, though it normally is for direct-connected clients, or
|
||||
clients using DHCP relays which support RFC 6939.
|
||||
|
||||
The special option id:* means "ignore any client-id
|
||||
|
||||
For DHCPv4, the special option id:* means "ignore any client-id
|
||||
and use MAC addresses only." This is useful when a client presents a client-id sometimes
|
||||
but not others.
|
||||
|
||||
@@ -697,7 +897,7 @@ This is
|
||||
useful when there is another DHCP server on the network which should
|
||||
be used by some machines.
|
||||
|
||||
The set:<tag> contruct sets the tag
|
||||
The set:<tag> construct sets the tag
|
||||
whenever this dhcp-host directive is in use. This can be used to
|
||||
selectively send DHCP options just for this host. More than one tag
|
||||
can be set in a dhcp-host directive (but not in other places where
|
||||
@@ -781,9 +981,11 @@ and to set the time-server address to 192.168.0.4, do
|
||||
.B --dhcp-option = 42,192.168.0.4
|
||||
or
|
||||
.B --dhcp-option = option:ntp-server, 192.168.0.4
|
||||
The special address 0.0.0.0 (or [::] for DHCPv6) is taken to mean "the address of the
|
||||
machine running dnsmasq". Data types allowed are comma separated
|
||||
dotted-quad IP addresses, a decimal number, colon-separated hex digits
|
||||
The special address 0.0.0.0 is taken to mean "the address of the
|
||||
machine running dnsmasq".
|
||||
|
||||
Data types allowed are comma separated
|
||||
dotted-quad IPv4 addresses, []-wrapped IPv6 addresses, a decimal number, colon-separated hex digits
|
||||
and a text string. If the optional tags are given then
|
||||
this option is only sent when all the tags are matched.
|
||||
|
||||
@@ -799,7 +1001,9 @@ keyword, followed by the option number or option name. The IPv6 option
|
||||
name space is disjoint from the IPv4 option name space. IPv6 addresses
|
||||
in options must be bracketed with square brackets, eg.
|
||||
.B --dhcp-option=option6:ntp-server,[1234::56]
|
||||
|
||||
For IPv6, [::] means "the global address of
|
||||
the machine running dnsmasq", whilst [fd00::] is replaced with the
|
||||
ULA, if it exists, and [fe80::] with the link-local address.
|
||||
|
||||
Be careful: no checking is done that the correct type of data for the
|
||||
option number is sent, it is quite possible to
|
||||
@@ -862,6 +1066,38 @@ DHCP options. This make extra space available in the DHCP packet for
|
||||
options but can, rarely, confuse old or broken clients. This flag
|
||||
forces "simple and safe" behaviour to avoid problems in such a case.
|
||||
.TP
|
||||
.B --dhcp-relay=<local address>,<server address>[,<interface]
|
||||
Configure dnsmasq to do DHCP relay. The local address is an address
|
||||
allocated to an interface on the host running dnsmasq. All DHCP
|
||||
requests arriving on that interface will we relayed to a remote DHCP
|
||||
server at the server address. It is possible to relay from a single local
|
||||
address to multiple remote servers by using multiple dhcp-relay
|
||||
configs with the same local address and different server
|
||||
addresses. A server address must be an IP literal address, not a
|
||||
domain name. In the case of DHCPv6, the server address may be the
|
||||
ALL_SERVERS multicast address, ff05::1:3. In this case the interface
|
||||
must be given, not be wildcard, and is used to direct the multicast to the
|
||||
correct interface to reach the DHCP server.
|
||||
|
||||
Access control for DHCP clients has the same rules as for the DHCP
|
||||
server, see --interface, --except-interface, etc. The optional
|
||||
interface name in the dhcp-relay config has a different function: it
|
||||
controls on which interface DHCP replies from the server will be
|
||||
accepted. This is intended for configurations which have three
|
||||
interfaces: one being relayed from, a second connecting the DHCP
|
||||
server, and a third untrusted network, typically the wider
|
||||
internet. It avoids the possibility of spoof replies arriving via this
|
||||
third interface.
|
||||
|
||||
It is allowed to have dnsmasq act as a DHCP server on one set of
|
||||
interfaces and relay from a disjoint set of interfaces. Note that
|
||||
whilst it is quite possible to write configurations which appear to
|
||||
act as a server and a relay on the same interface, this is not
|
||||
supported: the relay function will take precedence.
|
||||
|
||||
Both DHCPv4 and DHCPv6 relay is supported. It's not possible to relay
|
||||
DHCPv4 to a DHCPv6 server or vice-versa.
|
||||
.TP
|
||||
.B \-U, --dhcp-vendorclass=set:<tag>,[enterprise:<IANA-enterprise number>,]<vendor-class>
|
||||
Map from a vendor-class string to a tag. Most DHCP clients provide a
|
||||
"vendor class" which represents, in some sense, the type of host. This option
|
||||
@@ -890,7 +1126,7 @@ this to set a different printer server for hosts in the class
|
||||
"accounts" than for hosts in the class "engineering".
|
||||
.TP
|
||||
.B \-4, --dhcp-mac=set:<tag>,<MAC address>
|
||||
(IPv4 only) Map from a MAC address to a tag. The MAC address may include
|
||||
Map from a MAC address to a tag. The MAC address may include
|
||||
wildcards. For example
|
||||
.B --dhcp-mac=set:3com,01:34:23:*:*:*
|
||||
will set the tag "3com" for any host whose MAC address matches the pattern.
|
||||
@@ -912,7 +1148,7 @@ agent ID and one provided by a relay agent, the tag is set.
|
||||
(IPv4 only) A normal DHCP relay agent is only used to forward the initial parts of
|
||||
a DHCP interaction to the DHCP server. Once a client is configured, it
|
||||
communicates directly with the server. This is undesirable if the
|
||||
relay agent is addding extra information to the DHCP packets, such as
|
||||
relay agent is adding extra information to the DHCP packets, such as
|
||||
that used by
|
||||
.B dhcp-circuitid
|
||||
and
|
||||
@@ -929,7 +1165,7 @@ relays at those addresses are affected.
|
||||
Without a value, set the tag if the client sends a DHCP
|
||||
option of the given number or name. When a value is given, set the tag only if
|
||||
the option is sent and matches the value. The value may be of the form
|
||||
"01:ff:*:02" in which case the value must match (apart from widcards)
|
||||
"01:ff:*:02" in which case the value must match (apart from wildcards)
|
||||
but the option sent may have unmatched data past the end of the
|
||||
value. The value may also be of the same form as in
|
||||
.B dhcp-option
|
||||
@@ -942,7 +1178,7 @@ will set the tag "efi-ia32" if the the number 6 appears in the list of
|
||||
architectures sent by the client in option 93. (See RFC 4578 for
|
||||
details.) If the value is a string, substring matching is used.
|
||||
|
||||
The special form with vi-encap:<enterpise number> matches against
|
||||
The special form with vi-encap:<enterprise number> matches against
|
||||
vendor-identifying vendor classes for the specified enterprise. Please
|
||||
see RFC 3925 for more details of these rare and interesting beasts.
|
||||
.TP
|
||||
@@ -970,7 +1206,7 @@ dhcp-host configuration in dnsmasq and the contents of /etc/hosts and
|
||||
.TP
|
||||
.B --dhcp-generate-names=tag:<tag>[,tag:<tag>]
|
||||
(IPv4 only) Generate a name for DHCP clients which do not otherwise have one,
|
||||
using the MAC address expressed in hex, seperated by dashes. Note that
|
||||
using the MAC address expressed in hex, separated by dashes. Note that
|
||||
if a host provides a name, it will be used by preference to this,
|
||||
unless
|
||||
.B --dhcp-ignore-names
|
||||
@@ -1047,7 +1283,7 @@ timeout has elapsed with no keyboard input, the first available menu
|
||||
option will be automatically executed. If the timeout is zero then the first available menu
|
||||
item will be executed immediately. If
|
||||
.B pxe-prompt
|
||||
is ommitted the system will wait for user input if there are multiple
|
||||
is omitted the system will wait for user input if there are multiple
|
||||
items in the menu, but boot immediately if
|
||||
there is only one. See
|
||||
.B pxe-service
|
||||
@@ -1071,12 +1307,13 @@ create thousands of leases and use lots of memory in the dnsmasq
|
||||
process.
|
||||
.TP
|
||||
.B \-K, --dhcp-authoritative
|
||||
(IPv4 only) Should be set when dnsmasq is definitely the only DHCP server on a network.
|
||||
It changes the behaviour from strict RFC compliance so that DHCP requests on
|
||||
Should be set when dnsmasq is definitely the only DHCP server on a network.
|
||||
For DHCPv4, it changes the behaviour from strict RFC compliance so that DHCP requests on
|
||||
unknown leases from unknown hosts are not ignored. This allows new hosts
|
||||
to get a lease without a tedious timeout under all circumstances. It also
|
||||
allows dnsmasq to rebuild its lease database without each client needing to
|
||||
reacquire a lease, if the database is lost.
|
||||
reacquire a lease, if the database is lost. For DHCPv6 it sets the
|
||||
priority in replies to 255 (the maximum) instead of 0 (the minimum).
|
||||
.TP
|
||||
.B --dhcp-alternate-port[=<server port>[,<client port>]]
|
||||
(IPv4 only) Change the ports used for DHCP from the default. If this option is
|
||||
@@ -1105,6 +1342,11 @@ tried. This flag disables this check. Use with caution.
|
||||
Extra logging for DHCP: log all the options sent to DHCP clients and
|
||||
the tags used to determine them.
|
||||
.TP
|
||||
.B --quiet-dhcp, --quiet-dhcp6, --quiet-ra
|
||||
Suppress logging of the routine operation of these protocols. Errors and
|
||||
problems will still be logged. --quiet-dhcp and quiet-dhcp6 are
|
||||
over-ridden by --log-dhcp.
|
||||
.TP
|
||||
.B \-l, --dhcp-leasefile=<path>
|
||||
Use the specified file to store DHCP lease information.
|
||||
.TP
|
||||
@@ -1178,6 +1420,9 @@ For IPv4 only:
|
||||
|
||||
DNSMASQ_CLIENT_ID if the host provided a client-id.
|
||||
|
||||
DNSMASQ_CIRCUIT_ID, DNSMASQ_SUBSCRIBER_ID, DNSMASQ_REMOTE_ID if a
|
||||
DHCP relay-agent added any of these options.
|
||||
|
||||
If the client provides vendor-class, DNSMASQ_VENDOR_CLASS.
|
||||
|
||||
For IPv6 only:
|
||||
@@ -1192,7 +1437,7 @@ every call to the script.
|
||||
DNSMASQ_IAID containing the IAID for the lease. If the lease is a
|
||||
temporary allocation, this is prefixed to 'T'.
|
||||
|
||||
|
||||
DNSMASQ_MAC containing the MAC address of the client, if known.
|
||||
|
||||
Note that the supplied hostname, vendorclass and userclass data is
|
||||
only supplied for
|
||||
@@ -1342,7 +1587,7 @@ In the default mode, dnsmasq inserts the unqualified names of
|
||||
DHCP clients into the DNS. For this reason, the names must be unique,
|
||||
even if two clients which have the same name are in different
|
||||
domains. If a second DHCP client appears which has the same name as an
|
||||
existing client, the name is transfered to the new client. If
|
||||
existing client, the name is transferred to the new client. If
|
||||
.B --dhcp-fqdn
|
||||
is set, this behaviour changes: the unqualified name is no longer
|
||||
put in the DNS, only the qualified name. Two DHCP clients with the
|
||||
@@ -1380,11 +1625,26 @@ the relevant link-local address of the machine running dnsmasq is sent
|
||||
as recursive DNS server. If provided, the DHCPv6 options dns-server and
|
||||
domain-search are used for RDNSS and DNSSL.
|
||||
.TP
|
||||
.B --enable-tftp
|
||||
.B --ra-param=<interface>,[high|low],[[<ra-interval>],<router lifetime>]
|
||||
Set non-default values for router advertisements sent via an
|
||||
interface. The priority field for the router may be altered from the
|
||||
default of medium with eg
|
||||
.B --ra-param=eth0,high.
|
||||
The interval between router advertisements may be set (in seconds) with
|
||||
.B --ra-param=eth0,60.
|
||||
The lifetime of the route may be changed or set to zero, which allows
|
||||
a router to advertise prefixes but not a route via itself.
|
||||
.B --ra-parm=eth0,0,0
|
||||
(A value of zero for the interval means the default value.) All three parameters may be set at once.
|
||||
.B --ra-param=low,60,1200
|
||||
The interface field may include a wildcard.
|
||||
.TP
|
||||
.B --enable-tftp[=<interface>[,<interface>]]
|
||||
Enable the TFTP server function. This is deliberately limited to that
|
||||
needed to net-boot a client. Only reading is allowed; the tsize and
|
||||
blksize extensions are supported (tsize is only supported in octet
|
||||
mode).
|
||||
mode). Without an argument, the TFTP service is provided to the same set of interfaces as DHCP service.
|
||||
If the list of interfaces is provided, that defines which interfaces recieve TFTP service.
|
||||
.TP
|
||||
.B --tftp-root=<directory>[,<interface>]
|
||||
Look for files to transfer using TFTP relative to the given
|
||||
@@ -1455,6 +1715,13 @@ files. If extension(s) are given, any files which end in those
|
||||
extensions are skipped. Any files whose names end in ~ or start with . or start and end
|
||||
with # are always skipped. This flag may be given on the command
|
||||
line or in a configuration file.
|
||||
.TP
|
||||
.B --servers-file=<file>
|
||||
A special case of
|
||||
.B --conf-file
|
||||
which differs in two respects. Firstly, only --server and --rev-server are allowed
|
||||
in the configuration file included. Secondly, the file is re-read and the configuration
|
||||
therein is updated when dnsmasq recieves SIGHUP.
|
||||
.SH CONFIG FILE
|
||||
At startup, dnsmasq reads
|
||||
.I /etc/dnsmasq.conf,
|
||||
@@ -1495,12 +1762,22 @@ When it receives a SIGUSR1,
|
||||
writes statistics to the system log. It writes the cache size,
|
||||
the number of names which have had to removed from the cache before
|
||||
they expired in order to make room for new names and the total number
|
||||
of names that have been inserted into the cache. For each upstream
|
||||
of names that have been inserted into the cache. The number of cache hits and
|
||||
misses and the number of authoritative queries answered are also given. For each upstream
|
||||
server it gives the number of queries sent, and the number which
|
||||
resulted in an error. In
|
||||
.B --no-daemon
|
||||
mode or when full logging is enabled (-q), a complete dump of the
|
||||
contents of the cache is made.
|
||||
contents of the cache is made.
|
||||
|
||||
The cache statistics are also available in the DNS as answers to
|
||||
queries of class CHAOS and type TXT in domain bind. The domain names are cachesize.bind, insertions.bind, evictions.bind,
|
||||
misses.bind, hits.bind, auth.bind and servers.bind. An example command to query this, using the
|
||||
.B dig
|
||||
utility would be
|
||||
|
||||
dig +short chaos txt cachesize.bind
|
||||
|
||||
.PP
|
||||
When it receives SIGUSR2 and it is logging direct to a file (see
|
||||
.B --log-facility
|
||||
@@ -1596,7 +1873,7 @@ used to allocate the address, one from any matching
|
||||
The tag "bootp" is set for BOOTP requests, and a tag whose name is the
|
||||
name of the interface on which the request arrived is also set.
|
||||
|
||||
Any configuration lines which includes one or more tag:<tag> contructs
|
||||
Any configuration lines which include one or more tag:<tag> constructs
|
||||
will only be valid if all that tags are matched in the set derived
|
||||
above. Typically this is dhcp-option.
|
||||
.B dhcp-option
|
||||
@@ -1604,7 +1881,7 @@ which has tags will be used in preference to an untagged
|
||||
.B dhcp-option,
|
||||
provided that _all_ the tags match somewhere in the
|
||||
set collected as described above. The prefix '!' on a tag means 'not'
|
||||
so --dhcp=option=tag:!purple,3,1.2.3.4 sends the option when the
|
||||
so --dhcp-option=tag:!purple,3,1.2.3.4 sends the option when the
|
||||
tag purple is not in the set of valid tags. (If using this in a
|
||||
command line rather than a configuration file, be sure to escape !,
|
||||
which is a shell metacharacter)
|
||||
@@ -1648,6 +1925,171 @@ parameter in a BOOTP request is used as a tag,
|
||||
as is the tag "bootp", allowing some control over the options returned to
|
||||
different classes of hosts.
|
||||
|
||||
.SH AUTHORITATIVE CONFIGURATION
|
||||
.PP
|
||||
Configuring dnsmasq to act as an authoritative DNS server is
|
||||
complicated by the fact that it involves configuration of external DNS
|
||||
servers to provide delegation. We will walk through three scenarios of
|
||||
increasing complexity. Prerequisites for all of these scenarios
|
||||
are a globally accessible IP address, an A or AAAA record pointing to that address,
|
||||
and an external DNS server capable of doing delegation of the zone in
|
||||
question. For the first part of this explanation, we will call the A (or AAAA) record
|
||||
for the globally accessible address server.example.com, and the zone
|
||||
for which dnsmasq is authoritative our.zone.com.
|
||||
|
||||
The simplest configuration consists of two lines of dnsmasq configuration; something like
|
||||
|
||||
.nf
|
||||
.B auth-server=server.example.com,eth0
|
||||
.B auth-zone=our.zone.com,1.2.3.0/24
|
||||
.fi
|
||||
|
||||
and two records in the external DNS
|
||||
|
||||
.nf
|
||||
server.example.com A 192.0.43.10
|
||||
our.zone.com NS server.example.com
|
||||
.fi
|
||||
|
||||
eth0 is the external network interface on which dnsmasq is listening,
|
||||
and has (globally accessible) address 192.0.43.10.
|
||||
|
||||
Note that the external IP address may well be dynamic (ie assigned
|
||||
from an ISP by DHCP or PPP) If so, the A record must be linked to this
|
||||
dynamic assignment by one of the usual dynamic-DNS systems.
|
||||
|
||||
A more complex, but practically useful configuration has the address
|
||||
record for the globally accessible IP address residing in the
|
||||
authoritative zone which dnsmasq is serving, typically at the root. Now
|
||||
we have
|
||||
|
||||
.nf
|
||||
.B auth-server=our.zone.com,eth0
|
||||
.B auth-zone=our.zone.com,1.2.3.0/24
|
||||
.fi
|
||||
|
||||
.nf
|
||||
our.zone.com A 1.2.3.4
|
||||
our.zone.com NS our.zone.com
|
||||
.fi
|
||||
|
||||
The A record for our.zone.com has now become a glue record, it solves
|
||||
the chicken-and-egg problem of finding the IP address of the
|
||||
nameserver for our.zone.com when the A record is within that
|
||||
zone. Note that this is the only role of this record: as dnsmasq is
|
||||
now authoritative from our.zone.com it too must provide this
|
||||
record. If the external address is static, this can be done with an
|
||||
.B /etc/hosts
|
||||
entry or
|
||||
.B --host-record.
|
||||
|
||||
.nf
|
||||
.B auth-server=our.zone.com,eth0
|
||||
.B host-record=our.zone.com,1.2.3.4
|
||||
.B auth-zone=our.zone.com,1.2.3.0/24
|
||||
.fi
|
||||
|
||||
If the external address is dynamic, the address
|
||||
associated with our.zone.com must be derived from the address of the
|
||||
relevant interface. This is done using
|
||||
.B interface-name
|
||||
Something like:
|
||||
|
||||
.nf
|
||||
.B auth-server=our.zone.com,eth0
|
||||
.B interface-name=our.zone.com,eth0
|
||||
.B auth-zone=our.zone.com,1.2.3.0/24,eth0
|
||||
.fi
|
||||
|
||||
(The "eth0" argument in auth-zone adds the subnet containing eth0's
|
||||
dynamic address to the zone, so that the interface-name returns the
|
||||
address in outside queries.)
|
||||
|
||||
Our final configuration builds on that above, but also adds a
|
||||
secondary DNS server. This is another DNS server which learns the DNS data
|
||||
for the zone by doing zones transfer, and acts as a backup should
|
||||
the primary server become inaccessible. The configuration of the
|
||||
secondary is beyond the scope of this man-page, but the extra
|
||||
configuration of dnsmasq is simple:
|
||||
|
||||
.nf
|
||||
.B auth-sec-servers=secondary.myisp.com
|
||||
.fi
|
||||
|
||||
and
|
||||
|
||||
.nf
|
||||
our.zone.com NS secondary.myisp.com
|
||||
.fi
|
||||
|
||||
Adding auth-sec-servers enables zone transfer in dnsmasq, to allow the
|
||||
secondary to collect the DNS data. If you wish to restrict this data
|
||||
to particular hosts then
|
||||
|
||||
.nf
|
||||
.B auth-peer=<IP address of secondary>
|
||||
.fi
|
||||
|
||||
will do so.
|
||||
|
||||
Dnsmasq acts as an authoritative server for in-addr.arpa and
|
||||
ip6.arpa domains associated with the subnets given in auth-zone
|
||||
declarations, so reverse (address to name) lookups can be simply
|
||||
configured with a suitable NS record, for instance in this example,
|
||||
where we allow 1.2.3.0/24 addresses.
|
||||
|
||||
.nf
|
||||
3.2.1.in-addr.arpa NS our.zone.com
|
||||
.fi
|
||||
|
||||
Note that at present, reverse (in-addr.arpa and ip6.arpa) zones are
|
||||
not available in zone transfers, so there is no point arranging
|
||||
secondary servers for reverse lookups.
|
||||
|
||||
.PP
|
||||
When dnsmasq is configured to act as an authoritative server, the
|
||||
following data is used to populate the authoritative zone.
|
||||
.PP
|
||||
.B --mx-host, --srv-host, --dns-rr, --txt-record, --naptr-record
|
||||
, as long as the record names are in the authoritative domain.
|
||||
.PP
|
||||
.B --cname
|
||||
as long as the record name is in the authoritative domain. If the
|
||||
target of the CNAME is unqualified, then it is qualified with the
|
||||
authoritative zone name.
|
||||
.PP
|
||||
IPv4 and IPv6 addresses from /etc/hosts (and
|
||||
.B --addn-hosts
|
||||
) and
|
||||
.B --host-record
|
||||
and
|
||||
.B --interface-name
|
||||
provided the address falls into one of the subnets specified in the
|
||||
.B --auth-zone.
|
||||
.PP
|
||||
Addresses of DHCP leases, provided the address falls into one of the subnets specified in the
|
||||
.B --auth-zone.
|
||||
(If contructed DHCP ranges are is use, which depend on the address dynamically
|
||||
assigned to an interface, then the form of
|
||||
.B --auth-zone
|
||||
which defines subnets by the dynamic address of an interface should
|
||||
be used to ensure this condition is met.)
|
||||
.PP
|
||||
In the default mode, where a DHCP lease
|
||||
has an unqualified name, and possibly a qualified name constructed
|
||||
using
|
||||
.B --domain
|
||||
then the name in the authoritative zone is constructed from the
|
||||
unqualified name and the zone's domain. This may or may not equal
|
||||
that specified by
|
||||
.B --domain.
|
||||
If
|
||||
.B --dhcp-fqdn
|
||||
is set, then the fully qualified names associated with DHCP leases are
|
||||
used, and must match the zone's domain.
|
||||
|
||||
|
||||
|
||||
.SH EXIT CODES
|
||||
.PP
|
||||
0 - Dnsmasq successfully forked into the background, or terminated
|
||||
|
||||
463
man/fr/dnsmasq.8
463
man/fr/dnsmasq.8
@@ -6,24 +6,40 @@ Dnsmasq \- Un serveur DHCP et cache DNS poids-plume.
|
||||
.I [OPTION]...
|
||||
.SH "DESCRIPTION"
|
||||
.BR dnsmasq
|
||||
est un serveur DHCP et DNS à faible empreinte mémoire. Il offre à la fois les
|
||||
services DNS et DHCP pour un réseau local (LAN).
|
||||
est un serveur à faible empreinte mémoire faisant DNS, TFTP, PXE, annonces de
|
||||
routeurs et DHCP. Il offre à la fois les services DNS et DHCP pour un réseau
|
||||
local (LAN).
|
||||
.PP
|
||||
Dnsmasq accepte les requêtes DNS et y réponds soit en utilisant un petit cache
|
||||
local, soit en effectuant une requête à un serveur DNS récursif externe (par
|
||||
exemple celui de votre fournisseur d'accès internet). Il charge le contenu du
|
||||
fichier /etc/hosts afin que les noms locaux n'apparaissant pas dans les DNS
|
||||
globaux soient tout de même résolus, et assure également la résolution de nom
|
||||
pour les hôtes présents dans le service DHCP.
|
||||
pour les hôtes présents dans le service DHCP. Il peut aussi agir en temps que
|
||||
serveur DNS faisant autorité pour un ou plusieurs domaines, permettant à des
|
||||
noms locaux d'apparaitre dans le DNS global.
|
||||
.PP
|
||||
Le serveur DHCP Dnsmasq DHCP supporte les définitions d'adresses statiques et les
|
||||
réseaux multiples. Il envoie par défaut un jeu raisonnable de paramètres DHCP, et
|
||||
peut être configuré pour envoyer n'importe quel option DHCP.
|
||||
réseaux multiples. Il fournit par défaut un jeu raisonnable de paramètres DHCP,
|
||||
et peut être configuré pour fournir n'importe quelle option DHCP.
|
||||
Il inclut un serveur TFTP sécurisé en lecture seule permettant le démarrage via
|
||||
le réseau/PXE de clients DHCP et supporte également le protocole BOOTP.
|
||||
le réseau/PXE de clients DHCP et supporte également le protocole BOOTP. Le
|
||||
support PXE est complet, et comprend un mode proxy permettant de fournir des
|
||||
informations PXE aux clients alors que l'allocation DHCP est effectuée par un
|
||||
autre serveur.
|
||||
.PP
|
||||
Dnsmasq supporte IPv6 et contient un démon minimaliste capable de faire des
|
||||
annonces routeurs ("router-advertisements").
|
||||
Le serveur DHCPv6 de dnsmasq possède non seulement les mêmes fonctionalités
|
||||
que le serveur DHCPv4, mais aussi le support des annonces de routeurs ainsi
|
||||
qu'une fonctionalité permettant l'addition de ressources AAAA pour des
|
||||
clients utilisant DHCPv4 et la configuration IPv6 sans état (stateless
|
||||
autoconfiguration).
|
||||
Il inclut le support d'allocations d'adresses (à la fois en DHCPv6 et en
|
||||
annonces de routeurs - RA) pour des sous-réseaux dynamiquement délégués via
|
||||
une délégation de préfixe DHCPv6.
|
||||
.PP
|
||||
Dnsmasq est developpé pour de petits systèmes embarqués. It tends à avoir
|
||||
l'empreinte mémoire la plus faible possible pour les fonctions supportées,
|
||||
et permet d'exclure les fonctions inutiles du binaire compilé.
|
||||
.SH OPTIONS
|
||||
Notes : Il est possible d'utiliser des options sans leur donner de paramètre.
|
||||
Dans ce cas, la fonction correspondante sera désactivée. Par exemple
|
||||
@@ -76,9 +92,16 @@ l'absence d'enregistrement SOA.
|
||||
.TP
|
||||
.B --max-ttl=<durée>
|
||||
Définie la valeur de TTL maximum qui sera fournie aux clients. La valeur maximum
|
||||
de TTL spécifiée sera fournie aux clients en remplacement de la vraie valeur de TTL
|
||||
si cette dernière est supérieure. La valeur réelle de TTL est cependant conservée dans
|
||||
le cache afin d'éviter de saturer les serveurs DNS en amont.
|
||||
de TTL spécifiée sera fournie aux clients en remplacement de la vraie valeur de
|
||||
TTL si cette dernière est supérieure. La valeur réelle de TTL est cependant
|
||||
conservée dans le cache afin d'éviter de saturer les serveurs DNS en amont.
|
||||
.TP
|
||||
.B --max-cache-ttl=<durée>
|
||||
Définie la valeur de TTL maximum pour les entrées dans le cache
|
||||
.TP
|
||||
.B --auth-ttl=<durée>
|
||||
Définie la valeur de TTL retournée pour les réponses du serveur faisant
|
||||
autorité.
|
||||
.TP
|
||||
.B \-k, --keep-in-foreground
|
||||
Ne pas aller en tâche de fond au lancement, mais en dehors de cela, fonctionner
|
||||
@@ -90,7 +113,10 @@ Mode debug (déverminage) : ne pas aller en tâche de fond, ne pas écrire de
|
||||
fichier pid, ne pas changer d'identifiant utilisateur, générer un état complet
|
||||
du cache lors de la réception d'un signal SIGUSR1, envoyer les logs sur la
|
||||
sortie standard d'erreur ("stderr") de même que dans le syslog, ne pas créer de
|
||||
processus fils pour traiter les requêtes TCP.
|
||||
processus fils pour traiter les requêtes TCP. A noter que cette option est à
|
||||
user pour du déverminage seulement : pour empêcher dnsmasq se fonctionner en
|
||||
mode démon en production, utiliser
|
||||
.B -k.
|
||||
.TP
|
||||
.B \-q, --log-queries
|
||||
Enregistrer les résultats des requêtes DNS traitées par Dnsmasq dans un fichier
|
||||
@@ -185,7 +211,11 @@ ni
|
||||
.B \--except-interface.
|
||||
Utiliser l'option
|
||||
.B --listen-address
|
||||
à la place.
|
||||
à la place. Un simple joker, consistant d'un '*' final, peut-être utilisé dans
|
||||
les options
|
||||
.B \--interface
|
||||
et
|
||||
.B \--except-interface
|
||||
.TP
|
||||
.B \-I, --except-interface=<interface name>
|
||||
Ne pas écouter sur l'interface spécifiée. Notez que l'ordre dans lesquelles les
|
||||
@@ -198,6 +228,21 @@ et
|
||||
sont fournies n'importe pas, et que l'option
|
||||
.B --except-interface
|
||||
l'emporte toujours sur les autres.
|
||||
.TP
|
||||
.B --auth-server=<domaine>,<interface>|<addresse IP>
|
||||
Active le mode DNS faisant autorité pour les requêtes arrivant sur cette
|
||||
interface ou sur cette adresse. Noter que l'interface ou l'adresse n'ont
|
||||
pas besoin d'être mentionées ni dans
|
||||
.B --interface
|
||||
ni dans
|
||||
.B --listen-address
|
||||
En effet,
|
||||
.B --auth-server
|
||||
va passer outre ceux-ci et fournir un service DNS différent sur l'interface
|
||||
spécifiée. La valeur de <domaine> est l'enregistrement de type "colle"
|
||||
("glue record"). Il doit correspondre dans le service DNS global avec un
|
||||
enregistrement de type A et/ou AAAA pointant sur l'adresse sur laquelle dnsmasq
|
||||
écoute pour le mode DNS faisant autorité.
|
||||
.TP
|
||||
.B \-2, --no-dhcp-interface=<nom d'interface>
|
||||
Ne pas fournir de service DHCP sur l'interface spécifiée, mais fournir tout de
|
||||
@@ -312,11 +357,14 @@ Ne pas lire le contenu du fichier /etc/resolv.conf. N'obtenir l'adresse des
|
||||
serveurs de nom amont que depuis la ligne de commande ou le fichier de
|
||||
configuration de Dnsmasq.
|
||||
.TP
|
||||
.B \-1, --enable-dbus
|
||||
.B \-1, --enable-dbus[=<nom de service>]
|
||||
Autoriser la mise à jour de la configuration de Dnsmasq par le biais d'appel de
|
||||
méthodes DBus. Il est possible par ce biais de mettre à jour l'adresse de
|
||||
serveurs DNS amont (et les domaines correspondants) et de vider le cache. Cette
|
||||
option nécessite que Dnsmasq soit compilé avec le support DBus.
|
||||
option nécessite que Dnsmasq soit compilé avec le support DBus. Si un nom de
|
||||
service est fourni, dnsmasq fourni un service à ce nom, plutôt qu'avec la
|
||||
valeur par défaut :
|
||||
.B uk.org.thekelleys.dnsmasq
|
||||
.TP
|
||||
.B \-o, --strict-order
|
||||
Par défaut, Dnsmasq envoie les requêtes à n'importe lequel des serveurs amonts
|
||||
@@ -355,7 +403,8 @@ noms de domains entourés par des '/', selon une syntaxe similaire à l'option
|
||||
Ne pas vérifier régulièrement si le fichier /etc/resolv.conf a été modifié.
|
||||
.TP
|
||||
.B --clear-on-reload
|
||||
Lorsque le fichier /etc/resolv.conf est relu, vider le cache DNS.
|
||||
Lorsque le fichier /etc/resolv.conf est relu, ou si les serveurs amonts sont
|
||||
configurés via DBus, vider le cache DNS.
|
||||
Cela est utile si les nouveaux serveurs sont susceptibles d'avoir des données
|
||||
différentes de celles stockées dans le cache.
|
||||
.TP
|
||||
@@ -455,6 +504,12 @@ n'ayant de réponse ni dans /etc/hosts, ni dans les baux DHCP, et n'étant pas
|
||||
transmise à un serveur spécifique par le biais d'une directive
|
||||
.B --server.
|
||||
.TP
|
||||
.B --ipset=/<domaine>/[domaine/]<ipset>[,<ipset>]
|
||||
Obtient les adresses IP des domaines spécifiés et les place dans les groupes
|
||||
d'IP netfilter (ipset) indiqués. Domaines et sous-domaines sont résolus de la
|
||||
même façon que pour --address. Ces groupes d'IP doivent déjà exister. Voir
|
||||
ipset(8) pour plus de détails.
|
||||
.TP
|
||||
.B \-m, --mx-host=<nom de l'hôte>[[,<nom du MX>],<préference>]
|
||||
Spécifie un enregistrement de type MX pour <nom de l'hôte> retournant le nom
|
||||
donné dans <nom du MX> (s'il est présent), ou sinon le nom spécifié dans
|
||||
@@ -542,9 +597,9 @@ Retourne un enregistrement de type NAPTR, tel que spécifié dans le RFC3403.
|
||||
.TP
|
||||
.B --cname=<cname>,<cible>
|
||||
Retourne un enregistrement de type CNAME qui indique que <cname> est en
|
||||
réalité <cible>. Il existe des contraintes significatives sur la valeur
|
||||
de cible; il doit s'agir d'un nom DNS qui est connu de dnsmasq via /etc/hosts
|
||||
(ou un fichier hôtes additionnel), ou via DHCP, ou par un autre
|
||||
réalité <cible>. Il existe des contraintes importantes sur la valeur
|
||||
cible; il doit s'agir d'un nom DNS qui est connu de dnsmasq via /etc/hosts
|
||||
(ou un fichier hôtes additionnel), via DHCP, via interface--name ou par un autre
|
||||
.B --cname.
|
||||
Si une cible ne satisfait pas ces critères, le CNAME est ignoré. Le CNAME
|
||||
doit être unique, mais il est autorisé d'avoir plus d'un CNAME pointant
|
||||
@@ -568,6 +623,24 @@ Plus d'un nom peut être associé à une interface donnée en répétant cette o
|
||||
plusieurs fois; dans ce cas, l'enregistrement inverse pointe vers le nom fourni
|
||||
dans la première instance de cette option.
|
||||
.TP
|
||||
.B --synth-domain=<domaine>,<plage d'adresses>[,<préfixe>]
|
||||
Créé des enregistrements A/AAAA ou PTR pour une plage d'adresses. Les
|
||||
enregistrements utilisent l'adresse ainsi que les points (ou les deux points
|
||||
dans le cas d'IPv6) remplacés par des tirets.
|
||||
|
||||
Un exemple devrait rendre cela plus clair :
|
||||
La configuration
|
||||
.B --synth-domain=thekelleys.org.uk,192.168.0.0/24,internal-
|
||||
permet de retourner internal-192-168-0-56.thekelleys.org.uk lors d'une requête
|
||||
sur l'adresse 192.168.0.56 et vice-versa pour la requête inverse. La même
|
||||
logique s'applique pour IPv6, avec la particularité suivante : les adresses
|
||||
IPv6 pouvant commencer par '::', mais les noms DNS ne pouvant pas commencer
|
||||
par '-', si aucun préfixe n'est donné, un zéro est ajouté en début de nom.
|
||||
Ainsi, ::1 devient 0--1.
|
||||
|
||||
La plage d'adresses peut-être de la forme
|
||||
<adresse IP>,<adresse IP> ou <adresse IP>/<masque réseau>
|
||||
.TP
|
||||
.B --add-mac
|
||||
Ajoute l'adresse MAC du requêteur aux requêtes DNS transmises aux serveurs
|
||||
amonts. Cela peut être utilisé dans un but de filtrage DNS par les serveurs
|
||||
@@ -576,7 +649,20 @@ même sous-réseau que le serveur dnsmasq. Veuillez noter que le mécanisme
|
||||
utilisé pour effectuer cela (une option EDNS0) n'est pas encore standardisée,
|
||||
aussi cette fonctionalité doit être considérée comme expérimentale. Notez
|
||||
également qu'exposer les adresses MAC de la sorte peut avoir des implications
|
||||
en termes de sécurité et de vie privée.
|
||||
en termes de sécurité et de vie privée. L'avertissement donné pour --add-subnet
|
||||
s'applique également ici.
|
||||
.TP
|
||||
.B --add-subnet[[=<longueur de préfixe IPv4>],<longueur de préfixe IPv6>]
|
||||
Rajoute l'adresse de sous-réseau du requêteur aux requêtes DNS transmises
|
||||
aux serveurs amonts. La quantité d'adresses transmises dépend du paramètre
|
||||
longueur du préfixe : 32 (ou 128 dans le cas d'IPv6) transmet la totalité
|
||||
de l'adresse, 0 n'en transmet aucun mais marque néanmoins la requête ce qui
|
||||
fait qu'aucun serveur amont ne rajoutera d'adresse client. La valeur par
|
||||
défaut est zéro et pour IPv4 et pour IPv6. A noter que les serveurs amonts
|
||||
peuvent-être configurés pour retourner des valeurs différentes en fonction
|
||||
de cette information mais que le cache de dnsmasq n'en tient pas compte.
|
||||
Si une instance de dnsmasq est configurée de telle maniêre que des valeurs
|
||||
différentes pourraient-être rencontrés, alors le cache devrait être désactivé.
|
||||
.TP
|
||||
.B \-c, --cache-size=<taille>
|
||||
Définit la taille du cache de Dnsmasq. La valeur par défaut est de 150 noms.
|
||||
@@ -611,6 +697,39 @@ Si vous utilisez le premier mode DNSSEC, la validation par le resolveur des
|
||||
clients, cette option n'est pas requise. Dnsmasq retourne toujours toutes les
|
||||
données nécessaires par un client pour effectuer la validation lui-même.
|
||||
.TP
|
||||
|
||||
.B --auth-zone=<domaine>[,<sous-réseau>[/<longueur de préfixe>][,<sous-réseau>[/<longueur de préfixe>].....]]
|
||||
Définie une zone DNS pour laquelle dnsmasq agit en temps que serveur faisant
|
||||
autorité. Les enregistrements DNS définis localement et correspondant à ce
|
||||
domaine seront fournis. Les enregistrements A et AAAA doivent se situer dans
|
||||
l'un des sous-réseaux définis, ou dans un réseau correspondant à une plage DHCP
|
||||
(ce comportement peut-être désactivé par
|
||||
.B constructor-noauth:
|
||||
). Le ou les sous-réseaux sont également utilisé(s) pour définir les domaines
|
||||
in-addr.arpa et ip6.arpa servant à l'interrogation DNS inverse. Si la longueur
|
||||
de préfixe n'est pas spécifiée, elle sera par défaut de 24 pour IPv4 et 64 pour
|
||||
IPv6. Dans le cas d'IPv4, la longueur du masque de réseau devrait-être de 8, 16
|
||||
ou 24, sauf si en cas de mise en place d'une délégation de la zone in-addr.arpa
|
||||
conforme au RFC 2317.
|
||||
.TP
|
||||
.B --auth-soa=<numéro de série>[,<mainteneur de zone (hostmaster)>[,<rafraichissement>[,<nombre de réessais>[,<expiration>]]]]
|
||||
Spécifie les champs de l'enregistrement de type SOA (Start Of Authority)
|
||||
associé à une zone pour laquelle le serveur fait autorité. A noter que cela est
|
||||
optionnel, les valeurs par défaut devant convenir à la majorité des cas.
|
||||
.TP
|
||||
.B --auth-sec-servers=<domaine>[,<domaine>[,<domaine>...]]
|
||||
Spécifie un ou plusieurs serveur de nom secondaires pour une zone pour
|
||||
laquelle dnsmasq fait autorité. Ces serveurs doivent-être configurés pour
|
||||
récupérer auprès de dnsmasq les informations liées à la zone au travers d'un
|
||||
transfert de zone, et répondre aux requêtes pour toutes les zones pour
|
||||
lesquelles dnsmasq fait autorité.
|
||||
.TP
|
||||
.B --auth-peer=<adresse IP>[,<adresse IP>[,<adresse IP>...]]
|
||||
Spécifie la ou les adresses de serveurs secondaires autorisés à initier des
|
||||
requêtes de transfert de zone (AXFR) pour les zones pour lesquelles
|
||||
dnsmasq fait autorité. Si cette option n'est pas fournie, les requêtes AXFR
|
||||
seront acceptées pour tous les serveurs secondaires.
|
||||
.TP
|
||||
.B --conntrack
|
||||
Lis le marquage de suivi de connexion Linux associé aux requêtes DNS entrantes
|
||||
et positionne la même marque au trafic amont utilisé pour répondre à ces
|
||||
@@ -623,7 +742,8 @@ configuré pour cela. Cette option ne peut pas être combinée avec
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[tag:<label>[,tag:<label>],][set:<label>],]<adresse de début>[,<adresse de fin>][,<mode>][,<masque de réseau>[,<broadcast>]][,<durée de bail>]
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[tag:<label>[,tag:<label>],][set:<label>],]<addresse IPv6 de début>[,<adresse IPv6 de fin>][,<mode>][,<longueur de préfixe>][,<durée de bail>]
|
||||
.B \-F, --dhcp-range=[tag:<label>[,tag:<label>],][set:<label>],]<addresse IPv6 de début>[,<adresse IPv6 de fin>|constructor:<interface>][,<mode>][,<longueur de préfixe>][,<durée de bail>]
|
||||
|
||||
Active le serveur DHCP. Les adresses seront données dans la plage comprise entre
|
||||
<adresse de début> et <adresse de fin> et à partir des adresses définies
|
||||
statiquement dans l'option
|
||||
@@ -663,6 +783,43 @@ d'IPv4, la longueur de préfixe n'est pas automatiquement déduite de la
|
||||
configuration de l'interface. La taille minimale pour la longueur de préfixe
|
||||
est 64.
|
||||
|
||||
Pour IPv6 (et IPv6 uniquement), il est possible de définir les plages d'une
|
||||
autre façon. Dans ce cas, l'adresse de départ et l'adresse de fin optionnelle
|
||||
contiennent uniquement la partie réseau (par exemple ::1) et sont suivies par
|
||||
.B constructor:<interface>.
|
||||
Cela forme un modèle décrivant comment construire la plage, à partir des
|
||||
adresses assignées à l'interface. Par exemple
|
||||
|
||||
.B --dhcp-range=::1,::400,constructor:eth0
|
||||
|
||||
provoque la recherche d'adresses de la forme <réseau>::1 sur eth0 et crée une
|
||||
plage allant de <réseau>::1 à <réseau>:400. Si une interface est assignée à
|
||||
plus d'un réseau, les plages correspondantes seront automatiquement créées,
|
||||
rendues obsolètes puis supprimées lorsque l'adress est rendue obsolète puis
|
||||
supprimée. Le nom de l'interface peut être spécifié avec un caractère joker '*'
|
||||
final.
|
||||
|
||||
provoque la recherche d'adresses sur eth0 et crée une plage allant de
|
||||
<réseau>::1 à <réseau>:400. Si l'interface est assignée à
|
||||
plus d'un réseau, les plages correspondantes seront respectivement
|
||||
automatiquement créées, rendues obsolètes et supprimées lorsque l'adresse
|
||||
est rendue obsolète et supprimée. Le nom de l'interface peut être spécifié avec
|
||||
un caractère joker '*' final. Les adresses autoconfigurées, privées ou
|
||||
obsolètes ne conviennent pas.
|
||||
|
||||
Si une plage dhcp-range est uniquement utilisée pour du DHCP sans-état
|
||||
("stateless") ou de l'autoconfiguration sans état ("SLAAC"), alors l'adresse
|
||||
peut-être indiquée sous la forme '::'
|
||||
|
||||
.B --dhcp-range=::,constructor:eth0
|
||||
|
||||
Il existe une variante de la syntaxe constructor: qui consiste en l'utilisation
|
||||
du mot-clef
|
||||
.B constructor-noauth.
|
||||
Voir
|
||||
.B --auth-zone
|
||||
pour des explications à ce sujet.
|
||||
|
||||
L'identifiant de label optionnel
|
||||
.B set:<label>
|
||||
fournie une étiquette alphanumérique qui identifie ce réseau, afin de permettre
|
||||
@@ -677,7 +834,13 @@ Le mot clef optionnel <mode> peut être égal à
|
||||
spécifié, mais de ne pas activer l'allocation dynamique d'adresses IP : Seuls
|
||||
les hôtes possédant des adresses IP statiques fournies via
|
||||
.B dhcp-host
|
||||
ou présentes dans le fichier /etc/ethers seront alors servis par le DHCP.
|
||||
ou présentes dans le fichier /etc/ethers seront alors servis par le DHCP. Il est
|
||||
possible d'activer un mode "fourre-tout" en définissant un réseau statique
|
||||
comportant uniquement des zéros, c'est à dire :
|
||||
.B --dhcp=range=::,static
|
||||
Cela permet de retourner des réponses à tous les paquets de type
|
||||
Information-request (requête d'information) en mode DHCPv6 sans état sur le
|
||||
sous-réseau configuré.
|
||||
|
||||
Pour IPv4, le <mode> peut est égal à
|
||||
.B proxy
|
||||
@@ -748,9 +911,9 @@ sous-réseau qu'une plage dhcp-range valide. Pour les sous-réseaux qui n'ont pa
|
||||
besoin d'adresses dynamiquement allouées, utiliser le mot-clef "static" dans la
|
||||
déclaration de plage d'adresses dhcp-range.
|
||||
|
||||
Il est possible
|
||||
d'utiliser des identifiants clients plutôt que des adresses matérielles pour
|
||||
identifier les hôtes, en préfixant par ceux-ci par 'id:'. Ainsi,
|
||||
Il est possible d'utiliser des identifiants clients (appellé "DUID client" dans
|
||||
le monde IPv6) plutôt que des adresses matérielles pour identifier les hôtes,
|
||||
en préfixant ceux-ci par 'id:'. Ainsi,
|
||||
.B --dhcp-host=id:01:02:03:04,.....
|
||||
réfère à l'hôte d'identifiant 01:02:03:04. Il est également possible de
|
||||
spécifier l'identifiant client sous la forme d'une chaîne de caractères, comme
|
||||
@@ -762,11 +925,17 @@ Un seul
|
||||
peut contenir une adresse IPv4, une adresse IPv6, ou les deux en même temps.
|
||||
Les adresses IPv6 doivent-être mises entre crochets comme suit :
|
||||
.B --dhcp-host=laptop,[1234::56]
|
||||
A noter que pour le DHCP IPv6, l'adresse matérielle n'est en principe pas
|
||||
disponible, aussi un client doit-être identifié par un identifiant de client
|
||||
(appellé "DUID client") ou un nom d'hôte.
|
||||
Les adresses IPv6 peuvent ne contenir que la partie identifiant de client :
|
||||
.B --dhcp-host=laptop,[::56]
|
||||
Dans ce cas, lorsque des plages dhcp sont définies automatiquement par le biais
|
||||
de constructeurs, la partie réseau correspondante est rajoutée à l'adresse.
|
||||
|
||||
L'option spéciale id:* signifie : "ignorer tout identifiant client et n'utiliser
|
||||
A noter que pour le DHCP IPv6, l'adresse matérielle n'est pas toujours
|
||||
disponible, bien que ce soit toujours le cas pour des clients directement
|
||||
connectés (sur le même domaine de broadcast) ou pour des clients utilisant
|
||||
des relais DHCP qui supportent la RFC 6939.
|
||||
|
||||
En DHCPv4, l'option spéciale id:* signifie : "ignorer tout identifiant client et n'utiliser
|
||||
que l'adresse matérielle". Cela est utile lorsqu'un client présente un
|
||||
identifiant client mais pas les autres.
|
||||
|
||||
@@ -970,6 +1139,40 @@ quelques rares cas, perturber des clients vieux ou défectueux. Cette
|
||||
option force le comportement à l'utilisation des valeurs "simples et sûres"
|
||||
afin d'éviter des problèmes dans de tels cas.
|
||||
.TP
|
||||
.B --dhcp-relay=<adresse locale>,<adresse de serveur>[,<interface]
|
||||
Configure dnsmasq en temps que relais DHCP. L'adresse locale est une
|
||||
adresse allouée à l'une interface de la machine sur laquelle tourne dnsmasq.
|
||||
Toutes les requêtes DHCP arrivant sur cette interface seront relayées au
|
||||
serveur DHCP distant correspondant à l'adresse de serveur indiquée. Il est
|
||||
possible de relayer depuis une unique adresse locale vers différents serveurs
|
||||
distant en spécifiant plusieurs fois l'option dhcp-relay avec la même adresse
|
||||
locale et différentes adresses de serveur. L'adresse de serveur doit-être
|
||||
sous forme numérique. Dans le cas de DHCPv6, l'adresse de serveur peut-être
|
||||
l'adresse de multicast ff05::1:3 correspondant à tous les serveurs DHCP. Dans
|
||||
ce cas, l'interface doit-étre spécifiée et ne peut comporter de caractère
|
||||
joker. Elle sera utilisée pour indiquer l'interface à partir de laquelle le
|
||||
multicast pourra atteindre le serveur DHCP.
|
||||
|
||||
Le contrôle d'accès pour les clients DHCP suivent les mêmes règles que pour
|
||||
les serveurs DHCP : voir --interface, --except-interface, etc. Le nom
|
||||
d'interface optionel dans l'option dhcp-relay comporte une autre fonction :
|
||||
il contrôle l'interface sur laquelle la réponse du serveur sera acceptée. Cela
|
||||
sert par exemple dans des configurations à 3 interfaces : une à partir de
|
||||
laquelle les requêtes sont relayées, une seconde permettant de se connecter à
|
||||
un serveur DHCP, et une troisième reliée à un réseau non-sécurisé tel
|
||||
qu'internet. Cela permet d'éviter l'arrivée de requêtes usurpées via cette
|
||||
troisième interface.
|
||||
|
||||
Il est permis de configurer dnsmasq pour fonctionner comme serveur DHCP sur
|
||||
certaines interfaces et en temps que relais sur d'autres. Cependant, même s'il
|
||||
est possible de configurer dnsmasq de telle manière qu'il soit à la fois
|
||||
serveur et relais pour une même interface, cela n'est pas supporté et la
|
||||
fonction de relais prendra le dessus.
|
||||
|
||||
Le relais DHCPv4 et le relais DHCPv6 sont tous les deux supportés, mais il
|
||||
n'est pas possible de relayer des requêtes DHCPv4 à un serveur DHCPv6 et
|
||||
vice-versa.
|
||||
.TP
|
||||
.B \-U, --dhcp-vendorclass=set:<label>,[enterprise:<numéro IANA d'enterprise>,]<classe de vendeur>
|
||||
|
||||
Associe une chaîne de classe de vendeur à un label. La plupart
|
||||
@@ -1004,7 +1207,7 @@ d'impression différent pour les hôtes de la classe "comptes" et ceux de la
|
||||
classe "ingénierie".
|
||||
.TP
|
||||
.B \-4, --dhcp-mac=set:<label>,<adresse MAC>
|
||||
(IPv4 uniquement) Associe une adresse matérielle (MAC) à un label. L'adresse
|
||||
Associe une adresse matérielle (MAC) à un label. L'adresse
|
||||
matérielle peut inclure des jokers. Par exemple
|
||||
.B --dhcp-mac=set:3com,01:34:23:*:*:*
|
||||
permet de définir le label "3com" pour n'importe quel hôte dont l'adresse
|
||||
@@ -1204,14 +1407,16 @@ créant des milliers de baux et utilisant beaucoup de mémoire dans le processus
|
||||
Dnsmasq.
|
||||
.TP
|
||||
.B \-K, --dhcp-authoritative
|
||||
(IPv4 seulement) Cette option doit être donnée lorsque Dnsmasq est le seul
|
||||
serveur DHCP sur le réseau. Cela change le comportement par défaut qui est
|
||||
Doit être spécifié lorsque dnsmasq est réellement le seul serveur DHCP
|
||||
sur le réseau. Pour DHCPv4, cela change le comportement par défaut qui est
|
||||
celui d'un strict respect des RFC, afin que les requêtes DHCP pour des baux
|
||||
inconnus par des hôtes inconnus ne soient pas ignorées. Cela permet à de
|
||||
nouveaux hôtes d'obtenir des baux sans tenir compte de fastidieuses
|
||||
temporisations ("timeout"). Cela permet également à Dnsmasq de reconstruire
|
||||
sa base de données contenant les baux sans que les clients n'aient besoin de
|
||||
redemander un bail, si celle-ci est perdue.
|
||||
Dans le cas de DHCPv6, cela positionne la priorité des réponses à 255 (le
|
||||
maximum) au lieu de 0 (le minimum).
|
||||
.TP
|
||||
.B --dhcp-alternate-port[=<port serveur>[,<port client>]]
|
||||
(IPv4 seulement) Change les ports utilisés par défaut pour le DHCP. Si cette
|
||||
@@ -1243,6 +1448,11 @@ Traces additionnelles pour le service DHCP : enregistre toutes les options
|
||||
envoyées aux clients DHCP et les labels utilisés pour la
|
||||
détermination de celles-ci.
|
||||
.TP
|
||||
.B --quiet-dhcp, --quiet-dhcp6, --quiet-ra
|
||||
Supprime les logs des opérations de routine des protocoles concernés. Les
|
||||
erreurs et les problèmes seront toujours enregistrés. L'option --log-dhcp
|
||||
prends le pas sur --quiet-dhcp et quiet-dhcp6.
|
||||
.TP
|
||||
.B \-l, --dhcp-leasefile=<chemin de fichier>
|
||||
Utilise le fichier dont le chemin est fourni pour stocker les informations de
|
||||
baux DHCP.
|
||||
@@ -1319,6 +1529,9 @@ Pour IPv4 seulement :
|
||||
|
||||
DNSMASQ_CLIENT_ID, si l'hôte a fourni un identifiant de client.
|
||||
|
||||
DNSMASQ_CIRCUIT_ID, DNSMASQ_SUBSCRIBER_ID, DNSMASQ_REMOTE_ID si un relai DHCP a
|
||||
rajouté l'une de ces options.
|
||||
|
||||
Si le client fournit une information de classe de vendeur, DNSMASQ_VENDOR_CLASS.
|
||||
|
||||
Pour IPv6 seulement :
|
||||
@@ -1333,6 +1546,8 @@ pour chaque appel au script.
|
||||
DNSMASQ_IAID contenant l'IAID pour le bail. Si le bail est une allocation
|
||||
temporaire, cela est préfixé par le caractère 'T'.
|
||||
|
||||
DNSMASQ_MAC contient l'adresse MAC du client, si celle-ci est connue.
|
||||
|
||||
A noter que le nom d'hôte fourni, la classe de vendeur ou les données de classe
|
||||
d'utilisateur sont uniquement fournies pour les actions "add" ou l'action "old"
|
||||
lorsqu'un hôte reprend un bail existant, puisque ces informations ne sont pas
|
||||
@@ -1535,11 +1750,30 @@ dnsmasq est spécifiée comme DNS récursif. Si elles sont fournies, les
|
||||
options dns-server et domain-search sont utilisées respectivement pour RDNSS et
|
||||
DNSSL.
|
||||
.TP
|
||||
.B --enable-tftp
|
||||
.B --ra-param=<interface>,[high|low],[[<intervalle d'annonce routeur>],<durée de vie route>]
|
||||
Configure pour une interface donnée des valeurs pour les annonces routeurs
|
||||
différentes des valeurs par défaut. La valeur par défaut du champ priorité
|
||||
pour le routeur peut-être changée de "medium" (moyen) à "high" (haute) ou
|
||||
"low" (basse). Par exemple :
|
||||
.B --ra-param=eth0,high.
|
||||
Un intervalle (en secondes) entre les annonces routeur peut-être fourni par :
|
||||
.B --ra-param=eth0,60.
|
||||
La durée de vie de la route peut-être changée ou mise à zéro, auquel cas
|
||||
le routeur peut annoncer les préfixes mais pas de route :
|
||||
.B --ra-parm=eth0,0,0
|
||||
(une valeur de zéro pour l'intervalle signifie qu'il garde la valeur par défaut).
|
||||
Ces trois paramètres peuvent-être configurés en une fois :
|
||||
.B --ra-param=low,60,1200
|
||||
La valeur pour l'interface peut inclure un caractère joker.
|
||||
.TP
|
||||
.B --enable-tftp[=<interface>[,<interface>]]
|
||||
Active la fonction serveur TFTP. Celui-ci est de manière délibérée limité aux
|
||||
fonctions nécessaires au démarrage par le réseau ("net-boot") d'un client. Seul
|
||||
un accès en lecture est possible; les extensions tsize et blksize sont supportées
|
||||
(tsize est seulement supporté en mode octet).
|
||||
(tsize est seulement supporté en mode octet). Sans argument optionel, le service
|
||||
TFTP est fourni sur les mêmes interfaces que le service DHCP. Si une liste
|
||||
d'interfaces est fournie, cela définit les interfaces sur lesquelles le
|
||||
service TFTP sera activé.
|
||||
.TP
|
||||
.B --tftp-root=<répertoire>[,<interface>]
|
||||
Les fichiers à fournir dans les transferts TFTP seront cherchés en prenant le
|
||||
@@ -1847,6 +2081,167 @@ supprime la nécessité des associations statiques). Le paramètre
|
||||
que le label "bootp", permettant un certain contrôle sur les options retournées
|
||||
aux différentes classes d'hôtes.
|
||||
|
||||
|
||||
.SH CONFIGURATION EN TEMPS QUE SERVEUR FAISANT AUTORITÉ
|
||||
.PP
|
||||
Configurer dnsmasq pour agir en temps que serveur DNS faisant autorité est
|
||||
compliqué par le fait que cela implique la configuration de serveurs DNS
|
||||
externes pour mettre en place la délégation. Seront présentés ci-dessous trois
|
||||
scénarios de complexité croissante. Le pré-requis pour chacun de ces scénarios
|
||||
est l'existence d'une adresse IP globalement disponible, d'un enregistrement de
|
||||
type A ou AAAA pointant vers cette adresse, ainsi que d'un serveur DNS externe
|
||||
capable d'effectuer la délégation de la zone en question. Pour la première
|
||||
partie de ces explications, nous allons appeller serveur.exemple.com
|
||||
l'enregistrement A (ou AAAA) de l'adresse globalement accessible, et
|
||||
notre.zone.com la zone pour laquelle dnsmasq fait autorité.
|
||||
|
||||
La configuration la plus simple consiste en deux lignes de configuration,
|
||||
sous la forme :
|
||||
.nf
|
||||
.B auth-server=serveur.exemple.com,eth0
|
||||
.B auth-zone=notre.zone.com,1.2.3.0/24
|
||||
.fi
|
||||
|
||||
ainsi que deux enregistrements dans le DNS externe :
|
||||
|
||||
.nf
|
||||
serveur.exemple.com A 192.0.43.10
|
||||
notre.zone.com NS serveur.exemple.com
|
||||
.fi
|
||||
|
||||
eth0 est l'interface réseau externe sur laquelle dnsmasq écoute, dont l'adresse
|
||||
IP (globalement accessible) est 192.0.43.10.
|
||||
|
||||
A noter que l'adresse IP externe peut parfaitement être dynamique (par exemple
|
||||
attribuée par un FAI via DHCP ou PPP). Dans ce cas, l'enregistrement de type A
|
||||
doit être lié à cet enregistrement dynamique par l'une ou l'autre des techniques
|
||||
habituelles de système DNS dynamique.
|
||||
|
||||
Un exemple plus complexe mais en pratique plus utile correspond au cas où
|
||||
l'adresse IP globalement accessible se trouve dans la zone pour laquelle
|
||||
dnsmasq fait autorité, le plus souvent à la racine. Dans ce cas nous avons :
|
||||
|
||||
.nf
|
||||
.B auth-server=notre.zone.com,eth0
|
||||
.B auth-zone=notre.zone.com,1.2.3.0/24
|
||||
.fi
|
||||
|
||||
.nf
|
||||
notre.zone.com A 1.2.3.4
|
||||
notre.zone.com NS our.zone.com
|
||||
.fi
|
||||
|
||||
L'enregistrement A pour notre.zone.com est dorénavant un enregistrement "colle"
|
||||
qui résoud le problème de poule et d'oeuf consistant à trouver l'adresse IP
|
||||
du serveur de nom pour notre.zone.com lorsque l'enregistrement se trouve dans
|
||||
la zone en question. Il s'agit du seul rôle de cet enregistrement : comme dnsmasq
|
||||
fait désormais autorité pour notre.zone.com, il doit également fournir cet
|
||||
enregistrement. Si l'adresse externe est statique, cela peut-être réalisé par
|
||||
le biais d'une entrée dans
|
||||
.B /etc/hosts
|
||||
ou via un
|
||||
.B --host-record.
|
||||
|
||||
.nf
|
||||
.B auth-server=notre.zone.com,eth0
|
||||
.B host-record=notre.zone.com,1.2.3.4
|
||||
.B auth-zone=notre.zone.com,1.2.3.0/24
|
||||
.fi
|
||||
|
||||
Si l'adresse externe est dynamique, l'adresse associée à notre.zone.com doit
|
||||
être dérivée de l'interface correspondante. Cela peut être fait en utilisant
|
||||
.B interface-name
|
||||
Sous la forme :
|
||||
|
||||
.nf
|
||||
.B auth-server=notre.zone.com,eth0
|
||||
.B interface-name=notre.zone.com,eth0
|
||||
.B auth-zone=notre.zone.com,1.2.3.0/24
|
||||
.fi
|
||||
|
||||
La configuration finale rajoute à cette base un serveur DNS secondaire. Il
|
||||
s'agit d'un autre serveur DNS qui apprend les données DNS de la zone en
|
||||
effectuant un transfert de zone, et qui joue le rôle de serveur de secours
|
||||
au cas où le serveur principal devenait inaccessible. La configuration
|
||||
de ce serveur secondaire sort du cadre de cette page de manuel. Les éléments
|
||||
de configuration à rajouter dans dnsmasq sont les simples :
|
||||
|
||||
.nf
|
||||
.B auth-sec-servers=secondaire.monfai.com
|
||||
.fi
|
||||
|
||||
et
|
||||
|
||||
.nf
|
||||
notre.zone.com NS secondaire.monfai.com
|
||||
.fi
|
||||
|
||||
L'addition d'une option auth-sec-servers active les transferts de zone dans
|
||||
dnsmasq, ce qui permet au serveur secondaire de venir collecter les données
|
||||
DNS. Si vous souhaitez restreindre l'accès à ces données à des hôtes
|
||||
spécifiques, vous pouvez le faire via :
|
||||
|
||||
.nf
|
||||
.B auth-peer=<adresse IP du serveur secondaire>
|
||||
.fi
|
||||
|
||||
Dnsmasq joue le rôle de serveur faisant autorité pour les domaines in-addr.arpa
|
||||
et ip6.arpa associés aux sous-réseaux définis dans la déclaration de zone
|
||||
auth-zone, ce qui fait que les requêtes DNS inversées (de l'adresse vers
|
||||
le nom) peuvent-simplement être configurées avec un enregistrement NS
|
||||
adéquat. Par exemple, comme nous définissons plus haut les adresses
|
||||
1.2.3.0/24 :
|
||||
.nf
|
||||
3.2.1.in-addr.arpa NS notre.zone.com
|
||||
.fi
|
||||
|
||||
Veuillez noter que pour l'instant, les zones inverses ne sont pas
|
||||
disponibles dans les transferts de zone, donc il est inutile de configurer
|
||||
de serveur secondaire pour la résolution inverse.
|
||||
|
||||
.PP
|
||||
Lorsque dnsmasq est configuré en temps que serveur faisant autorité,
|
||||
les données suivantes sont utilisées pour peupler la zone considérée :
|
||||
.PP
|
||||
.B --mx-host, --srv-host, --dns-rr, --txt-record, --naptr-record
|
||||
, pour autant que les noms des enregistrements se trouvent dans la zone en
|
||||
question.
|
||||
.PP
|
||||
.B --cname
|
||||
pour peu que le nom soit dans le domaine. Si la cible du CNAME n'est
|
||||
pas pleinement qualifiée, alors elle est qualifiée avec le nom de la
|
||||
zone pour laquelle le serveur fait autorité.
|
||||
.PP
|
||||
Les adresses IPv4 et IPv6 extraites de /etc/hosts (et
|
||||
.B --addn-hosts
|
||||
) ainsi que les options
|
||||
.B --host-record
|
||||
fournissant des adresses situées dans l'un des sous-réseaux spécifiés dans
|
||||
.B --auth-zone.
|
||||
.PP
|
||||
Adresses spécifiées par
|
||||
.B --interface-name.
|
||||
Dans ce cas, l'adresse n'est pas limitée à l'un des sous-réseaux donné dans
|
||||
.B --auth-zone.
|
||||
|
||||
.PP
|
||||
Les adresses de baux DHCP, si l'adresse est située dans l'un des sous-réseaux de
|
||||
.B --auth-zone
|
||||
OU dans une plage DHCP construite. Dans le mode par défaut, où le bail
|
||||
DHCP a un nom non qualifié, et éventuellement pour un nom qualifié construit
|
||||
via
|
||||
.B --domain
|
||||
, alors le nom dans la zone faisant autorité est construit à partir du nom
|
||||
non qualifié et du nom de domaine de la zone. Cela peut on non être égal
|
||||
celui fourni par
|
||||
.B --domain.
|
||||
Si l'option
|
||||
.B --dhcp-fqdn
|
||||
est fournie, alors les noms pleinemenet qualifiés associés aux baux DHCP
|
||||
sont utilisés, dès lors qu'ils correspondent au nom de domaine associé
|
||||
à la zone.
|
||||
|
||||
|
||||
.SH CODES DE SORTIE
|
||||
.PP
|
||||
0 - Dnsmasq s'est correctement lancé en tâche de fond, ou alors s'est
|
||||
|
||||
1474
po/pt_BR.po
1474
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
810
src/auth.c
Normal file
810
src/auth.c
Normal file
@@ -0,0 +1,810 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_AUTH
|
||||
|
||||
static struct addrlist *find_subnet(struct auth_zone *zone, int flag, struct all_addr *addr_u)
|
||||
{
|
||||
struct addrlist *subnet;
|
||||
|
||||
for (subnet = zone->subnet; subnet; subnet = subnet->next)
|
||||
{
|
||||
if (!(subnet->flags & ADDRLIST_IPV6))
|
||||
{
|
||||
struct in_addr netmask, addr = addr_u->addr.addr4;
|
||||
|
||||
if (!(flag & F_IPV4))
|
||||
continue;
|
||||
|
||||
netmask.s_addr = htonl(~((1 << (32 - subnet->prefixlen)) - 1));
|
||||
|
||||
if (is_same_net(addr, subnet->addr.addr.addr4, netmask))
|
||||
return subnet;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (is_same_net6(&(addr_u->addr.addr6), &subnet->addr.addr.addr6, subnet->prefixlen))
|
||||
return subnet;
|
||||
#endif
|
||||
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int filter_zone(struct auth_zone *zone, int flag, struct all_addr *addr_u)
|
||||
{
|
||||
/* No zones specified, no filter */
|
||||
if (!zone->subnet)
|
||||
return 1;
|
||||
|
||||
return find_subnet(zone, flag, addr_u) != NULL;
|
||||
}
|
||||
|
||||
int in_zone(struct auth_zone *zone, char *name, char **cut)
|
||||
{
|
||||
size_t namelen = strlen(name);
|
||||
size_t domainlen = strlen(zone->domain);
|
||||
|
||||
if (cut)
|
||||
*cut = NULL;
|
||||
|
||||
if (namelen >= domainlen &&
|
||||
hostname_isequal(zone->domain, &name[namelen - domainlen]))
|
||||
{
|
||||
|
||||
if (namelen == domainlen)
|
||||
return 1;
|
||||
|
||||
if (name[namelen - domainlen - 1] == '.')
|
||||
{
|
||||
if (cut)
|
||||
*cut = &name[namelen - domainlen - 1];
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, int local_query)
|
||||
{
|
||||
char *name = daemon->namebuff;
|
||||
unsigned char *p, *ansp;
|
||||
int qtype, qclass;
|
||||
int nameoffset, axfroffset = 0;
|
||||
int q, anscount = 0, authcount = 0;
|
||||
struct crec *crecp;
|
||||
int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0;
|
||||
struct auth_zone *zone = NULL;
|
||||
struct addrlist *subnet = NULL;
|
||||
char *cut;
|
||||
struct mx_srv_record *rec, *move, **up;
|
||||
struct txt_record *txt;
|
||||
struct interface_name *intr;
|
||||
struct naptr *na;
|
||||
struct all_addr addr;
|
||||
struct cname *a;
|
||||
|
||||
if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
|
||||
return 0;
|
||||
|
||||
/* determine end of question section (we put answers there) */
|
||||
if (!(ansp = skip_questions(header, qlen)))
|
||||
return 0; /* bad packet */
|
||||
|
||||
/* now process each question, answers go in RRs after the question */
|
||||
p = (unsigned char *)(header+1);
|
||||
|
||||
for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
{
|
||||
unsigned short flag = 0;
|
||||
int found = 0;
|
||||
|
||||
/* save pointer to name for copying into answers */
|
||||
nameoffset = p - (unsigned char *)header;
|
||||
|
||||
/* now extract name as .-concatenated string into name */
|
||||
if (!extract_name(header, qlen, &p, name, 1, 4))
|
||||
return 0; /* bad packet */
|
||||
|
||||
GETSHORT(qtype, p);
|
||||
GETSHORT(qclass, p);
|
||||
|
||||
if (qclass != C_IN)
|
||||
{
|
||||
auth = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (qtype == T_PTR)
|
||||
{
|
||||
if (!(flag = in_arpa_name_2_addr(name, &addr)))
|
||||
continue;
|
||||
|
||||
if (!local_query)
|
||||
{
|
||||
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
||||
if ((subnet = find_subnet(zone, flag, &addr)))
|
||||
break;
|
||||
|
||||
if (!zone)
|
||||
{
|
||||
auth = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
intr = NULL;
|
||||
|
||||
if (flag == F_IPV4)
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
{
|
||||
struct addrlist *addrlist;
|
||||
|
||||
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
|
||||
if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
|
||||
break;
|
||||
|
||||
if (addrlist)
|
||||
break;
|
||||
else
|
||||
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
|
||||
intr = intr->next;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (flag == F_IPV6)
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
{
|
||||
struct addrlist *addrlist;
|
||||
|
||||
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
|
||||
if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
|
||||
break;
|
||||
|
||||
if (addrlist)
|
||||
break;
|
||||
else
|
||||
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
|
||||
intr = intr->next;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (intr)
|
||||
{
|
||||
if (in_zone(zone, intr->name, NULL))
|
||||
{
|
||||
found = 1;
|
||||
log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
T_PTR, C_IN, "d", intr->name))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((crecp = cache_find_by_addr(NULL, &addr, now, flag)))
|
||||
do {
|
||||
strcpy(name, cache_get_name(crecp));
|
||||
|
||||
if (crecp->flags & F_DHCP && !option_bool(OPT_DHCP_FQDN))
|
||||
{
|
||||
char *p = strchr(name, '.');
|
||||
if (p)
|
||||
*p = 0; /* must be bare name */
|
||||
|
||||
/* add external domain */
|
||||
strcat(name, ".");
|
||||
strcat(name, zone->domain);
|
||||
log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid));
|
||||
found = 1;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
T_PTR, C_IN, "d", name))
|
||||
anscount++;
|
||||
}
|
||||
else if (crecp->flags & (F_DHCP | F_HOSTS) && in_zone(zone, name, NULL))
|
||||
{
|
||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));
|
||||
found = 1;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
T_PTR, C_IN, "d", name))
|
||||
anscount++;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
} while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));
|
||||
|
||||
if (found)
|
||||
nxdomain = 0;
|
||||
else
|
||||
log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
cname_restart:
|
||||
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
||||
if (in_zone(zone, name, &cut))
|
||||
break;
|
||||
|
||||
if (!zone)
|
||||
{
|
||||
auth = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (rec = daemon->mxnames; rec; rec = rec->next)
|
||||
if (!rec->issrv && hostname_isequal(name, rec->name))
|
||||
{
|
||||
nxdomain = 0;
|
||||
|
||||
if (qtype == T_MX)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_MX, C_IN, "sd", rec->weight, rec->target))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next)
|
||||
if (rec->issrv && hostname_isequal(name, rec->name))
|
||||
{
|
||||
nxdomain = 0;
|
||||
|
||||
if (qtype == T_SRV)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_SRV, C_IN, "sssd",
|
||||
rec->priority, rec->weight, rec->srvport, rec->target))
|
||||
|
||||
anscount++;
|
||||
}
|
||||
|
||||
/* unlink first SRV record found */
|
||||
if (!move)
|
||||
{
|
||||
move = rec;
|
||||
*up = rec->next;
|
||||
}
|
||||
else
|
||||
up = &rec->next;
|
||||
}
|
||||
else
|
||||
up = &rec->next;
|
||||
|
||||
/* put first SRV record back at the end. */
|
||||
if (move)
|
||||
{
|
||||
*up = move;
|
||||
move->next = NULL;
|
||||
}
|
||||
|
||||
for (txt = daemon->rr; txt; txt = txt->next)
|
||||
if (hostname_isequal(name, txt->name))
|
||||
{
|
||||
nxdomain = 0;
|
||||
if (txt->class == qtype)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, txt->class, C_IN, "t", txt->len, txt->txt))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
for (txt = daemon->txt; txt; txt = txt->next)
|
||||
if (txt->class == C_IN && hostname_isequal(name, txt->name))
|
||||
{
|
||||
nxdomain = 0;
|
||||
if (qtype == T_TXT)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_TXT, C_IN, "t", txt->len, txt->txt))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
for (na = daemon->naptr; na; na = na->next)
|
||||
if (hostname_isequal(name, na->name))
|
||||
{
|
||||
nxdomain = 0;
|
||||
if (qtype == T_NAPTR)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_NAPTR, C_IN, "sszzzd",
|
||||
na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (qtype == T_A)
|
||||
flag = F_IPV4;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (qtype == T_AAAA)
|
||||
flag = F_IPV6;
|
||||
#endif
|
||||
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
if (hostname_isequal(name, intr->name))
|
||||
{
|
||||
struct addrlist *addrlist;
|
||||
|
||||
nxdomain = 0;
|
||||
|
||||
if (flag)
|
||||
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
|
||||
if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == qtype &&
|
||||
(local_query || filter_zone(zone, flag, &addrlist->addr)))
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
qtype == T_A ? "4" : "6", &addrlist->addr))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
for (a = daemon->cnames; a; a = a->next)
|
||||
if (hostname_isequal(name, a->alias) )
|
||||
{
|
||||
log_query(F_CONFIG | F_CNAME, name, NULL, NULL);
|
||||
strcpy(name, a->target);
|
||||
if (!strchr(name, '.'))
|
||||
{
|
||||
strcat(name, ".");
|
||||
strcat(name, zone->domain);
|
||||
}
|
||||
found = 1;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, &nameoffset,
|
||||
T_CNAME, C_IN, "d", name))
|
||||
anscount++;
|
||||
|
||||
goto cname_restart;
|
||||
}
|
||||
|
||||
if (!cut)
|
||||
{
|
||||
nxdomain = 0;
|
||||
|
||||
if (qtype == T_SOA)
|
||||
{
|
||||
auth = soa = 1; /* inhibits auth section */
|
||||
found = 1;
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
|
||||
}
|
||||
else if (qtype == T_AXFR)
|
||||
{
|
||||
struct iname *peers;
|
||||
|
||||
if (peer_addr->sa.sa_family == AF_INET)
|
||||
peer_addr->in.sin_port = 0;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
peer_addr->in6.sin6_port = 0;
|
||||
#endif
|
||||
|
||||
for (peers = daemon->auth_peers; peers; peers = peers->next)
|
||||
if (sockaddr_isequal(peer_addr, &peers->addr))
|
||||
break;
|
||||
|
||||
/* Refuse all AXFR unless --auth-sec-servers is set */
|
||||
if ((!peers && daemon->auth_peers) || !daemon->secondary_forward_server)
|
||||
{
|
||||
if (peer_addr->sa.sa_family == AF_INET)
|
||||
inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
#endif
|
||||
|
||||
my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
auth = 1;
|
||||
soa = 1; /* inhibits auth section */
|
||||
ns = 1; /* ensure we include NS records! */
|
||||
axfr = 1;
|
||||
found = 1;
|
||||
axfroffset = nameoffset;
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>");
|
||||
}
|
||||
else if (qtype == T_NS)
|
||||
{
|
||||
auth = 1;
|
||||
ns = 1; /* inhibits auth section */
|
||||
found = 1;
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>");
|
||||
}
|
||||
}
|
||||
|
||||
if (!option_bool(OPT_DHCP_FQDN) && cut)
|
||||
{
|
||||
*cut = 0; /* remove domain part */
|
||||
|
||||
if (!strchr(name, '.') && (crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
|
||||
{
|
||||
if (crecp->flags & F_DHCP)
|
||||
do
|
||||
{
|
||||
nxdomain = 0;
|
||||
if ((crecp->flags & flag) &&
|
||||
(local_query || filter_zone(zone, flag, &(crecp->addr.addr))))
|
||||
{
|
||||
*cut = '.'; /* restore domain part */
|
||||
log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
|
||||
*cut = 0; /* remove domain part */
|
||||
found = 1;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
qtype == T_A ? "4" : "6", &crecp->addr))
|
||||
anscount++;
|
||||
}
|
||||
} while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
|
||||
}
|
||||
|
||||
*cut = '.'; /* restore domain part */
|
||||
}
|
||||
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
|
||||
{
|
||||
if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
|
||||
do
|
||||
{
|
||||
nxdomain = 0;
|
||||
if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr.addr))))
|
||||
{
|
||||
log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
|
||||
found = 1;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
qtype == T_A ? "4" : "6", &crecp->addr))
|
||||
anscount++;
|
||||
}
|
||||
} while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
|
||||
}
|
||||
|
||||
if (!found)
|
||||
log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL);
|
||||
|
||||
}
|
||||
|
||||
/* Add auth section */
|
||||
if (auth && zone)
|
||||
{
|
||||
char *authname;
|
||||
int newoffset, offset = 0;
|
||||
|
||||
if (!subnet)
|
||||
authname = zone->domain;
|
||||
else
|
||||
{
|
||||
/* handle NS and SOA for PTR records */
|
||||
|
||||
authname = name;
|
||||
|
||||
if (!(subnet->flags & ADDRLIST_IPV6))
|
||||
{
|
||||
in_addr_t a = ntohl(subnet->addr.addr.addr4.s_addr) >> 8;
|
||||
char *p = name;
|
||||
|
||||
if (subnet->prefixlen >= 24)
|
||||
p += sprintf(p, "%d.", a & 0xff);
|
||||
a = a >> 8;
|
||||
if (subnet->prefixlen >= 16 )
|
||||
p += sprintf(p, "%d.", a & 0xff);
|
||||
a = a >> 8;
|
||||
p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
|
||||
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
char *p = name;
|
||||
int i;
|
||||
|
||||
for (i = subnet->prefixlen-1; i >= 0; i -= 4)
|
||||
{
|
||||
int dig = ((unsigned char *)&subnet->addr.addr.addr6)[i>>3];
|
||||
p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
|
||||
}
|
||||
p += sprintf(p, "ip6.arpa");
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* handle NS and SOA in auth section or for explicit queries */
|
||||
newoffset = ansp - (unsigned char *)header;
|
||||
if (((anscount == 0 && !ns) || soa) &&
|
||||
add_resource_record(header, limit, &trunc, 0, &ansp,
|
||||
daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
|
||||
authname, daemon->authserver, daemon->hostmaster,
|
||||
daemon->soa_sn, daemon->soa_refresh,
|
||||
daemon->soa_retry, daemon->soa_expiry,
|
||||
daemon->auth_ttl))
|
||||
{
|
||||
offset = newoffset;
|
||||
if (soa)
|
||||
anscount++;
|
||||
else
|
||||
authcount++;
|
||||
}
|
||||
|
||||
if (anscount != 0 || ns)
|
||||
{
|
||||
struct name_list *secondary;
|
||||
|
||||
newoffset = ansp - (unsigned char *)header;
|
||||
if (add_resource_record(header, limit, &trunc, -offset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver))
|
||||
{
|
||||
if (offset == 0)
|
||||
offset = newoffset;
|
||||
if (ns)
|
||||
anscount++;
|
||||
else
|
||||
authcount++;
|
||||
}
|
||||
|
||||
if (!subnet)
|
||||
for (secondary = daemon->secondary_forward_server; secondary; secondary = secondary->next)
|
||||
if (add_resource_record(header, limit, &trunc, offset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_NS, C_IN, "d", secondary->name))
|
||||
{
|
||||
if (ns)
|
||||
anscount++;
|
||||
else
|
||||
authcount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (axfr)
|
||||
{
|
||||
for (rec = daemon->mxnames; rec; rec = rec->next)
|
||||
if (in_zone(zone, rec->name, &cut))
|
||||
{
|
||||
if (cut)
|
||||
*cut = 0;
|
||||
|
||||
if (rec->issrv)
|
||||
{
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_SRV, C_IN, "sssd", cut ? rec->name : NULL,
|
||||
rec->priority, rec->weight, rec->srvport, rec->target))
|
||||
|
||||
anscount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_MX, C_IN, "sd", cut ? rec->name : NULL, rec->weight, rec->target))
|
||||
anscount++;
|
||||
}
|
||||
|
||||
/* restore config data */
|
||||
if (cut)
|
||||
*cut = '.';
|
||||
}
|
||||
|
||||
for (txt = daemon->rr; txt; txt = txt->next)
|
||||
if (in_zone(zone, txt->name, &cut))
|
||||
{
|
||||
if (cut)
|
||||
*cut = 0;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
|
||||
NULL, txt->class, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
|
||||
anscount++;
|
||||
|
||||
/* restore config data */
|
||||
if (cut)
|
||||
*cut = '.';
|
||||
}
|
||||
|
||||
for (txt = daemon->txt; txt; txt = txt->next)
|
||||
if (txt->class == C_IN && in_zone(zone, txt->name, &cut))
|
||||
{
|
||||
if (cut)
|
||||
*cut = 0;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_TXT, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
|
||||
anscount++;
|
||||
|
||||
/* restore config data */
|
||||
if (cut)
|
||||
*cut = '.';
|
||||
}
|
||||
|
||||
for (na = daemon->naptr; na; na = na->next)
|
||||
if (in_zone(zone, na->name, &cut))
|
||||
{
|
||||
if (cut)
|
||||
*cut = 0;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_NAPTR, C_IN, "sszzzd", cut ? na->name : NULL,
|
||||
na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
|
||||
anscount++;
|
||||
|
||||
/* restore config data */
|
||||
if (cut)
|
||||
*cut = '.';
|
||||
}
|
||||
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
if (in_zone(zone, intr->name, &cut))
|
||||
{
|
||||
struct addrlist *addrlist;
|
||||
|
||||
if (cut)
|
||||
*cut = 0;
|
||||
|
||||
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
|
||||
if (!(addrlist->flags & ADDRLIST_IPV6) &&
|
||||
(local_query || filter_zone(zone, F_IPV4, &addrlist->addr)) &&
|
||||
add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr))
|
||||
anscount++;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
|
||||
if ((addrlist->flags & ADDRLIST_IPV6) &&
|
||||
(local_query || filter_zone(zone, F_IPV6, &addrlist->addr)) &&
|
||||
add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr))
|
||||
anscount++;
|
||||
#endif
|
||||
|
||||
/* restore config data */
|
||||
if (cut)
|
||||
*cut = '.';
|
||||
}
|
||||
|
||||
for (a = daemon->cnames; a; a = a->next)
|
||||
if (in_zone(zone, a->alias, &cut))
|
||||
{
|
||||
strcpy(name, a->target);
|
||||
if (!strchr(name, '.'))
|
||||
{
|
||||
strcat(name, ".");
|
||||
strcat(name, zone->domain);
|
||||
}
|
||||
|
||||
if (cut)
|
||||
*cut = 0;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
T_CNAME, C_IN, "d", cut ? a->alias : NULL, name))
|
||||
anscount++;
|
||||
}
|
||||
|
||||
cache_enumerate(1);
|
||||
while ((crecp = cache_enumerate(0)))
|
||||
{
|
||||
if ((crecp->flags & (F_IPV4 | F_IPV6)) &&
|
||||
!(crecp->flags & (F_NEG | F_NXDOMAIN)) &&
|
||||
(crecp->flags & F_FORWARD))
|
||||
{
|
||||
if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN))
|
||||
{
|
||||
char *cache_name = cache_get_name(crecp);
|
||||
if (!strchr(cache_name, '.') &&
|
||||
(local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr))))
|
||||
{
|
||||
qtype = T_A;
|
||||
#ifdef HAVE_IPV6
|
||||
if (crecp->flags & F_IPV6)
|
||||
qtype = T_AAAA;
|
||||
#endif
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
(crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
|
||||
{
|
||||
strcpy(name, cache_get_name(crecp));
|
||||
if (in_zone(zone, name, &cut) &&
|
||||
(local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr))))
|
||||
{
|
||||
qtype = T_A;
|
||||
#ifdef HAVE_IPV6
|
||||
if (crecp->flags & F_IPV6)
|
||||
qtype = T_AAAA;
|
||||
#endif
|
||||
if (cut)
|
||||
*cut = 0;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
(crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* repeat SOA as last record */
|
||||
if (add_resource_record(header, limit, &trunc, axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
|
||||
daemon->authserver, daemon->hostmaster,
|
||||
daemon->soa_sn, daemon->soa_refresh,
|
||||
daemon->soa_retry, daemon->soa_expiry,
|
||||
daemon->auth_ttl))
|
||||
anscount++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* done all questions, set up header and return length of result */
|
||||
/* clear authoritative and truncated flags, set QR flag */
|
||||
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
|
||||
|
||||
if (local_query)
|
||||
{
|
||||
/* set RA flag */
|
||||
header->hb4 |= HB4_RA;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* clear RA flag */
|
||||
header->hb4 &= ~HB4_RA;
|
||||
}
|
||||
|
||||
/* authoritive */
|
||||
if (auth)
|
||||
header->hb3 |= HB3_AA;
|
||||
|
||||
/* truncation */
|
||||
if (trunc)
|
||||
header->hb3 |= HB3_TC;
|
||||
|
||||
if ((auth || local_query) && nxdomain)
|
||||
SET_RCODE(header, NXDOMAIN);
|
||||
else
|
||||
SET_RCODE(header, NOERROR); /* no error */
|
||||
header->ancount = htons(anscount);
|
||||
header->nscount = htons(authcount);
|
||||
header->arcount = htons(0);
|
||||
return ansp - (unsigned char *)header;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
146
src/blockdata.c
Normal file
146
src/blockdata.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
|
||||
static struct blockdata *keyblock_free;
|
||||
static unsigned int blockdata_count, blockdata_hwm, blockdata_alloced;
|
||||
|
||||
static void blockdata_expand(int n)
|
||||
{
|
||||
struct blockdata *new = whine_malloc(n * sizeof(struct blockdata));
|
||||
|
||||
if (new)
|
||||
{
|
||||
int i;
|
||||
|
||||
new[n-1].next = keyblock_free;
|
||||
keyblock_free = new;
|
||||
|
||||
for (i = 0; i < n - 1; i++)
|
||||
new[i].next = &new[i+1];
|
||||
|
||||
blockdata_alloced += n;
|
||||
}
|
||||
}
|
||||
|
||||
/* Preallocate some blocks, proportional to cachesize, to reduce heap fragmentation. */
|
||||
void blockdata_init(void)
|
||||
{
|
||||
keyblock_free = NULL;
|
||||
blockdata_alloced = 0;
|
||||
blockdata_count = 0;
|
||||
blockdata_hwm = 0;
|
||||
|
||||
blockdata_expand((daemon->cachesize * 100) / sizeof(struct blockdata));
|
||||
}
|
||||
|
||||
void blockdata_report(void)
|
||||
{
|
||||
my_syslog(LOG_INFO, _("DNSSEC memory in use %u, max %u, allocated %u"),
|
||||
blockdata_count * sizeof(struct blockdata), blockdata_hwm * sizeof(struct blockdata), blockdata_alloced * sizeof(struct blockdata));
|
||||
}
|
||||
|
||||
struct blockdata *blockdata_alloc(char *data, size_t len)
|
||||
{
|
||||
struct blockdata *block, *ret = NULL;
|
||||
struct blockdata **prev = &ret;
|
||||
size_t blen;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
if (!keyblock_free)
|
||||
blockdata_expand(50);
|
||||
|
||||
if (keyblock_free)
|
||||
{
|
||||
block = keyblock_free;
|
||||
keyblock_free = block->next;
|
||||
blockdata_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* failed to alloc, free partial chain */
|
||||
blockdata_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (blockdata_hwm < blockdata_count)
|
||||
blockdata_hwm = blockdata_count;
|
||||
|
||||
blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
|
||||
memcpy(block->key, data, blen);
|
||||
data += blen;
|
||||
len -= blen;
|
||||
*prev = block;
|
||||
prev = &block->next;
|
||||
block->next = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void blockdata_free(struct blockdata *blocks)
|
||||
{
|
||||
struct blockdata *tmp;
|
||||
|
||||
if (blocks)
|
||||
{
|
||||
for (tmp = blocks; tmp->next; tmp = tmp->next)
|
||||
blockdata_count--;
|
||||
tmp->next = keyblock_free;
|
||||
keyblock_free = blocks;
|
||||
blockdata_count--;
|
||||
}
|
||||
}
|
||||
|
||||
/* if data == NULL, return pointer to static block of sufficient size */
|
||||
void *blockdata_retrieve(struct blockdata *block, size_t len, void *data)
|
||||
{
|
||||
size_t blen;
|
||||
struct blockdata *b;
|
||||
void *new, *d;
|
||||
|
||||
static unsigned int buff_len = 0;
|
||||
static unsigned char *buff = NULL;
|
||||
|
||||
if (!data)
|
||||
{
|
||||
if (len > buff_len)
|
||||
{
|
||||
if (!(new = whine_malloc(len)))
|
||||
return NULL;
|
||||
if (buff)
|
||||
free(buff);
|
||||
buff = new;
|
||||
}
|
||||
data = buff;
|
||||
}
|
||||
|
||||
for (d = data, b = block; len > 0 && b; b = b->next)
|
||||
{
|
||||
blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
|
||||
memcpy(d, b->key, blen);
|
||||
d += blen;
|
||||
len -= blen;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
#endif
|
||||
183
src/bpf.c
183
src/bpf.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -19,12 +19,19 @@
|
||||
#if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
|
||||
#include <ifaddrs.h>
|
||||
|
||||
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <netinet/if_ether.h>
|
||||
#if defined(__FreeBSD__)
|
||||
# include <net/if_var.h>
|
||||
#endif
|
||||
#include <netinet/in_var.h>
|
||||
#ifdef HAVE_IPV6
|
||||
# include <netinet6/in6_var.h>
|
||||
#endif
|
||||
|
||||
#ifndef SA_SIZE
|
||||
#define SA_SIZE(sa) \
|
||||
@@ -33,6 +40,13 @@
|
||||
1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_BSD_NETWORK
|
||||
static int del_family = 0;
|
||||
static struct all_addr del_addr;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||
|
||||
int arp_enumerate(void *parm, int (*callback)())
|
||||
{
|
||||
int mib[6];
|
||||
@@ -83,13 +97,13 @@ int arp_enumerate(void *parm, int (*callback)())
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
#endif /* defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) */
|
||||
|
||||
|
||||
int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
{
|
||||
struct ifaddrs *head, *addrs;
|
||||
int errsav, ret = 0;
|
||||
int errsav, fd = -1, ret = 0;
|
||||
|
||||
if (family == AF_UNSPEC)
|
||||
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||
@@ -105,22 +119,35 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
if (getifaddrs(&head) == -1)
|
||||
return 0;
|
||||
|
||||
#if defined(HAVE_BSD_NETWORK) && defined(HAVE_IPV6)
|
||||
if (family == AF_INET6)
|
||||
fd = socket(PF_INET6, SOCK_DGRAM, 0);
|
||||
#endif
|
||||
|
||||
for (addrs = head; addrs; addrs = addrs->ifa_next)
|
||||
{
|
||||
if (addrs->ifa_addr->sa_family == family)
|
||||
{
|
||||
int iface_index = if_nametoindex(addrs->ifa_name);
|
||||
|
||||
if (iface_index == 0)
|
||||
if (iface_index == 0 || !addrs->ifa_addr ||
|
||||
(!addrs->ifa_netmask && family != AF_LINK))
|
||||
continue;
|
||||
|
||||
if (family == AF_INET)
|
||||
{
|
||||
struct in_addr addr, netmask, broadcast;
|
||||
addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr;
|
||||
#ifdef HAVE_BSD_NETWORK
|
||||
if (del_family == AF_INET && del_addr.addr.addr4.s_addr == addr.s_addr)
|
||||
continue;
|
||||
#endif
|
||||
netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr;
|
||||
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
|
||||
if (!((*callback)(addr, iface_index, netmask, broadcast, parm)))
|
||||
if (addrs->ifa_broadaddr)
|
||||
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
|
||||
else
|
||||
broadcast.s_addr = 0;
|
||||
if (!((*callback)(addr, iface_index, NULL, netmask, broadcast, parm)))
|
||||
goto err;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
@@ -130,11 +157,50 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
unsigned char *netmask = (unsigned char *) &((struct sockaddr_in6 *) addrs->ifa_netmask)->sin6_addr;
|
||||
int scope_id = ((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_scope_id;
|
||||
int i, j, prefix = 0;
|
||||
u32 valid = 0xffffffff, preferred = 0xffffffff;
|
||||
int flags = 0;
|
||||
#ifdef HAVE_BSD_NETWORK
|
||||
if (del_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&del_addr.addr.addr6, addr))
|
||||
continue;
|
||||
#endif
|
||||
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||
struct in6_ifreq ifr6;
|
||||
|
||||
memset(&ifr6, 0, sizeof(ifr6));
|
||||
strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
|
||||
|
||||
ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
|
||||
if (fd != -1 && ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
|
||||
{
|
||||
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
|
||||
flags |= IFACE_TENTATIVE;
|
||||
|
||||
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
|
||||
flags |= IFACE_DEPRECATED;
|
||||
|
||||
#ifdef IN6_IFF_TEMPORARY
|
||||
if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY)))
|
||||
flags |= IFACE_PERMANENT;
|
||||
#endif
|
||||
|
||||
#ifdef IN6_IFF_PRIVACY
|
||||
if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_PRIVACY)))
|
||||
flags |= IFACE_PERMANENT;
|
||||
#endif
|
||||
}
|
||||
|
||||
ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
|
||||
if (fd != -1 && ioctl(fd, SIOCGIFALIFETIME_IN6, &ifr6) != -1)
|
||||
{
|
||||
valid = ifr6.ifr_ifru.ifru_lifetime.ia6t_vltime;
|
||||
preferred = ifr6.ifr_ifru.ifru_lifetime.ia6t_pltime;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < IN6ADDRSZ; i++, prefix += 8)
|
||||
if (netmask[i] != 0xff)
|
||||
break;
|
||||
|
||||
|
||||
if (i != IN6ADDRSZ && netmask[i])
|
||||
for (j = 7; j > 0; j--, prefix++)
|
||||
if ((netmask[i] & (1 << j)) == 0)
|
||||
@@ -145,12 +211,14 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
{
|
||||
addr->s6_addr[2] = 0;
|
||||
addr->s6_addr[3] = 0;
|
||||
}
|
||||
|
||||
if (!((*callback)(addr, prefix, scope_id, iface_index, 0, parm)))
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!((*callback)(addr, prefix, scope_id, iface_index, flags,
|
||||
(int) preferred, (int)valid, parm)))
|
||||
goto err;
|
||||
}
|
||||
#endif /* HAVE_IPV6 */
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (family == AF_LINK)
|
||||
{
|
||||
@@ -168,12 +236,14 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
|
||||
err:
|
||||
errsav = errno;
|
||||
freeifaddrs(head);
|
||||
freeifaddrs(head);
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
errno = errsav;
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
#endif /* defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK) */
|
||||
|
||||
|
||||
#if defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP)
|
||||
@@ -292,6 +362,87 @@ void send_via_bpf(struct dhcp_packet *mess, size_t len,
|
||||
while (writev(daemon->dhcp_raw_fd, iov, 4) == -1 && retry_send());
|
||||
}
|
||||
|
||||
#endif /* defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP) */
|
||||
|
||||
|
||||
#ifdef HAVE_BSD_NETWORK
|
||||
|
||||
void route_init(void)
|
||||
{
|
||||
/* AF_UNSPEC: all addr families */
|
||||
daemon->routefd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
|
||||
|
||||
if (daemon->routefd == -1 || !fix_fd(daemon->routefd))
|
||||
die(_("cannot create PF_ROUTE socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
|
||||
void route_sock(time_t now)
|
||||
{
|
||||
struct if_msghdr *msg;
|
||||
int rc = recv(daemon->routefd, daemon->packet, daemon->packet_buff_sz, 0);
|
||||
|
||||
if (rc < 4)
|
||||
return;
|
||||
|
||||
msg = (struct if_msghdr *)daemon->packet;
|
||||
|
||||
if (rc < msg->ifm_msglen)
|
||||
return;
|
||||
|
||||
if (msg->ifm_version != RTM_VERSION)
|
||||
{
|
||||
static int warned = 0;
|
||||
if (!warned)
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("Unknown protocol version from route socket"));
|
||||
warned = 1;
|
||||
}
|
||||
}
|
||||
else if (msg->ifm_type == RTM_NEWADDR)
|
||||
{
|
||||
del_family = 0;
|
||||
newaddress(now);
|
||||
}
|
||||
else if (msg->ifm_type == RTM_DELADDR)
|
||||
{
|
||||
/* There's a race in the kernel, such that if we run iface_enumerate() immediately
|
||||
we get a DELADDR event, the deleted address still appears. Here we store the deleted address
|
||||
in a static variable, and omit it from the set returned by iface_enumerate() */
|
||||
int mask = ((struct ifa_msghdr *)msg)->ifam_addrs;
|
||||
int maskvec[] = { RTA_DST, RTA_GATEWAY, RTA_NETMASK, RTA_GENMASK,
|
||||
RTA_IFP, RTA_IFA, RTA_AUTHOR, RTA_BRD };
|
||||
int of;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0, of = sizeof(struct ifa_msghdr); of < rc && i < sizeof(maskvec)/sizeof(maskvec[0]); i++)
|
||||
if (mask & maskvec[i])
|
||||
{
|
||||
struct sockaddr *sa = (struct sockaddr *)((char *)msg + of);
|
||||
size_t diff = (sa->sa_len != 0) ? sa->sa_len : sizeof(long);
|
||||
|
||||
if (maskvec[i] == RTA_IFA)
|
||||
{
|
||||
del_family = sa->sa_family;
|
||||
if (del_family == AF_INET)
|
||||
del_addr.addr.addr4 = ((struct sockaddr_in *)sa)->sin_addr;
|
||||
#ifdef HAVE_IPV6
|
||||
else if (del_family == AF_INET6)
|
||||
del_addr.addr.addr6 = ((struct sockaddr_in6 *)sa)->sin6_addr;
|
||||
#endif
|
||||
else
|
||||
del_family = 0;
|
||||
}
|
||||
|
||||
of += diff;
|
||||
/* round up as needed */
|
||||
if (diff & (sizeof(long) - 1))
|
||||
of += sizeof(long) - (diff & (sizeof(long) - 1));
|
||||
}
|
||||
|
||||
newaddress(now);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_BSD_NETWORK */
|
||||
|
||||
|
||||
|
||||
630
src/cache.c
630
src/cache.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -24,10 +24,6 @@ static struct crec *new_chain = NULL;
|
||||
static int cache_inserted = 0, cache_live_freed = 0, insert_error;
|
||||
static union bigname *big_free = NULL;
|
||||
static int bignames_left, hash_size;
|
||||
static int uid = 0;
|
||||
#ifdef HAVE_DNSSEC
|
||||
static struct keydata *keyblock_free = NULL;
|
||||
#endif
|
||||
|
||||
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
|
||||
static const struct {
|
||||
@@ -56,7 +52,11 @@ static const struct {
|
||||
{ 38, "A6" },
|
||||
{ 39, "DNAME" },
|
||||
{ 41, "OPT" },
|
||||
{ 43, "DS" },
|
||||
{ 46, "RRSIG" },
|
||||
{ 47, "NSEC" },
|
||||
{ 48, "DNSKEY" },
|
||||
{ 50, "NSEC3" },
|
||||
{ 249, "TKEY" },
|
||||
{ 250, "TSIG" },
|
||||
{ 251, "IXFR" },
|
||||
@@ -72,11 +72,24 @@ static void cache_link(struct crec *crecp);
|
||||
static void rehash(int size);
|
||||
static void cache_hash(struct crec *crecp);
|
||||
|
||||
static unsigned int next_uid(void)
|
||||
{
|
||||
static unsigned int uid = 0;
|
||||
|
||||
uid++;
|
||||
|
||||
/* uid == 0 used to indicate CNAME to interface name. */
|
||||
if (uid == SRC_INTERFACE)
|
||||
uid++;
|
||||
|
||||
return uid;
|
||||
}
|
||||
|
||||
void cache_init(void)
|
||||
{
|
||||
struct crec *crecp;
|
||||
int i;
|
||||
|
||||
|
||||
bignames_left = daemon->cachesize/10;
|
||||
|
||||
if (daemon->cachesize > 0)
|
||||
@@ -87,7 +100,7 @@ void cache_init(void)
|
||||
{
|
||||
cache_link(crecp);
|
||||
crecp->flags = 0;
|
||||
crecp->uid = uid++;
|
||||
crecp->uid = next_uid();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,13 +184,28 @@ static void cache_hash(struct crec *crecp)
|
||||
crecp->hash_next = *up;
|
||||
*up = crecp;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
static void cache_blockdata_free(struct crec *crecp)
|
||||
{
|
||||
if (crecp->flags & F_DNSKEY)
|
||||
{
|
||||
if (crecp->flags & F_DS)
|
||||
blockdata_free(crecp->addr.sig.keydata);
|
||||
else
|
||||
blockdata_free(crecp->addr.key.keydata);
|
||||
}
|
||||
else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
|
||||
blockdata_free(crecp->addr.ds.keydata);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void cache_free(struct crec *crecp)
|
||||
{
|
||||
crecp->flags &= ~F_FORWARD;
|
||||
crecp->flags &= ~F_REVERSE;
|
||||
crecp->uid = uid++; /* invalidate CNAMES pointing to this. */
|
||||
|
||||
crecp->uid = next_uid(); /* invalidate CNAMES pointing to this. */
|
||||
|
||||
if (cache_tail)
|
||||
cache_tail->next = crecp;
|
||||
else
|
||||
@@ -193,9 +221,9 @@ static void cache_free(struct crec *crecp)
|
||||
big_free = crecp->name.bname;
|
||||
crecp->flags &= ~F_BIGNAME;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
else if (crecp->flags & (F_DNSKEY | F_DS))
|
||||
keydata_free(crecp->addr.key.keydata);
|
||||
cache_blockdata_free(crecp);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -235,16 +263,49 @@ char *cache_get_name(struct crec *crecp)
|
||||
return crecp->name.sname;
|
||||
}
|
||||
|
||||
char *cache_get_cname_target(struct crec *crecp)
|
||||
{
|
||||
if (crecp->addr.cname.uid != SRC_INTERFACE)
|
||||
return cache_get_name(crecp->addr.cname.target.cache);
|
||||
|
||||
return crecp->addr.cname.target.int_name->name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct crec *cache_enumerate(int init)
|
||||
{
|
||||
static int bucket;
|
||||
static struct crec *cache;
|
||||
|
||||
if (init)
|
||||
{
|
||||
bucket = 0;
|
||||
cache = NULL;
|
||||
}
|
||||
else if (cache && cache->hash_next)
|
||||
cache = cache->hash_next;
|
||||
else
|
||||
{
|
||||
cache = NULL;
|
||||
while (bucket < hash_size)
|
||||
if ((cache = hash_table[bucket++]))
|
||||
break;
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
static int is_outdated_cname_pointer(struct crec *crecp)
|
||||
{
|
||||
if (!(crecp->flags & F_CNAME))
|
||||
if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == SRC_INTERFACE)
|
||||
return 0;
|
||||
|
||||
/* NB. record may be reused as DS or DNSKEY, where uid is
|
||||
overloaded for something completely different */
|
||||
if (crecp->addr.cname.cache &&
|
||||
(crecp->addr.cname.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) &&
|
||||
crecp->addr.cname.uid == crecp->addr.cname.cache->uid)
|
||||
if (crecp->addr.cname.target.cache &&
|
||||
(crecp->addr.cname.target.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) &&
|
||||
crecp->addr.cname.uid == crecp->addr.cname.target.cache->uid)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@@ -281,27 +342,52 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
|
||||
if (flags & F_FORWARD)
|
||||
{
|
||||
for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
|
||||
if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
|
||||
{
|
||||
*up = crecp->hash_next;
|
||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
{
|
||||
cache_unlink(crecp);
|
||||
cache_free(crecp);
|
||||
}
|
||||
}
|
||||
else if ((crecp->flags & F_FORWARD) &&
|
||||
((flags & crecp->flags & F_TYPE) || ((crecp->flags | flags) & F_CNAME)) &&
|
||||
hostname_isequal(cache_get_name(crecp), name))
|
||||
{
|
||||
if (crecp->flags & (F_HOSTS | F_DHCP))
|
||||
return 0;
|
||||
*up = crecp->hash_next;
|
||||
cache_unlink(crecp);
|
||||
cache_free(crecp);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
|
||||
{
|
||||
*up = crecp->hash_next;
|
||||
if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
|
||||
{
|
||||
cache_unlink(crecp);
|
||||
cache_free(crecp);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
|
||||
{
|
||||
/* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
|
||||
if ((flags & crecp->flags & (F_IPV4 | F_IPV6)) ||
|
||||
(((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
|
||||
{
|
||||
if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
|
||||
return 0;
|
||||
*up = crecp->hash_next;
|
||||
cache_unlink(crecp);
|
||||
cache_free(crecp);
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* Deletion has to be class-sensitive for DS, DNSKEY, RRSIG, also
|
||||
type-covered sensitive for RRSIG */
|
||||
if ((flags & (F_DNSKEY | F_DS)) &&
|
||||
(flags & (F_DNSKEY | F_DS)) == (crecp->flags & (F_DNSKEY | F_DS)) &&
|
||||
crecp->uid == addr->addr.dnssec.class &&
|
||||
(!((flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY)) ||
|
||||
crecp->addr.sig.type_covered == addr->addr.dnssec.type))
|
||||
{
|
||||
if (crecp->flags & F_CONFIG)
|
||||
return 0;
|
||||
*up = crecp->hash_next;
|
||||
cache_unlink(crecp);
|
||||
cache_free(crecp);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
up = &crecp->hash_next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -318,13 +404,13 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
|
||||
if (is_expired(now, crecp))
|
||||
{
|
||||
*up = crecp->hash_next;
|
||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
|
||||
{
|
||||
cache_unlink(crecp);
|
||||
cache_free(crecp);
|
||||
}
|
||||
}
|
||||
else if (!(crecp->flags & (F_HOSTS | F_DHCP)) &&
|
||||
else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
|
||||
(flags & crecp->flags & F_REVERSE) &&
|
||||
(flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
|
||||
memcmp(&crecp->addr.addr, addr, addrlen) == 0)
|
||||
@@ -371,19 +457,21 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
int freed_all = flags & F_REVERSE;
|
||||
int free_avail = 0;
|
||||
|
||||
if(daemon->max_cache_ttl < ttl)
|
||||
ttl = daemon->max_cache_ttl;
|
||||
|
||||
/* Don't log keys */
|
||||
if (flags & (F_IPV4 | F_IPV6))
|
||||
log_query(flags | F_UPSTREAM, name, addr, NULL);
|
||||
/* Don't log DNSSEC records here, done elsewhere */
|
||||
if (flags & (F_IPV4 | F_IPV6 | F_CNAME))
|
||||
{
|
||||
log_query(flags | F_UPSTREAM, name, addr, NULL);
|
||||
/* Don;t mess with TTL for DNSSEC records. */
|
||||
if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
|
||||
ttl = daemon->max_cache_ttl;
|
||||
}
|
||||
|
||||
/* if previous insertion failed give up now. */
|
||||
if (insert_error)
|
||||
return NULL;
|
||||
|
||||
|
||||
/* First remove any expired entries and entries for the name/address we
|
||||
are currently inserting. Fail is we attempt to delete a name from
|
||||
are currently inserting. Fail if we attempt to delete a name from
|
||||
/etc/hosts or DHCP. */
|
||||
if (!cache_scan_free(name, addr, now, flags))
|
||||
{
|
||||
@@ -411,14 +499,32 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
insert. Once in this state, all inserts will probably fail. */
|
||||
if (free_avail)
|
||||
{
|
||||
static int warned = 0;
|
||||
if (!warned)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("Internal error in cache."));
|
||||
warned = 1;
|
||||
}
|
||||
insert_error = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (freed_all)
|
||||
{
|
||||
struct all_addr free_addr = new->addr.addr;;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* For DNSSEC records, addr holds class and type_covered for RRSIG */
|
||||
if (new->flags & (F_DS | F_DNSKEY))
|
||||
{
|
||||
free_addr.addr.dnssec.class = new->uid;
|
||||
if ((new->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
|
||||
free_addr.addr.dnssec.type = new->addr.sig.type_covered;
|
||||
}
|
||||
#endif
|
||||
|
||||
free_avail = 1; /* Must be free space now. */
|
||||
cache_scan_free(cache_get_name(new), &new->addr.addr, now, new->flags);
|
||||
cache_scan_free(cache_get_name(new), &free_addr, now, new->flags);
|
||||
cache_live_freed++;
|
||||
}
|
||||
else
|
||||
@@ -430,7 +536,7 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
}
|
||||
|
||||
/* Check if we need to and can allocate extra memory for a long name.
|
||||
If that fails, give up now. */
|
||||
If that fails, give up now, always succeed for DNSSEC records. */
|
||||
if (name && (strlen(name) > SMALLDNAME-1))
|
||||
{
|
||||
if (big_free)
|
||||
@@ -438,13 +544,13 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
big_name = big_free;
|
||||
big_free = big_free->next;
|
||||
}
|
||||
else if (!bignames_left ||
|
||||
else if ((bignames_left == 0 && !(flags & (F_DS | F_DNSKEY))) ||
|
||||
!(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
|
||||
{
|
||||
insert_error = 1;
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
else if (bignames_left != 0)
|
||||
bignames_left--;
|
||||
|
||||
}
|
||||
@@ -467,7 +573,14 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
*cache_get_name(new) = 0;
|
||||
|
||||
if (addr)
|
||||
new->addr.addr = *addr;
|
||||
{
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (flags & (F_DS | F_DNSKEY))
|
||||
new->uid = addr->addr.dnssec.class;
|
||||
else
|
||||
#endif
|
||||
new->addr.addr = *addr;
|
||||
}
|
||||
|
||||
new->ttd = now + (time_t)ttl;
|
||||
new->next = new_chain;
|
||||
@@ -499,10 +612,13 @@ void cache_end_insert(void)
|
||||
new_chain = NULL;
|
||||
}
|
||||
|
||||
struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned short prot)
|
||||
struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot)
|
||||
{
|
||||
struct crec *ans;
|
||||
int no_rr = prot & F_NO_RR;
|
||||
|
||||
prot &= ~F_NO_RR;
|
||||
|
||||
if (crecp) /* iterating */
|
||||
ans = crecp->next;
|
||||
else
|
||||
@@ -519,10 +635,13 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
|
||||
if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
|
||||
{
|
||||
if ((crecp->flags & F_FORWARD) &&
|
||||
#ifdef HAVE_DNSSEC
|
||||
((crecp->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) &&
|
||||
#endif
|
||||
(crecp->flags & prot) &&
|
||||
hostname_isequal(cache_get_name(crecp), name))
|
||||
{
|
||||
if (crecp->flags & (F_HOSTS | F_DHCP))
|
||||
if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
|
||||
{
|
||||
*chainp = crecp;
|
||||
chainp = &crecp->next;
|
||||
@@ -547,7 +666,7 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!insert)
|
||||
if (!insert && !no_rr)
|
||||
{
|
||||
insert = up;
|
||||
ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
|
||||
@@ -563,7 +682,7 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
|
||||
{
|
||||
/* expired entry, free it */
|
||||
*up = crecp->hash_next;
|
||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
|
||||
{
|
||||
cache_unlink(crecp);
|
||||
cache_free(crecp);
|
||||
@@ -576,7 +695,10 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
|
||||
|
||||
if (ans &&
|
||||
(ans->flags & F_FORWARD) &&
|
||||
(ans->flags & prot) &&
|
||||
#ifdef HAVE_DNSSEC
|
||||
((ans->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) &&
|
||||
#endif
|
||||
(ans->flags & prot) &&
|
||||
hostname_isequal(cache_get_name(ans), name))
|
||||
return ans;
|
||||
|
||||
@@ -584,7 +706,7 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
|
||||
}
|
||||
|
||||
struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
|
||||
time_t now, unsigned short prot)
|
||||
time_t now, unsigned int prot)
|
||||
{
|
||||
struct crec *ans;
|
||||
#ifdef HAVE_IPV6
|
||||
@@ -613,7 +735,7 @@ struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
|
||||
if ((crecp->flags & prot) &&
|
||||
memcmp(&crecp->addr.addr, addr, addrlen) == 0)
|
||||
{
|
||||
if (crecp->flags & (F_HOSTS | F_DHCP))
|
||||
if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
|
||||
{
|
||||
*chainp = crecp;
|
||||
chainp = &crecp->next;
|
||||
@@ -629,7 +751,7 @@ struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
|
||||
else
|
||||
{
|
||||
*up = crecp->hash_next;
|
||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
|
||||
{
|
||||
cache_unlink(crecp);
|
||||
cache_free(crecp);
|
||||
@@ -657,17 +779,18 @@ static void add_hosts_cname(struct crec *target)
|
||||
if (hostname_isequal(cache_get_name(target), a->target) &&
|
||||
(crec = whine_malloc(sizeof(struct crec))))
|
||||
{
|
||||
crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_HOSTS | F_CNAME;
|
||||
crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME;
|
||||
crec->name.namep = a->alias;
|
||||
crec->addr.cname.cache = target;
|
||||
crec->addr.cname.target.cache = target;
|
||||
crec->addr.cname.uid = target->uid;
|
||||
crec->uid = next_uid();
|
||||
cache_hash(crec);
|
||||
add_hosts_cname(crec); /* handle chains */
|
||||
}
|
||||
}
|
||||
|
||||
static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
|
||||
int index, struct crec **rhash, int hashsz)
|
||||
unsigned int index, struct crec **rhash, int hashsz)
|
||||
{
|
||||
struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
|
||||
int i, nameexists = 0;
|
||||
@@ -771,7 +894,7 @@ static int gettok(FILE *f, char *token)
|
||||
}
|
||||
}
|
||||
|
||||
static int read_hostsfile(char *filename, int index, int cache_size, struct crec **rhash, int hashsz)
|
||||
static int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
|
||||
{
|
||||
FILE *f = fopen(filename, "r");
|
||||
char *token = daemon->namebuff, *domain_suffix = NULL;
|
||||
@@ -878,14 +1001,22 @@ void cache_reload(void)
|
||||
struct hostsfile *ah;
|
||||
struct host_record *hr;
|
||||
struct name_list *nl;
|
||||
struct cname *a;
|
||||
struct interface_name *intr;
|
||||
#ifdef HAVE_DNSSEC
|
||||
struct ds_config *ds;
|
||||
#endif
|
||||
|
||||
cache_inserted = cache_live_freed = 0;
|
||||
|
||||
for (i=0; i<hash_size; i++)
|
||||
for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
|
||||
{
|
||||
#ifdef HAVE_DNSSEC
|
||||
cache_blockdata_free(cache);
|
||||
#endif
|
||||
tmp = cache->hash_next;
|
||||
if (cache->flags & F_HOSTS)
|
||||
if (cache->flags & (F_HOSTS | F_CONFIG))
|
||||
{
|
||||
*up = cache->hash_next;
|
||||
free(cache);
|
||||
@@ -904,6 +1035,37 @@ void cache_reload(void)
|
||||
up = &cache->hash_next;
|
||||
}
|
||||
|
||||
/* Add CNAMEs to interface_names to the cache */
|
||||
for (a = daemon->cnames; a; a = a->next)
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
if (hostname_isequal(a->target, intr->name) &&
|
||||
((cache = whine_malloc(sizeof(struct crec)))))
|
||||
{
|
||||
cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
|
||||
cache->name.namep = a->alias;
|
||||
cache->addr.cname.target.int_name = intr;
|
||||
cache->addr.cname.uid = SRC_INTERFACE;
|
||||
cache->uid = next_uid();
|
||||
cache_hash(cache);
|
||||
add_hosts_cname(cache); /* handle chains */
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
for (ds = daemon->ds; ds; ds = ds->next)
|
||||
if ((cache = whine_malloc(sizeof(struct crec))) &&
|
||||
(cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
|
||||
{
|
||||
cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
|
||||
cache->name.namep = ds->name;
|
||||
cache->addr.ds.keylen = ds->digestlen;
|
||||
cache->addr.ds.algo = ds->algo;
|
||||
cache->addr.ds.keytag = ds->keytag;
|
||||
cache->addr.ds.digest = ds->digest_type;
|
||||
cache->uid = ds->class;
|
||||
cache_hash(cache);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* borrow the packet buffer for a temporary by-address hash */
|
||||
memset(daemon->packet, 0, daemon->packet_buff_sz);
|
||||
revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
|
||||
@@ -919,7 +1081,7 @@ void cache_reload(void)
|
||||
{
|
||||
cache->name.namep = nl->name;
|
||||
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
|
||||
add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
|
||||
add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
|
||||
@@ -927,7 +1089,7 @@ void cache_reload(void)
|
||||
{
|
||||
cache->name.namep = nl->name;
|
||||
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
|
||||
add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
|
||||
add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -940,7 +1102,7 @@ void cache_reload(void)
|
||||
}
|
||||
|
||||
if (!option_bool(OPT_NO_HOSTS))
|
||||
total_size = read_hostsfile(HOSTSFILE, 0, total_size, (struct crec **)daemon->packet, revhashsz);
|
||||
total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
|
||||
|
||||
daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
|
||||
for (ah = daemon->addn_hosts; ah; ah = ah->next)
|
||||
@@ -948,38 +1110,6 @@ void cache_reload(void)
|
||||
total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
|
||||
}
|
||||
|
||||
char *get_domain(struct in_addr addr)
|
||||
{
|
||||
struct cond_domain *c;
|
||||
|
||||
for (c = daemon->cond_domain; c; c = c->next)
|
||||
if (!c->is6 &&
|
||||
ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
|
||||
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
|
||||
return c->domain;
|
||||
|
||||
return daemon->domain_suffix;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
char *get_domain6(struct in6_addr *addr)
|
||||
{
|
||||
struct cond_domain *c;
|
||||
|
||||
u64 addrpart = addr6part(addr);
|
||||
|
||||
for (c = daemon->cond_domain; c; c = c->next)
|
||||
if (c->is6 &&
|
||||
is_same_net6(addr, &c->start6, 64) &&
|
||||
addrpart >= addr6part(&c->start6) &&
|
||||
addrpart <= addr6part(&c->end6))
|
||||
return c->domain;
|
||||
|
||||
return daemon->domain_suffix;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
struct in_addr a_record_from_hosts(char *name, time_t now)
|
||||
{
|
||||
@@ -1028,14 +1158,15 @@ static void add_dhcp_cname(struct crec *target, time_t ttd)
|
||||
|
||||
if (aliasc)
|
||||
{
|
||||
aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME;
|
||||
aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME | F_CONFIG;
|
||||
if (ttd == 0)
|
||||
aliasc->flags |= F_IMMORTAL;
|
||||
else
|
||||
aliasc->ttd = ttd;
|
||||
aliasc->name.namep = a->alias;
|
||||
aliasc->addr.cname.cache = target;
|
||||
aliasc->addr.cname.target.cache = target;
|
||||
aliasc->addr.cname.uid = target->uid;
|
||||
aliasc->uid = next_uid();
|
||||
cache_hash(aliasc);
|
||||
add_dhcp_cname(aliasc, ttd);
|
||||
}
|
||||
@@ -1063,7 +1194,7 @@ void cache_add_dhcp_entry(char *host_name, int prot,
|
||||
while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
|
||||
{
|
||||
/* check all addresses associated with name */
|
||||
if (crec->flags & F_HOSTS)
|
||||
if (crec->flags & (F_HOSTS | F_CONFIG))
|
||||
{
|
||||
if (crec->flags & F_CNAME)
|
||||
my_syslog(MS_DHCP | LOG_WARNING,
|
||||
@@ -1123,7 +1254,7 @@ void cache_add_dhcp_entry(char *host_name, int prot,
|
||||
crec->ttd = ttd;
|
||||
crec->addr.addr = *host_address;
|
||||
crec->name.namep = host_name;
|
||||
crec->uid = uid++;
|
||||
crec->uid = next_uid();
|
||||
cache_hash(crec);
|
||||
|
||||
add_dhcp_cname(crec, ttd);
|
||||
@@ -1131,16 +1262,118 @@ void cache_add_dhcp_entry(char *host_name, int prot,
|
||||
}
|
||||
#endif
|
||||
|
||||
int cache_make_stat(struct txt_record *t)
|
||||
{
|
||||
static char *buff = NULL;
|
||||
static int bufflen = 60;
|
||||
int len;
|
||||
struct server *serv, *serv1;
|
||||
char *p;
|
||||
|
||||
if (!buff && !(buff = whine_malloc(60)))
|
||||
return 0;
|
||||
|
||||
p = buff;
|
||||
|
||||
switch (t->stat)
|
||||
{
|
||||
case TXT_STAT_CACHESIZE:
|
||||
sprintf(buff+1, "%d", daemon->cachesize);
|
||||
break;
|
||||
|
||||
case TXT_STAT_INSERTS:
|
||||
sprintf(buff+1, "%d", cache_inserted);
|
||||
break;
|
||||
|
||||
case TXT_STAT_EVICTIONS:
|
||||
sprintf(buff+1, "%d", cache_live_freed);
|
||||
break;
|
||||
|
||||
case TXT_STAT_MISSES:
|
||||
sprintf(buff+1, "%u", daemon->queries_forwarded);
|
||||
break;
|
||||
|
||||
case TXT_STAT_HITS:
|
||||
sprintf(buff+1, "%u", daemon->local_answer);
|
||||
break;
|
||||
|
||||
#ifdef HAVE_AUTH
|
||||
case TXT_STAT_AUTH:
|
||||
sprintf(buff+1, "%u", daemon->auth_answer);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case TXT_STAT_SERVERS:
|
||||
/* sum counts from different records for same server */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
serv->flags &= ~SERV_COUNTED;
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (!(serv->flags &
|
||||
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
|
||||
{
|
||||
char *new, *lenp;
|
||||
int port, newlen, bytes_avail, bytes_needed;
|
||||
unsigned int queries = 0, failed_queries = 0;
|
||||
for (serv1 = serv; serv1; serv1 = serv1->next)
|
||||
if (!(serv1->flags &
|
||||
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
|
||||
sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||
{
|
||||
serv1->flags |= SERV_COUNTED;
|
||||
queries += serv1->queries;
|
||||
failed_queries += serv1->failed_queries;
|
||||
}
|
||||
port = prettyprint_addr(&serv->addr, daemon->addrbuff);
|
||||
lenp = p++; /* length */
|
||||
bytes_avail = (p - buff) + bufflen;
|
||||
bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
|
||||
if (bytes_needed >= bytes_avail)
|
||||
{
|
||||
/* expand buffer if necessary */
|
||||
newlen = bytes_needed + 1 + bufflen - bytes_avail;
|
||||
if (!(new = whine_malloc(newlen)))
|
||||
return 0;
|
||||
memcpy(new, buff, bufflen);
|
||||
free(buff);
|
||||
p = new + (p - buff);
|
||||
lenp = p - 1;
|
||||
buff = new;
|
||||
bufflen = newlen;
|
||||
bytes_avail = (p - buff) + bufflen;
|
||||
bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
|
||||
}
|
||||
*lenp = bytes_needed;
|
||||
p += bytes_needed;
|
||||
}
|
||||
t->txt = (unsigned char *)buff;
|
||||
t->len = p - buff;
|
||||
return 1;
|
||||
}
|
||||
|
||||
len = strlen(buff+1);
|
||||
t->txt = (unsigned char *)buff;
|
||||
t->len = len + 1;
|
||||
*buff = len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dump_cache(time_t now)
|
||||
{
|
||||
struct server *serv, *serv1;
|
||||
char *t = "";
|
||||
|
||||
my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
|
||||
my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
|
||||
daemon->cachesize, cache_live_freed, cache_inserted);
|
||||
my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
|
||||
daemon->queries_forwarded, daemon->local_answer);
|
||||
#ifdef HAVE_AUTH
|
||||
my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->auth_answer);
|
||||
#endif
|
||||
#ifdef HAVE_DNSSEC
|
||||
blockdata_report();
|
||||
#endif
|
||||
|
||||
/* sum counts from different records for same server */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
@@ -1169,35 +1402,34 @@ void dump_cache(time_t now)
|
||||
{
|
||||
struct crec *cache ;
|
||||
int i;
|
||||
my_syslog(LOG_INFO, "Host Address Flags Expires");
|
||||
my_syslog(LOG_INFO, "Host Address Flags Expires");
|
||||
|
||||
for (i=0; i<hash_size; i++)
|
||||
for (cache = hash_table[i]; cache; cache = cache->hash_next)
|
||||
{
|
||||
char *a, *p = daemon->namebuff;
|
||||
p += sprintf(p, "%-40.40s ", cache_get_name(cache));
|
||||
if ((cache->flags & F_NEG) && (cache->flags & F_FORWARD))
|
||||
a = "";
|
||||
else if (cache->flags & F_CNAME)
|
||||
{
|
||||
a = "";
|
||||
if (!is_outdated_cname_pointer(cache))
|
||||
a = cache_get_name(cache->addr.cname.cache);
|
||||
}
|
||||
char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache);
|
||||
*a = 0;
|
||||
if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
|
||||
n = "<Root>";
|
||||
p += sprintf(p, "%-40.40s ", n);
|
||||
if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
|
||||
a = cache_get_cname_target(cache);
|
||||
#ifdef HAVE_DNSSEC
|
||||
else if (cache->flags & F_DNSKEY)
|
||||
{
|
||||
a = daemon->addrbuff;
|
||||
sprintf(a, "%3u %u", cache->addr.key.algo, cache->uid);
|
||||
}
|
||||
else if (cache->flags & F_DS)
|
||||
{
|
||||
a = daemon->addrbuff;
|
||||
sprintf(a, "%5u %3u %3u %u", cache->addr.key.flags_or_keyid,
|
||||
cache->addr.key.algo, cache->addr.key.digest, cache->uid);
|
||||
if (cache->flags & F_DNSKEY)
|
||||
/* RRSIG */
|
||||
sprintf(a, "%5u %3u %s", cache->addr.sig.keytag,
|
||||
cache->addr.sig.algo, querystr("", cache->addr.sig.type_covered));
|
||||
else if (!(cache->flags & F_NEG))
|
||||
sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
|
||||
cache->addr.ds.algo, cache->addr.ds.digest);
|
||||
}
|
||||
else if (cache->flags & F_DNSKEY)
|
||||
sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
|
||||
cache->addr.key.algo, cache->addr.key.flags);
|
||||
#endif
|
||||
else
|
||||
else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
|
||||
{
|
||||
a = daemon->addrbuff;
|
||||
if (cache->flags & F_IPV4)
|
||||
@@ -1208,12 +1440,21 @@ void dump_cache(time_t now)
|
||||
#endif
|
||||
}
|
||||
|
||||
p += sprintf(p, "%-30.30s %s%s%s%s%s%s%s%s%s%s%s%s%s ", a,
|
||||
cache->flags & F_IPV4 ? "4" : "",
|
||||
cache->flags & F_IPV6 ? "6" : "",
|
||||
cache->flags & F_DNSKEY ? "K" : "",
|
||||
cache->flags & F_DS ? "S" : "",
|
||||
cache->flags & F_CNAME ? "C" : "",
|
||||
if (cache->flags & F_IPV4)
|
||||
t = "4";
|
||||
else if (cache->flags & F_IPV6)
|
||||
t = "6";
|
||||
else if (cache->flags & F_CNAME)
|
||||
t = "C";
|
||||
#ifdef HAVE_DNSSEC
|
||||
else if ((cache->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
|
||||
t = "G"; /* DNSKEY and DS set -> RRISG */
|
||||
else if (cache->flags & F_DS)
|
||||
t = "S";
|
||||
else if (cache->flags & F_DNSKEY)
|
||||
t = "K";
|
||||
#endif
|
||||
p += sprintf(p, "%-30.30s %s%s%s%s%s%s%s%s%s ", a, t,
|
||||
cache->flags & F_FORWARD ? "F" : " ",
|
||||
cache->flags & F_REVERSE ? "R" : " ",
|
||||
cache->flags & F_IMMORTAL ? "I" : " ",
|
||||
@@ -1234,11 +1475,13 @@ void dump_cache(time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
char *record_source(int index)
|
||||
char *record_source(unsigned int index)
|
||||
{
|
||||
struct hostsfile *ah;
|
||||
|
||||
if (index == 0)
|
||||
if (index == SRC_CONFIG)
|
||||
return "config";
|
||||
else if (index == SRC_HOSTS)
|
||||
return HOSTSFILE;
|
||||
|
||||
for (ah = daemon->addn_hosts; ah; ah = ah->next)
|
||||
@@ -1248,14 +1491,45 @@ char *record_source(int index)
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
void querystr(char *str, unsigned short type)
|
||||
char *querystr(char *desc, unsigned short type)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
sprintf(str, "query[type=%d]", type);
|
||||
int len = 10; /* strlen("type=xxxxx") */
|
||||
const char *types = NULL;
|
||||
static char *buff = NULL;
|
||||
static int bufflen = 0;
|
||||
|
||||
for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
|
||||
if (typestr[i].type == type)
|
||||
sprintf(str,"query[%s]", typestr[i].name);
|
||||
{
|
||||
types = typestr[i].name;
|
||||
len = strlen(types);
|
||||
break;
|
||||
}
|
||||
|
||||
len += 3; /* braces, terminator */
|
||||
len += strlen(desc);
|
||||
|
||||
if (!buff || bufflen < len)
|
||||
{
|
||||
if (buff)
|
||||
free(buff);
|
||||
else if (len < 20)
|
||||
len = 20;
|
||||
|
||||
buff = whine_malloc(len);
|
||||
bufflen = len;
|
||||
}
|
||||
|
||||
if (buff)
|
||||
{
|
||||
if (types)
|
||||
sprintf(buff, "%s[%s]", desc, types);
|
||||
else
|
||||
sprintf(buff, "%s[type=%d]", desc, type);
|
||||
}
|
||||
|
||||
return buff ? buff : "";
|
||||
}
|
||||
|
||||
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
||||
@@ -1268,13 +1542,20 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
||||
|
||||
if (addr)
|
||||
{
|
||||
if (flags & F_KEYTAG)
|
||||
sprintf(daemon->addrbuff, arg, addr->addr.keytag);
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
||||
addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
||||
addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
#else
|
||||
strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
|
||||
strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
dest = arg;
|
||||
|
||||
if (flags & F_REVERSE)
|
||||
{
|
||||
@@ -1285,14 +1566,7 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
||||
if (flags & F_NEG)
|
||||
{
|
||||
if (flags & F_NXDOMAIN)
|
||||
{
|
||||
if (flags & F_IPV4)
|
||||
dest = "NXDOMAIN-IPv4";
|
||||
else if (flags & F_IPV6)
|
||||
dest = "NXDOMAIN-IPv6";
|
||||
else
|
||||
dest = "NXDOMAIN";
|
||||
}
|
||||
dest = "NXDOMAIN";
|
||||
else
|
||||
{
|
||||
if (flags & F_IPV4)
|
||||
@@ -1316,6 +1590,10 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
||||
source = arg;
|
||||
else if (flags & F_UPSTREAM)
|
||||
source = "reply";
|
||||
else if (flags & F_SECSTAT)
|
||||
source = "validation";
|
||||
else if (flags & F_AUTH)
|
||||
source = "auth";
|
||||
else if (flags & F_SERVER)
|
||||
{
|
||||
source = "forwarded";
|
||||
@@ -1326,6 +1604,18 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
||||
source = arg;
|
||||
verb = "from";
|
||||
}
|
||||
else if (flags & F_DNSSEC)
|
||||
{
|
||||
source = arg;
|
||||
verb = "to";
|
||||
}
|
||||
else if (flags & F_IPSET)
|
||||
{
|
||||
source = "ipset add";
|
||||
dest = name;
|
||||
name = arg;
|
||||
verb = daemon->addrbuff;
|
||||
}
|
||||
else
|
||||
source = "cached";
|
||||
|
||||
@@ -1335,50 +1625,4 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
||||
my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
struct keydata *keydata_alloc(char *data, size_t len)
|
||||
{
|
||||
struct keydata *block, *ret = NULL;
|
||||
struct keydata **prev = &ret;
|
||||
while (len > 0)
|
||||
{
|
||||
if (keyblock_free)
|
||||
{
|
||||
block = keyblock_free;
|
||||
keyblock_free = block->next;
|
||||
}
|
||||
else
|
||||
block = whine_malloc(sizeof(struct keydata));
|
||||
|
||||
if (!block)
|
||||
{
|
||||
/* failed to alloc, free partial chain */
|
||||
keydata_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(block->key, data, len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len);
|
||||
data += KEYBLOCK_LEN;
|
||||
len -= KEYBLOCK_LEN;
|
||||
*prev = block;
|
||||
prev = &block->next;
|
||||
block->next = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void keydata_free(struct keydata *blocks)
|
||||
{
|
||||
struct keydata *tmp;
|
||||
|
||||
if (blocks)
|
||||
{
|
||||
for (tmp = blocks; tmp->next; tmp = tmp->next);
|
||||
tmp->next = keyblock_free;
|
||||
keyblock_free = blocks;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
91
src/config.h
91
src/config.h
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -18,7 +18,8 @@
|
||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
|
||||
#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
|
||||
#define KEYBLOCK_LEN 140 /* choose to mininise fragmentation when storing DNSSEC keys */
|
||||
#define KEYBLOCK_LEN 40 /* choose to mininise fragmentation when storing DNSSEC keys */
|
||||
#define DNSSEC_WORK 50 /* Max number of queries to validate one question */
|
||||
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
|
||||
#define FORWARD_TEST 50 /* try all servers every 50 queries */
|
||||
#define FORWARD_TIME 20 /* or 20 seconds */
|
||||
@@ -30,7 +31,8 @@
|
||||
#define PING_CACHE_TIME 30 /* Ping test assumed to be valid this long. */
|
||||
#define DECLINE_BACKOFF 600 /* disable DECLINEd static addresses for this long */
|
||||
#define DHCP_PACKET_MAX 16384 /* hard limit on DHCP packet size */
|
||||
#define SMALLDNAME 40 /* most domain names are smaller than this */
|
||||
#define SMALLDNAME 50 /* most domain names are smaller than this */
|
||||
#define CNAME_CHAIN 10 /* chains longer than this atr dropped for loop protection */
|
||||
#define HOSTSFILE "/etc/hosts"
|
||||
#define ETHERSFILE "/etc/ethers"
|
||||
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
||||
@@ -39,10 +41,13 @@
|
||||
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
|
||||
#define LOG_MAX 5 /* log-queue length */
|
||||
#define RANDFILE "/dev/urandom"
|
||||
#define EDNS0_OPTION_MAC 5 /* dyndns.org temporary assignment */
|
||||
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* Default - may be overridden by config */
|
||||
#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
|
||||
|
||||
#define AUTH_TTL 600 /* default TTL for auth DNS */
|
||||
#define SOA_REFRESH 1200 /* SOA refresh default */
|
||||
#define SOA_RETRY 180 /* SOA retry default */
|
||||
#define SOA_EXPIRY 1209600 /* SOA expiry default */
|
||||
|
||||
/* compile-time options: uncomment below to enable or do eg.
|
||||
make COPTS=-DHAVE_BROKEN_RTC
|
||||
|
||||
@@ -92,12 +97,22 @@ HAVE_CONNTRACK
|
||||
a build-dependency on libnetfilter_conntrack, but the resulting binary will
|
||||
still run happily on a kernel without conntrack support.
|
||||
|
||||
HAVE_IPSET
|
||||
define this to include the ability to selectively add resolved ip addresses
|
||||
to given ipsets.
|
||||
|
||||
HAVE_AUTH
|
||||
define this to include the facility to act as an authoritative DNS
|
||||
server for one or more zones.
|
||||
|
||||
|
||||
NO_IPV6
|
||||
NO_TFTP
|
||||
NO_DHCP
|
||||
NO_DHCP6
|
||||
NO_SCRIPT
|
||||
NO_LARGEFILE
|
||||
NO_AUTH
|
||||
these are avilable to explictly disable compile time options which would
|
||||
otherwise be enabled automatically (HAVE_IPV6, >2Gb file sizes) or
|
||||
which are enabled by default in the distributed source tree. Building dnsmasq
|
||||
@@ -111,6 +126,11 @@ RESOLVFILE
|
||||
|
||||
*/
|
||||
|
||||
/* Defining this builds a binary which handles time differently and works better on a system without a
|
||||
stable RTC (it uses uptime, not epoch time) and writes the DHCP leases file less often to avoid flash wear.
|
||||
*/
|
||||
|
||||
/* #define HAVE_BROKEN_RTC */
|
||||
|
||||
/* The default set of options to build. Built with these options, dnsmasq
|
||||
has no library dependencies other than libc */
|
||||
@@ -119,12 +139,21 @@ RESOLVFILE
|
||||
#define HAVE_DHCP6
|
||||
#define HAVE_TFTP
|
||||
#define HAVE_SCRIPT
|
||||
#define HAVE_AUTH
|
||||
#define HAVE_IPSET
|
||||
|
||||
/* Build options which require external libraries.
|
||||
|
||||
Defining HAVE_<opt>_STATIC as _well_ as HAVE_<opt> will link the library statically.
|
||||
|
||||
You can use "make COPTS=-DHAVE_<opt>" instead of editing these.
|
||||
*/
|
||||
|
||||
/* #define HAVE_LUASCRIPT */
|
||||
/* #define HAVE_BROKEN_RTC */
|
||||
/* #define HAVE_DBUS */
|
||||
/* #define HAVE_IDN */
|
||||
/* #define HAVE_CONNTRACK */
|
||||
|
||||
/* #define HAVE_DNSSEC */
|
||||
|
||||
|
||||
/* Default locations for important system files. */
|
||||
@@ -175,10 +204,6 @@ HAVE_SOLARIS_NETWORK
|
||||
HAVE_GETOPT_LONG
|
||||
defined when GNU-style getopt_long available.
|
||||
|
||||
HAVE_ARC4RANDOM
|
||||
defined if arc4random() available to get better security from DNS spoofs
|
||||
by using really random ids (OpenBSD)
|
||||
|
||||
HAVE_SOCKADDR_SA_LEN
|
||||
defined if struct sockaddr has sa_len field (*BSD)
|
||||
*/
|
||||
@@ -187,7 +212,6 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#if defined(__uClinux__)
|
||||
#define HAVE_LINUX_NETWORK
|
||||
#define HAVE_GETOPT_LONG
|
||||
#undef HAVE_ARC4RANDOM
|
||||
#undef HAVE_SOCKADDR_SA_LEN
|
||||
/* Never use fork() on uClinux. Note that this is subtly different from the
|
||||
--keep-in-foreground option, since it also suppresses forking new
|
||||
@@ -201,7 +225,6 @@ HAVE_SOCKADDR_SA_LEN
|
||||
((__UCLIBC_MAJOR__==0) && (__UCLIBC_MINOR__==9) && (__UCLIBC_SUBLEVEL__<21))
|
||||
# define HAVE_GETOPT_LONG
|
||||
#endif
|
||||
#undef HAVE_ARC4RANDOM
|
||||
#undef HAVE_SOCKADDR_SA_LEN
|
||||
#if !defined(__ARCH_HAS_MMU__) && !defined(__UCLIBC_HAS_MMU__)
|
||||
# define NO_FORK
|
||||
@@ -216,7 +239,6 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#elif defined(__linux__)
|
||||
#define HAVE_LINUX_NETWORK
|
||||
#define HAVE_GETOPT_LONG
|
||||
#undef HAVE_ARC4RANDOM
|
||||
#undef HAVE_SOCKADDR_SA_LEN
|
||||
|
||||
#elif defined(__FreeBSD__) || \
|
||||
@@ -228,29 +250,26 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#if defined(optional_argument) && defined(required_argument)
|
||||
# define HAVE_GETOPT_LONG
|
||||
#endif
|
||||
#if !defined(__FreeBSD_kernel__)
|
||||
# define HAVE_ARC4RANDOM
|
||||
#endif
|
||||
#define HAVE_SOCKADDR_SA_LEN
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
#define HAVE_BSD_NETWORK
|
||||
#define HAVE_GETOPT_LONG
|
||||
#define HAVE_ARC4RANDOM
|
||||
#define HAVE_SOCKADDR_SA_LEN
|
||||
/* Define before sys/socket.h is included so we get socklen_t */
|
||||
#define _BSD_SOCKLEN_T_
|
||||
|
||||
/* Select the RFC_3542 version of the IPv6 socket API.
|
||||
Define before netinet6/in6.h is included. */
|
||||
#define __APPLE_USE_RFC_3542
|
||||
|
||||
#elif defined(__NetBSD__)
|
||||
#define HAVE_BSD_NETWORK
|
||||
#define HAVE_GETOPT_LONG
|
||||
#undef HAVE_ARC4RANDOM
|
||||
#define HAVE_SOCKADDR_SA_LEN
|
||||
|
||||
#elif defined(__sun) || defined(__sun__)
|
||||
#define HAVE_SOLARIS_NETWORK
|
||||
#define HAVE_GETOPT_LONG
|
||||
#undef HAVE_ARC4RANDOM
|
||||
#undef HAVE_SOCKADDR_SA_LEN
|
||||
#define ETHER_ADDR_LEN 6
|
||||
|
||||
@@ -263,12 +282,12 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#if defined(INET6_ADDRSTRLEN) && defined(IPV6_V6ONLY)
|
||||
# define HAVE_IPV6
|
||||
# define ADDRSTRLEN INET6_ADDRSTRLEN
|
||||
#elif defined(INET_ADDRSTRLEN)
|
||||
#else
|
||||
# if !defined(INET_ADDRSTRLEN)
|
||||
# define INET_ADDRSTRLEN 16 /* 4*3 + 3 dots + NULL */
|
||||
# endif
|
||||
# undef HAVE_IPV6
|
||||
# define ADDRSTRLEN INET_ADDRSTRLEN
|
||||
#else
|
||||
# undef HAVE_IPV6
|
||||
# define ADDRSTRLEN 16 /* 4*3 + 3 dots + NULL */
|
||||
#endif
|
||||
|
||||
|
||||
@@ -307,6 +326,13 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#define HAVE_SCRIPT
|
||||
#endif
|
||||
|
||||
#ifdef NO_AUTH
|
||||
#undef HAVE_AUTH
|
||||
#endif
|
||||
|
||||
#if defined(NO_IPSET) || !defined(HAVE_LINUX_NETWORK)
|
||||
#undef HAVE_IPSET
|
||||
#endif
|
||||
|
||||
/* Define a string indicating which options are in use.
|
||||
DNSMASQP_COMPILE_OPTS is only defined in dnsmasq.c */
|
||||
@@ -365,7 +391,20 @@ static char *compile_opts =
|
||||
#ifndef HAVE_CONNTRACK
|
||||
"no-"
|
||||
#endif
|
||||
"conntrack";
|
||||
"conntrack "
|
||||
#ifndef HAVE_IPSET
|
||||
"no-"
|
||||
#endif
|
||||
"ipset "
|
||||
#ifndef HAVE_AUTH
|
||||
"no-"
|
||||
#endif
|
||||
"auth "
|
||||
#ifndef HAVE_DNSSEC
|
||||
"no-"
|
||||
#endif
|
||||
"DNSSEC";
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
186
src/dbus.c
186
src/dbus.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -91,122 +91,23 @@ static dbus_bool_t add_watch(DBusWatch *watch, void *data)
|
||||
|
||||
static void remove_watch(DBusWatch *watch, void *data)
|
||||
{
|
||||
struct watch **up, *w;
|
||||
struct watch **up, *w, *tmp;
|
||||
|
||||
for (up = &(daemon->watches), w = daemon->watches; w; w = w->next)
|
||||
if (w->watch == watch)
|
||||
{
|
||||
*up = w->next;
|
||||
free(w);
|
||||
}
|
||||
else
|
||||
up = &(w->next);
|
||||
for (up = &(daemon->watches), w = daemon->watches; w; w = tmp)
|
||||
{
|
||||
tmp = w->next;
|
||||
if (w->watch == watch)
|
||||
{
|
||||
*up = tmp;
|
||||
free(w);
|
||||
}
|
||||
else
|
||||
up = &(w->next);
|
||||
}
|
||||
|
||||
w = data; /* no warning */
|
||||
}
|
||||
|
||||
static void add_update_server(union mysockaddr *addr,
|
||||
union mysockaddr *source_addr,
|
||||
const char *interface,
|
||||
const char *domain)
|
||||
{
|
||||
struct server *serv;
|
||||
|
||||
/* See if there is a suitable candidate, and unmark */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if ((serv->flags & SERV_FROM_DBUS) &&
|
||||
(serv->flags & SERV_MARK))
|
||||
{
|
||||
if (domain)
|
||||
{
|
||||
if (!(serv->flags & SERV_HAS_DOMAIN) || !hostname_isequal(domain, serv->domain))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (serv->flags & SERV_HAS_DOMAIN)
|
||||
continue;
|
||||
}
|
||||
|
||||
serv->flags &= ~SERV_MARK;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!serv && (serv = whine_malloc(sizeof (struct server))))
|
||||
{
|
||||
/* Not found, create a new one. */
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
|
||||
if (domain && !(serv->domain = whine_malloc(strlen(domain)+1)))
|
||||
{
|
||||
free(serv);
|
||||
serv = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
serv->next = daemon->servers;
|
||||
daemon->servers = serv;
|
||||
serv->flags = SERV_FROM_DBUS;
|
||||
if (domain)
|
||||
{
|
||||
strcpy(serv->domain, domain);
|
||||
serv->flags |= SERV_HAS_DOMAIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (serv)
|
||||
{
|
||||
if (interface)
|
||||
strcpy(serv->interface, interface);
|
||||
else
|
||||
serv->interface[0] = 0;
|
||||
|
||||
if (source_addr->in.sin_family == AF_INET &&
|
||||
addr->in.sin_addr.s_addr == 0 &&
|
||||
serv->domain)
|
||||
serv->flags |= SERV_NO_ADDR;
|
||||
else
|
||||
{
|
||||
serv->flags &= ~SERV_NO_ADDR;
|
||||
serv->addr = *addr;
|
||||
serv->source_addr = *source_addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void mark_dbus(void)
|
||||
{
|
||||
struct server *serv;
|
||||
|
||||
/* mark everything from DBUS */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (serv->flags & SERV_FROM_DBUS)
|
||||
serv->flags |= SERV_MARK;
|
||||
}
|
||||
|
||||
static void cleanup_dbus()
|
||||
{
|
||||
struct server *serv, *tmp, **up;
|
||||
|
||||
/* unlink and free anything still marked. */
|
||||
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
|
||||
{
|
||||
tmp = serv->next;
|
||||
if (serv->flags & SERV_MARK)
|
||||
{
|
||||
server_gone(serv);
|
||||
*up = serv->next;
|
||||
if (serv->domain)
|
||||
free(serv->domain);
|
||||
free(serv);
|
||||
}
|
||||
else
|
||||
up = &serv->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void dbus_read_servers(DBusMessage *message)
|
||||
{
|
||||
DBusMessageIter iter;
|
||||
@@ -215,8 +116,8 @@ static void dbus_read_servers(DBusMessage *message)
|
||||
|
||||
dbus_message_iter_init(message, &iter);
|
||||
|
||||
mark_dbus();
|
||||
|
||||
mark_servers(SERV_FROM_DBUS);
|
||||
|
||||
while (1)
|
||||
{
|
||||
int skip = 0;
|
||||
@@ -286,13 +187,13 @@ static void dbus_read_servers(DBusMessage *message)
|
||||
domain = NULL;
|
||||
|
||||
if (!skip)
|
||||
add_update_server(&addr, &source_addr, NULL, domain);
|
||||
add_update_server(SERV_FROM_DBUS, &addr, &source_addr, NULL, domain);
|
||||
|
||||
} while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING);
|
||||
}
|
||||
|
||||
/* unlink and free anything still marked. */
|
||||
cleanup_dbus();
|
||||
cleanup_servers();
|
||||
}
|
||||
|
||||
static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
@@ -302,8 +203,6 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
const char *addr_err;
|
||||
char *dup = NULL;
|
||||
|
||||
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
|
||||
|
||||
if (!dbus_message_iter_init(message, &iter))
|
||||
{
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
@@ -318,7 +217,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
strings ? "Expected array of string" : "Expected array of string arrays");
|
||||
}
|
||||
|
||||
mark_dbus();
|
||||
mark_servers(SERV_FROM_DBUS);
|
||||
|
||||
/* array_iter points to each "as" element in the outer array */
|
||||
dbus_message_iter_recurse(&iter, &array_iter);
|
||||
@@ -326,6 +225,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
{
|
||||
const char *str = NULL;
|
||||
union mysockaddr addr, source_addr;
|
||||
int flags = 0;
|
||||
char interface[IF_NAMESIZE];
|
||||
char *str_addr, *str_domain = NULL;
|
||||
|
||||
@@ -340,9 +240,11 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
}
|
||||
|
||||
/* dup the string because it gets modified during parsing */
|
||||
if (dup)
|
||||
free(dup);
|
||||
if (!(dup = str_domain = whine_malloc(strlen(str)+1)))
|
||||
break;
|
||||
|
||||
|
||||
strcpy(str_domain, str);
|
||||
|
||||
/* point to address part of old string for error message */
|
||||
@@ -400,9 +302,11 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
}
|
||||
|
||||
/* dup the string because it gets modified during parsing */
|
||||
if (dup)
|
||||
free(dup);
|
||||
if (!(dup = str_addr = whine_malloc(strlen(str)+1)))
|
||||
break;
|
||||
|
||||
|
||||
strcpy(str_addr, str);
|
||||
}
|
||||
|
||||
@@ -411,16 +315,19 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
memset(&interface, 0, sizeof(interface));
|
||||
|
||||
/* parse the IP address */
|
||||
addr_err = parse_server(str_addr, &addr, &source_addr, (char *) &interface, NULL);
|
||||
|
||||
if (addr_err)
|
||||
{
|
||||
if ((addr_err = parse_server(str_addr, &addr, &source_addr, (char *) &interface, &flags)))
|
||||
{
|
||||
error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid IP address '%s': %s",
|
||||
str, addr_err);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* 0.0.0.0 for server address == NULL, for Dbus */
|
||||
if (addr.in.sin_family == AF_INET &&
|
||||
addr.in.sin_addr.s_addr == 0)
|
||||
flags |= SERV_NO_ADDR;
|
||||
|
||||
if (strings)
|
||||
{
|
||||
char *p;
|
||||
@@ -434,7 +341,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
else
|
||||
p = NULL;
|
||||
|
||||
add_update_server(&addr, &source_addr, interface, str_domain);
|
||||
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain);
|
||||
} while ((str_domain = p));
|
||||
}
|
||||
else
|
||||
@@ -449,7 +356,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
dbus_message_iter_get_basic(&string_iter, &str);
|
||||
dbus_message_iter_next (&string_iter);
|
||||
|
||||
add_update_server(&addr, &source_addr, interface, str);
|
||||
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str);
|
||||
} while (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING);
|
||||
}
|
||||
|
||||
@@ -457,7 +364,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
dbus_message_iter_next(&array_iter);
|
||||
}
|
||||
|
||||
cleanup_dbus();
|
||||
cleanup_servers();
|
||||
|
||||
if (dup)
|
||||
free(dup);
|
||||
@@ -471,6 +378,7 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
{
|
||||
char *method = (char *)dbus_message_get_member(message);
|
||||
DBusMessage *reply = NULL;
|
||||
int clear_cache = 0, new_servers = 0;
|
||||
|
||||
if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
|
||||
{
|
||||
@@ -494,24 +402,34 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
}
|
||||
else if (strcmp(method, "SetServers") == 0)
|
||||
{
|
||||
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
|
||||
dbus_read_servers(message);
|
||||
check_servers();
|
||||
new_servers = 1;
|
||||
}
|
||||
else if (strcmp(method, "SetServersEx") == 0)
|
||||
{
|
||||
reply = dbus_read_servers_ex(message, 0);
|
||||
check_servers();
|
||||
new_servers = 1;
|
||||
}
|
||||
else if (strcmp(method, "SetDomainServers") == 0)
|
||||
{
|
||||
reply = dbus_read_servers_ex(message, 1);
|
||||
check_servers();
|
||||
new_servers = 1;
|
||||
}
|
||||
else if (strcmp(method, "ClearCache") == 0)
|
||||
clear_cache_and_reload(dnsmasq_time());
|
||||
clear_cache = 1;
|
||||
else
|
||||
return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
|
||||
|
||||
if (new_servers)
|
||||
{
|
||||
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
|
||||
check_servers();
|
||||
if (option_bool(OPT_RELOAD))
|
||||
clear_cache = 1;
|
||||
}
|
||||
|
||||
if (clear_cache)
|
||||
clear_cache_and_reload(dnsmasq_time());
|
||||
|
||||
method = user_data; /* no warning */
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -91,6 +91,7 @@ struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *con
|
||||
{
|
||||
struct dhcp_netid *tagif = run_tag_if(tags);
|
||||
struct dhcp_opt *opt;
|
||||
struct dhcp_opt *tmp;
|
||||
|
||||
/* flag options which are valid with the current tag set (sans context tags) */
|
||||
for (opt = opts; opt; opt = opt->next)
|
||||
@@ -135,7 +136,6 @@ struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *con
|
||||
for (opt = opts; opt; opt = opt->next)
|
||||
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) && !opt->netid)
|
||||
{
|
||||
struct dhcp_opt *tmp;
|
||||
for (tmp = opts; tmp; tmp = tmp->next)
|
||||
if (tmp->opt == opt->opt && (tmp->flags & DHOPT_TAGOK))
|
||||
break;
|
||||
@@ -145,6 +145,13 @@ struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *con
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring duplicate dhcp-option %d"), tmp->opt);
|
||||
}
|
||||
|
||||
/* Finally, eliminate duplicate options later in the chain, and therefore earlier in the config file. */
|
||||
for (opt = opts; opt; opt = opt->next)
|
||||
if (opt->flags & DHOPT_TAGOK)
|
||||
for (tmp = opt->next; tmp; tmp = tmp->next)
|
||||
if (tmp->opt == opt->opt)
|
||||
tmp->flags &= ~DHOPT_TAGOK;
|
||||
|
||||
return tagif;
|
||||
}
|
||||
|
||||
@@ -246,6 +253,110 @@ int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
|
||||
{
|
||||
struct hwaddr_config *conf_addr;
|
||||
|
||||
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
|
||||
if (conf_addr->wildcard_mask == 0 &&
|
||||
conf_addr->hwaddr_len == len &&
|
||||
(conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
|
||||
memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_config_in_context(struct dhcp_context *context, struct dhcp_config *config)
|
||||
{
|
||||
if (!context) /* called via find_config() from lease_update_from_configs() */
|
||||
return 1;
|
||||
|
||||
if (!(config->flags & (CONFIG_ADDR | CONFIG_ADDR6)))
|
||||
return 1;
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if ((context->flags & CONTEXT_V6) && (config->flags & CONFIG_WILDCARD))
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
for (; context; context = context->current)
|
||||
#ifdef HAVE_DHCP6
|
||||
if (context->flags & CONTEXT_V6)
|
||||
{
|
||||
if ((config->flags & CONFIG_ADDR6) && is_same_net6(&config->addr6, &context->start6, context->prefix))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dhcp_config *find_config(struct dhcp_config *configs,
|
||||
struct dhcp_context *context,
|
||||
unsigned char *clid, int clid_len,
|
||||
unsigned char *hwaddr, int hw_len,
|
||||
int hw_type, char *hostname)
|
||||
{
|
||||
int count, new;
|
||||
struct dhcp_config *config, *candidate;
|
||||
struct hwaddr_config *conf_addr;
|
||||
|
||||
if (clid)
|
||||
for (config = configs; config; config = config->next)
|
||||
if (config->flags & CONFIG_CLID)
|
||||
{
|
||||
if (config->clid_len == clid_len &&
|
||||
memcmp(config->clid, clid, clid_len) == 0 &&
|
||||
is_config_in_context(context, config))
|
||||
return config;
|
||||
|
||||
/* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
|
||||
cope with that here. This is IPv4 only. context==NULL implies IPv4,
|
||||
see lease_update_from_configs() */
|
||||
if ((!context || !(context->flags & CONTEXT_V6)) && *clid == 0 && config->clid_len == clid_len-1 &&
|
||||
memcmp(config->clid, clid+1, clid_len-1) == 0 &&
|
||||
is_config_in_context(context, config))
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
if (hwaddr)
|
||||
for (config = configs; config; config = config->next)
|
||||
if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
|
||||
is_config_in_context(context, config))
|
||||
return config;
|
||||
|
||||
if (hostname && context)
|
||||
for (config = configs; config; config = config->next)
|
||||
if ((config->flags & CONFIG_NAME) &&
|
||||
hostname_isequal(config->hostname, hostname) &&
|
||||
is_config_in_context(context, config))
|
||||
return config;
|
||||
|
||||
|
||||
if (!hwaddr)
|
||||
return NULL;
|
||||
|
||||
/* use match with fewest wildcard octets */
|
||||
for (candidate = NULL, count = 0, config = configs; config; config = config->next)
|
||||
if (is_config_in_context(context, config))
|
||||
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
|
||||
if (conf_addr->wildcard_mask != 0 &&
|
||||
conf_addr->hwaddr_len == hw_len &&
|
||||
(conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
|
||||
(new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
|
||||
{
|
||||
count = new;
|
||||
candidate = config;
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
void dhcp_update_configs(struct dhcp_config *configs)
|
||||
{
|
||||
/* Some people like to keep all static IP addresses in /etc/hosts.
|
||||
@@ -288,13 +399,13 @@ void dhcp_update_configs(struct dhcp_config *configs)
|
||||
if (cache_find_by_name(crec, config->hostname, 0, cacheflags))
|
||||
{
|
||||
/* use primary (first) address */
|
||||
while (crec && !(crec->flags & F_REVERSE))
|
||||
crec = cache_find_by_name(crec, config->hostname, 0, cacheflags);
|
||||
if (!crec)
|
||||
continue; /* should be never */
|
||||
inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
|
||||
config->hostname, daemon->addrbuff);
|
||||
while (crec && !(crec->flags & F_REVERSE))
|
||||
crec = cache_find_by_name(crec, config->hostname, 0, cacheflags);
|
||||
if (!crec)
|
||||
continue; /* should be never */
|
||||
inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
|
||||
config->hostname, daemon->addrbuff);
|
||||
}
|
||||
|
||||
if (prot == AF_INET &&
|
||||
@@ -333,116 +444,54 @@ void dhcp_update_configs(struct dhcp_config *configs)
|
||||
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
static int join_multicast_worker(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam)
|
||||
{
|
||||
char ifrn_name[IFNAMSIZ];
|
||||
struct ipv6_mreq mreq;
|
||||
int fd, i, max = *((int *)vparam);
|
||||
struct iname *tmp;
|
||||
|
||||
(void)prefix;
|
||||
(void)scope;
|
||||
(void)dad;
|
||||
|
||||
/* record which interfaces we join on, so that we do it at most one per
|
||||
interface, even when they have multiple addresses. Use outpacket
|
||||
as an array of int, since it's always allocated here and easy
|
||||
to expand for theoretical vast numbers of interfaces. */
|
||||
for (i = 0; i < max; i++)
|
||||
if (if_index == ((int *)daemon->outpacket.iov_base)[i])
|
||||
return 1;
|
||||
|
||||
if ((fd = socket(PF_INET6, SOCK_DGRAM, 0)) == -1)
|
||||
return 0;
|
||||
|
||||
if (!indextoname(fd, if_index, ifrn_name))
|
||||
{
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
/* Are we doing DHCP on this interface? */
|
||||
if (!iface_check(AF_INET6, (struct all_addr *)local, ifrn_name))
|
||||
return 1;
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifrn_name) == 0))
|
||||
return 1;
|
||||
|
||||
mreq.ipv6mr_interface = if_index;
|
||||
|
||||
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
|
||||
|
||||
if (daemon->dhcp6 &&
|
||||
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
|
||||
return 0;
|
||||
|
||||
inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
|
||||
|
||||
if (daemon->dhcp6 &&
|
||||
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
|
||||
return 0;
|
||||
|
||||
inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
|
||||
|
||||
if (daemon->ra_contexts &&
|
||||
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
|
||||
return 0;
|
||||
|
||||
expand_buf(&daemon->outpacket, (max+1) * sizeof(int));
|
||||
((int *)daemon->outpacket.iov_base)[max++] = if_index;
|
||||
|
||||
*((int *)vparam) = max;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void join_multicast(void)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
if (!iface_enumerate(AF_INET6, &count, join_multicast_worker))
|
||||
die(_("failed to join DHCPv6 multicast group: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
void bindtodevice(int fd)
|
||||
char *whichdevice(void)
|
||||
{
|
||||
/* If we are doing DHCP on exactly one interface, and running linux, do SO_BINDTODEVICE
|
||||
to that device. This is for the use case of (eg) OpenStack, which runs a new
|
||||
dnsmasq instance for each VLAN interface it creates. Without the BINDTODEVICE,
|
||||
individual processes don't always see the packets they should.
|
||||
SO_BINDTODEVICE is only available Linux. */
|
||||
SO_BINDTODEVICE is only available Linux.
|
||||
|
||||
Note that if wildcards are used in --interface, or --interface is not used at all,
|
||||
or a configured interface doesn't yet exist, then more interfaces may arrive later,
|
||||
so we can't safely assert there is only one interface and proceed.
|
||||
*/
|
||||
|
||||
struct irec *iface, *found;
|
||||
struct iname *if_tmp;
|
||||
|
||||
if (!daemon->if_names)
|
||||
return NULL;
|
||||
|
||||
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||
if (if_tmp->name && (!if_tmp->used || strchr(if_tmp->name, '*')))
|
||||
return NULL;
|
||||
|
||||
for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->dhcp_ok)
|
||||
{
|
||||
if (!found)
|
||||
found = iface;
|
||||
else if (strcmp(found->name, iface->name) != 0)
|
||||
{
|
||||
/* more than one. */
|
||||
found = NULL;
|
||||
break;
|
||||
}
|
||||
return NULL; /* more than one. */
|
||||
}
|
||||
|
||||
|
||||
if (found)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
strcpy(ifr.ifr_name, found->name);
|
||||
/* only allowed by root. */
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 &&
|
||||
errno != EPERM)
|
||||
die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
return found->name;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void bindtodevice(char *device, int fd)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
strcpy(ifr.ifr_name, device);
|
||||
/* only allowed by root. */
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 &&
|
||||
errno != EPERM)
|
||||
die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -582,11 +631,13 @@ void display_opts6(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
u16 lookup_dhcp_opt(int prot, char *name)
|
||||
int lookup_dhcp_opt(int prot, char *name)
|
||||
{
|
||||
const struct opttab_t *t;
|
||||
int i;
|
||||
|
||||
(void)prot;
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (prot == AF_INET6)
|
||||
t = opttab6;
|
||||
@@ -595,18 +646,19 @@ u16 lookup_dhcp_opt(int prot, char *name)
|
||||
t = opttab;
|
||||
|
||||
for (i = 0; t[i].name; i++)
|
||||
if (!(t[i].size & OT_INTERNAL) &&
|
||||
strcasecmp(t[i].name, name) == 0)
|
||||
if (strcasecmp(t[i].name, name) == 0)
|
||||
return t[i].val;
|
||||
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
u16 lookup_dhcp_len(int prot, u16 val)
|
||||
int lookup_dhcp_len(int prot, int val)
|
||||
{
|
||||
const struct opttab_t *t;
|
||||
int i;
|
||||
|
||||
(void)prot;
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (prot == AF_INET6)
|
||||
t = opttab6;
|
||||
@@ -616,14 +668,9 @@ u16 lookup_dhcp_len(int prot, u16 val)
|
||||
|
||||
for (i = 0; t[i].name; i++)
|
||||
if (val == t[i].val)
|
||||
{
|
||||
if (t[i].size & OT_INTERNAL)
|
||||
return 0;
|
||||
|
||||
return t[i].size & ~OT_DEC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return t[i].size & ~OT_DEC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
|
||||
@@ -750,4 +797,109 @@ char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len,
|
||||
|
||||
}
|
||||
|
||||
void log_context(int family, struct dhcp_context *context)
|
||||
{
|
||||
/* Cannot use dhcp_buff* for RA contexts */
|
||||
|
||||
void *start = &context->start;
|
||||
void *end = &context->end;
|
||||
char *template = "", *p = daemon->namebuff;
|
||||
|
||||
*p = 0;
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (family == AF_INET6)
|
||||
{
|
||||
struct in6_addr subnet = context->start6;
|
||||
if (!(context->flags & CONTEXT_TEMPLATE))
|
||||
setaddr6part(&subnet, 0);
|
||||
inet_ntop(AF_INET6, &subnet, daemon->addrbuff, ADDRSTRLEN);
|
||||
start = &context->start6;
|
||||
end = &context->end6;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
|
||||
strcpy(daemon->namebuff, _(", prefix deprecated"));
|
||||
else
|
||||
{
|
||||
p += sprintf(p, _(", lease time "));
|
||||
prettyprint_time(p, context->lease_time);
|
||||
p += strlen(p);
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (context->flags & CONTEXT_CONSTRUCTED)
|
||||
{
|
||||
char ifrn_name[IFNAMSIZ];
|
||||
|
||||
template = p;
|
||||
p += sprintf(p, ", ");
|
||||
|
||||
if (indextoname(daemon->icmp6fd, context->if_index, ifrn_name))
|
||||
sprintf(p, "%s for %s", (context->flags & CONTEXT_OLD) ? "old prefix" : "constructed", ifrn_name);
|
||||
}
|
||||
else if (context->flags & CONTEXT_TEMPLATE && !(context->flags & CONTEXT_RA_STATELESS))
|
||||
{
|
||||
template = p;
|
||||
p += sprintf(p, ", ");
|
||||
|
||||
sprintf(p, "template for %s", context->template_interface);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(context->flags & CONTEXT_OLD) &&
|
||||
((context->flags & CONTEXT_DHCP) || family == AF_INET))
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
if (context->flags & CONTEXT_RA_STATELESS)
|
||||
{
|
||||
if (context->flags & CONTEXT_TEMPLATE)
|
||||
strncpy(daemon->dhcp_buff, context->template_interface, 256);
|
||||
else
|
||||
strcpy(daemon->dhcp_buff, daemon->addrbuff);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
inet_ntop(family, start, daemon->dhcp_buff, 256);
|
||||
inet_ntop(family, end, daemon->dhcp_buff3, 256);
|
||||
my_syslog(MS_DHCP | LOG_INFO,
|
||||
(context->flags & CONTEXT_RA_STATELESS) ?
|
||||
_("%s stateless on %s%.0s%.0s%s") :
|
||||
(context->flags & CONTEXT_STATIC) ?
|
||||
_("%s, static leases only on %.0s%s%s%.0s") :
|
||||
(context->flags & CONTEXT_PROXY) ?
|
||||
_("%s, proxy on subnet %.0s%s%.0s%.0s") :
|
||||
_("%s, IP range %s -- %s%s%.0s"),
|
||||
(family != AF_INET) ? "DHCPv6" : "DHCP",
|
||||
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template);
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (context->flags & CONTEXT_TEMPLATE)
|
||||
{
|
||||
strcpy(daemon->addrbuff, context->template_interface);
|
||||
template = "";
|
||||
}
|
||||
|
||||
if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
|
||||
|
||||
if ((context->flags & CONTEXT_RA) || (option_bool(OPT_RA) && (context->flags & CONTEXT_DHCP) && family == AF_INET6))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s"), daemon->addrbuff, template);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void log_relay(int family, struct dhcp_relay *relay)
|
||||
{
|
||||
inet_ntop(family, &relay->local, daemon->addrbuff, ADDRSTRLEN);
|
||||
inet_ntop(family, &relay->server, daemon->namebuff, ADDRSTRLEN);
|
||||
|
||||
if (relay->interface)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
|
||||
else
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s"), daemon->addrbuff, daemon->namebuff);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
321
src/dhcp.c
321
src/dhcp.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
struct iface_param {
|
||||
struct dhcp_context *current;
|
||||
struct dhcp_relay *relay;
|
||||
struct in_addr relay_local;
|
||||
int ind;
|
||||
};
|
||||
|
||||
@@ -28,10 +30,12 @@ struct match_param {
|
||||
struct in_addr netmask, broadcast, addr;
|
||||
};
|
||||
|
||||
static int complete_context(struct in_addr local, int if_index,
|
||||
static int complete_context(struct in_addr local, int if_index, char *label,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
||||
static int check_listen_addrs(struct in_addr local, int if_index,
|
||||
static int check_listen_addrs(struct in_addr local, int if_index, char *label,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
||||
static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index);
|
||||
static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface);
|
||||
|
||||
static int make_fd(int port)
|
||||
{
|
||||
@@ -65,14 +69,22 @@ static int make_fd(int port)
|
||||
|
||||
/* When bind-interfaces is set, there might be more than one dnmsasq
|
||||
instance binding port 67. That's OK if they serve different networks.
|
||||
Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
|
||||
Need to set REUSEADDR|REUSEPORT to make this posible.
|
||||
Handle the case that REUSEPORT is defined, but the kernel doesn't
|
||||
support it. This handles the introduction of REUSEPORT on Linux. */
|
||||
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
#ifdef SO_REUSEPORT
|
||||
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt));
|
||||
#else
|
||||
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
|
||||
if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
|
||||
errno == ENOPROTOOPT)
|
||||
rc = 0;
|
||||
#endif
|
||||
|
||||
if (rc != -1)
|
||||
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
|
||||
|
||||
if (rc == -1)
|
||||
die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
@@ -124,6 +136,8 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
|
||||
struct dhcp_packet *mess;
|
||||
struct dhcp_context *context;
|
||||
struct dhcp_relay *relay;
|
||||
int is_relay_reply = 0;
|
||||
struct iname *tmp;
|
||||
struct ifreq ifr;
|
||||
struct msghdr msg;
|
||||
@@ -242,57 +256,86 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
unicast_dest = 1;
|
||||
#endif
|
||||
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
|
||||
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
if ((relay = relay_reply4((struct dhcp_packet *)daemon->dhcp_packet.iov_base, ifr.ifr_name)))
|
||||
{
|
||||
/* Reply from server, using us as relay. */
|
||||
iface_index = relay->iface_index;
|
||||
if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
|
||||
return;
|
||||
is_relay_reply = 1;
|
||||
iov.iov_len = sz;
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
|
||||
return;
|
||||
}
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
return;
|
||||
|
||||
/* unlinked contexts are marked by context->current == context */
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
context->current = context;
|
||||
|
||||
parm.current = NULL;
|
||||
parm.ind = iface_index;
|
||||
|
||||
if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name))
|
||||
{
|
||||
/* If we failed to match the primary address of the interface, see if we've got a --listen-address
|
||||
for a secondary */
|
||||
struct match_param match;
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
|
||||
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
else
|
||||
{
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
|
||||
return;
|
||||
}
|
||||
|
||||
match.matched = 0;
|
||||
match.ind = iface_index;
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
if (!daemon->if_addrs ||
|
||||
!iface_enumerate(AF_INET, &match, check_listen_addrs) ||
|
||||
!match.matched)
|
||||
/* unlinked contexts/relays are marked by context->current == context */
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
context->current = context;
|
||||
|
||||
for (relay = daemon->relay4; relay; relay = relay->next)
|
||||
relay->current = relay;
|
||||
|
||||
parm.current = NULL;
|
||||
parm.relay = NULL;
|
||||
parm.relay_local.s_addr = 0;
|
||||
parm.ind = iface_index;
|
||||
|
||||
if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name, NULL))
|
||||
{
|
||||
/* If we failed to match the primary address of the interface, see if we've got a --listen-address
|
||||
for a secondary */
|
||||
struct match_param match;
|
||||
|
||||
match.matched = 0;
|
||||
match.ind = iface_index;
|
||||
|
||||
if (!daemon->if_addrs ||
|
||||
!iface_enumerate(AF_INET, &match, check_listen_addrs) ||
|
||||
!match.matched)
|
||||
return;
|
||||
|
||||
iface_addr = match.addr;
|
||||
/* make sure secondary address gets priority in case
|
||||
there is more than one address on the interface in the same subnet */
|
||||
complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);
|
||||
}
|
||||
|
||||
if (!iface_enumerate(AF_INET, &parm, complete_context))
|
||||
return;
|
||||
|
||||
iface_addr = match.addr;
|
||||
/* make sure secondary address gets priority in case
|
||||
there is more than one address on the interface in the same subnet */
|
||||
complete_context(match.addr, iface_index, match.netmask, match.broadcast, &parm);
|
||||
}
|
||||
/* We're relaying this request */
|
||||
if (parm.relay_local.s_addr != 0 &&
|
||||
relay_upstream4(parm.relay, (struct dhcp_packet *)daemon->dhcp_packet.iov_base, (size_t)sz, iface_index))
|
||||
return;
|
||||
|
||||
/* May have configured relay, but not DHCP server */
|
||||
if (!daemon->dhcp)
|
||||
return;
|
||||
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
|
||||
now, unicast_dest, &is_inform, pxe_fd, iface_addr);
|
||||
lease_update_file(now);
|
||||
lease_update_dns(0);
|
||||
|
||||
if (!iface_enumerate(AF_INET, &parm, complete_context))
|
||||
return;
|
||||
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
|
||||
now, unicast_dest, &is_inform, pxe_fd, iface_addr);
|
||||
lease_update_file(now);
|
||||
lease_update_dns(0);
|
||||
|
||||
if (iov.iov_len == 0)
|
||||
return;
|
||||
if (iov.iov_len == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
msg.msg_name = &dest;
|
||||
msg.msg_namelen = sizeof(dest);
|
||||
@@ -313,7 +356,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
if (mess->ciaddr.s_addr != 0)
|
||||
dest.sin_addr = mess->ciaddr;
|
||||
}
|
||||
else if (mess->giaddr.s_addr)
|
||||
else if (mess->giaddr.s_addr && !is_relay_reply)
|
||||
{
|
||||
/* Send to BOOTP relay */
|
||||
dest.sin_port = htons(daemon->dhcp_server_port);
|
||||
@@ -326,7 +369,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
source port too, and send back to that. If we're replying
|
||||
to a DHCPINFORM, trust the source address always. */
|
||||
if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
|
||||
dest.sin_port == 0 || dest.sin_addr.s_addr == 0)
|
||||
dest.sin_port == 0 || dest.sin_addr.s_addr == 0 || is_relay_reply)
|
||||
{
|
||||
dest.sin_port = htons(daemon->dhcp_client_port);
|
||||
dest.sin_addr = mess->ciaddr;
|
||||
@@ -403,12 +446,14 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
}
|
||||
|
||||
/* check against secondary interface addresses */
|
||||
static int check_listen_addrs(struct in_addr local, int if_index,
|
||||
static int check_listen_addrs(struct in_addr local, int if_index, char *label,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||
{
|
||||
struct match_param *param = vparam;
|
||||
struct iname *tmp;
|
||||
|
||||
(void) label;
|
||||
|
||||
if (if_index == param->ind)
|
||||
{
|
||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
@@ -436,11 +481,14 @@ static int check_listen_addrs(struct in_addr local, int if_index,
|
||||
|
||||
Note that the current chain may be superceded later for configured hosts or those coming via gateways. */
|
||||
|
||||
static int complete_context(struct in_addr local, int if_index,
|
||||
static int complete_context(struct in_addr local, int if_index, char *label,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
struct dhcp_relay *relay;
|
||||
struct iface_param *param = vparam;
|
||||
|
||||
(void)label;
|
||||
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
{
|
||||
@@ -483,6 +531,15 @@ static int complete_context(struct in_addr local, int if_index,
|
||||
}
|
||||
}
|
||||
|
||||
for (relay = daemon->relay4; relay; relay = relay->next)
|
||||
if (if_index == param->ind && relay->local.addr.addr4.s_addr == local.s_addr && relay->current == relay &&
|
||||
(param->relay_local.s_addr == 0 || param->relay_local.s_addr == local.s_addr))
|
||||
{
|
||||
relay->current = param->relay;
|
||||
param->relay = relay;
|
||||
param->relay_local = local;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -692,89 +749,6 @@ int address_allocate(struct dhcp_context *context,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *config)
|
||||
{
|
||||
if (!context) /* called via find_config() from lease_update_from_configs() */
|
||||
return 1;
|
||||
if (!(config->flags & CONFIG_ADDR))
|
||||
return 1;
|
||||
for (; context; context = context->current)
|
||||
if (is_same_net(config->addr, context->start, context->netmask))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
|
||||
{
|
||||
struct hwaddr_config *conf_addr;
|
||||
|
||||
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
|
||||
if (conf_addr->wildcard_mask == 0 &&
|
||||
conf_addr->hwaddr_len == len &&
|
||||
(conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
|
||||
memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dhcp_config *find_config(struct dhcp_config *configs,
|
||||
struct dhcp_context *context,
|
||||
unsigned char *clid, int clid_len,
|
||||
unsigned char *hwaddr, int hw_len,
|
||||
int hw_type, char *hostname)
|
||||
{
|
||||
int count, new;
|
||||
struct dhcp_config *config, *candidate;
|
||||
struct hwaddr_config *conf_addr;
|
||||
|
||||
if (clid)
|
||||
for (config = configs; config; config = config->next)
|
||||
if (config->flags & CONFIG_CLID)
|
||||
{
|
||||
if (config->clid_len == clid_len &&
|
||||
memcmp(config->clid, clid, clid_len) == 0 &&
|
||||
is_addr_in_context(context, config))
|
||||
return config;
|
||||
|
||||
/* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
|
||||
cope with that here */
|
||||
if (*clid == 0 && config->clid_len == clid_len-1 &&
|
||||
memcmp(config->clid, clid+1, clid_len-1) == 0 &&
|
||||
is_addr_in_context(context, config))
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
for (config = configs; config; config = config->next)
|
||||
if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
|
||||
is_addr_in_context(context, config))
|
||||
return config;
|
||||
|
||||
if (hostname && context)
|
||||
for (config = configs; config; config = config->next)
|
||||
if ((config->flags & CONFIG_NAME) &&
|
||||
hostname_isequal(config->hostname, hostname) &&
|
||||
is_addr_in_context(context, config))
|
||||
return config;
|
||||
|
||||
/* use match with fewest wildcard octets */
|
||||
for (candidate = NULL, count = 0, config = configs; config; config = config->next)
|
||||
if (is_addr_in_context(context, config))
|
||||
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
|
||||
if (conf_addr->wildcard_mask != 0 &&
|
||||
conf_addr->hwaddr_len == hw_len &&
|
||||
(conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
|
||||
(new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
|
||||
{
|
||||
count = new;
|
||||
candidate = config;
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
void dhcp_read_ethers(void)
|
||||
{
|
||||
FILE *f = fopen(ETHERSFILE, "r");
|
||||
@@ -976,5 +950,74 @@ char *host_from_dns(struct in_addr addr)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index)
|
||||
{
|
||||
/* ->local is same value for all relays on ->current chain */
|
||||
struct all_addr from;
|
||||
|
||||
if (mess->op != BOOTREQUEST)
|
||||
return 0;
|
||||
|
||||
/* source address == relay address */
|
||||
from.addr.addr4 = relay->local.addr.addr4;
|
||||
|
||||
/* already gatewayed ? */
|
||||
if (mess->giaddr.s_addr)
|
||||
{
|
||||
/* if so check if by us, to stomp on loops. */
|
||||
if (mess->giaddr.s_addr == relay->local.addr.addr4.s_addr)
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* plug in our address */
|
||||
mess->giaddr.s_addr = relay->local.addr.addr4.s_addr;
|
||||
}
|
||||
|
||||
if ((mess->hops++) > 20)
|
||||
return 1;
|
||||
|
||||
for (; relay; relay = relay->current)
|
||||
{
|
||||
union mysockaddr to;
|
||||
|
||||
to.sa.sa_family = AF_INET;
|
||||
to.in.sin_addr = relay->server.addr.addr4;
|
||||
to.in.sin_port = htons(daemon->dhcp_server_port);
|
||||
|
||||
send_from(daemon->dhcpfd, 0, (char *)mess, sz, &to, &from, 0);
|
||||
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
inet_ntop(AF_INET, &relay->local, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, inet_ntoa(relay->server.addr.addr4));
|
||||
}
|
||||
|
||||
/* Save this for replies */
|
||||
relay->iface_index = iface_index;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface)
|
||||
{
|
||||
struct dhcp_relay *relay;
|
||||
|
||||
if (mess->giaddr.s_addr == 0 || mess->op != BOOTREPLY)
|
||||
return NULL;
|
||||
|
||||
for (relay = daemon->relay4; relay; relay = relay->next)
|
||||
{
|
||||
if (mess->giaddr.s_addr == relay->local.addr.addr4.s_addr)
|
||||
{
|
||||
if (!relay->interface || wildcard_match(relay->interface, arrival_interface))
|
||||
return relay->iface_index != 0 ? relay : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -55,9 +55,16 @@
|
||||
#define OPTION6_RECONF_ACCEPT 20
|
||||
#define OPTION6_DNS_SERVER 23
|
||||
#define OPTION6_DOMAIN_SEARCH 24
|
||||
#define OPTION6_REFRESH_TIME 32
|
||||
#define OPTION6_REMOTE_ID 37
|
||||
#define OPTION6_SUBSCRIBER_ID 38
|
||||
#define OPTION6_FQDN 39
|
||||
#define OPTION6_CLIENT_MAC 79
|
||||
|
||||
/* replace this with the real number when allocated.
|
||||
defining this also enables the relevant code. */
|
||||
/* #define OPTION6_PREFIX_CLASS 99 */
|
||||
|
||||
|
||||
#define DHCP6SUCCESS 0
|
||||
#define DHCP6UNSPEC 1
|
||||
|
||||
689
src/dhcp6.c
689
src/dhcp6.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -18,15 +18,26 @@
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
struct iface_param {
|
||||
struct dhcp_context *current;
|
||||
struct in6_addr fallback;
|
||||
struct dhcp_relay *relay;
|
||||
struct in6_addr fallback, relay_local, ll_addr, ula_addr;
|
||||
int ind, addr_match;
|
||||
};
|
||||
|
||||
static int complete_context6(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam);
|
||||
struct mac_param {
|
||||
struct in6_addr *target;
|
||||
unsigned char *mac;
|
||||
unsigned int maclen;
|
||||
};
|
||||
|
||||
|
||||
static int complete_context6(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int flags,
|
||||
unsigned int preferred, unsigned int valid, void *vparam);
|
||||
static int find_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv);
|
||||
static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm);
|
||||
|
||||
void dhcp6_init(void)
|
||||
@@ -47,16 +58,24 @@ void dhcp6_init(void)
|
||||
!set_ipv6pktinfo(fd))
|
||||
die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET);
|
||||
|
||||
/* When bind-interfaces is set, there might be more than one dnmsasq
|
||||
/* When bind-interfaces is set, there might be more than one dnmsasq
|
||||
instance binding port 547. That's OK if they serve different networks.
|
||||
Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
|
||||
Need to set REUSEADDR|REUSEPORT to make this posible.
|
||||
Handle the case that REUSEPORT is defined, but the kernel doesn't
|
||||
support it. This handles the introduction of REUSEPORT on Linux. */
|
||||
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
#ifdef SO_REUSEPORT
|
||||
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt));
|
||||
#else
|
||||
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
|
||||
if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
|
||||
errno == ENOPROTOOPT)
|
||||
rc = 0;
|
||||
#endif
|
||||
|
||||
if (rc != -1)
|
||||
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
|
||||
|
||||
if (rc == -1)
|
||||
die(_("failed to set SO_REUSE{ADDR|PORT} on DHCPv6 socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
@@ -78,6 +97,7 @@ void dhcp6_init(void)
|
||||
void dhcp6_packet(time_t now)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
struct dhcp_relay *relay;
|
||||
struct iface_param parm;
|
||||
struct cmsghdr *cmptr;
|
||||
struct msghdr msg;
|
||||
@@ -91,6 +111,9 @@ void dhcp6_packet(time_t now)
|
||||
struct ifreq ifr;
|
||||
struct iname *tmp;
|
||||
unsigned short port;
|
||||
struct in6_addr dst_addr;
|
||||
|
||||
memset(&dst_addr, 0, sizeof(dst_addr));
|
||||
|
||||
msg.msg_control = control_u.control6;
|
||||
msg.msg_controllen = sizeof(control_u);
|
||||
@@ -113,60 +136,88 @@ void dhcp6_packet(time_t now)
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
|
||||
if_index = p.p->ipi6_ifindex;
|
||||
dst_addr = p.p->ipi6_addr;
|
||||
}
|
||||
|
||||
if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
return;
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
return;
|
||||
|
||||
parm.current = NULL;
|
||||
parm.ind = if_index;
|
||||
parm.addr_match = 0;
|
||||
memset(&parm.fallback, 0, IN6ADDRSZ);
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)
|
||||
{
|
||||
/* wildcard context for DHCP-stateless only */
|
||||
parm.current = context;
|
||||
context->current = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unlinked contexts are marked by context->current == context */
|
||||
context->current = context;
|
||||
memset(&context->local6, 0, IN6ADDRSZ);
|
||||
}
|
||||
|
||||
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
|
||||
return;
|
||||
|
||||
if (daemon->if_names || daemon->if_addrs)
|
||||
if ((port = relay_reply6(&from, sz, ifr.ifr_name)) == 0)
|
||||
{
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
break;
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
parm.current = NULL;
|
||||
parm.relay = NULL;
|
||||
memset(&parm.relay_local, 0, IN6ADDRSZ);
|
||||
parm.ind = if_index;
|
||||
parm.addr_match = 0;
|
||||
memset(&parm.fallback, 0, IN6ADDRSZ);
|
||||
memset(&parm.ll_addr, 0, IN6ADDRSZ);
|
||||
memset(&parm.ula_addr, 0, IN6ADDRSZ);
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)
|
||||
{
|
||||
/* wildcard context for DHCP-stateless only */
|
||||
parm.current = context;
|
||||
context->current = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unlinked contexts are marked by context->current == context */
|
||||
context->current = context;
|
||||
memset(&context->local6, 0, IN6ADDRSZ);
|
||||
}
|
||||
|
||||
if (!tmp && !parm.addr_match)
|
||||
for (relay = daemon->relay6; relay; relay = relay->next)
|
||||
relay->current = relay;
|
||||
|
||||
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
|
||||
return;
|
||||
|
||||
if (daemon->if_names || daemon->if_addrs)
|
||||
{
|
||||
|
||||
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
break;
|
||||
|
||||
if (!tmp && !parm.addr_match)
|
||||
return;
|
||||
}
|
||||
|
||||
if (parm.relay)
|
||||
{
|
||||
/* Ignore requests sent to the ALL_SERVERS multicast address for relay when
|
||||
we're listening there for DHCPv6 server reasons. */
|
||||
struct in6_addr all_servers;
|
||||
|
||||
inet_pton(AF_INET6, ALL_SERVERS, &all_servers);
|
||||
|
||||
if (!IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers))
|
||||
relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id);
|
||||
return;
|
||||
}
|
||||
|
||||
/* May have configured relay, but not DHCP server */
|
||||
if (!daemon->doing_dhcp6)
|
||||
return;
|
||||
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
|
||||
port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
|
||||
&parm.ll_addr, &parm.ula_addr, sz, &from.sin6_addr, now);
|
||||
|
||||
lease_update_file(now);
|
||||
lease_update_dns(0);
|
||||
}
|
||||
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
|
||||
port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
|
||||
sz, IN6_IS_ADDR_MULTICAST(&from.sin6_addr), now);
|
||||
|
||||
lease_update_file(now);
|
||||
lease_update_dns(0);
|
||||
|
||||
|
||||
/* The port in the source address of the original request should
|
||||
be correct, but at least once client sends from the server port,
|
||||
so we explicitly send to the client port to a client, and the
|
||||
@@ -180,51 +231,161 @@ void dhcp6_packet(time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsigned int *maclenp, unsigned int *mactypep)
|
||||
{
|
||||
/* Recieving a packet from a host does not populate the neighbour
|
||||
cache, so we send a neighbour discovery request if we can't
|
||||
find the sender. Repeat a few times in case of packet loss. */
|
||||
|
||||
struct neigh_packet neigh;
|
||||
struct sockaddr_in6 addr;
|
||||
struct mac_param mac_param;
|
||||
int i;
|
||||
|
||||
neigh.type = ND_NEIGHBOR_SOLICIT;
|
||||
neigh.code = 0;
|
||||
neigh.reserved = 0;
|
||||
neigh.target = *client;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.sin6_len = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
addr.sin6_family = AF_INET6;
|
||||
addr.sin6_port = htons(IPPROTO_ICMPV6);
|
||||
addr.sin6_addr = *client;
|
||||
addr.sin6_scope_id = iface;
|
||||
|
||||
mac_param.target = client;
|
||||
mac_param.maclen = 0;
|
||||
mac_param.mac = mac;
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
iface_enumerate(AF_UNSPEC, &mac_param, find_mac);
|
||||
|
||||
if (mac_param.maclen != 0)
|
||||
break;
|
||||
|
||||
sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, (struct sockaddr *)&addr, sizeof(addr));
|
||||
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 100000000; /* 100ms */
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
|
||||
*maclenp = mac_param.maclen;
|
||||
*mactypep = ARPHRD_ETHER;
|
||||
}
|
||||
|
||||
static int find_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
|
||||
{
|
||||
struct mac_param *parm = parmv;
|
||||
|
||||
if (family == AF_INET6 && IN6_ARE_ADDR_EQUAL(parm->target, (struct in6_addr *)addrp))
|
||||
{
|
||||
if (maclen <= DHCP_CHADDR_MAX)
|
||||
{
|
||||
parm->maclen = maclen;
|
||||
memcpy(parm->mac, mac, maclen);
|
||||
}
|
||||
|
||||
return 0; /* found, abort */
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int complete_context6(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam)
|
||||
int scope, int if_index, int flags, unsigned int preferred,
|
||||
unsigned int valid, void *vparam)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
struct dhcp_relay *relay;
|
||||
struct iface_param *param = vparam;
|
||||
struct iname *tmp;
|
||||
|
||||
(void)scope; /* warning */
|
||||
(void)dad;
|
||||
|
||||
if (if_index == param->ind &&
|
||||
!IN6_IS_ADDR_LOOPBACK(local) &&
|
||||
!IN6_IS_ADDR_LINKLOCAL(local) &&
|
||||
!IN6_IS_ADDR_MULTICAST(local))
|
||||
|
||||
if (if_index == param->ind)
|
||||
{
|
||||
/* if we have --listen-address config, see if the
|
||||
arrival interface has a matching address. */
|
||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
if (tmp->addr.sa.sa_family == AF_INET6 &&
|
||||
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
|
||||
param->addr_match = 1;
|
||||
|
||||
/* Determine a globally address on the arrival interface, even
|
||||
if we have no matching dhcp-context, because we're only
|
||||
allocating on remote subnets via relays. This
|
||||
is used as a default for the DNS server option. */
|
||||
param->fallback = *local;
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (IN6_IS_ADDR_LINKLOCAL(local))
|
||||
param->ll_addr = *local;
|
||||
else if (IN6_IS_ADDR_ULA(local))
|
||||
param->ula_addr = *local;
|
||||
|
||||
if (!IN6_IS_ADDR_LOOPBACK(local) &&
|
||||
!IN6_IS_ADDR_LINKLOCAL(local) &&
|
||||
!IN6_IS_ADDR_MULTICAST(local))
|
||||
{
|
||||
if (prefix == context->prefix &&
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix))
|
||||
/* if we have --listen-address config, see if the
|
||||
arrival interface has a matching address. */
|
||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
if (tmp->addr.sa.sa_family == AF_INET6 &&
|
||||
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
|
||||
param->addr_match = 1;
|
||||
|
||||
/* Determine a globally address on the arrival interface, even
|
||||
if we have no matching dhcp-context, because we're only
|
||||
allocating on remote subnets via relays. This
|
||||
is used as a default for the DNS server option. */
|
||||
param->fallback = *local;
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
{
|
||||
/* link it onto the current chain if we've not seen it before */
|
||||
if (context->current == context)
|
||||
if ((context->flags & CONTEXT_DHCP) &&
|
||||
!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
|
||||
prefix <= context->prefix &&
|
||||
is_same_net6(local, &context->start6, context->prefix) &&
|
||||
is_same_net6(local, &context->end6, context->prefix))
|
||||
{
|
||||
context->current = param->current;
|
||||
param->current = context;
|
||||
context->local6 = *local;
|
||||
|
||||
|
||||
/* link it onto the current chain if we've not seen it before */
|
||||
if (context->current == context)
|
||||
{
|
||||
struct dhcp_context *tmp, **up;
|
||||
|
||||
/* use interface values only for contructed contexts */
|
||||
if (!(context->flags & CONTEXT_CONSTRUCTED))
|
||||
preferred = valid = 0xffffffff;
|
||||
else if (flags & IFACE_DEPRECATED)
|
||||
preferred = 0;
|
||||
|
||||
if (context->flags & CONTEXT_DEPRECATE)
|
||||
preferred = 0;
|
||||
|
||||
/* order chain, longest preferred time first */
|
||||
for (up = ¶m->current, tmp = param->current; tmp; tmp = tmp->current)
|
||||
if (tmp->preferred <= preferred)
|
||||
break;
|
||||
else
|
||||
up = &tmp->current;
|
||||
|
||||
context->current = *up;
|
||||
*up = context;
|
||||
context->local6 = *local;
|
||||
context->preferred = preferred;
|
||||
context->valid = valid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (relay = daemon->relay6; relay; relay = relay->next)
|
||||
if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr.addr6) && relay->current == relay &&
|
||||
(IN6_IS_ADDR_UNSPECIFIED(¶m->relay_local) || IN6_ARE_ADDR_EQUAL(local, ¶m->relay_local)))
|
||||
{
|
||||
relay->current = param->relay;
|
||||
param->relay = relay;
|
||||
param->relay_local = *local;
|
||||
}
|
||||
|
||||
}
|
||||
return 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, u64 addr)
|
||||
@@ -240,8 +401,8 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
|
||||
int serial, struct dhcp_netid *netids, struct in6_addr *ans)
|
||||
struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len, int temp_addr,
|
||||
int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans)
|
||||
{
|
||||
/* Find a free address: exclude anything in use and anything allocated to
|
||||
a particular hwaddr/clientid/hostname in our configuration.
|
||||
@@ -257,23 +418,27 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
|
||||
u64 j;
|
||||
|
||||
/* hash hwaddr: use the SDBM hashing algorithm. This works
|
||||
for MAC addresses, let's see how it manages with client-ids! */
|
||||
for (j = 0, i = 0; i < clid_len; i++)
|
||||
j += clid[i] + (j << 6) + (j << 16) - j;
|
||||
for MAC addresses, let's see how it manages with client-ids!
|
||||
For temporary addresses, we generate a new random one each time. */
|
||||
if (temp_addr)
|
||||
j = rand64();
|
||||
else
|
||||
for (j = iaid, i = 0; i < clid_len; i++)
|
||||
j += clid[i] + (j << 6) + (j << 16) - j;
|
||||
|
||||
for (pass = 0; pass <= 1; pass++)
|
||||
for (pass = 0; pass <= plain_range ? 1 : 0; pass++)
|
||||
for (c = context; c; c = c->current)
|
||||
if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS))
|
||||
if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS | CONTEXT_USED))
|
||||
continue;
|
||||
else if (!match_netid(c->filter, netids, pass))
|
||||
continue;
|
||||
else
|
||||
{
|
||||
if (option_bool(OPT_CONSEC_ADDR))
|
||||
if (!temp_addr && option_bool(OPT_CONSEC_ADDR))
|
||||
/* seed is largest extant lease addr in this context */
|
||||
start = lease_find_max_addr6(c) + serial;
|
||||
else
|
||||
start = addr6part(&c->start6) + ((j + c->addr_epoch + serial) % (1 + addr6part(&c->end6) - addr6part(&c->start6)));
|
||||
start = addr6part(&c->start6) + ((j + c->addr_epoch) % (1 + addr6part(&c->end6) - addr6part(&c->start6)));
|
||||
|
||||
/* iterate until we find a free address. */
|
||||
addr = start;
|
||||
@@ -290,7 +455,7 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
|
||||
{
|
||||
*ans = c->start6;
|
||||
setaddr6part (ans, addr);
|
||||
return 1;
|
||||
return c;
|
||||
}
|
||||
|
||||
addr++;
|
||||
@@ -300,13 +465,15 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
|
||||
|
||||
} while (addr != start);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* can dynamically allocate addr */
|
||||
struct dhcp_context *address6_available(struct dhcp_context *context,
|
||||
struct in6_addr *taddr,
|
||||
struct dhcp_netid *netids)
|
||||
struct dhcp_netid *netids,
|
||||
int plain_range)
|
||||
{
|
||||
u64 start, end, addr = addr6part(taddr);
|
||||
struct dhcp_context *tmp;
|
||||
@@ -321,100 +488,54 @@ struct dhcp_context *address6_available(struct dhcp_context *context,
|
||||
is_same_net6(&tmp->end6, taddr, tmp->prefix) &&
|
||||
addr >= start &&
|
||||
addr <= end &&
|
||||
match_netid(tmp->filter, netids, 1))
|
||||
match_netid(tmp->filter, netids, plain_range))
|
||||
return tmp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct dhcp_context *narrow_context6(struct dhcp_context *context,
|
||||
struct in6_addr *taddr,
|
||||
struct dhcp_netid *netids)
|
||||
/* address OK if configured */
|
||||
struct dhcp_context *address6_valid(struct dhcp_context *context,
|
||||
struct in6_addr *taddr,
|
||||
struct dhcp_netid *netids,
|
||||
int plain_range)
|
||||
{
|
||||
/* We start of with a set of possible contexts, all on the current physical interface.
|
||||
These are chained on ->current.
|
||||
Here we have an address, and return the actual context correponding to that
|
||||
address. Note that none may fit, if the address came a dhcp-host and is outside
|
||||
any dhcp-range. In that case we return a static range if possible, or failing that,
|
||||
any context on the correct subnet. (If there's more than one, this is a dodgy
|
||||
configuration: maybe there should be a warning.) */
|
||||
|
||||
struct dhcp_context *tmp;
|
||||
|
||||
if (!(tmp = address6_available(context, taddr, netids)))
|
||||
{
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
if (match_netid(tmp->filter, netids, 1) &&
|
||||
is_same_net6(taddr, &tmp->start6, tmp->prefix) &&
|
||||
(tmp->flags & CONTEXT_STATIC))
|
||||
break;
|
||||
|
||||
if (!tmp)
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
if (match_netid(tmp->filter, netids, 1) &&
|
||||
is_same_net6(taddr, &tmp->start6, tmp->prefix) &&
|
||||
!(tmp->flags & CONTEXT_PROXY))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Only one context allowed now */
|
||||
if (tmp)
|
||||
tmp->current = NULL;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static int is_config_in_context6(struct dhcp_context *context, struct dhcp_config *config)
|
||||
{
|
||||
if (!context) /* called via find_config() from lease_update_from_configs() */
|
||||
return 1;
|
||||
if (!(config->flags & CONFIG_ADDR6) || is_addr_in_context6(context, &config->addr6))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int is_addr_in_context6(struct dhcp_context *context, struct in6_addr *addr)
|
||||
{
|
||||
for (; context; context = context->current)
|
||||
if (is_same_net6(addr, &context->start6, context->prefix))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct dhcp_config *find_config6(struct dhcp_config *configs,
|
||||
struct dhcp_context *context,
|
||||
unsigned char *duid, int duid_len,
|
||||
char *hostname)
|
||||
{
|
||||
struct dhcp_config *config;
|
||||
|
||||
if (duid)
|
||||
for (config = configs; config; config = config->next)
|
||||
if (config->flags & CONFIG_CLID)
|
||||
{
|
||||
if (config->clid_len == duid_len &&
|
||||
memcmp(config->clid, duid, duid_len) == 0 &&
|
||||
is_config_in_context6(context, config))
|
||||
return config;
|
||||
}
|
||||
|
||||
if (hostname && context)
|
||||
for (config = configs; config; config = config->next)
|
||||
if ((config->flags & CONFIG_NAME) &&
|
||||
hostname_isequal(config->hostname, hostname) &&
|
||||
is_config_in_context6(context, config))
|
||||
return config;
|
||||
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
if (is_same_net6(&tmp->start6, taddr, tmp->prefix) &&
|
||||
match_netid(tmp->filter, netids, plain_range))
|
||||
return tmp;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr)
|
||||
{
|
||||
if (!config || !(config->flags & CONFIG_ADDR6))
|
||||
return 0;
|
||||
|
||||
if ((config->flags & CONFIG_WILDCARD) && context->prefix == 64)
|
||||
{
|
||||
*addr = context->start6;
|
||||
setaddr6part(addr, addr6part(&config->addr6));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (is_same_net6(&context->start6, &config->addr6, context->prefix))
|
||||
{
|
||||
*addr = config->addr6;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void make_duid(time_t now)
|
||||
{
|
||||
(void)now;
|
||||
|
||||
if (daemon->duid_config)
|
||||
{
|
||||
unsigned char *p;
|
||||
@@ -427,8 +548,14 @@ void make_duid(time_t now)
|
||||
}
|
||||
else
|
||||
{
|
||||
time_t newnow = 0;
|
||||
|
||||
/* If we have no persistent lease database, or a non-stable RTC, use DUID_LL (newnow == 0) */
|
||||
#ifndef HAVE_BROKEN_RTC
|
||||
/* rebase epoch to 1/1/2000 */
|
||||
time_t newnow = now - 946684800;
|
||||
if (!option_bool(OPT_LEASE_RO) || daemon->lease_change_command)
|
||||
newnow = now - 946684800;
|
||||
#endif
|
||||
|
||||
iface_enumerate(AF_LOCAL, &newnow, make_duid1);
|
||||
|
||||
@@ -446,27 +573,207 @@ static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, vo
|
||||
|
||||
unsigned char *p;
|
||||
(void)index;
|
||||
|
||||
(void)parm;
|
||||
time_t newnow = *((time_t *)parm);
|
||||
|
||||
if (type >= 256)
|
||||
return 1;
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
daemon->duid = p = safe_malloc(maclen + 4);
|
||||
daemon->duid_len = maclen + 4;
|
||||
PUTSHORT(3, p); /* DUID_LL */
|
||||
PUTSHORT(type, p); /* address type */
|
||||
#else
|
||||
daemon->duid = p = safe_malloc(maclen + 8);
|
||||
daemon->duid_len = maclen + 8;
|
||||
PUTSHORT(1, p); /* DUID_LLT */
|
||||
PUTSHORT(type, p); /* address type */
|
||||
PUTLONG(*((time_t *)parm), p); /* time */
|
||||
#endif
|
||||
|
||||
if (newnow == 0)
|
||||
{
|
||||
daemon->duid = p = safe_malloc(maclen + 4);
|
||||
daemon->duid_len = maclen + 4;
|
||||
PUTSHORT(3, p); /* DUID_LL */
|
||||
PUTSHORT(type, p); /* address type */
|
||||
}
|
||||
else
|
||||
{
|
||||
daemon->duid = p = safe_malloc(maclen + 8);
|
||||
daemon->duid_len = maclen + 8;
|
||||
PUTSHORT(1, p); /* DUID_LLT */
|
||||
PUTSHORT(type, p); /* address type */
|
||||
PUTLONG(*((time_t *)parm), p); /* time */
|
||||
}
|
||||
|
||||
memcpy(p, mac, maclen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct cparam {
|
||||
time_t now;
|
||||
int newone, newname;
|
||||
};
|
||||
|
||||
static int construct_worker(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int flags,
|
||||
int preferred, int valid, void *vparam)
|
||||
{
|
||||
char ifrn_name[IFNAMSIZ];
|
||||
struct in6_addr start6, end6;
|
||||
struct dhcp_context *template, *context;
|
||||
|
||||
(void)scope;
|
||||
(void)flags;
|
||||
(void)valid;
|
||||
(void)preferred;
|
||||
|
||||
struct cparam *param = vparam;
|
||||
|
||||
if (IN6_IS_ADDR_LOOPBACK(local) ||
|
||||
IN6_IS_ADDR_LINKLOCAL(local) ||
|
||||
IN6_IS_ADDR_MULTICAST(local))
|
||||
return 1;
|
||||
|
||||
if (!(flags & IFACE_PERMANENT))
|
||||
return 1;
|
||||
|
||||
if (flags & IFACE_DEPRECATED)
|
||||
return 1;
|
||||
|
||||
if (!indextoname(daemon->icmp6fd, if_index, ifrn_name))
|
||||
return 0;
|
||||
|
||||
for (template = daemon->dhcp6; template; template = template->next)
|
||||
if (!(template->flags & CONTEXT_TEMPLATE))
|
||||
{
|
||||
/* non-template entries, just fill in interface and local addresses */
|
||||
if (prefix <= template->prefix &&
|
||||
is_same_net6(local, &template->start6, template->prefix) &&
|
||||
is_same_net6(local, &template->end6, template->prefix))
|
||||
{
|
||||
template->if_index = if_index;
|
||||
template->local6 = *local;
|
||||
}
|
||||
|
||||
}
|
||||
else if (wildcard_match(template->template_interface, ifrn_name) &&
|
||||
template->prefix >= prefix)
|
||||
{
|
||||
start6 = *local;
|
||||
setaddr6part(&start6, addr6part(&template->start6));
|
||||
end6 = *local;
|
||||
setaddr6part(&end6, addr6part(&template->end6));
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_CONSTRUCTED) &&
|
||||
IN6_ARE_ADDR_EQUAL(&start6, &context->start6) &&
|
||||
IN6_ARE_ADDR_EQUAL(&end6, &context->end6))
|
||||
{
|
||||
int flags = context->flags;
|
||||
context->flags &= ~(CONTEXT_GC | CONTEXT_OLD);
|
||||
if (flags & CONTEXT_OLD)
|
||||
{
|
||||
/* address went, now it's back */
|
||||
log_context(AF_INET6, context);
|
||||
/* fast RAs for a while */
|
||||
ra_start_unsolicted(param->now, context);
|
||||
param->newone = 1;
|
||||
/* Add address to name again */
|
||||
if (context->flags & CONTEXT_RA_NAME)
|
||||
param->newname = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!context && (context = whine_malloc(sizeof (struct dhcp_context))))
|
||||
{
|
||||
*context = *template;
|
||||
context->start6 = start6;
|
||||
context->end6 = end6;
|
||||
context->flags &= ~CONTEXT_TEMPLATE;
|
||||
context->flags |= CONTEXT_CONSTRUCTED;
|
||||
context->if_index = if_index;
|
||||
context->local6 = *local;
|
||||
context->saved_valid = 0;
|
||||
|
||||
context->next = daemon->dhcp6;
|
||||
daemon->dhcp6 = context;
|
||||
|
||||
ra_start_unsolicted(param->now, context);
|
||||
/* we created a new one, need to call
|
||||
lease_update_file to get periodic functions called */
|
||||
param->newone = 1;
|
||||
|
||||
/* Will need to add new putative SLAAC addresses to existing leases */
|
||||
if (context->flags & CONTEXT_RA_NAME)
|
||||
param->newname = 1;
|
||||
|
||||
log_context(AF_INET6, context);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dhcp_construct_contexts(time_t now)
|
||||
{
|
||||
struct dhcp_context *context, *tmp, **up;
|
||||
struct cparam param;
|
||||
param.newone = 0;
|
||||
param.newname = 0;
|
||||
param.now = now;
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (context->flags & CONTEXT_CONSTRUCTED)
|
||||
context->flags |= CONTEXT_GC;
|
||||
|
||||
iface_enumerate(AF_INET6, ¶m, construct_worker);
|
||||
|
||||
for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
|
||||
{
|
||||
|
||||
tmp = context->next;
|
||||
|
||||
if (context->flags & CONTEXT_GC && !(context->flags & CONTEXT_OLD))
|
||||
{
|
||||
if ((context->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)) ||
|
||||
option_bool(OPT_RA))
|
||||
{
|
||||
/* previously constructed context has gone. advertise it's demise */
|
||||
context->flags |= CONTEXT_OLD;
|
||||
context->address_lost_time = now;
|
||||
/* Apply same ceiling of configured lease time as in radv.c */
|
||||
if (context->saved_valid > context->lease_time)
|
||||
context->saved_valid = context->lease_time;
|
||||
/* maximum time is 2 hours, from RFC */
|
||||
if (context->saved_valid > 7200) /* 2 hours */
|
||||
context->saved_valid = 7200;
|
||||
ra_start_unsolicted(now, context);
|
||||
param.newone = 1; /* include deletion */
|
||||
|
||||
if (context->flags & CONTEXT_RA_NAME)
|
||||
param.newname = 1;
|
||||
|
||||
log_context(AF_INET6, context);
|
||||
|
||||
up = &context->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we were never doing RA for this, so free now */
|
||||
*up = context->next;
|
||||
free(context);
|
||||
}
|
||||
}
|
||||
else
|
||||
up = &context->next;
|
||||
}
|
||||
|
||||
if (param.newone)
|
||||
{
|
||||
if (daemon->dhcp || daemon->doing_dhcp6)
|
||||
{
|
||||
if (param.newname)
|
||||
lease_update_slaac(now);
|
||||
lease_update_file(now);
|
||||
}
|
||||
else
|
||||
/* Not doing DHCP, so no lease system, manage alarms for ra only */
|
||||
send_alarm(periodic_ra(now), now);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -36,25 +36,48 @@
|
||||
|
||||
#define C_IN 1 /* the arpa internet */
|
||||
#define C_CHAOS 3 /* for chaos net (MIT) */
|
||||
#define C_HESIOD 4 /* hesiod */
|
||||
#define C_ANY 255 /* wildcard match */
|
||||
|
||||
#define T_A 1
|
||||
#define T_NS 2
|
||||
#define T_NS 2
|
||||
#define T_MD 3
|
||||
#define T_MF 4
|
||||
#define T_CNAME 5
|
||||
#define T_SOA 6
|
||||
#define T_MB 7
|
||||
#define T_MG 8
|
||||
#define T_MR 9
|
||||
#define T_PTR 12
|
||||
#define T_MINFO 14
|
||||
#define T_MX 15
|
||||
#define T_TXT 16
|
||||
#define T_RP 17
|
||||
#define T_AFSDB 18
|
||||
#define T_RT 21
|
||||
#define T_SIG 24
|
||||
#define T_PX 26
|
||||
#define T_AAAA 28
|
||||
#define T_NXT 30
|
||||
#define T_SRV 33
|
||||
#define T_NAPTR 35
|
||||
#define T_KX 36
|
||||
#define T_DNAME 39
|
||||
#define T_OPT 41
|
||||
#define T_DS 43
|
||||
#define T_RRSIG 46
|
||||
#define T_NSEC 47
|
||||
#define T_DNSKEY 48
|
||||
#define T_NSEC3 50
|
||||
#define T_TKEY 249
|
||||
#define T_TSIG 250
|
||||
#define T_AXFR 252
|
||||
#define T_MAILB 253
|
||||
#define T_ANY 255
|
||||
|
||||
#define EDNS0_OPTION_MAC 65001 /* dyndns.org temporary assignment */
|
||||
#define EDNS0_OPTION_CLIENT_SUBNET 8 /* IANA */
|
||||
|
||||
struct dns_header {
|
||||
u16 id;
|
||||
u8 hb3,hb4;
|
||||
@@ -73,6 +96,8 @@ struct dns_header {
|
||||
#define HB4_RCODE 0x0f
|
||||
|
||||
#define OPCODE(x) (((x)->hb3 & HB3_OPCODE) >> 3)
|
||||
#define SET_OPCODE(x, code) (x)->hb3 = ((x)->hb3 & ~HB3_OPCODE) | code
|
||||
|
||||
#define RCODE(x) ((x)->hb4 & HB4_RCODE)
|
||||
#define SET_RCODE(x, code) (x)->hb4 = ((x)->hb4 & ~HB4_RCODE) | code
|
||||
|
||||
@@ -112,3 +137,8 @@ struct dns_header {
|
||||
(cp) += 4; \
|
||||
}
|
||||
|
||||
#define CHECK_LEN(header, pp, plen, len) \
|
||||
((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen))
|
||||
|
||||
#define ADD_RDLEN(header, pp, plen, len) \
|
||||
(!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1))
|
||||
|
||||
489
src/dnsmasq.c
489
src/dnsmasq.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -50,7 +50,13 @@ int main (int argc, char **argv)
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
cap_user_header_t hdr = NULL;
|
||||
cap_user_data_t data = NULL;
|
||||
char *bound_device = NULL;
|
||||
int did_bind = 0;
|
||||
#endif
|
||||
#if defined(HAVE_DHCP) || defined(HAVE_DHCP6)
|
||||
struct dhcp_context *context;
|
||||
struct dhcp_relay *relay;
|
||||
#endif
|
||||
|
||||
#ifdef LOCALEDIR
|
||||
setlocale(LC_ALL, "");
|
||||
@@ -75,14 +81,28 @@ int main (int argc, char **argv)
|
||||
umask(022); /* known umask, create leases and pid files as 0644 */
|
||||
|
||||
read_opts(argc, argv, compile_opts);
|
||||
|
||||
|
||||
if (daemon->edns_pktsz < PACKETSZ)
|
||||
daemon->edns_pktsz = PACKETSZ;
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* Enforce min packet big enough for DNSSEC */
|
||||
if (option_bool(OPT_DNSSEC_VALID) && daemon->edns_pktsz < EDNS_PKTSZ)
|
||||
daemon->edns_pktsz = EDNS_PKTSZ;
|
||||
#endif
|
||||
|
||||
daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
|
||||
daemon->edns_pktsz : DNSMASQ_PACKETSZ;
|
||||
daemon->packet = safe_malloc(daemon->packet_buff_sz);
|
||||
|
||||
|
||||
daemon->addrbuff = safe_malloc(ADDRSTRLEN);
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
{
|
||||
daemon->keyname = safe_malloc(MAXDNAME);
|
||||
daemon->workspacename = safe_malloc(MAXDNAME);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (!daemon->lease_file)
|
||||
@@ -124,6 +144,19 @@ int main (int argc, char **argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
{
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (!daemon->ds)
|
||||
die(_("No trust anchors provided for DNSSEC"), NULL, EC_BADCONF);
|
||||
|
||||
if (daemon->cachesize < CACHESIZ)
|
||||
die(_("Cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF);
|
||||
#else
|
||||
die(_("DNSSEC not available: set HAVE_DNSSEC in src/config.h"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef HAVE_TFTP
|
||||
if (option_bool(OPT_TFTP))
|
||||
die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
|
||||
@@ -147,70 +180,82 @@ int main (int argc, char **argv)
|
||||
die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_AUTH
|
||||
if (daemon->authserver)
|
||||
die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
rand_init();
|
||||
|
||||
now = dnsmasq_time();
|
||||
|
||||
/* Create a serial at startup if not configured. */
|
||||
if (daemon->authinterface && daemon->soa_sn == 0)
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
die(_("zone serial must be configured in --auth-soa"), NULL, EC_BADCONF);
|
||||
#else
|
||||
daemon->soa_sn = now;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->dhcp6)
|
||||
{
|
||||
daemon->doing_ra = option_bool(OPT_RA);
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
{
|
||||
if (context->flags & CONTEXT_DHCP)
|
||||
daemon->doing_dhcp6 = 1;
|
||||
if (context->flags & CONTEXT_RA)
|
||||
daemon->doing_ra = 1;
|
||||
#if !defined(HAVE_LINUX_NETWORK) && !defined(HAVE_BSD_NETWORK)
|
||||
if (context->flags & CONTEXT_TEMPLATE)
|
||||
die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp || daemon->dhcp6)
|
||||
/* Note that order matters here, we must call lease_init before
|
||||
creating any file descriptors which shouldn't be leaked
|
||||
to the lease-script init process. We need to call common_init
|
||||
before lease_init to allocate buffers it uses.*/
|
||||
if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || daemon->relay6)
|
||||
{
|
||||
/* Note that order matters here, we must call lease_init before
|
||||
creating any file descriptors which shouldn't be leaked
|
||||
to the lease-script init process. We need to call common_init
|
||||
before lease_init to allocate buffers it uses.*/
|
||||
dhcp_common_init();
|
||||
lease_init(now);
|
||||
|
||||
if (daemon->dhcp)
|
||||
dhcp_init();
|
||||
if (daemon->dhcp || daemon->doing_dhcp6)
|
||||
lease_init(now);
|
||||
}
|
||||
|
||||
if (daemon->dhcp || daemon->relay4)
|
||||
dhcp_init();
|
||||
|
||||
# ifdef HAVE_DHCP6
|
||||
/* Start RA subsystem if --enable-ra OR dhcp-range=<subnet>, ra-only */
|
||||
if (daemon->ra_contexts || option_bool(OPT_RA))
|
||||
{
|
||||
/* link the DHCP6 contexts to the ra-only ones so we can traverse them all
|
||||
from ->ra_contexts, but only the non-ra-onlies from ->dhcp6 */
|
||||
struct dhcp_context *context;
|
||||
|
||||
if (!daemon->ra_contexts)
|
||||
daemon->ra_contexts = daemon->dhcp6;
|
||||
else
|
||||
{
|
||||
for (context = daemon->ra_contexts; context->next; context = context->next);
|
||||
context->next = daemon->dhcp6;
|
||||
}
|
||||
ra_init(now);
|
||||
}
|
||||
|
||||
if (daemon->dhcp6)
|
||||
if (daemon->doing_ra || daemon->doing_dhcp6 || daemon->relay6)
|
||||
ra_init(now);
|
||||
|
||||
if (daemon->doing_dhcp6 || daemon->relay6)
|
||||
dhcp6_init();
|
||||
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* After lease_init */
|
||||
#ifdef HAVE_IPSET
|
||||
if (daemon->ipsets)
|
||||
ipset_init();
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
netlink_init();
|
||||
#elif defined(HAVE_BSD_NETWORK)
|
||||
route_init();
|
||||
#endif
|
||||
|
||||
if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
|
||||
die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
/* after netlink_init */
|
||||
if (daemon->ra_contexts || daemon->dhcp6)
|
||||
join_multicast();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
/* after netlink_init */
|
||||
if (daemon->dhcp || daemon->dhcp6)
|
||||
lease_find_interfaces(now);
|
||||
#endif
|
||||
|
||||
if (!enumerate_interfaces())
|
||||
|
||||
if (!enumerate_interfaces(1) || !enumerate_interfaces(0))
|
||||
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
|
||||
|
||||
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
|
||||
@@ -224,24 +269,50 @@ int main (int argc, char **argv)
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
|
||||
/* after enumerate_interfaces() */
|
||||
bound_device = whichdevice();
|
||||
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
bindtodevice(daemon->dhcpfd);
|
||||
if (daemon->enable_pxe)
|
||||
bindtodevice(daemon->pxefd);
|
||||
if (!daemon->relay4 && bound_device)
|
||||
{
|
||||
bindtodevice(bound_device, daemon->dhcpfd);
|
||||
did_bind = 1;
|
||||
}
|
||||
if (daemon->enable_pxe && bound_device)
|
||||
{
|
||||
bindtodevice(bound_device, daemon->pxefd);
|
||||
did_bind = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
|
||||
if (daemon->dhcp6)
|
||||
bindtodevice(daemon->dhcp6fd);
|
||||
if (daemon->doing_dhcp6 && !daemon->relay6 && bound_device)
|
||||
{
|
||||
bindtodevice(bound_device, daemon->dhcp6fd);
|
||||
did_bind = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
create_wildcard_listeners();
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
/* after enumerate_interfaces() */
|
||||
if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
|
||||
join_multicast(1);
|
||||
|
||||
/* After netlink_init() and before create_helper() */
|
||||
lease_make_duid(now);
|
||||
#endif
|
||||
|
||||
if (daemon->port != 0)
|
||||
cache_init();
|
||||
{
|
||||
cache_init();
|
||||
#ifdef HAVE_DNSSEC
|
||||
blockdata_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (option_bool(OPT_DBUS))
|
||||
#ifdef HAVE_DBUS
|
||||
@@ -326,7 +397,7 @@ int main (int argc, char **argv)
|
||||
piperead = pipefd[0];
|
||||
pipewrite = pipefd[1];
|
||||
/* prime the pipe to load stuff first time. */
|
||||
send_event(pipewrite, EVENT_RELOAD, 0, NULL);
|
||||
send_event(pipewrite, EVENT_INIT, 0, NULL);
|
||||
|
||||
err_pipe[1] = -1;
|
||||
|
||||
@@ -591,12 +662,29 @@ int main (int argc, char **argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (option_bool(OPT_LOCAL_SERVICE))
|
||||
my_syslog(LOG_INFO, _("DNS service limited to local subnets"));
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
{
|
||||
my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
|
||||
if (option_bool(OPT_DNSSEC_TIME))
|
||||
my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until first cache reload"));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (log_err != 0)
|
||||
my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
|
||||
daemon->log_file, strerror(log_err));
|
||||
|
||||
|
||||
if (bind_fallback)
|
||||
my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
|
||||
|
||||
if (option_bool(OPT_NOWILD))
|
||||
warn_bound_listeners();
|
||||
|
||||
warn_int_names();
|
||||
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||
@@ -614,90 +702,38 @@ int main (int argc, char **argv)
|
||||
|
||||
if (daemon->max_logs != 0)
|
||||
my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
|
||||
|
||||
if (daemon->ra_contexts)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
|
||||
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp || daemon->dhcp6 || daemon->ra_contexts)
|
||||
{
|
||||
struct dhcp_context *dhcp_tmp;
|
||||
int family = AF_INET;
|
||||
dhcp_tmp = daemon->dhcp;
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
again:
|
||||
#endif
|
||||
for (; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
|
||||
{
|
||||
void *start = &dhcp_tmp->start;
|
||||
void *end = &dhcp_tmp->end;
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (family == AF_INET6)
|
||||
{
|
||||
start = &dhcp_tmp->start6;
|
||||
end = &dhcp_tmp->end6;
|
||||
struct in6_addr subnet = dhcp_tmp->start6;
|
||||
setaddr6part(&subnet, 0);
|
||||
inet_ntop(AF_INET6, &subnet, daemon->dhcp_buff2, 256);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (family != AF_INET && (dhcp_tmp->flags & CONTEXT_DEPRECATE))
|
||||
strcpy(daemon->namebuff, _("prefix deprecated"));
|
||||
else
|
||||
{
|
||||
char *p = daemon->namebuff;
|
||||
p += sprintf(p, _("lease time "));
|
||||
prettyprint_time(p, dhcp_tmp->lease_time);
|
||||
}
|
||||
|
||||
inet_ntop(family, start, daemon->dhcp_buff, 256);
|
||||
inet_ntop(family, end, daemon->dhcp_buff3, 256);
|
||||
if ((dhcp_tmp->flags & CONTEXT_DHCP) || family == AF_INET)
|
||||
my_syslog(MS_DHCP | LOG_INFO,
|
||||
(dhcp_tmp->flags & CONTEXT_RA_STATELESS) ?
|
||||
_("%s stateless on %s%.0s%.0s") :
|
||||
(dhcp_tmp->flags & CONTEXT_STATIC) ?
|
||||
_("%s, static leases only on %.0s%s, %s") :
|
||||
(dhcp_tmp->flags & CONTEXT_PROXY) ?
|
||||
_("%s, proxy on subnet %.0s%s%.0s") :
|
||||
_("%s, IP range %s -- %s, %s"),
|
||||
(family != AF_INET) ? "DHCPv6" : "DHCP",
|
||||
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff);
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
log_context(AF_INET, context);
|
||||
|
||||
if (dhcp_tmp->flags & CONTEXT_RA_NAME)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s"),
|
||||
daemon->dhcp_buff2);
|
||||
if (dhcp_tmp->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS))
|
||||
{
|
||||
if (!(dhcp_tmp->flags & CONTEXT_DEPRECATE))
|
||||
{
|
||||
char *p = daemon->namebuff;
|
||||
p += sprintf(p, _("prefix valid "));
|
||||
prettyprint_time(p, dhcp_tmp->lease_time > 7200 ? dhcp_tmp->lease_time : 7200);
|
||||
}
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("SLAAC on %s %s"),
|
||||
daemon->dhcp_buff2, daemon->namebuff);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (family == AF_INET)
|
||||
{
|
||||
family = AF_INET6;
|
||||
if (daemon->ra_contexts)
|
||||
dhcp_tmp = daemon->ra_contexts;
|
||||
else
|
||||
dhcp_tmp = daemon->dhcp6;
|
||||
goto again;
|
||||
}
|
||||
#endif
|
||||
for (relay = daemon->relay4; relay; relay = relay->next)
|
||||
log_relay(AF_INET, relay);
|
||||
|
||||
}
|
||||
#endif
|
||||
# ifdef HAVE_DHCP6
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
log_context(AF_INET6, context);
|
||||
|
||||
for (relay = daemon->relay6; relay; relay = relay->next)
|
||||
log_relay(AF_INET6, relay);
|
||||
|
||||
if (daemon->doing_dhcp6 || daemon->doing_ra)
|
||||
dhcp_construct_contexts(now);
|
||||
|
||||
if (option_bool(OPT_RA))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
|
||||
# endif
|
||||
|
||||
# ifdef HAVE_LINUX_NETWORK
|
||||
if (did_bind)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface %s"), bound_device);
|
||||
# endif
|
||||
|
||||
/* after dhcp_contruct_contexts */
|
||||
if (daemon->dhcp || daemon->doing_dhcp6)
|
||||
lease_find_interfaces(now);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
if (option_bool(OPT_TFTP))
|
||||
@@ -791,7 +827,7 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp)
|
||||
if (daemon->dhcp || daemon->relay4)
|
||||
{
|
||||
FD_SET(daemon->dhcpfd, &rset);
|
||||
bump_maxfd(daemon->dhcpfd, &maxfd);
|
||||
@@ -804,24 +840,27 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->dhcp6)
|
||||
if (daemon->doing_dhcp6 || daemon->relay6)
|
||||
{
|
||||
FD_SET(daemon->dhcp6fd, &rset);
|
||||
bump_maxfd(daemon->dhcp6fd, &maxfd);
|
||||
}
|
||||
|
||||
if (daemon->ra_contexts)
|
||||
if (daemon->doing_ra)
|
||||
{
|
||||
FD_SET(daemon->icmp6fd, &rset);
|
||||
bump_maxfd(daemon->icmp6fd, &maxfd);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
FD_SET(daemon->netlinkfd, &rset);
|
||||
bump_maxfd(daemon->netlinkfd, &maxfd);
|
||||
#elif defined(HAVE_BSD_NETWORK)
|
||||
FD_SET(daemon->routefd, &rset);
|
||||
bump_maxfd(daemon->routefd, &maxfd);
|
||||
#endif
|
||||
|
||||
|
||||
FD_SET(piperead, &rset);
|
||||
bump_maxfd(piperead, &maxfd);
|
||||
|
||||
@@ -862,19 +901,26 @@ int main (int argc, char **argv)
|
||||
now = dnsmasq_time();
|
||||
|
||||
check_log_writer(&wset);
|
||||
|
||||
|
||||
/* prime. */
|
||||
enumerate_interfaces(1);
|
||||
|
||||
/* Check the interfaces to see if any have exited DAD state
|
||||
and if so, bind the address. */
|
||||
if (is_dad_listeners())
|
||||
{
|
||||
enumerate_interfaces();
|
||||
enumerate_interfaces(0);
|
||||
/* NB, is_dad_listeners() == 1 --> we're binding interfaces */
|
||||
create_bound_listeners(0);
|
||||
warn_bound_listeners();
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
if (FD_ISSET(daemon->netlinkfd, &rset))
|
||||
netlink_multicast();
|
||||
netlink_multicast(now);
|
||||
#elif defined(HAVE_BSD_NETWORK)
|
||||
if (FD_ISSET(daemon->routefd, &rset))
|
||||
route_sock(now);
|
||||
#endif
|
||||
|
||||
/* Check for changes to resolv files once per second max. */
|
||||
@@ -913,7 +959,7 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp)
|
||||
if (daemon->dhcp || daemon->relay4)
|
||||
{
|
||||
if (FD_ISSET(daemon->dhcpfd, &rset))
|
||||
dhcp_packet(now, 0);
|
||||
@@ -922,11 +968,11 @@ int main (int argc, char **argv)
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->dhcp6 && FD_ISSET(daemon->dhcp6fd, &rset))
|
||||
if ((daemon->doing_dhcp6 || daemon->relay6) && FD_ISSET(daemon->dhcp6fd, &rset))
|
||||
dhcp6_packet(now);
|
||||
|
||||
if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
|
||||
icmp6_packet();
|
||||
if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
|
||||
icmp6_packet(now);
|
||||
#endif
|
||||
|
||||
# ifdef HAVE_SCRIPT
|
||||
@@ -1078,7 +1124,7 @@ static void async_event(int pipe, time_t now)
|
||||
{
|
||||
pid_t p;
|
||||
struct event_desc ev;
|
||||
int i;
|
||||
int i, check = 0;
|
||||
char *msg;
|
||||
|
||||
/* NOTE: the memory used to return msg is leaked: use msgs in events only
|
||||
@@ -1088,12 +1134,36 @@ static void async_event(int pipe, time_t now)
|
||||
switch (ev.event)
|
||||
{
|
||||
case EVENT_RELOAD:
|
||||
clear_cache_and_reload(now);
|
||||
if (daemon->port != 0 && daemon->resolv_files && option_bool(OPT_NO_POLL))
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
|
||||
{
|
||||
reload_servers(daemon->resolv_files->name);
|
||||
check_servers();
|
||||
my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
|
||||
reset_option_bool(OPT_DNSSEC_TIME);
|
||||
}
|
||||
#endif
|
||||
/* fall through */
|
||||
|
||||
case EVENT_INIT:
|
||||
clear_cache_and_reload(now);
|
||||
|
||||
if (daemon->port != 0)
|
||||
{
|
||||
if (daemon->resolv_files && option_bool(OPT_NO_POLL))
|
||||
{
|
||||
reload_servers(daemon->resolv_files->name);
|
||||
check = 1;
|
||||
}
|
||||
|
||||
if (daemon->servers_file)
|
||||
{
|
||||
read_servers_file();
|
||||
check = 1;
|
||||
}
|
||||
|
||||
if (check)
|
||||
check_servers();
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
rerun_scripts();
|
||||
#endif
|
||||
@@ -1106,13 +1176,13 @@ static void async_event(int pipe, time_t now)
|
||||
|
||||
case EVENT_ALARM:
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp || daemon->dhcp6)
|
||||
if (daemon->dhcp || daemon->doing_dhcp6)
|
||||
{
|
||||
lease_prune(NULL, now);
|
||||
lease_update_file(now);
|
||||
}
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (daemon->ra_contexts)
|
||||
else if (daemon->doing_ra)
|
||||
/* Not doing DHCP, so no lease system, manage alarms for ra only */
|
||||
send_alarm(periodic_ra(now), now);
|
||||
#endif
|
||||
@@ -1265,11 +1335,13 @@ void poll_resolv(int force, int do_reload, time_t now)
|
||||
|
||||
void clear_cache_and_reload(time_t now)
|
||||
{
|
||||
(void)now;
|
||||
|
||||
if (daemon->port != 0)
|
||||
cache_reload();
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp || daemon->dhcp6)
|
||||
if (daemon->dhcp || daemon->doing_dhcp6)
|
||||
{
|
||||
if (option_bool(OPT_ETHERS))
|
||||
dhcp_read_ethers();
|
||||
@@ -1280,7 +1352,7 @@ void clear_cache_and_reload(time_t now)
|
||||
lease_update_dns(1);
|
||||
}
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (daemon->ra_contexts)
|
||||
else if (daemon->doing_ra)
|
||||
/* Not doing DHCP, so no lease system, manage
|
||||
alarms for ra only */
|
||||
send_alarm(periodic_ra(now), now);
|
||||
@@ -1307,7 +1379,7 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
|
||||
|
||||
/* will we be able to get memory? */
|
||||
if (daemon->port != 0)
|
||||
get_new_frec(now, &wait);
|
||||
get_new_frec(now, &wait, 0);
|
||||
|
||||
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
{
|
||||
@@ -1384,7 +1456,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
|
||||
if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
|
||||
{
|
||||
int confd;
|
||||
int confd, client_ok = 1;
|
||||
struct irec *iface = NULL;
|
||||
pid_t p;
|
||||
union mysockaddr tcp_addr;
|
||||
@@ -1392,28 +1464,74 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
|
||||
while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
|
||||
|
||||
if (confd == -1 ||
|
||||
getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
|
||||
if (confd == -1)
|
||||
continue;
|
||||
|
||||
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
|
||||
iface = listener->iface; /* May be NULL */
|
||||
else
|
||||
if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
|
||||
{
|
||||
/* Check for allowed interfaces when binding the wildcard address:
|
||||
we do this by looking for an interface with the same address as
|
||||
the local address of the TCP connection, then looking to see if that's
|
||||
an allowed interface. As a side effect, we get the netmask of the
|
||||
interface too, for localisation. */
|
||||
|
||||
/* interface may be new since startup */
|
||||
if (enumerate_interfaces())
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (sockaddr_isequal(&iface->addr, &tcp_addr))
|
||||
break;
|
||||
close(confd);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!iface && !(option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND)))
|
||||
/* Make sure that the interface list is up-to-date.
|
||||
|
||||
We do this here as we may need the results below, and
|
||||
the DNS code needs them for --interface-name stuff.
|
||||
|
||||
Multiple calls to enumerate_interfaces() per select loop are
|
||||
inhibited, so calls to it in the child process (which doesn't select())
|
||||
have no effect. This avoids two processes reading from the same
|
||||
netlink fd and screwing the pooch entirely.
|
||||
*/
|
||||
|
||||
enumerate_interfaces(0);
|
||||
|
||||
if (option_bool(OPT_NOWILD))
|
||||
iface = listener->iface; /* May be NULL */
|
||||
else
|
||||
{
|
||||
int if_index;
|
||||
char intr_name[IF_NAMESIZE];
|
||||
|
||||
/* if we can find the arrival interface, check it's one that's allowed */
|
||||
if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
|
||||
indextoname(listener->tcpfd, if_index, intr_name))
|
||||
{
|
||||
struct all_addr addr;
|
||||
addr.addr.addr4 = tcp_addr.in.sin_addr;
|
||||
#ifdef HAVE_IPV6
|
||||
if (tcp_addr.sa.sa_family == AF_INET6)
|
||||
addr.addr.addr6 = tcp_addr.in6.sin6_addr;
|
||||
#endif
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->index == if_index)
|
||||
break;
|
||||
|
||||
if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
|
||||
client_ok = 0;
|
||||
}
|
||||
|
||||
if (option_bool(OPT_CLEVERBIND))
|
||||
iface = listener->iface; /* May be NULL */
|
||||
else
|
||||
{
|
||||
/* Check for allowed interfaces when binding the wildcard address:
|
||||
we do this by looking for an interface with the same address as
|
||||
the local address of the TCP connection, then looking to see if that's
|
||||
an allowed interface. As a side effect, we get the netmask of the
|
||||
interface too, for localisation. */
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (sockaddr_isequal(&iface->addr, &tcp_addr))
|
||||
break;
|
||||
|
||||
if (!iface)
|
||||
client_ok = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!client_ok)
|
||||
{
|
||||
shutdown(confd, SHUT_RDWR);
|
||||
close(confd);
|
||||
@@ -1440,11 +1558,18 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
struct server *s;
|
||||
int flags;
|
||||
struct in_addr netmask;
|
||||
int auth_dns;
|
||||
|
||||
if (iface)
|
||||
netmask = iface->netmask;
|
||||
{
|
||||
netmask = iface->netmask;
|
||||
auth_dns = iface->dns_auth;
|
||||
}
|
||||
else
|
||||
netmask.s_addr = 0;
|
||||
{
|
||||
netmask.s_addr = 0;
|
||||
auth_dns = 0;
|
||||
}
|
||||
|
||||
#ifndef NO_FORK
|
||||
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to
|
||||
@@ -1463,7 +1588,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
|
||||
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
|
||||
buff = tcp_request(confd, now, &tcp_addr, netmask);
|
||||
buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
|
||||
|
||||
shutdown(confd, SHUT_RDWR);
|
||||
close(confd);
|
||||
@@ -1576,7 +1701,7 @@ int icmp_ping(struct in_addr addr)
|
||||
set_log_writer(&wset, &maxfd);
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->ra_contexts)
|
||||
if (daemon->doing_ra)
|
||||
{
|
||||
FD_SET(daemon->icmp6fd, &rset);
|
||||
bump_maxfd(daemon->icmp6fd, &maxfd);
|
||||
@@ -1595,8 +1720,8 @@ int icmp_ping(struct in_addr addr)
|
||||
check_dns_listeners(&rset, now);
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
|
||||
icmp6_packet();
|
||||
if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
|
||||
icmp6_packet(now);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
|
||||
444
src/dnsmasq.h
444
src/dnsmasq.h
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -14,7 +14,7 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define COPYRIGHT "Copyright (c) 2000-2012 Simon Kelley"
|
||||
#define COPYRIGHT "Copyright (c) 2000-2014 Simon Kelley"
|
||||
|
||||
#ifndef NO_LARGEFILE
|
||||
/* Ensure we can use files >2GB (log files may grow this big) */
|
||||
@@ -50,12 +50,16 @@
|
||||
#include <getopt.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "ip6addr.h"
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long long u64;
|
||||
|
||||
#define countof(x) (long)(sizeof(x) / sizeof(x[0]))
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
#include "dns-protocol.h"
|
||||
#include "dhcp-protocol.h"
|
||||
#ifdef HAVE_DHCP6
|
||||
@@ -160,6 +164,7 @@ struct event_desc {
|
||||
#define EVENT_FORK_ERR 18
|
||||
#define EVENT_LUA_ERR 19
|
||||
#define EVENT_TFTP_ERR 20
|
||||
#define EVENT_INIT 21
|
||||
|
||||
/* Exit codes. */
|
||||
#define EC_GOOD 0
|
||||
@@ -213,7 +218,7 @@ struct event_desc {
|
||||
#define OPT_NO_OVERRIDE 30
|
||||
#define OPT_NO_REBIND 31
|
||||
#define OPT_ADD_MAC 32
|
||||
#define OPT_DNSSEC 33
|
||||
#define OPT_DNSSEC_PROXY 33
|
||||
#define OPT_CONSEC_ADDR 34
|
||||
#define OPT_CONNTRACK 35
|
||||
#define OPT_FQDN_UPDATE 36
|
||||
@@ -221,7 +226,16 @@ struct event_desc {
|
||||
#define OPT_TFTP_LC 38
|
||||
#define OPT_CLEVERBIND 39
|
||||
#define OPT_TFTP 40
|
||||
#define OPT_LAST 41
|
||||
#define OPT_CLIENT_SUBNET 41
|
||||
#define OPT_QUIET_DHCP 42
|
||||
#define OPT_QUIET_DHCP6 43
|
||||
#define OPT_QUIET_RA 44
|
||||
#define OPT_DNSSEC_VALID 45
|
||||
#define OPT_DNSSEC_TIME 46
|
||||
#define OPT_DNSSEC_DEBUG 47
|
||||
#define OPT_DNSSEC_NO_SIGN 48
|
||||
#define OPT_LOCAL_SERVICE 49
|
||||
#define OPT_LAST 50
|
||||
|
||||
/* extra flags for my_syslog, we use a couple of facilities since they are known
|
||||
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
|
||||
@@ -234,6 +248,12 @@ struct all_addr {
|
||||
#ifdef HAVE_IPV6
|
||||
struct in6_addr addr6;
|
||||
#endif
|
||||
/* for log_query */
|
||||
unsigned int keytag;
|
||||
/* for cache_insert if RRSIG, DNSKEY, DS */
|
||||
struct {
|
||||
unsigned short class, type;
|
||||
} dnssec;
|
||||
} addr;
|
||||
};
|
||||
|
||||
@@ -261,10 +281,19 @@ struct naptr {
|
||||
struct naptr *next;
|
||||
};
|
||||
|
||||
#define TXT_STAT_CACHESIZE 1
|
||||
#define TXT_STAT_INSERTS 2
|
||||
#define TXT_STAT_EVICTIONS 3
|
||||
#define TXT_STAT_MISSES 4
|
||||
#define TXT_STAT_HITS 5
|
||||
#define TXT_STAT_AUTH 6
|
||||
#define TXT_STAT_SERVERS 7
|
||||
|
||||
struct txt_record {
|
||||
char *name;
|
||||
unsigned char *txt;
|
||||
unsigned short class, len;
|
||||
int stat;
|
||||
struct txt_record *next;
|
||||
};
|
||||
|
||||
@@ -276,8 +305,38 @@ struct ptr_record {
|
||||
struct cname {
|
||||
char *alias, *target;
|
||||
struct cname *next;
|
||||
};
|
||||
|
||||
struct ds_config {
|
||||
char *name, *digest;
|
||||
int digestlen, class, algo, keytag, digest_type;
|
||||
struct ds_config *next;
|
||||
};
|
||||
|
||||
#define ADDRLIST_LITERAL 1
|
||||
#define ADDRLIST_IPV6 2
|
||||
|
||||
struct addrlist {
|
||||
struct all_addr addr;
|
||||
int flags, prefixlen;
|
||||
struct addrlist *next;
|
||||
};
|
||||
|
||||
#define AUTH6 1
|
||||
#define AUTH4 2
|
||||
|
||||
struct auth_zone {
|
||||
char *domain;
|
||||
struct auth_name_list {
|
||||
char *name;
|
||||
int flags;
|
||||
struct auth_name_list *next;
|
||||
} *interface_names;
|
||||
struct addrlist *subnet;
|
||||
struct auth_zone *next;
|
||||
};
|
||||
|
||||
|
||||
struct host_record {
|
||||
struct name_list {
|
||||
char *name;
|
||||
@@ -293,6 +352,8 @@ struct host_record {
|
||||
struct interface_name {
|
||||
char *name; /* domain name */
|
||||
char *intr; /* interface name */
|
||||
int family; /* AF_INET, AF_INET6 or zero for both */
|
||||
struct addrlist *addr;
|
||||
struct interface_name *next;
|
||||
};
|
||||
|
||||
@@ -301,8 +362,8 @@ union bigname {
|
||||
union bigname *next; /* freelist */
|
||||
};
|
||||
|
||||
struct keydata {
|
||||
struct keydata *next;
|
||||
struct blockdata {
|
||||
struct blockdata *next;
|
||||
unsigned char key[KEYBLOCK_LEN];
|
||||
};
|
||||
|
||||
@@ -312,19 +373,32 @@ struct crec {
|
||||
union {
|
||||
struct all_addr addr;
|
||||
struct {
|
||||
struct crec *cache;
|
||||
int uid;
|
||||
union {
|
||||
struct crec *cache;
|
||||
struct interface_name *int_name;
|
||||
} target;
|
||||
unsigned int uid; /* 0 if union is interface-name */
|
||||
} cname;
|
||||
struct {
|
||||
struct keydata *keydata;
|
||||
struct blockdata *keydata;
|
||||
unsigned short keylen, flags, keytag;
|
||||
unsigned char algo;
|
||||
unsigned char digest; /* DS only */
|
||||
unsigned short flags_or_keyid; /* flags for DNSKEY, keyid for DS */
|
||||
} key;
|
||||
} key;
|
||||
struct {
|
||||
struct blockdata *keydata;
|
||||
unsigned short keylen, keytag;
|
||||
unsigned char algo;
|
||||
unsigned char digest;
|
||||
} ds;
|
||||
struct {
|
||||
struct blockdata *keydata;
|
||||
unsigned short keylen, type_covered, keytag;
|
||||
char algo;
|
||||
} sig;
|
||||
} addr;
|
||||
time_t ttd; /* time to die */
|
||||
/* used as keylen if F_DS or F_DNSKEY, index to source for F_HOSTS */
|
||||
int uid;
|
||||
/* used as class if DNSKEY/DS/RRSIG, index to source for F_HOSTS */
|
||||
unsigned int uid;
|
||||
unsigned short flags;
|
||||
union {
|
||||
char sname[SMALLDNAME];
|
||||
@@ -357,9 +431,18 @@ struct crec {
|
||||
#define F_SERVER (1u<<18)
|
||||
#define F_QUERY (1u<<19)
|
||||
#define F_NOERR (1u<<20)
|
||||
/* composites */
|
||||
#define F_TYPE (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS) /* Only one may be set */
|
||||
#define F_AUTH (1u<<21)
|
||||
#define F_DNSSEC (1u<<22)
|
||||
#define F_KEYTAG (1u<<23)
|
||||
#define F_SECSTAT (1u<<24)
|
||||
#define F_NO_RR (1u<<25)
|
||||
#define F_IPSET (1u<<26)
|
||||
|
||||
/* Values of uid in crecs with F_CONFIG bit set. */
|
||||
#define SRC_INTERFACE 0
|
||||
#define SRC_CONFIG 1
|
||||
#define SRC_HOSTS 2
|
||||
#define SRC_AH 3
|
||||
|
||||
|
||||
/* struct sockaddr is not large enough to hold any address,
|
||||
@@ -373,6 +456,12 @@ union mysockaddr {
|
||||
#endif
|
||||
};
|
||||
|
||||
/* bits in flag param to IPv6 callbacks from iface_enumerate() */
|
||||
#define IFACE_TENTATIVE 1
|
||||
#define IFACE_DEPRECATED 2
|
||||
#define IFACE_PERMANENT 4
|
||||
|
||||
|
||||
#define SERV_FROM_RESOLV 1 /* 1 for servers from resolv, 0 for command line. */
|
||||
#define SERV_NO_ADDR 2 /* no server, this domain is local only */
|
||||
#define SERV_LITERAL_ADDRESS 4 /* addr is the answer, not the server */
|
||||
@@ -386,6 +475,7 @@ union mysockaddr {
|
||||
#define SERV_COUNTED 512 /* workspace for log code */
|
||||
#define SERV_USE_RESOLV 1024 /* forward this domain in the normal way */
|
||||
#define SERV_NO_REBIND 2048 /* inhibit dns-rebind protection */
|
||||
#define SERV_FROM_FILE 4096 /* read from --servers-file */
|
||||
|
||||
struct serverfd {
|
||||
int fd;
|
||||
@@ -409,11 +499,17 @@ struct server {
|
||||
struct server *next;
|
||||
};
|
||||
|
||||
struct ipsets {
|
||||
char **sets;
|
||||
char *domain;
|
||||
struct ipsets *next;
|
||||
};
|
||||
|
||||
struct irec {
|
||||
union mysockaddr addr;
|
||||
struct in_addr netmask; /* only valid for IPv4 */
|
||||
int tftp_ok, dhcp_ok, mtu, done, dad;
|
||||
char *name;
|
||||
int tftp_ok, dhcp_ok, mtu, done, warned, dad, dns_auth, index, multicast_done, found;
|
||||
char *name;
|
||||
struct irec *next;
|
||||
};
|
||||
|
||||
@@ -446,11 +542,38 @@ struct hostsfile {
|
||||
struct hostsfile *next;
|
||||
int flags;
|
||||
char *fname;
|
||||
int index; /* matches to cache entries for logging */
|
||||
unsigned int index; /* matches to cache entries for logging */
|
||||
};
|
||||
|
||||
|
||||
/* DNSSEC status values. */
|
||||
#define STAT_SECURE 1
|
||||
#define STAT_INSECURE 2
|
||||
#define STAT_BOGUS 3
|
||||
#define STAT_NEED_DS 4
|
||||
#define STAT_NEED_KEY 5
|
||||
#define STAT_TRUNCATED 6
|
||||
#define STAT_SECURE_WILDCARD 7
|
||||
#define STAT_NO_SIG 8
|
||||
#define STAT_NO_DS 9
|
||||
#define STAT_NEED_DS_NEG 10
|
||||
#define STAT_CHASE_CNAME 11
|
||||
|
||||
#define FREC_NOREBIND 1
|
||||
#define FREC_CHECKING_DISABLED 2
|
||||
#define FREC_HAS_SUBNET 4
|
||||
#define FREC_DNSKEY_QUERY 8
|
||||
#define FREC_DS_QUERY 16
|
||||
#define FREC_AD_QUESTION 32
|
||||
#define FREC_DO_QUESTION 64
|
||||
#define FREC_ADDED_PHEADER 128
|
||||
#define FREC_CHECK_NOSIGN 256
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
#define HASH_SIZE 20 /* SHA-1 digest size */
|
||||
#else
|
||||
#define HASH_SIZE sizeof(int)
|
||||
#endif
|
||||
|
||||
struct frec {
|
||||
union mysockaddr source;
|
||||
@@ -463,8 +586,15 @@ struct frec {
|
||||
unsigned int iface;
|
||||
unsigned short orig_id, new_id;
|
||||
int fd, forwardall, flags;
|
||||
unsigned int crc;
|
||||
time_t time;
|
||||
unsigned char *hash[HASH_SIZE];
|
||||
#ifdef HAVE_DNSSEC
|
||||
int class, work_counter;
|
||||
struct blockdata *stash; /* Saved reply, whilst we validate */
|
||||
size_t stash_len;
|
||||
struct frec *dependent; /* Query awaiting internally-generated DNSKEY or DS query */
|
||||
struct frec *blocking_query; /* Query which is blocking us. */
|
||||
#endif
|
||||
struct frec *next;
|
||||
};
|
||||
|
||||
@@ -503,19 +633,22 @@ struct dhcp_lease {
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
unsigned int length;
|
||||
#endif
|
||||
int hwaddr_len, hwaddr_type; /* hw_type used for iaid in v6 */
|
||||
unsigned char hwaddr[DHCP_CHADDR_MAX]; /* also IPv6 address */
|
||||
int hwaddr_len, hwaddr_type;
|
||||
unsigned char hwaddr[DHCP_CHADDR_MAX];
|
||||
struct in_addr addr, override, giaddr;
|
||||
unsigned char *extradata;
|
||||
unsigned int extradata_len, extradata_size;
|
||||
int last_interface;
|
||||
#ifdef HAVE_DHCP6
|
||||
struct in6_addr addr6;
|
||||
int iaid;
|
||||
struct slaac_address {
|
||||
struct in6_addr addr, local;
|
||||
struct in6_addr addr;
|
||||
time_t ping_time;
|
||||
int backoff; /* zero -> confirmed */
|
||||
struct slaac_address *next;
|
||||
} *slaac_address;
|
||||
int vendorclass_count;
|
||||
#endif
|
||||
struct dhcp_lease *next;
|
||||
};
|
||||
@@ -572,6 +705,7 @@ struct dhcp_config {
|
||||
#define CONFIG_DECLINED 1024 /* address declined by client */
|
||||
#define CONFIG_BANK 2048 /* from dhcp hosts file */
|
||||
#define CONFIG_ADDR6 4096
|
||||
#define CONFIG_WILDCARD 8192
|
||||
|
||||
struct dhcp_opt {
|
||||
int opt, len, flags;
|
||||
@@ -644,13 +778,27 @@ struct dhcp_bridge {
|
||||
};
|
||||
|
||||
struct cond_domain {
|
||||
char *domain;
|
||||
char *domain, *prefix;
|
||||
struct in_addr start, end;
|
||||
#ifdef HAVE_IPV6
|
||||
struct in6_addr start6, end6;
|
||||
#endif
|
||||
int is6;
|
||||
struct cond_domain *next;
|
||||
};
|
||||
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
struct prefix_class {
|
||||
int class;
|
||||
struct dhcp_netid tag;
|
||||
struct prefix_class *next;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct ra_interface {
|
||||
char *name;
|
||||
int interval, lifetime, prio;
|
||||
struct ra_interface *next;
|
||||
};
|
||||
|
||||
struct dhcp_context {
|
||||
@@ -662,23 +810,34 @@ struct dhcp_context {
|
||||
struct in6_addr start6, end6; /* range of available addresses */
|
||||
struct in6_addr local6;
|
||||
int prefix, if_index;
|
||||
time_t ra_time;
|
||||
unsigned int valid, preferred, saved_valid;
|
||||
time_t ra_time, ra_short_period_start, address_lost_time;
|
||||
char *template_interface;
|
||||
#endif
|
||||
int flags;
|
||||
struct dhcp_netid netid, *filter;
|
||||
struct dhcp_context *next, *current;
|
||||
};
|
||||
|
||||
#define CONTEXT_STATIC 1
|
||||
#define CONTEXT_NETMASK 2
|
||||
#define CONTEXT_BRDCAST 4
|
||||
#define CONTEXT_PROXY 8
|
||||
#define CONTEXT_RA_ONLY 16
|
||||
#define CONTEXT_RA_DONE 32
|
||||
#define CONTEXT_RA_NAME 64
|
||||
#define CONTEXT_RA_STATELESS 128
|
||||
#define CONTEXT_DHCP 256
|
||||
#define CONTEXT_DEPRECATE 512
|
||||
#define CONTEXT_STATIC (1u<<0)
|
||||
#define CONTEXT_NETMASK (1u<<1)
|
||||
#define CONTEXT_BRDCAST (1u<<2)
|
||||
#define CONTEXT_PROXY (1u<<3)
|
||||
#define CONTEXT_RA_ONLY (1u<<4)
|
||||
#define CONTEXT_RA_DONE (1u<<5)
|
||||
#define CONTEXT_RA_NAME (1u<<6)
|
||||
#define CONTEXT_RA_STATELESS (1u<<7)
|
||||
#define CONTEXT_DHCP (1u<<8)
|
||||
#define CONTEXT_DEPRECATE (1u<<9)
|
||||
#define CONTEXT_TEMPLATE (1u<<10) /* create contexts using addresses */
|
||||
#define CONTEXT_CONSTRUCTED (1u<<11)
|
||||
#define CONTEXT_GC (1u<<12)
|
||||
#define CONTEXT_RA (1u<<13)
|
||||
#define CONTEXT_CONF_USED (1u<<14)
|
||||
#define CONTEXT_USED (1u<<15)
|
||||
#define CONTEXT_OLD (1u<<16)
|
||||
#define CONTEXT_V6 (1u<<17)
|
||||
|
||||
|
||||
struct ping_result {
|
||||
struct in_addr addr;
|
||||
@@ -718,6 +877,12 @@ struct tftp_prefix {
|
||||
struct tftp_prefix *next;
|
||||
};
|
||||
|
||||
struct dhcp_relay {
|
||||
struct all_addr local, server;
|
||||
char *interface; /* Allowable interface for replies from server, and dest for IPv6 multicast */
|
||||
int iface_index; /* working - interface in which requests arrived, for return */
|
||||
struct dhcp_relay *current, *next;
|
||||
};
|
||||
|
||||
extern struct daemon {
|
||||
/* datastuctures representing the command-line and
|
||||
@@ -727,33 +892,42 @@ extern struct daemon {
|
||||
unsigned int options, options2;
|
||||
struct resolvc default_resolv, *resolv_files;
|
||||
time_t last_resolv;
|
||||
char *servers_file;
|
||||
struct mx_srv_record *mxnames;
|
||||
struct naptr *naptr;
|
||||
struct txt_record *txt, *rr;
|
||||
struct ptr_record *ptr;
|
||||
struct host_record *host_records, *host_records_tail;
|
||||
struct cname *cnames;
|
||||
struct auth_zone *auth_zones;
|
||||
struct interface_name *int_names;
|
||||
char *mxtarget;
|
||||
int addr4_netmask;
|
||||
int addr6_netmask;
|
||||
char *lease_file;
|
||||
char *username, *groupname, *scriptuser;
|
||||
char *luascript;
|
||||
char *authserver, *hostmaster;
|
||||
struct iname *authinterface;
|
||||
struct name_list *secondary_forward_server;
|
||||
int group_set, osport;
|
||||
char *domain_suffix;
|
||||
struct cond_domain *cond_domain;
|
||||
struct cond_domain *cond_domain, *synth_domains;
|
||||
char *runfile;
|
||||
char *lease_change_command;
|
||||
struct iname *if_names, *if_addrs, *if_except, *dhcp_except;
|
||||
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
|
||||
struct bogus_addr *bogus_addr;
|
||||
struct server *servers;
|
||||
struct ipsets *ipsets;
|
||||
int log_fac; /* log facility */
|
||||
char *log_file; /* optional log file */
|
||||
int max_logs; /* queue limit */
|
||||
int cachesize, ftabsize;
|
||||
int port, query_port, min_port;
|
||||
unsigned long local_ttl, neg_ttl, max_ttl, max_cache_ttl;
|
||||
unsigned long local_ttl, neg_ttl, max_ttl, max_cache_ttl, auth_ttl;
|
||||
struct hostsfile *addn_hosts;
|
||||
struct dhcp_context *dhcp, *dhcp6, *ra_contexts;
|
||||
struct dhcp_context *dhcp, *dhcp6;
|
||||
struct ra_interface *ra_interfaces;
|
||||
struct dhcp_config *dhcp_conf;
|
||||
struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6, *dhcp_match6;
|
||||
struct dhcp_vendor *dhcp_vendors;
|
||||
@@ -762,8 +936,10 @@ extern struct daemon {
|
||||
struct pxe_service *pxe_services;
|
||||
struct tag_if *tag_if;
|
||||
struct addr_list *override_relays;
|
||||
struct dhcp_relay *relay4, *relay6;
|
||||
int override;
|
||||
int enable_pxe;
|
||||
int doing_ra, doing_dhcp6;
|
||||
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names;
|
||||
struct dhcp_netid_list *force_broadcast, *bootp_dynamic;
|
||||
struct hostsfile *dhcp_hosts_file, *dhcp_opts_file;
|
||||
@@ -778,12 +954,23 @@ extern struct daemon {
|
||||
unsigned int duid_enterprise, duid_config_len;
|
||||
unsigned char *duid_config;
|
||||
char *dbus_name;
|
||||
unsigned long soa_sn, soa_refresh, soa_retry, soa_expiry;
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
struct prefix_class *prefix_classes;
|
||||
#endif
|
||||
#ifdef HAVE_DNSSEC
|
||||
struct ds_config *ds;
|
||||
#endif
|
||||
|
||||
/* globally used stuff for DNS */
|
||||
char *packet; /* packet buffer */
|
||||
int packet_buff_sz; /* size of above */
|
||||
char *namebuff; /* MAXDNAME size buffer */
|
||||
unsigned int local_answer, queries_forwarded;
|
||||
#ifdef HAVE_DNSSEC
|
||||
char *keyname; /* MAXDNAME size buffer */
|
||||
char *workspacename; /* ditto */
|
||||
#endif
|
||||
unsigned int local_answer, queries_forwarded, auth_answer;
|
||||
struct frec *frec_list;
|
||||
struct serverfd *sfds;
|
||||
struct irec *interfaces;
|
||||
@@ -797,13 +984,14 @@ extern struct daemon {
|
||||
pid_t tcp_pids[MAX_PROCS];
|
||||
struct randfd randomsocks[RANDOM_SOCKS];
|
||||
int v6pktinfo;
|
||||
struct addrlist *interface_addrs; /* list of all addresses/prefix lengths associated with all local interfaces */
|
||||
|
||||
/* DHCP state */
|
||||
int dhcpfd, helperfd, pxefd;
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
int netlinkfd;
|
||||
#elif defined(HAVE_BSD_NETWORK)
|
||||
int dhcp_raw_fd, dhcp_icmp_fd;
|
||||
int dhcp_raw_fd, dhcp_icmp_fd, routefd;
|
||||
#endif
|
||||
struct iovec dhcp_packet;
|
||||
char *dhcp_buff, *dhcp_buff2, *dhcp_buff3;
|
||||
@@ -834,13 +1022,13 @@ extern struct daemon {
|
||||
/* cache.c */
|
||||
void cache_init(void);
|
||||
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg);
|
||||
char *record_source(int index);
|
||||
void querystr(char *str, unsigned short type);
|
||||
char *record_source(unsigned int index);
|
||||
char *querystr(char *desc, unsigned short type);
|
||||
struct crec *cache_find_by_addr(struct crec *crecp,
|
||||
struct all_addr *addr, time_t now,
|
||||
unsigned short prot);
|
||||
unsigned int prot);
|
||||
struct crec *cache_find_by_name(struct crec *crecp,
|
||||
char *name, time_t now, unsigned short prot);
|
||||
char *name, time_t now, unsigned int prot);
|
||||
void cache_end_insert(void);
|
||||
void cache_start_insert(void);
|
||||
struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
@@ -850,26 +1038,45 @@ void cache_add_dhcp_entry(char *host_name, int prot, struct all_addr *host_addre
|
||||
struct in_addr a_record_from_hosts(char *name, time_t now);
|
||||
void cache_unhash_dhcp(void);
|
||||
void dump_cache(time_t now);
|
||||
int cache_make_stat(struct txt_record *t);
|
||||
char *cache_get_name(struct crec *crecp);
|
||||
char *cache_get_cname_target(struct crec *crecp);
|
||||
struct crec *cache_enumerate(int init);
|
||||
|
||||
/* blockdata.c */
|
||||
#ifdef HAVE_DNSSEC
|
||||
void blockdata_init(void);
|
||||
void blockdata_report(void);
|
||||
struct blockdata *blockdata_alloc(char *data, size_t len);
|
||||
void *blockdata_retrieve(struct blockdata *block, size_t len, void *data);
|
||||
void blockdata_free(struct blockdata *blocks);
|
||||
#endif
|
||||
|
||||
/* domain.c */
|
||||
char *get_domain(struct in_addr addr);
|
||||
#ifdef HAVE_IPV6
|
||||
char *get_domain6(struct in6_addr *addr);
|
||||
#endif
|
||||
#ifdef HAVE_DNSSEC
|
||||
struct keydata *keydata_alloc(char *data, size_t len);
|
||||
void keydata_free(struct keydata *blocks);
|
||||
#endif
|
||||
int is_name_synthetic(int flags, char *name, struct all_addr *addr);
|
||||
int is_rev_synth(int flag, struct all_addr *addr, char *name);
|
||||
|
||||
/* rfc1035.c */
|
||||
int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||
char *name, int isExtract, int extrabytes);
|
||||
unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes);
|
||||
unsigned char *skip_questions(struct dns_header *header, size_t plen);
|
||||
unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen);
|
||||
unsigned int extract_request(struct dns_header *header, size_t qlen,
|
||||
char *name, unsigned short *typep);
|
||||
size_t setup_reply(struct dns_header *header, size_t qlen,
|
||||
struct all_addr *addrp, unsigned int flags,
|
||||
unsigned long local_ttl);
|
||||
int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff,
|
||||
time_t now, int is_sign, int checkrebind, int checking_disabled);
|
||||
time_t now, char **ipsets, int is_sign, int checkrebind,
|
||||
int no_cache, int secure, int *doctored);
|
||||
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask, time_t now);
|
||||
struct in_addr local_addr, struct in_addr local_netmask,
|
||||
time_t now, int *ad_reqd, int *do_bit);
|
||||
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||
struct bogus_addr *addr, time_t now);
|
||||
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
|
||||
@@ -879,10 +1086,41 @@ unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
|
||||
size_t resize_packet(struct dns_header *header, size_t plen,
|
||||
unsigned char *pheader, size_t hlen);
|
||||
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
|
||||
size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source);
|
||||
#ifdef HAVE_DNSSEC
|
||||
size_t add_do_bit(struct dns_header *header, size_t plen, char *limit);
|
||||
#endif
|
||||
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
|
||||
int add_resource_record(struct dns_header *header, char *limit, int *truncp,
|
||||
int nameoffset, unsigned char **pp, unsigned long ttl,
|
||||
int *offset, unsigned short type, unsigned short class, char *format, ...);
|
||||
unsigned char *skip_questions(struct dns_header *header, size_t plen);
|
||||
int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||
char *name, int isExtract, int extrabytes);
|
||||
int in_arpa_name_2_addr(char *namein, struct all_addr *addrp);
|
||||
int private_net(struct in_addr addr, int ban_localhost);
|
||||
|
||||
/* auth.c */
|
||||
#ifdef HAVE_AUTH
|
||||
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen,
|
||||
time_t now, union mysockaddr *peer_addr, int local_query);
|
||||
int in_zone(struct auth_zone *zone, char *name, char **cut);
|
||||
#endif
|
||||
|
||||
/* dnssec.c */
|
||||
size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class, int type, union mysockaddr *addr);
|
||||
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t n, char *name, char *keyname, int class);
|
||||
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
|
||||
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class, int *neganswer);
|
||||
int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname);
|
||||
int dnskey_keytag(int alg, int flags, unsigned char *rdata, int rdlen);
|
||||
size_t filter_rrsigs(struct dns_header *header, size_t plen);
|
||||
unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name);
|
||||
|
||||
/* util.c */
|
||||
void rand_init(void);
|
||||
unsigned short rand16(void);
|
||||
u64 rand64(void);
|
||||
int legal_hostname(char *c);
|
||||
char *canonicalise(char *s, int *nomem);
|
||||
unsigned char *do_rfc1035_name(unsigned char *p, char *sval);
|
||||
@@ -911,6 +1149,8 @@ char *print_mac(char *buff, unsigned char *mac, int len);
|
||||
void bump_maxfd(int fd, int *max);
|
||||
int read_write(int fd, unsigned char *packet, int size, int rw);
|
||||
|
||||
int wildcard_match(const char* wildcard, const char* match);
|
||||
|
||||
/* log.c */
|
||||
void die(char *message, char *arg1, int exit_code);
|
||||
int log_start(struct passwd *ent_pw, int errfd);
|
||||
@@ -925,6 +1165,7 @@ void read_opts (int argc, char **argv, char *compile_opts);
|
||||
char *option_string(int prot, unsigned int opt, unsigned char *val,
|
||||
int opt_len, char *buf, int buf_len);
|
||||
void reread_dhcp(void);
|
||||
void read_servers_file(void);
|
||||
void set_option_bool(unsigned int opt);
|
||||
void reset_option_bool(unsigned int opt);
|
||||
struct hostsfile *expand_filelist(struct hostsfile *list);
|
||||
@@ -935,9 +1176,9 @@ char *parse_server(char *arg, union mysockaddr *addr,
|
||||
void reply_query(int fd, int family, time_t now);
|
||||
void receive_query(struct listener *listen, time_t now);
|
||||
unsigned char *tcp_request(int confd, time_t now,
|
||||
union mysockaddr *local_addr, struct in_addr netmask);
|
||||
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns);
|
||||
void server_gone(struct server *server);
|
||||
struct frec *get_new_frec(time_t now, int *wait);
|
||||
struct frec *get_new_frec(time_t now, int *wait, int force);
|
||||
int send_from(int fd, int nowild, char *packet, size_t len,
|
||||
union mysockaddr *to, struct all_addr *source,
|
||||
unsigned int iface);
|
||||
@@ -948,17 +1189,35 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp);
|
||||
int random_sock(int family);
|
||||
void pre_allocate_sfds(void);
|
||||
int reload_servers(char *fname);
|
||||
void mark_servers(int flag);
|
||||
void cleanup_servers(void);
|
||||
void add_update_server(int flags,
|
||||
union mysockaddr *addr,
|
||||
union mysockaddr *source_addr,
|
||||
const char *interface,
|
||||
const char *domain);
|
||||
void check_servers(void);
|
||||
int enumerate_interfaces();
|
||||
int enumerate_interfaces(int reset);
|
||||
void create_wildcard_listeners(void);
|
||||
void create_bound_listeners(int die);
|
||||
void warn_bound_listeners(void);
|
||||
void warn_int_names(void);
|
||||
int is_dad_listeners(void);
|
||||
int iface_check(int family, struct all_addr *addr, char *name);
|
||||
int iface_check(int family, struct all_addr *addr, char *name, int *auth_dns);
|
||||
int loopback_exception(int fd, int family, struct all_addr *addr, char *name);
|
||||
int label_exception(int index, int family, struct all_addr *addr);
|
||||
int fix_fd(int fd);
|
||||
struct in_addr get_ifaddr(char *intr);
|
||||
int tcp_interface(int fd, int af);
|
||||
#ifdef HAVE_IPV6
|
||||
int set_ipv6pktinfo(int fd);
|
||||
#endif
|
||||
#ifdef HAVE_DHCP6
|
||||
void join_multicast(int dienow);
|
||||
#endif
|
||||
#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_BSD_NETWORK)
|
||||
void newaddress(time_t now);
|
||||
#endif
|
||||
|
||||
|
||||
/* dhcp.c */
|
||||
#ifdef HAVE_DHCP
|
||||
@@ -973,12 +1232,6 @@ struct dhcp_context *narrow_context(struct dhcp_context *context,
|
||||
int address_allocate(struct dhcp_context *context,
|
||||
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
|
||||
struct dhcp_netid *netids, time_t now);
|
||||
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
|
||||
struct dhcp_config *find_config(struct dhcp_config *configs,
|
||||
struct dhcp_context *context,
|
||||
unsigned char *clid, int clid_len,
|
||||
unsigned char *hwaddr, int hw_len,
|
||||
int hw_type, char *hostname);
|
||||
void dhcp_read_ethers(void);
|
||||
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
|
||||
char *host_from_dns(struct in_addr addr);
|
||||
@@ -994,10 +1247,14 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr);
|
||||
struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type);
|
||||
struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
|
||||
int lease_type, int iaid, struct in6_addr *addr);
|
||||
void lease6_filter(int lease_type, int iaid, struct dhcp_context *context);
|
||||
void lease6_reset(void);
|
||||
struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid);
|
||||
struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr);
|
||||
u64 lease_find_max_addr6(struct dhcp_context *context);
|
||||
void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface);
|
||||
void lease_update_slaac(time_t now);
|
||||
void lease_set_iaid(struct dhcp_lease *lease, int iaid);
|
||||
void lease_make_duid(time_t now);
|
||||
#endif
|
||||
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||
unsigned char *clid, int hw_len, int hw_type, int clid_len, time_t now, int force);
|
||||
@@ -1040,7 +1297,7 @@ void poll_resolv(int force, int do_reload, time_t now);
|
||||
/* netlink.c */
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
void netlink_init(void);
|
||||
void netlink_multicast(void);
|
||||
void netlink_multicast(time_t now);
|
||||
#endif
|
||||
|
||||
/* bpf.c */
|
||||
@@ -1048,6 +1305,8 @@ void netlink_multicast(void);
|
||||
void init_bpf(void);
|
||||
void send_via_bpf(struct dhcp_packet *mess, size_t len,
|
||||
struct in_addr iface_addr, struct ifreq *ifr);
|
||||
void route_init(void);
|
||||
void route_sock(time_t now);
|
||||
#endif
|
||||
|
||||
/* bpf.c or netlink.c */
|
||||
@@ -1063,6 +1322,12 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* ipset.c */
|
||||
#ifdef HAVE_IPSET
|
||||
void ipset_init(void);
|
||||
int add_to_ipset(const char *setname, const struct all_addr *ipaddr, int flags, int remove);
|
||||
#endif
|
||||
|
||||
/* helper.c */
|
||||
#if defined(HAVE_SCRIPT)
|
||||
int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd);
|
||||
@@ -1092,28 +1357,33 @@ int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
|
||||
#ifdef HAVE_DHCP6
|
||||
void dhcp6_init(void);
|
||||
void dhcp6_packet(time_t now);
|
||||
int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
|
||||
int serial, struct dhcp_netid *netids, struct in6_addr *ans);
|
||||
int is_addr_in_context6(struct dhcp_context *context, struct in6_addr *addr);
|
||||
struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len, int temp_addr,
|
||||
int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans);
|
||||
int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr);
|
||||
struct dhcp_context *address6_available(struct dhcp_context *context,
|
||||
struct in6_addr *taddr,
|
||||
struct dhcp_netid *netids);
|
||||
struct dhcp_context *narrow_context6(struct dhcp_context *context,
|
||||
struct in6_addr *taddr,
|
||||
struct dhcp_netid *netids);
|
||||
struct dhcp_config *find_config6(struct dhcp_config *configs,
|
||||
struct dhcp_context *context,
|
||||
unsigned char *duid, int duid_len,
|
||||
char *hostname);
|
||||
struct dhcp_netid *netids,
|
||||
int plain_range);
|
||||
struct dhcp_context *address6_valid(struct dhcp_context *context,
|
||||
struct in6_addr *taddr,
|
||||
struct dhcp_netid *netids,
|
||||
int plain_range);
|
||||
struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net,
|
||||
int prefix, u64 addr);
|
||||
void make_duid(time_t now);
|
||||
void dhcp_construct_contexts(time_t now);
|
||||
void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac,
|
||||
unsigned int *maclenp, unsigned int *mactypep);
|
||||
#endif
|
||||
|
||||
|
||||
/* rfc3315.c */
|
||||
#ifdef HAVE_DHCP6
|
||||
unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
|
||||
struct in6_addr *fallback, size_t sz, int is_multicast, time_t now);
|
||||
struct in6_addr *fallback, struct in6_addr *ll_addr, struct in6_addr *ula_addr,
|
||||
size_t sz, struct in6_addr *client_addr, time_t now);
|
||||
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id);
|
||||
|
||||
unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface);
|
||||
#endif
|
||||
|
||||
/* dhcp-common.c */
|
||||
@@ -1129,17 +1399,25 @@ void log_tags(struct dhcp_netid *netid, u32 xid);
|
||||
int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
|
||||
void dhcp_update_configs(struct dhcp_config *configs);
|
||||
void display_opts(void);
|
||||
u16 lookup_dhcp_opt(int prot, char *name);
|
||||
u16 lookup_dhcp_len(int prot, u16 val);
|
||||
int lookup_dhcp_opt(int prot, char *name);
|
||||
int lookup_dhcp_len(int prot, int val);
|
||||
char *option_string(int prot, unsigned int opt, unsigned char *val,
|
||||
int opt_len, char *buf, int buf_len);
|
||||
struct dhcp_config *find_config(struct dhcp_config *configs,
|
||||
struct dhcp_context *context,
|
||||
unsigned char *clid, int clid_len,
|
||||
unsigned char *hwaddr, int hw_len,
|
||||
int hw_type, char *hostname);
|
||||
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
void bindtodevice(int fd);
|
||||
char *whichdevice(void);
|
||||
void bindtodevice(char *device, int fd);
|
||||
#endif
|
||||
# ifdef HAVE_DHCP6
|
||||
void display_opts6(void);
|
||||
void join_multicast(void);
|
||||
# endif
|
||||
void log_context(int family, struct dhcp_context *context);
|
||||
void log_relay(int family, struct dhcp_relay *relay);
|
||||
#endif
|
||||
|
||||
/* outpacket.c */
|
||||
@@ -1158,16 +1436,14 @@ void put_opt6_string(char *s);
|
||||
/* radv.c */
|
||||
#ifdef HAVE_DHCP6
|
||||
void ra_init(time_t now);
|
||||
void icmp6_packet(void);
|
||||
void icmp6_packet(time_t now);
|
||||
time_t periodic_ra(time_t now);
|
||||
void ra_start_unsolicted(time_t now, struct dhcp_context *context);
|
||||
#endif
|
||||
|
||||
/* slaac.c */
|
||||
#ifdef HAVE_DHCP6
|
||||
void build_subnet_map(void);
|
||||
void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force);
|
||||
time_t periodic_slaac(time_t now, struct dhcp_lease *leases);
|
||||
void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface, struct dhcp_lease *leases);
|
||||
void schedule_subnet_map(void);
|
||||
#endif
|
||||
|
||||
2301
src/dnssec.c
Normal file
2301
src/dnssec.c
Normal file
File diff suppressed because it is too large
Load Diff
232
src/domain.c
Normal file
232
src/domain.c
Normal file
@@ -0,0 +1,232 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
|
||||
static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c);
|
||||
#ifdef HAVE_IPV6
|
||||
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c);
|
||||
#endif
|
||||
|
||||
|
||||
int is_name_synthetic(int flags, char *name, struct all_addr *addr)
|
||||
{
|
||||
char *p;
|
||||
struct cond_domain *c = NULL;
|
||||
int prot = AF_INET;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (flags & F_IPV6)
|
||||
prot = AF_INET6;
|
||||
#endif
|
||||
|
||||
for (c = daemon->synth_domains; c; c = c->next)
|
||||
{
|
||||
int found = 0;
|
||||
char *tail, *pref;
|
||||
|
||||
for (tail = name, pref = c->prefix; *tail != 0 && pref && *pref != 0; tail++, pref++)
|
||||
{
|
||||
unsigned int c1 = (unsigned char) *pref;
|
||||
unsigned int c2 = (unsigned char) *tail;
|
||||
|
||||
if (c1 >= 'A' && c1 <= 'Z')
|
||||
c1 += 'a' - 'A';
|
||||
if (c2 >= 'A' && c2 <= 'Z')
|
||||
c2 += 'a' - 'A';
|
||||
|
||||
if (c1 != c2)
|
||||
break;
|
||||
}
|
||||
|
||||
if (pref && *pref != 0)
|
||||
continue; /* prefix match fail */
|
||||
|
||||
/* NB, must not alter name if we return zero */
|
||||
for (p = tail; *p; p++)
|
||||
{
|
||||
char c = *p;
|
||||
|
||||
if ((c >='0' && c <= '9') || c == '-')
|
||||
continue;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f')))
|
||||
continue;
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p != '.')
|
||||
continue;
|
||||
|
||||
*p = 0;
|
||||
|
||||
/* swap . or : for - */
|
||||
for (p = tail; *p; p++)
|
||||
if (*p == '-')
|
||||
{
|
||||
if (prot == AF_INET)
|
||||
*p = '.';
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
*p = ':';
|
||||
#endif
|
||||
}
|
||||
|
||||
if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr))
|
||||
{
|
||||
if (prot == AF_INET)
|
||||
{
|
||||
if (!c->is6 &&
|
||||
ntohl(addr->addr.addr4.s_addr) >= ntohl(c->start.s_addr) &&
|
||||
ntohl(addr->addr.addr4.s_addr) <= ntohl(c->end.s_addr))
|
||||
found = 1;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
u64 addrpart = addr6part(&addr->addr.addr6);
|
||||
|
||||
if (c->is6 &&
|
||||
is_same_net6(&addr->addr.addr6, &c->start6, 64) &&
|
||||
addrpart >= addr6part(&c->start6) &&
|
||||
addrpart <= addr6part(&c->end6))
|
||||
found = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* restore name */
|
||||
for (p = tail; *p; p++)
|
||||
if (*p == '.' || *p == ':')
|
||||
*p = '-';
|
||||
|
||||
*p = '.';
|
||||
|
||||
if (found)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int is_rev_synth(int flag, struct all_addr *addr, char *name)
|
||||
{
|
||||
struct cond_domain *c;
|
||||
|
||||
if (flag & F_IPV4 && (c = search_domain(addr->addr.addr4, daemon->synth_domains)))
|
||||
{
|
||||
char *p;
|
||||
|
||||
*name = 0;
|
||||
if (c->prefix)
|
||||
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
|
||||
|
||||
inet_ntop(AF_INET, &addr->addr.addr4, name + strlen(name), ADDRSTRLEN);
|
||||
for (p = name; *p; p++)
|
||||
if (*p == '.')
|
||||
*p = '-';
|
||||
|
||||
strncat(name, ".", MAXDNAME);
|
||||
strncat(name, c->domain, MAXDNAME);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (flag & F_IPV6 && (c = search_domain6(&addr->addr.addr6, daemon->synth_domains)))
|
||||
{
|
||||
char *p;
|
||||
|
||||
*name = 0;
|
||||
if (c->prefix)
|
||||
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
|
||||
|
||||
inet_ntop(AF_INET6, &addr->addr.addr6, name + strlen(name), ADDRSTRLEN);
|
||||
|
||||
/* IPv6 presentation address can start with ":", but valid domain names
|
||||
cannot start with "-" so prepend a zero in that case. */
|
||||
if (!c->prefix && *name == ':')
|
||||
{
|
||||
*name = '0';
|
||||
inet_ntop(AF_INET6, &addr->addr.addr6, name+1, ADDRSTRLEN);
|
||||
}
|
||||
|
||||
for (p = name; *p; p++)
|
||||
if (*p == ':')
|
||||
*p = '-';
|
||||
|
||||
strncat(name, ".", MAXDNAME);
|
||||
strncat(name, c->domain, MAXDNAME);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c)
|
||||
{
|
||||
for (; c; c = c->next)
|
||||
if (!c->is6 &&
|
||||
ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
|
||||
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
|
||||
return c;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *get_domain(struct in_addr addr)
|
||||
{
|
||||
struct cond_domain *c;
|
||||
|
||||
if ((c = search_domain(addr, daemon->cond_domain)))
|
||||
return c->domain;
|
||||
|
||||
return daemon->domain_suffix;
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c)
|
||||
{
|
||||
u64 addrpart = addr6part(addr);
|
||||
|
||||
for (; c; c = c->next)
|
||||
if (c->is6 &&
|
||||
is_same_net6(addr, &c->start6, 64) &&
|
||||
addrpart >= addr6part(&c->start6) &&
|
||||
addrpart <= addr6part(&c->end6))
|
||||
return c;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *get_domain6(struct in6_addr *addr)
|
||||
{
|
||||
struct cond_domain *c;
|
||||
|
||||
if (addr && (c = search_domain6(addr, daemon->cond_domain)))
|
||||
return c->domain;
|
||||
|
||||
return daemon->domain_suffix;
|
||||
}
|
||||
#endif
|
||||
1373
src/forward.c
1373
src/forward.c
File diff suppressed because it is too large
Load Diff
219
src/helper.c
219
src/helper.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -60,10 +60,18 @@ struct script_data
|
||||
unsigned int length;
|
||||
#else
|
||||
time_t expires;
|
||||
#endif
|
||||
#ifdef HAVE_TFTP
|
||||
off_t file_len;
|
||||
#endif
|
||||
#ifdef HAVE_IPV6
|
||||
struct in6_addr addr6;
|
||||
#endif
|
||||
#ifdef HAVE_DHCP6
|
||||
int iaid, vendorclass_count;
|
||||
#endif
|
||||
unsigned char hwaddr[DHCP_CHADDR_MAX];
|
||||
char interface[IF_NAMESIZE];
|
||||
|
||||
};
|
||||
|
||||
static struct script_data *buf = NULL;
|
||||
@@ -215,27 +223,17 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
continue;
|
||||
|
||||
|
||||
if (!is6)
|
||||
/* stringify MAC into dhcp_buff */
|
||||
p = daemon->dhcp_buff;
|
||||
if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0)
|
||||
p += sprintf(p, "%.2x-", data.hwaddr_type);
|
||||
for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
|
||||
{
|
||||
/* stringify MAC into dhcp_buff */
|
||||
p = daemon->dhcp_buff;
|
||||
if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0)
|
||||
p += sprintf(p, "%.2x-", data.hwaddr_type);
|
||||
for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
|
||||
{
|
||||
p += sprintf(p, "%.2x", data.hwaddr[i]);
|
||||
if (i != data.hwaddr_len - 1)
|
||||
p += sprintf(p, ":");
|
||||
}
|
||||
p += sprintf(p, "%.2x", data.hwaddr[i]);
|
||||
if (i != data.hwaddr_len - 1)
|
||||
p += sprintf(p, ":");
|
||||
}
|
||||
|
||||
/* expiry or length into dhcp_buff2 */
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
sprintf(daemon->dhcp_buff2, "%u", data.length);
|
||||
#else
|
||||
sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
|
||||
#endif
|
||||
|
||||
|
||||
/* supplied data may just exceed normal buffer (unlikely) */
|
||||
if ((data.hostname_len + data.ed_len + data.clid_len) > MAXDNAME &&
|
||||
!(alloc_buff = buf = malloc(data.hostname_len + data.ed_len + data.clid_len)))
|
||||
@@ -246,32 +244,25 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
continue;
|
||||
|
||||
/* CLID into packet */
|
||||
if (!is6)
|
||||
for (p = daemon->packet, i = 0; i < data.clid_len; i++)
|
||||
{
|
||||
p += sprintf(p, "%.2x", buf[i]);
|
||||
if (i != data.clid_len - 1)
|
||||
for (p = daemon->packet, i = 0; i < data.clid_len; i++)
|
||||
{
|
||||
p += sprintf(p, "%.2x", buf[i]);
|
||||
if (i != data.clid_len - 1)
|
||||
p += sprintf(p, ":");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
else
|
||||
if (is6)
|
||||
{
|
||||
/* or IAID and server DUID for IPv6 */
|
||||
sprintf(daemon->dhcp_buff3, "%s%u", data.flags & LEASE_TA ? "T" : "", data.hwaddr_type);
|
||||
for (p = daemon->packet, i = 0; i < daemon->duid_len; i++)
|
||||
sprintf(daemon->dhcp_buff3, "%s%u", data.flags & LEASE_TA ? "T" : "", data.iaid);
|
||||
for (p = daemon->dhcp_packet.iov_base, i = 0; i < daemon->duid_len; i++)
|
||||
{
|
||||
p += sprintf(p, "%.2x", daemon->duid[i]);
|
||||
if (i != daemon->duid_len - 1)
|
||||
p += sprintf(p, ":");
|
||||
}
|
||||
|
||||
/* duid not MAC for IPv6 */
|
||||
for (p = daemon->dhcp_buff, i = 0; i < data.clid_len; i++)
|
||||
{
|
||||
p += sprintf(p, "%.2x", buf[i]);
|
||||
if (i != data.clid_len - 1)
|
||||
p += sprintf(p, ":");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -300,13 +291,15 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
inet_ntop(AF_INET, &data.addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
#ifdef HAVE_DHCP6
|
||||
else
|
||||
inet_ntop(AF_INET6, &data.hwaddr, daemon->addrbuff, ADDRSTRLEN);
|
||||
inet_ntop(AF_INET6, &data.addr6, daemon->addrbuff, ADDRSTRLEN);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
/* file length */
|
||||
if (data.action == ACTION_TFTP)
|
||||
sprintf(daemon->dhcp_buff, "%u", data.hwaddr_len);
|
||||
|
||||
sprintf(is6 ? daemon->packet : daemon->dhcp_buff, "%lu", (unsigned long)data.file_len);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LUASCRIPT
|
||||
if (daemon->luascript)
|
||||
{
|
||||
@@ -323,7 +316,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
lua_setfield(lua, -2, "destination_address");
|
||||
lua_pushstring(lua, hostname);
|
||||
lua_setfield(lua, -2, "file_name");
|
||||
lua_pushstring(lua, daemon->dhcp_buff);
|
||||
lua_pushstring(lua, is6 ? daemon->packet : daemon->dhcp_buff);
|
||||
lua_setfield(lua, -2, "file_size");
|
||||
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
|
||||
}
|
||||
@@ -336,9 +329,9 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
|
||||
if (is6)
|
||||
{
|
||||
lua_pushstring(lua, daemon->dhcp_buff);
|
||||
lua_setfield(lua, -2, "client_duid");
|
||||
lua_pushstring(lua, daemon->packet);
|
||||
lua_setfield(lua, -2, "client_duid");
|
||||
lua_pushstring(lua, daemon->dhcp_packet.iov_base);
|
||||
lua_setfield(lua, -2, "server_duid");
|
||||
lua_pushstring(lua, daemon->dhcp_buff3);
|
||||
lua_setfield(lua, -2, "iaid");
|
||||
@@ -382,12 +375,16 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
if (!is6)
|
||||
buf = grab_extradata_lua(buf, end, "vendor_class");
|
||||
#ifdef HAVE_DHCP6
|
||||
else
|
||||
for (i = 0; i < data.hwaddr_len; i++)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff2, "vendor_class%i", i);
|
||||
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
|
||||
}
|
||||
else if (data.vendorclass_count != 0)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff2, "vendor_class_id");
|
||||
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
|
||||
for (i = 0; i < data.vendorclass_count - 1; i++)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff2, "vendor_class%i", i);
|
||||
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
buf = grab_extradata_lua(buf, end, "supplied_hostname");
|
||||
@@ -397,6 +394,9 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
buf = grab_extradata_lua(buf, end, "cpewan_oui");
|
||||
buf = grab_extradata_lua(buf, end, "cpewan_serial");
|
||||
buf = grab_extradata_lua(buf, end, "cpewan_class");
|
||||
buf = grab_extradata_lua(buf, end, "circuit_id");
|
||||
buf = grab_extradata_lua(buf, end, "subscriber_id");
|
||||
buf = grab_extradata_lua(buf, end, "remote_id");
|
||||
}
|
||||
|
||||
buf = grab_extradata_lua(buf, end, "tags");
|
||||
@@ -427,7 +427,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
lua_setfield(lua, -2, "old_hostname");
|
||||
}
|
||||
|
||||
if (!is6)
|
||||
if (!is6 || data.hwaddr_len != 0)
|
||||
{
|
||||
lua_pushstring(lua, daemon->dhcp_buff);
|
||||
lua_setfield(lua, -2, "mac_address");
|
||||
@@ -480,26 +480,24 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
|
||||
if (data.action != ACTION_TFTP)
|
||||
{
|
||||
if (is6)
|
||||
{
|
||||
my_setenv("DNSMASQ_IAID", daemon->dhcp_buff3, &err);
|
||||
my_setenv("DNSMASQ_SERVER_DUID", daemon->packet, &err);
|
||||
}
|
||||
#ifdef HAVE_DHCP6
|
||||
my_setenv("DNSMASQ_IAID", is6 ? daemon->dhcp_buff3 : NULL, &err);
|
||||
my_setenv("DNSMASQ_SERVER_DUID", is6 ? daemon->dhcp_packet.iov_base : NULL, &err);
|
||||
my_setenv("DNSMASQ_MAC", is6 && data.hwaddr_len != 0 ? daemon->dhcp_buff : NULL, &err);
|
||||
#endif
|
||||
|
||||
if (!is6 && data.clid_len != 0)
|
||||
my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err);
|
||||
|
||||
if (strlen(data.interface) != 0)
|
||||
my_setenv("DNSMASQ_INTERFACE", data.interface, &err);
|
||||
my_setenv("DNSMASQ_CLIENT_ID", !is6 && data.clid_len != 0 ? daemon->packet : NULL, &err);
|
||||
my_setenv("DNSMASQ_INTERFACE", strlen(data.interface) != 0 ? data.interface : NULL, &err);
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
sprintf(daemon->dhcp_buff2, "%u", data.length);
|
||||
my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
|
||||
#else
|
||||
sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
|
||||
my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
|
||||
#endif
|
||||
|
||||
if (domain)
|
||||
my_setenv("DNSMASQ_DOMAIN", domain, &err);
|
||||
my_setenv("DNSMASQ_DOMAIN", domain, &err);
|
||||
|
||||
end = extradata + data.ed_len;
|
||||
buf = extradata;
|
||||
@@ -509,10 +507,10 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
#ifdef HAVE_DHCP6
|
||||
else
|
||||
{
|
||||
if (data.hwaddr_len != 0)
|
||||
if (data.vendorclass_count != 0)
|
||||
{
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err);
|
||||
for (i = 0; i < data.hwaddr_len - 1; i++)
|
||||
for (i = 0; i < data.vendorclass_count - 1; i++)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff2, "DNSMASQ_VENDOR_CLASS%i", i);
|
||||
buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
|
||||
@@ -528,14 +526,17 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err);
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err);
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_CIRCUIT_ID", &err);
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_SUBSCRIBER_ID", &err);
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_REMOTE_ID", &err);
|
||||
}
|
||||
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err);
|
||||
|
||||
|
||||
if (is6)
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err);
|
||||
else if (data.giaddr.s_addr != 0)
|
||||
my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
|
||||
else
|
||||
my_setenv("DNSMASQ_RELAY_ADDRESS", data.giaddr.s_addr != 0 ? inet_ntoa(data.giaddr) : NULL, &err);
|
||||
|
||||
for (i = 0; buf; i++)
|
||||
{
|
||||
@@ -543,22 +544,16 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
|
||||
}
|
||||
|
||||
if (data.action != ACTION_DEL && data.remaining_time != 0)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
|
||||
my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
|
||||
}
|
||||
sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
|
||||
my_setenv("DNSMASQ_TIME_REMAINING", data.action != ACTION_DEL && data.remaining_time != 0 ? daemon->dhcp_buff2 : NULL, &err);
|
||||
|
||||
if (data.action == ACTION_OLD_HOSTNAME && hostname)
|
||||
{
|
||||
my_setenv("DNSMASQ_OLD_HOSTNAME", hostname, &err);
|
||||
hostname = NULL;
|
||||
}
|
||||
my_setenv("DNSMASQ_OLD_HOSTNAME", data.action == ACTION_OLD_HOSTNAME ? hostname : NULL, &err);
|
||||
if (data.action == ACTION_OLD_HOSTNAME)
|
||||
hostname = NULL;
|
||||
}
|
||||
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
my_setenv("DNSMASQ_LOG_DHCP", "1", &err);
|
||||
|
||||
my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &err);
|
||||
|
||||
/* we need to have the event_fd around if exec fails */
|
||||
if ((i = fcntl(event_fd, F_GETFD)) != -1)
|
||||
fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
|
||||
@@ -569,7 +564,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
{
|
||||
execl(daemon->lease_change_command,
|
||||
p ? p+1 : daemon->lease_change_command,
|
||||
action_str, daemon->dhcp_buff, daemon->addrbuff, hostname, (char*)NULL);
|
||||
action_str, is6 ? daemon->packet : daemon->dhcp_buff,
|
||||
daemon->addrbuff, hostname, (char*)NULL);
|
||||
err = errno;
|
||||
}
|
||||
/* failed, send event so the main process logs the problem */
|
||||
@@ -580,31 +576,44 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
|
||||
static void my_setenv(const char *name, const char *value, int *error)
|
||||
{
|
||||
if (*error == 0 && setenv(name, value, 1) != 0)
|
||||
*error = errno;
|
||||
if (*error == 0)
|
||||
{
|
||||
if (!value)
|
||||
unsetenv(name);
|
||||
else if (setenv(name, value, 1) != 0)
|
||||
*error = errno;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err)
|
||||
{
|
||||
unsigned char *next;
|
||||
unsigned char *next = NULL;
|
||||
char *val = NULL;
|
||||
|
||||
if (!buf || (buf == end))
|
||||
return NULL;
|
||||
|
||||
for (next = buf; *next != 0; next++)
|
||||
if (next == end)
|
||||
return NULL;
|
||||
|
||||
if (next != buf)
|
||||
if (buf && (buf != end))
|
||||
{
|
||||
char *p;
|
||||
/* No "=" in value */
|
||||
if ((p = strchr((char *)buf, '=')))
|
||||
*p = 0;
|
||||
my_setenv(env, (char *)buf, err);
|
||||
}
|
||||
for (next = buf; ; next++)
|
||||
if (next == end)
|
||||
{
|
||||
next = NULL;
|
||||
break;
|
||||
}
|
||||
else if (*next == 0)
|
||||
break;
|
||||
|
||||
return next + 1;
|
||||
if (next && (next != buf))
|
||||
{
|
||||
char *p;
|
||||
/* No "=" in value */
|
||||
if ((p = strchr((char *)buf, '=')))
|
||||
*p = 0;
|
||||
val = (char *)buf;
|
||||
}
|
||||
}
|
||||
|
||||
my_setenv(env, val, err);
|
||||
|
||||
return next ? next + 1 : NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LUASCRIPT
|
||||
@@ -654,8 +663,7 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
|
||||
unsigned char *p;
|
||||
unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
|
||||
int fd = daemon->dhcpfd;
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
#ifdef HAVE_DHCP6
|
||||
if (!daemon->dhcp)
|
||||
fd = daemon->dhcp6fd;
|
||||
#endif
|
||||
@@ -675,6 +683,11 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
|
||||
|
||||
buf->action = action;
|
||||
buf->flags = lease->flags;
|
||||
#ifdef HAVE_DHCP6
|
||||
buf->vendorclass_count = lease->vendorclass_count;
|
||||
buf->addr6 = lease->addr6;
|
||||
buf->iaid = lease->iaid;
|
||||
#endif
|
||||
buf->hwaddr_len = lease->hwaddr_len;
|
||||
buf->hwaddr_type = lease->hwaddr_type;
|
||||
buf->clid_len = clid_len;
|
||||
@@ -732,13 +745,13 @@ void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer)
|
||||
|
||||
buf->action = ACTION_TFTP;
|
||||
buf->hostname_len = filename_len;
|
||||
buf->hwaddr_len = file_len;
|
||||
buf->file_len = file_len;
|
||||
|
||||
if ((buf->flags = peer->sa.sa_family) == AF_INET)
|
||||
buf->addr = peer->in.sin_addr;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
memcpy(buf->hwaddr, &peer->in6.sin6_addr, IN6ADDRSZ);
|
||||
buf->addr6 = peer->in6.sin6_addr;
|
||||
#endif
|
||||
|
||||
memcpy((unsigned char *)(buf+1), filename, filename_len);
|
||||
|
||||
34
src/ip6addr.h
Normal file
34
src/ip6addr.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define IN6_IS_ADDR_ULA(a) \
|
||||
((((__const uint32_t *) (a))[0] & htonl (0xff000000)) \
|
||||
== htonl (0xfd000000))
|
||||
|
||||
#define IN6_IS_ADDR_ULA_ZERO(a) \
|
||||
(((__const uint32_t *) (a))[0] == htonl (0xfd000000) \
|
||||
&& ((__const uint32_t *) (a))[1] == 0 \
|
||||
&& ((__const uint32_t *) (a))[2] == 0 \
|
||||
&& ((__const uint32_t *) (a))[3] == 0)
|
||||
|
||||
#define IN6_IS_ADDR_LINK_LOCAL_ZERO(a) \
|
||||
(((__const uint32_t *) (a))[0] == htonl (0xfe800000) \
|
||||
&& ((__const uint32_t *) (a))[1] == 0 \
|
||||
&& ((__const uint32_t *) (a))[2] == 0 \
|
||||
&& ((__const uint32_t *) (a))[3] == 0)
|
||||
|
||||
229
src/ipset.c
Normal file
229
src/ipset.c
Normal file
@@ -0,0 +1,229 @@
|
||||
/* ipset.c is Copyright (c) 2013 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_IPSET
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
/* We want to be able to compile against old header files
|
||||
Kernel version is handled at run-time. */
|
||||
|
||||
#define NFNL_SUBSYS_IPSET 6
|
||||
|
||||
#define IPSET_ATTR_DATA 7
|
||||
#define IPSET_ATTR_IP 1
|
||||
#define IPSET_ATTR_IPADDR_IPV4 1
|
||||
#define IPSET_ATTR_IPADDR_IPV6 2
|
||||
#define IPSET_ATTR_PROTOCOL 1
|
||||
#define IPSET_ATTR_SETNAME 2
|
||||
#define IPSET_CMD_ADD 9
|
||||
#define IPSET_CMD_DEL 10
|
||||
#define IPSET_MAXNAMELEN 32
|
||||
#define IPSET_PROTOCOL 6
|
||||
|
||||
#ifndef NFNETLINK_V0
|
||||
#define NFNETLINK_V0 0
|
||||
#endif
|
||||
|
||||
#ifndef NLA_F_NESTED
|
||||
#define NLA_F_NESTED (1 << 15)
|
||||
#endif
|
||||
|
||||
#ifndef NLA_F_NET_BYTEORDER
|
||||
#define NLA_F_NET_BYTEORDER (1 << 14)
|
||||
#endif
|
||||
|
||||
struct my_nlattr {
|
||||
__u16 nla_len;
|
||||
__u16 nla_type;
|
||||
};
|
||||
|
||||
struct my_nfgenmsg {
|
||||
__u8 nfgen_family; /* AF_xxx */
|
||||
__u8 version; /* nfnetlink version */
|
||||
__be16 res_id; /* resource id */
|
||||
};
|
||||
|
||||
|
||||
/* data structure size in here is fixed */
|
||||
#define BUFF_SZ 256
|
||||
|
||||
#define NL_ALIGN(len) (((len)+3) & ~(3))
|
||||
static const struct sockaddr_nl snl = { .nl_family = AF_NETLINK };
|
||||
static int ipset_sock, old_kernel;
|
||||
static char *buffer;
|
||||
|
||||
static inline void add_attr(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data)
|
||||
{
|
||||
struct my_nlattr *attr = (void *)nlh + NL_ALIGN(nlh->nlmsg_len);
|
||||
uint16_t payload_len = NL_ALIGN(sizeof(struct my_nlattr)) + len;
|
||||
attr->nla_type = type;
|
||||
attr->nla_len = payload_len;
|
||||
memcpy((void *)attr + NL_ALIGN(sizeof(struct my_nlattr)), data, len);
|
||||
nlh->nlmsg_len += NL_ALIGN(payload_len);
|
||||
}
|
||||
|
||||
void ipset_init(void)
|
||||
{
|
||||
struct utsname utsname;
|
||||
int version;
|
||||
char *split;
|
||||
|
||||
if (uname(&utsname) < 0)
|
||||
die(_("failed to find kernel version: %s"), NULL, EC_MISC);
|
||||
|
||||
split = strtok(utsname.release, ".");
|
||||
version = (split ? atoi(split) : 0);
|
||||
split = strtok(NULL, ".");
|
||||
version = version * 256 + (split ? atoi(split) : 0);
|
||||
split = strtok(NULL, ".");
|
||||
version = version * 256 + (split ? atoi(split) : 0);
|
||||
old_kernel = (version < KERNEL_VERSION(2,6,32));
|
||||
|
||||
if (old_kernel && (ipset_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) != -1)
|
||||
return;
|
||||
|
||||
if (!old_kernel &&
|
||||
(buffer = safe_malloc(BUFF_SZ)) &&
|
||||
(ipset_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER)) != -1 &&
|
||||
(bind(ipset_sock, (struct sockaddr *)&snl, sizeof(snl)) != -1))
|
||||
return;
|
||||
|
||||
die (_("failed to create IPset control socket: %s"), NULL, EC_MISC);
|
||||
}
|
||||
|
||||
static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr, int af, int remove)
|
||||
{
|
||||
struct nlmsghdr *nlh;
|
||||
struct my_nfgenmsg *nfg;
|
||||
struct my_nlattr *nested[2];
|
||||
uint8_t proto;
|
||||
int addrsz = INADDRSZ;
|
||||
ssize_t rc;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (af == AF_INET6)
|
||||
addrsz = IN6ADDRSZ;
|
||||
#endif
|
||||
|
||||
if (strlen(setname) >= IPSET_MAXNAMELEN)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(buffer, 0, BUFF_SZ);
|
||||
|
||||
nlh = (struct nlmsghdr *)buffer;
|
||||
nlh->nlmsg_len = NL_ALIGN(sizeof(struct nlmsghdr));
|
||||
nlh->nlmsg_type = (remove ? IPSET_CMD_DEL : IPSET_CMD_ADD) | (NFNL_SUBSYS_IPSET << 8);
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST;
|
||||
|
||||
nfg = (struct my_nfgenmsg *)(buffer + nlh->nlmsg_len);
|
||||
nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nfgenmsg));
|
||||
nfg->nfgen_family = af;
|
||||
nfg->version = NFNETLINK_V0;
|
||||
nfg->res_id = htons(0);
|
||||
|
||||
proto = IPSET_PROTOCOL;
|
||||
add_attr(nlh, IPSET_ATTR_PROTOCOL, sizeof(proto), &proto);
|
||||
add_attr(nlh, IPSET_ATTR_SETNAME, strlen(setname) + 1, setname);
|
||||
nested[0] = (struct my_nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
|
||||
nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nlattr));
|
||||
nested[0]->nla_type = NLA_F_NESTED | IPSET_ATTR_DATA;
|
||||
nested[1] = (struct my_nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
|
||||
nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nlattr));
|
||||
nested[1]->nla_type = NLA_F_NESTED | IPSET_ATTR_IP;
|
||||
add_attr(nlh,
|
||||
(af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6) | NLA_F_NET_BYTEORDER,
|
||||
addrsz, &ipaddr->addr);
|
||||
nested[1]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[1];
|
||||
nested[0]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[0];
|
||||
|
||||
while ((rc = sendto(ipset_sock, buffer, nlh->nlmsg_len, 0,
|
||||
(struct sockaddr *)&snl, sizeof(snl))) == -1 && retry_send());
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int old_add_to_ipset(const char *setname, const struct all_addr *ipaddr, int remove)
|
||||
{
|
||||
socklen_t size;
|
||||
struct ip_set_req_adt_get {
|
||||
unsigned op;
|
||||
unsigned version;
|
||||
union {
|
||||
char name[IPSET_MAXNAMELEN];
|
||||
uint16_t index;
|
||||
} set;
|
||||
char typename[IPSET_MAXNAMELEN];
|
||||
} req_adt_get;
|
||||
struct ip_set_req_adt {
|
||||
unsigned op;
|
||||
uint16_t index;
|
||||
uint32_t ip;
|
||||
} req_adt;
|
||||
|
||||
if (strlen(setname) >= sizeof(req_adt_get.set.name))
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
req_adt_get.op = 0x10;
|
||||
req_adt_get.version = 3;
|
||||
strcpy(req_adt_get.set.name, setname);
|
||||
size = sizeof(req_adt_get);
|
||||
if (getsockopt(ipset_sock, SOL_IP, 83, &req_adt_get, &size) < 0)
|
||||
return -1;
|
||||
req_adt.op = remove ? 0x102 : 0x101;
|
||||
req_adt.index = req_adt_get.set.index;
|
||||
req_adt.ip = ntohl(ipaddr->addr.addr4.s_addr);
|
||||
if (setsockopt(ipset_sock, SOL_IP, 83, &req_adt, sizeof(req_adt)) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int add_to_ipset(const char *setname, const struct all_addr *ipaddr, int flags, int remove)
|
||||
{
|
||||
int af = AF_INET;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (flags & F_IPV6)
|
||||
{
|
||||
af = AF_INET6;
|
||||
/* old method only supports IPv4 */
|
||||
if (old_kernel)
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return old_kernel ? old_add_to_ipset(setname, ipaddr, remove) : new_add_to_ipset(setname, ipaddr, af, remove);
|
||||
}
|
||||
|
||||
#endif
|
||||
202
src/lease.c
202
src/lease.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -108,6 +108,7 @@ void lease_init(time_t now)
|
||||
{
|
||||
char *s = daemon->dhcp_buff2;
|
||||
int lease_type = LEASE_NA;
|
||||
int iaid;
|
||||
|
||||
if (s[0] == 'T')
|
||||
{
|
||||
@@ -115,12 +116,12 @@ void lease_init(time_t now)
|
||||
s++;
|
||||
}
|
||||
|
||||
hw_type = atoi(s);
|
||||
iaid = strtoul(s, NULL, 10);
|
||||
|
||||
if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
|
||||
{
|
||||
lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, hw_type, clid_len, now, 0);
|
||||
|
||||
lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, 0, clid_len, now, 0);
|
||||
lease_set_iaid(lease, iaid);
|
||||
if (strcmp(daemon->dhcp_buff, "*") != 0)
|
||||
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL);
|
||||
}
|
||||
@@ -187,10 +188,12 @@ void lease_update_from_configs(void)
|
||||
char *name;
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
|
||||
lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
|
||||
(config->flags & CONFIG_NAME) &&
|
||||
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
|
||||
if (lease->flags & (LEASE_TA | LEASE_NA))
|
||||
continue;
|
||||
else if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
|
||||
lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
|
||||
(config->flags & CONFIG_NAME) &&
|
||||
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
|
||||
lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL);
|
||||
else if ((name = host_from_dns(lease->addr)))
|
||||
lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */
|
||||
@@ -277,10 +280,10 @@ void lease_update_file(time_t now)
|
||||
ourprintf(&err, "%lu ", (unsigned long)lease->expires);
|
||||
#endif
|
||||
|
||||
inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN);
|
||||
inet_ntop(AF_INET6, &lease->addr6, daemon->addrbuff, ADDRSTRLEN);
|
||||
|
||||
ourprintf(&err, "%s%u %s ", (lease->flags & LEASE_TA) ? "T" : "",
|
||||
lease->hwaddr_type, daemon->addrbuff);
|
||||
lease->iaid, daemon->addrbuff);
|
||||
ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
|
||||
|
||||
if (lease->clid && lease->clid_len != 0)
|
||||
@@ -303,12 +306,12 @@ void lease_update_file(time_t now)
|
||||
file_dirty = 0;
|
||||
}
|
||||
|
||||
/* Set alarm for when the first lease expires + slop. */
|
||||
/* Set alarm for when the first lease expires. */
|
||||
next_event = 0;
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
/* do timed RAs and determine when the next is, also pings to potential SLAAC addresses */
|
||||
if (daemon->ra_contexts)
|
||||
if (daemon->doing_ra)
|
||||
{
|
||||
time_t event;
|
||||
|
||||
@@ -328,8 +331,8 @@ void lease_update_file(time_t now)
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if (lease->expires != 0 &&
|
||||
(next_event == 0 || difftime(next_event, lease->expires + 10) > 0.0))
|
||||
next_event = lease->expires + 10;
|
||||
(next_event == 0 || difftime(next_event, lease->expires) > 0.0))
|
||||
next_event = lease->expires;
|
||||
|
||||
if (err)
|
||||
{
|
||||
@@ -345,11 +348,12 @@ void lease_update_file(time_t now)
|
||||
}
|
||||
|
||||
|
||||
static int find_interface_v4(struct in_addr local, int if_index,
|
||||
static int find_interface_v4(struct in_addr local, int if_index, char *label,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
(void) label;
|
||||
(void) broadcast;
|
||||
(void) vparam;
|
||||
|
||||
@@ -363,16 +367,19 @@ static int find_interface_v4(struct in_addr local, int if_index,
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
static int find_interface_v6(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam)
|
||||
int scope, int if_index, int flags,
|
||||
int preferred, int valid, void *vparam)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
(void)scope;
|
||||
(void)dad;
|
||||
(void)flags;
|
||||
(void)preferred;
|
||||
(void)valid;
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if ((lease->flags & (LEASE_TA | LEASE_NA)))
|
||||
if (is_same_net6(local, (struct in6_addr *)&lease->hwaddr, prefix))
|
||||
if (is_same_net6(local, &lease->addr6, prefix))
|
||||
lease_set_interface(lease, if_index, *((time_t *)vparam));
|
||||
|
||||
return 1;
|
||||
@@ -386,6 +393,18 @@ void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *inte
|
||||
slaac_ping_reply(sender, packet, interface, leases);
|
||||
}
|
||||
|
||||
void lease_update_slaac(time_t now)
|
||||
{
|
||||
/* Called when we contruct a new RA-names context, to add putative
|
||||
new SLAAC addresses to existing leases. */
|
||||
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
if (daemon->dhcp)
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
slaac_add_addrs(lease, now, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -395,22 +414,24 @@ void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *inte
|
||||
start-time. */
|
||||
void lease_find_interfaces(time_t now)
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
build_subnet_map();
|
||||
#endif
|
||||
|
||||
iface_enumerate(AF_INET, &now, find_interface_v4);
|
||||
#ifdef HAVE_DHCP6
|
||||
iface_enumerate(AF_INET6, &now, find_interface_v6);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
void lease_make_duid(time_t now)
|
||||
{
|
||||
/* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
|
||||
if (!daemon->duid && daemon->dhcp6)
|
||||
if (!daemon->duid && daemon->doing_dhcp6)
|
||||
{
|
||||
file_dirty = 1;
|
||||
make_duid(now);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -420,6 +441,11 @@ void lease_update_dns(int force)
|
||||
|
||||
if (daemon->port != 0 && (dns_dirty || force))
|
||||
{
|
||||
#ifndef HAVE_BROKEN_RTC
|
||||
/* force transfer to authoritative secondaries */
|
||||
daemon->soa_sn++;
|
||||
#endif
|
||||
|
||||
cache_unhash_dhcp();
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
@@ -442,17 +468,24 @@ void lease_update_dns(int force)
|
||||
cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (lease->fqdn)
|
||||
cache_add_dhcp_entry(lease->fqdn, prot,
|
||||
prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr,
|
||||
prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6,
|
||||
lease->expires);
|
||||
|
||||
if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
|
||||
cache_add_dhcp_entry(lease->hostname, prot,
|
||||
prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr,
|
||||
prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6,
|
||||
lease->expires);
|
||||
|
||||
#else
|
||||
if (lease->fqdn)
|
||||
cache_add_dhcp_entry(lease->fqdn, prot, (struct all_addr *)&lease->addr, lease->expires);
|
||||
|
||||
if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
|
||||
cache_add_dhcp_entry(lease->hostname, prot, (struct all_addr *)&lease->addr, lease->expires);
|
||||
#endif
|
||||
}
|
||||
|
||||
dns_dirty = 0;
|
||||
@@ -539,8 +572,7 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
/* addr or clid may be NULL for "don't care, both NULL resets "USED" flags both
|
||||
set activates USED check */
|
||||
/* find address for {CLID, IAID, address} */
|
||||
struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
|
||||
int lease_type, int iaid, struct in6_addr *addr)
|
||||
{
|
||||
@@ -548,43 +580,57 @@ struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
{
|
||||
if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
|
||||
if (!(lease->flags & lease_type) || lease->iaid != iaid)
|
||||
continue;
|
||||
|
||||
if (clid && addr && (lease->flags & LEASE_USED))
|
||||
if (!IN6_ARE_ADDR_EQUAL(&lease->addr6, addr))
|
||||
continue;
|
||||
|
||||
if (addr && memcmp(lease->hwaddr, addr, IN6ADDRSZ) != 0)
|
||||
continue;
|
||||
|
||||
if (clid &&
|
||||
(clid_len != lease->clid_len ||
|
||||
if ((clid_len != lease->clid_len ||
|
||||
memcmp(clid, lease->clid, clid_len) != 0))
|
||||
continue;
|
||||
|
||||
lease->flags |= LEASE_USED;
|
||||
return lease;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void lease6_filter(int lease_type, int iaid, struct dhcp_context *context)
|
||||
/* reset "USED flags */
|
||||
void lease6_reset(void)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
lease->flags &= ~LEASE_USED;
|
||||
}
|
||||
|
||||
/* enumerate all leases belonging to {CLID, IAID} */
|
||||
struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
if (!first)
|
||||
first = leases;
|
||||
else
|
||||
first = first->next;
|
||||
|
||||
for (lease = first; lease; lease = lease->next)
|
||||
{
|
||||
/* reset "USED flag */
|
||||
lease->flags &= ~LEASE_USED;
|
||||
|
||||
if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
|
||||
if (lease->flags & LEASE_USED)
|
||||
continue;
|
||||
|
||||
/* leases on the wrong interface get filtered out here */
|
||||
if (!is_addr_in_context6(context, (struct in6_addr *)&lease->hwaddr))
|
||||
lease->flags |= LEASE_USED;
|
||||
|
||||
if (!(lease->flags & lease_type) || lease->iaid != iaid)
|
||||
continue;
|
||||
|
||||
if ((clid_len != lease->clid_len ||
|
||||
memcmp(clid, lease->clid, clid_len) != 0))
|
||||
continue;
|
||||
|
||||
return lease;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr)
|
||||
@@ -596,8 +642,8 @@ struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 add
|
||||
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
|
||||
continue;
|
||||
|
||||
if (is_same_net6((struct in6_addr *)lease->hwaddr, net, prefix) &&
|
||||
(prefix == 128 || addr6part((struct in6_addr *)lease->hwaddr) == addr))
|
||||
if (is_same_net6(&lease->addr6, net, prefix) &&
|
||||
(prefix == 128 || addr6part(&lease->addr6) == addr))
|
||||
return lease;
|
||||
}
|
||||
|
||||
@@ -616,11 +662,11 @@ u64 lease_find_max_addr6(struct dhcp_context *context)
|
||||
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
|
||||
continue;
|
||||
|
||||
if (is_same_net6((struct in6_addr *)lease->hwaddr, &context->start6, 64) &&
|
||||
addr6part((struct in6_addr *)lease->hwaddr) > addr6part(&context->start6) &&
|
||||
addr6part((struct in6_addr *)lease->hwaddr) <= addr6part(&context->end6) &&
|
||||
addr6part((struct in6_addr *)lease->hwaddr) > addr)
|
||||
addr = addr6part((struct in6_addr *)lease->hwaddr);
|
||||
if (is_same_net6(&lease->addr6, &context->start6, 64) &&
|
||||
addr6part(&lease->addr6) > addr6part(&context->start6) &&
|
||||
addr6part(&lease->addr6) <= addr6part(&context->end6) &&
|
||||
addr6part(&lease->addr6) > addr)
|
||||
addr = addr6part(&lease->addr6);
|
||||
}
|
||||
|
||||
return addr;
|
||||
@@ -662,6 +708,7 @@ static struct dhcp_lease *lease_allocate(void)
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
lease->length = 0xffffffff; /* illegal value */
|
||||
#endif
|
||||
lease->hwaddr_len = 256; /* illegal value */
|
||||
lease->next = leases;
|
||||
leases = lease;
|
||||
|
||||
@@ -674,9 +721,9 @@ static struct dhcp_lease *lease_allocate(void)
|
||||
struct dhcp_lease *lease4_allocate(struct in_addr addr)
|
||||
{
|
||||
struct dhcp_lease *lease = lease_allocate();
|
||||
lease->addr = addr;
|
||||
lease->hwaddr_len = 256; /* illegal value */
|
||||
|
||||
if (lease)
|
||||
lease->addr = addr;
|
||||
|
||||
return lease;
|
||||
}
|
||||
|
||||
@@ -684,8 +731,13 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr)
|
||||
struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
|
||||
{
|
||||
struct dhcp_lease *lease = lease_allocate();
|
||||
memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ;
|
||||
lease->flags |= lease_type;
|
||||
|
||||
if (lease)
|
||||
{
|
||||
lease->addr6 = *addrp;
|
||||
lease->flags |= lease_type;
|
||||
lease->iaid = 0;
|
||||
}
|
||||
|
||||
return lease;
|
||||
}
|
||||
@@ -693,14 +745,23 @@ struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
|
||||
|
||||
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
|
||||
{
|
||||
time_t exp = now + (time_t)len;
|
||||
|
||||
time_t exp;
|
||||
|
||||
if (len == 0xffffffff)
|
||||
{
|
||||
exp = 0;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
exp = now + (time_t)len;
|
||||
/* Check for 2038 overflow. Make the lease
|
||||
inifinite in that case, as the least disruptive
|
||||
thing we can do. */
|
||||
if (difftime(exp, now) <= 0.0)
|
||||
exp = 0;
|
||||
}
|
||||
|
||||
if (exp != lease->expires)
|
||||
{
|
||||
dns_dirty = 1;
|
||||
@@ -721,6 +782,17 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
void lease_set_iaid(struct dhcp_lease *lease, int iaid)
|
||||
{
|
||||
if (lease->iaid != iaid)
|
||||
{
|
||||
lease->iaid = iaid;
|
||||
lease->flags |= LEASE_CHANGED;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||
unsigned char *clid, int hw_len, int hw_type, int clid_len,
|
||||
time_t now, int force)
|
||||
@@ -731,6 +803,7 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||
#endif
|
||||
|
||||
(void)force;
|
||||
(void)now;
|
||||
|
||||
if (hw_len != lease->hwaddr_len ||
|
||||
hw_type != lease->hwaddr_type ||
|
||||
@@ -742,9 +815,6 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||
lease->hwaddr_type = hw_type;
|
||||
lease->flags |= LEASE_CHANGED;
|
||||
file_dirty = 1; /* run script on change */
|
||||
#ifdef HAVE_DHCP6
|
||||
change = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* only update clid when one is available, stops packets
|
||||
@@ -902,6 +972,8 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *do
|
||||
|
||||
void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now)
|
||||
{
|
||||
(void)now;
|
||||
|
||||
if (lease->last_interface == interface)
|
||||
return;
|
||||
|
||||
@@ -930,6 +1002,8 @@ int do_script_run(time_t now)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
(void)now;
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
/* If we're going to be sending DBus signals, but the connection is not yet up,
|
||||
delay everything until it is. */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -50,10 +50,14 @@ void netlink_init(void)
|
||||
addr.nl_pid = 0; /* autobind */
|
||||
addr.nl_groups = RTMGRP_IPV4_ROUTE;
|
||||
if (option_bool(OPT_CLEVERBIND))
|
||||
addr.nl_groups |= RTMGRP_IPV4_IFADDR;
|
||||
addr.nl_groups |= RTMGRP_IPV4_IFADDR;
|
||||
#ifdef HAVE_IPV6
|
||||
addr.nl_groups |= RTMGRP_IPV6_ROUTE;
|
||||
if (daemon->ra_contexts || option_bool(OPT_CLEVERBIND))
|
||||
if (option_bool(OPT_CLEVERBIND))
|
||||
addr.nl_groups |= RTMGRP_IPV6_IFADDR;
|
||||
#endif
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->doing_ra || daemon->doing_dhcp6)
|
||||
addr.nl_groups |= RTMGRP_IPV6_IFADDR;
|
||||
#endif
|
||||
|
||||
@@ -187,19 +191,19 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
if (h->nlmsg_seq != seq || h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
|
||||
{
|
||||
/* May be multicast arriving async */
|
||||
if (nl_async(h) && option_bool(OPT_CLEVERBIND))
|
||||
newaddr = 1;
|
||||
if (nl_async(h))
|
||||
{
|
||||
newaddr = 1;
|
||||
enumerate_interfaces(1); /* reset */
|
||||
}
|
||||
}
|
||||
else if (h->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
/* handle async new interface address arrivals, these have to be done
|
||||
after we complete as we're not re-entrant */
|
||||
if (newaddr)
|
||||
{
|
||||
enumerate_interfaces();
|
||||
create_bound_listeners(0);
|
||||
}
|
||||
|
||||
newaddress(dnsmasq_time());
|
||||
|
||||
return callback_ok;
|
||||
}
|
||||
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
|
||||
@@ -213,7 +217,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
if (ifa->ifa_family == AF_INET)
|
||||
{
|
||||
struct in_addr netmask, addr, broadcast;
|
||||
|
||||
char *label = NULL;
|
||||
|
||||
netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
|
||||
addr.s_addr = 0;
|
||||
broadcast.s_addr = 0;
|
||||
@@ -224,29 +229,49 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
addr = *((struct in_addr *)(rta+1));
|
||||
else if (rta->rta_type == IFA_BROADCAST)
|
||||
broadcast = *((struct in_addr *)(rta+1));
|
||||
else if (rta->rta_type == IFA_LABEL)
|
||||
label = RTA_DATA(rta);
|
||||
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
}
|
||||
|
||||
if (addr.s_addr && callback_ok)
|
||||
if (!((*callback)(addr, ifa->ifa_index, netmask, broadcast, parm)))
|
||||
if (!((*callback)(addr, ifa->ifa_index, label, netmask, broadcast, parm)))
|
||||
callback_ok = 0;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (ifa->ifa_family == AF_INET6)
|
||||
{
|
||||
struct in6_addr *addrp = NULL;
|
||||
u32 valid = 0, preferred = 0;
|
||||
int flags = 0;
|
||||
|
||||
while (RTA_OK(rta, len1))
|
||||
{
|
||||
if (rta->rta_type == IFA_ADDRESS)
|
||||
addrp = ((struct in6_addr *)(rta+1));
|
||||
|
||||
else if (rta->rta_type == IFA_CACHEINFO)
|
||||
{
|
||||
struct ifa_cacheinfo *ifc = (struct ifa_cacheinfo *)(rta+1);
|
||||
preferred = ifc->ifa_prefered;
|
||||
valid = ifc->ifa_valid;
|
||||
}
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
}
|
||||
|
||||
if (ifa->ifa_flags & IFA_F_TENTATIVE)
|
||||
flags |= IFACE_TENTATIVE;
|
||||
|
||||
if (ifa->ifa_flags & IFA_F_DEPRECATED)
|
||||
flags |= IFACE_DEPRECATED;
|
||||
|
||||
if (!(ifa->ifa_flags & IFA_F_TEMPORARY))
|
||||
flags |= IFACE_PERMANENT;
|
||||
|
||||
if (addrp && callback_ok)
|
||||
if (!((*callback)(addrp, (int)(ifa->ifa_prefixlen), (int)(ifa->ifa_scope),
|
||||
(int)(ifa->ifa_index), (int)(ifa->ifa_flags & IFA_F_TENTATIVE), parm)))
|
||||
(int)(ifa->ifa_index), flags,
|
||||
(int) preferred, (int)valid, parm)))
|
||||
callback_ok = 0;
|
||||
}
|
||||
#endif
|
||||
@@ -305,7 +330,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
}
|
||||
}
|
||||
|
||||
void netlink_multicast(void)
|
||||
void netlink_multicast(time_t now)
|
||||
{
|
||||
ssize_t len;
|
||||
struct nlmsghdr *h;
|
||||
@@ -318,17 +343,14 @@ void netlink_multicast(void)
|
||||
|
||||
if ((len = netlink_recv()) != -1)
|
||||
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
|
||||
if (nl_async(h) && option_bool(OPT_CLEVERBIND))
|
||||
if (nl_async(h))
|
||||
newaddr = 1;
|
||||
|
||||
/* restore non-blocking status */
|
||||
fcntl(daemon->netlinkfd, F_SETFL, flags);
|
||||
|
||||
|
||||
if (newaddr)
|
||||
{
|
||||
enumerate_interfaces();
|
||||
create_bound_listeners(0);
|
||||
}
|
||||
newaddress(now);
|
||||
}
|
||||
|
||||
static int nl_async(struct nlmsghdr *h)
|
||||
@@ -371,25 +393,11 @@ static int nl_async(struct nlmsghdr *h)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (h->nlmsg_type == RTM_NEWADDR)
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
/* force RAs to sync new network and pick up new interfaces. */
|
||||
if (daemon->ra_contexts)
|
||||
{
|
||||
schedule_subnet_map();
|
||||
ra_start_unsolicted(dnsmasq_time(), NULL);
|
||||
/* cause lease_update_file to run after we return, in case we were called from
|
||||
iface_enumerate and can't re-enter it now */
|
||||
send_alarm(0, 0);
|
||||
}
|
||||
#endif
|
||||
return 1; /* clever bind mode - rescan */
|
||||
}
|
||||
else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
|
||||
return 1; /* clever bind mode - rescan */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
1003
src/network.c
1003
src/network.c
File diff suppressed because it is too large
Load Diff
1172
src/option.c
1172
src/option.c
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -70,9 +70,9 @@ void *put_opt6(void *data, size_t len)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if ((p = expand(len)))
|
||||
if ((p = expand(len)) && data)
|
||||
memcpy(p, data, len);
|
||||
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -33,6 +33,13 @@ struct ra_packet {
|
||||
u32 retrans_time;
|
||||
};
|
||||
|
||||
struct neigh_packet {
|
||||
u8 type, code;
|
||||
u16 checksum;
|
||||
u16 reserved;
|
||||
struct in6_addr target;
|
||||
};
|
||||
|
||||
struct prefix_opt {
|
||||
u8 type, len, prefix_len, flags;
|
||||
u32 valid_lifetime, preferred_lifetime, reserved;
|
||||
|
||||
539
src/radv.c
539
src/radv.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -27,25 +27,34 @@
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
struct ra_param {
|
||||
time_t now;
|
||||
int ind, managed, other, found_context, first;
|
||||
char *if_name;
|
||||
struct dhcp_netid *tags;
|
||||
struct in6_addr link_local;
|
||||
struct in6_addr link_local, link_global, ula;
|
||||
unsigned int glob_pref_time, link_pref_time, ula_pref_time, adv_interval;
|
||||
};
|
||||
|
||||
struct search_param {
|
||||
time_t now; int iface;
|
||||
char name[IF_NAMESIZE+1];
|
||||
};
|
||||
|
||||
static void send_ra(int iface, char *iface_name, struct in6_addr *dest);
|
||||
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest);
|
||||
static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam);
|
||||
int scope, int if_index, int flags,
|
||||
unsigned int preferred, unsigned int valid, void *vparam);
|
||||
static int iface_search(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam);
|
||||
int scope, int if_index, int flags,
|
||||
int prefered, int valid, void *vparam);
|
||||
static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
|
||||
static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now);
|
||||
static unsigned int calc_lifetime(struct ra_interface *ra);
|
||||
static unsigned int calc_interval(struct ra_interface *ra);
|
||||
static unsigned int calc_prio(struct ra_interface *ra);
|
||||
static struct ra_interface *find_iface_param(char *iface);
|
||||
|
||||
static int hop_limit;
|
||||
static time_t ra_short_period_start;
|
||||
|
||||
void ra_init(time_t now)
|
||||
{
|
||||
@@ -62,14 +71,19 @@ void ra_init(time_t now)
|
||||
expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
|
||||
|
||||
/* See if we're guessing SLAAC addresses, if so we need to recieve ping replies */
|
||||
for (context = daemon->ra_contexts; context; context = context->next)
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_RA_NAME))
|
||||
break;
|
||||
|
||||
/* Need ICMP6 socket for transmission for DHCPv6 even when not doing RA. */
|
||||
|
||||
ICMP6_FILTER_SETBLOCKALL(&filter);
|
||||
ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
|
||||
if (context)
|
||||
ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
|
||||
if (daemon->doing_ra)
|
||||
{
|
||||
ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
|
||||
if (context)
|
||||
ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
|
||||
}
|
||||
|
||||
if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1 ||
|
||||
getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) ||
|
||||
@@ -85,7 +99,8 @@ void ra_init(time_t now)
|
||||
|
||||
daemon->icmp6fd = fd;
|
||||
|
||||
ra_start_unsolicted(now, NULL);
|
||||
if (daemon->doing_ra)
|
||||
ra_start_unsolicted(now, NULL);
|
||||
}
|
||||
|
||||
void ra_start_unsolicted(time_t now, struct dhcp_context *context)
|
||||
@@ -94,18 +109,20 @@ void ra_start_unsolicted(time_t now, struct dhcp_context *context)
|
||||
if it's not appropriate to advertise those contexts.
|
||||
This gets re-called on a netlink route-change to re-do the advertisement
|
||||
and pick up new interfaces */
|
||||
|
||||
|
||||
if (context)
|
||||
context->ra_time = now;
|
||||
context->ra_short_period_start = context->ra_time = now;
|
||||
else
|
||||
for (context = daemon->ra_contexts; context; context = context->next)
|
||||
context->ra_time = now + (rand16()/13000); /* range 0 - 5 */
|
||||
|
||||
/* re-do frequently for a minute or so, in case the first gets lost. */
|
||||
ra_short_period_start = now;
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (!(context->flags & CONTEXT_TEMPLATE))
|
||||
{
|
||||
context->ra_time = now + (rand16()/13000); /* range 0 - 5 */
|
||||
/* re-do frequently for a minute or so, in case the first gets lost. */
|
||||
context->ra_short_period_start = now;
|
||||
}
|
||||
}
|
||||
|
||||
void icmp6_packet(void)
|
||||
void icmp6_packet(time_t now)
|
||||
{
|
||||
char interface[IF_NAMESIZE+1];
|
||||
ssize_t sz;
|
||||
@@ -149,11 +166,11 @@ void icmp6_packet(void)
|
||||
if (!indextoname(daemon->icmp6fd, if_index, interface))
|
||||
return;
|
||||
|
||||
if (!iface_check(AF_LOCAL, NULL, interface))
|
||||
if (!iface_check(AF_LOCAL, NULL, interface, NULL))
|
||||
return;
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, interface) == 0))
|
||||
if (tmp->name && wildcard_match(tmp->name, interface))
|
||||
return;
|
||||
|
||||
if (packet[1] != 0)
|
||||
@@ -172,22 +189,27 @@ void icmp6_packet(void)
|
||||
mac = daemon->namebuff;
|
||||
}
|
||||
|
||||
my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
|
||||
if (!option_bool(OPT_QUIET_RA))
|
||||
my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
|
||||
/* source address may not be valid in solicit request. */
|
||||
send_ra(if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
|
||||
send_ra(now, if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
|
||||
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest)
|
||||
{
|
||||
struct ra_packet *ra;
|
||||
struct ra_param parm;
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_in6 addr;
|
||||
struct dhcp_context *context;
|
||||
struct dhcp_context *context, *tmp, **up;
|
||||
struct dhcp_netid iface_id;
|
||||
struct dhcp_opt *opt_cfg;
|
||||
int done_dns = 0;
|
||||
struct ra_interface *ra_param = find_iface_param(iface_name);
|
||||
int done_dns = 0, old_prefix = 0;
|
||||
unsigned int min_pref_time;
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
FILE *f;
|
||||
#endif
|
||||
|
||||
save_counter(0);
|
||||
ra = expand(sizeof(struct ra_packet));
|
||||
@@ -195,8 +217,8 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
|
||||
ra->type = ND_ROUTER_ADVERT;
|
||||
ra->code = 0;
|
||||
ra->hop_limit = hop_limit;
|
||||
ra->flags = 0x00;
|
||||
ra->lifetime = htons(1800); /* AdvDefaultLifetime*/
|
||||
ra->flags = calc_prio(ra_param);
|
||||
ra->lifetime = htons(calc_lifetime(ra_param));
|
||||
ra->reachable_time = 0;
|
||||
ra->retrans_time = 0;
|
||||
|
||||
@@ -206,31 +228,133 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
|
||||
parm.found_context = 0;
|
||||
parm.if_name = iface_name;
|
||||
parm.first = 1;
|
||||
|
||||
parm.now = now;
|
||||
parm.glob_pref_time = parm.link_pref_time = parm.ula_pref_time = 0;
|
||||
parm.adv_interval = calc_interval(ra_param);
|
||||
|
||||
/* set tag with name == interface */
|
||||
iface_id.net = iface_name;
|
||||
iface_id.next = NULL;
|
||||
parm.tags = &iface_id;
|
||||
|
||||
for (context = daemon->ra_contexts; context; context = context->next)
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
{
|
||||
context->flags &= ~CONTEXT_RA_DONE;
|
||||
context->netid.next = &context->netid;
|
||||
}
|
||||
|
||||
if (!iface_enumerate(AF_INET6, &parm, add_prefixes) ||
|
||||
!parm.found_context)
|
||||
if (!iface_enumerate(AF_INET6, &parm, add_prefixes))
|
||||
return;
|
||||
|
||||
strncpy(ifr.ifr_name, iface_name, IF_NAMESIZE);
|
||||
/* Find smallest preferred time within address classes,
|
||||
to use as lifetime for options. This is a rather arbitrary choice. */
|
||||
min_pref_time = 0xffffffff;
|
||||
if (parm.glob_pref_time != 0 && parm.glob_pref_time < min_pref_time)
|
||||
min_pref_time = parm.glob_pref_time;
|
||||
|
||||
if (ioctl(daemon->icmp6fd, SIOCGIFMTU, &ifr) != -1)
|
||||
if (parm.ula_pref_time != 0 && parm.ula_pref_time < min_pref_time)
|
||||
min_pref_time = parm.ula_pref_time;
|
||||
|
||||
if (parm.link_pref_time != 0 && parm.link_pref_time < min_pref_time)
|
||||
min_pref_time = parm.link_pref_time;
|
||||
|
||||
/* Look for constructed contexts associated with addresses which have gone,
|
||||
and advertise them with preferred_time == 0 RFC 6204 4.3 L-13 */
|
||||
for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
|
||||
{
|
||||
put_opt6_char(ICMP6_OPT_MTU);
|
||||
put_opt6_char(1);
|
||||
put_opt6_short(0);
|
||||
put_opt6_long(ifr.ifr_mtu);
|
||||
tmp = context->next;
|
||||
|
||||
if (context->if_index == iface && (context->flags & CONTEXT_OLD))
|
||||
{
|
||||
unsigned int old = difftime(now, context->address_lost_time);
|
||||
|
||||
if (old > context->saved_valid)
|
||||
{
|
||||
/* We've advertised this enough, time to go */
|
||||
*up = context->next;
|
||||
free(context);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct prefix_opt *opt;
|
||||
struct in6_addr local = context->start6;
|
||||
int do_slaac = 0;
|
||||
|
||||
old_prefix = 1;
|
||||
|
||||
/* zero net part of address */
|
||||
setaddr6part(&local, addr6part(&local) & ~((context->prefix == 64) ? (u64)-1LL : (1LLU << (128 - context->prefix)) - 1LLU));
|
||||
|
||||
|
||||
if ((context->flags &
|
||||
(CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
|
||||
{
|
||||
do_slaac = 1;
|
||||
if (context->flags & CONTEXT_DHCP)
|
||||
{
|
||||
parm.other = 1;
|
||||
if (!(context->flags & CONTEXT_RA_STATELESS))
|
||||
parm.managed = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* don't do RA for non-ra-only unless --enable-ra is set */
|
||||
if (option_bool(OPT_RA))
|
||||
{
|
||||
parm.managed = 1;
|
||||
parm.other = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((opt = expand(sizeof(struct prefix_opt))))
|
||||
{
|
||||
opt->type = ICMP6_OPT_PREFIX;
|
||||
opt->len = 4;
|
||||
opt->prefix_len = context->prefix;
|
||||
/* autonomous only if we're not doing dhcp, always set "on-link" */
|
||||
opt->flags = do_slaac ? 0xC0 : 0x80;
|
||||
opt->valid_lifetime = htonl(context->saved_valid - old);
|
||||
opt->preferred_lifetime = htonl(0);
|
||||
opt->reserved = 0;
|
||||
opt->prefix = local;
|
||||
|
||||
inet_ntop(AF_INET6, &local, daemon->addrbuff, ADDRSTRLEN);
|
||||
if (!option_bool(OPT_QUIET_RA))
|
||||
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s old prefix", iface_name, daemon->addrbuff);
|
||||
}
|
||||
|
||||
up = &context->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
up = &context->next;
|
||||
}
|
||||
|
||||
/* If we're advertising only old prefixes, set router lifetime to zero. */
|
||||
if (old_prefix && !parm.found_context)
|
||||
ra->lifetime = htons(0);
|
||||
|
||||
/* No prefixes to advertise. */
|
||||
if (!old_prefix && !parm.found_context)
|
||||
return;
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* Note that IPv6 MTU is not necessarilly the same as the IPv4 MTU
|
||||
available from SIOCGIFMTU */
|
||||
sprintf(daemon->namebuff, "/proc/sys/net/ipv6/conf/%s/mtu", iface_name);
|
||||
if ((f = fopen(daemon->namebuff, "r")))
|
||||
{
|
||||
if (fgets(daemon->namebuff, MAXDNAME, f))
|
||||
{
|
||||
put_opt6_char(ICMP6_OPT_MTU);
|
||||
put_opt6_char(1);
|
||||
put_opt6_short(0);
|
||||
put_opt6_long(atoi(daemon->namebuff));
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
#endif
|
||||
|
||||
iface_enumerate(AF_LOCAL, &iface, add_lla);
|
||||
|
||||
@@ -247,22 +371,48 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
|
||||
|
||||
if (opt_cfg->opt == OPTION6_DNS_SERVER)
|
||||
{
|
||||
struct in6_addr *a = (struct in6_addr *)opt_cfg->val;
|
||||
struct in6_addr *a;
|
||||
int len;
|
||||
|
||||
done_dns = 1;
|
||||
|
||||
if (opt_cfg->len == 0)
|
||||
continue;
|
||||
continue;
|
||||
|
||||
put_opt6_char(ICMP6_OPT_RDNSS);
|
||||
put_opt6_char((opt_cfg->len/8) + 1);
|
||||
put_opt6_short(0);
|
||||
put_opt6_long(1800); /* lifetime - twice RA retransmit */
|
||||
/* zero means "self" */
|
||||
for (i = 0; i < opt_cfg->len; i += IN6ADDRSZ, a++)
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(a))
|
||||
put_opt6(&parm.link_local, IN6ADDRSZ);
|
||||
else
|
||||
put_opt6(a, IN6ADDRSZ);
|
||||
/* reduce len for any addresses we can't substitute */
|
||||
for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, i = 0;
|
||||
i < opt_cfg->len; i += IN6ADDRSZ, a++)
|
||||
if ((IN6_IS_ADDR_UNSPECIFIED(a) && parm.glob_pref_time == 0) ||
|
||||
(IN6_IS_ADDR_ULA_ZERO(a) && parm.ula_pref_time == 0) ||
|
||||
(IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && parm.link_pref_time == 0))
|
||||
len -= IN6ADDRSZ;
|
||||
|
||||
if (len != 0)
|
||||
{
|
||||
put_opt6_char(ICMP6_OPT_RDNSS);
|
||||
put_opt6_char((len/8) + 1);
|
||||
put_opt6_short(0);
|
||||
put_opt6_long(min_pref_time);
|
||||
|
||||
for (a = (struct in6_addr *)opt_cfg->val, i = 0; i < opt_cfg->len; i += IN6ADDRSZ, a++)
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(a))
|
||||
{
|
||||
if (parm.glob_pref_time != 0)
|
||||
put_opt6(&parm.link_global, IN6ADDRSZ);
|
||||
}
|
||||
else if (IN6_IS_ADDR_ULA_ZERO(a))
|
||||
{
|
||||
if (parm.ula_pref_time != 0)
|
||||
put_opt6(&parm.ula, IN6ADDRSZ);
|
||||
}
|
||||
else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
|
||||
{
|
||||
if (parm.link_pref_time != 0)
|
||||
put_opt6(&parm.link_local, IN6ADDRSZ);
|
||||
}
|
||||
else
|
||||
put_opt6(a, IN6ADDRSZ);
|
||||
}
|
||||
}
|
||||
|
||||
if (opt_cfg->opt == OPTION6_DOMAIN_SEARCH && opt_cfg->len != 0)
|
||||
@@ -272,7 +422,7 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
|
||||
put_opt6_char(ICMP6_OPT_DNSSL);
|
||||
put_opt6_char(len + 1);
|
||||
put_opt6_short(0);
|
||||
put_opt6_long(1800); /* lifetime - twice RA retransmit */
|
||||
put_opt6_long(min_pref_time);
|
||||
put_opt6(opt_cfg->val, opt_cfg->len);
|
||||
|
||||
/* pad */
|
||||
@@ -281,13 +431,13 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
|
||||
}
|
||||
}
|
||||
|
||||
if (!done_dns)
|
||||
if (daemon->port == NAMESERVER_PORT && !done_dns && parm.link_pref_time != 0)
|
||||
{
|
||||
/* default == us. */
|
||||
/* default == us, as long as we are supplying DNS service. */
|
||||
put_opt6_char(ICMP6_OPT_RDNSS);
|
||||
put_opt6_char(3);
|
||||
put_opt6_short(0);
|
||||
put_opt6_long(1800); /* lifetime - twice RA retransmit */
|
||||
put_opt6_long(min_pref_time);
|
||||
put_opt6(&parm.link_local, IN6ADDRSZ);
|
||||
}
|
||||
|
||||
@@ -312,40 +462,55 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
|
||||
addr.sin6_scope_id = iface;
|
||||
}
|
||||
else
|
||||
inet_pton(AF_INET6, ALL_NODES, &addr.sin6_addr);
|
||||
{
|
||||
inet_pton(AF_INET6, ALL_NODES, &addr.sin6_addr);
|
||||
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &iface, sizeof(iface));
|
||||
}
|
||||
|
||||
send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0),
|
||||
(union mysockaddr *)&addr, (struct all_addr *)&parm.link_local, iface);
|
||||
while (sendto(daemon->icmp6fd, daemon->outpacket.iov_base, save_counter(0), 0,
|
||||
(struct sockaddr *)&addr, sizeof(addr)) == -1 && retry_send());
|
||||
|
||||
}
|
||||
|
||||
static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam)
|
||||
int scope, int if_index, int flags,
|
||||
unsigned int preferred, unsigned int valid, void *vparam)
|
||||
{
|
||||
struct ra_param *param = vparam;
|
||||
|
||||
(void)scope; /* warning */
|
||||
(void)dad;
|
||||
|
||||
|
||||
if (if_index == param->ind)
|
||||
{
|
||||
if (IN6_IS_ADDR_LINKLOCAL(local))
|
||||
param->link_local = *local;
|
||||
{
|
||||
/* Can there be more than one LL address?
|
||||
Select the one with the longest preferred time
|
||||
if there is. */
|
||||
if (preferred > param->link_pref_time)
|
||||
{
|
||||
param->link_pref_time = preferred;
|
||||
param->link_local = *local;
|
||||
}
|
||||
}
|
||||
else if (!IN6_IS_ADDR_LOOPBACK(local) &&
|
||||
!IN6_IS_ADDR_LINKLOCAL(local) &&
|
||||
!IN6_IS_ADDR_MULTICAST(local))
|
||||
{
|
||||
int do_prefix = 0;
|
||||
int real_prefix = 0;
|
||||
int do_slaac = 0;
|
||||
int deprecate = 0;
|
||||
int constructed = 0;
|
||||
unsigned int time = 0xffffffff;
|
||||
struct dhcp_context *context;
|
||||
|
||||
for (context = daemon->ra_contexts; context; context = context->next)
|
||||
if (prefix == context->prefix &&
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix))
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
|
||||
prefix <= context->prefix &&
|
||||
is_same_net6(local, &context->start6, context->prefix) &&
|
||||
is_same_net6(local, &context->end6, context->prefix))
|
||||
{
|
||||
context->saved_valid = valid;
|
||||
|
||||
if ((context->flags &
|
||||
(CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
|
||||
{
|
||||
@@ -365,13 +530,21 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
param->managed = 1;
|
||||
param->other = 1;
|
||||
}
|
||||
|
||||
/* find floor time */
|
||||
if (time > context->lease_time)
|
||||
time = context->lease_time;
|
||||
|
||||
/* find floor time, don't reduce below 3 * RA interval. */
|
||||
if (time > context->lease_time)
|
||||
{
|
||||
time = context->lease_time;
|
||||
if (time < ((unsigned int)(3 * param->adv_interval)))
|
||||
time = 3 * param->adv_interval;
|
||||
}
|
||||
|
||||
if (context->flags & CONTEXT_DEPRECATE)
|
||||
deprecate = 1;
|
||||
|
||||
if (context->flags & CONTEXT_CONSTRUCTED)
|
||||
constructed = 1;
|
||||
|
||||
|
||||
/* collect dhcp-range tags */
|
||||
if (context->netid.next == &context->netid && context->netid.net)
|
||||
@@ -389,38 +562,66 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
if (!param->first)
|
||||
context->ra_time = 0;
|
||||
context->flags |= CONTEXT_RA_DONE;
|
||||
do_prefix = 1;
|
||||
real_prefix = context->prefix;
|
||||
}
|
||||
|
||||
param->first = 0;
|
||||
param->found_context = 1;
|
||||
}
|
||||
|
||||
/* configured time is ceiling */
|
||||
if (!constructed || valid > time)
|
||||
valid = time;
|
||||
|
||||
if (do_prefix)
|
||||
if (flags & IFACE_DEPRECATED)
|
||||
preferred = 0;
|
||||
|
||||
if (deprecate)
|
||||
time = 0;
|
||||
|
||||
/* configured time is ceiling */
|
||||
if (!constructed || preferred > time)
|
||||
preferred = time;
|
||||
|
||||
if (IN6_IS_ADDR_ULA(local))
|
||||
{
|
||||
if (preferred > param->ula_pref_time)
|
||||
{
|
||||
param->ula_pref_time = preferred;
|
||||
param->ula = *local;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (preferred > param->glob_pref_time)
|
||||
{
|
||||
param->glob_pref_time = preferred;
|
||||
param->link_global = *local;
|
||||
}
|
||||
}
|
||||
|
||||
if (real_prefix != 0)
|
||||
{
|
||||
struct prefix_opt *opt;
|
||||
|
||||
if ((opt = expand(sizeof(struct prefix_opt))))
|
||||
{
|
||||
/* zero net part of address */
|
||||
setaddr6part(local, addr6part(local) & ~((prefix == 64) ? (u64)-1LL : (1LLU << (128 - prefix)) - 1LLU));
|
||||
|
||||
/* lifetimes must be min 2 hrs, by RFC 2462 */
|
||||
if (time < 7200)
|
||||
time = 7200;
|
||||
setaddr6part(local, addr6part(local) & ~((real_prefix == 64) ? (u64)-1LL : (1LLU << (128 - real_prefix)) - 1LLU));
|
||||
|
||||
opt->type = ICMP6_OPT_PREFIX;
|
||||
opt->len = 4;
|
||||
opt->prefix_len = prefix;
|
||||
opt->prefix_len = real_prefix;
|
||||
/* autonomous only if we're not doing dhcp, always set "on-link" */
|
||||
opt->flags = do_slaac ? 0xC0 : 0x80;
|
||||
opt->valid_lifetime = htonl(time);
|
||||
opt->preferred_lifetime = htonl(deprecate ? 0 : time);
|
||||
opt->valid_lifetime = htonl(valid);
|
||||
opt->preferred_lifetime = htonl(preferred);
|
||||
opt->reserved = 0;
|
||||
opt->prefix = *local;
|
||||
|
||||
inet_ntop(AF_INET6, local, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
|
||||
if (!option_bool(OPT_QUIET_RA))
|
||||
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -454,15 +655,14 @@ time_t periodic_ra(time_t now)
|
||||
struct search_param param;
|
||||
struct dhcp_context *context;
|
||||
time_t next_event;
|
||||
char interface[IF_NAMESIZE+1];
|
||||
|
||||
|
||||
param.now = now;
|
||||
param.iface = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* find overdue events, and time of first future event */
|
||||
for (next_event = 0, context = daemon->ra_contexts; context; context = context->next)
|
||||
for (next_event = 0, context = daemon->dhcp6; context; context = context->next)
|
||||
if (context->ra_time != 0)
|
||||
{
|
||||
if (difftime(context->ra_time, now) <= 0.0)
|
||||
@@ -476,70 +676,151 @@ time_t periodic_ra(time_t now)
|
||||
if (!context)
|
||||
break;
|
||||
|
||||
/* There's a context overdue, but we can't find an interface
|
||||
associated with it, because it's for a subnet we dont
|
||||
have an interface on. Probably we're doing DHCP on
|
||||
a remote subnet via a relay. Zero the timer, since we won't
|
||||
ever be able to send ra's and satistfy it. */
|
||||
if (iface_enumerate(AF_INET6, ¶m, iface_search))
|
||||
if ((context->flags & CONTEXT_OLD) &&
|
||||
context->if_index != 0 &&
|
||||
indextoname(daemon->icmp6fd, context->if_index, param.name))
|
||||
{
|
||||
/* A context for an old address. We'll not find the interface by
|
||||
looking for addresses, but we know it anyway, since the context is
|
||||
constructed */
|
||||
param.iface = context->if_index;
|
||||
new_timeout(context, param.name, now);
|
||||
}
|
||||
else if (iface_enumerate(AF_INET6, ¶m, iface_search))
|
||||
/* There's a context overdue, but we can't find an interface
|
||||
associated with it, because it's for a subnet we dont
|
||||
have an interface on. Probably we're doing DHCP on
|
||||
a remote subnet via a relay. Zero the timer, since we won't
|
||||
ever be able to send ra's and satistfy it. */
|
||||
context->ra_time = 0;
|
||||
else if (param.iface != 0 &&
|
||||
indextoname(daemon->icmp6fd, param.iface, interface) &&
|
||||
iface_check(AF_LOCAL, NULL, interface))
|
||||
|
||||
if (param.iface != 0 &&
|
||||
iface_check(AF_LOCAL, NULL, param.name, NULL))
|
||||
{
|
||||
struct iname *tmp;
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, interface) == 0))
|
||||
if (tmp->name && wildcard_match(tmp->name, param.name))
|
||||
break;
|
||||
if (!tmp)
|
||||
send_ra(param.iface, interface, NULL);
|
||||
send_ra(now, param.iface, param.name, NULL);
|
||||
}
|
||||
}
|
||||
return next_event;
|
||||
}
|
||||
|
||||
static int iface_search(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam)
|
||||
int scope, int if_index, int flags,
|
||||
int preferred, int valid, void *vparam)
|
||||
{
|
||||
struct search_param *param = vparam;
|
||||
struct dhcp_context *context;
|
||||
|
||||
(void)scope;
|
||||
(void)dad;
|
||||
(void)preferred;
|
||||
(void)valid;
|
||||
|
||||
for (context = daemon->ra_contexts; context; context = context->next)
|
||||
if (prefix == context->prefix &&
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix))
|
||||
if (context->ra_time != 0 && difftime(context->ra_time, param->now) <= 0.0)
|
||||
{
|
||||
/* found an interface that's overdue for RA determine new
|
||||
timeout value and arrange for RA to be sent unless interface is
|
||||
still doing DAD.*/
|
||||
|
||||
if (!dad)
|
||||
param->iface = if_index;
|
||||
|
||||
if (difftime(param->now, ra_short_period_start) < 60.0)
|
||||
/* range 5 - 20 */
|
||||
context->ra_time = param->now + 5 + (rand16()/4400);
|
||||
else
|
||||
/* range 450 - 600 */
|
||||
context->ra_time = param->now + 450 + (rand16()/440);
|
||||
|
||||
/* zero timers for other contexts on the same subnet, so they don't timeout
|
||||
independently */
|
||||
for (context = context->next; context; context = context->next)
|
||||
if (prefix == context->prefix &&
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix))
|
||||
context->ra_time = 0;
|
||||
|
||||
return 0; /* found, abort */
|
||||
}
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
|
||||
prefix <= context->prefix &&
|
||||
is_same_net6(local, &context->start6, context->prefix) &&
|
||||
is_same_net6(local, &context->end6, context->prefix) &&
|
||||
context->ra_time != 0 &&
|
||||
difftime(context->ra_time, param->now) <= 0.0)
|
||||
{
|
||||
/* found an interface that's overdue for RA determine new
|
||||
timeout value and arrange for RA to be sent unless interface is
|
||||
still doing DAD.*/
|
||||
|
||||
if (!(flags & IFACE_TENTATIVE))
|
||||
param->iface = if_index;
|
||||
|
||||
/* should never fail */
|
||||
if (!indextoname(daemon->icmp6fd, if_index, param->name))
|
||||
{
|
||||
param->iface = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
new_timeout(context, param->name, param->now);
|
||||
|
||||
/* zero timers for other contexts on the same subnet, so they don't timeout
|
||||
independently */
|
||||
for (context = context->next; context; context = context->next)
|
||||
if (prefix <= context->prefix &&
|
||||
is_same_net6(local, &context->start6, context->prefix) &&
|
||||
is_same_net6(local, &context->end6, context->prefix))
|
||||
context->ra_time = 0;
|
||||
|
||||
return 0; /* found, abort */
|
||||
}
|
||||
|
||||
return 1; /* keep searching */
|
||||
}
|
||||
|
||||
static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now)
|
||||
{
|
||||
if (difftime(now, context->ra_short_period_start) < 60.0)
|
||||
/* range 5 - 20 */
|
||||
context->ra_time = now + 5 + (rand16()/4400);
|
||||
else
|
||||
{
|
||||
/* range 3/4 - 1 times MaxRtrAdvInterval */
|
||||
unsigned int adv_interval = calc_interval(find_iface_param(iface_name));
|
||||
context->ra_time = now + (3 * adv_interval)/4 + ((adv_interval * (unsigned int)rand16()) >> 18);
|
||||
}
|
||||
}
|
||||
|
||||
static struct ra_interface *find_iface_param(char *iface)
|
||||
{
|
||||
struct ra_interface *ra;
|
||||
|
||||
for (ra = daemon->ra_interfaces; ra; ra = ra->next)
|
||||
if (wildcard_match(ra->name, iface))
|
||||
return ra;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned int calc_interval(struct ra_interface *ra)
|
||||
{
|
||||
int interval = 600;
|
||||
|
||||
if (ra && ra->interval != 0)
|
||||
{
|
||||
interval = ra->interval;
|
||||
if (interval > 1800)
|
||||
interval = 1800;
|
||||
else if (interval < 4)
|
||||
interval = 4;
|
||||
}
|
||||
|
||||
return (unsigned int)interval;
|
||||
}
|
||||
|
||||
static unsigned int calc_lifetime(struct ra_interface *ra)
|
||||
{
|
||||
int lifetime, interval = (int)calc_interval(ra);
|
||||
|
||||
if (!ra || ra->lifetime == -1) /* not specified */
|
||||
lifetime = 3 * interval;
|
||||
else
|
||||
{
|
||||
lifetime = ra->lifetime;
|
||||
if (lifetime < interval && lifetime != 0)
|
||||
lifetime = interval;
|
||||
else if (lifetime > 9000)
|
||||
lifetime = 9000;
|
||||
}
|
||||
|
||||
return (unsigned int)lifetime;
|
||||
}
|
||||
|
||||
static unsigned int calc_prio(struct ra_interface *ra)
|
||||
{
|
||||
if (ra)
|
||||
return ra->prio;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
1067
src/rfc1035.c
1067
src/rfc1035.c
File diff suppressed because it is too large
Load Diff
354
src/rfc2131.c
354
src/rfc2131.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -34,11 +34,12 @@ static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
|
||||
static struct in_addr option_addr(unsigned char *opt);
|
||||
static unsigned int option_uint(unsigned char *opt, int i, int size);
|
||||
static void log_packet(char *type, void *addr, unsigned char *ext_mac,
|
||||
int mac_len, char *interface, char *string, u32 xid);
|
||||
int mac_len, char *interface, char *string, char *err, u32 xid);
|
||||
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
|
||||
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
|
||||
static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end);
|
||||
static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
|
||||
static int in_list(unsigned char *list, int opt);
|
||||
static void do_options(struct dhcp_context *context,
|
||||
struct dhcp_packet *mess,
|
||||
unsigned char *real_end,
|
||||
@@ -91,7 +92,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
struct dhcp_netid known_id, iface_id, cpewan_id;
|
||||
struct dhcp_opt *o;
|
||||
unsigned char pxe_uuid[17];
|
||||
unsigned char *oui = NULL, *serial = NULL, *class = NULL;
|
||||
unsigned char *oui = NULL, *serial = NULL;
|
||||
#ifdef HAVE_SCRIPT
|
||||
unsigned char *class = NULL;
|
||||
#endif
|
||||
|
||||
subnet_addr.s_addr = override.s_addr = 0;
|
||||
|
||||
@@ -155,8 +159,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
unsigned char *y = option_ptr(opt, offset + elen + 5);
|
||||
oui = option_find1(x, y, 1, 1);
|
||||
serial = option_find1(x, y, 2, 1);
|
||||
class = option_find1(x, y, 3, 1);
|
||||
|
||||
#ifdef HAVE_SCRIPT
|
||||
class = option_find1(x, y, 3, 1);
|
||||
#endif
|
||||
/* If TR069-id is present set the tag "cpewan-id" to facilitate echoing
|
||||
the gateway id back. Note that the device class is optional */
|
||||
if (oui && serial)
|
||||
@@ -354,6 +359,117 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->end));
|
||||
}
|
||||
}
|
||||
|
||||
/* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
|
||||
Otherwise assume the option is an array, and look for a matching element.
|
||||
If no data given, existance of the option is enough. This code handles
|
||||
rfc3925 V-I classes too. */
|
||||
for (o = daemon->dhcp_match; o; o = o->next)
|
||||
{
|
||||
unsigned int len, elen, match = 0;
|
||||
size_t offset, o2;
|
||||
|
||||
if (o->flags & DHOPT_RFC3925)
|
||||
{
|
||||
if (!(opt = option_find(mess, sz, OPTION_VENDOR_IDENT, 5)))
|
||||
continue;
|
||||
|
||||
for (offset = 0; offset < (option_len(opt) - 5u); offset += len + 5)
|
||||
{
|
||||
len = option_uint(opt, offset + 4 , 1);
|
||||
/* Need to take care that bad data can't run us off the end of the packet */
|
||||
if ((offset + len + 5 <= (option_len(opt))) &&
|
||||
(option_uint(opt, offset, 4) == (unsigned int)o->u.encap))
|
||||
for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
|
||||
{
|
||||
elen = option_uint(opt, o2, 1);
|
||||
if ((o2 + elen + 1 <= option_len(opt)) &&
|
||||
(match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))
|
||||
break;
|
||||
}
|
||||
if (match)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(opt = option_find(mess, sz, o->opt, 1)))
|
||||
continue;
|
||||
|
||||
match = match_bytes(o, option_ptr(opt, 0), option_len(opt));
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
o->netid->next = netid;
|
||||
netid = o->netid;
|
||||
}
|
||||
}
|
||||
|
||||
/* user-class options are, according to RFC3004, supposed to contain
|
||||
a set of counted strings. Here we check that this is so (by seeing
|
||||
if the counts are consistent with the overall option length) and if
|
||||
so zero the counts so that we don't get spurious matches between
|
||||
the vendor string and the counts. If the lengths don't add up, we
|
||||
assume that the option is a single string and non RFC3004 compliant
|
||||
and just do the substring match. dhclient provides these broken options.
|
||||
The code, later, which sends user-class data to the lease-change script
|
||||
relies on the transformation done here.
|
||||
*/
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
|
||||
{
|
||||
unsigned char *ucp = option_ptr(opt, 0);
|
||||
int tmp, j;
|
||||
for (j = 0; j < option_len(opt); j += ucp[j] + 1);
|
||||
if (j == option_len(opt))
|
||||
for (j = 0; j < option_len(opt); j = tmp)
|
||||
{
|
||||
tmp = j + ucp[j] + 1;
|
||||
ucp[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
||||
{
|
||||
int mopt;
|
||||
|
||||
if (vendor->match_type == MATCH_VENDOR)
|
||||
mopt = OPTION_VENDOR_ID;
|
||||
else if (vendor->match_type == MATCH_USER)
|
||||
mopt = OPTION_USER_CLASS;
|
||||
else
|
||||
continue;
|
||||
|
||||
if ((opt = option_find(mess, sz, mopt, 1)))
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i <= (option_len(opt) - vendor->len); i++)
|
||||
if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0)
|
||||
{
|
||||
vendor->netid.next = netid;
|
||||
netid = &vendor->netid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* mark vendor-encapsulated options which match the client-supplied vendor class,
|
||||
save client-supplied vendor class */
|
||||
if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
|
||||
{
|
||||
memcpy(daemon->dhcp_buff3, option_ptr(opt, 0), option_len(opt));
|
||||
vendor_class_len = option_len(opt);
|
||||
}
|
||||
match_vendor_opts(opt, daemon->dhcp_opts);
|
||||
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
if (sanitise(opt, daemon->namebuff))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %s"), ntohl(mess->xid), daemon->namebuff);
|
||||
if (sanitise(option_find(mess, sz, OPTION_USER_CLASS, 1), daemon->namebuff))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u user class: %s"), ntohl(mess->xid), daemon->namebuff);
|
||||
}
|
||||
|
||||
mess->op = BOOTREPLY;
|
||||
|
||||
@@ -493,18 +609,17 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
lease_set_interface(lease, int_index, now);
|
||||
|
||||
clear_packet(mess, end);
|
||||
match_vendor_opts(NULL, daemon->dhcp_opts); /* clear flags */
|
||||
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
|
||||
netid, subnet_addr, 0, 0, -1, NULL, 0, now);
|
||||
netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now);
|
||||
}
|
||||
}
|
||||
|
||||
log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, message, mess->xid);
|
||||
log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, NULL, message, mess->xid);
|
||||
|
||||
return message ? 0 : dhcp_packet_size(mess, agent_id, real_end);
|
||||
}
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 4)))
|
||||
if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 3)))
|
||||
{
|
||||
/* http://tools.ietf.org/wg/dhc/draft-ietf-dhc-fqdn-option/draft-ietf-dhc-fqdn-option-10.txt */
|
||||
int len = option_len(opt);
|
||||
@@ -534,7 +649,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
}
|
||||
|
||||
if (fqdn_flags & 0x04)
|
||||
while (*op != 0 && ((op + (*op) + 1) - pp) < len)
|
||||
while (*op != 0 && ((op + (*op)) - pp) < len)
|
||||
{
|
||||
memcpy(pq, op+1, *op);
|
||||
pq += *op;
|
||||
@@ -622,119 +737,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
}
|
||||
}
|
||||
|
||||
/* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
|
||||
Otherwise assume the option is an array, and look for a matching element.
|
||||
If no data given, existance of the option is enough. This code handles
|
||||
rfc3925 V-I classes too. */
|
||||
for (o = daemon->dhcp_match; o; o = o->next)
|
||||
{
|
||||
unsigned int len, elen, match = 0;
|
||||
size_t offset, o2;
|
||||
|
||||
if (o->flags & DHOPT_RFC3925)
|
||||
{
|
||||
if (!(opt = option_find(mess, sz, OPTION_VENDOR_IDENT, 5)))
|
||||
continue;
|
||||
|
||||
for (offset = 0; offset < (option_len(opt) - 5u); offset += len + 5)
|
||||
{
|
||||
len = option_uint(opt, offset + 4 , 1);
|
||||
/* Need to take care that bad data can't run us off the end of the packet */
|
||||
if ((offset + len + 5 <= (option_len(opt))) &&
|
||||
(option_uint(opt, offset, 4) == (unsigned int)o->u.encap))
|
||||
for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
|
||||
{
|
||||
elen = option_uint(opt, o2, 1);
|
||||
if ((o2 + elen + 1 <= option_len(opt)) &&
|
||||
(match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))
|
||||
break;
|
||||
}
|
||||
if (match)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(opt = option_find(mess, sz, o->opt, 1)))
|
||||
continue;
|
||||
|
||||
match = match_bytes(o, option_ptr(opt, 0), option_len(opt));
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
o->netid->next = netid;
|
||||
netid = o->netid;
|
||||
}
|
||||
}
|
||||
|
||||
/* user-class options are, according to RFC3004, supposed to contain
|
||||
a set of counted strings. Here we check that this is so (by seeing
|
||||
if the counts are consistent with the overall option length) and if
|
||||
so zero the counts so that we don't get spurious matches between
|
||||
the vendor string and the counts. If the lengths don't add up, we
|
||||
assume that the option is a single string and non RFC3004 compliant
|
||||
and just do the substring match. dhclient provides these broken options.
|
||||
The code, later, which sends user-class data to the lease-change script
|
||||
relies on the transformation done here.
|
||||
*/
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
|
||||
{
|
||||
unsigned char *ucp = option_ptr(opt, 0);
|
||||
int tmp, j;
|
||||
for (j = 0; j < option_len(opt); j += ucp[j] + 1);
|
||||
if (j == option_len(opt))
|
||||
for (j = 0; j < option_len(opt); j = tmp)
|
||||
{
|
||||
tmp = j + ucp[j] + 1;
|
||||
ucp[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
||||
{
|
||||
int mopt;
|
||||
|
||||
if (vendor->match_type == MATCH_VENDOR)
|
||||
mopt = OPTION_VENDOR_ID;
|
||||
else if (vendor->match_type == MATCH_USER)
|
||||
mopt = OPTION_USER_CLASS;
|
||||
else
|
||||
continue;
|
||||
|
||||
if ((opt = option_find(mess, sz, mopt, 1)))
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i <= (option_len(opt) - vendor->len); i++)
|
||||
if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0)
|
||||
{
|
||||
vendor->netid.next = netid;
|
||||
netid = &vendor->netid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* mark vendor-encapsulated options which match the client-supplied vendor class,
|
||||
save client-supplied vendor class */
|
||||
if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
|
||||
{
|
||||
memcpy(daemon->dhcp_buff3, option_ptr(opt, 0), option_len(opt));
|
||||
vendor_class_len = option_len(opt);
|
||||
}
|
||||
match_vendor_opts(opt, daemon->dhcp_opts);
|
||||
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
if (sanitise(opt, daemon->namebuff))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %s"), ntohl(mess->xid), daemon->namebuff);
|
||||
if (sanitise(option_find(mess, sz, OPTION_USER_CLASS, 1), daemon->namebuff))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u user class: %s"), ntohl(mess->xid), daemon->namebuff);
|
||||
}
|
||||
|
||||
tagif_netid = run_tag_if(netid);
|
||||
|
||||
|
||||
/* if all the netids in the ignore list are present, ignore this client */
|
||||
for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
|
||||
if (match_netid(id_list->list, tagif_netid, 0))
|
||||
@@ -827,7 +831,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
opt71.next = daemon->dhcp_opts;
|
||||
do_encap_opts(&opt71, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||
|
||||
log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, mess->xid);
|
||||
log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, NULL, mess->xid);
|
||||
log_tags(tagif_netid, ntohl(mess->xid));
|
||||
return dhcp_packet_size(mess, agent_id, real_end);
|
||||
}
|
||||
@@ -848,8 +852,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
if (tmp)
|
||||
{
|
||||
struct dhcp_boot *boot = find_boot(tagif_netid);
|
||||
|
||||
struct dhcp_boot *boot;
|
||||
|
||||
if (tmp->netid.net)
|
||||
{
|
||||
tmp->netid.next = netid;
|
||||
tagif_netid = run_tag_if(&tmp->netid);
|
||||
}
|
||||
|
||||
boot = find_boot(tagif_netid);
|
||||
|
||||
mess->yiaddr.s_addr = 0;
|
||||
if (mess_type == DHCPDISCOVER || mess->ciaddr.s_addr == 0)
|
||||
{
|
||||
@@ -879,7 +891,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
prune_vendor_opts(tagif_netid);
|
||||
do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||
|
||||
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", mess->xid);
|
||||
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid);
|
||||
log_tags(tagif_netid, ntohl(mess->xid));
|
||||
return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end);
|
||||
}
|
||||
@@ -911,7 +923,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
|
||||
return 0;
|
||||
|
||||
log_packet("DHCPDECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, daemon->dhcp_buff, mess->xid);
|
||||
log_packet("DHCPDECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, NULL, daemon->dhcp_buff, mess->xid);
|
||||
|
||||
if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
|
||||
lease_prune(lease, now);
|
||||
@@ -943,13 +955,15 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
else
|
||||
message = _("unknown lease");
|
||||
|
||||
log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, message, mess->xid);
|
||||
log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
|
||||
|
||||
return 0;
|
||||
|
||||
case DHCPDISCOVER:
|
||||
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||
{
|
||||
if (option_bool(OPT_QUIET_DHCP))
|
||||
return 0;
|
||||
message = _("ignored");
|
||||
opt = NULL;
|
||||
}
|
||||
@@ -1007,7 +1021,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
message = _("no address available");
|
||||
}
|
||||
|
||||
log_packet("DHCPDISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, message, mess->xid);
|
||||
log_packet("DHCPDISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, NULL, message, mess->xid);
|
||||
|
||||
if (message || !(context = narrow_context(context, mess->yiaddr, tagif_netid)))
|
||||
return 0;
|
||||
@@ -1020,7 +1034,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
log_tags(tagif_netid, ntohl(mess->xid));
|
||||
|
||||
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
|
||||
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
|
||||
|
||||
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
|
||||
clear_packet(mess, end);
|
||||
@@ -1072,7 +1086,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
Have to set override to make sure we echo back the correct server-id */
|
||||
struct irec *intr;
|
||||
|
||||
enumerate_interfaces();
|
||||
enumerate_interfaces(0);
|
||||
|
||||
for (intr = daemon->interfaces; intr; intr = intr->next)
|
||||
if (intr->addr.sa.sa_family == AF_INET &&
|
||||
@@ -1136,7 +1150,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
mess->yiaddr = mess->ciaddr;
|
||||
}
|
||||
|
||||
log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
|
||||
log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
|
||||
|
||||
if (!message)
|
||||
{
|
||||
@@ -1208,7 +1222,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
if (message)
|
||||
{
|
||||
log_packet("DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, message, mess->xid);
|
||||
log_packet("DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
|
||||
|
||||
mess->yiaddr.s_addr = 0;
|
||||
clear_packet(mess, end);
|
||||
@@ -1256,7 +1270,20 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
add_extradata_opt(lease, oui);
|
||||
add_extradata_opt(lease, serial);
|
||||
add_extradata_opt(lease, class);
|
||||
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_AGENT_ID, 1)))
|
||||
{
|
||||
add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_CIRCUIT_ID, 1));
|
||||
add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SUBSCR_ID, 1));
|
||||
add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_REMOTE_ID, 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
add_extradata_opt(lease, NULL);
|
||||
add_extradata_opt(lease, NULL);
|
||||
add_extradata_opt(lease, NULL);
|
||||
}
|
||||
|
||||
/* space-concat tag set */
|
||||
if (!tagif_netid)
|
||||
add_extradata_opt(lease, NULL);
|
||||
@@ -1334,7 +1361,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
else
|
||||
override = lease->override;
|
||||
|
||||
log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, mess->xid);
|
||||
log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);
|
||||
|
||||
clear_packet(mess, end);
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
||||
@@ -1357,7 +1384,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||
message = _("ignored");
|
||||
|
||||
log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, mess->xid);
|
||||
log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, NULL, mess->xid);
|
||||
|
||||
if (message || mess->ciaddr.s_addr == 0)
|
||||
return 0;
|
||||
@@ -1372,8 +1399,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
lease->hostname)
|
||||
hostname = lease->hostname;
|
||||
|
||||
if (!hostname && (hostname = host_from_dns(mess->ciaddr)))
|
||||
domain = get_domain(mess->ciaddr);
|
||||
if (!hostname)
|
||||
hostname = host_from_dns(mess->ciaddr);
|
||||
|
||||
if (context && context->netid.net)
|
||||
{
|
||||
@@ -1383,7 +1410,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
log_tags(tagif_netid, ntohl(mess->xid));
|
||||
|
||||
log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, mess->xid);
|
||||
log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);
|
||||
|
||||
if (lease)
|
||||
{
|
||||
@@ -1397,7 +1424,21 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
clear_packet(mess, end);
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
|
||||
|
||||
|
||||
/* RFC 2131 says that DHCPINFORM shouldn't include lease-time parameters, but
|
||||
we supply a utility which makes DHCPINFORM requests to get this information.
|
||||
Only include lease time if OPTION_LEASE_TIME is in the parameter request list,
|
||||
which won't be true for ordinary clients, but will be true for the
|
||||
dhcp_lease_time utility. */
|
||||
if (lease && in_list(req_options, OPTION_LEASE_TIME))
|
||||
{
|
||||
if (lease->expires == 0)
|
||||
time = 0xffffffff;
|
||||
else
|
||||
time = (unsigned int)difftime(lease->expires, now);
|
||||
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
|
||||
}
|
||||
|
||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||
|
||||
@@ -1503,10 +1544,13 @@ static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt)
|
||||
#endif
|
||||
|
||||
static void log_packet(char *type, void *addr, unsigned char *ext_mac,
|
||||
int mac_len, char *interface, char *string, u32 xid)
|
||||
int mac_len, char *interface, char *string, char *err, u32 xid)
|
||||
{
|
||||
struct in_addr a;
|
||||
|
||||
if (!err && !option_bool(OPT_LOG_OPTS) && option_bool(OPT_QUIET_DHCP))
|
||||
return;
|
||||
|
||||
/* addr may be misaligned */
|
||||
if (addr)
|
||||
memcpy(&a, addr, sizeof(a));
|
||||
@@ -1514,22 +1558,24 @@ static void log_packet(char *type, void *addr, unsigned char *ext_mac,
|
||||
print_mac(daemon->namebuff, ext_mac, mac_len);
|
||||
|
||||
if(option_bool(OPT_LOG_OPTS))
|
||||
my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s%s %s",
|
||||
my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s%s %s%s",
|
||||
ntohl(xid),
|
||||
type,
|
||||
interface,
|
||||
addr ? inet_ntoa(a) : "",
|
||||
addr ? " " : "",
|
||||
daemon->namebuff,
|
||||
string ? string : "");
|
||||
string ? string : "",
|
||||
err ? err : "");
|
||||
else
|
||||
my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s%s %s",
|
||||
my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s%s %s%s",
|
||||
type,
|
||||
interface,
|
||||
addr ? inet_ntoa(a) : "",
|
||||
addr ? " " : "",
|
||||
daemon->namebuff,
|
||||
string ? string : "");
|
||||
string ? string : "",
|
||||
err ? err : "");
|
||||
}
|
||||
|
||||
static void log_options(unsigned char *start, u32 xid)
|
||||
@@ -1739,7 +1785,7 @@ static unsigned char *free_space(struct dhcp_packet *mess, unsigned char *end, i
|
||||
if (overload[2] & 2)
|
||||
{
|
||||
p = dhcp_skip_opts(mess->sname);
|
||||
if (p + len + 3 >= mess->sname + sizeof(mess->file))
|
||||
if (p + len + 3 >= mess->sname + sizeof(mess->sname))
|
||||
p = NULL;
|
||||
}
|
||||
}
|
||||
@@ -1806,7 +1852,8 @@ static int do_opt(struct dhcp_opt *opt, unsigned char *p, struct dhcp_context *c
|
||||
}
|
||||
}
|
||||
else
|
||||
memcpy(p, opt->val, len);
|
||||
/* empty string may be extended to "\0" by null_term */
|
||||
memcpy(p, opt->val ? opt->val : (unsigned char *)"", len);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
@@ -2234,7 +2281,8 @@ static void do_options(struct dhcp_context *context,
|
||||
!option_find2(OPTION_ROUTER))
|
||||
option_put(mess, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr));
|
||||
|
||||
if (in_list(req_options, OPTION_DNSSERVER) &&
|
||||
if (daemon->port == NAMESERVER_PORT &&
|
||||
in_list(req_options, OPTION_DNSSERVER) &&
|
||||
!option_find2(OPTION_DNSSERVER))
|
||||
option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
|
||||
}
|
||||
@@ -2261,7 +2309,9 @@ static void do_options(struct dhcp_context *context,
|
||||
|
||||
if (domain)
|
||||
len += strlen(domain) + 1;
|
||||
|
||||
else if (fqdn_flags & 0x04)
|
||||
len--;
|
||||
|
||||
if ((p = free_space(mess, end, OPTION_CLIENT_FQDN, len)))
|
||||
{
|
||||
*(p++) = fqdn_flags & 0x0f; /* MBZ bits to zero */
|
||||
@@ -2272,8 +2322,10 @@ static void do_options(struct dhcp_context *context,
|
||||
{
|
||||
p = do_rfc1035_name(p, hostname);
|
||||
if (domain)
|
||||
p = do_rfc1035_name(p, domain);
|
||||
*p++ = 0;
|
||||
{
|
||||
p = do_rfc1035_name(p, domain);
|
||||
*p++ = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
1957
src/rfc3315.c
1957
src/rfc3315.c
File diff suppressed because it is too large
Load Diff
70
src/slaac.c
70
src/slaac.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
static int map_rebuild = 0;
|
||||
static int ping_id = 0;
|
||||
|
||||
void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force)
|
||||
@@ -38,8 +37,10 @@ void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force)
|
||||
old = lease->slaac_address;
|
||||
lease->slaac_address = NULL;
|
||||
|
||||
for (context = daemon->ra_contexts; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_RA_NAME) && lease->last_interface == context->if_index)
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_RA_NAME) &&
|
||||
!(context->flags & CONTEXT_OLD) &&
|
||||
lease->last_interface == context->if_index)
|
||||
{
|
||||
struct in6_addr addr = context->start6;
|
||||
if (lease->hwaddr_len == 6 &&
|
||||
@@ -92,7 +93,6 @@ void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force)
|
||||
slaac->ping_time = now;
|
||||
slaac->backoff = 1;
|
||||
slaac->addr = addr;
|
||||
slaac->local = context->local6;
|
||||
/* Do RA's to prod it */
|
||||
ra_start_unsolicted(now, context);
|
||||
}
|
||||
@@ -123,8 +123,8 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
|
||||
struct slaac_address *slaac;
|
||||
time_t next_event = 0;
|
||||
|
||||
for (context = daemon->ra_contexts; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_RA_NAME))
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
|
||||
break;
|
||||
|
||||
/* nothing configured */
|
||||
@@ -134,12 +134,6 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
|
||||
while (ping_id == 0)
|
||||
ping_id = rand16();
|
||||
|
||||
if (map_rebuild)
|
||||
{
|
||||
map_rebuild = 0;
|
||||
build_subnet_map();
|
||||
}
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
|
||||
{
|
||||
@@ -205,57 +199,11 @@ void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *inte
|
||||
slaac->backoff = 0;
|
||||
gotone = 1;
|
||||
inet_ntop(AF_INET6, sender, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_INFO, "SLAAC-CONFIRM(%s) %s %s", interface, daemon->addrbuff, lease->hostname);
|
||||
if (!option_bool(OPT_QUIET_DHCP6))
|
||||
my_syslog(MS_DHCP | LOG_INFO, "SLAAC-CONFIRM(%s) %s %s", interface, daemon->addrbuff, lease->hostname);
|
||||
}
|
||||
|
||||
lease_update_dns(gotone);
|
||||
}
|
||||
|
||||
/* Build a map from ra-names subnets to corresponding interfaces. This
|
||||
is used to go from DHCPv4 leases to SLAAC addresses,
|
||||
interface->IPv6-subnet, IPv6-subnet + MAC address -> SLAAC.
|
||||
*/
|
||||
static int add_subnet(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
|
||||
(void)scope;
|
||||
(void)dad;
|
||||
(void)vparam;
|
||||
|
||||
for (context = daemon->ra_contexts; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_RA_NAME) &&
|
||||
prefix == context->prefix &&
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix))
|
||||
{
|
||||
context->if_index = if_index;
|
||||
context->local6 = *local;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void build_subnet_map(void)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
int ok = 0;
|
||||
|
||||
for (context = daemon->ra_contexts; context; context = context->next)
|
||||
{
|
||||
context->if_index = 0;
|
||||
if ((context->flags & CONTEXT_RA_NAME))
|
||||
ok = 1;
|
||||
}
|
||||
|
||||
/* ra-names configured */
|
||||
if (ok)
|
||||
iface_enumerate(AF_INET6, NULL, add_subnet);
|
||||
}
|
||||
|
||||
void schedule_subnet_map(void)
|
||||
{
|
||||
map_rebuild = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
58
src/tftp.c
58
src/tftp.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -49,9 +49,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
struct iovec iov;
|
||||
struct ifreq ifr;
|
||||
int is_err = 1, if_index = 0, mtu = 0;
|
||||
#ifdef HAVE_DHCP
|
||||
struct iname *tmp;
|
||||
#endif
|
||||
struct tftp_transfer *transfer;
|
||||
int port = daemon->start_tftp_port; /* may be zero to use ephemeral port */
|
||||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
||||
@@ -61,7 +59,13 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
char *name = NULL;
|
||||
char *prefix = daemon->tftp_prefix;
|
||||
struct tftp_prefix *pref;
|
||||
|
||||
struct all_addr addra;
|
||||
#ifdef HAVE_IPV6
|
||||
/* Can always get recvd interface for IPv6 */
|
||||
int check_dest = !option_bool(OPT_NOWILD) || listen->family == AF_INET6;
|
||||
#else
|
||||
int check_dest = !option_bool(OPT_NOWILD);
|
||||
#endif
|
||||
union {
|
||||
struct cmsghdr align; /* this ensures alignment */
|
||||
#ifdef HAVE_IPV6
|
||||
@@ -92,8 +96,9 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
|
||||
if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2)
|
||||
return;
|
||||
|
||||
if (option_bool(OPT_NOWILD))
|
||||
|
||||
/* Can always get recvd interface for IPv6 */
|
||||
if (!check_dest)
|
||||
{
|
||||
if (listen->iface)
|
||||
{
|
||||
@@ -189,25 +194,44 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
return;
|
||||
|
||||
name = namebuff;
|
||||
|
||||
addra.addr.addr4 = addr.in.sin_addr;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (listen->family == AF_INET6)
|
||||
addra.addr.addr6 = addr.in6.sin6_addr;
|
||||
#endif
|
||||
|
||||
if (daemon->tftp_interfaces)
|
||||
{
|
||||
if (!iface_check(AF_INET6, (struct all_addr *)&addr.in6.sin6_addr, name))
|
||||
/* dedicated tftp interface list */
|
||||
for (tmp = daemon->tftp_interfaces; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, name))
|
||||
break;
|
||||
|
||||
if (!tmp)
|
||||
return;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (!iface_check(AF_INET, (struct all_addr *)&addr.in.sin_addr, name))
|
||||
return;
|
||||
|
||||
{
|
||||
/* Do the same as DHCP */
|
||||
if (!iface_check(listen->family, &addra, name, NULL))
|
||||
{
|
||||
if (!option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces(0);
|
||||
if (!loopback_exception(listen->tftpfd, listen->family, &addra, name) &&
|
||||
!label_exception(if_index, listen->family, &addra) )
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
/* allowed interfaces are the same as for DHCP */
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
||||
return;
|
||||
/* allowed interfaces are the same as for DHCP */
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, name))
|
||||
return;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
strncpy(ifr.ifr_name, name, IF_NAMESIZE);
|
||||
if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
|
||||
mtu = ifr.ifr_mtu;
|
||||
@@ -549,7 +573,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
}
|
||||
/* don't complain about timeout when we're awaiting the last
|
||||
ACK, some clients never send it */
|
||||
else if (++transfer->backoff > 5 && len != 0)
|
||||
else if (++transfer->backoff > 7 && len != 0)
|
||||
{
|
||||
endcon = 1;
|
||||
len = 0;
|
||||
|
||||
79
src/util.c
79
src/util.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -28,24 +28,12 @@
|
||||
#include <idna.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ARC4RANDOM
|
||||
void rand_init(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned short rand16(void)
|
||||
{
|
||||
return (unsigned short) (arc4random() >> 15);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* SURF random number generator */
|
||||
|
||||
static u32 seed[32];
|
||||
static u32 in[12];
|
||||
static u32 out[8];
|
||||
static int outleft = 0;
|
||||
|
||||
void rand_init()
|
||||
{
|
||||
@@ -83,18 +71,31 @@ static void surf(void)
|
||||
|
||||
unsigned short rand16(void)
|
||||
{
|
||||
static int outleft = 0;
|
||||
|
||||
if (!outleft) {
|
||||
if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
|
||||
surf();
|
||||
outleft = 8;
|
||||
}
|
||||
|
||||
if (!outleft)
|
||||
{
|
||||
if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
|
||||
surf();
|
||||
outleft = 8;
|
||||
}
|
||||
|
||||
return (unsigned short) out[--outleft];
|
||||
}
|
||||
|
||||
#endif
|
||||
u64 rand64(void)
|
||||
{
|
||||
static int outleft = 0;
|
||||
|
||||
if (outleft < 2)
|
||||
{
|
||||
if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
|
||||
surf();
|
||||
outleft = 8;
|
||||
}
|
||||
|
||||
outleft -= 2;
|
||||
|
||||
return (u64)out[outleft+1] + (((u64)out[outleft]) << 32);
|
||||
}
|
||||
|
||||
static int check_name(char *in)
|
||||
{
|
||||
@@ -108,10 +109,10 @@ static int check_name(char *in)
|
||||
|
||||
if (in[l-1] == '.')
|
||||
{
|
||||
if (l == 1) return 0;
|
||||
in[l-1] = 0;
|
||||
nowhite = 1;
|
||||
}
|
||||
|
||||
|
||||
for (; (c = *in); in++)
|
||||
{
|
||||
if (c == '.')
|
||||
@@ -142,17 +143,20 @@ static int check_name(char *in)
|
||||
int legal_hostname(char *name)
|
||||
{
|
||||
char c;
|
||||
int first;
|
||||
|
||||
if (!check_name(name))
|
||||
return 0;
|
||||
|
||||
for (; (c = *name); name++)
|
||||
for (first = 1; (c = *name); name++, first = 0)
|
||||
/* check for legal char a-z A-Z 0-9 - _ . */
|
||||
{
|
||||
if ((c >= 'A' && c <= 'Z') ||
|
||||
(c >= 'a' && c <= 'z') ||
|
||||
(c >= '0' && c <= '9') ||
|
||||
c == '-' || c == '_')
|
||||
(c >= '0' && c <= '9'))
|
||||
continue;
|
||||
|
||||
if (!first && (c == '-' || c == '_'))
|
||||
continue;
|
||||
|
||||
/* end of hostname part */
|
||||
@@ -454,7 +458,7 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
|
||||
int j, bytes = (1 + (r - in))/2;
|
||||
for (j = 0; j < bytes; j++)
|
||||
{
|
||||
char sav;
|
||||
char sav = sav;
|
||||
if (j < bytes - 1)
|
||||
{
|
||||
sav = in[(j+1)*2];
|
||||
@@ -581,3 +585,20 @@ int read_write(int fd, unsigned char *packet, int size, int rw)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Basically match a string value against a wildcard pattern. */
|
||||
int wildcard_match(const char* wildcard, const char* match)
|
||||
{
|
||||
while (*wildcard && *match)
|
||||
{
|
||||
if (*wildcard == '*')
|
||||
return 1;
|
||||
|
||||
if (*wildcard != *match)
|
||||
return 0;
|
||||
|
||||
++wildcard;
|
||||
++match;
|
||||
}
|
||||
|
||||
return *wildcard == *match;
|
||||
}
|
||||
|
||||
9
trust-anchors.conf
Normal file
9
trust-anchors.conf
Normal file
@@ -0,0 +1,9 @@
|
||||
# The root DNSSEC trust anchor, valid as at 30/01/2014
|
||||
|
||||
# Note that this is a DS record (ie a hash of the root Zone Signing Key)
|
||||
# If was downloaded from https://data.iana.org/root-anchors/root-anchors.xml
|
||||
|
||||
trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user