Compare commits
1010 Commits
v2.63test2
...
v2.77rc3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ab78b937f | ||
|
|
c7be0164ce | ||
|
|
d203af4a02 | ||
|
|
05f76dab89 | ||
|
|
bf05f8ff20 | ||
|
|
09f3b2cd9c | ||
|
|
22827870fa | ||
|
|
4583dd9e42 | ||
|
|
561441320f | ||
|
|
b2a9c571eb | ||
|
|
efff74c1ae | ||
|
|
a9df0e30b0 | ||
|
|
5ce3e76fbf | ||
|
|
6ec5f5c427 | ||
|
|
5a7212c70e | ||
|
|
3a8b0f6fcc | ||
|
|
a24c31e023 | ||
|
|
f5a3679f1d | ||
|
|
5ac813cb86 | ||
|
|
a93b02e321 | ||
|
|
c77fb9d8f0 | ||
|
|
facc18f2a8 | ||
|
|
bc515b71ec | ||
|
|
7bfa26399b | ||
|
|
461b7b43b4 | ||
|
|
b1cefa57f1 | ||
|
|
ce9a9704c6 | ||
|
|
93a9a55055 | ||
|
|
44eb875a5a | ||
|
|
bc87e609c2 | ||
|
|
005c46d6f5 | ||
|
|
503c609149 | ||
|
|
60704f5e2e | ||
|
|
4e7694d710 | ||
|
|
e33b48700e | ||
|
|
ad59f278c6 | ||
|
|
16f03e7139 | ||
|
|
dc99058d83 | ||
|
|
916959c188 | ||
|
|
864913c0f3 | ||
|
|
13dee6f49e | ||
|
|
62f9c0d470 | ||
|
|
54bb3639d4 | ||
|
|
fca008d8d4 | ||
|
|
43517fcaf5 | ||
|
|
88a77a78ad | ||
|
|
3e2496fb16 | ||
|
|
05da782f8f | ||
|
|
361dfe5158 | ||
|
|
68f6312d4b | ||
|
|
730c6745f0 | ||
|
|
d42d4706bb | ||
|
|
0740e43e20 | ||
|
|
903df07bcb | ||
|
|
0ef1334d78 | ||
|
|
5eb9dde09c | ||
|
|
ae3154aca9 | ||
|
|
3ebe62d1b7 | ||
|
|
f89cae3ecf | ||
|
|
09b768efa4 | ||
|
|
a1d973f987 | ||
|
|
0682b7795c | ||
|
|
b637d7815d | ||
|
|
7ac9ae1125 | ||
|
|
c6af3a32f2 | ||
|
|
16800ea072 | ||
|
|
b5e33ae53a | ||
|
|
3c0c1111fe | ||
|
|
2675f20615 | ||
|
|
e94ad0fa01 | ||
|
|
396750cef5 | ||
|
|
6c45519e18 | ||
|
|
6d95099c56 | ||
|
|
c8328ecde8 | ||
|
|
094bfaeb4f | ||
|
|
bf4e62c19e | ||
|
|
6b1c464d6d | ||
|
|
fa78573778 | ||
|
|
cd2ddb9904 | ||
|
|
9bb3998da4 | ||
|
|
d6dce53e08 | ||
|
|
06093a9a84 | ||
|
|
1d07667ac7 | ||
|
|
591ed1e905 | ||
|
|
907efeb2dc | ||
|
|
beea62cb66 | ||
|
|
5874f3e922 | ||
|
|
04cb536f16 | ||
|
|
8ee8524016 | ||
|
|
ce7845bf54 | ||
|
|
d55f81f5fd | ||
|
|
294d36df47 | ||
|
|
f186bdcbc7 | ||
|
|
ed1bd54b5c | ||
|
|
da2cad4b14 | ||
|
|
0a4a04969d | ||
|
|
45cb8dd9be | ||
|
|
88b09aaddc | ||
|
|
fe71bba356 | ||
|
|
cbc100fc81 | ||
|
|
68bea10bbf | ||
|
|
8628cd603f | ||
|
|
ff325644c7 | ||
|
|
b97026035e | ||
|
|
69cbf78bb6 | ||
|
|
c6cdf6bbee | ||
|
|
09217a1a87 | ||
|
|
332c41e2ff | ||
|
|
2c0c36f54b | ||
|
|
d6b749af91 | ||
|
|
14ffa0770b | ||
|
|
87985855ad | ||
|
|
a2bc254bed | ||
|
|
a7b27e84fa | ||
|
|
529b030228 | ||
|
|
4caa86dd7d | ||
|
|
e1abeeeec2 | ||
|
|
40205a053e | ||
|
|
b8ac466209 | ||
|
|
d1377fa3c4 | ||
|
|
fa79466c2a | ||
|
|
a93bd4b016 | ||
|
|
407a1f3e95 | ||
|
|
4b6af5d53f | ||
|
|
7aa3f9af66 | ||
|
|
f7cf749943 | ||
|
|
aa300f7167 | ||
|
|
c7f3bd2ac8 | ||
|
|
22fe2fd038 | ||
|
|
7480aeffc8 | ||
|
|
bec366b404 | ||
|
|
e06e6e34bf | ||
|
|
832e47beab | ||
|
|
df3d54f776 | ||
|
|
22c0f4fe87 | ||
|
|
9e4cf47ee8 | ||
|
|
fdc97e1383 | ||
|
|
a18bf3149a | ||
|
|
1566bacb2c | ||
|
|
e6e751b066 | ||
|
|
8de875f0fb | ||
|
|
4ace25c5d6 | ||
|
|
1e5051228d | ||
|
|
926332a764 | ||
|
|
d05dd58de1 | ||
|
|
f7443d76f7 | ||
|
|
f344dbc622 | ||
|
|
f4d0c660ca | ||
|
|
1801a29226 | ||
|
|
92be34a407 | ||
|
|
bb58f63ce5 | ||
|
|
367341f745 | ||
|
|
eddf365284 | ||
|
|
a63b8b89e6 | ||
|
|
5757371d43 | ||
|
|
b633de9413 | ||
|
|
c49778df4a | ||
|
|
53a9173fc0 | ||
|
|
d917275e48 | ||
|
|
cc7cb0b893 | ||
|
|
ec0628c4b2 | ||
|
|
97b1d25764 | ||
|
|
33702ab1f8 | ||
|
|
11867dc28c | ||
|
|
d3a8b39c7d | ||
|
|
15379ea1f2 | ||
|
|
efef497b89 | ||
|
|
5aa5f0ff2f | ||
|
|
5bb88f0963 | ||
|
|
1d03016bbc | ||
|
|
ce5732e84f | ||
|
|
a86fdf437e | ||
|
|
3e86d316c4 | ||
|
|
d67ecac59d | ||
|
|
fa14bec83b | ||
|
|
14a4ae883d | ||
|
|
3b799c826d | ||
|
|
b40f26c019 | ||
|
|
dd4ad9ac7e | ||
|
|
2dbba34b2c | ||
|
|
c2bcd1e183 | ||
|
|
d64c81fff7 | ||
|
|
93be5b1e02 | ||
|
|
9a31b68b59 | ||
|
|
0007ee9064 | ||
|
|
67ab3285b5 | ||
|
|
41a8d9e99b | ||
|
|
90477fb794 | ||
|
|
98079ea898 | ||
|
|
4790115455 | ||
|
|
27b78d990b | ||
|
|
77607cbea0 | ||
|
|
102208df69 | ||
|
|
6de81f1250 | ||
|
|
20fd11e11a | ||
|
|
9cdcfe9f19 | ||
|
|
5e3e464ac4 | ||
|
|
3a3965ac21 | ||
|
|
a7369bef8a | ||
|
|
d2aa7dfbb6 | ||
|
|
63ec5d1264 | ||
|
|
f6381cf482 | ||
|
|
34b5d19488 | ||
|
|
d6cb7e4815 | ||
|
|
d389e0191b | ||
|
|
d3699bb6bc | ||
|
|
13480e8c2a | ||
|
|
5b3b93f80a | ||
|
|
b69e845b1c | ||
|
|
90c3822bfa | ||
|
|
c895a0626d | ||
|
|
b842bc97bb | ||
|
|
0f38fa05a6 | ||
|
|
45c5cb1f8f | ||
|
|
f6d6956261 | ||
|
|
60176c7bf4 | ||
|
|
362c9303da | ||
|
|
5e95a552ee | ||
|
|
90cb222551 | ||
|
|
850163288d | ||
|
|
e3ec6f0bd7 | ||
|
|
f7bfbdc872 | ||
|
|
4918bd5505 | ||
|
|
9bad339af8 | ||
|
|
ba4fc0f996 | ||
|
|
2fd5bc952d | ||
|
|
0ddb8769bb | ||
|
|
654f59e762 | ||
|
|
d91b1fd402 | ||
|
|
c6d82c9ba6 | ||
|
|
4d25cf89d5 | ||
|
|
24e9207e13 | ||
|
|
89130d91d6 | ||
|
|
d644b2a17d | ||
|
|
bd7bfa21c4 | ||
|
|
403de05925 | ||
|
|
46c89f2bd0 | ||
|
|
23facf0d77 | ||
|
|
549b1a478c | ||
|
|
7f8565b94c | ||
|
|
06568c6636 | ||
|
|
5d07d77e75 | ||
|
|
62018e1f72 | ||
|
|
7c0f2543a7 | ||
|
|
ca85a28241 | ||
|
|
585840b033 | ||
|
|
dec180ac00 | ||
|
|
86fa104692 | ||
|
|
b059c96dc6 | ||
|
|
a77cec8d58 | ||
|
|
64bcff1c7c | ||
|
|
2ed162ac20 | ||
|
|
e66b4dff3c | ||
|
|
8efd731cc4 | ||
|
|
a5ae1f8587 | ||
|
|
b8f16556d3 | ||
|
|
cbe379ad6b | ||
|
|
338b340be9 | ||
|
|
a006eb7e14 | ||
|
|
554b580e97 | ||
|
|
0df29f5e23 | ||
|
|
b4c0f092d8 | ||
|
|
78c6184752 | ||
|
|
38440b204d | ||
|
|
ad4a8ff7d9 | ||
|
|
04b0ac0537 | ||
|
|
982faf4024 | ||
|
|
fe3992f9fa | ||
|
|
7aa970e2c7 | ||
|
|
30d0879ed5 | ||
|
|
fd6ad9e481 | ||
|
|
794fccca7f | ||
|
|
394ff492da | ||
|
|
1e153945de | ||
|
|
0b8a5a30a7 | ||
|
|
150162bc37 | ||
|
|
8805283088 | ||
|
|
65c7212000 | ||
|
|
979fe86bc8 | ||
|
|
ff841ebf5a | ||
|
|
360f2513ab | ||
|
|
4c960fa90a | ||
|
|
9003b50b13 | ||
|
|
f6e62e2af9 | ||
|
|
47b9ac59c7 | ||
|
|
0705a7e2d5 | ||
|
|
28b879ac47 | ||
|
|
caeea190f1 | ||
|
|
8ff70de618 | ||
|
|
ee4d1cea92 | ||
|
|
f4f400776b | ||
|
|
b467a454b4 | ||
|
|
efb8b5566a | ||
|
|
f9c863708c | ||
|
|
2941d3ac89 | ||
|
|
d36b732c4c | ||
|
|
d2c5458e31 | ||
|
|
8d8a54ec79 | ||
|
|
1062667618 | ||
|
|
6ef15b34ca | ||
|
|
3d04f46334 | ||
|
|
aff3396280 | ||
|
|
70d1873dd9 | ||
|
|
0491805d2f | ||
|
|
61b838dd57 | ||
|
|
fbf01f7046 | ||
|
|
5f4dc5c6ca | ||
|
|
2ae195f5a7 | ||
|
|
393415597c | ||
|
|
ae4624bf46 | ||
|
|
5e321739db | ||
|
|
9f79ee4ae3 | ||
|
|
28de38768e | ||
|
|
25cf5e373e | ||
|
|
424c4a8a53 | ||
|
|
97e618a0e3 | ||
|
|
d8dbd903d0 | ||
|
|
81c538efce | ||
|
|
d310ab7ecb | ||
|
|
0b1008d367 | ||
|
|
32fc6dbe03 | ||
|
|
83d2ed09fc | ||
|
|
fbc5205702 | ||
|
|
cbc6524234 | ||
|
|
094b5c3d90 | ||
|
|
3267804598 | ||
|
|
476693678e | ||
|
|
bd9520b7ad | ||
|
|
3ad3f3bbd4 | ||
|
|
ad946d555d | ||
|
|
800c5cc1e7 | ||
|
|
857973e6f7 | ||
|
|
9c448c8018 | ||
|
|
193de4abf5 | ||
|
|
98906275a0 | ||
|
|
b9ff5c8f43 | ||
|
|
3d9d2dd001 | ||
|
|
17b475912f | ||
|
|
e9828b6f66 | ||
|
|
72eba2bffc | ||
|
|
6ac3bc0452 | ||
|
|
00cd9d5519 | ||
|
|
f2658275b2 | ||
|
|
25e27235dd | ||
|
|
bf2db4b084 | ||
|
|
5782649ad9 | ||
|
|
288df49c96 | ||
|
|
10cfc0ddb3 | ||
|
|
15b1b7e9c3 | ||
|
|
00c0f69aa5 | ||
|
|
51943369e3 | ||
|
|
2d75f2e4a5 | ||
|
|
976afc93e4 | ||
|
|
7f68f82146 | ||
|
|
85900a246c | ||
|
|
b4f971a081 | ||
|
|
3e1551a1de | ||
|
|
af292dae6d | ||
|
|
933878f2c8 | ||
|
|
d54409dcd3 | ||
|
|
5bf50af2d0 | ||
|
|
c43b8a6326 | ||
|
|
b06900d1a3 | ||
|
|
f2f02fc3fb | ||
|
|
aaeea9f6ed | ||
|
|
2bb6f7735f | ||
|
|
40766e55e8 | ||
|
|
b5ea1cc255 | ||
|
|
6d8e8ac0fa | ||
|
|
24b167ada8 | ||
|
|
993f8cbb1b | ||
|
|
47a9516980 | ||
|
|
dc8a1b1bcf | ||
|
|
cdb755c5f1 | ||
|
|
063efb330a | ||
|
|
70772c9091 | ||
|
|
10d8540f62 | ||
|
|
006c162382 | ||
|
|
6799a46605 | ||
|
|
c4638f9e66 | ||
|
|
4b34f5d22f | ||
|
|
a0358e5ddb | ||
|
|
a03f8d4c37 | ||
|
|
c4a0937683 | ||
|
|
2f4c4b6076 | ||
|
|
a008a843cf | ||
|
|
d92c53e700 | ||
|
|
a754e1d7b2 | ||
|
|
8e9ffba66e | ||
|
|
15a97ad6fb | ||
|
|
91f4a5e4b5 | ||
|
|
0fa7e62947 | ||
|
|
62f992f06c | ||
|
|
a23949d44d | ||
|
|
b692f23466 | ||
|
|
8aa999ef69 | ||
|
|
20b215f293 | ||
|
|
e6096e643a | ||
|
|
8938ae05ac | ||
|
|
9d1b22aac2 | ||
|
|
1fc02680af | ||
|
|
4872aa747b | ||
|
|
7ea3d3fdca | ||
|
|
50f86ce8e4 | ||
|
|
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 | ||
|
|
29d28dda95 | ||
|
|
421594f83d | ||
|
|
d89fb4ed4f | ||
|
|
295a54eed3 | ||
|
|
5c0bd5b112 | ||
|
|
86e3b9a026 | ||
|
|
2f38141f43 | ||
|
|
8273ea5a19 | ||
|
|
4f7b304f53 | ||
|
|
8e4b87918f | ||
|
|
83b2198e86 | ||
|
|
d1a5975f9b | ||
|
|
52002051ad | ||
|
|
b191a77901 | ||
|
|
23780dd577 | ||
|
|
d1e9a582ad | ||
|
|
819ff4dd0f | ||
|
|
de604c18a0 | ||
|
|
be6cfb42ab | ||
|
|
2022310f95 | ||
|
|
657ed09693 | ||
|
|
c99df938d7 | ||
|
|
cf568a3726 | ||
|
|
e4807d8bb2 | ||
|
|
35239a302a | ||
|
|
db3946c358 | ||
|
|
0d28af84d0 | ||
|
|
42698cb7ab | ||
|
|
1d860415f2 | ||
|
|
289a253569 | ||
|
|
faafb3f7b7 | ||
|
|
2b127a1eab | ||
|
|
dfb23b3f77 | ||
|
|
b269221c00 | ||
|
|
8b46061e73 | ||
|
|
4d0f5b4c44 | ||
|
|
1dedeb87cc | ||
|
|
79cfefd856 | ||
|
|
0c0d4793ac | ||
|
|
12d71ed28c | ||
|
|
9fed0f71c2 | ||
|
|
2e34ac1403 | ||
|
|
bc54ae392b | ||
|
|
00acd06340 | ||
|
|
476e4a03c1 | ||
|
|
5f11b3e5e0 | ||
|
|
3169daad46 | ||
|
|
fd05f12790 | ||
|
|
ad094275b0 | ||
|
|
c740e4f342 | ||
|
|
132255b5da | ||
|
|
c4c0488ac6 | ||
|
|
a2ce6fcc91 | ||
|
|
12090548d2 | ||
|
|
8223cb15e7 | ||
|
|
4ba9b38cc5 | ||
|
|
42243214b5 | ||
|
|
23245c0cb2 | ||
|
|
b271446f82 | ||
|
|
611ebc5f1e | ||
|
|
be0f45cdbc | ||
|
|
9b40cbf587 | ||
|
|
c4a7f90ebb | ||
|
|
9609baee41 | ||
|
|
395eb71931 | ||
|
|
8bc4cecee6 | ||
|
|
6b617c0d15 | ||
|
|
55d290a3bf | ||
|
|
e17b4b3871 | ||
|
|
236e072cab |
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
src/*.o
|
||||
src/*.mo
|
||||
src/dnsmasq.pot
|
||||
src/dnsmasq
|
||||
src/dnsmasq_baseline
|
||||
src/.copts_*
|
||||
contrib/lease-tools/dhcp_lease_time
|
||||
contrib/lease-tools/dhcp_release
|
||||
contrib/lease-tools/dhcp_release6
|
||||
debian/base/
|
||||
debian/daemon/
|
||||
debian/files
|
||||
debian/substvars
|
||||
debian/utils-substvars
|
||||
debian/utils/
|
||||
@@ -56,7 +56,7 @@ release 0.95 Major rewrite: remove calls to gethostbyname() and talk
|
||||
any more memory after start-up. The NAT-like forwarding was
|
||||
inspired by a suggestion from Eli Chen <eli@routefree.com>
|
||||
|
||||
release 0.96 Fixed embarrasing thinko in cache linked-list code.
|
||||
release 0.96 Fixed embarrassing thinko in cache linked-list code.
|
||||
|
||||
release 0.98 Some enhancements and bug-fixes.
|
||||
Thanks to "Denis Carre" <denis.carre@laposte.net> and Martin
|
||||
@@ -78,7 +78,7 @@ release 0.98 Some enhancements and bug-fixes.
|
||||
ids, to thwart DNS spoofers.
|
||||
(7) Dnsmasq no longer forwards queries when the
|
||||
"recursion desired" bit is not set in the header.
|
||||
(8) Fixed getopt code to work on compliers with unsigned char.
|
||||
(8) Fixed getopt code to work on compilers with unsigned char.
|
||||
|
||||
release 0.991 Added -b flag: when set causes dnsmasq to always answer
|
||||
reverse queries on the RFC 1918 private IP space itself and
|
||||
@@ -88,7 +88,7 @@ release 0.991 Added -b flag: when set causes dnsmasq to always answer
|
||||
Fixed a bug which stopped dnsmasq working on a box with
|
||||
two or more interfaces with the same IP address.
|
||||
|
||||
Fixed cacheing of CNAMEs. Previously, a CNAME which pointed
|
||||
Fixed caching of CNAMEs. Previously, a CNAME which pointed
|
||||
to a name with many A records would not have all the addresses
|
||||
returned when being answered from the cache.
|
||||
|
||||
@@ -191,7 +191,7 @@ release 1.1 Added --user argument to allow user to change to
|
||||
|
||||
release 1.2 Added IPv6 DNS record support. AAAA records are cached
|
||||
and read from /etc/hosts. Reverse-lookups in the
|
||||
ip6.int and ip6.arpa domains are suppored. Dnsmasq can
|
||||
ip6.int and ip6.arpa domains are supported. Dnsmasq can
|
||||
talk to upstream servers via IPv6 if it finds IP6 addresses
|
||||
in /etc/resolv.conf and it offers DNS service automatically
|
||||
if IPv6 support is present in the kernel.
|
||||
@@ -214,7 +214,7 @@ release 1.3 Some versions of the Linux kernel return EINVAL rather
|
||||
starting, rather than after the first query - principle
|
||||
of least surprise applies here.
|
||||
|
||||
release 1.4 Fix a bug with DHPC lease parsing which broke in
|
||||
release 1.4 Fix a bug with DHCP lease parsing which broke in
|
||||
non-UTC timezones. Thanks to Mark Wormgoor for
|
||||
spotting and diagnosing this. Fixed versions in
|
||||
the .spec files this time. Fixed bug in Suse startup
|
||||
@@ -258,7 +258,7 @@ release 1.7 Fix a problem with cache not clearing properly
|
||||
on receipt of SIGHUP. Bug spotted by Sat Deshpande.
|
||||
|
||||
In group-id changing code:
|
||||
1) Drop supplimentary groups.
|
||||
1) Drop supplementary groups.
|
||||
2) Change gid before dropping root (patch from Soewono Effendi.)
|
||||
3) Change group to "dip" if it exists, to allow access
|
||||
to /etc/ppp/resolv.conf (suggestion from Jorg Sommer.)
|
||||
@@ -297,7 +297,7 @@ release 1.9 Fixes to rpm .spec files.
|
||||
required. The difference is not really visible with
|
||||
bloated libcs like glibc, but should dramatically reduce
|
||||
memory requirements when linked against ulibc for use on
|
||||
embeded routers, and that's the point really. Thanks to
|
||||
embedded routers, and that's the point really. Thanks to
|
||||
Matthew Natalier for prompting this.
|
||||
|
||||
Changed debug mode (-d) so that all logging appears on
|
||||
@@ -319,12 +319,12 @@ release 1.9 Fixes to rpm .spec files.
|
||||
uClinux. Thanks to Matthew Natalier for uClinux stuff.
|
||||
|
||||
release 1.10 Log warnings if resolv.conf or dhcp.leases are not
|
||||
accessable for any reason, as suggested by Hinrich Eilts.
|
||||
accessible for any reason, as suggested by Hinrich Eilts.
|
||||
|
||||
Fixed wrong address printing in error message about
|
||||
no interface with address.
|
||||
|
||||
Updated docs and split installation instuctions into setup.html.
|
||||
Updated docs and split installation instructions into setup.html.
|
||||
|
||||
Fix bug in CNAME chasing code: One CNAME pointing
|
||||
to many A records would lose A records after the
|
||||
@@ -346,7 +346,7 @@ release 1.10 Log warnings if resolv.conf or dhcp.leases are not
|
||||
|
||||
Added -S option to directly specify upstream servers and
|
||||
added ability to direct queries for specific domains to
|
||||
specfic servers. Suggested by Jens Vonderheide.
|
||||
specific servers. Suggested by Jens Vonderheide.
|
||||
|
||||
Upgraded random ID generation - patch from Rob Funk.
|
||||
|
||||
@@ -386,13 +386,13 @@ release 1.11 Actually implement the -R flag promised in the 1.10 man page.
|
||||
names in /etc/hosts -suggestion from Phil Harman.
|
||||
|
||||
Always return a zero time-to-live for names derived from
|
||||
DHCP which stops anthing else caching these
|
||||
DHCP which stops anything else caching these
|
||||
names. Previously the TTL was derived from the lease
|
||||
time but that is incorrect since a lease can be given
|
||||
up early: dnsmasq would know this but anything with the
|
||||
name cached with long TTL would not be updated.
|
||||
|
||||
Extended HAVE_IPV6 config flag to allow compliation on
|
||||
Extended HAVE_IPV6 config flag to allow compilation on
|
||||
old systems which don't have modern library routines
|
||||
like inet_ntop(). Thanks to Phil Harman for the patch.
|
||||
|
||||
@@ -471,7 +471,7 @@ release 1.14 Fixed man page description of -b option which confused
|
||||
/etc/resolv.conf.
|
||||
(Thanks to Klaas Teschauer)
|
||||
|
||||
Check that recieved queries have only rfc1035-legal characters
|
||||
Check that received queries have only rfc1035-legal characters
|
||||
in them. This check is mainly to avoid bad strings being
|
||||
sent to syslog.
|
||||
|
||||
@@ -549,7 +549,7 @@ release 1.16 Allow "/" characters in domain names - this fixes
|
||||
|
||||
release 1.17 Fixed crash with DHCP hostnames > 40 characters.
|
||||
|
||||
Fixed name-comparision routines to not depend on Locale,
|
||||
Fixed name-comparison routines to not depend on Locale,
|
||||
in theory this versions since 1.15 could lock up or give
|
||||
wrong results when run with locale != 'C'.
|
||||
|
||||
@@ -574,7 +574,7 @@ release 1.18 Added round-robin DNS for names which have more than one
|
||||
forwarded because -D is in effect, return NXDOMAIN not
|
||||
an empty reply.
|
||||
|
||||
Add code to return the software version in repsonse to the
|
||||
Add code to return the software version in response to the
|
||||
correct magic query in the same way as BIND. Use
|
||||
"dig version.bind chaos txt" to make the query.
|
||||
|
||||
@@ -635,7 +635,7 @@ release 2.0
|
||||
dynamic allocation.
|
||||
|
||||
Allow dhcp-host options for the same host with different
|
||||
IP adresses where the correct one will be selected for
|
||||
IP addresses where the correct one will be selected for
|
||||
the network the host appears on.
|
||||
|
||||
Fix parsing of --dhcp-option to allow more than one
|
||||
@@ -674,7 +674,7 @@ release 2.1
|
||||
|
||||
Fix unaligned access warnings on BSD/Alpha.
|
||||
|
||||
Allow empty DHCP options, like so: dhpc-option=44
|
||||
Allow empty DHCP options, like so: dhcp-option=44
|
||||
|
||||
Allow single-byte DHCP options like so: dhcp-option=20,1
|
||||
|
||||
@@ -745,7 +745,7 @@ release 2.3
|
||||
around a bug in the DHCP client in HP Jetdirect printers.
|
||||
Thanks to Marko Stolle for finding this problem.
|
||||
|
||||
Return DHCP T1 and T2 times, with "fuzz" to desychronise lease
|
||||
Return DHCP T1 and T2 times, with "fuzz" to desynchronise lease
|
||||
renewals, as specified in the RFC.
|
||||
|
||||
Ensure that the END option is always present in DHCP
|
||||
@@ -838,7 +838,7 @@ release 2.4
|
||||
by Chad Skeeters.
|
||||
|
||||
Fixed bug in /etc/ethers parsing code triggered by tab
|
||||
characters. Qudos to Dag Wieers for hepling to nail that
|
||||
characters. Kudos to Dag Wieers for helping to nail that
|
||||
one.
|
||||
|
||||
Added "bind-interfaces" option correctly.
|
||||
@@ -975,7 +975,7 @@ release 2.8
|
||||
configuration. Specifically: (1) options are matched on
|
||||
the netids from dhcp-range, dhcp-host, vendor class and
|
||||
user class(es). Multiple net-ids are allowed and options
|
||||
are searched on them all. (2) matches agains vendor class
|
||||
are searched on them all. (2) matches against vendor class
|
||||
and user class are now on a substring, if the given
|
||||
string is a substring of the vendor/user class, then a
|
||||
match occurs. Thanks again to Richard Musil for prompting
|
||||
@@ -997,7 +997,7 @@ release 2.8
|
||||
|
||||
Add checks against DHCP clients which return zero-length
|
||||
hostnames. This avoids the potential lease-loss problems
|
||||
reffered to above. Also, if a client sends a hostname when
|
||||
referred to above. Also, if a client sends a hostname when
|
||||
it creates a lease but subsequently sends no or a
|
||||
zero-length hostname whilst renewing, continue to use the
|
||||
existing hostname, don't wipe it out.
|
||||
@@ -1019,7 +1019,7 @@ release 2.9
|
||||
broken. The new algorithm is to pick as before for the
|
||||
first try, but if a query is retried, to send to all
|
||||
available servers in parallel. The first one to reply
|
||||
then becomes prefered for the next query. This should
|
||||
then becomes preferred for the next query. This should
|
||||
improve reliability without generating significant extra
|
||||
upstream load.
|
||||
|
||||
@@ -1027,7 +1027,7 @@ release 2.9
|
||||
unqualified domains introduced in version 2.8
|
||||
|
||||
Allow fallback to "bind-interfaces" at runtime: Some
|
||||
verions of *BSD seem to have enough stuff in the header
|
||||
versions of *BSD seem to have enough stuff in the header
|
||||
files to build but no kernel support. Also now log if
|
||||
"bind-interfaces" is forced on.
|
||||
|
||||
@@ -1049,7 +1049,7 @@ release 2.9
|
||||
first name found is now returned for reverse lookups,
|
||||
rather than all of them.
|
||||
|
||||
Add back fatal errors when nonexistant
|
||||
Add back fatal errors when nonexistent
|
||||
interfaces or interface addresses are given but only in
|
||||
"bind-interfaces" mode. Principle of least surprise applies.
|
||||
|
||||
@@ -1193,7 +1193,7 @@ version 2.14
|
||||
|
||||
version 2.15
|
||||
Fixed NXDOMAIN/NODATA confusion for locally known
|
||||
names. We now return a NODATA reponse for names which are
|
||||
names. We now return a NODATA response for names which are
|
||||
locally known. Now a query for (eg AAAA or MX) for a name
|
||||
with an IPv4 address in /etc/hosts which fails upstream
|
||||
will generate a NODATA response. Note that the query
|
||||
@@ -1229,7 +1229,7 @@ version 2.16
|
||||
|
||||
Set NONBLOCK on all listening sockets to workaround non-POSIX
|
||||
compliance in Linux 2.4 and 2.6. This fixes rare hangs which
|
||||
occured when corrupted packets were received. Thanks to
|
||||
occurred when corrupted packets were received. Thanks to
|
||||
Joris van Rantwijk for chasing that down.
|
||||
|
||||
Updated config.h for NetBSD. Thanks to Martin Lambers.
|
||||
@@ -1297,7 +1297,7 @@ version 2.18
|
||||
interfaces with more than one IPv6 address. Thanks to
|
||||
Martin Pels for help with that.
|
||||
|
||||
Fix problems which occured when more than one dhcp-range
|
||||
Fix problems which occurred when more than one dhcp-range
|
||||
was specified in the same subnet: sometimes parameters
|
||||
(lease time, network-id tag) from the wrong one would be
|
||||
used. Thanks to Rory Campbell-Lange for the bug report.
|
||||
@@ -1314,7 +1314,7 @@ version 2.19
|
||||
Thanks to Richard Atterer for the bug report.
|
||||
|
||||
Check for under-length option fields in DHCP packets, a
|
||||
zero length client-id, in particluar, could seriously
|
||||
zero length client-id, in particular, could seriously
|
||||
confuse dnsmasq 'till now. Thanks to Will Murname for help
|
||||
with that.
|
||||
|
||||
@@ -1389,7 +1389,7 @@ version 2.21
|
||||
recursive queries.
|
||||
|
||||
Fix DHCP address allocation problem when netid tags are in
|
||||
use. Thanks to Will Murnane for the bug report and
|
||||
use. Thanks to Will Murname for the bug report and
|
||||
subsequent testing.
|
||||
|
||||
Add an additional data section to the reply for MX and SRV
|
||||
@@ -1505,7 +1505,7 @@ version 2.23
|
||||
from dnsmasq --version. Thanks to Dirk Schenkewitz for
|
||||
the suggestion.
|
||||
|
||||
Fix pathalogical behaviour when a broken client keeps sending
|
||||
Fix pathological behaviour when a broken client keeps sending
|
||||
DHCPDISCOVER messages repeatedly and fast. Because dealing with
|
||||
each of these takes a few seconds, (because of the ping) then a
|
||||
queue of DHCP packets could build up. Now, the results of a ping
|
||||
@@ -1593,7 +1593,7 @@ version 2.24
|
||||
than one dhcp-range is available. Thanks to Sorin Panca
|
||||
for help chasing this down.
|
||||
|
||||
Added more explict error mesages to the hosts file and
|
||||
Added more explicit error messages to the hosts file and
|
||||
ethers file reading code. Markus Kaiserswerth suffered to
|
||||
make this happen.
|
||||
|
||||
@@ -1617,7 +1617,7 @@ version 2.25
|
||||
|
||||
Fixed Suse spec file - thanks to Steven Springl.
|
||||
|
||||
Fixed DHCP bug when two distict subnets are on the same
|
||||
Fixed DHCP bug when two distinct subnets are on the same
|
||||
physical interface. Thanks to Pawel Zawora for finding
|
||||
this and suggesting the fix.
|
||||
|
||||
@@ -1740,7 +1740,7 @@ version 2.28
|
||||
Fixed regression in netlink code under 2.2.x kernels which
|
||||
occurred in 2.27. Erik Jan Tromp is the vintage kernel fan
|
||||
who found this. P.S. It looks like this "netlink bind:
|
||||
permission denied" problem occured in kernels at least as
|
||||
permission denied" problem occurred in kernels at least as
|
||||
late a 2.4.18. Good information from Alain Richoux.
|
||||
|
||||
Added a warning when it's impossible to give a host its
|
||||
@@ -1761,7 +1761,7 @@ version 2.28
|
||||
Eric House and Eric Spakman for help in chasing this down.
|
||||
|
||||
Tolerate configuration screwups which lead to the DHCP
|
||||
server attemping to allocate its own address to a
|
||||
server attempting to allocate its own address to a
|
||||
client; eg setting the whole subnet range as a DHCP
|
||||
range. Addresses in use by the server are now excluded
|
||||
from use by clients.
|
||||
@@ -2273,7 +2273,7 @@ version 2.40
|
||||
this.
|
||||
|
||||
Use client-id as hash-seed for DHCP address allocation
|
||||
with Firewire and Infiniband, as these don't supply an MAC
|
||||
with Firewire and InfiniBand, as these don't supply an MAC
|
||||
address.
|
||||
|
||||
Tweaked TFTP file-open code to make it behave sensibly
|
||||
@@ -2307,7 +2307,7 @@ version 2.40
|
||||
Continue to use unqualified hostnames provided by DHCP
|
||||
clients, even if the domain part is illegal. (The domain
|
||||
is ignored, and an error logged.) Previously in this
|
||||
situation, the whole name whould have been
|
||||
situation, the whole name would have been
|
||||
rejected. Thanks to Jima for the patch.
|
||||
|
||||
Handle EINTR returns from wait() correctly and reap
|
||||
@@ -2319,7 +2319,7 @@ version 2.40
|
||||
leases file and passed to the lease-change
|
||||
script. Suggestion from Ben Voigt.
|
||||
|
||||
Re-run the lease chamge script with an "old" event for
|
||||
Re-run the lease change script with an "old" event for
|
||||
each lease when dnsmasq receives a SIGHUP.
|
||||
|
||||
Added more useful exit codes, including passing on a
|
||||
@@ -2417,7 +2417,7 @@ version 2.41
|
||||
Changed behavior of DHCP server to always return total length of
|
||||
a new lease in DHCPOFFER, even if an existing lease
|
||||
exists. (It used to return the time remaining on the lease
|
||||
whne one existed.) This fixes problems with the Sony Ericsson
|
||||
when one existed.) This fixes problems with the Sony Ericsson
|
||||
K610i phone. Thanks to Hakon Stordahl for finding and
|
||||
fixing this.
|
||||
|
||||
@@ -2476,7 +2476,7 @@ version 2.42
|
||||
|
||||
Fix OS detection logic to cope with GNU/FreeBSD.
|
||||
|
||||
Fix unitialised variable in DBus code - thanks to Roy
|
||||
Fix uninitialised variable in DBus code - thanks to Roy
|
||||
Marples.
|
||||
|
||||
Fix network enumeration code to work on later NetBSD -
|
||||
|
||||
189
FAQ
189
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
|
||||
@@ -59,7 +59,7 @@ A: Yes, there is explicit support for *BSD and MacOS X and Solaris.
|
||||
|
||||
Q: My company's nameserver knows about some names which aren't in the
|
||||
public DNS. Even though I put it first in /etc/resolv.conf, it
|
||||
dosen't work: dnsmasq seems not to use the nameservers in the order
|
||||
doesn't work: dnsmasq seems not to use the nameservers in the order
|
||||
given. What am I doing wrong?
|
||||
|
||||
A: By default, dnsmasq treats all the nameservers it knows about as
|
||||
@@ -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.
|
||||
@@ -144,19 +144,19 @@ Q: Who are Verisign, what do they have to do with the bogus-nxdomain
|
||||
option in dnsmasq and why should I wory about it?
|
||||
|
||||
A: [note: this was written in September 2003, things may well change.]
|
||||
Versign run the .com and .net top-level-domains. They have just
|
||||
Verisign run the .com and .net top-level-domains. They have just
|
||||
changed the configuration of their servers so that unknown .com and
|
||||
.net domains, instead of returning an error code NXDOMAIN, (no such
|
||||
domain) return the address of a host at Versign which runs a web
|
||||
domain) return the address of a host at Verisign which runs a web
|
||||
server showing a search page. Most right-thinking people regard
|
||||
this new behaviour as broken :-). You can test to see if you are
|
||||
suffering Versign brokeness by run a command like
|
||||
suffering Verisign brokenness by run a command like
|
||||
|
||||
host jlsdajkdalld.com
|
||||
|
||||
If you get "jlsdajkdalld.com" does not exist, then all is fine, if
|
||||
host returns an IP address, then the DNS is broken. (Try a few
|
||||
different unlikely domains, just in case you picked a wierd one
|
||||
different unlikely domains, just in case you picked a weird one
|
||||
which really _is_ registered.)
|
||||
|
||||
Assuming that your DNS is broken, and you want to fix it, simply
|
||||
@@ -180,7 +180,7 @@ A: There are a couple of configuration gotchas which have been
|
||||
whilst the ISC one works.
|
||||
|
||||
The first thing to check is the broadcast address set for the
|
||||
ethernet interface. This is normally the adddress on the connected
|
||||
ethernet interface. This is normally the address on the connected
|
||||
network with all ones in the host part. For instance if the
|
||||
address of the ethernet interface is 192.168.55.7 and the netmask
|
||||
is 255.255.255.0 then the broadcast address should be
|
||||
@@ -205,7 +205,7 @@ A: By default, none of the DHCP clients send the host-name when asking
|
||||
send with the "hostname" keyword in /etc/network/interfaces. (See
|
||||
"man interfaces" for details.) That doesn't work for dhclient, were
|
||||
you have to add something like "send host-name daisy" to
|
||||
/etc/dhclient.conf [Update: the lastest dhcpcd packages _do_ send
|
||||
/etc/dhclient.conf [Update: the latest dhcpcd packages _do_ send
|
||||
the hostname by default.
|
||||
|
||||
Q: I'm network booting my machines, and trying to give them static
|
||||
@@ -236,53 +236,70 @@ Q: What network types are supported by the DHCP server?
|
||||
A: Ethernet (and 802.11 wireless) are supported on all platforms. On
|
||||
Linux all network types (including FireWire) are supported.
|
||||
|
||||
Q: What is this strange "bind-interface" option?
|
||||
Q: What are these strange "bind-interface" and "bind-dynamic" options?
|
||||
|
||||
A: The DNS spec says that the reply to a DNS query must come from the
|
||||
same address it was sent to. The traditional way to write an UDP
|
||||
server to do this is to find all of the addresses belonging to the
|
||||
machine (ie all the interfaces on the machine) and then create a
|
||||
socket for each interface which is bound to the address of the
|
||||
interface. Then when a packet is sent to address A, it is received
|
||||
on the socket bound to address A and when the reply is also sent
|
||||
via that socket, the source address is set to A by the kernel and
|
||||
everything works. This is the how dnsmasq works when
|
||||
"bind-interfaces" is set, with the obvious extension that is misses
|
||||
out creating sockets for some interfaces depending on the
|
||||
--interface, --address and --except-interface flags. The
|
||||
disadvantage of this approach is that it breaks if interfaces don't
|
||||
exist or are not configured when the daemon starts and does the
|
||||
socket creation step. In a hotplug-aware world this is a real
|
||||
problem.
|
||||
A: Dnsmasq from v2.63 can operate in one of three different "networking
|
||||
modes". This is unfortunate as it requires users configuring dnsmasq
|
||||
to take into account some rather bizarre constraints and select the
|
||||
mode which best fits the requirements of a particular installation.
|
||||
The origin of these are deficiencies in the Unix networking
|
||||
model and APIs and each mode has different advantages and
|
||||
problems. Just to add to the confusion, not all modes are available on
|
||||
all platforms (due the to lack of supporting network APIs).To further
|
||||
add to the confusion, the rules for the DHCP subsystem on dnsmasq are
|
||||
different to the rules for the DNS and TFTP subsystems.
|
||||
|
||||
The alternative approach is to have only one socket, which is bound
|
||||
to the correct port and the wildcard IP address (0.0.0.0). That
|
||||
socket will receive _all_ packets sent to port 53, no matter what
|
||||
destination address they have. This solves the problem of
|
||||
interfaces which are created or reconfigured after daemon
|
||||
start-up. To make this work is more complicated because of the
|
||||
"reply source address" problem. When a UDP packet is sent by a
|
||||
socket bound to 0.0.0.0 its source address will be set to the
|
||||
address of one of the machine's interfaces, but which one is not
|
||||
determined and can vary depending on the OS being run. To get round
|
||||
this it is neccessary to use a scary advanced API to determine the
|
||||
address to which a query was sent, and force that to be the source
|
||||
address in the reply. For IPv4 this stuff in non-portable and quite
|
||||
often not even available (It's different between FreeBSD 5.x and
|
||||
Linux, for instance, and FreeBSD 4.x, Linux 2.0.x and OpenBSD don't
|
||||
have it at all.) Hence "bind-interfaces" has to always be available
|
||||
as a fall back. For IPv6 the API is standard and universally
|
||||
available.
|
||||
The three modes are "wildcard", "bind-interfaces" and "bind-dynamic".
|
||||
|
||||
It could be argued that if the --interface or --address flags are
|
||||
used then binding interfaces is more appropriate, but using
|
||||
wildcard binding means that dnsmasq will quite happily start up
|
||||
after being told to use interfaces which don't exist, but which are
|
||||
created later. Wildcard binding breaks the scenario when dnsmasq is
|
||||
listening on one interface and another server (most probably BIND)
|
||||
is listening on another. It's not possible for BIND to bind to an
|
||||
(address,port) pair when dnsmasq has bound (wildcard,port), hence
|
||||
the ability to explicitly turn off wildcard binding.
|
||||
In "wildcard" mode, dnsmasq binds the wildcard IP address (0.0.0.0 or
|
||||
::). This allows it to receive all the packets sent to the server on
|
||||
the relevant port. Access control (--interface, --except-interface,
|
||||
--listen-address, etc) is implemented by dnsmasq: it queries the
|
||||
kernel to determine the interface on which a packet was received and
|
||||
the address to which it was sent, and applies the configured
|
||||
rules. Wildcard mode is the default if neither of the other modes are
|
||||
specified.
|
||||
|
||||
In "bind-interfaces" mode, dnsmasq runs through all the network
|
||||
interfaces available when it starts, finds the set of IP addresses on
|
||||
those interfaces, filters that set using the access control
|
||||
configuration, and then binds the set of IP addresses. Only packets
|
||||
sent to the allowed addresses are delivered by the kernel to dnsmasq.
|
||||
|
||||
In "bind-dynamic" mode, access control filtering is done both by
|
||||
binding individual IP addresses, as for bind-interfaces, and by
|
||||
inspecting individual packets on arrival as for wildcard mode. In
|
||||
addition, dnsmasq notices when new interfaces appear or new addresses
|
||||
appear on existing interfaces, and the resulting IP addresses are
|
||||
bound automatically without having to restart dnsmasq.
|
||||
|
||||
The mode chosen has four different effects: co-existence with other
|
||||
servers, semantics of --interface access control, effect of new
|
||||
interfaces, and legality of --interface specifications for
|
||||
non-existent interfaces. We will deal with these in order.
|
||||
|
||||
A dnsmasq instance running in wildcard mode precludes a machine from
|
||||
running a second instance of dnsmasq or any other DNS, TFTP or DHCP
|
||||
server. Attempts to do so will fail with an "address in use" error.
|
||||
Dnsmasq running in --bind-interfaces or bind-dynamic mode allow other
|
||||
instances of dnsmasq or other servers, as long as no two servers are
|
||||
configured to listen on the same interface address.
|
||||
|
||||
The semantics of --interface varies subtly between wildcard or
|
||||
bind-dynamic mode and bind-interfaces mode. The situation where this
|
||||
matters is a request which arrives via one interface (A), but with a
|
||||
destination address of a second interface (B) and when dnsmasq is
|
||||
configured to listen only on B. In wildcard or bind-dynamic mode, such
|
||||
a request will be ignored, in bind-interfaces mode, it will be
|
||||
accepted.
|
||||
|
||||
The creation of new network interfaces after dnsmasq starts is ignored
|
||||
by dnsmasq when in --bind-interfaces mode. In wildcard or bind-dynamic
|
||||
mode, such interfaces are handled normally.
|
||||
|
||||
A --interface specification for a non-existent interface is a fatal
|
||||
error at start-up when in --bind-interfaces mode, by just generates a
|
||||
warning in wildcard or bind-dynamic mode.
|
||||
|
||||
Q: Why doesn't Kerberos work/why can't I get sensible answers to
|
||||
queries for SRV records.
|
||||
@@ -296,15 +313,25 @@ Q: Can I get email notification when a new version of dnsmasq is
|
||||
released?
|
||||
|
||||
A: Yes, new releases of dnsmasq are always announced through
|
||||
freshmeat.net, and they allow you to subcribe to email alerts when
|
||||
freshmeat.net, and they allow you to subscribe to email alerts when
|
||||
new versions of particular projects are released. New releases are
|
||||
also announced in the dnsmasq-discuss mailing list, subscribe at
|
||||
http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss
|
||||
|
||||
Q: What does the dhcp-authoritative option do?
|
||||
|
||||
A: See http://www.isc.org/files/auth.html - that's
|
||||
for the ISC daemon, but the same applies to dnsmasq.
|
||||
A: The DHCP spec says that when a DHCP server recieves a renewal request
|
||||
from a client it has no knowledge of, it should just ignore it.
|
||||
This is because it's supported to have more than one DHCP server
|
||||
on a network, and another DHCP server may be dealing with the client.
|
||||
This has the unfortunate effect that when _no_ DHCP replies to
|
||||
the client, it takes some time for the client to time-out and start
|
||||
to get a new lease. Setting this option makes dnsmasq violate the
|
||||
standard to the extent that it will send a NAK reply to the client,
|
||||
causing it to immediately start to get a new lease. This improves
|
||||
behaviour when machines move networks, and in the case that the DHCP
|
||||
lease database is lost. As long as there are not more tha one DHCP
|
||||
server on the network, it's safe to enable the option.
|
||||
|
||||
Q: Why does my Gentoo box pause for a minute before getting a new
|
||||
lease?
|
||||
@@ -332,18 +359,64 @@ A: By default, the identity of a machine is determined by using the
|
||||
method for setting the client-id varies with DHCP client software,
|
||||
dhcpcd uses the "-I" flag. Windows uses a registry setting,
|
||||
see http://www.jsiinc.com/SUBF/TIP2800/rh2845.htm
|
||||
|
||||
Addendum:
|
||||
From version 2.46, dnsmasq has a solution to this which doesn't
|
||||
involve setting client-IDs. It's possible to put more than one MAC
|
||||
address in a --dhcp-host configuration. This tells dnsmasq that it
|
||||
should use the specified IP for any of the specified MAC addresses,
|
||||
and furthermore it gives dnsmasq permission to sumarily abandon a
|
||||
and furthermore it gives dnsmasq permission to summarily abandon a
|
||||
lease to one of the MAC addresses if another one comes along. Note
|
||||
that this will work fine only as longer as only one interface is
|
||||
up at any time. There is no way for dnsmasq to enforce this
|
||||
constraint: if you configure multiple MAC addresses and violate
|
||||
this rule, bad things will happen.
|
||||
|
||||
Addendum-II: The link above is dead, the former contents of the link are:
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
How can I keep the same DHCP client reservation, if the MAC address changes?
|
||||
|
||||
When you reserve an IP address for a DHCP client, you provide the
|
||||
MAC address of the client's NIC.
|
||||
|
||||
It is possible to use a custom identifier, which is sent as
|
||||
option 61 in the client's DHCP Discover and Request packet.
|
||||
|
||||
The DhcpClientIdentifier is a REG_DWORD value that is located at:
|
||||
|
||||
Windows NT 4.0 SP2+
|
||||
|
||||
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\<Adapter Name>'X'\Parameters\Tcpip
|
||||
|
||||
where <Adapter Name> is the NIC driver name and 'X' is the number of the NIC.
|
||||
|
||||
Windows 2000
|
||||
|
||||
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TcpIp\Parameters\Interfaces\<NIC GUID>
|
||||
|
||||
where <NIC GUID> is the GUID of the NIC.
|
||||
|
||||
The valid range of data is 0x0 - 0xFFFFFFFF. The custom identifier is send as 4 bytes,
|
||||
8 hexadecimal character, in groups of 2 hexadecimal characters, with the groups being
|
||||
sent in reverse order. If the custom identifier is less than 8 hexadeciaml characters,
|
||||
it is zero padded at the end. Examples:
|
||||
|
||||
Custom Client Client Reservation
|
||||
Identifier on DHCP Server
|
||||
12345678 78563412
|
||||
123456 56341200
|
||||
1234 34120000
|
||||
1234567 67452301
|
||||
12345 45230100
|
||||
123 23010000
|
||||
A18F42 428FA100
|
||||
CF432 32F40C00
|
||||
C32D1BE BED1320C
|
||||
|
||||
-------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
Q: Can dnsmasq do DHCP on IP-alias interfaces?
|
||||
|
||||
A: Yes, from version-2.21. The support is only available running under
|
||||
@@ -471,7 +544,7 @@ Q: DHCP doesn't work with windows 7 but everything else is fine.
|
||||
|
||||
A: There seems to be a problem if Windows 7 doesn't get a value for
|
||||
DHCP option 252 in DHCP packets it gets from the server. The
|
||||
symtoms have beeen variously reported as continual DHCPINFORM
|
||||
symptoms have been variously reported as continual DHCPINFORM
|
||||
requests in an attempt to get an option-252, or even ignoring DHCP
|
||||
offers completely (and failing to get an IP address) if there is no
|
||||
option-252 supplied. DHCP option 252 is for WPAD, WWW Proxy
|
||||
|
||||
84
Makefile
84
Makefile
@@ -1,4 +1,4 @@
|
||||
# dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
# dnsmasq is Copyright (c) 2000-2016 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,35 +51,51 @@ 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`
|
||||
idn2_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LIBIDN2 $(PKG_CONFIG) --cflags libidn2`
|
||||
idn2_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LIBIDN2 $(PKG_CONFIG) --libs libidn2`
|
||||
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.2`
|
||||
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.2`
|
||||
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 NO_GMP --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)`\"'
|
||||
|
||||
sum?=$(shell $(CC) -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' ')
|
||||
sum!=$(CC) -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' '
|
||||
copts_conf = .copts_$(sum)
|
||||
|
||||
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 tables.o loop.o inotify.o \
|
||||
poll.o rrfilter.o edns0.o arp.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) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
|
||||
build_libs="$(dbus_libs) $(idn2_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
|
||||
rm -f $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq core */core
|
||||
mostly_clean :
|
||||
rm -f $(BUILDDIR)/*.mo $(BUILDDIR)/*.pot
|
||||
rm -f $(BUILDDIR)/.copts_* $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq
|
||||
|
||||
clean : mostly_clean
|
||||
rm -f $(BUILDDIR)/dnsmasq_baseline
|
||||
rm -f core */core
|
||||
rm -f *~ contrib/*/*~ */*~
|
||||
|
||||
install : all install-common
|
||||
|
||||
@@ -92,8 +108,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; \
|
||||
@@ -104,24 +120,45 @@ install-i18n : all-i18n install-common
|
||||
cd $(MAN); ../bld/install-man $(DESTDIR)$(MANDIR) $(INSTALL)
|
||||
|
||||
merge :
|
||||
@cd $(BUILDDIR) && $(MAKE) -f $(top)/Makefile dnsmasq.pot
|
||||
@cd $(BUILDDIR) && $(MAKE) top="$(top)" -f $(top)/Makefile dnsmasq.pot
|
||||
for f in `cd $(PO); echo *.po`; do \
|
||||
echo -n msgmerge $(PO)/$$f && $(MSGMERGE) --no-wrap -U $(PO)/$$f $(BUILDDIR)/dnsmasq.pot; \
|
||||
done
|
||||
|
||||
# Canonicalise .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
|
||||
|
||||
# rules below are targets in recusive makes with cwd=$(SRC)
|
||||
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 recursive makes with cwd=$(BUILDDIR)
|
||||
|
||||
$(copts_conf): $(hdrs)
|
||||
@rm -f *.o .copts_*
|
||||
@touch $@
|
||||
|
||||
$(objs:.o=.c) $(hdrs):
|
||||
ln -s $(top)/$(SRC)/$@ .
|
||||
|
||||
$(objs): $(copts_conf) $(hdrs)
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $(COPTS) $(i18n) $(build_cflags) $(RPM_OPT_FLAGS) -c $<
|
||||
|
||||
dnsmasq : $(hdrs) $(objs)
|
||||
dnsmasq : $(objs)
|
||||
$(CC) $(LDFLAGS) -o $@ $(objs) $(build_libs) $(LIBS)
|
||||
|
||||
dnsmasq.pot : $(objs:.o=.c) $(hdrs)
|
||||
@@ -130,5 +167,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,9 @@ 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 tables.c \
|
||||
loop.c inotify.c poll.c rrfilter.c edns0.c arp.c
|
||||
|
||||
LOCAL_MODULE := dnsmasq
|
||||
|
||||
@@ -17,4 +19,6 @@ LOCAL_C_INCLUDES := external/dnsmasq/src
|
||||
LOCAL_CFLAGS := -O2 -g -W -Wall -D__ANDROID__ -DNO_IPV6 -DNO_TFTP -DNO_SCRIPT
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES := libc libcutils
|
||||
|
||||
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
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))
|
||||
@@ -8,17 +8,27 @@
|
||||
# which has a set of references substituted into it by git.
|
||||
# If we can find one which matches $v[0-9].* then we assume it's
|
||||
# a version-number tag, else we just use the whole string.
|
||||
# If there is more than one v[0-9].* tag, sort them and use the
|
||||
# first. This favours, eg v2.63 over 2.63rc6.
|
||||
|
||||
if which git >/dev/null 2>&1 && [ -d $1/.git ]; then
|
||||
cd $1; git describe
|
||||
# Change directory to the toplevel source directory.
|
||||
if test -z "$1" || ! test -d "$1" || ! cd "$1"; then
|
||||
echo "$0: First argument $1 must be toplevel dir." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if which git >/dev/null 2>&1 && \
|
||||
([ -d .git ] || grep '^gitdir:' .git >/dev/null 2>&1) && \
|
||||
git describe >/dev/null 2>&1; then
|
||||
git describe | sed 's/^v//'
|
||||
elif grep '\$Format:%d\$' $1/VERSION >/dev/null 2>&1; then
|
||||
# unsubstituted VERSION, but no git available.
|
||||
# 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}" | head -n 1 | sed 's/^v//'
|
||||
echo "${vers}" | sort -r | head -n 1 | sed 's/^v//'
|
||||
else
|
||||
cat $1/VERSION
|
||||
fi
|
||||
|
||||
@@ -2,10 +2,39 @@
|
||||
|
||||
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
|
||||
# Nasty, nasty, in --copy, arg 2 is another config to search for, use with NO_GMP
|
||||
if [ $op = "--copy" ]; then
|
||||
if grep "^\#[[:space:]]*define[[:space:]]*$pkg" config.h >/dev/null 2>&1 || \
|
||||
echo $in | grep $pkg >/dev/null 2>&1; then
|
||||
pkg=""
|
||||
else
|
||||
pkg="$*"
|
||||
fi
|
||||
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
|
||||
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ sudo chmod 644 /Library/LaunchDaemons/uk.org.thekelleys.dnsmasq.plist
|
||||
|
||||
Optionally, edit your dnsmasq configuration file to your liking.
|
||||
|
||||
To start the launchd job, which starts dnsmaq, reboot or use the command:
|
||||
To start the launchd job, which starts dnsmasq, reboot or use the command:
|
||||
sudo launchctl load /Library/LaunchDaemons/uk.org.thekelleys.dnsmasq.plist
|
||||
|
||||
To stop the launchd job, which stops dnsmasq, use the command:
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
This is a patch against SuSEfirewall2-3.1-206 (SuSE 9.x and older)
|
||||
It fixes the depancy from the dns daemon name 'named'
|
||||
It fixes the dependency from the dns daemon name 'named'
|
||||
After appending the patch, the SuSEfirewall is again able to autodetect
|
||||
the dnsmasq named service.
|
||||
This is a very old bug in the SuSEfirewall script.
|
||||
The SuSE people think the name of the dns server will allways 'named'
|
||||
The SuSE people think the name of the dns server will always 'named'
|
||||
|
||||
|
||||
--- /sbin/SuSEfirewall2.orig 2004-01-23 13:30:09.000000000 +0100
|
||||
|
||||
@@ -13,10 +13,10 @@ connection comes out of the other side. However, sometimes, we want to
|
||||
maintain that relationship through the proxy and continue the connection
|
||||
mark on packets upstream of our proxy
|
||||
|
||||
DNSMasq includes such a feature enabled by the --conntrack
|
||||
Dnsmasq includes such a feature enabled by the --conntrack
|
||||
option. This allows, for example, using iptables to mark traffic from
|
||||
a particular IP, and that mark to be persisted to requests made *by*
|
||||
DNSMasq. Such a feature could be useful for bandwidth accounting,
|
||||
Dnsmasq. Such a feature could be useful for bandwidth accounting,
|
||||
captive portals and the like. Note a similar feature has been
|
||||
implemented in Squid 2.2
|
||||
|
||||
@@ -40,7 +40,7 @@ on IP address. 3) Saves the firewall mark back to the connection mark
|
||||
(which will persist it across related packets)
|
||||
|
||||
4) is applied to the OUTPUT table, which is where we first see packets
|
||||
generated locally. DNSMasq will have already copied the firewall mark
|
||||
generated locally. Dnsmasq will have already copied the firewall mark
|
||||
from the request, across to the new packet, and so all that remains is
|
||||
for iptables to copy it to the connection mark so it's persisted across
|
||||
packets.
|
||||
|
||||
43
contrib/dbus-test/dbus-test.py
Executable file
43
contrib/dbus-test/dbus-test.py
Executable file
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/python
|
||||
import dbus
|
||||
|
||||
bus = dbus.SystemBus()
|
||||
p = bus.get_object("uk.org.thekelleys.dnsmasq", "/uk/org/thekelleys/dnsmasq")
|
||||
l = dbus.Interface(p, dbus_interface="uk.org.thekelleys.dnsmasq")
|
||||
|
||||
# The new more flexible SetServersEx method
|
||||
array = dbus.Array()
|
||||
array.append(["1.2.3.5"])
|
||||
array.append(["1.2.3.4#664", "foobar.com"])
|
||||
array.append(["1003:1234:abcd::1%eth0", "eng.mycorp.com", "lab.mycorp.com"])
|
||||
print l.SetServersEx(array)
|
||||
|
||||
# Must create a new object for dnsmasq as the introspection gives the wrong
|
||||
# signature for SetServers (av) while the code only expects a bunch of arguments
|
||||
# instead of an array of variants
|
||||
p = bus.get_object("uk.org.thekelleys.dnsmasq", "/uk/org/thekelleys/dnsmasq", introspect=False)
|
||||
l = dbus.Interface(p, dbus_interface="uk.org.thekelleys.dnsmasq")
|
||||
|
||||
# The previous method; all addresses in machine byte order
|
||||
print l.SetServers(dbus.UInt32(16909060), # 1.2.3.5
|
||||
dbus.UInt32(16909061), # 1.2.3.4
|
||||
"foobar.com",
|
||||
dbus.Byte(0x10), # 1003:1234:abcd::1
|
||||
dbus.Byte(0x03),
|
||||
dbus.Byte(0x12),
|
||||
dbus.Byte(0x34),
|
||||
dbus.Byte(0xab),
|
||||
dbus.Byte(0xcd),
|
||||
dbus.Byte(0x00),
|
||||
dbus.Byte(0x00),
|
||||
dbus.Byte(0x00),
|
||||
dbus.Byte(0x00),
|
||||
dbus.Byte(0x00),
|
||||
dbus.Byte(0x00),
|
||||
dbus.Byte(0x00),
|
||||
dbus.Byte(0x00),
|
||||
dbus.Byte(0x00),
|
||||
dbus.Byte(0x01),
|
||||
"eng.mycorp.com",
|
||||
"lab.mycorp.com")
|
||||
|
||||
@@ -55,7 +55,7 @@ Index: src/dnsmasq.c
|
||||
}
|
||||
|
||||
@@ -434,7 +433,7 @@
|
||||
/* lose the setuid and setgid capbilities */
|
||||
/* lose the setuid and setgid capabilities */
|
||||
if (capset(hdr, data) == -1)
|
||||
{
|
||||
- send_event(err_pipe[1], EVENT_CAP_ERR, errno);
|
||||
|
||||
6
contrib/lease-tools/Makefile
Normal file
6
contrib/lease-tools/Makefile
Normal file
@@ -0,0 +1,6 @@
|
||||
CFLAGS?= -O2 -Wall -W
|
||||
|
||||
all: dhcp_release dhcp_release6 dhcp_lease_time
|
||||
|
||||
clean:
|
||||
rm -f *~ *.o core dhcp_release dhcp_release6 dhcp_lease_time
|
||||
@@ -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;
|
||||
|
||||
/* Explicitly 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
|
||||
@@ -117,7 +117,7 @@ static ssize_t netlink_recv(int fd)
|
||||
msg.msg_flags = 0;
|
||||
while ((rc = recvmsg(fd, &msg, MSG_PEEK)) == -1 && errno == EINTR);
|
||||
|
||||
/* 2.2.x doesn't suport MSG_PEEK at all, returning EOPNOTSUPP, so we just grab a
|
||||
/* 2.2.x doesn't support MSG_PEEK at all, returning EOPNOTSUPP, so we just grab a
|
||||
big buffer and pray in that case. */
|
||||
if (rc == -1 && errno == EOPNOTSUPP)
|
||||
{
|
||||
@@ -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)
|
||||
{
|
||||
@@ -281,6 +277,11 @@ int main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (inet_addr(argv[2]) == INADDR_NONE)
|
||||
{
|
||||
perror("invalid ip address");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
lease.s_addr = inet_addr(argv[2]);
|
||||
server = find_interface(lease, nl, if_nametoindex(argv[1]));
|
||||
38
contrib/lease-tools/dhcp_release6.1
Normal file
38
contrib/lease-tools/dhcp_release6.1
Normal file
@@ -0,0 +1,38 @@
|
||||
.TH DHCP_RELEASE 1
|
||||
.SH NAME
|
||||
dhcp_release6 \- Release a DHCPv6 lease on a the local dnsmasq DHCP server.
|
||||
.SH SYNOPSIS
|
||||
.B dhcp_release6 --iface <interface> --client-id <client-id> --server-id
|
||||
server-id --iaid <iaid> --ip <IP> [--dry-run] [--help]
|
||||
.SH "DESCRIPTION"
|
||||
A utility which forces the DHCP server running on this machine to release a
|
||||
DHCPv6 lease.
|
||||
.SS OPTIONS
|
||||
.IP "-a, --ip"
|
||||
IPv6 address to release.
|
||||
.IP "-c, --client-id"
|
||||
Colon-separated hex string representing DHCPv6 client id. Normally
|
||||
it can be found in leases file both on client and server.
|
||||
.IP "-d, --dry-run"
|
||||
Print hexadecimal representation of generated DHCPv6 release packet to standard
|
||||
output and exit.
|
||||
.IP "-h, --help"
|
||||
print usage information to standard output and exit.
|
||||
.IP "-i, --iaid"
|
||||
Decimal representation of DHCPv6 IAID. Normally it can be found in leases file
|
||||
both on client and server.
|
||||
.IP "-n, --iface"
|
||||
Network interface to send a DHCPv6 release packet from.
|
||||
.IP "-s, --server-id"
|
||||
Colon-separated hex string representing DHCPv6 server id. Normally
|
||||
it can be found in leases file both on client and server.
|
||||
.SH NOTES
|
||||
MUST be run as root - will fail otherwise.
|
||||
.SH LIMITATIONS
|
||||
Only usable on IPv6 DHCP leases.
|
||||
.SH SEE ALSO
|
||||
.BR dnsmasq (8)
|
||||
.SH AUTHOR
|
||||
This manual page was written by Simon Kelley <simon@thekelleys.org.uk>.
|
||||
|
||||
|
||||
445
contrib/lease-tools/dhcp_release6.c
Normal file
445
contrib/lease-tools/dhcp_release6.c
Normal file
@@ -0,0 +1,445 @@
|
||||
/*
|
||||
dhcp_release6 --iface <interface> --client-id <client-id> --server-id
|
||||
server-id --iaid <iaid> --ip <IP> [--dry-run] [--help]
|
||||
MUST be run as root - will fail otherwise
|
||||
*/
|
||||
|
||||
/* Send a DHCPRELEASE message to IPv6 multicast address via the specified interface
|
||||
to tell the local DHCP server to delete a particular lease.
|
||||
|
||||
The interface argument is the interface in which a DHCP
|
||||
request _would_ be received if it was coming from the client,
|
||||
rather than being faked up here.
|
||||
|
||||
The client-id argument is colon-separated hex string and mandatory. Normally
|
||||
it can be found in leases file both on client and server
|
||||
|
||||
The server-id argument is colon-separated hex string and mandatory. Normally
|
||||
it can be found in leases file both on client and server.
|
||||
|
||||
The iaid argument is numeric string and mandatory. Normally
|
||||
it can be found in leases file both on client and server.
|
||||
|
||||
IP is an IPv6 address to release
|
||||
|
||||
If --dry-run is specified, dhcp_release6 just prints hexadecimal representation of
|
||||
packet to send to stdout and exits.
|
||||
|
||||
If --help is specified, dhcp_release6 print usage information to stdout and exits
|
||||
|
||||
|
||||
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define NOT_REPLY_CODE 115
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
enum DHCP6_TYPES{
|
||||
SOLICIT = 1,
|
||||
ADVERTISE = 2,
|
||||
REQUEST = 3,
|
||||
CONFIRM = 4,
|
||||
RENEW = 5,
|
||||
REBIND = 6,
|
||||
REPLY = 7,
|
||||
RELEASE = 8,
|
||||
DECLINE = 9,
|
||||
RECONFIGURE = 10,
|
||||
INFORMATION_REQUEST = 11,
|
||||
RELAY_FORW = 12,
|
||||
RELAY_REPL = 13
|
||||
|
||||
};
|
||||
enum DHCP6_OPTIONS{
|
||||
CLIENTID = 1,
|
||||
SERVERID = 2,
|
||||
IA_NA = 3,
|
||||
IA_TA = 4,
|
||||
IAADDR = 5,
|
||||
ORO = 6,
|
||||
PREFERENCE = 7,
|
||||
ELAPSED_TIME = 8,
|
||||
RELAY_MSG = 9,
|
||||
AUTH = 11,
|
||||
UNICAST = 12,
|
||||
STATUS_CODE = 13,
|
||||
RAPID_COMMIT = 14,
|
||||
USER_CLASS = 15,
|
||||
VENDOR_CLASS = 16,
|
||||
VENDOR_OPTS = 17,
|
||||
INTERFACE_ID = 18,
|
||||
RECONF_MSG = 19,
|
||||
RECONF_ACCEPT = 20,
|
||||
};
|
||||
|
||||
enum DHCP6_STATUSES{
|
||||
SUCCESS = 0,
|
||||
UNSPEC_FAIL = 1,
|
||||
NOADDR_AVAIL=2,
|
||||
NO_BINDING = 3,
|
||||
NOT_ON_LINK = 4,
|
||||
USE_MULTICAST =5
|
||||
};
|
||||
static struct option longopts[] = {
|
||||
{"ip", required_argument, 0, 'a'},
|
||||
{"server-id", required_argument, 0, 's'},
|
||||
{"client-id", required_argument, 0, 'c'},
|
||||
{"iface", required_argument, 0, 'n'},
|
||||
{"iaid", required_argument, 0, 'i'},
|
||||
{"dry-run", no_argument, 0, 'd'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
const short DHCP6_CLIENT_PORT = 546;
|
||||
const short DHCP6_SERVER_PORT = 547;
|
||||
|
||||
const char* DHCP6_MULTICAST_ADDRESS = "ff02::1:2";
|
||||
|
||||
struct dhcp6_option{
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
char value[1024];
|
||||
};
|
||||
|
||||
struct dhcp6_iaaddr_option{
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
struct in6_addr ip;
|
||||
uint32_t preferred_lifetime;
|
||||
uint32_t valid_lifetime;
|
||||
|
||||
|
||||
};
|
||||
|
||||
struct dhcp6_iana_option{
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
uint32_t iaid;
|
||||
uint32_t t1;
|
||||
uint32_t t2;
|
||||
char options[1024];
|
||||
};
|
||||
|
||||
|
||||
struct dhcp6_packet{
|
||||
size_t len;
|
||||
char buf[2048];
|
||||
|
||||
} ;
|
||||
|
||||
size_t pack_duid(const char* str, char* dst){
|
||||
|
||||
char* tmp = strdup(str);
|
||||
char* tmp_to_free = tmp;
|
||||
char *ptr;
|
||||
uint8_t write_pos = 0;
|
||||
while ((ptr = strtok (tmp, ":"))) {
|
||||
dst[write_pos] = (uint8_t) strtol(ptr, NULL, 16);
|
||||
write_pos += 1;
|
||||
tmp = NULL;
|
||||
|
||||
}
|
||||
free(tmp_to_free);
|
||||
return write_pos;
|
||||
}
|
||||
|
||||
struct dhcp6_option create_client_id_option(const char* duid){
|
||||
struct dhcp6_option option;
|
||||
option.type = htons(CLIENTID);
|
||||
bzero(option.value, sizeof(option.value));
|
||||
option.len = htons(pack_duid(duid, option.value));
|
||||
return option;
|
||||
}
|
||||
|
||||
struct dhcp6_option create_server_id_option(const char* duid){
|
||||
struct dhcp6_option option;
|
||||
option.type = htons(SERVERID);
|
||||
bzero(option.value, sizeof(option.value));
|
||||
option.len = htons(pack_duid(duid, option.value));
|
||||
return option;
|
||||
}
|
||||
|
||||
struct dhcp6_iaaddr_option create_iaadr_option(const char* ip){
|
||||
struct dhcp6_iaaddr_option result;
|
||||
result.type =htons(IAADDR);
|
||||
/* no suboptions needed here, so length is 24 */
|
||||
result.len = htons(24);
|
||||
result.preferred_lifetime = 0;
|
||||
result.valid_lifetime = 0;
|
||||
int s = inet_pton(AF_INET6, ip, &(result.ip));
|
||||
if (s <= 0) {
|
||||
if (s == 0)
|
||||
fprintf(stderr, "Not in presentation format");
|
||||
else
|
||||
perror("inet_pton");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
struct dhcp6_iana_option create_iana_option(const char * iaid, struct dhcp6_iaaddr_option ia_addr){
|
||||
struct dhcp6_iana_option result;
|
||||
result.type = htons(IA_NA);
|
||||
result.iaid = htonl(atoi(iaid));
|
||||
result.t1 = 0;
|
||||
result.t2 = 0;
|
||||
result.len = htons(12 + ntohs(ia_addr.len) + 2 * sizeof(uint16_t));
|
||||
memcpy(result.options, &ia_addr, ntohs(ia_addr.len) + 2 * sizeof(uint16_t));
|
||||
return result;
|
||||
}
|
||||
|
||||
struct dhcp6_packet create_release_packet(const char* iaid, const char* ip, const char* client_id, const char* server_id){
|
||||
struct dhcp6_packet result;
|
||||
bzero(result.buf, sizeof(result.buf));
|
||||
/* message_type */
|
||||
result.buf[0] = RELEASE;
|
||||
/* tx_id */
|
||||
bzero(result.buf+1, 3);
|
||||
|
||||
struct dhcp6_option client_option = create_client_id_option(client_id);
|
||||
struct dhcp6_option server_option = create_server_id_option(server_id);
|
||||
struct dhcp6_iaaddr_option iaaddr_option = create_iaadr_option(ip);
|
||||
struct dhcp6_iana_option iana_option = create_iana_option(iaid, iaaddr_option);
|
||||
int offset = 4;
|
||||
memcpy(result.buf + offset, &client_option, ntohs(client_option.len) + 2*sizeof(uint16_t));
|
||||
offset += (ntohs(client_option.len)+ 2 *sizeof(uint16_t) );
|
||||
memcpy(result.buf + offset, &server_option, ntohs(server_option.len) + 2*sizeof(uint16_t) );
|
||||
offset += (ntohs(server_option.len)+ 2* sizeof(uint16_t));
|
||||
memcpy(result.buf + offset, &iana_option, ntohs(iana_option.len) + 2*sizeof(uint16_t) );
|
||||
offset += (ntohs(iana_option.len)+ 2* sizeof(uint16_t));
|
||||
result.len = offset;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t parse_iana_suboption(char* buf, size_t len){
|
||||
size_t current_pos = 0;
|
||||
char option_value[1024];
|
||||
while (current_pos < len) {
|
||||
uint16_t option_type, option_len;
|
||||
memcpy(&option_type,buf + current_pos, sizeof(uint16_t));
|
||||
memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t));
|
||||
option_type = ntohs(option_type);
|
||||
option_len = ntohs(option_len);
|
||||
current_pos += 2 * sizeof(uint16_t);
|
||||
if (option_type == STATUS_CODE){
|
||||
uint16_t status;
|
||||
memcpy(&status, buf + current_pos, sizeof(uint16_t));
|
||||
status = ntohs(status);
|
||||
if (status != SUCCESS){
|
||||
memcpy(option_value, buf + current_pos + sizeof(uint16_t) , option_len - sizeof(uint16_t));
|
||||
option_value[option_len-sizeof(uint16_t)] ='\0';
|
||||
fprintf(stderr, "Error: %s\n", option_value);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
int16_t parse_packet(char* buf, size_t len){
|
||||
uint8_t type = buf[0];
|
||||
/*skipping tx id. you need it, uncomment following line
|
||||
uint16_t tx_id = ntohs((buf[1] <<16) + (buf[2] <<8) + buf[3]);
|
||||
*/
|
||||
size_t current_pos = 4;
|
||||
if (type != REPLY ){
|
||||
return NOT_REPLY_CODE;
|
||||
}
|
||||
char option_value[1024];
|
||||
while (current_pos < len) {
|
||||
uint16_t option_type, option_len;
|
||||
memcpy(&option_type,buf + current_pos, sizeof(uint16_t));
|
||||
memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t));
|
||||
option_type = ntohs(option_type);
|
||||
option_len = ntohs(option_len);
|
||||
current_pos += 2 * sizeof(uint16_t);
|
||||
if (option_type == STATUS_CODE){
|
||||
uint16_t status;
|
||||
memcpy(&status, buf + current_pos, sizeof(uint16_t));
|
||||
status = ntohs(status);
|
||||
if (status != SUCCESS){
|
||||
memcpy(option_value, buf + current_pos +sizeof(uint16_t) , option_len -sizeof(uint16_t));
|
||||
fprintf(stderr, "Error: %d %s\n", status, option_value);
|
||||
return status;
|
||||
}
|
||||
|
||||
}
|
||||
if (option_type == IA_NA ){
|
||||
uint16_t result = parse_iana_suboption(buf + current_pos +24, option_len -24);
|
||||
if (result){
|
||||
return result;
|
||||
}
|
||||
}
|
||||
current_pos += option_len;
|
||||
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void usage(const char* arg, FILE* stream){
|
||||
const char* usage_string ="--ip IPv6 --iface IFACE --server-id SERVER_ID --client-id CLIENT_ID --iaid IAID [--dry-run] | --help";
|
||||
fprintf (stream, "Usage: %s %s\n", arg, usage_string);
|
||||
|
||||
}
|
||||
|
||||
int send_release_packet(const char* iface, struct dhcp6_packet* packet){
|
||||
|
||||
struct sockaddr_in6 server_addr, client_addr;
|
||||
char response[1400];
|
||||
int sock = socket(PF_INET6, SOCK_DGRAM, 0);
|
||||
int i = 0;
|
||||
if (sock < 0) {
|
||||
perror("creating socket");
|
||||
return -1;
|
||||
}
|
||||
if (setsockopt(sock, SOL_SOCKET, 25, iface, strlen(iface)) == -1) {
|
||||
perror("SO_BINDTODEVICE");
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
memset(&server_addr, 0, sizeof(server_addr));
|
||||
server_addr.sin6_family = AF_INET6;
|
||||
client_addr.sin6_family = AF_INET6;
|
||||
client_addr.sin6_port = htons(DHCP6_CLIENT_PORT);
|
||||
client_addr.sin6_flowinfo = 0;
|
||||
client_addr.sin6_scope_id =0;
|
||||
inet_pton(AF_INET6, "::", &client_addr.sin6_addr);
|
||||
bind(sock, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in6));
|
||||
inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr);
|
||||
server_addr.sin6_port = htons(DHCP6_SERVER_PORT);
|
||||
int16_t recv_size = 0;
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (sendto(sock, packet->buf, packet->len, 0,
|
||||
(struct sockaddr *)&server_addr,
|
||||
sizeof(server_addr)) < 0) {
|
||||
perror("sendto failed");
|
||||
exit(4);
|
||||
}
|
||||
recv_size = recvfrom(sock, response, sizeof(response), MSG_DONTWAIT, NULL, 0);
|
||||
if (recv_size == -1){
|
||||
if (errno == EAGAIN){
|
||||
sleep(1);
|
||||
continue;
|
||||
}else {
|
||||
perror("recvfrom");
|
||||
}
|
||||
}
|
||||
int16_t result = parse_packet(response, recv_size);
|
||||
if (result == NOT_REPLY_CODE){
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
fprintf(stderr, "Response timed out\n");
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char * const argv[]) {
|
||||
const char* UNINITIALIZED = "";
|
||||
const char* iface = UNINITIALIZED;
|
||||
const char* ip = UNINITIALIZED;
|
||||
const char* client_id = UNINITIALIZED;
|
||||
const char* server_id = UNINITIALIZED;
|
||||
const char* iaid = UNINITIALIZED;
|
||||
int dry_run = 0;
|
||||
while (1) {
|
||||
int option_index = 0;
|
||||
int c = getopt_long(argc, argv, "a:s:c:n:i:hd", longopts, &option_index);
|
||||
if (c == -1){
|
||||
break;
|
||||
}
|
||||
switch(c){
|
||||
case 0:
|
||||
if (longopts[option_index].flag !=0){
|
||||
break;
|
||||
}
|
||||
printf ("option %s", longopts[option_index].name);
|
||||
if (optarg)
|
||||
printf (" with arg %s", optarg);
|
||||
printf ("\n");
|
||||
break;
|
||||
case 'i':
|
||||
iaid = optarg;
|
||||
break;
|
||||
case 'n':
|
||||
iface = optarg;
|
||||
break;
|
||||
case 'a':
|
||||
ip = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
client_id = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
dry_run = 1;
|
||||
break;
|
||||
case 's':
|
||||
server_id = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
usage(argv[0], stdout);
|
||||
return 0;
|
||||
case '?':
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
default:
|
||||
abort();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if (iaid == UNINITIALIZED){
|
||||
fprintf(stderr, "Missing required iaid parameter\n");
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
}
|
||||
if (server_id == UNINITIALIZED){
|
||||
fprintf(stderr, "Missing required server-id parameter\n");
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
}
|
||||
if (client_id == UNINITIALIZED){
|
||||
fprintf(stderr, "Missing required client-id parameter\n");
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
}
|
||||
if (ip == UNINITIALIZED){
|
||||
fprintf(stderr, "Missing required ip parameter\n");
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
}
|
||||
if (iface == UNINITIALIZED){
|
||||
fprintf(stderr, "Missing required iface parameter\n");
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct dhcp6_packet packet = create_release_packet(iaid, ip, client_id, server_id);
|
||||
if (dry_run){
|
||||
uint16_t i;
|
||||
for(i=0;i<packet.len;i++){
|
||||
printf("%hhx", packet.buf[i]);
|
||||
}
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
return send_release_packet(iface, &packet);
|
||||
|
||||
}
|
||||
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
|
||||
@@ -3,7 +3,7 @@
|
||||
# first column of this file, then a DNAT port-forward will be set up
|
||||
# to the address which has just been allocated by DHCP . The second field
|
||||
# is port number(s). If there is only one, then the port-forward goes to
|
||||
# the same port on the DHCP-client, if there are two seperated with a
|
||||
# the same port on the DHCP-client, if there are two separated with a
|
||||
# colon, then the second number is the port to which the connection
|
||||
# is forwarded on the DHCP-client. By default, forwarding is set up
|
||||
# for TCP, but it can done for UDP instead by prefixing the port to "u".
|
||||
|
||||
18
contrib/reverse-dns/README
Normal file
18
contrib/reverse-dns/README
Normal file
@@ -0,0 +1,18 @@
|
||||
The script reads stdin and replaces all IP addresses with names before
|
||||
outputting it again. IPs from private networks are reverse looked up
|
||||
via dns. Other IP addresses are searched for in the dnsmasq query log.
|
||||
This gives names (CNAMEs if I understand DNS correctly) that are closer
|
||||
to the name the client originally asked for then the names obtained by
|
||||
reverse lookup. Just run
|
||||
|
||||
netstat -n -4 | ./reverse_replace.sh
|
||||
|
||||
to see what it does. It needs
|
||||
|
||||
log-queries
|
||||
log-facility=/var/log/dnsmasq.log
|
||||
|
||||
in the dnsmasq configuration.
|
||||
|
||||
The script runs on debian (with ash installed) and on busybox.
|
||||
|
||||
125
contrib/reverse-dns/reverse_replace.sh
Normal file
125
contrib/reverse-dns/reverse_replace.sh
Normal file
@@ -0,0 +1,125 @@
|
||||
#!/bin/ash
|
||||
# $Id: reverse_replace.sh 18 2015-03-01 16:12:35Z jo $
|
||||
#
|
||||
# Usage e.g.: netstat -n -4 | reverse_replace.sh
|
||||
# Parses stdin for IP4 addresses and replaces them
|
||||
# with names retrieved by parsing the dnsmasq log.
|
||||
# This currently only gives CNAMEs. But these
|
||||
# usually tell you more than the ones from reverse
|
||||
# lookups.
|
||||
#
|
||||
# This has been tested on debian and asuswrt. Please
|
||||
# report successful tests on other platforms.
|
||||
#
|
||||
# Author: Joachim Zobel <jz-2014@heute-morgen.de>
|
||||
# License: Consider this MIT style licensed. You can
|
||||
# do as you ike, but you must not remove my name.
|
||||
#
|
||||
|
||||
LOG=/var/log/dnsmasq.log
|
||||
MAX_LINES=15000
|
||||
|
||||
# sed regex do match IPs
|
||||
IP_regex='[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'
|
||||
# private IP ranges
|
||||
IP_private='\(^127\.\)\|\(^192\.168\.\)\|\(^10\.\)\|\(^172\.1[6-9]\.\)\|\(^172\.2[0-9]\.\)\|\(^172\.3[0-1]\.\)'
|
||||
|
||||
#######################################################################
|
||||
# Find Commands
|
||||
|
||||
HOST=nslookup
|
||||
if type host > /dev/null 2>&1; then
|
||||
# echo "No need for nslookup, host is there"
|
||||
HOST=host
|
||||
fi
|
||||
|
||||
#######################################################################
|
||||
# Functions
|
||||
|
||||
# Use shell variables for an (IP) lookup table
|
||||
create_lookup_table()
|
||||
{
|
||||
# Parse log into lookup table
|
||||
local CMDS="$( tail -"$MAX_LINES" "$LOG" | \
|
||||
grep " is $IP_regex" | \
|
||||
sed "s#.* \([^ ]*\) is \($IP_regex\).*#set_val \2 \1;#" )"
|
||||
|
||||
local IFS='
|
||||
'
|
||||
for CMD in $CMDS
|
||||
do
|
||||
eval $CMD
|
||||
done
|
||||
}
|
||||
|
||||
set_val()
|
||||
{
|
||||
local _IP=$(echo $1 | tr . _)
|
||||
local KEY="__IP__$_IP"
|
||||
eval "$KEY"=$2
|
||||
}
|
||||
|
||||
get_val()
|
||||
{
|
||||
local _IP=$(echo $1 | tr . _)
|
||||
local KEY="__IP__$_IP"
|
||||
eval echo -n '${'"$KEY"'}'
|
||||
}
|
||||
|
||||
dns_lookup()
|
||||
{
|
||||
local IP=$1
|
||||
|
||||
local RTN="$($HOST $IP | \
|
||||
sed 's#\s\+#\n#g' | \
|
||||
grep -v '^$' | \
|
||||
tail -1 | tr -d '\n' | \
|
||||
sed 's#\.$##')"
|
||||
if echo $RTN | grep -q NXDOMAIN; then
|
||||
echo -n $IP
|
||||
else
|
||||
echo -n "$RTN"
|
||||
fi
|
||||
}
|
||||
|
||||
reverse_dns()
|
||||
{
|
||||
local IP=$1
|
||||
|
||||
# Skip if it is not an IP
|
||||
if ! echo $IP | grep -q "^$IP_regex$"; then
|
||||
echo -n $IP
|
||||
return
|
||||
fi
|
||||
|
||||
# Do a dns lookup, if it is a local IP
|
||||
if echo $IP | grep -q $IP_private; then
|
||||
dns_lookup $IP
|
||||
return
|
||||
fi
|
||||
|
||||
local NAME="$(get_val $IP)"
|
||||
|
||||
if [ -z "$NAME" ]; then
|
||||
echo -n $IP
|
||||
else
|
||||
echo -n $NAME
|
||||
fi
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Main
|
||||
create_lookup_table
|
||||
|
||||
while read LINE; do
|
||||
for IP in $(echo "$LINE" | \
|
||||
sed "s#\b\($IP_regex\)\b#\n\1\n#g" | \
|
||||
grep $IP_regex)
|
||||
do
|
||||
NAME=`reverse_dns $IP `
|
||||
# echo "$NAME $IP"
|
||||
LINE=`echo "$LINE" | sed "s#$IP#$NAME#" `
|
||||
done
|
||||
echo $LINE
|
||||
done
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[Unit]
|
||||
Description=A lightweight DHCP and caching DNS server
|
||||
Description=dnsmasq - A lightweight DHCP and caching DNS server
|
||||
|
||||
[Service]
|
||||
Type=dbus
|
||||
|
||||
@@ -2,7 +2,7 @@ A remake of patch Bob Carroll had posted to dnsmasq,
|
||||
now compatible with version 2.47. Hopefully he doesn't
|
||||
mind (sending a copy of this mail to him too).
|
||||
|
||||
Maybe the patch in question is not acceptible
|
||||
Maybe the patch in question is not acceptable
|
||||
as it doesn't add new switch, rather it binds itself to "strict-order".
|
||||
|
||||
What it does is: if you have strict-order in the
|
||||
|
||||
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;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
This is the README for the DNSmasq webmin module.
|
||||
This is the README for the Dnsmasq webmin module.
|
||||
|
||||
Problems:
|
||||
|
||||
@@ -48,7 +48,7 @@ wade through the config file and man pages again.
|
||||
|
||||
If you modify it, or add a language file, and you have a spare moment,
|
||||
please e-mail me - I won't be upset at all if you fix my poor coding!
|
||||
(rather the opposite - I'd be pleased someone found it usefull)
|
||||
(rather the opposite - I'd be pleased someone found it useful)
|
||||
|
||||
Cheers,
|
||||
Neil Fisher <neil@magnecor.com.au>
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
CFLAGS?= -O2 -Wall -W
|
||||
|
||||
all: dhcp_release dhcp_lease_time
|
||||
|
||||
clean:
|
||||
rm -f *~ *.o core dhcp_release dhcp_lease_time
|
||||
@@ -4,7 +4,7 @@ reboot, then it will eventually be restored as hosts renew their
|
||||
leases. Until a host renews (which may take hours/days) it will
|
||||
not exist in the DNS if dnsmasq's DDNS function is in use.
|
||||
|
||||
*WRT systems remount all non-volatile fileystems read-only after boot,
|
||||
*WRT systems remount all non-volatile filesystems read-only after boot,
|
||||
so the normal leasefile will not work. They do, however have NV
|
||||
storage, accessed with the nvram command:
|
||||
|
||||
@@ -62,7 +62,7 @@ about 100 bytes, so restricting the number of leases to 50 will limit
|
||||
use to half that. (The default limit in the distributed source is 150)
|
||||
|
||||
Any UI script which reads the dnsmasq leasefile will have to be
|
||||
ammended, probably by changing it to read the output of
|
||||
amended, probably by changing it to read the output of
|
||||
`lease_update init` instead.
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,8 @@ and avoids startup races with the provider of nameserver information.
|
||||
|
||||
|
||||
Dnsmasq provides one service on the DBus: uk.org.thekelleys.dnsmasq
|
||||
and a single object: /uk/org/thekelleys/dnsmasq
|
||||
and a single object: /uk/org/thekelleys/dnsmasq
|
||||
The name of the service may be changed by giving an argument to --enable-dbus.
|
||||
|
||||
1. METHODS
|
||||
----------
|
||||
@@ -39,6 +40,14 @@ ClearCache
|
||||
Returns nothing. Clears the domain name cache and re-reads
|
||||
/etc/hosts. The same as sending dnsmasq a HUP signal.
|
||||
|
||||
SetFilterWin2KOption
|
||||
--------------------
|
||||
Takes boolean, sets or resets the --filterwin2k option.
|
||||
|
||||
SetBogusPrivOption
|
||||
------------------
|
||||
Takes boolean, sets or resets the --bogus-priv option.
|
||||
|
||||
SetServers
|
||||
----------
|
||||
Returns nothing. Takes a set of arguments representing the new
|
||||
@@ -94,6 +103,148 @@ Each call to SetServers completely replaces the set of servers
|
||||
specified by via the DBus, but it leaves any servers specified via the
|
||||
command line or /etc/dnsmasq.conf or /etc/resolv.conf alone.
|
||||
|
||||
SetServersEx
|
||||
------------
|
||||
|
||||
This function is more flexible and the SetServers function, in that it can
|
||||
handle address scoping, port numbers, and is easier for clients to use.
|
||||
|
||||
Returns nothing. Takes a set of arguments representing the new
|
||||
upstream DNS servers to be used by dnsmasq. All addresses (both IPv4 and IPv6)
|
||||
are represented as STRINGS. Each server address may be followed by one or more
|
||||
STRINGS, which are the domains for which the preceding server should be used.
|
||||
|
||||
This function takes an array of STRING arrays, where each inner array represents
|
||||
a set of DNS servers and domains for which those servers may be used. Each
|
||||
string represents a list of upstream DNS servers first, and domains second.
|
||||
Mixing of domains and servers within a the string array is not allowed.
|
||||
|
||||
Examples.
|
||||
|
||||
[
|
||||
["1.2.3.4", "foobar.com"],
|
||||
["1003:1234:abcd::1%eth0", "eng.mycorp.com", "lab.mycorp.com"]
|
||||
]
|
||||
|
||||
is equivalent to
|
||||
|
||||
--server=/foobar.com/1.2.3.4 \
|
||||
--server=/eng.mycorp.com/lab.mycorp.com/1003:1234:abcd::1%eth0
|
||||
|
||||
An IPv4 address of 0.0.0.0 is interpreted as "no address, local only",
|
||||
so
|
||||
|
||||
[ ["0.0.0.0", "local.domain"] ]
|
||||
|
||||
is equivalent to
|
||||
|
||||
--local=/local.domain/
|
||||
|
||||
|
||||
Each call to SetServersEx completely replaces the set of servers
|
||||
specified by via the DBus, but it leaves any servers specified via the
|
||||
command line or /etc/dnsmasq.conf or /etc/resolv.conf alone.
|
||||
|
||||
|
||||
SetDomainServers
|
||||
----------------
|
||||
|
||||
Yes another variation for setting DNS servers, with the capability of
|
||||
SetServersEx, but without using arrays of arrays, which are not
|
||||
sendable with dbus-send. The arguments are an array of strings which
|
||||
are identical to the equivalent arguments --server, so the example
|
||||
for SetServersEx is represented as
|
||||
|
||||
[
|
||||
"/foobar.com/1.2.3.4"
|
||||
"/eng.mycorp.com/lab.mycorp.com/1003:1234:abcd::1%eth0"
|
||||
]
|
||||
|
||||
GetLoopServers
|
||||
--------------
|
||||
|
||||
(Only available if dnsmasq compiled with HAVE_LOOP)
|
||||
|
||||
Return an array of strings, each string is the IP address of an upstream
|
||||
server which has been found to loop queries back to this dnsmasq instance, and
|
||||
it therefore not being used.
|
||||
|
||||
AddDhcpLease
|
||||
------------
|
||||
|
||||
Returns nothing. Adds or updates a DHCP or DHCPv6 lease to the internal lease
|
||||
database, as if a client requested and obtained a lease.
|
||||
|
||||
If a lease for the IPv4 or IPv6 address already exist, it is overwritten.
|
||||
|
||||
Note that this function will trigger the DhcpLeaseAdded or DhcpLeaseUpdated
|
||||
D-Bus signal and will run the configured DHCP lease script accordingly.
|
||||
|
||||
This function takes many arguments which are the lease parameters:
|
||||
- A string with the textual representation of the IPv4 or IPv6 address of the
|
||||
client.
|
||||
|
||||
Examples:
|
||||
"192.168.1.115"
|
||||
"1003:1234:abcd::1%eth0"
|
||||
"2001:db8:abcd::1"
|
||||
|
||||
- A string representing the hardware address of the client, using the same
|
||||
format as the one used in the lease database.
|
||||
|
||||
Examples:
|
||||
|
||||
"00:23:45:67:89:ab"
|
||||
"06-00:20:e0:3b:13:af" (token ring)
|
||||
|
||||
- The hostname of the client, as an array of bytes (so there is no problem
|
||||
with non-ASCII character encoding). May be empty.
|
||||
|
||||
Example (for "hostname.or.fqdn"):
|
||||
[104, 111, 115, 116, 110, 97, 109, 101, 46, 111, 114, 46, 102, 113, 100, 110]
|
||||
|
||||
- The client identifier (IPv4) or DUID (IPv6) as an array of bytes. May be
|
||||
empty.
|
||||
|
||||
Examples:
|
||||
|
||||
DHCPv6 DUID:
|
||||
[0, 3, 0, 1, 0, 35, 69, 103, 137, 171]
|
||||
DHCPv4 client identifier:
|
||||
[255, 12, 34, 56, 78, 0, 1, 0, 1, 29, 9, 99, 190, 35, 69, 103, 137, 171]
|
||||
|
||||
- The duration of the lease, in seconds. If the lease is updated, then
|
||||
the duration replaces the previous duration.
|
||||
|
||||
Example:
|
||||
|
||||
7200
|
||||
|
||||
- The IAID (Identity association identifier) of the DHCPv6 lease, as a network
|
||||
byte-order unsigned integer. For DHCPv4 leases, this must be set to 0.
|
||||
|
||||
Example (for IPv6):
|
||||
|
||||
203569230
|
||||
|
||||
- A boolean which, if true, indicates that the DHCPv6 lease is for a temporary
|
||||
address (IA_TA). If false, the DHCPv6 lease is for a non-temporary address
|
||||
(IA_NA). For DHCPv4 leases, this must be set to false.
|
||||
|
||||
RemoveDhcpLease
|
||||
---------------
|
||||
|
||||
Returns nothing. Removes a DHCP or DHCPv6 lease to the internal lease
|
||||
database, as if a client sent a release message to abandon a lease.
|
||||
|
||||
This function takes only one parameter: the text representation of the
|
||||
IPv4 or IPv6 address of the lease to remove.
|
||||
|
||||
Note that this function will trigger the DhcpLeaseRemoved signal and the
|
||||
configured DHCP lease script will be run with the "del" action.
|
||||
|
||||
|
||||
|
||||
2. SIGNALS
|
||||
----------
|
||||
|
||||
|
||||
270
debian/changelog
vendored
270
debian/changelog
vendored
@@ -1,6 +1,258 @@
|
||||
dnsmasq (2.77-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
* Don't register as a resolvconf source when config file
|
||||
includes port=0 to disable DNS.
|
||||
* Handle gratuitous format change in /usr/share/dns/root.ds
|
||||
(closes: #858506) (closes: #860064)
|
||||
* Add lsb-base dependancy.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 11 Apr 2017 14:19:20 +0000
|
||||
|
||||
dnsmasq (2.76-5) unstable; urgency=medium
|
||||
|
||||
* Nail libnettle dependency to avoid ABI incompatibility.
|
||||
(closes: #846642)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 14 Dec 2016 17:58:10 +0000
|
||||
|
||||
dnsmasq (2.76-4.1) unstable; urgency=medium
|
||||
|
||||
* Non-maintainer upload.
|
||||
* Add two upstream patches to fix binding to an interface being
|
||||
destroyed and recreated. Closes: #834722.
|
||||
+ 2675f2061525bc954be14988d64384b74aa7bf8b
|
||||
+ 16800ea072dd0cdf14d951c4bb8d2808b3dfe53d
|
||||
|
||||
-- Vincent Bernat <bernat@debian.org> Sat, 26 Nov 2016 20:15:34 +0100
|
||||
|
||||
dnsmasq (2.76-4) unstable; urgency=medium
|
||||
|
||||
* Non-maintainer upload.
|
||||
* Fix FTCBFS: Use triplet-prefixed tools. (closes: #836072)
|
||||
|
||||
-- Helmut Grohne <helmut@subdivi.de> Tue, 30 Aug 2016 13:59:12 +0200
|
||||
|
||||
dnsmasq (2.76-3) unstable; urgency=medium
|
||||
|
||||
* Bump auth zone serial on SIGHUP. (closes: #833733)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Sat, 13 Aug 2016 21:43:10 +0000
|
||||
|
||||
dnsmasq (2.76-2) unstable; urgency=medium
|
||||
|
||||
* Fix to systemd to fix failure to start with bridge interface.
|
||||
(Closes: #831372)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Sat, 16 Jul 2016 22:09:10 +0000
|
||||
|
||||
dnsmasq (2.76-1.2) unstable; urgency=medium
|
||||
|
||||
* Non-maintainer upload.
|
||||
* dnsmasq: Install marker file to determine package installed state,
|
||||
for the benefit of the init script. (Closes: #819856)
|
||||
|
||||
-- Christian Hofstaedtler <zeha@debian.org> Sat, 16 Jul 2016 00:17:57 +0000
|
||||
|
||||
dnsmasq (2.76-1.1) unstable; urgency=medium
|
||||
|
||||
* Non-maintainer upload.
|
||||
* Provide nss-lookup.target for systemd, without relying on insserv.
|
||||
Patch from Michael Biebl <biebl@debian.org>. (Closes: #826242)
|
||||
|
||||
-- Christian Hofstaedtler <zeha@debian.org> Fri, 01 Jul 2016 13:41:11 +0000
|
||||
|
||||
dnsmasq (2.76-1) unstable; urgency=low
|
||||
|
||||
* New upstream. (closes: #798586)
|
||||
* Use /run/dnsmasq directly, rather than relying on link from /var/run
|
||||
to avoid problems before /var is mounted. (closes: #800351)
|
||||
* Test for the existence of /usr/share/doc/dnsmasq rather then
|
||||
/etc/dnsmasq.d/README in the daemon startup script. (closes: #819856)
|
||||
* Add --help to manpage and mention dhcp6 in summary. (closes: #821226)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 10 Sep 2015 23:07:21 +0000
|
||||
|
||||
dnsmasq (2.75-1) unstable; urgency=low
|
||||
|
||||
* New upstream. (closes: #794095)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 30 Jul 2015 20:58:31 +0000
|
||||
|
||||
dnsmasq (2.74-1) unstable; urgency=low
|
||||
|
||||
* New upstream. (LP: #1468611)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 15 Jul 2015 21:54:11 +0000
|
||||
|
||||
dnsmasq (2.73-2) unstable; urgency=low
|
||||
|
||||
* Fix behaviour of empty --conf-file (closes: #790341)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 7 Jul 2015 21:46:42 +0000
|
||||
|
||||
dnsmasq (2.73-1) unstable; urgency=low
|
||||
|
||||
* New upstream. (closes: #786996)
|
||||
* Tweak field width in cache dump to avoid truncating IPv6
|
||||
addresses. (closes: #771557)
|
||||
* Add newline at the end of example config file. (LP: #1416895)
|
||||
* Make Debian package build reproducible. (closes: #777323)
|
||||
* Add Requires=network.target to systemd unit.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 4 Jun 2015 22:31:42 +0000
|
||||
|
||||
dnsmasq (2.72-3) unstable; urgency=medium
|
||||
|
||||
* debian/systemd.service: switch from Type=dbus to Type=forking.
|
||||
dnsmasq does not depend on dbus, but Type=dbus systemd services cannot
|
||||
work without it. (Closes: #769486, #776530)
|
||||
- debian/init: when called with systemd-exec argument, let dnsmasq
|
||||
go into the background, so Type=forking can detect when it is ready
|
||||
* Remove line containing only whitespace in debian/control.
|
||||
(closes: #777571)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 11 Feb 2015 21:56:12 +0000
|
||||
|
||||
dnsmasq (2.72-2) unstable; urgency=low
|
||||
|
||||
* Fix build in Debian-kFreeBSD. (closes: #763693)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 02 Oct 2014 22:34:12 +0000
|
||||
|
||||
dnsmasq (2.72-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
* If dns-root-data package is installed, use it to set the DNSSEC
|
||||
trust anchor(s). Recommend dns-root-data. (closes: #760460)
|
||||
* Handle AD bit correctly in replies from cache. (closes: #761654)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 20 May 2014 21:01:11 +0000
|
||||
|
||||
dnsmasq (2.71-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
* Fix 100% CPU-usage bug when dnsmasq started with cachesize
|
||||
set to zero. (LP: #1314697)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 16 May 2014 20:17:10 +0000
|
||||
|
||||
dnsmasq (2.70-3) unstable; urgency=medium
|
||||
|
||||
* Write a pid-file, even when being started using systemd, since
|
||||
other components may wish to signal dnsmasq.
|
||||
* Enable dnsmasq systemd unit on install. Otherwise dnsmasq does not run on
|
||||
fresh installations (without administrator handholding) and even worse it
|
||||
is disabled on systems switching from sysv to systemd. Modify
|
||||
postinst/postrm exactly as dh_systemd would, add dependency on
|
||||
init-system-helpers. Closes: #724602
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 11 May 2014 17:45:21 +0000
|
||||
|
||||
dnsmasq (2.70-2) unstable; urgency=low
|
||||
|
||||
* Ensure daemon not stared if dnsmasq package has been removed,
|
||||
even if dnsmasq-base is still installed. (closes: #746941)
|
||||
* Tidy cruft in initscript. (closes: #746940)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 04 May 2014 21:34:11 +0000
|
||||
|
||||
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.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 21 Sep 2012 17:17:22 +0000
|
||||
|
||||
dnsmasq (2.63-4) unstable; urgency=low
|
||||
|
||||
* Make pid-file creation immune to symlink attacks. (closes: #686484)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 21 Sep 2012 17:16:34 +0000
|
||||
|
||||
dnsmasq (2.63-3) unstable; urgency=low
|
||||
|
||||
* Move adduser dependency to dnsmasq-base. (closes: #686694)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 4 Sep 2012 21:44:15 +0000
|
||||
|
||||
dnsmasq (2.63-2) unstable; urgency=low
|
||||
|
||||
* Fix version script to report correct version.
|
||||
* Unbotch move of dbus config file by using correct versions in
|
||||
Replaces: and Breaks: lines. (closes: #685204)
|
||||
* Create dnsmasq user in dnsmasq-base so that Dbus doesn't complain if
|
||||
only dnsmasq-base is installed. (closes: #685987)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 28 Aug 2012 16:18:35 +0000
|
||||
|
||||
dnsmasq (2.63-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
* Move /etc/dbus-1/system.d/dnsmasq.conf from dnsmasq to dnsmasq-base.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Mon, 11 Jun 2012 21:55:35 +0000
|
||||
|
||||
@@ -469,7 +721,7 @@ dnsmasq (2.26-1) unstable; urgency=high
|
||||
dnsmasq (2.25-1) unstable; urgency=low
|
||||
|
||||
* Remove bashisms in postinst and prerm scripts.
|
||||
* Remove misconcieved dependency on locales.
|
||||
* Remove misconceived dependency on locales.
|
||||
* Depend on adduser.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 01 Dec 2005 21:02:12 +0000
|
||||
@@ -491,7 +743,7 @@ dnsmasq (2.23-1) unstable; urgency=low
|
||||
* Add support for DNSMASQ_EXCEPT in /etc/defaults/dnsmasq.
|
||||
putting "lo" in this also disables resolvconf support.
|
||||
* No longer delete pre-existing /etc/init.d symlinks. The
|
||||
change in default runlevels which neccesitated this
|
||||
change in default runlevels which necessitated this
|
||||
is now ancient history and anyway the startup script now
|
||||
behaves when called twice. (closes: #312111)
|
||||
* Tightened config-file parser. (closes: #317030)
|
||||
@@ -676,7 +928,7 @@ dnsmasq (2.6-3) unstable; urgency=low
|
||||
|
||||
* Removed reload command from start script and moved force-reload
|
||||
to be equivalent to restart. This is needed to be policy compliant
|
||||
since SIHGUP doesn't cause dnsmasq to reload its configuration file,
|
||||
since SIGHUP doesn't cause dnsmasq to reload its configuration file,
|
||||
only the /etc/hosts, /etc/resolv.conf etc. (closes: #244208)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 18 Apr 2004 14:40:51 +0000
|
||||
@@ -766,8 +1018,8 @@ dnsmasq (2.0-1) unstable; urgency=low
|
||||
* New upstream: This removes the ability to read the
|
||||
the leases file of ISC DHCP and replaces it with a built-in
|
||||
DHCP server. Apologies in advance for breaking backwards
|
||||
compatibilty, but this replaces a bit of a hack (the ISC stuff)
|
||||
with a nicely engineered and much more apropriate solution.
|
||||
compatibility, but this replaces a bit of a hack (the ISC stuff)
|
||||
with a nicely engineered and much more appropriate solution.
|
||||
Wearing my upstream-maintainer hat, I want to lose the hack now,
|
||||
rather than have to support it into Sarge.
|
||||
* New upstream closes some bugs since they become
|
||||
@@ -793,7 +1045,7 @@ dnsmasq (1.18-1) unstable; urgency=low
|
||||
* New upstream which does round-robin. (closes: #215460)
|
||||
* Removed conflicts with other dns servers since it is now
|
||||
possible to control exactly where dnsmasq listens on multi-homed
|
||||
hosts, making co-existance with another nameserver
|
||||
hosts, making co-existence with another nameserver
|
||||
a viable proposition. (closes #176163)
|
||||
* New upstream allows _ in hostnames and check for illegal
|
||||
names in /etc/hosts. (closes: #218842)
|
||||
@@ -879,13 +1131,13 @@ dnsmasq (1.11-2) unstable; urgency=low
|
||||
|
||||
dnsmasq (1.11-1) unstable; urgency=low
|
||||
|
||||
* New uptream.
|
||||
* New upstream.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tues, 12 Jan 2003 22:25:17 -0100
|
||||
|
||||
dnsmasq (1.10-1) unstable; urgency=low
|
||||
|
||||
* New uptream.
|
||||
* New upstream.
|
||||
* Force service to stop in postinst before restarting. I don't
|
||||
understand the circumstances under which it would still be running at
|
||||
this point, but this is the correct fix anyway. (closes: #169718)
|
||||
@@ -897,7 +1149,7 @@ dnsmasq (1.10-1) unstable; urgency=low
|
||||
|
||||
dnsmasq (1.9-1) unstable; urgency=low
|
||||
|
||||
* New uptream.
|
||||
* New upstream.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Mon, 23 Sept 2002 21:35:07 -0100
|
||||
|
||||
|
||||
1
debian/conffiles
vendored
1
debian/conffiles
vendored
@@ -2,5 +2,4 @@
|
||||
/etc/default/dnsmasq
|
||||
/etc/dnsmasq.conf
|
||||
/etc/resolvconf/update.d/dnsmasq
|
||||
/etc/dbus-1/system.d/dnsmasq.conf
|
||||
/etc/insserv.conf.d/dnsmasq
|
||||
|
||||
17
debian/control
vendored
17
debian/control
vendored
@@ -1,13 +1,16 @@
|
||||
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), libbsd-dev [!linux-any]
|
||||
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Standards-Version: 3.9.3
|
||||
Standards-Version: 3.9.8
|
||||
|
||||
Package: dnsmasq
|
||||
Architecture: all
|
||||
Depends: netbase, adduser, dnsmasq-base(>= ${source:Version})
|
||||
Depends: netbase, dnsmasq-base(>= ${binary:Version}),
|
||||
init-system-helpers (>= 1.18~), lsb-base (>= 3.0-6)
|
||||
Suggests: resolvconf
|
||||
Conflicts: resolvconf (<<1.15)
|
||||
Description: Small caching DNS proxy and DHCP/TFTP server
|
||||
@@ -22,8 +25,10 @@ Description: Small caching DNS proxy and DHCP/TFTP server
|
||||
|
||||
Package: dnsmasq-base
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}
|
||||
Conflicts: dnsmasq (<<2.41)
|
||||
Depends: adduser, ${shlibs:Depends}
|
||||
Breaks: dnsmasq (<< 2.63-1~)
|
||||
Replaces: dnsmasq (<< 2.63-1~)
|
||||
Recommends: dns-root-data
|
||||
Description: Small caching DNS proxy and DHCP/TFTP server
|
||||
This package contains the dnsmasq executable and documentation, but
|
||||
not the infrastructure required to run it as a system daemon. For
|
||||
@@ -37,5 +42,3 @@ Description: Utilities for manipulating DHCP leases
|
||||
Small utilities to query a DHCP server's lease database and
|
||||
remove leases from it. These programs are distributed with dnsmasq
|
||||
and may not work correctly with other DHCP servers.
|
||||
|
||||
|
||||
|
||||
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-2016 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
|
||||
|
||||
1
debian/dnsmasq-base.conffiles
vendored
Normal file
1
debian/dnsmasq-base.conffiles
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/etc/dbus-1/system.d/dnsmasq.conf
|
||||
24
debian/dnsmasq-base.postinst
vendored
Normal file
24
debian/dnsmasq-base.postinst
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# Create the dnsmasq user in dnsmasq-base, so that Dbus doesn't complain.
|
||||
|
||||
# create a user to run as (code stolen from dovecot-common)
|
||||
if [ "$1" = "configure" ]; then
|
||||
if [ -z "`id -u dnsmasq 2> /dev/null`" ]; then
|
||||
adduser --system --home /var/lib/misc --gecos "dnsmasq" \
|
||||
--no-create-home --disabled-password \
|
||||
--quiet dnsmasq || true
|
||||
fi
|
||||
|
||||
# Make the directory where we keep the pid file - this
|
||||
# has to be owned by "dnsmasq" so that the file can be unlinked.
|
||||
# This is only actually used by the dnsmasq binary package, not
|
||||
# dnsmasq-base, but it's much easier to create it here so that
|
||||
# we don't have synchronisation issues with the creation of the
|
||||
# dnsmasq user.
|
||||
if [ ! -d /run/dnsmasq ]; then
|
||||
mkdir /run/dnsmasq
|
||||
chown dnsmasq:nogroup /run/dnsmasq
|
||||
fi
|
||||
fi
|
||||
11
debian/dnsmasq-base.postrm
vendored
Normal file
11
debian/dnsmasq-base.postrm
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
if [ purge = "$1" ]; then
|
||||
if [ -x "$(command -v deluser)" ]; then
|
||||
deluser --quiet --system dnsmasq > /dev/null || true
|
||||
else
|
||||
echo >&2 "not removing dnsmasq system account because deluser command was not found"
|
||||
fi
|
||||
rm -rf /run/dnsmasq
|
||||
fi
|
||||
70
debian/init
vendored
70
debian/init
vendored
@@ -8,7 +8,8 @@
|
||||
# Description: DHCP and DNS server
|
||||
### END INIT INFO
|
||||
|
||||
set +e # Don't exit on error status
|
||||
# Don't exit on error status
|
||||
set +e
|
||||
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||
DAEMON=/usr/sbin/dnsmasq
|
||||
@@ -29,6 +30,11 @@ if [ -r /etc/default/locale ]; then
|
||||
export LANG
|
||||
fi
|
||||
|
||||
# The following test ensures the dnsmasq service is not started, when the
|
||||
# package 'dnsmasq' is removed but not purged, even if the dnsmasq-base
|
||||
# package is still in place.
|
||||
test -e /usr/share/dnsmasq/installed-marker || exit 0
|
||||
|
||||
test -x $DAEMON || exit 0
|
||||
|
||||
# Provide skeleton LSB log functions for backports which don't have LSB functions.
|
||||
@@ -75,7 +81,7 @@ if [ ! "$RESOLV_CONF" ] &&
|
||||
[ "$IGNORE_RESOLVCONF" != "yes" ] &&
|
||||
[ -x /sbin/resolvconf ]
|
||||
then
|
||||
RESOLV_CONF=/var/run/dnsmasq/resolv.conf
|
||||
RESOLV_CONF=/run/dnsmasq/resolv.conf
|
||||
fi
|
||||
|
||||
for INTERFACE in $DNSMASQ_INTERFACE; do
|
||||
@@ -90,6 +96,24 @@ 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"
|
||||
|
||||
# If the dns-root-data package is installed, then the trust anchors will be
|
||||
# available in $ROOT_DS, in BIND zone-file format. Reformat as dnsmasq
|
||||
# --trust-anchor options.
|
||||
|
||||
ROOT_DS="/usr/share/dns/root.ds"
|
||||
|
||||
if [ -f $ROOT_DS ]; then
|
||||
DNSMASQ_OPTS="$DNSMASQ_OPTS `sed -e s/"^.*DS[\t ]"/--trust-anchor=.,/ -e s/" "/,/g $ROOT_DS | tr '\n' ' '`"
|
||||
fi
|
||||
|
||||
start()
|
||||
{
|
||||
# Return
|
||||
@@ -97,16 +121,16 @@ start()
|
||||
# 1 if daemon was already running
|
||||
# 2 if daemon could not be started
|
||||
|
||||
# /var/run may be volatile, so we need to ensure that
|
||||
# /var/run/dnsmasq exists here as well as in postinst
|
||||
if [ ! -d /var/run/dnsmasq ]; then
|
||||
mkdir /var/run/dnsmasq || return 2
|
||||
chown dnsmasq:nogroup /var/run/dnsmasq || return 2
|
||||
# /run may be volatile, so we need to ensure that
|
||||
# /run/dnsmasq exists here as well as in postinst
|
||||
if [ ! -d /run/dnsmasq ]; then
|
||||
mkdir /run/dnsmasq || return 2
|
||||
chown dnsmasq:nogroup /run/dnsmasq || return 2
|
||||
fi
|
||||
|
||||
start-stop-daemon --start --quiet --pidfile /var/run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null || return 1
|
||||
start-stop-daemon --start --quiet --pidfile /var/run/dnsmasq/$NAME.pid --exec $DAEMON -- \
|
||||
-x /var/run/dnsmasq/$NAME.pid \
|
||||
start-stop-daemon --start --quiet --pidfile /run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null || return 1
|
||||
start-stop-daemon --start --quiet --pidfile /run/dnsmasq/$NAME.pid --exec $DAEMON -- \
|
||||
-x /run/dnsmasq/$NAME.pid \
|
||||
${MAILHOSTNAME:+ -m $MAILHOSTNAME} \
|
||||
${MAILTARGET:+ -t $MAILTARGET} \
|
||||
${DNSMASQ_USER:+ -u $DNSMASQ_USER} \
|
||||
@@ -130,6 +154,11 @@ start_resolvconf()
|
||||
[ $interface = lo ] && return
|
||||
done
|
||||
|
||||
# Also skip this if DNS functionality is disabled in /etc/dnsmasq.conf
|
||||
if grep -qs '^port=0' /etc/dnsmasq.conf; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -x /sbin/resolvconf ] ; then
|
||||
echo "nameserver 127.0.0.1" | /sbin/resolvconf -a lo.$NAME
|
||||
fi
|
||||
@@ -143,10 +172,7 @@ stop()
|
||||
# 1 if daemon was already stopped
|
||||
# 2 if daemon could not be stopped
|
||||
# other if a failure occurred
|
||||
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile /var/run/dnsmasq/$NAME.pid --name $NAME
|
||||
RETVAL="$?"
|
||||
[ "$RETVAL" = 2 ] && return 2
|
||||
return "$RETVAL"
|
||||
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile /run/dnsmasq/$NAME.pid --name $NAME
|
||||
}
|
||||
|
||||
stop_resolvconf()
|
||||
@@ -164,9 +190,9 @@ status()
|
||||
# 1 if daemon is dead and pid file exists
|
||||
# 3 if daemon is not running
|
||||
# 4 if daemon status is unknown
|
||||
start-stop-daemon --start --quiet --pidfile /var/run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null
|
||||
start-stop-daemon --start --quiet --pidfile /run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null
|
||||
case "$?" in
|
||||
0) [ -e "/var/run/dnsmasq/$NAME.pid" ] && return 1 ; return 3 ;;
|
||||
0) [ -e "/run/dnsmasq/$NAME.pid" ] && return 1 ; return 3 ;;
|
||||
1) return 0 ;;
|
||||
*) return 4 ;;
|
||||
esac
|
||||
@@ -257,7 +283,7 @@ case "$1" in
|
||||
esac
|
||||
;;
|
||||
dump-stats)
|
||||
kill -s USR1 `cat /var/run/dnsmasq/$NAME.pid`
|
||||
kill -s USR1 `cat /run/dnsmasq/$NAME.pid`
|
||||
;;
|
||||
systemd-start-resolvconf)
|
||||
start_resolvconf
|
||||
@@ -266,9 +292,13 @@ case "$1" in
|
||||
stop_resolvconf
|
||||
;;
|
||||
systemd-exec)
|
||||
# --pid-file without argument disables writing a PIDfile, we don't need one with sytemd.
|
||||
# Enable DBus by default because we use DBus activation with systemd.
|
||||
exec $DAEMON --keep-in-foreground --pid-file --enable-dbus \
|
||||
# /run may be volatile, so we need to ensure that
|
||||
# /run/dnsmasq exists here as well as in postinst
|
||||
if [ ! -d /run/dnsmasq ]; then
|
||||
mkdir /run/dnsmasq || return 2
|
||||
chown dnsmasq:nogroup /run/dnsmasq || return 2
|
||||
fi
|
||||
exec $DAEMON -x /run/dnsmasq/$NAME.pid \
|
||||
${MAILHOSTNAME:+ -m $MAILHOSTNAME} \
|
||||
${MAILTARGET:+ -t $MAILTARGET} \
|
||||
${DNSMASQ_USER:+ -u $DNSMASQ_USER} \
|
||||
|
||||
2
debian/installed-marker
vendored
Normal file
2
debian/installed-marker
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# This file indicates dnsmasq (and not just dnsmasq-base) is installed.
|
||||
# It is an implementation detail of the dnsmasq init script.
|
||||
39
debian/postinst
vendored
39
debian/postinst
vendored
@@ -1,32 +1,27 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# create a user to run as (code stolen from dovecot-common)
|
||||
if [ "$1" = "configure" ]; then
|
||||
if [ -z "`id -u dnsmasq 2> /dev/null`" ]; then
|
||||
adduser --system --home /var/lib/misc --gecos "dnsmasq" \
|
||||
--no-create-home --disabled-password \
|
||||
--quiet dnsmasq || true
|
||||
fi
|
||||
# Code copied from dh_systemd_enable ----------------------
|
||||
# This will only remove masks created by d-s-h on package removal.
|
||||
deb-systemd-helper unmask dnsmasq.service >/dev/null || true
|
||||
|
||||
# Make the directory where we keep the pid file - this
|
||||
# has to be owned by "dnsmasq" do that the file can be unlinked.
|
||||
if [ ! -d /var/run/dnsmasq ]; then
|
||||
mkdir /var/run/dnsmasq
|
||||
chown dnsmasq:nogroup /var/run/dnsmasq
|
||||
fi
|
||||
|
||||
# handle new location of pidfile during an upgrade
|
||||
if [ -e /var/run/dnsmasq.pid ]; then
|
||||
mv /var/run/dnsmasq.pid /var/run/dnsmasq
|
||||
fi
|
||||
# was-enabled defaults to true, so new installations run enable.
|
||||
if deb-systemd-helper --quiet was-enabled dnsmasq.service; then
|
||||
# Enables the unit on first installation, creates new
|
||||
# symlinks on upgrades if the unit file has changed.
|
||||
deb-systemd-helper enable dnsmasq.service >/dev/null || true
|
||||
else
|
||||
# Update the statefile to add new symlinks (if any), which need to be
|
||||
# cleaned up on purge. Also remove old symlinks.
|
||||
deb-systemd-helper update-state dnsmasq.service >/dev/null || true
|
||||
fi
|
||||
# End code copied from dh_systemd_enable ------------------
|
||||
|
||||
if [ -x /etc/init.d/dnsmasq ]; then
|
||||
update-rc.d dnsmasq defaults 15 85 >/dev/null
|
||||
|
||||
if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ]; then
|
||||
if [ -e /var/run/dnsmasq/dnsmasq.pid ]; then
|
||||
if [ -e /run/dnsmasq/dnsmasq.pid ]; then
|
||||
ACTION=restart
|
||||
else
|
||||
ACTION=start
|
||||
@@ -40,10 +35,4 @@ if [ -x /etc/init.d/dnsmasq ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# dpkg can botch the change of /usr/share/doc/dnsmasq from
|
||||
# directory to symlink. Fix up here.
|
||||
if [ ! -h /usr/share/doc/dnsmasq ] && { rmdir /usr/share/doc/dnsmasq; }; then
|
||||
cd /usr/share/doc/
|
||||
ln -s /usr/share/doc/dnsmasq-base dnsmasq
|
||||
fi
|
||||
|
||||
|
||||
22
debian/postrm
vendored
22
debian/postrm
vendored
@@ -3,10 +3,20 @@ set -e
|
||||
|
||||
if [ purge = "$1" ]; then
|
||||
update-rc.d dnsmasq remove >/dev/null
|
||||
if [ -x "$(command -v deluser)" ]; then
|
||||
deluser --quiet --system dnsmasq > /dev/null || true
|
||||
else
|
||||
echo >&2 "not removing dnsmasq system account because deluser command was not found"
|
||||
fi
|
||||
rm -rf /var/run/dnsmasq
|
||||
fi
|
||||
|
||||
# Code copied from dh_systemd_enable ----------------------
|
||||
if [ "$1" = "remove" ]; then
|
||||
if [ -x "/usr/bin/deb-systemd-helper" ]; then
|
||||
deb-systemd-helper mask dnsmasq.service >/dev/null
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$1" = "purge" ]; then
|
||||
if [ -x "/usr/bin/deb-systemd-helper" ]; then
|
||||
deb-systemd-helper purge dnsmasq.service >/dev/null
|
||||
deb-systemd-helper unmask dnsmasq.service >/dev/null
|
||||
fi
|
||||
fi
|
||||
# End code copied from dh_systemd_enable ------------------
|
||||
|
||||
|
||||
7
debian/readme
vendored
7
debian/readme
vendored
@@ -31,7 +31,7 @@ Notes on configuring dnsmasq as packaged for Debian.
|
||||
as the first nameserver address in /etc/resolv.conf.
|
||||
|
||||
(6) In the absence of resolvconf, dns-nameservers lines in
|
||||
/etc/network/interfaces are ignored. If you do do not use
|
||||
/etc/network/interfaces are ignored. If you do not use
|
||||
resolvconf, list 127.0.0.1 as the first nameserver address
|
||||
in /etc/resolv.conf and configure your nameservers using
|
||||
"server=<IP-address>" lines in /etc/dnsmasq.conf.
|
||||
@@ -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 than the debian changelog.
|
||||
|
||||
(9) Dnsmasq comes as three packages - dnsmasq-utils, dnsmasq-base and
|
||||
dnsmasq. Dnsmasq-base provides the dnsmasq executable and
|
||||
|
||||
40
debian/resolvconf
vendored
40
debian/resolvconf
vendored
@@ -1,23 +1,22 @@
|
||||
#!/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
|
||||
|
||||
RUN_DIR="/var/run/dnsmasq"
|
||||
RUN_DIR="/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
|
||||
|
||||
145
debian/rules
vendored
145
debian/rules
vendored
@@ -11,68 +11,102 @@
|
||||
|
||||
package=dnsmasq-base
|
||||
|
||||
CFLAGS = $(shell export DEB_BUILD_OPTIONS=$(DEB_BUILD_OPTIONS); dpkg-buildflags --get CFLAGS)
|
||||
CFLAGS += $(shell dpkg-buildflags --get CPPFLAGS)
|
||||
dpkg_buildflags := DEB_BUILD_MAINT_OPTIONS="hardening=+all,+pie,+bindnow" dpkg-buildflags
|
||||
|
||||
CFLAGS = $(shell $(dpkg_buildflags) --get CFLAGS)
|
||||
CFLAGS += $(shell $(dpkg_buildflags) --get CPPFLAGS)
|
||||
CFLAGS += -Wall -W
|
||||
|
||||
LDFLAGS = $(shell dpkg-buildflags --get LDFLAGS)
|
||||
LDFLAGS = $(shell $(dpkg_buildflags) --get LDFLAGS)
|
||||
|
||||
COPTS =
|
||||
DEB_COPTS = $(COPTS)
|
||||
|
||||
TARGET = install-i18n
|
||||
|
||||
DEB_BUILD_ARCH_OS := $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS)
|
||||
DEB_HOST_ARCH_OS := $(shell dpkg-architecture -qDEB_HOST_ARCH_OS)
|
||||
DEB_HOST_GNU_TYPE := $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
|
||||
DEB_BUILD_GNU_TYPE := $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
|
||||
BUILD_DATE := $(shell dpkg-parsechangelog --show-field Date)
|
||||
|
||||
ifeq ($(origin CC),default)
|
||||
CC = $(DEB_HOST_GNU_TYPE)-gcc
|
||||
endif
|
||||
|
||||
# Support non-cross-builds on systems without gnu-triplet-binaries for pkg-config.
|
||||
ifeq ($(DEB_BUILD_GNU_TYPE),$(DEB_HOST_GNU_TYPE))
|
||||
PKG_CONFIG=pkg-config
|
||||
else
|
||||
PKG_CONFIG=$(DEB_HOST_GNU_TYPE)-pkg-config
|
||||
endif
|
||||
|
||||
# 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
|
||||
ifeq ($(DEB_HOST_ARCH_OS),linux)
|
||||
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
|
||||
|
||||
ifneq ($(DEB_HOST_ARCH_OS),linux)
|
||||
# For strlcpy in FreeBSD
|
||||
LDFLAGS += -lbsd
|
||||
endif
|
||||
|
||||
clean:
|
||||
$(checkdir)
|
||||
rm -rf debian/daemon debian/base debian/utils debian/*~ debian/files debian/substvars debian/utils-substvars
|
||||
make clean
|
||||
make -C contrib/wrt clean
|
||||
make -C contrib/lease-tools clean
|
||||
|
||||
binary-indep: checkroot
|
||||
$(checkdir)
|
||||
@@ -84,8 +118,8 @@ binary-indep: checkroot
|
||||
-d debian/daemon/etc/dnsmasq.d \
|
||||
-d debian/daemon/etc/resolvconf/update.d \
|
||||
-d debian/daemon/usr/lib/resolvconf/dpkg-event.d \
|
||||
-d debian/daemon/usr/share/dnsmasq \
|
||||
-d debian/daemon/etc/default \
|
||||
-d debian/daemon/etc/dbus-1/system.d \
|
||||
-d debian/daemon/lib/systemd/system \
|
||||
-d debian/daemon/etc/insserv.conf.d
|
||||
install -m 644 debian/conffiles debian/daemon/DEBIAN
|
||||
@@ -93,15 +127,16 @@ binary-indep: checkroot
|
||||
install -m 755 debian/init debian/daemon/etc/init.d/dnsmasq
|
||||
install -m 755 debian/resolvconf debian/daemon/etc/resolvconf/update.d/dnsmasq
|
||||
install -m 755 debian/resolvconf-package debian/daemon/usr/lib/resolvconf/dpkg-event.d/dnsmasq
|
||||
install -m 644 debian/installed-marker debian/daemon/usr/share/dnsmasq
|
||||
install -m 644 debian/default debian/daemon/etc/default/dnsmasq
|
||||
install -m 644 dnsmasq.conf.example debian/daemon/etc/dnsmasq.conf
|
||||
install -m 644 debian/readme.dnsmasq.d debian/daemon/etc/dnsmasq.d/README
|
||||
install -m 644 debian/dbus.conf debian/daemon/etc/dbus-1/system.d/dnsmasq.conf
|
||||
install -m 644 debian/systemd.service debian/daemon/lib/systemd/system/dnsmasq.service
|
||||
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
|
||||
cd debian/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -T -pdnsmasq -Pdebian/daemon
|
||||
find debian/daemon -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
chown -R root.root debian/daemon
|
||||
chmod -R g-ws debian/daemon
|
||||
dpkg --build debian/daemon ..
|
||||
@@ -111,67 +146,81 @@ binary-arch: checkroot
|
||||
rm -rf debian/base
|
||||
install -m 755 \
|
||||
-d debian/base/DEBIAN \
|
||||
-d debian/base/etc/dbus-1/system.d \
|
||||
-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=$(CC) PKG_CONFIG=$(PKG_CONFIG)
|
||||
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
|
||||
install -m 644 doc.html debian/base/usr/share/doc/$(package)/.
|
||||
# Need to remove paypal links in Debian Package for policy reasons.
|
||||
sed -e /\<H2\>Donations/Q -e /icon.png/d doc.html -e /favicon.ico/d >debian/base/usr/share/doc/$(package)/doc.html
|
||||
echo "</BODY>" >>debian/base/usr/share/doc/$(package)/doc.html
|
||||
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
|
||||
gzip -9n debian/base/usr/share/doc/$(package)/FAQ
|
||||
install -m 644 CHANGELOG debian/base/usr/share/doc/$(package)/changelog
|
||||
gzip -9 debian/base/usr/share/doc/$(package)/changelog
|
||||
gzip -9n debian/base/usr/share/doc/$(package)/changelog
|
||||
install -m 644 CHANGELOG.archive debian/base/usr/share/doc/$(package)/changelog.archive
|
||||
gzip -9 debian/base/usr/share/doc/$(package)/changelog.archive
|
||||
gzip -9n debian/base/usr/share/doc/$(package)/changelog.archive
|
||||
install -m 644 dbus/DBus-interface debian/base/usr/share/doc/$(package)/.
|
||||
gzip -9 debian/base/usr/share/doc/$(package)/DBus-interface
|
||||
gzip -9n debian/base/usr/share/doc/$(package)/DBus-interface
|
||||
endif
|
||||
install -m 644 debian/dnsmasq-base.conffiles debian/base/DEBIAN/conffiles
|
||||
install -m 755 debian/dnsmasq-base.postinst debian/base/DEBIAN/postinst
|
||||
install -m 755 debian/dnsmasq-base.postrm debian/base/DEBIAN/postrm
|
||||
install -m 644 debian/changelog debian/base/usr/share/doc/$(package)/changelog.Debian
|
||||
gzip -9 debian/base/usr/share/doc/$(package)/changelog.Debian
|
||||
gzip -9n debian/base/usr/share/doc/$(package)/changelog.Debian
|
||||
install -m 644 debian/readme debian/base/usr/share/doc/$(package)/README.Debian
|
||||
install -m 644 debian/copyright debian/base/usr/share/doc/$(package)/copyright
|
||||
gzip -9 debian/base/usr/share/man/man8/dnsmasq.8
|
||||
install -m 644 debian/dbus.conf debian/base/etc/dbus-1/system.d/dnsmasq.conf
|
||||
gzip -9n debian/base/usr/share/man/man8/dnsmasq.8
|
||||
for f in debian/base/usr/share/man/*; do \
|
||||
if [ -f $$f/man8/dnsmasq.8 ]; then \
|
||||
gzip -9 $$f/man8/dnsmasq.8 ; \
|
||||
gzip -9n $$f/man8/dnsmasq.8 ; \
|
||||
fi \
|
||||
done
|
||||
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
strip -R .note -R .comment debian/base/usr/sbin/dnsmasq
|
||||
$(DEB_HOST_GNU_TYPE)-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
|
||||
cd debian/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-shlibdeps --warnings=1 debian/base/usr/sbin/dnsmasq
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq-base -Pdebian/base
|
||||
find debian/base -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
chown -R root.root debian/base
|
||||
chmod -R g-ws debian/base
|
||||
dpkg --build debian/base ..
|
||||
|
||||
ifeq ($(DEB_BUILD_ARCH_OS),linux)
|
||||
ifeq ($(DEB_HOST_ARCH_OS),linux)
|
||||
rm -rf debian/utils
|
||||
install -m 755 -d debian/utils/DEBIAN \
|
||||
-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
|
||||
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
|
||||
install -m 755 contrib/wrt/dhcp_lease_time debian/utils/usr/bin/dhcp_lease_time
|
||||
install -m 644 contrib/wrt/dhcp_lease_time.1 debian/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||
make -C contrib/lease-tools PREFIX=/usr DESTDIR=`pwd`/debian/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
|
||||
install -m 755 contrib/lease-tools/dhcp_release debian/utils/usr/bin/dhcp_release
|
||||
install -m 644 contrib/lease-tools/dhcp_release.1 debian/utils/usr/share/man/man1/dhcp_release.1
|
||||
gzip -9n debian/utils/usr/share/man/man1/dhcp_release.1
|
||||
install -m 755 contrib/lease-tools/dhcp_release6 debian/utils/usr/bin/dhcp_release6
|
||||
install -m 644 contrib/lease-tools/dhcp_release6.1 debian/utils/usr/share/man/man1/dhcp_release6.1
|
||||
gzip -9n debian/utils/usr/share/man/man1/dhcp_release6.1
|
||||
install -m 755 contrib/lease-tools/dhcp_lease_time debian/utils/usr/bin/dhcp_lease_time
|
||||
install -m 644 contrib/lease-tools/dhcp_lease_time.1 debian/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||
install -m 644 debian/copyright debian/utils/usr/share/doc/dnsmasq-utils/copyright
|
||||
install -m 644 debian/changelog debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
|
||||
gzip -9 debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
|
||||
gzip -9 debian/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||
gzip -9n debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
|
||||
gzip -9n debian/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
strip -R .note -R .comment debian/utils/usr/bin/dhcp_release
|
||||
strip -R .note -R .comment debian/utils/usr/bin/dhcp_lease_time
|
||||
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/utils/usr/bin/dhcp_release
|
||||
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/utils/usr/bin/dhcp_release6
|
||||
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/utils/usr/bin/dhcp_lease_time
|
||||
endif
|
||||
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | 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
|
||||
find debian/utils -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
chown -R root.root debian/utils
|
||||
chmod -R g-ws debian/utils
|
||||
dpkg --build debian/utils ..
|
||||
|
||||
1
debian/shlibs.local
vendored
Normal file
1
debian/shlibs.local
vendored
Normal file
@@ -0,0 +1 @@
|
||||
libnettle 6 libnettle6 (>= 3.3)
|
||||
18
debian/systemd.service
vendored
18
debian/systemd.service
vendored
@@ -1,9 +1,13 @@
|
||||
[Unit]
|
||||
Description=A lightweight DHCP and caching DNS server
|
||||
Description=dnsmasq - A lightweight DHCP and caching DNS server
|
||||
Requires=network.target
|
||||
Wants=nss-lookup.target
|
||||
Before=nss-lookup.target
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=dbus
|
||||
BusName=uk.org.thekelleys.dnsmasq
|
||||
Type=forking
|
||||
PIDFile=/run/dnsmasq/dnsmasq.pid
|
||||
|
||||
# Test the config file and refuse starting if it is not valid.
|
||||
ExecStartPre=/usr/sbin/dnsmasq --test
|
||||
@@ -11,16 +15,10 @@ ExecStartPre=/usr/sbin/dnsmasq --test
|
||||
# We run dnsmasq via the /etc/init.d/dnsmasq script which acts as a
|
||||
# wrapper picking up extra configuration files and then execs dnsmasq
|
||||
# itself, when called with the "systemd-exec" function.
|
||||
#
|
||||
# It also adds the command-line flags
|
||||
# --keep-in-foreground --pid-file --enable-dbus
|
||||
# to disable writing a pid-file (not needed with systemd) and
|
||||
# enable DBus by default because we use DBus activation.
|
||||
#
|
||||
ExecStart=/etc/init.d/dnsmasq systemd-exec
|
||||
|
||||
# The systemd-*-resolvconf functions configure (and deconfigure)
|
||||
# resolvconf to work with the dnsmasq DNS server. They're called liek
|
||||
# resolvconf to work with the dnsmasq DNS server. They're called like
|
||||
# this to get correct error handling (ie don't start-resolvconf if the
|
||||
# dnsmasq daemon fails to start.
|
||||
ExecStartPost=/etc/init.d/dnsmasq systemd-start-resolvconf
|
||||
|
||||
@@ -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
|
||||
@@ -173,7 +189,7 @@
|
||||
# add names to the DNS for the IPv6 address of SLAAC-configured dual-stack
|
||||
# hosts. Use the DHCPv4 lease to derive the name, network segment and
|
||||
# MAC address and assume that the host will also have an
|
||||
# IPv6 address calculated using the SLAAC alogrithm.
|
||||
# IPv6 address calculated using the SLAAC algorithm.
|
||||
#dhcp-range=1234::, ra-names
|
||||
|
||||
# Do Router Advertisements, BUT NOT DHCP for this subnet.
|
||||
@@ -194,7 +210,7 @@
|
||||
#dhcp-range=1234::, ra-stateless, ra-names
|
||||
|
||||
# Do router advertisements for all subnets where we're doing DHCPv6
|
||||
# Unless overriden by ra-stateless, ra-names, et al, the router
|
||||
# Unless overridden by ra-stateless, ra-names, et al, the router
|
||||
# advertisements will have the M and O bits set, so that the clients
|
||||
# get addresses and configuration from DHCPv6, and the A bit reset, so the
|
||||
# clients don't use SLAAC addresses.
|
||||
@@ -235,6 +251,13 @@
|
||||
# the IP address 192.168.0.60
|
||||
#dhcp-host=id:01:02:02:04,192.168.0.60
|
||||
|
||||
# Always give the InfiniBand interface with hardware address
|
||||
# 80:00:00:48:fe:80:00:00:00:00:00:00:f4:52:14:03:00:28:05:81 the
|
||||
# ip address 192.168.0.61. The client id is derived from the prefix
|
||||
# ff:00:00:00:00:00:02:00:00:02:c9:00 and the last 8 pairs of
|
||||
# hex digits of the hardware address.
|
||||
#dhcp-host=id:ff:00:00:00:00:00:02:00:00:02:c9:00:f4:52:14:03:00:28:05:81,192.168.0.61
|
||||
|
||||
# Always give the host with client identifier "marjorie"
|
||||
# the IP address 192.168.0.60
|
||||
#dhcp-host=id:marjorie,192.168.0.60
|
||||
@@ -265,7 +288,7 @@
|
||||
# Give a fixed IPv6 address and name to client with
|
||||
# DUID 00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2
|
||||
# Note the MAC addresses CANNOT be used to identify DHCPv6 clients.
|
||||
# Note also the they [] around the IPv6 address are obilgatory.
|
||||
# Note also the they [] around the IPv6 address are obligatory.
|
||||
#dhcp-host=id:00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2, fred, [1234::5]
|
||||
|
||||
# Ignore any clients which are not specified in dhcp-host lines
|
||||
@@ -326,6 +349,17 @@
|
||||
# dnsmasq and another.
|
||||
#dhcp-option=option6:dns-server,[::],[1234::88]
|
||||
|
||||
# Ask client to poll for option changes every six hours. (RFC4242)
|
||||
#dhcp-option=option6:information-refresh-time,6h
|
||||
|
||||
# Set option 58 client renewal time (T1). Defaults to half of the
|
||||
# lease time if not specified. (RFC2132)
|
||||
#dhcp-option=option:T1:1m
|
||||
|
||||
# Set option 59 rebinding time (T2). Defaults to 7/8 of the
|
||||
# lease time if not specified. (RFC2132)
|
||||
#dhcp-option=option:T2:2m
|
||||
|
||||
# Set the NTP time server address to be the same machine as
|
||||
# is running dnsmasq
|
||||
#dhcp-option=42,0.0.0.0
|
||||
@@ -467,6 +501,9 @@
|
||||
# Set the root directory for files available via FTP.
|
||||
#tftp-root=/var/ftpd
|
||||
|
||||
# Do not abort if the tftp-root is unavailable
|
||||
#tftp-no-fail
|
||||
|
||||
# Make the TFTP server more secure: with this set, only files owned by
|
||||
# the user dnsmasq is running as will be send over the net.
|
||||
#tftp-secure
|
||||
@@ -477,7 +514,7 @@
|
||||
#tftp-no-blocksize
|
||||
|
||||
# Set the boot file name only when the "red" tag is set.
|
||||
#dhcp-boot=net:red,pxelinux.red-net
|
||||
#dhcp-boot=tag:red,pxelinux.red-net
|
||||
|
||||
# An example of dhcp-boot with an external TFTP server: the name and IP
|
||||
# address of the server are given after the filename.
|
||||
@@ -488,7 +525,7 @@
|
||||
# (using /etc/hosts) then that name can be specified as the
|
||||
# tftp_servername (the third option to dhcp-boot) and in that
|
||||
# case dnsmasq resolves this name and returns the resultant IP
|
||||
# addresses in round robin fasion. This facility can be used to
|
||||
# addresses in round robin fashion. This facility can be used to
|
||||
# load balance the tftp load among a set of servers.
|
||||
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,tftp_server_name
|
||||
|
||||
@@ -522,7 +559,7 @@
|
||||
# If you want to disable negative caching, uncomment this.
|
||||
#no-negcache
|
||||
|
||||
# Normally responses which come form /etc/hosts and the DHCP lease
|
||||
# Normally responses which come from /etc/hosts and the DHCP lease
|
||||
# file have Time-To-Live set as zero, which conventionally means
|
||||
# do not cache further. If you are happy to trade lower load on the
|
||||
# server for potentially stale date, you can set a time-to-live (in
|
||||
@@ -618,6 +655,12 @@
|
||||
# Log lots of extra information about DHCP transactions.
|
||||
#log-dhcp
|
||||
|
||||
# Include a another lot of configuration options.
|
||||
# Include another lot of configuration options.
|
||||
#conf-file=/etc/dnsmasq.more.conf
|
||||
#conf-dir=/etc/dnsmasq.d
|
||||
|
||||
# Include all the files in a directory except those ending in .bak
|
||||
#conf-dir=/etc/dnsmasq.d,.bak
|
||||
|
||||
# Include all files in a directory which end in .conf
|
||||
#conf-dir=/etc/dnsmasq.d/,*.conf
|
||||
|
||||
137
doc.html
137
doc.html
@@ -1,8 +1,7 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE> Dnsmasq - a DNS forwarder for NAT firewalls.</TITLE>
|
||||
<link rel="icon"
|
||||
href="http://www.thekelleys.org.uk/dnsmasq/images/favicon.ico">
|
||||
<TITLE> Dnsmasq - network services for small networks.</TITLE>
|
||||
<link rel="icon" href="http://www.thekelleys.org.uk/dnsmasq/images/favicon.ico">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="WHITE">
|
||||
<table width="100%" border="0" cellpadding="0" cellspacing="0">
|
||||
@@ -11,82 +10,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
|
||||
caching 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,15 +67,31 @@ 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>
|
||||
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
|
||||
first location for queries, bugreports, suggestions etc. The list is mirrored, with a
|
||||
search facility, at <A HREF="https://www.mail-archive.com/dnsmasq-discuss@lists.thekelleys.org.uk/">
|
||||
https://www.mail-archive.com/dnsmasq-discuss@lists.thekelleys.org.uk/</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>
|
||||
|
||||
|
||||
928
man/dnsmasq.8
928
man/dnsmasq.8
File diff suppressed because it is too large
Load Diff
@@ -1062,10 +1062,14 @@ esta opci
|
||||
cuando hay cambios hechos a el client-id y tiempos de arriendo y vencimiento.
|
||||
.TP
|
||||
.B --bridge-interface=<nombre de interface>,<alias>[,<alias>]
|
||||
Tratar paquetes de pedidos DHCP que llegan a cualquiera de las interfaces <alias>
|
||||
como si hubieran llegado a la interface <nombre de interface>. Esta opción
|
||||
es necesaria al usar bridging estilo viejo en plataformas BSD, dado a que
|
||||
los paquetes llegan a interfaces tap que no tienen una dirección IP.
|
||||
Tratar paquetes de pedidos DHCP (v4 y v6) y de IPv6 Router Solicit que
|
||||
llegan a cualquiera de las interfaces <alias> como si hubieran llegado
|
||||
a la interface <nombre de interface>. Esta opción permite que dnsmasq
|
||||
puede proporcionar los servicios DHCP y RA a través de interfaces
|
||||
ethernet sin dirección y sin puente; por ejemplo en un nodo de cálculo
|
||||
de OpenStack, donde cada una de esas interfaces es una interfaz TAP
|
||||
para una máquina virtual, o al usar bridging estilo viejo en
|
||||
plataformas BSD.
|
||||
.TP
|
||||
.B \-s, --domain=<dominio>[,<rango de IPs>]
|
||||
Especifica los dominios DNS para el servidor DHCP. Dominios pueden ser
|
||||
|
||||
554
man/fr/dnsmasq.8
554
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
|
||||
@@ -232,6 +277,18 @@ autre serveur de nom (ou une autre instance de Dnsmasq) tourne sur la même
|
||||
machine. Utiliser cette option permet également d'avoir plusieurs instances de
|
||||
Dnsmasq fournissant un service DHCP sur la même machine.
|
||||
.TP
|
||||
.B --bind-dynamic
|
||||
Autorise un mode réseau intermédiaire entre
|
||||
.B --bind-interfaces
|
||||
et le mode par défaut. Dnsmasq s'associe à une seule interface, ce qui permet
|
||||
plusieurs instances de dnsmasq, mais si une interface ou adresse apparaissent,
|
||||
il se mettra automatiquement à écouter sur celles-ci (les règles de contrôle
|
||||
d'accès s'appliquent).
|
||||
De fait, les interfaces créées dynamiquement fonctionnent de la même façon que
|
||||
dans le comportement par défaut. Ce fonctionnement nécessite des APIs réseau
|
||||
non standard et n'est disponible que sous Linux. Sur les autres plateformes,
|
||||
le fonctionnement est celui du mode --bind-interfaces.
|
||||
.TP
|
||||
.B \-y, --localise-queries
|
||||
Retourne des réponses aux requêtes DNS dépendantes de l'interface sur laquelle
|
||||
la requête a été reçue, à partir du fichier /etc/hosts. Si un nom dans
|
||||
@@ -300,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
|
||||
@@ -343,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
|
||||
@@ -443,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
|
||||
@@ -530,11 +597,19 @@ 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. 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 vers la même cible.
|
||||
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
|
||||
vers la même cible.
|
||||
.TP
|
||||
.B --dns-rr=<nom>,<numéro-RR>,[<données hexadécimales>]
|
||||
Retourne un enregistrement DNS arbitraire. Le numéro correspond au type
|
||||
d'enregistrement (qui est toujours de la classe C_IN). La valeur de
|
||||
l'enregistrement est donnée dans les données hexadécimales, qui peuvent
|
||||
être de la forme 01:23:45, 01 23 45,+012345 ou n'importe quelle combinaison.
|
||||
.TP
|
||||
.B --interface-name=<nom>,<interface>
|
||||
Définit un entregistrement DNS associant le nom avec l'adresse primaire sur
|
||||
@@ -548,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
|
||||
@@ -556,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.
|
||||
@@ -591,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
|
||||
@@ -601,9 +740,10 @@ avec le support conntrack, le noyau doit également inclure conntrack et être
|
||||
configuré pour cela. Cette option ne peut pas être combinée avec
|
||||
--query-port.
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[interface:<interface>,][tag:<label>[,tag:<label>],][set:<label>],]<adresse de début>[,<adresse de fin>][,<mode>][,<masque de réseau>[,<broadcast>]][,<durée de bail>]
|
||||
.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=[interface:<interface>,][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
|
||||
@@ -643,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
|
||||
@@ -657,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
|
||||
@@ -669,7 +852,7 @@ et
|
||||
pour plus de détails).
|
||||
|
||||
Pour IPv6, le mode peut-être une combinaison des valeurs
|
||||
.B ra-only, slaac, ra-names, ra-stateless.
|
||||
.B ra-only, slaac, ra-names, ra-stateless, off-link.
|
||||
|
||||
.B ra-only
|
||||
indique à dnsmasq de n'effectuer que des annonces de routeur (Router
|
||||
@@ -705,8 +888,9 @@ peut-être combiné avec
|
||||
et
|
||||
.B slaac.
|
||||
|
||||
La section interface:<nom d'interface> n'est normalement pas utilisée. Se
|
||||
référer aux indications de la section NOTES pour plus de détail à ce sujet.
|
||||
.B off-link
|
||||
indique à dnsmasq d'annoncer le préfixe sans le bit L (sur lien).
|
||||
|
||||
.TP
|
||||
.B \-G, --dhcp-host=[<adresse matérielle>][,id:<identifiant client>|*][,set:<label>][,<adresse IP>][,<nom d'hôte>][,<durée de bail>][,ignore]
|
||||
Spécifie les paramètres DHCP relatifs à un hôte. Cela permet à une machine
|
||||
@@ -730,9 +914,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
|
||||
@@ -744,11 +928,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.
|
||||
|
||||
@@ -952,6 +1142,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
|
||||
@@ -986,7 +1210,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
|
||||
@@ -1186,14 +1410,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
|
||||
@@ -1225,6 +1451,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.
|
||||
@@ -1301,6 +1532,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 :
|
||||
@@ -1315,6 +1549,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
|
||||
@@ -1422,11 +1658,14 @@ changement d'état de bail à chaque changement de l'identifiant de client, de
|
||||
longueur de bail ou de date d'expiration.
|
||||
.TP
|
||||
.B --bridge-interface=<interface>,<alias>[,<alias>]
|
||||
Traiter les requêtes DHCP arrivant sur n'importe laquelle des interfaces <alias>
|
||||
comme si elles arrivaient de l'interface <interface>. Cette option est
|
||||
nécessaire lors de l'utilisation de pont ethernet "ancien mode" sur plate-forme
|
||||
BSD, puisque dans ce cas les paquets arrivent sur des interfaces "tap" n'ont
|
||||
pas d'adresse IP.
|
||||
Traiter les requêtes DHCP (v4 et v6) et IPv6 Router Solicit arrivant
|
||||
sur n'importe laquelle des interfaces <alias> comme si elles
|
||||
arrivaient de l'interface <interface>. Cette option permet à dnsmasq
|
||||
de fournir les service DHCP et RA sur les interfaces ethernet non
|
||||
adressés et non pontés; par exemple sur un hôte de calcul d'OpenStack
|
||||
où chaque telle interface est une interface TAP à une machine
|
||||
virtuelle, ou lors de l'utilisation de pont ethernet "ancien mode" sur
|
||||
plate-forme BSD. Chaque <alias> peut finir avec un simple '*' joker.
|
||||
.TP
|
||||
.B \-s, --domain=<domaine>[,<gamme d'adresses>[,local]]
|
||||
Spécifie le domaine du serveur DHCP. Le domaine peut être donné de manière
|
||||
@@ -1517,12 +1756,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[=<interface>]
|
||||
.B --ra-param=<interface>,[mtu:<valeur>|<interface>|off,][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,0.
|
||||
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 quatre paramètres peuvent-être configurés en une fois :
|
||||
.B --ra-param=eth0,mtu:1280,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). Voir dans la section NOTES les
|
||||
informations relatives à la spécification de l'interface.
|
||||
(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
|
||||
@@ -1560,6 +1817,13 @@ Sans cela, en effet, l'accès de tous les fichiers du serveur pour lequel le
|
||||
droit de lecture pour tout le monde est positionné ("world-readable") devient
|
||||
possible par n'importe quel hôte sur le réseau.
|
||||
.TP
|
||||
.B --tftp-lowercase
|
||||
Converti les noms de fichiers des requêtes TFTP en minuscules. Cela est utile
|
||||
pour les requêtes effectuées depuis les machines Windows, dont les systèmes
|
||||
de fichiers sont insensibles à la casse et pour lesquels la détermination
|
||||
de la casse est parfois un peu aléatoire. A noter que le serveur tftp de
|
||||
dnsmasq converti systématiquement les "\\" en "/" dans les noms de fichiers.
|
||||
.TP
|
||||
.B --tftp-max=<connexions>
|
||||
Définit le nombre maximum de connexions TFTP simultanées autorisées. La valeur
|
||||
par défaut est de 50. Lorsqu'un grand nombre de connexions TFTP est spécifié,
|
||||
@@ -1823,50 +2087,166 @@ 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.
|
||||
|
||||
Il est possible de spécifier un nom d'interface à
|
||||
.B dhcp-range
|
||||
sous la forme "interface:<nom d'interface>". La sémantique est comme suit :
|
||||
Pour le DHCP, s'il existe une autre valeur de dhcp-range pour laquelle
|
||||
_aucun_ nom d'interface n'est donné, alors le nom d'interface est ignoré
|
||||
et dnsmasq se comporte comme si la partie spécifiant l'interface n'existait
|
||||
pas, sinon le service DHCP n'est fourni qu'aux interfaces mentionnées dans
|
||||
les déclarations dhcp-range. Pour le DNS, si il n'y a pas d'option
|
||||
.B --interface
|
||||
ou
|
||||
.B --listen-address
|
||||
, alors le comportement n'est pas impacté par la spécification d'interface. Si
|
||||
l'une ou l'autre de ces options est présente, alors les interfaces mentionnées
|
||||
dans les plages d'adresses dhcp-range sont rajoutées à la liste de celles
|
||||
où le service DNS est assuré.
|
||||
|
||||
De manière similaire,
|
||||
.B enable-tftp
|
||||
peut prendre un nom d'interface, ce qui active le TFTP pour cette seule
|
||||
interface, en ignorant les options
|
||||
.B --interface
|
||||
ou
|
||||
.B --listen-address
|
||||
De plus,
|
||||
.B --tftp-secure
|
||||
,
|
||||
.B --tftp-unique-root
|
||||
.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
|
||||
.B --tftp-no-blocksize
|
||||
sont ignorées pour les requêtes sur de telles interfaces. (une directive
|
||||
.B --tftp-root
|
||||
donnant le chemin de la racine et une interface doit-être fournie).
|
||||
|
||||
Ces règles peuvent paraître étrange à première vue, mais elles permettent
|
||||
d'ajouter à la configuration de dnsmasq des lignes de configuration de la
|
||||
forme "dhcp-range=interface:virt0,192.168.0.4,192.168.0.200" afin de fournir
|
||||
un service DHCP et DNS sur cette interface, sans pour autant affecter les
|
||||
services fournis sur d'autres interfaces, malgré l'absence de paramètres
|
||||
"interface=<interface>" sur les autres lignes de configuration.
|
||||
"enable-tftp=virt0" et "tftp-root=<root>,virt0" effectuent la même chose pour
|
||||
TFTP.
|
||||
L'idée de tout cela est de permettre l'addition de telles lignes
|
||||
automatiquement par libvirt ou un système équivalent, sans perturbation
|
||||
d'une configuration manuelle existant par ailleurs.
|
||||
.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
|
||||
|
||||
1448
po/pt_BR.po
1448
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
@@ -78,7 +78,7 @@ by modifying MODIFY_RESOLV_CONF_DYNAMICALLY="no" in <TT>/etc/sysconfig/network/c
|
||||
|
||||
|
||||
<h3>Automatic DNS server configuration with DHCP.</h3>
|
||||
You need to get your DHCP client to write the addresse(s) of the DNS
|
||||
You need to get your DHCP client to write the address(es) of the DNS
|
||||
servers to a file other than <TT>/etc/resolv.conf</TT>. For dhcpcd, the
|
||||
<TT>dhcpcd.exe</TT> script gets run with the addresses of the nameserver(s) in
|
||||
the shell variable <TT>$DNS</TT>. The following bit of shell script
|
||||
@@ -86,8 +86,8 @@ uses that to write a file suitable for dnsmasq.
|
||||
<PRE>
|
||||
|
||||
echo -n >|/etc/dhcpc/resolv.conf
|
||||
dnsservs=${DNS//,/ }
|
||||
for serv in $dnsservs; do
|
||||
dnsservers=${DNS//,/ }
|
||||
for serv in $dnsservers; do
|
||||
echo "nameserver $serv" >>/etc/dhcpc/resolv.conf
|
||||
done
|
||||
|
||||
@@ -186,7 +186,7 @@ more than one nameserver just include as many
|
||||
|
||||
<H2>Local domains.</H2>
|
||||
Sometimes people have local domains which they do not want forwarded
|
||||
to upstream servers. This is accomodated by using server options
|
||||
to upstream servers. This is accommodated by using server options
|
||||
without the server IP address. To make things clearer <TT>local</TT>
|
||||
is a synonym for <TT>server</TT>. For example the option
|
||||
<TT>local=/localnet/</TT> ensures that any domain name query which ends in
|
||||
|
||||
247
src/arp.c
Normal file
247
src/arp.c
Normal file
@@ -0,0 +1,247 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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"
|
||||
|
||||
/* Time between forced re-loads from kernel. */
|
||||
#define INTERVAL 90
|
||||
|
||||
#define ARP_MARK 0
|
||||
#define ARP_FOUND 1 /* Confirmed */
|
||||
#define ARP_NEW 2 /* Newly created */
|
||||
#define ARP_EMPTY 3 /* No MAC addr */
|
||||
|
||||
struct arp_record {
|
||||
unsigned short hwlen, status;
|
||||
int family;
|
||||
unsigned char hwaddr[DHCP_CHADDR_MAX];
|
||||
struct all_addr addr;
|
||||
struct arp_record *next;
|
||||
};
|
||||
|
||||
static struct arp_record *arps = NULL, *old = NULL, *freelist = NULL;
|
||||
static time_t last = 0;
|
||||
|
||||
static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
|
||||
{
|
||||
struct arp_record *arp;
|
||||
|
||||
(void)parmv;
|
||||
|
||||
if (maclen > DHCP_CHADDR_MAX)
|
||||
return 1;
|
||||
|
||||
#ifndef HAVE_IPV6
|
||||
if (family != AF_INET)
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
/* Look for existing entry */
|
||||
for (arp = arps; arp; arp = arp->next)
|
||||
{
|
||||
if (family != arp->family || arp->status == ARP_NEW)
|
||||
continue;
|
||||
|
||||
if (family == AF_INET)
|
||||
{
|
||||
if (arp->addr.addr.addr4.s_addr != ((struct in_addr *)addrp)->s_addr)
|
||||
continue;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, (struct in6_addr *)addrp))
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (arp->status == ARP_EMPTY)
|
||||
{
|
||||
/* existing address, was negative. */
|
||||
arp->status = ARP_NEW;
|
||||
arp->hwlen = maclen;
|
||||
memcpy(arp->hwaddr, mac, maclen);
|
||||
}
|
||||
else if (arp->hwlen == maclen && memcmp(arp->hwaddr, mac, maclen) == 0)
|
||||
/* Existing entry matches - confirm. */
|
||||
arp->status = ARP_FOUND;
|
||||
else
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!arp)
|
||||
{
|
||||
/* New entry */
|
||||
if (freelist)
|
||||
{
|
||||
arp = freelist;
|
||||
freelist = freelist->next;
|
||||
}
|
||||
else if (!(arp = whine_malloc(sizeof(struct arp_record))))
|
||||
return 1;
|
||||
|
||||
arp->next = arps;
|
||||
arps = arp;
|
||||
arp->status = ARP_NEW;
|
||||
arp->hwlen = maclen;
|
||||
arp->family = family;
|
||||
memcpy(arp->hwaddr, mac, maclen);
|
||||
if (family == AF_INET)
|
||||
arp->addr.addr.addr4.s_addr = ((struct in_addr *)addrp)->s_addr;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
memcpy(&arp->addr.addr.addr6, addrp, IN6ADDRSZ);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* If in lazy mode, we cache absence of ARP entries. */
|
||||
int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now)
|
||||
{
|
||||
struct arp_record *arp, *tmp, **up;
|
||||
int updated = 0;
|
||||
|
||||
again:
|
||||
|
||||
/* If the database is less then INTERVAL old, look in there */
|
||||
if (difftime(now, last) < INTERVAL)
|
||||
{
|
||||
/* addr == NULL -> just make cache up-to-date */
|
||||
if (!addr)
|
||||
return 0;
|
||||
|
||||
for (arp = arps; arp; arp = arp->next)
|
||||
{
|
||||
if (addr->sa.sa_family != arp->family)
|
||||
continue;
|
||||
|
||||
if (arp->family == AF_INET &&
|
||||
arp->addr.addr.addr4.s_addr != addr->in.sin_addr.s_addr)
|
||||
continue;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (arp->family == AF_INET6 &&
|
||||
!IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, &addr->in6.sin6_addr))
|
||||
continue;
|
||||
#endif
|
||||
|
||||
/* Only accept positive entries unless in lazy mode. */
|
||||
if (arp->status != ARP_EMPTY || lazy || updated)
|
||||
{
|
||||
if (mac && arp->hwlen != 0)
|
||||
memcpy(mac, arp->hwaddr, arp->hwlen);
|
||||
return arp->hwlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found, try the kernel */
|
||||
if (!updated)
|
||||
{
|
||||
updated = 1;
|
||||
last = now;
|
||||
|
||||
/* Mark all non-negative entries */
|
||||
for (arp = arps; arp; arp = arp->next)
|
||||
if (arp->status != ARP_EMPTY)
|
||||
arp->status = ARP_MARK;
|
||||
|
||||
iface_enumerate(AF_UNSPEC, NULL, filter_mac);
|
||||
|
||||
/* Remove all unconfirmed entries to old list. */
|
||||
for (arp = arps, up = &arps; arp; arp = tmp)
|
||||
{
|
||||
tmp = arp->next;
|
||||
|
||||
if (arp->status == ARP_MARK)
|
||||
{
|
||||
*up = arp->next;
|
||||
arp->next = old;
|
||||
old = arp;
|
||||
}
|
||||
else
|
||||
up = &arp->next;
|
||||
}
|
||||
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* record failure, so we don't consult the kernel each time
|
||||
we're asked for this address */
|
||||
if (freelist)
|
||||
{
|
||||
arp = freelist;
|
||||
freelist = freelist->next;
|
||||
}
|
||||
else
|
||||
arp = whine_malloc(sizeof(struct arp_record));
|
||||
|
||||
if (arp)
|
||||
{
|
||||
arp->next = arps;
|
||||
arps = arp;
|
||||
arp->status = ARP_EMPTY;
|
||||
arp->family = addr->sa.sa_family;
|
||||
arp->hwlen = 0;
|
||||
|
||||
if (addr->sa.sa_family == AF_INET)
|
||||
arp->addr.addr.addr4.s_addr = addr->in.sin_addr.s_addr;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
memcpy(&arp->addr.addr.addr6, &addr->in6.sin6_addr, IN6ADDRSZ);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_arp_script_run(void)
|
||||
{
|
||||
struct arp_record *arp;
|
||||
|
||||
/* Notify any which went, then move to free list */
|
||||
if (old)
|
||||
{
|
||||
#ifdef HAVE_SCRIPT
|
||||
if (option_bool(OPT_SCRIPT_ARP))
|
||||
queue_arp(ACTION_ARP_DEL, old->hwaddr, old->hwlen, old->family, &old->addr);
|
||||
#endif
|
||||
arp = old;
|
||||
old = arp->next;
|
||||
arp->next = freelist;
|
||||
freelist = arp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (arp = arps; arp; arp = arp->next)
|
||||
if (arp->status == ARP_NEW)
|
||||
{
|
||||
#ifdef HAVE_SCRIPT
|
||||
if (option_bool(OPT_SCRIPT_ARP))
|
||||
queue_arp(ACTION_ARP, arp->hwaddr, arp->hwlen, arp->family, &arp->addr);
|
||||
#endif
|
||||
arp->status = ARP_FOUND;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
894
src/auth.c
Normal file
894
src/auth.c
Normal file
@@ -0,0 +1,894 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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_addrlist(struct addrlist *list, int flag, struct all_addr *addr_u)
|
||||
{
|
||||
do {
|
||||
if (!(list->flags & ADDRLIST_IPV6))
|
||||
{
|
||||
struct in_addr netmask, addr = addr_u->addr.addr4;
|
||||
|
||||
if (!(flag & F_IPV4))
|
||||
continue;
|
||||
|
||||
netmask.s_addr = htonl(~(in_addr_t)0 << (32 - list->prefixlen));
|
||||
|
||||
if (is_same_net(addr, list->addr.addr.addr4, netmask))
|
||||
return list;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (is_same_net6(&(addr_u->addr.addr6), &list->addr.addr.addr6, list->prefixlen))
|
||||
return list;
|
||||
#endif
|
||||
|
||||
} while ((list = list->next));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct addrlist *find_subnet(struct auth_zone *zone, int flag, struct all_addr *addr_u)
|
||||
{
|
||||
if (!zone->subnet)
|
||||
return NULL;
|
||||
|
||||
return find_addrlist(zone->subnet, flag, addr_u);
|
||||
}
|
||||
|
||||
static struct addrlist *find_exclude(struct auth_zone *zone, int flag, struct all_addr *addr_u)
|
||||
{
|
||||
if (!zone->exclude)
|
||||
return NULL;
|
||||
|
||||
return find_addrlist(zone->exclude, flag, addr_u);
|
||||
}
|
||||
|
||||
static int filter_zone(struct auth_zone *zone, int flag, struct all_addr *addr_u)
|
||||
{
|
||||
if (find_exclude(zone, flag, addr_u))
|
||||
return 0;
|
||||
|
||||
/* No subnets 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, int do_bit, int have_pseudoheader)
|
||||
{
|
||||
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, *candidate;
|
||||
unsigned int wclen;
|
||||
|
||||
/* Clear buffer beyond request to avoid risk of
|
||||
information disclosure. */
|
||||
memset(((char *)header) + qlen, 0,
|
||||
(limit - ((char *)header)) - qlen);
|
||||
|
||||
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;
|
||||
int cname_wildcard = 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 || qtype == T_SOA || qtype == T_NS) &&
|
||||
(flag = in_arpa_name_2_addr(name, &addr)) &&
|
||||
!local_query)
|
||||
{
|
||||
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
||||
if ((subnet = find_subnet(zone, flag, &addr)))
|
||||
break;
|
||||
|
||||
if (!zone)
|
||||
{
|
||||
auth = 0;
|
||||
continue;
|
||||
}
|
||||
else if (qtype == T_SOA)
|
||||
soa = 1, found = 1;
|
||||
else if (qtype == T_NS)
|
||||
ns = 1, found = 1;
|
||||
}
|
||||
|
||||
if (qtype == T_PTR && flag)
|
||||
{
|
||||
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 (local_query || 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 */
|
||||
if (zone)
|
||||
{
|
||||
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) && (local_query || 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:
|
||||
if (found)
|
||||
/* NS and SOA .arpa requests have set found above. */
|
||||
cut = NULL;
|
||||
else
|
||||
{
|
||||
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)))
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
if (addrlist->flags & ADDRLIST_REVONLY)
|
||||
continue;
|
||||
#endif
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
peer_addr->in6.sin6_scope_id = 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)));
|
||||
}
|
||||
|
||||
/* Only supply CNAME if no record for any type is known. */
|
||||
if (nxdomain)
|
||||
{
|
||||
/* Check for possible wildcard match against *.domain
|
||||
return length of match, to get longest.
|
||||
Note that if return length of wildcard section, so
|
||||
we match b.simon to _both_ *.simon and b.simon
|
||||
but return a longer (better) match to b.simon.
|
||||
*/
|
||||
for (wclen = 0, candidate = NULL, a = daemon->cnames; a; a = a->next)
|
||||
if (a->alias[0] == '*')
|
||||
{
|
||||
char *test = name;
|
||||
|
||||
while ((test = strchr(test+1, '.')))
|
||||
{
|
||||
if (hostname_isequal(test, &(a->alias[1])))
|
||||
{
|
||||
if (strlen(test) > wclen && !cname_wildcard)
|
||||
{
|
||||
wclen = strlen(test);
|
||||
candidate = a;
|
||||
cname_wildcard = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (hostname_isequal(a->alias, name) && strlen(a->alias) > wclen)
|
||||
{
|
||||
/* Simple case, no wildcard */
|
||||
wclen = strlen(a->alias);
|
||||
candidate = a;
|
||||
}
|
||||
|
||||
if (candidate)
|
||||
{
|
||||
log_query(F_CONFIG | F_CNAME, name, NULL, NULL);
|
||||
strcpy(name, candidate->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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* authoritative */
|
||||
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);
|
||||
|
||||
/* Advertise our packet size limit in our reply */
|
||||
if (have_pseudoheader)
|
||||
return add_pseudoheader(header, ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
||||
|
||||
return ansp - (unsigned char *)header;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
151
src/blockdata.c
Normal file
151
src/blockdata.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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 (n > 0 && 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;
|
||||
|
||||
/* Note that daemon->cachesize is enforced to have non-zero size if OPT_DNSSEC_VALID is set */
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
blockdata_expand((daemon->cachesize * 100) / sizeof(struct blockdata));
|
||||
}
|
||||
|
||||
void blockdata_report(void)
|
||||
{
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
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
|
||||
190
src/bpf.c
190
src/bpf.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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,11 +19,21 @@
|
||||
#if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
|
||||
#include <ifaddrs.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
#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) \
|
||||
@@ -32,6 +42,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];
|
||||
@@ -82,13 +99,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 errsave, fd = -1, ret = 0;
|
||||
|
||||
if (family == AF_UNSPEC)
|
||||
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||
@@ -104,22 +121,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
|
||||
@@ -129,11 +159,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)
|
||||
@@ -144,12 +213,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)
|
||||
{
|
||||
@@ -166,13 +237,15 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
errsav = errno;
|
||||
freeifaddrs(head);
|
||||
errno = errsav;
|
||||
errsave = errno;
|
||||
freeifaddrs(head);
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
errno = errsave;
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
#endif /* defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK) */
|
||||
|
||||
|
||||
#if defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP)
|
||||
@@ -288,9 +361,90 @@ void send_via_bpf(struct dhcp_packet *mess, size_t len,
|
||||
iov[3].iov_base = mess;
|
||||
iov[3].iov_len = len;
|
||||
|
||||
while (writev(daemon->dhcp_raw_fd, iov, 4) == -1 && retry_send());
|
||||
while (retry_send(writev(daemon->dhcp_raw_fd, iov, 4)));
|
||||
}
|
||||
|
||||
#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(void)
|
||||
{
|
||||
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;
|
||||
queue_event(EVENT_NEWADDR);
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
queue_event(EVENT_NEWADDR);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_BSD_NETWORK */
|
||||
|
||||
|
||||
|
||||
889
src/cache.c
889
src/cache.c
File diff suppressed because it is too large
Load Diff
181
src/config.h
181
src/config.h
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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
|
||||
@@ -17,33 +17,45 @@
|
||||
#define FTABSIZ 150 /* max number of outstanding requests (default) */
|
||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
|
||||
#define TCP_MAX_QUERIES 100 /* Maximum number of queries per incoming TCP connection */
|
||||
#define TCP_BACKLOG 32 /* kernel backlog limit for TCP connections */
|
||||
#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 SAFE_PKTSZ 1280 /* "go anywhere" UDP packet size */
|
||||
#define KEYBLOCK_LEN 40 /* choose to minimise 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 */
|
||||
#define SERVERS_LOGGED 30 /* Only log this many servers when logging state */
|
||||
#define LOCALS_LOGGED 8 /* Only log this many local addresses when logging state */
|
||||
#define RANDOM_SOCKS 64 /* max simultaneous random ports */
|
||||
#define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */
|
||||
#define CACHESIZ 150 /* default cache size */
|
||||
#define TTL_FLOOR_LIMIT 3600 /* don't allow --min-cache-ttl to raise TTL above this under any circumstances */
|
||||
#define MAXLEASES 1000 /* maximum number of DHCP leases */
|
||||
#define PING_WAIT 3 /* wait for ping address-in-use test */
|
||||
#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 RUNFILE "/var/run/dnsmasq.pid"
|
||||
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
||||
#define CHUSER "nobody"
|
||||
#define CHGRP "dip"
|
||||
#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" /* DBUS interface specifics */
|
||||
#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 */
|
||||
#define LOOP_TEST_DOMAIN "test" /* domain for loop testing, "test" is reserved by RFC 2606 and won't therefore clash */
|
||||
#define LOOP_TEST_TYPE T_TXT
|
||||
|
||||
/* compile-time options: uncomment below to enable or do eg.
|
||||
make COPTS=-DHAVE_BROKEN_RTC
|
||||
|
||||
@@ -82,28 +94,57 @@ HAVE_DBUS
|
||||
servers via DBus.
|
||||
|
||||
HAVE_IDN
|
||||
define this if you want international domain name support.
|
||||
define this if you want international domain name 2003 support.
|
||||
NOTE: for backwards compatibility, IDN support is automatically
|
||||
included when internationalisation support is built, using the
|
||||
*-i18n makefile targets, even if HAVE_IDN is not explicitly set.
|
||||
|
||||
HAVE_LIBIDN2
|
||||
define this if you want international domain name 2008 support.
|
||||
|
||||
HAVE_CONNTRACK
|
||||
define this to include code which propogates conntrack marks from
|
||||
define this to include code which propagates conntrack marks from
|
||||
incoming DNS queries to the corresponding upstream queries. This adds
|
||||
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.
|
||||
|
||||
HAVE_DNSSEC
|
||||
include DNSSEC validator.
|
||||
|
||||
HAVE_LOOP
|
||||
include functionality to probe for and remove DNS forwarding loops.
|
||||
|
||||
HAVE_INOTIFY
|
||||
use the Linux inotify facility to efficiently re-read configuration files.
|
||||
|
||||
NO_ID
|
||||
Don't report *.bind CHAOS info to clients, forward such requests upstream instead.
|
||||
NO_IPV6
|
||||
NO_TFTP
|
||||
NO_DHCP
|
||||
NO_DHCP6
|
||||
NO_SCRIPT
|
||||
NO_LARGEFILE
|
||||
these are avilable to explictly disable compile time options which would
|
||||
NO_AUTH
|
||||
NO_INOTIFY
|
||||
these are available to explicitly 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
|
||||
with something like "make COPTS=-DNO_SCRIPT" will do the trick.
|
||||
|
||||
NO_NETTLE_ECC
|
||||
Don't include the ECDSA cypher in DNSSEC validation. Needed for older Nettle versions.
|
||||
NO_GMP
|
||||
Don't use and link against libgmp, Useful if nettle is built with --enable-mini-gmp.
|
||||
|
||||
LEASEFILE
|
||||
CONFFILE
|
||||
RESOLVFILE
|
||||
@@ -112,6 +153,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 */
|
||||
@@ -120,12 +166,23 @@ RESOLVFILE
|
||||
#define HAVE_DHCP6
|
||||
#define HAVE_TFTP
|
||||
#define HAVE_SCRIPT
|
||||
#define HAVE_AUTH
|
||||
#define HAVE_IPSET
|
||||
#define HAVE_LOOP
|
||||
|
||||
/* 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_LIBIDN2 */
|
||||
/* #define HAVE_CONNTRACK */
|
||||
|
||||
/* #define HAVE_DNSSEC */
|
||||
|
||||
|
||||
/* Default locations for important system files. */
|
||||
@@ -158,7 +215,13 @@ RESOLVFILE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef RUNFILE
|
||||
# if defined(__ANDROID__)
|
||||
# define RUNFILE "/data/dnsmasq.pid"
|
||||
# else
|
||||
# define RUNFILE "/var/run/dnsmasq.pid"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* platform dependent options: these are determined automatically below
|
||||
|
||||
@@ -170,19 +233,14 @@ 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)
|
||||
*/
|
||||
|
||||
/* Must preceed __linux__ since uClinux defines __linux__ too. */
|
||||
/* Must precede __linux__ since uClinux defines __linux__ too. */
|
||||
#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
|
||||
@@ -196,7 +254,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
|
||||
@@ -211,7 +268,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__) || \
|
||||
@@ -219,33 +275,31 @@ HAVE_SOCKADDR_SA_LEN
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD_kernel__)
|
||||
#define HAVE_BSD_NETWORK
|
||||
/* Later verions of FreeBSD have getopt_long() */
|
||||
/* Later versions of FreeBSD have getopt_long() */
|
||||
#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
|
||||
#define NO_IPSET
|
||||
|
||||
#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
|
||||
|
||||
@@ -258,12 +312,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
|
||||
|
||||
|
||||
@@ -292,7 +346,7 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#define HAVE_DHCP
|
||||
#endif
|
||||
|
||||
#if defined(NO_SCRIPT) || !defined(HAVE_DHCP) || defined(NO_FORK)
|
||||
#if defined(NO_SCRIPT) || defined(NO_FORK)
|
||||
#undef HAVE_SCRIPT
|
||||
#undef HAVE_LUASCRIPT
|
||||
#endif
|
||||
@@ -302,9 +356,24 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#define HAVE_SCRIPT
|
||||
#endif
|
||||
|
||||
#ifdef NO_AUTH
|
||||
#undef HAVE_AUTH
|
||||
#endif
|
||||
|
||||
#if defined(NO_IPSET)
|
||||
#undef HAVE_IPSET
|
||||
#endif
|
||||
|
||||
#ifdef NO_LOOP
|
||||
#undef HAVE_LOOP
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_LINUX_NETWORK) && !defined(NO_INOTIFY)
|
||||
#define HAVE_INOTIFY
|
||||
#endif
|
||||
|
||||
/* Define a string indicating which options are in use.
|
||||
DNSMASQP_COMPILE_OPTS is only defined in dnsmasq.c */
|
||||
DNSMASQ_COMPILE_OPTS is only defined in dnsmasq.c */
|
||||
|
||||
#ifdef DNSMASQ_COMPILE_OPTS
|
||||
|
||||
@@ -335,6 +404,10 @@ static char *compile_opts =
|
||||
"no-"
|
||||
#endif
|
||||
"IDN "
|
||||
#if !defined(HAVE_LIBIDN2)
|
||||
"no-"
|
||||
#endif
|
||||
"IDN2 "
|
||||
#ifndef HAVE_DHCP
|
||||
"no-"
|
||||
#endif
|
||||
@@ -344,14 +417,14 @@ static char *compile_opts =
|
||||
"no-"
|
||||
# endif
|
||||
"DHCPv6 "
|
||||
# if !defined(HAVE_SCRIPT)
|
||||
#endif
|
||||
#if !defined(HAVE_SCRIPT)
|
||||
"no-scripts "
|
||||
# else
|
||||
# if !defined(HAVE_LUASCRIPT)
|
||||
"no-"
|
||||
# endif
|
||||
"Lua "
|
||||
#else
|
||||
# if !defined(HAVE_LUASCRIPT)
|
||||
"no-"
|
||||
# endif
|
||||
"Lua "
|
||||
#endif
|
||||
#ifndef HAVE_TFTP
|
||||
"no-"
|
||||
@@ -360,7 +433,31 @@ 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 "
|
||||
#ifdef NO_ID
|
||||
"no-ID "
|
||||
#endif
|
||||
#ifndef HAVE_LOOP
|
||||
"no-"
|
||||
#endif
|
||||
"loop-detect "
|
||||
#ifndef HAVE_INOTIFY
|
||||
"no-"
|
||||
#endif
|
||||
"inotify";
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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
|
||||
|
||||
650
src/dbus.c
650
src/dbus.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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,7 @@
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
|
||||
const char* introspection_xml =
|
||||
const char* introspection_xml_template =
|
||||
"<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
|
||||
"\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
|
||||
"<node name=\"" DNSMASQ_PATH "\">\n"
|
||||
@@ -29,15 +29,32 @@ const char* introspection_xml =
|
||||
" <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
|
||||
" </method>\n"
|
||||
" </interface>\n"
|
||||
" <interface name=\"" DNSMASQ_SERVICE "\">\n"
|
||||
" <interface name=\"%s\">\n"
|
||||
" <method name=\"ClearCache\">\n"
|
||||
" </method>\n"
|
||||
" <method name=\"GetVersion\">\n"
|
||||
" <arg name=\"version\" direction=\"out\" type=\"s\"/>\n"
|
||||
" </method>\n"
|
||||
#ifdef HAVE_LOOP
|
||||
" <method name=\"GetLoopServers\">\n"
|
||||
" <arg name=\"server\" direction=\"out\" type=\"as\"/>\n"
|
||||
" </method>\n"
|
||||
#endif
|
||||
" <method name=\"SetServers\">\n"
|
||||
" <arg name=\"servers\" direction=\"in\" type=\"av\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"SetDomainServers\">\n"
|
||||
" <arg name=\"servers\" direction=\"in\" type=\"as\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"SetServersEx\">\n"
|
||||
" <arg name=\"servers\" direction=\"in\" type=\"aas\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"SetFilterWin2KOption\">\n"
|
||||
" <arg name=\"filterwin2k\" direction=\"in\" type=\"b\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"SetBogusPrivOption\">\n"
|
||||
" <arg name=\"boguspriv\" direction=\"in\" type=\"b\"/>\n"
|
||||
" </method>\n"
|
||||
" <signal name=\"DhcpLeaseAdded\">\n"
|
||||
" <arg name=\"ipaddr\" type=\"s\"/>\n"
|
||||
" <arg name=\"hwaddr\" type=\"s\"/>\n"
|
||||
@@ -53,9 +70,26 @@ const char* introspection_xml =
|
||||
" <arg name=\"hwaddr\" type=\"s\"/>\n"
|
||||
" <arg name=\"hostname\" type=\"s\"/>\n"
|
||||
" </signal>\n"
|
||||
#ifdef HAVE_DHCP
|
||||
" <method name=\"AddDhcpLease\">\n"
|
||||
" <arg name=\"ipaddr\" type=\"s\"/>\n"
|
||||
" <arg name=\"hwaddr\" type=\"s\"/>\n"
|
||||
" <arg name=\"hostname\" type=\"ay\"/>\n"
|
||||
" <arg name=\"clid\" type=\"ay\"/>\n"
|
||||
" <arg name=\"lease_duration\" type=\"u\"/>\n"
|
||||
" <arg name=\"ia_id\" type=\"u\"/>\n"
|
||||
" <arg name=\"is_temporary\" type=\"b\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"DeleteDhcpLease\">\n"
|
||||
" <arg name=\"ipaddr\" type=\"s\"/>\n"
|
||||
" <arg name=\"success\" type=\"b\" direction=\"out\"/>\n"
|
||||
" </method>\n"
|
||||
#endif
|
||||
" </interface>\n"
|
||||
"</node>\n";
|
||||
|
||||
static char *introspection_xml = NULL;
|
||||
|
||||
struct watch {
|
||||
DBusWatch *watch;
|
||||
struct watch *next;
|
||||
@@ -83,33 +117,32 @@ 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 dbus_read_servers(DBusMessage *message)
|
||||
{
|
||||
struct server *serv, *tmp, **up;
|
||||
DBusMessageIter iter;
|
||||
union mysockaddr addr, source_addr;
|
||||
char *domain;
|
||||
|
||||
dbus_message_iter_init(message, &iter);
|
||||
|
||||
/* mark everything from DBUS */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (serv->flags & SERV_FROM_DBUS)
|
||||
serv->flags |= SERV_MARK;
|
||||
|
||||
mark_servers(SERV_FROM_DBUS);
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -143,13 +176,16 @@ static void dbus_read_servers(DBusMessage *message)
|
||||
dbus_message_iter_get_basic(&iter, &p[i]);
|
||||
dbus_message_iter_next (&iter);
|
||||
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BYTE)
|
||||
break;
|
||||
{
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef HAVE_IPV6
|
||||
my_syslog(LOG_WARNING, _("attempt to set an IPv6 server address via DBus - no IPv6 support"));
|
||||
#else
|
||||
if (i == sizeof(struct in6_addr)-1)
|
||||
if (i == sizeof(struct in6_addr))
|
||||
{
|
||||
memcpy(&addr.in6.sin6_addr, p, sizeof(struct in6_addr));
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
@@ -169,6 +205,7 @@ static void dbus_read_servers(DBusMessage *message)
|
||||
/* At the end */
|
||||
break;
|
||||
|
||||
/* process each domain */
|
||||
do {
|
||||
if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING)
|
||||
{
|
||||
@@ -179,123 +216,499 @@ static void dbus_read_servers(DBusMessage *message)
|
||||
domain = NULL;
|
||||
|
||||
if (!skip)
|
||||
{
|
||||
/* See if this is already there, and unmark */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if ((serv->flags & SERV_FROM_DBUS) &&
|
||||
(serv->flags & SERV_MARK))
|
||||
{
|
||||
if (!(serv->flags & SERV_HAS_DOMAIN) && !domain)
|
||||
{
|
||||
serv->flags &= ~SERV_MARK;
|
||||
break;
|
||||
}
|
||||
if ((serv->flags & SERV_HAS_DOMAIN) &&
|
||||
domain &&
|
||||
hostname_isequal(domain, serv->domain))
|
||||
{
|
||||
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);
|
||||
|
||||
if (domain && !serv->domain)
|
||||
{
|
||||
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 (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;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING);
|
||||
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. */
|
||||
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
|
||||
cleanup_servers();
|
||||
}
|
||||
|
||||
#ifdef HAVE_LOOP
|
||||
static DBusMessage *dbus_reply_server_loop(DBusMessage *message)
|
||||
{
|
||||
DBusMessageIter args, args_iter;
|
||||
struct server *serv;
|
||||
DBusMessage *reply = dbus_message_new_method_return(message);
|
||||
|
||||
dbus_message_iter_init_append (reply, &args);
|
||||
dbus_message_iter_open_container (&args, DBUS_TYPE_ARRAY,DBUS_TYPE_STRING_AS_STRING, &args_iter);
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (serv->flags & SERV_LOOP)
|
||||
{
|
||||
prettyprint_addr(&serv->addr, daemon->addrbuff);
|
||||
dbus_message_iter_append_basic (&args_iter, DBUS_TYPE_STRING, &daemon->addrbuff);
|
||||
}
|
||||
|
||||
dbus_message_iter_close_container (&args, &args_iter);
|
||||
|
||||
return reply;
|
||||
}
|
||||
#endif
|
||||
|
||||
static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
{
|
||||
DBusMessageIter iter, array_iter, string_iter;
|
||||
DBusMessage *error = NULL;
|
||||
const char *addr_err;
|
||||
char *dup = NULL;
|
||||
|
||||
if (!dbus_message_iter_init(message, &iter))
|
||||
{
|
||||
tmp = serv->next;
|
||||
if (serv->flags & SERV_MARK)
|
||||
{
|
||||
server_gone(serv);
|
||||
*up = serv->next;
|
||||
free(serv);
|
||||
}
|
||||
else
|
||||
up = &serv->next;
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Failed to initialize dbus message iter");
|
||||
}
|
||||
|
||||
/* check that the message contains an array of arrays */
|
||||
if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
|
||||
(dbus_message_iter_get_element_type(&iter) != (strings ? DBUS_TYPE_STRING : DBUS_TYPE_ARRAY)))
|
||||
{
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
strings ? "Expected array of string" : "Expected array of string arrays");
|
||||
}
|
||||
|
||||
mark_servers(SERV_FROM_DBUS);
|
||||
|
||||
/* array_iter points to each "as" element in the outer array */
|
||||
dbus_message_iter_recurse(&iter, &array_iter);
|
||||
while (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_INVALID)
|
||||
{
|
||||
const char *str = NULL;
|
||||
union mysockaddr addr, source_addr;
|
||||
int flags = 0;
|
||||
char interface[IF_NAMESIZE];
|
||||
char *str_addr, *str_domain = NULL;
|
||||
|
||||
if (strings)
|
||||
{
|
||||
dbus_message_iter_get_basic(&array_iter, &str);
|
||||
if (!str || !strlen (str))
|
||||
{
|
||||
error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Empty string");
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
if ((str_addr = strrchr(str, '/')))
|
||||
str = str_addr+1;
|
||||
|
||||
if ((str_addr = strrchr(str_domain, '/')))
|
||||
{
|
||||
if (*str_domain != '/' || str_addr == str_domain)
|
||||
{
|
||||
error = dbus_message_new_error_printf(message,
|
||||
DBUS_ERROR_INVALID_ARGS,
|
||||
"No domain terminator '%s'",
|
||||
str);
|
||||
break;
|
||||
}
|
||||
*str_addr++ = 0;
|
||||
str_domain++;
|
||||
}
|
||||
else
|
||||
{
|
||||
str_addr = str_domain;
|
||||
str_domain = NULL;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* check the types of the struct and its elements */
|
||||
if ((dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY) ||
|
||||
(dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_STRING))
|
||||
{
|
||||
error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Expected inner array of strings");
|
||||
break;
|
||||
}
|
||||
|
||||
/* string_iter points to each "s" element in the inner array */
|
||||
dbus_message_iter_recurse(&array_iter, &string_iter);
|
||||
if (dbus_message_iter_get_arg_type(&string_iter) != DBUS_TYPE_STRING)
|
||||
{
|
||||
/* no IP address given */
|
||||
error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Expected IP address");
|
||||
break;
|
||||
}
|
||||
|
||||
dbus_message_iter_get_basic(&string_iter, &str);
|
||||
if (!str || !strlen (str))
|
||||
{
|
||||
error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Empty IP address");
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
memset(&source_addr, 0, sizeof(source_addr));
|
||||
memset(&interface, 0, sizeof(interface));
|
||||
|
||||
/* parse the IP address */
|
||||
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;
|
||||
|
||||
do {
|
||||
if (str_domain)
|
||||
{
|
||||
if ((p = strchr(str_domain, '/')))
|
||||
*p++ = 0;
|
||||
}
|
||||
else
|
||||
p = NULL;
|
||||
|
||||
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain);
|
||||
} while ((str_domain = p));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* jump past the address to the domain list (if any) */
|
||||
dbus_message_iter_next (&string_iter);
|
||||
|
||||
/* parse domains and add each server/domain pair to the list */
|
||||
do {
|
||||
str = NULL;
|
||||
if (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING)
|
||||
dbus_message_iter_get_basic(&string_iter, &str);
|
||||
dbus_message_iter_next (&string_iter);
|
||||
|
||||
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str);
|
||||
} while (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING);
|
||||
}
|
||||
|
||||
/* jump to next element in outer array */
|
||||
dbus_message_iter_next(&array_iter);
|
||||
}
|
||||
|
||||
cleanup_servers();
|
||||
|
||||
if (dup)
|
||||
free(dup);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static DBusMessage *dbus_set_bool(DBusMessage *message, int flag, char *name)
|
||||
{
|
||||
DBusMessageIter iter;
|
||||
dbus_bool_t enabled;
|
||||
|
||||
if (!dbus_message_iter_init(message, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, "Expected boolean argument");
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &enabled);
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
my_syslog(LOG_INFO, _("Enabling --%s option from D-Bus"), name);
|
||||
set_option_bool(flag);
|
||||
}
|
||||
else
|
||||
{
|
||||
my_syslog(LOG_INFO, _("Disabling --%s option from D-Bus"), name);
|
||||
reset_option_bool(flag);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
static DBusMessage *dbus_add_lease(DBusMessage* message)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
const char *ipaddr, *hwaddr, *hostname, *tmp;
|
||||
const unsigned char* clid;
|
||||
int clid_len, hostname_len, hw_len, hw_type;
|
||||
dbus_uint32_t expires, ia_id;
|
||||
dbus_bool_t is_temporary;
|
||||
struct all_addr addr;
|
||||
time_t now = dnsmasq_time();
|
||||
unsigned char dhcp_chaddr[DHCP_CHADDR_MAX];
|
||||
|
||||
DBusMessageIter iter, array_iter;
|
||||
if (!dbus_message_iter_init(message, &iter))
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Failed to initialize dbus message iter");
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Expected string as first argument");
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &ipaddr);
|
||||
dbus_message_iter_next(&iter);
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Expected string as second argument");
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &hwaddr);
|
||||
dbus_message_iter_next(&iter);
|
||||
|
||||
if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
|
||||
(dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE))
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Expected byte array as third argument");
|
||||
|
||||
dbus_message_iter_recurse(&iter, &array_iter);
|
||||
dbus_message_iter_get_fixed_array(&array_iter, &hostname, &hostname_len);
|
||||
tmp = memchr(hostname, '\0', hostname_len);
|
||||
if (tmp)
|
||||
{
|
||||
if (tmp == &hostname[hostname_len - 1])
|
||||
hostname_len--;
|
||||
else
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Hostname contains an embedded NUL character");
|
||||
}
|
||||
dbus_message_iter_next(&iter);
|
||||
|
||||
if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
|
||||
(dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE))
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Expected byte array as fourth argument");
|
||||
|
||||
dbus_message_iter_recurse(&iter, &array_iter);
|
||||
dbus_message_iter_get_fixed_array(&array_iter, &clid, &clid_len);
|
||||
dbus_message_iter_next(&iter);
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Expected uint32 as fifth argument");
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &expires);
|
||||
dbus_message_iter_next(&iter);
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Expected uint32 as sixth argument");
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &ia_id);
|
||||
dbus_message_iter_next(&iter);
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Expected uint32 as sixth argument");
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &is_temporary);
|
||||
|
||||
if (inet_pton(AF_INET, ipaddr, &addr.addr.addr4))
|
||||
{
|
||||
if (ia_id != 0 || is_temporary)
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"ia_id and is_temporary must be zero for IPv4 lease");
|
||||
|
||||
if (!(lease = lease_find_by_addr(addr.addr.addr4)))
|
||||
lease = lease4_allocate(addr.addr.addr4);
|
||||
}
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (inet_pton(AF_INET6, ipaddr, &addr.addr.addr6))
|
||||
{
|
||||
if (!(lease = lease6_find_by_addr(&addr.addr.addr6, 128, 0)))
|
||||
lease = lease6_allocate(&addr.addr.addr6,
|
||||
is_temporary ? LEASE_TA : LEASE_NA);
|
||||
lease_set_iaid(lease, ia_id);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid IP address '%s'", ipaddr);
|
||||
|
||||
hw_len = parse_hex((char*)hwaddr, dhcp_chaddr, DHCP_CHADDR_MAX, NULL, &hw_type);
|
||||
if (hw_type == 0 && hw_len != 0)
|
||||
hw_type = ARPHRD_ETHER;
|
||||
|
||||
lease_set_hwaddr(lease, dhcp_chaddr, clid, hw_len, hw_type,
|
||||
clid_len, now, 0);
|
||||
lease_set_expires(lease, expires, now);
|
||||
if (hostname_len != 0)
|
||||
lease_set_hostname(lease, hostname, 0, get_domain(lease->addr), NULL);
|
||||
|
||||
lease_update_file(now);
|
||||
lease_update_dns(0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static DBusMessage *dbus_del_lease(DBusMessage* message)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
DBusMessageIter iter;
|
||||
const char *ipaddr;
|
||||
DBusMessage *reply;
|
||||
struct all_addr addr;
|
||||
dbus_bool_t ret = 1;
|
||||
time_t now = dnsmasq_time();
|
||||
|
||||
if (!dbus_message_iter_init(message, &iter))
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Failed to initialize dbus message iter");
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Expected string as first argument");
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &ipaddr);
|
||||
|
||||
if (inet_pton(AF_INET, ipaddr, &addr.addr.addr4))
|
||||
lease = lease_find_by_addr(addr.addr.addr4);
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (inet_pton(AF_INET6, ipaddr, &addr.addr.addr6))
|
||||
lease = lease6_find_by_addr(&addr.addr.addr6, 128, 0);
|
||||
#endif
|
||||
else
|
||||
return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid IP address '%s'", ipaddr);
|
||||
|
||||
if (lease)
|
||||
{
|
||||
lease_prune(lease, now);
|
||||
lease_update_file(now);
|
||||
lease_update_dns(0);
|
||||
}
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
if ((reply = dbus_message_new_method_return(message)))
|
||||
dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &ret,
|
||||
DBUS_TYPE_INVALID);
|
||||
|
||||
|
||||
return reply;
|
||||
}
|
||||
#endif
|
||||
|
||||
DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
DBusMessage *message,
|
||||
void *user_data)
|
||||
{
|
||||
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"))
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(message);
|
||||
|
||||
dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection_xml, DBUS_TYPE_INVALID);
|
||||
dbus_connection_send (connection, reply, NULL);
|
||||
dbus_message_unref (reply);
|
||||
/* string length: "%s" provides space for termination zero */
|
||||
if (!introspection_xml &&
|
||||
(introspection_xml = whine_malloc(strlen(introspection_xml_template) + strlen(daemon->dbus_name))))
|
||||
sprintf(introspection_xml, introspection_xml_template, daemon->dbus_name);
|
||||
|
||||
if (introspection_xml)
|
||||
{
|
||||
reply = dbus_message_new_method_return(message);
|
||||
dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection_xml, DBUS_TYPE_INVALID);
|
||||
}
|
||||
}
|
||||
else if (strcmp(method, "GetVersion") == 0)
|
||||
{
|
||||
char *v = VERSION;
|
||||
DBusMessage *reply = dbus_message_new_method_return(message);
|
||||
reply = dbus_message_new_method_return(message);
|
||||
|
||||
dbus_message_append_args(reply, DBUS_TYPE_STRING, &v, DBUS_TYPE_INVALID);
|
||||
dbus_connection_send (connection, reply, NULL);
|
||||
dbus_message_unref (reply);
|
||||
}
|
||||
#ifdef HAVE_LOOP
|
||||
else if (strcmp(method, "GetLoopServers") == 0)
|
||||
{
|
||||
reply = dbus_reply_server_loop(message);
|
||||
}
|
||||
#endif
|
||||
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);
|
||||
new_servers = 1;
|
||||
}
|
||||
else if (strcmp(method, "SetDomainServers") == 0)
|
||||
{
|
||||
reply = dbus_read_servers_ex(message, 1);
|
||||
new_servers = 1;
|
||||
}
|
||||
else if (strcmp(method, "SetFilterWin2KOption") == 0)
|
||||
{
|
||||
reply = dbus_set_bool(message, OPT_FILTER, "filterwin2k");
|
||||
}
|
||||
else if (strcmp(method, "SetBogusPrivOption") == 0)
|
||||
{
|
||||
reply = dbus_set_bool(message, OPT_BOGUSPRIV, "bogus-priv");
|
||||
}
|
||||
#ifdef HAVE_DHCP
|
||||
else if (strcmp(method, "AddDhcpLease") == 0)
|
||||
{
|
||||
reply = dbus_add_lease(message);
|
||||
}
|
||||
else if (strcmp(method, "DeleteDhcpLease") == 0)
|
||||
{
|
||||
reply = dbus_del_lease(message);
|
||||
}
|
||||
#endif
|
||||
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 */
|
||||
|
||||
/* If no reply or no error, return nothing */
|
||||
if (!reply)
|
||||
reply = dbus_message_new_method_return(message);
|
||||
|
||||
if (reply)
|
||||
{
|
||||
dbus_connection_send (connection, reply, NULL);
|
||||
dbus_message_unref (reply);
|
||||
}
|
||||
|
||||
return (DBUS_HANDLER_RESULT_HANDLED);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -315,7 +728,7 @@ char *dbus_init(void)
|
||||
dbus_connection_set_watch_functions(connection, add_watch, remove_watch,
|
||||
NULL, NULL, NULL);
|
||||
dbus_error_init (&dbus_error);
|
||||
dbus_bus_request_name (connection, DNSMASQ_SERVICE, 0, &dbus_error);
|
||||
dbus_bus_request_name (connection, daemon->dbus_name, 0, &dbus_error);
|
||||
if (dbus_error_is_set (&dbus_error))
|
||||
return (char *)dbus_error.message;
|
||||
|
||||
@@ -325,7 +738,7 @@ char *dbus_init(void)
|
||||
|
||||
daemon->dbus = connection;
|
||||
|
||||
if ((message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, "Up")))
|
||||
if ((message = dbus_message_new_signal(DNSMASQ_PATH, daemon->dbus_name, "Up")))
|
||||
{
|
||||
dbus_connection_send(connection, message, NULL);
|
||||
dbus_message_unref(message);
|
||||
@@ -335,8 +748,7 @@ char *dbus_init(void)
|
||||
}
|
||||
|
||||
|
||||
void set_dbus_listeners(int *maxfdp,
|
||||
fd_set *rset, fd_set *wset, fd_set *eset)
|
||||
void set_dbus_listeners(void)
|
||||
{
|
||||
struct watch *w;
|
||||
|
||||
@@ -346,19 +758,17 @@ void set_dbus_listeners(int *maxfdp,
|
||||
unsigned int flags = dbus_watch_get_flags(w->watch);
|
||||
int fd = dbus_watch_get_unix_fd(w->watch);
|
||||
|
||||
bump_maxfd(fd, maxfdp);
|
||||
|
||||
if (flags & DBUS_WATCH_READABLE)
|
||||
FD_SET(fd, rset);
|
||||
poll_listen(fd, POLLIN);
|
||||
|
||||
if (flags & DBUS_WATCH_WRITABLE)
|
||||
FD_SET(fd, wset);
|
||||
poll_listen(fd, POLLOUT);
|
||||
|
||||
FD_SET(fd, eset);
|
||||
poll_listen(fd, POLLERR);
|
||||
}
|
||||
}
|
||||
|
||||
void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset)
|
||||
void check_dbus_listeners()
|
||||
{
|
||||
DBusConnection *connection = (DBusConnection *)daemon->dbus;
|
||||
struct watch *w;
|
||||
@@ -369,13 +779,13 @@ void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset)
|
||||
unsigned int flags = 0;
|
||||
int fd = dbus_watch_get_unix_fd(w->watch);
|
||||
|
||||
if (FD_ISSET(fd, rset))
|
||||
if (poll_check(fd, POLLIN))
|
||||
flags |= DBUS_WATCH_READABLE;
|
||||
|
||||
if (FD_ISSET(fd, wset))
|
||||
if (poll_check(fd, POLLOUT))
|
||||
flags |= DBUS_WATCH_WRITABLE;
|
||||
|
||||
if (FD_ISSET(fd, eset))
|
||||
if (poll_check(fd, POLLERR))
|
||||
flags |= DBUS_WATCH_ERROR;
|
||||
|
||||
if (flags != 0)
|
||||
@@ -410,7 +820,7 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
|
||||
if (lease->flags & (LEASE_TA | LEASE_NA))
|
||||
{
|
||||
print_mac(mac, lease->clid, lease->clid_len);
|
||||
inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN);
|
||||
inet_ntop(AF_INET6, &lease->addr6, daemon->addrbuff, ADDRSTRLEN);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@@ -430,7 +840,7 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
|
||||
else
|
||||
return;
|
||||
|
||||
if (!(message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, action_str)))
|
||||
if (!(message = dbus_message_new_signal(DNSMASQ_PATH, daemon->dbus_name, action_str)))
|
||||
return;
|
||||
|
||||
dbus_message_iter_init_append(message, &args);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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,11 +20,11 @@
|
||||
|
||||
void dhcp_common_init(void)
|
||||
{
|
||||
/* These each hold a DHCP option max size 255
|
||||
and get a terminating zero added */
|
||||
daemon->dhcp_buff = safe_malloc(256);
|
||||
daemon->dhcp_buff2 = safe_malloc(256);
|
||||
daemon->dhcp_buff3 = safe_malloc(256);
|
||||
/* These each hold a DHCP option max size 255
|
||||
and get a terminating zero added */
|
||||
daemon->dhcp_buff = safe_malloc(DHCP_BUFF_SZ);
|
||||
daemon->dhcp_buff2 = safe_malloc(DHCP_BUFF_SZ);
|
||||
daemon->dhcp_buff3 = safe_malloc(DHCP_BUFF_SZ);
|
||||
|
||||
/* dhcp_packet is used by v4 and v6, outpacket only by v6
|
||||
sizeof(struct dhcp_packet) is as good an initial size as any,
|
||||
@@ -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,38 +253,108 @@ int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void check_dhcp_hosts(int fatal)
|
||||
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
|
||||
{
|
||||
/* If the same IP appears in more than one host config, then DISCOVER
|
||||
for one of the hosts will get the address, but REQUEST will be NAKed,
|
||||
since the address is reserved by the other one -> protocol loop.
|
||||
Also check that FQDNs match the domain we are using. */
|
||||
struct hwaddr_config *conf_addr;
|
||||
|
||||
struct dhcp_config *configs, *cp;
|
||||
|
||||
for (configs = daemon->dhcp_conf; configs; configs = configs->next)
|
||||
{
|
||||
char *domain;
|
||||
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;
|
||||
}
|
||||
|
||||
if ((configs->flags & DHOPT_BANK) || fatal)
|
||||
{
|
||||
for (cp = configs->next; cp; cp = cp->next)
|
||||
if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr)
|
||||
{
|
||||
if (fatal)
|
||||
die(_("duplicate IP address %s in dhcp-config directive."),
|
||||
inet_ntoa(cp->addr), EC_BADCONF);
|
||||
else
|
||||
my_syslog(MS_DHCP | LOG_ERR, _("duplicate IP address %s in %s."),
|
||||
inet_ntoa(cp->addr), daemon->dhcp_hosts_file);
|
||||
configs->flags &= ~CONFIG_ADDR;
|
||||
}
|
||||
|
||||
/* split off domain part */
|
||||
if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname)))
|
||||
configs->domain = domain;
|
||||
}
|
||||
}
|
||||
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)
|
||||
@@ -289,7 +366,7 @@ void dhcp_update_configs(struct dhcp_config *configs)
|
||||
in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP,
|
||||
restore the status-quo ante first. */
|
||||
|
||||
struct dhcp_config *config;
|
||||
struct dhcp_config *config, *conf_tmp;
|
||||
struct crec *crec;
|
||||
int prot = AF_INET;
|
||||
|
||||
@@ -322,16 +399,17 @@ 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 && !config_find_by_address(configs, crec->addr.addr.addr.addr4))
|
||||
if (prot == AF_INET &&
|
||||
(!(conf_tmp = config_find_by_address(configs, crec->addr.addr.addr.addr4)) || conf_tmp == config))
|
||||
{
|
||||
config->addr = crec->addr.addr.addr.addr4;
|
||||
config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
|
||||
@@ -339,7 +417,8 @@ void dhcp_update_configs(struct dhcp_config *configs)
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (prot == AF_INET6 && !config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 128, 0))
|
||||
if (prot == AF_INET6 &&
|
||||
(!(conf_tmp = config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 128, 0)) || conf_tmp == config))
|
||||
{
|
||||
memcpy(&config->addr6, &crec->addr.addr.addr.addr6, IN6ADDRSZ);
|
||||
config->flags |= CONFIG_ADDR6 | CONFIG_ADDR_HOSTS;
|
||||
@@ -365,103 +444,29 @@ 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 dhcp_context *context;
|
||||
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;
|
||||
|
||||
/* weird libvirt-inspired access control */
|
||||
for (context = daemon->ra_contexts ? daemon->ra_contexts : daemon->dhcp6;
|
||||
context; context = context->next)
|
||||
if (!context->interface || strcmp(context->interface, ifrn_name) == 0)
|
||||
break;
|
||||
|
||||
if (!context)
|
||||
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)
|
||||
@@ -469,22 +474,24 @@ void bindtodevice(int fd)
|
||||
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
|
||||
|
||||
@@ -531,15 +538,15 @@ static const struct opttab_t {
|
||||
{ "x-windows-fs", 48, OT_ADDR_LIST },
|
||||
{ "x-windows-dm", 49, OT_ADDR_LIST },
|
||||
{ "requested-address", 50, OT_INTERNAL | OT_ADDR_LIST },
|
||||
{ "lease-time", 51, OT_INTERNAL | OT_DEC },
|
||||
{ "lease-time", 51, OT_INTERNAL | OT_TIME },
|
||||
{ "option-overload", 52, OT_INTERNAL },
|
||||
{ "message-type", 53, OT_INTERNAL | OT_DEC },
|
||||
{ "server-identifier", 54, OT_INTERNAL | OT_ADDR_LIST },
|
||||
{ "parameter-request", 55, OT_INTERNAL },
|
||||
{ "message", 56, OT_INTERNAL },
|
||||
{ "max-message-size", 57, OT_INTERNAL },
|
||||
{ "T1", 58, OT_INTERNAL | OT_DEC},
|
||||
{ "T2", 59, OT_INTERNAL | OT_DEC},
|
||||
{ "T1", 58, OT_TIME},
|
||||
{ "T2", 59, OT_TIME},
|
||||
{ "vendor-class", 60, 0 },
|
||||
{ "client-id", 61, OT_INTERNAL },
|
||||
{ "nis+-domain", 64, OT_NAME },
|
||||
@@ -590,8 +597,9 @@ static const struct opttab_t opttab6[] = {
|
||||
{ "nis-domain", 29, OT_RFC1035_NAME },
|
||||
{ "nis+-domain", 30, OT_RFC1035_NAME },
|
||||
{ "sntp-server", 31, OT_ADDR_LIST },
|
||||
{ "information-refresh-time", 32, OT_TIME },
|
||||
{ "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
|
||||
{ "ntp-server", 56, OT_ADDR_LIST },
|
||||
{ "ntp-server", 56, 0 },
|
||||
{ "bootfile-url", 59, OT_NAME },
|
||||
{ "bootfile-param", 60, OT_CSTRING },
|
||||
{ NULL, 0, 0 }
|
||||
@@ -623,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;
|
||||
@@ -636,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;
|
||||
@@ -657,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)
|
||||
@@ -754,14 +760,17 @@ char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if ((ot[o].size & OT_DEC) && opt_len != 0)
|
||||
else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0)
|
||||
{
|
||||
unsigned int dec = 0;
|
||||
|
||||
for (i = 0; i < opt_len; i++)
|
||||
dec = (dec << 8) | val[i];
|
||||
|
||||
sprintf(buf, "%u", dec);
|
||||
if (ot[o].size & OT_TIME)
|
||||
prettyprint_time(buf, dec);
|
||||
else
|
||||
sprintf(buf, "%u", dec);
|
||||
}
|
||||
else
|
||||
nodecode = 1;
|
||||
@@ -788,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, DHCP_BUFF_SZ);
|
||||
else
|
||||
strcpy(daemon->dhcp_buff, daemon->addrbuff);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
inet_ntop(family, start, daemon->dhcp_buff, DHCP_BUFF_SZ);
|
||||
inet_ntop(family, end, daemon->dhcp_buff3, DHCP_BUFF_SZ);
|
||||
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-2016 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,6 +19,10 @@
|
||||
#define DHCP_CLIENT_ALTPORT 1068
|
||||
#define PXE_PORT 4011
|
||||
|
||||
/* These each hold a DHCP option max size 255
|
||||
and get a terminating zero added */
|
||||
#define DHCP_BUFF_SZ 256
|
||||
|
||||
#define BOOTREQUEST 1
|
||||
#define BOOTREPLY 2
|
||||
#define DHCP_COOKIE 0x63825363
|
||||
|
||||
571
src/dhcp.c
571
src/dhcp.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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)
|
||||
{
|
||||
@@ -63,16 +67,24 @@ static int make_fd(int port)
|
||||
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1)
|
||||
die(_("failed to set options on DHCP 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 dnsmasq
|
||||
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 possible.
|
||||
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);
|
||||
}
|
||||
@@ -116,9 +128,7 @@ void dhcp_init(void)
|
||||
|
||||
/* Make BPF raw send socket */
|
||||
init_bpf();
|
||||
#endif
|
||||
|
||||
check_dhcp_hosts(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void dhcp_packet(time_t now, int pxe_fd)
|
||||
@@ -126,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;
|
||||
@@ -133,11 +145,14 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
struct cmsghdr *cmptr;
|
||||
struct iovec iov;
|
||||
ssize_t sz;
|
||||
int iface_index = 0, unicast_dest = 0, is_inform = 0;
|
||||
int iface_index = 0, unicast_dest = 0, is_inform = 0, loopback = 0;
|
||||
int rcvd_iface_index;
|
||||
struct in_addr iface_addr;
|
||||
struct iface_param parm;
|
||||
time_t recvtime = now;
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
struct arpreq arp_req;
|
||||
struct timeval tv;
|
||||
#endif
|
||||
|
||||
union {
|
||||
@@ -164,6 +179,9 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
return;
|
||||
|
||||
#if defined (HAVE_LINUX_NETWORK)
|
||||
if (ioctl(fd, SIOCGSTAMP, &tv) == 0)
|
||||
recvtime = tv.tv_sec;
|
||||
|
||||
if (msg.msg_controllen >= sizeof(struct cmsghdr))
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
@@ -205,26 +223,34 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
|
||||
if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name) ||
|
||||
ioctl(daemon->dhcpfd, SIOCGIFFLAGS, &ifr) != 0)
|
||||
return;
|
||||
|
||||
|
||||
mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
|
||||
loopback = !mess->giaddr.s_addr && (ifr.ifr_flags & IFF_LOOPBACK);
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* ARP fiddling uses original interface even if we pretend to use a different one. */
|
||||
strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
|
||||
#endif
|
||||
|
||||
/* One form of bridging on BSD has the property that packets
|
||||
can be recieved on bridge interfaces which do not have an IP address.
|
||||
We allow these to be treated as aliases of another interface which does have
|
||||
an IP address with --dhcp-bridge=interface,alias,alias */
|
||||
/* If the interface on which the DHCP request was received is an
|
||||
alias of some other interface (as specified by the
|
||||
--bridge-interface option), change ifr.ifr_name so that we look
|
||||
for DHCP contexts associated with the aliased interface instead
|
||||
of with the aliasing one. */
|
||||
rcvd_iface_index = iface_index;
|
||||
for (bridge = daemon->bridges; bridge; bridge = bridge->next)
|
||||
{
|
||||
for (alias = bridge->alias; alias; alias = alias->next)
|
||||
if (strncmp(ifr.ifr_name, alias->iface, IF_NAMESIZE) == 0)
|
||||
if (wildcard_matchn(alias->iface, ifr.ifr_name, IF_NAMESIZE))
|
||||
{
|
||||
if (!(iface_index = if_nametoindex(bridge->iface)))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("unknown interface %s in bridge-interface"), ifr.ifr_name);
|
||||
my_syslog(MS_DHCP | LOG_WARNING,
|
||||
_("unknown interface %s in bridge-interface"),
|
||||
bridge->iface);
|
||||
return;
|
||||
}
|
||||
else
|
||||
@@ -244,66 +270,88 @@ 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;
|
||||
|
||||
/* weird libvirt-inspired access control */
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
if (!context->interface || strcmp(context->interface, ifr.ifr_name) == 0)
|
||||
break;
|
||||
|
||||
if (!context)
|
||||
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;
|
||||
|
||||
match.matched = 0;
|
||||
match.ind = iface_index;
|
||||
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
|
||||
{
|
||||
if (iface_check(AF_INET, NULL, ifr.ifr_name, NULL))
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!daemon->if_addrs ||
|
||||
!iface_enumerate(AF_INET, &match, check_listen_addrs) ||
|
||||
!match.matched)
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
/* 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, mess, (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, loopback, &is_inform, pxe_fd, iface_addr, recvtime);
|
||||
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);
|
||||
msg.msg_control = NULL;
|
||||
@@ -323,7 +371,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);
|
||||
@@ -336,42 +384,48 @@ 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;
|
||||
}
|
||||
}
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
else if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
|
||||
mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
|
||||
else
|
||||
{
|
||||
/* broadcast to 255.255.255.255 (or mac address invalid) */
|
||||
/* fill cmsg for outbound interface (both broadcast & unicast) */
|
||||
struct in_pktinfo *pkt;
|
||||
msg.msg_control = control_u.control;
|
||||
msg.msg_controllen = sizeof(control_u);
|
||||
cmptr = CMSG_FIRSTHDR(&msg);
|
||||
pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
|
||||
pkt->ipi_ifindex = iface_index;
|
||||
pkt->ipi_ifindex = rcvd_iface_index;
|
||||
pkt->ipi_spec_dst.s_addr = 0;
|
||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
||||
cmptr->cmsg_level = IPPROTO_IP;
|
||||
cmptr->cmsg_type = IP_PKTINFO;
|
||||
dest.sin_addr.s_addr = INADDR_BROADCAST;
|
||||
dest.sin_port = htons(daemon->dhcp_client_port);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unicast to unconfigured client. Inject mac address direct into ARP cache.
|
||||
struct sockaddr limits size to 14 bytes. */
|
||||
dest.sin_addr = mess->yiaddr;
|
||||
dest.sin_port = htons(daemon->dhcp_client_port);
|
||||
memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in));
|
||||
arp_req.arp_ha.sa_family = mess->htype;
|
||||
memcpy(arp_req.arp_ha.sa_data, mess->chaddr, mess->hlen);
|
||||
/* interface name already copied in */
|
||||
arp_req.arp_flags = ATF_COM;
|
||||
ioctl(daemon->dhcpfd, SIOCSARP, &arp_req);
|
||||
cmptr->cmsg_type = IP_PKTINFO;
|
||||
|
||||
if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
|
||||
mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
|
||||
{
|
||||
/* broadcast to 255.255.255.255 (or mac address invalid) */
|
||||
dest.sin_addr.s_addr = INADDR_BROADCAST;
|
||||
dest.sin_port = htons(daemon->dhcp_client_port);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unicast to unconfigured client. Inject mac address direct into ARP cache.
|
||||
struct sockaddr limits size to 14 bytes. */
|
||||
dest.sin_addr = mess->yiaddr;
|
||||
dest.sin_port = htons(daemon->dhcp_client_port);
|
||||
memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in));
|
||||
arp_req.arp_ha.sa_family = mess->htype;
|
||||
memcpy(arp_req.arp_ha.sa_data, mess->chaddr, mess->hlen);
|
||||
/* interface name already copied in */
|
||||
arp_req.arp_flags = ATF_COM;
|
||||
if (ioctl(daemon->dhcpfd, SIOCSARP, &arp_req) == -1)
|
||||
my_syslog(MS_DHCP | LOG_ERR, _("ARP-cache injection failed: %s"), strerror(errno));
|
||||
}
|
||||
}
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER)
|
||||
@@ -409,16 +463,23 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
|
||||
#endif
|
||||
|
||||
while(sendmsg(fd, &msg, 0) == -1 && retry_send());
|
||||
while(retry_send(sendmsg(fd, &msg, 0)));
|
||||
|
||||
/* This can fail when, eg, iptables DROPS destination 255.255.255.255 */
|
||||
if (errno != 0)
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("Error sending DHCP packet to %s: %s"),
|
||||
inet_ntoa(dest.sin_addr), strerror(errno));
|
||||
}
|
||||
|
||||
|
||||
/* 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)
|
||||
@@ -444,13 +505,16 @@ static int check_listen_addrs(struct in_addr local, int if_index,
|
||||
3) Fills in local (this host) and router (this host or relay) addresses.
|
||||
4) Links contexts which are valid for hosts directly connected to the arrival interface on ->current.
|
||||
|
||||
Note that the current chain may be superceded later for configured hosts or those coming via gateways. */
|
||||
Note that the current chain may be superseded 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)
|
||||
{
|
||||
@@ -493,6 +557,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;
|
||||
}
|
||||
|
||||
@@ -532,7 +605,7 @@ struct dhcp_context *narrow_context(struct dhcp_context *context,
|
||||
{
|
||||
/* 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
|
||||
Here we have an address, and return the actual context corresponding 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
|
||||
@@ -574,9 +647,69 @@ struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct i
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check if and address is in use by sending ICMP ping.
|
||||
This wrapper handles a cache and load-limiting.
|
||||
Return is NULL is address in use, or a pointer to a cache entry
|
||||
recording that it isn't. */
|
||||
struct ping_result *do_icmp_ping(time_t now, struct in_addr addr, unsigned int hash, int loopback)
|
||||
{
|
||||
static struct ping_result dummy;
|
||||
struct ping_result *r, *victim = NULL;
|
||||
int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
|
||||
((float)PING_WAIT)));
|
||||
|
||||
/* check if we failed to ping addr sometime in the last
|
||||
PING_CACHE_TIME seconds. If so, assume the same situation still exists.
|
||||
This avoids problems when a stupid client bangs
|
||||
on us repeatedly. As a final check, if we did more
|
||||
than 60% of the possible ping checks in the last
|
||||
PING_CACHE_TIME, we are in high-load mode, so don't do any more. */
|
||||
for (count = 0, r = daemon->ping_results; r; r = r->next)
|
||||
if (difftime(now, r->time) > (float)PING_CACHE_TIME)
|
||||
victim = r; /* old record */
|
||||
else
|
||||
{
|
||||
count++;
|
||||
if (r->addr.s_addr == addr.s_addr)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* didn't find cached entry */
|
||||
if ((count >= max) || option_bool(OPT_NO_PING) || loopback)
|
||||
{
|
||||
/* overloaded, or configured not to check, loopback interface, return "not in use" */
|
||||
dummy.hash = 0;
|
||||
return &dummy;
|
||||
}
|
||||
else if (icmp_ping(addr))
|
||||
return NULL; /* address in use. */
|
||||
else
|
||||
{
|
||||
/* at this point victim may hold an expired record */
|
||||
if (!victim)
|
||||
{
|
||||
if ((victim = whine_malloc(sizeof(struct ping_result))))
|
||||
{
|
||||
victim->next = daemon->ping_results;
|
||||
daemon->ping_results = victim;
|
||||
}
|
||||
}
|
||||
|
||||
/* record that this address is OK for 30s
|
||||
without more ping checks */
|
||||
if (victim)
|
||||
{
|
||||
victim->addr = addr;
|
||||
victim->time = now;
|
||||
victim->hash = hash;
|
||||
}
|
||||
return victim;
|
||||
}
|
||||
}
|
||||
|
||||
int address_allocate(struct dhcp_context *context,
|
||||
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
|
||||
struct dhcp_netid *netids, time_t now)
|
||||
struct dhcp_netid *netids, time_t now, int loopback)
|
||||
{
|
||||
/* Find a free address: exclude anything in use and anything allocated to
|
||||
a particular hwaddr/clientid/hostname in our configuration.
|
||||
@@ -590,7 +723,11 @@ int address_allocate(struct dhcp_context *context,
|
||||
/* hash hwaddr: use the SDBM hashing algorithm. Seems to give good
|
||||
dispersal even with similarly-valued "strings". */
|
||||
for (j = 0, i = 0; i < hw_len; i++)
|
||||
j += hwaddr[i] + (j << 6) + (j << 16) - j;
|
||||
j = hwaddr[i] + (j << 6) + (j << 16) - j;
|
||||
|
||||
/* j == 0 is marker */
|
||||
if (j == 0)
|
||||
j = 1;
|
||||
|
||||
for (pass = 0; pass <= 1; pass++)
|
||||
for (c = context; c; c = c->current)
|
||||
@@ -628,69 +765,27 @@ int address_allocate(struct dhcp_context *context,
|
||||
(!IN_CLASSC(ntohl(addr.s_addr)) ||
|
||||
((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0xff) != 0x0))))
|
||||
{
|
||||
struct ping_result *r, *victim = NULL;
|
||||
int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
|
||||
((float)PING_WAIT)));
|
||||
struct ping_result *r;
|
||||
|
||||
*addrp = addr;
|
||||
|
||||
/* check if we failed to ping addr sometime in the last
|
||||
PING_CACHE_TIME seconds. If so, assume the same situation still exists.
|
||||
This avoids problems when a stupid client bangs
|
||||
on us repeatedly. As a final check, if we did more
|
||||
than 60% of the possible ping checks in the last
|
||||
PING_CACHE_TIME, we are in high-load mode, so don't do any more. */
|
||||
for (count = 0, r = daemon->ping_results; r; r = r->next)
|
||||
if (difftime(now, r->time) > (float)PING_CACHE_TIME)
|
||||
victim = r; /* old record */
|
||||
else
|
||||
{
|
||||
count++;
|
||||
if (r->addr.s_addr == addr.s_addr)
|
||||
{
|
||||
/* consec-ip mode: we offered this address for another client
|
||||
(different hash) recently, don't offer it to this one. */
|
||||
if (option_bool(OPT_CONSEC_ADDR) && r->hash != j)
|
||||
break;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!r)
|
||||
{
|
||||
if ((count < max) && !option_bool(OPT_NO_PING) && icmp_ping(addr))
|
||||
if ((r = do_icmp_ping(now, addr, j, loopback)))
|
||||
{
|
||||
/* consec-ip mode: we offered this address for another client
|
||||
(different hash) recently, don't offer it to this one. */
|
||||
if (!option_bool(OPT_CONSEC_ADDR) || r->hash == j)
|
||||
{
|
||||
/* address in use: perturb address selection so that we are
|
||||
less likely to try this address again. */
|
||||
if (!option_bool(OPT_CONSEC_ADDR))
|
||||
c->addr_epoch++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* at this point victim may hold an expired record */
|
||||
if (!victim)
|
||||
{
|
||||
if ((victim = whine_malloc(sizeof(struct ping_result))))
|
||||
{
|
||||
victim->next = daemon->ping_results;
|
||||
daemon->ping_results = victim;
|
||||
}
|
||||
}
|
||||
|
||||
/* record that this address is OK for 30s
|
||||
without more ping checks */
|
||||
if (victim)
|
||||
{
|
||||
victim->addr = addr;
|
||||
victim->time = now;
|
||||
victim->hash = j;
|
||||
}
|
||||
*addrp = addr;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* address in use: perturb address selection so that we are
|
||||
less likely to try this address again. */
|
||||
if (!option_bool(OPT_CONSEC_ADDR))
|
||||
c->addr_epoch++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
|
||||
|
||||
if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1))
|
||||
@@ -702,89 +797,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");
|
||||
@@ -986,5 +998,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-2016 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
|
||||
|
||||
692
src/dhcp6.c
692
src/dhcp6.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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,19 @@
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
struct iface_param {
|
||||
struct dhcp_context *current;
|
||||
struct in6_addr fallback;
|
||||
int ind;
|
||||
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);
|
||||
|
||||
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 make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm);
|
||||
|
||||
void dhcp6_init(void)
|
||||
@@ -36,15 +40,39 @@ void dhcp6_init(void)
|
||||
#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
|
||||
int class = IPTOS_CLASS_CS6;
|
||||
#endif
|
||||
|
||||
int oneopt = 1;
|
||||
|
||||
if ((fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1 ||
|
||||
#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
|
||||
setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
|
||||
#endif
|
||||
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &oneopt, sizeof(oneopt)) == -1 ||
|
||||
!fix_fd(fd) ||
|
||||
!set_ipv6pktinfo(fd))
|
||||
die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET);
|
||||
|
||||
/* When bind-interfaces is set, there might be more than one dnsmasq
|
||||
instance binding port 547. That's OK if they serve different networks.
|
||||
Need to set REUSEADDR|REUSEPORT to make this possible.
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
saddr.sin6_len = sizeof(struct sockaddr_in6);
|
||||
@@ -62,6 +90,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;
|
||||
@@ -71,11 +100,13 @@ void dhcp6_packet(time_t now)
|
||||
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
||||
} control_u;
|
||||
struct sockaddr_in6 from;
|
||||
struct all_addr dest;
|
||||
ssize_t sz;
|
||||
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);
|
||||
@@ -98,49 +129,114 @@ void dhcp6_packet(time_t now)
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
|
||||
if_index = p.p->ipi6_ifindex;
|
||||
dest.addr.addr6 = p.p->ipi6_addr;
|
||||
dst_addr = p.p->ipi6_addr;
|
||||
}
|
||||
|
||||
if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
if (!iface_check(AF_INET6, (struct all_addr *)&dest, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
return;
|
||||
|
||||
/* weird libvirt-inspired access control */
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (!context->interface || strcmp(context->interface, ifr.ifr_name) == 0)
|
||||
break;
|
||||
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
/* unlinked contexts are marked by context->current == context */
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if ((port = relay_reply6(&from, sz, ifr.ifr_name)) == 0)
|
||||
{
|
||||
context->current = context;
|
||||
memset(&context->local6, 0, IN6ADDRSZ);
|
||||
struct dhcp_bridge *bridge, *alias;
|
||||
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
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);
|
||||
|
||||
/* If the interface on which the DHCPv6 request was received is
|
||||
an alias of some other interface (as specified by the
|
||||
--bridge-interface option), change parm.ind so that we look
|
||||
for DHCPv6 contexts associated with the aliased interface
|
||||
instead of with the aliasing one. */
|
||||
for (bridge = daemon->bridges; bridge; bridge = bridge->next)
|
||||
{
|
||||
for (alias = bridge->alias; alias; alias = alias->next)
|
||||
if (wildcard_matchn(alias->iface, ifr.ifr_name, IF_NAMESIZE))
|
||||
{
|
||||
parm.ind = if_nametoindex(bridge->iface);
|
||||
if (!parm.ind)
|
||||
{
|
||||
my_syslog(MS_DHCP | LOG_WARNING,
|
||||
_("unknown interface %s in bridge-interface"),
|
||||
bridge->iface);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (alias)
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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, now);
|
||||
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);
|
||||
}
|
||||
|
||||
parm.current = NULL;
|
||||
parm.ind = if_index;
|
||||
memset(&parm.fallback, 0, IN6ADDRSZ);
|
||||
|
||||
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
|
||||
return;
|
||||
|
||||
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
|
||||
@@ -148,49 +244,144 @@ void dhcp6_packet(time_t now)
|
||||
if (port != 0)
|
||||
{
|
||||
from.sin6_port = htons(port);
|
||||
while (sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, save_counter(0),
|
||||
0, (struct sockaddr *)&from, sizeof(from)) == -1 &&
|
||||
retry_send());
|
||||
while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base,
|
||||
save_counter(0), 0, (struct sockaddr *)&from,
|
||||
sizeof(from))));
|
||||
}
|
||||
}
|
||||
|
||||
void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsigned int *maclenp, unsigned int *mactypep, time_t now)
|
||||
{
|
||||
/* Receiving 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;
|
||||
union mysockaddr addr;
|
||||
int i, maclen;
|
||||
|
||||
neigh.type = ND_NEIGHBOR_SOLICIT;
|
||||
neigh.code = 0;
|
||||
neigh.reserved = 0;
|
||||
neigh.target = *client;
|
||||
/* RFC4443 section-2.3: checksum has to be zero to be calculated */
|
||||
neigh.checksum = 0;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
addr.in6.sin6_family = AF_INET6;
|
||||
addr.in6.sin6_port = htons(IPPROTO_ICMPV6);
|
||||
addr.in6.sin6_addr = *client;
|
||||
addr.in6.sin6_scope_id = iface;
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
if ((maclen = find_mac(&addr, mac, 0, now)) != 0)
|
||||
break;
|
||||
|
||||
sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr));
|
||||
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 100000000; /* 100ms */
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
|
||||
*maclenp = maclen;
|
||||
*mactypep = ARPHRD_ETHER;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
/* 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 constructed 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)
|
||||
@@ -206,8 +397,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.
|
||||
@@ -223,23 +414,36 @@ 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)));
|
||||
{
|
||||
u64 range = 1 + addr6part(&c->end6) - addr6part(&c->start6);
|
||||
u64 offset = j + c->addr_epoch;
|
||||
|
||||
/* don't divide by zero if range is whole 2^64 */
|
||||
if (range != 0)
|
||||
offset = offset % range;
|
||||
|
||||
start = addr6part(&c->start6) + offset;
|
||||
}
|
||||
|
||||
/* iterate until we find a free address. */
|
||||
addr = start;
|
||||
@@ -256,7 +460,7 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
|
||||
{
|
||||
*ans = c->start6;
|
||||
setaddr6part (ans, addr);
|
||||
return 1;
|
||||
return c;
|
||||
}
|
||||
|
||||
addr++;
|
||||
@@ -266,13 +470,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;
|
||||
@@ -287,93 +493,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_addr_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))
|
||||
return 1;
|
||||
for (; context; context = context->current)
|
||||
if (is_same_net6(&config->addr6, &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_addr_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_addr_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;
|
||||
@@ -386,8 +553,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);
|
||||
|
||||
@@ -405,27 +578,206 @@ 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_unsolicited(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_unsolicited(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) || 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_unsolicited(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-2016 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
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#define NAMESERVER_PORT 53
|
||||
#define TFTP_PORT 69
|
||||
#define MAX_PORT 65535u
|
||||
|
||||
#define IN6ADDRSZ 16
|
||||
#define INADDRSZ 4
|
||||
@@ -36,43 +37,70 @@
|
||||
|
||||
#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 */
|
||||
#define EDNS0_OPTION_NOMDEVICEID 65073 /* Nominum temporary assignment */
|
||||
#define EDNS0_OPTION_NOMCPEID 65074 /* Nominum temporary assignment */
|
||||
|
||||
struct dns_header {
|
||||
u16 id;
|
||||
u8 hb3,hb4;
|
||||
u16 qdcount,ancount,nscount,arcount;
|
||||
};
|
||||
|
||||
#define HB3_QR 0x80
|
||||
#define HB3_QR 0x80 /* Query */
|
||||
#define HB3_OPCODE 0x78
|
||||
#define HB3_AA 0x04
|
||||
#define HB3_TC 0x02
|
||||
#define HB3_RD 0x01
|
||||
#define HB3_AA 0x04 /* Authoritative Answer */
|
||||
#define HB3_TC 0x02 /* TrunCated */
|
||||
#define HB3_RD 0x01 /* Recursion Desired */
|
||||
|
||||
#define HB4_RA 0x80
|
||||
#define HB4_AD 0x20
|
||||
#define HB4_CD 0x10
|
||||
#define HB4_RA 0x80 /* Recursion Available */
|
||||
#define HB4_AD 0x20 /* Authenticated Data */
|
||||
#define HB4_CD 0x10 /* Checking Disabled */
|
||||
#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 +140,16 @@ 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))
|
||||
|
||||
/* Escape character in our presentation format for names.
|
||||
Cannot be '.' or /000 and must be !isprint().
|
||||
Note that escaped chars are stored as
|
||||
<NAME_ESCAPE> <orig-char+1>
|
||||
to ensure that the escaped form of /000 doesn't include /000
|
||||
*/
|
||||
#define NAME_ESCAPE 1
|
||||
|
||||
1099
src/dnsmasq.c
1099
src/dnsmasq.c
File diff suppressed because it is too large
Load Diff
684
src/dnsmasq.h
684
src/dnsmasq.h
File diff suppressed because it is too large
Load Diff
2277
src/dnssec.c
Normal file
2277
src/dnssec.c
Normal file
File diff suppressed because it is too large
Load Diff
246
src/domain.c
Normal file
246
src/domain.c
Normal file
@@ -0,0 +1,246 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (prot == AF_INET6 && strstr(tail, "--ffff-") == tail)
|
||||
{
|
||||
/* special hack for v4-mapped. */
|
||||
memcpy(tail, "::ffff:", 7);
|
||||
for (p = tail + 7; *p; p++)
|
||||
if (*p == '-')
|
||||
*p = '.';
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* V4-mapped have periods.... */
|
||||
for (p = name; *p; p++)
|
||||
if (*p == ':' || *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
|
||||
429
src/edns0.c
Normal file
429
src/edns0.c
Normal file
@@ -0,0 +1,429 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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"
|
||||
|
||||
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t *len, unsigned char **p, int *is_sign, int *is_last)
|
||||
{
|
||||
/* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
|
||||
also return length of pseudoheader in *len and pointer to the UDP size in *p
|
||||
Finally, check to see if a packet is signed. If it is we cannot change a single bit before
|
||||
forwarding. We look for TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
|
||||
|
||||
int i, arcount = ntohs(header->arcount);
|
||||
unsigned char *ansp = (unsigned char *)(header+1);
|
||||
unsigned short rdlen, type, class;
|
||||
unsigned char *ret = NULL;
|
||||
|
||||
if (is_sign)
|
||||
{
|
||||
*is_sign = 0;
|
||||
|
||||
if (OPCODE(header) == QUERY)
|
||||
{
|
||||
for (i = ntohs(header->qdcount); i != 0; i--)
|
||||
{
|
||||
if (!(ansp = skip_name(ansp, header, plen, 4)))
|
||||
return NULL;
|
||||
|
||||
GETSHORT(type, ansp);
|
||||
GETSHORT(class, ansp);
|
||||
|
||||
if (class == C_IN && type == T_TKEY)
|
||||
*is_sign = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(ansp = skip_questions(header, plen)))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (arcount == 0)
|
||||
return NULL;
|
||||
|
||||
if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < arcount; i++)
|
||||
{
|
||||
unsigned char *save, *start = ansp;
|
||||
if (!(ansp = skip_name(ansp, header, plen, 10)))
|
||||
return NULL;
|
||||
|
||||
GETSHORT(type, ansp);
|
||||
save = ansp;
|
||||
GETSHORT(class, ansp);
|
||||
ansp += 4; /* TTL */
|
||||
GETSHORT(rdlen, ansp);
|
||||
if (!ADD_RDLEN(header, ansp, plen, rdlen))
|
||||
return NULL;
|
||||
if (type == T_OPT)
|
||||
{
|
||||
if (len)
|
||||
*len = ansp - start;
|
||||
|
||||
if (p)
|
||||
*p = save;
|
||||
|
||||
if (is_last)
|
||||
*is_last = (i == arcount-1);
|
||||
|
||||
ret = start;
|
||||
}
|
||||
else if (is_sign &&
|
||||
i == arcount - 1 &&
|
||||
class == C_ANY &&
|
||||
type == T_TSIG)
|
||||
*is_sign = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* replace == 2 ->delete existing option only. */
|
||||
size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do, int replace)
|
||||
{
|
||||
unsigned char *lenp, *datap, *p, *udp_len, *buff = NULL;
|
||||
int rdlen = 0, is_sign, is_last;
|
||||
unsigned short flags = set_do ? 0x8000 : 0, rcode = 0;
|
||||
|
||||
p = find_pseudoheader(header, plen, NULL, &udp_len, &is_sign, &is_last);
|
||||
|
||||
if (is_sign)
|
||||
return plen;
|
||||
|
||||
if (p)
|
||||
{
|
||||
/* Existing header */
|
||||
int i;
|
||||
unsigned short code, len;
|
||||
|
||||
p = udp_len;
|
||||
GETSHORT(udp_sz, p);
|
||||
GETSHORT(rcode, p);
|
||||
GETSHORT(flags, p);
|
||||
|
||||
if (set_do)
|
||||
{
|
||||
p -= 2;
|
||||
flags |= 0x8000;
|
||||
PUTSHORT(flags, p);
|
||||
}
|
||||
|
||||
lenp = p;
|
||||
GETSHORT(rdlen, p);
|
||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
return plen; /* bad packet */
|
||||
datap = p;
|
||||
|
||||
/* no option to add */
|
||||
if (optno == 0)
|
||||
return plen;
|
||||
|
||||
/* check if option already there */
|
||||
for (i = 0; i + 4 < rdlen;)
|
||||
{
|
||||
GETSHORT(code, p);
|
||||
GETSHORT(len, p);
|
||||
|
||||
/* malformed option, delete the whole OPT RR and start again. */
|
||||
if (i + len > rdlen)
|
||||
{
|
||||
rdlen = 0;
|
||||
is_last = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (code == optno)
|
||||
{
|
||||
if (replace == 0)
|
||||
return plen;
|
||||
|
||||
/* delete option if we're to replace it. */
|
||||
p -= 4;
|
||||
rdlen -= len + 4;
|
||||
memcpy(p, p+len+4, rdlen - i);
|
||||
PUTSHORT(rdlen, lenp);
|
||||
lenp -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
p += len;
|
||||
i += len + 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're going to extend the RR, it has to be the last RR in the packet */
|
||||
if (!is_last)
|
||||
{
|
||||
/* First, take a copy of the options. */
|
||||
if (rdlen != 0 && (buff = whine_malloc(rdlen)))
|
||||
memcpy(buff, datap, rdlen);
|
||||
|
||||
/* now, delete OPT RR */
|
||||
plen = rrfilter(header, plen, 0);
|
||||
|
||||
/* Now, force addition of a new one */
|
||||
p = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!p)
|
||||
{
|
||||
/* We are (re)adding the pseudoheader */
|
||||
if (!(p = skip_questions(header, plen)) ||
|
||||
!(p = skip_section(p,
|
||||
ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
|
||||
header, plen)))
|
||||
return plen;
|
||||
*p++ = 0; /* empty name */
|
||||
PUTSHORT(T_OPT, p);
|
||||
PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
|
||||
PUTSHORT(rcode, p); /* extended RCODE and version */
|
||||
PUTSHORT(flags, p); /* DO flag */
|
||||
lenp = p;
|
||||
PUTSHORT(rdlen, p); /* RDLEN */
|
||||
datap = p;
|
||||
/* Copy back any options */
|
||||
if (buff)
|
||||
{
|
||||
memcpy(p, buff, rdlen);
|
||||
free(buff);
|
||||
p += rdlen;
|
||||
}
|
||||
header->arcount = htons(ntohs(header->arcount) + 1);
|
||||
}
|
||||
|
||||
if (((ssize_t)optlen) > (limit - (p + 4)))
|
||||
return plen; /* Too big */
|
||||
|
||||
/* Add new option */
|
||||
if (optno != 0 && replace != 2)
|
||||
{
|
||||
PUTSHORT(optno, p);
|
||||
PUTSHORT(optlen, p);
|
||||
memcpy(p, opt, optlen);
|
||||
p += optlen;
|
||||
PUTSHORT(p - datap, lenp);
|
||||
}
|
||||
return p - (unsigned char *)header;
|
||||
}
|
||||
|
||||
size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit)
|
||||
{
|
||||
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1, 0);
|
||||
}
|
||||
|
||||
static unsigned char char64(unsigned char c)
|
||||
{
|
||||
return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[c & 0x3f];
|
||||
}
|
||||
|
||||
static void encoder(unsigned char *in, char *out)
|
||||
{
|
||||
out[0] = char64(in[0]>>2);
|
||||
out[1] = char64((in[0]<<4) | (in[1]>>4));
|
||||
out[2] = char64((in[1]<<2) | (in[2]>>6));
|
||||
out[3] = char64(in[2]);
|
||||
}
|
||||
|
||||
static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
|
||||
{
|
||||
int maclen, replace = 2; /* can't get mac address, just delete any incoming. */
|
||||
unsigned char mac[DHCP_CHADDR_MAX];
|
||||
char encode[18]; /* handle 6 byte MACs */
|
||||
|
||||
if ((maclen = find_mac(l3, mac, 1, now)) == 6)
|
||||
{
|
||||
replace = 1;
|
||||
|
||||
if (option_bool(OPT_MAC_HEX))
|
||||
print_mac(encode, mac, maclen);
|
||||
else
|
||||
{
|
||||
encoder(mac, encode);
|
||||
encoder(mac+3, encode+4);
|
||||
encode[8] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, strlen(encode), 0, replace);
|
||||
}
|
||||
|
||||
|
||||
static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
|
||||
{
|
||||
int maclen;
|
||||
unsigned char mac[DHCP_CHADDR_MAX];
|
||||
|
||||
if ((maclen = find_mac(l3, mac, 1, now)) != 0)
|
||||
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, 0);
|
||||
|
||||
return plen;
|
||||
}
|
||||
|
||||
struct subnet_opt {
|
||||
u16 family;
|
||||
u8 source_netmask, scope_netmask;
|
||||
#ifdef HAVE_IPV6
|
||||
u8 addr[IN6ADDRSZ];
|
||||
#else
|
||||
u8 addr[INADDRSZ];
|
||||
#endif
|
||||
};
|
||||
|
||||
static void *get_addrp(union mysockaddr *addr, const short family)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
if (family == AF_INET6)
|
||||
return &addr->in6.sin6_addr;
|
||||
#endif
|
||||
|
||||
return &addr->in.sin_addr;
|
||||
}
|
||||
|
||||
static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
|
||||
{
|
||||
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
|
||||
|
||||
int len;
|
||||
void *addrp;
|
||||
int sa_family = source->sa.sa_family;
|
||||
|
||||
opt->source_netmask = 0;
|
||||
opt->scope_netmask = 0;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (source->sa.sa_family == AF_INET6 && daemon->add_subnet6)
|
||||
{
|
||||
opt->source_netmask = daemon->add_subnet6->mask;
|
||||
if (daemon->add_subnet6->addr_used)
|
||||
{
|
||||
sa_family = daemon->add_subnet6->addr.sa.sa_family;
|
||||
addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
|
||||
}
|
||||
else
|
||||
addrp = &source->in6.sin6_addr;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (source->sa.sa_family == AF_INET && daemon->add_subnet4)
|
||||
{
|
||||
opt->source_netmask = daemon->add_subnet4->mask;
|
||||
if (daemon->add_subnet4->addr_used)
|
||||
{
|
||||
sa_family = daemon->add_subnet4->addr.sa.sa_family;
|
||||
addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
|
||||
}
|
||||
else
|
||||
addrp = &source->in.sin_addr;
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
|
||||
#else
|
||||
opt->family = htons(1);
|
||||
#endif
|
||||
|
||||
len = 0;
|
||||
|
||||
if (opt->source_netmask != 0)
|
||||
{
|
||||
len = ((opt->source_netmask - 1) >> 3) + 1;
|
||||
memcpy(opt->addr, addrp, len);
|
||||
if (opt->source_netmask & 7)
|
||||
opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
|
||||
}
|
||||
|
||||
return len + 4;
|
||||
}
|
||||
|
||||
static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source)
|
||||
{
|
||||
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
|
||||
|
||||
int len;
|
||||
struct subnet_opt opt;
|
||||
|
||||
len = calc_subnet_opt(&opt, source);
|
||||
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, 0);
|
||||
}
|
||||
|
||||
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
|
||||
{
|
||||
/* Section 9.2, Check that subnet option in reply matches. */
|
||||
|
||||
int len, calc_len;
|
||||
struct subnet_opt opt;
|
||||
unsigned char *p;
|
||||
int code, i, rdlen;
|
||||
|
||||
calc_len = calc_subnet_opt(&opt, peer);
|
||||
|
||||
if (!(p = skip_name(pseudoheader, header, plen, 10)))
|
||||
return 1;
|
||||
|
||||
p += 8; /* skip UDP length and RCODE */
|
||||
|
||||
GETSHORT(rdlen, p);
|
||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
return 1; /* bad packet */
|
||||
|
||||
/* check if option there */
|
||||
for (i = 0; i + 4 < rdlen; i += len + 4)
|
||||
{
|
||||
GETSHORT(code, p);
|
||||
GETSHORT(len, p);
|
||||
if (code == EDNS0_OPTION_CLIENT_SUBNET)
|
||||
{
|
||||
/* make sure this doesn't mismatch. */
|
||||
opt.scope_netmask = p[3];
|
||||
if (len != calc_len || memcmp(p, &opt, len) != 0)
|
||||
return 0;
|
||||
}
|
||||
p += len;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
union mysockaddr *source, time_t now, int *check_subnet)
|
||||
{
|
||||
*check_subnet = 0;
|
||||
|
||||
if (option_bool(OPT_ADD_MAC))
|
||||
plen = add_mac(header, plen, limit, source, now);
|
||||
|
||||
if (option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX))
|
||||
plen = add_dns_client(header, plen, limit, source, now);
|
||||
|
||||
if (daemon->dns_client_id)
|
||||
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID,
|
||||
(unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1);
|
||||
|
||||
if (option_bool(OPT_CLIENT_SUBNET))
|
||||
{
|
||||
plen = add_source_addr(header, plen, limit, source);
|
||||
*check_subnet = 1;
|
||||
}
|
||||
|
||||
return plen;
|
||||
}
|
||||
1601
src/forward.c
1601
src/forward.c
File diff suppressed because it is too large
Load Diff
343
src/helper.c
343
src/helper.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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,11 +14,12 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_SCRIPT
|
||||
|
||||
/* This file has code to fork a helper process which recieves data via a pipe
|
||||
/* This file has code to fork a helper process which receives data via a pipe
|
||||
shared with the main process and which is responsible for calling a script when
|
||||
DHCP leases change.
|
||||
|
||||
@@ -34,10 +35,15 @@ static void my_setenv(const char *name, const char *value, int *error);
|
||||
static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err);
|
||||
|
||||
#ifdef HAVE_LUASCRIPT
|
||||
#define LUA_COMPAT_ALL
|
||||
#include <lua.h>
|
||||
#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
#ifndef lua_open
|
||||
#define lua_open() luaL_newstate()
|
||||
#endif
|
||||
|
||||
lua_State *lua;
|
||||
|
||||
static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field);
|
||||
@@ -55,10 +61,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;
|
||||
@@ -122,7 +136,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
max_fd != STDIN_FILENO && max_fd != pipefd[0] &&
|
||||
max_fd != event_fd && max_fd != err_fd)
|
||||
close(max_fd);
|
||||
|
||||
|
||||
#ifdef HAVE_LUASCRIPT
|
||||
if (daemon->luascript)
|
||||
{
|
||||
@@ -176,6 +190,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
unsigned char *buf = (unsigned char *)daemon->namebuff;
|
||||
unsigned char *end, *extradata, *alloc_buff = NULL;
|
||||
int is6, err = 0;
|
||||
int pipeout[2];
|
||||
|
||||
free(alloc_buff);
|
||||
|
||||
@@ -206,31 +221,32 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
action_str = "tftp";
|
||||
is6 = (data.flags != AF_INET);
|
||||
}
|
||||
else
|
||||
else if (data.action == ACTION_ARP)
|
||||
{
|
||||
action_str = "arp-add";
|
||||
is6 = (data.flags != AF_INET);
|
||||
}
|
||||
else if (data.action == ACTION_ARP_DEL)
|
||||
{
|
||||
action_str = "arp-del";
|
||||
is6 = (data.flags != AF_INET);
|
||||
data.action = ACTION_ARP;
|
||||
}
|
||||
else
|
||||
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)))
|
||||
@@ -241,32 +257,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
|
||||
|
||||
@@ -293,15 +302,17 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
|
||||
if (!is6)
|
||||
inet_ntop(AF_INET, &data.addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
#ifdef HAVE_DHCP6
|
||||
#ifdef HAVE_IPV6
|
||||
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)
|
||||
{
|
||||
@@ -318,11 +329,27 @@ 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 */
|
||||
}
|
||||
}
|
||||
else if (data.action == ACTION_ARP)
|
||||
{
|
||||
lua_getglobal(lua, "arp");
|
||||
if (lua_type(lua, -1) != LUA_TFUNCTION)
|
||||
lua_pop(lua, 1); /* arp function optional */
|
||||
else
|
||||
{
|
||||
lua_pushstring(lua, action_str); /* arg1 - action */
|
||||
lua_newtable(lua); /* arg2 - data table */
|
||||
lua_pushstring(lua, daemon->addrbuff);
|
||||
lua_setfield(lua, -2, "client_address");
|
||||
lua_pushstring(lua, daemon->dhcp_buff);
|
||||
lua_setfield(lua, -2, "mac_address");
|
||||
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_getglobal(lua, "lease"); /* function to call */
|
||||
@@ -331,9 +358,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");
|
||||
@@ -377,12 +404,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");
|
||||
@@ -392,6 +423,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");
|
||||
@@ -422,7 +456,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");
|
||||
@@ -440,16 +474,54 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
if (!daemon->lease_change_command)
|
||||
continue;
|
||||
|
||||
/* Pipe to capture stdout and stderr from script */
|
||||
if (!option_bool(OPT_DEBUG) && pipe(pipeout) == -1)
|
||||
continue;
|
||||
|
||||
/* possible fork errors are all temporary resource problems */
|
||||
while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM))
|
||||
sleep(2);
|
||||
|
||||
if (pid == -1)
|
||||
continue;
|
||||
{
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
close(pipeout[0]);
|
||||
close(pipeout[1]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* wait for child to complete */
|
||||
if (pid != 0)
|
||||
{
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
close(pipeout[1]);
|
||||
|
||||
/* Read lines sent to stdout/err by the script and pass them back to be logged */
|
||||
if (!(fp = fdopen(pipeout[0], "r")))
|
||||
close(pipeout[0]);
|
||||
else
|
||||
{
|
||||
while (fgets(daemon->packet, daemon->packet_buff_sz, fp))
|
||||
{
|
||||
/* do not include new lines, log will append them */
|
||||
size_t len = strlen(daemon->packet);
|
||||
if (len > 0)
|
||||
{
|
||||
--len;
|
||||
if (daemon->packet[len] == '\n')
|
||||
daemon->packet[len] = 0;
|
||||
}
|
||||
send_event(event_fd, EVENT_SCRIPT_LOG, 0, daemon->packet);
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
/* reap our children's children, if necessary */
|
||||
while (1)
|
||||
{
|
||||
@@ -472,29 +544,36 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (data.action != ACTION_TFTP)
|
||||
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
if (is6)
|
||||
{
|
||||
my_setenv("DNSMASQ_IAID", daemon->dhcp_buff3, &err);
|
||||
my_setenv("DNSMASQ_SERVER_DUID", daemon->packet, &err);
|
||||
}
|
||||
/* map stdout/stderr of script to pipeout */
|
||||
close(pipeout[0]);
|
||||
dup2(pipeout[1], STDOUT_FILENO);
|
||||
dup2(pipeout[1], STDERR_FILENO);
|
||||
close(pipeout[1]);
|
||||
}
|
||||
|
||||
if (data.action != ACTION_TFTP && data.action != ACTION_ARP)
|
||||
{
|
||||
#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;
|
||||
@@ -504,10 +583,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);
|
||||
@@ -523,14 +602,18 @@ 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_REQUESTED_OPTIONS", &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++)
|
||||
{
|
||||
@@ -538,22 +621,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;
|
||||
|
||||
my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &err);
|
||||
}
|
||||
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
my_setenv("DNSMASQ_LOG_DHCP", "1", &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);
|
||||
@@ -563,8 +640,9 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
if (err == 0)
|
||||
{
|
||||
execl(daemon->lease_change_command,
|
||||
p ? p+1 : daemon->lease_change_command,
|
||||
action_str, daemon->dhcp_buff, daemon->addrbuff, hostname, (char*)NULL);
|
||||
p ? p+1 : daemon->lease_change_command, action_str,
|
||||
(is6 && data.action != ACTION_ARP) ? daemon->packet : daemon->dhcp_buff,
|
||||
daemon->addrbuff, hostname, (char*)NULL);
|
||||
err = errno;
|
||||
}
|
||||
/* failed, send event so the main process logs the problem */
|
||||
@@ -575,31 +653,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
|
||||
@@ -649,8 +740,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
|
||||
@@ -670,6 +760,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;
|
||||
@@ -727,13 +822,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);
|
||||
@@ -742,6 +837,30 @@ void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer)
|
||||
}
|
||||
#endif
|
||||
|
||||
void queue_arp(int action, unsigned char *mac, int maclen, int family, struct all_addr *addr)
|
||||
{
|
||||
/* no script */
|
||||
if (daemon->helperfd == -1)
|
||||
return;
|
||||
|
||||
buff_alloc(sizeof(struct script_data));
|
||||
memset(buf, 0, sizeof(struct script_data));
|
||||
|
||||
buf->action = action;
|
||||
buf->hwaddr_len = maclen;
|
||||
buf->hwaddr_type = ARPHRD_ETHER;
|
||||
if ((buf->flags = family) == AF_INET)
|
||||
buf->addr = addr->addr.addr4;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
buf->addr6 = addr->addr.addr6;
|
||||
#endif
|
||||
|
||||
memcpy(buf->hwaddr, mac, maclen);
|
||||
|
||||
bytes_in_buf = sizeof(struct script_data);
|
||||
}
|
||||
|
||||
int helper_buf_empty(void)
|
||||
{
|
||||
return bytes_in_buf == 0;
|
||||
|
||||
296
src/inotify.c
Normal file
296
src/inotify.c
Normal file
@@ -0,0 +1,296 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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_INOTIFY
|
||||
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/param.h> /* For MAXSYMLINKS */
|
||||
|
||||
/* the strategy is to set a inotify on the directories containing
|
||||
resolv files, for any files in the directory which are close-write
|
||||
or moved into the directory.
|
||||
|
||||
When either of those happen, we look to see if the file involved
|
||||
is actually a resolv-file, and if so, call poll-resolv with
|
||||
the "force" argument, to ensure it's read.
|
||||
|
||||
This adds one new error condition: the directories containing
|
||||
all specified resolv-files must exist at start-up, even if the actual
|
||||
files don't.
|
||||
*/
|
||||
|
||||
static char *inotify_buffer;
|
||||
#define INOTIFY_SZ (sizeof(struct inotify_event) + NAME_MAX + 1)
|
||||
|
||||
/* If path is a symbolic link, return the path it
|
||||
points to, made absolute if relative.
|
||||
If path doesn't exist or is not a symlink, return NULL.
|
||||
Return value is malloc'ed */
|
||||
static char *my_readlink(char *path)
|
||||
{
|
||||
ssize_t rc, size = 64;
|
||||
char *buf;
|
||||
|
||||
while (1)
|
||||
{
|
||||
buf = safe_malloc(size);
|
||||
rc = readlink(path, buf, (size_t)size);
|
||||
|
||||
if (rc == -1)
|
||||
{
|
||||
/* Not link or doesn't exist. */
|
||||
if (errno == EINVAL || errno == ENOENT)
|
||||
{
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
die(_("cannot access path %s: %s"), path, EC_MISC);
|
||||
}
|
||||
else if (rc < size-1)
|
||||
{
|
||||
char *d;
|
||||
|
||||
buf[rc] = 0;
|
||||
if (buf[0] != '/' && ((d = strrchr(path, '/'))))
|
||||
{
|
||||
/* Add path to relative link */
|
||||
char *new_buf = safe_malloc((d - path) + strlen(buf) + 2);
|
||||
*(d+1) = 0;
|
||||
strcpy(new_buf, path);
|
||||
strcat(new_buf, buf);
|
||||
free(buf);
|
||||
buf = new_buf;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Buffer too small, increase and retry */
|
||||
size += 64;
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void inotify_dnsmasq_init()
|
||||
{
|
||||
struct resolvc *res;
|
||||
inotify_buffer = safe_malloc(INOTIFY_SZ);
|
||||
daemon->inotifyfd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||
|
||||
if (daemon->inotifyfd == -1)
|
||||
die(_("failed to create inotify: %s"), NULL, EC_MISC);
|
||||
|
||||
if (option_bool(OPT_NO_RESOLV))
|
||||
return;
|
||||
|
||||
for (res = daemon->resolv_files; res; res = res->next)
|
||||
{
|
||||
char *d, *new_path, *path = safe_malloc(strlen(res->name) + 1);
|
||||
int links = MAXSYMLINKS;
|
||||
|
||||
strcpy(path, res->name);
|
||||
|
||||
/* Follow symlinks until we reach a non-symlink, or a non-existent file. */
|
||||
while ((new_path = my_readlink(path)))
|
||||
{
|
||||
if (links-- == 0)
|
||||
die(_("too many symlinks following %s"), res->name, EC_MISC);
|
||||
free(path);
|
||||
path = new_path;
|
||||
}
|
||||
|
||||
res->wd = -1;
|
||||
|
||||
if ((d = strrchr(path, '/')))
|
||||
{
|
||||
*d = 0; /* make path just directory */
|
||||
res->wd = inotify_add_watch(daemon->inotifyfd, path, IN_CLOSE_WRITE | IN_MOVED_TO);
|
||||
|
||||
res->file = d+1; /* pointer to filename */
|
||||
*d = '/';
|
||||
|
||||
if (res->wd == -1 && errno == ENOENT)
|
||||
die(_("directory %s for resolv-file is missing, cannot poll"), res->name, EC_MISC);
|
||||
}
|
||||
|
||||
if (res->wd == -1)
|
||||
die(_("failed to create inotify for %s: %s"), res->name, EC_MISC);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* initialisation for dynamic-dir. Set inotify watch for each directory, and read pre-existing files */
|
||||
void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revhashsz)
|
||||
{
|
||||
struct hostsfile *ah;
|
||||
|
||||
for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
|
||||
{
|
||||
DIR *dir_stream = NULL;
|
||||
struct dirent *ent;
|
||||
struct stat buf;
|
||||
|
||||
if (!(ah->flags & flag))
|
||||
continue;
|
||||
|
||||
if (stat(ah->fname, &buf) == -1 || !(S_ISDIR(buf.st_mode)))
|
||||
{
|
||||
my_syslog(LOG_ERR, _("bad dynamic directory %s: %s"),
|
||||
ah->fname, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(ah->flags & AH_WD_DONE))
|
||||
{
|
||||
ah->wd = inotify_add_watch(daemon->inotifyfd, ah->fname, IN_CLOSE_WRITE | IN_MOVED_TO);
|
||||
ah->flags |= AH_WD_DONE;
|
||||
}
|
||||
|
||||
/* Read contents of dir _after_ calling add_watch, in the hope of avoiding
|
||||
a race which misses files being added as we start */
|
||||
if (ah->wd == -1 || !(dir_stream = opendir(ah->fname)))
|
||||
{
|
||||
my_syslog(LOG_ERR, _("failed to create inotify for %s: %s"),
|
||||
ah->fname, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
while ((ent = readdir(dir_stream)))
|
||||
{
|
||||
size_t lendir = strlen(ah->fname);
|
||||
size_t lenfile = strlen(ent->d_name);
|
||||
char *path;
|
||||
|
||||
/* ignore emacs backups and dotfiles */
|
||||
if (lenfile == 0 ||
|
||||
ent->d_name[lenfile - 1] == '~' ||
|
||||
(ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
|
||||
ent->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
if ((path = whine_malloc(lendir + lenfile + 2)))
|
||||
{
|
||||
strcpy(path, ah->fname);
|
||||
strcat(path, "/");
|
||||
strcat(path, ent->d_name);
|
||||
|
||||
/* ignore non-regular files */
|
||||
if (stat(path, &buf) != -1 && S_ISREG(buf.st_mode))
|
||||
{
|
||||
if (ah->flags & AH_HOSTS)
|
||||
total_size = read_hostsfile(path, ah->index, total_size, rhash, revhashsz);
|
||||
#ifdef HAVE_DHCP
|
||||
else if (ah->flags & (AH_DHCP_HST | AH_DHCP_OPT))
|
||||
option_read_dynfile(path, ah->flags);
|
||||
#endif
|
||||
}
|
||||
|
||||
free(path);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir_stream);
|
||||
}
|
||||
}
|
||||
|
||||
int inotify_check(time_t now)
|
||||
{
|
||||
int hit = 0;
|
||||
struct hostsfile *ah;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int rc;
|
||||
char *p;
|
||||
struct resolvc *res;
|
||||
struct inotify_event *in;
|
||||
|
||||
while ((rc = read(daemon->inotifyfd, inotify_buffer, INOTIFY_SZ)) == -1 && errno == EINTR);
|
||||
|
||||
if (rc <= 0)
|
||||
break;
|
||||
|
||||
for (p = inotify_buffer; rc - (p - inotify_buffer) >= (int)sizeof(struct inotify_event); p += sizeof(struct inotify_event) + in->len)
|
||||
{
|
||||
in = (struct inotify_event*)p;
|
||||
|
||||
for (res = daemon->resolv_files; res; res = res->next)
|
||||
if (res->wd == in->wd && in->len != 0 && strcmp(res->file, in->name) == 0)
|
||||
hit = 1;
|
||||
|
||||
/* ignore emacs backups and dotfiles */
|
||||
if (in->len == 0 ||
|
||||
in->name[in->len - 1] == '~' ||
|
||||
(in->name[0] == '#' && in->name[in->len - 1] == '#') ||
|
||||
in->name[0] == '.')
|
||||
continue;
|
||||
|
||||
for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
|
||||
if (ah->wd == in->wd)
|
||||
{
|
||||
size_t lendir = strlen(ah->fname);
|
||||
char *path;
|
||||
|
||||
if ((path = whine_malloc(lendir + in->len + 2)))
|
||||
{
|
||||
strcpy(path, ah->fname);
|
||||
strcat(path, "/");
|
||||
strcat(path, in->name);
|
||||
|
||||
my_syslog(LOG_INFO, _("inotify, new or changed file %s"), path);
|
||||
|
||||
if (ah->flags & AH_HOSTS)
|
||||
{
|
||||
read_hostsfile(path, ah->index, 0, NULL, 0);
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp || daemon->doing_dhcp6)
|
||||
{
|
||||
/* Propagate the consequences of loading a new dhcp-host */
|
||||
dhcp_update_configs(daemon->dhcp_conf);
|
||||
lease_update_from_configs();
|
||||
lease_update_file(now);
|
||||
lease_update_dns(1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_DHCP
|
||||
else if (ah->flags & AH_DHCP_HST)
|
||||
{
|
||||
if (option_read_dynfile(path, AH_DHCP_HST))
|
||||
{
|
||||
/* Propagate the consequences of loading a new dhcp-host */
|
||||
dhcp_update_configs(daemon->dhcp_conf);
|
||||
lease_update_from_configs();
|
||||
lease_update_file(now);
|
||||
lease_update_dns(1);
|
||||
}
|
||||
}
|
||||
else if (ah->flags & AH_DHCP_OPT)
|
||||
option_read_dynfile(path, AH_DHCP_OPT);
|
||||
#endif
|
||||
|
||||
free(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
#endif /* INOTIFY */
|
||||
|
||||
34
src/ip6addr.h
Normal file
34
src/ip6addr.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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)
|
||||
|
||||
238
src/ipset.c
Normal file
238
src/ipset.c
Normal file
@@ -0,0 +1,238 @@
|
||||
/* 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"
|
||||
|
||||
#if defined(HAVE_IPSET) && defined(HAVE_LINUX_NETWORK)
|
||||
|
||||
#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;
|
||||
|
||||
#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 (retry_send(sendto(ipset_sock, buffer, nlh->nlmsg_len, 0,
|
||||
(struct sockaddr *)&snl, sizeof(snl))));
|
||||
|
||||
return errno == 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
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 ret = 0, af = AF_INET;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (flags & F_IPV6)
|
||||
{
|
||||
af = AF_INET6;
|
||||
/* old method only supports IPv4 */
|
||||
if (old_kernel)
|
||||
{
|
||||
errno = EAFNOSUPPORT ;
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ret != -1)
|
||||
ret = old_kernel ? old_add_to_ipset(setname, ipaddr, remove) : new_add_to_ipset(setname, ipaddr, af, remove);
|
||||
|
||||
if (ret == -1)
|
||||
my_syslog(LOG_ERR, _("failed to update ipset %s: %s"), setname, strerror(errno));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
474
src/lease.c
474
src/lease.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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
|
||||
@@ -21,21 +21,126 @@
|
||||
static struct dhcp_lease *leases = NULL, *old_leases = NULL;
|
||||
static int dns_dirty, file_dirty, leases_left;
|
||||
|
||||
void lease_init(time_t now)
|
||||
static int read_leases(time_t now, FILE *leasestream)
|
||||
{
|
||||
unsigned long ei;
|
||||
struct all_addr addr;
|
||||
struct dhcp_lease *lease;
|
||||
int clid_len, hw_len, hw_type;
|
||||
int items;
|
||||
char *domain = NULL;
|
||||
|
||||
*daemon->dhcp_buff3 = *daemon->dhcp_buff2 = '\0';
|
||||
|
||||
/* client-id max length is 255 which is 255*2 digits + 254 colons
|
||||
borrow DNS packet buffer which is always larger than 1000 bytes
|
||||
|
||||
Check various buffers are big enough for the code below */
|
||||
|
||||
#if (DHCP_BUFF_SZ < 255) || (MAXDNAME < 64) || (PACKETSZ+MAXDNAME+RRFIXEDSZ < 764)
|
||||
# error Buffer size breakage in leasefile parsing.
|
||||
#endif
|
||||
|
||||
while ((items=fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2)) == 2)
|
||||
{
|
||||
*daemon->namebuff = *daemon->dhcp_buff = *daemon->packet = '\0';
|
||||
hw_len = hw_type = clid_len = 0;
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (strcmp(daemon->dhcp_buff3, "duid") == 0)
|
||||
{
|
||||
daemon->duid_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, 130, NULL, NULL);
|
||||
if (daemon->duid_len < 0)
|
||||
return 0;
|
||||
daemon->duid = safe_malloc(daemon->duid_len);
|
||||
memcpy(daemon->duid, daemon->dhcp_buff2, daemon->duid_len);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (fscanf(leasestream, " %64s %255s %764s",
|
||||
daemon->namebuff, daemon->dhcp_buff, daemon->packet) != 3)
|
||||
return 0;
|
||||
|
||||
if (inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4))
|
||||
{
|
||||
if ((lease = lease4_allocate(addr.addr.addr4)))
|
||||
domain = get_domain(lease->addr);
|
||||
|
||||
hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
|
||||
/* For backwards compatibility, no explicit MAC address type means ether. */
|
||||
if (hw_type == 0 && hw_len != 0)
|
||||
hw_type = ARPHRD_ETHER;
|
||||
}
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6))
|
||||
{
|
||||
char *s = daemon->dhcp_buff2;
|
||||
int lease_type = LEASE_NA;
|
||||
|
||||
if (s[0] == 'T')
|
||||
{
|
||||
lease_type = LEASE_TA;
|
||||
s++;
|
||||
}
|
||||
|
||||
if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
|
||||
{
|
||||
lease_set_iaid(lease, strtoul(s, NULL, 10));
|
||||
domain = get_domain6((struct in6_addr *)lease->hwaddr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
return 0;
|
||||
|
||||
if (!lease)
|
||||
die (_("too many stored leases"), NULL, EC_MISC);
|
||||
|
||||
if (strcmp(daemon->packet, "*") != 0)
|
||||
clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
|
||||
|
||||
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet,
|
||||
hw_len, hw_type, clid_len, now, 0);
|
||||
|
||||
if (strcmp(daemon->dhcp_buff, "*") != 0)
|
||||
lease_set_hostname(lease, daemon->dhcp_buff, 0, domain, NULL);
|
||||
|
||||
ei = atol(daemon->dhcp_buff3);
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
if (ei != 0)
|
||||
lease->expires = (time_t)ei + now;
|
||||
else
|
||||
lease->expires = (time_t)0;
|
||||
lease->length = ei;
|
||||
#else
|
||||
/* strictly time_t is opaque, but this hack should work on all sane systems,
|
||||
even when sizeof(time_t) == 8 */
|
||||
lease->expires = (time_t)ei;
|
||||
#endif
|
||||
|
||||
/* set these correctly: the "old" events are generated later from
|
||||
the startup synthesised SIGHUP. */
|
||||
lease->flags &= ~(LEASE_NEW | LEASE_CHANGED);
|
||||
|
||||
*daemon->dhcp_buff3 = *daemon->dhcp_buff2 = '\0';
|
||||
}
|
||||
|
||||
return (items == 0 || items == EOF);
|
||||
}
|
||||
|
||||
void lease_init(time_t now)
|
||||
{
|
||||
FILE *leasestream;
|
||||
|
||||
|
||||
leases_left = daemon->dhcp_max;
|
||||
|
||||
|
||||
if (option_bool(OPT_LEASE_RO))
|
||||
{
|
||||
/* run "<lease_change_script> init" once to get the
|
||||
initial state of the database. If leasefile-ro is
|
||||
set without a script, we just do without any
|
||||
set without a script, we just do without any
|
||||
lease database. */
|
||||
#ifdef HAVE_SCRIPT
|
||||
if (daemon->lease_change_command)
|
||||
@@ -56,98 +161,24 @@ void lease_init(time_t now)
|
||||
{
|
||||
/* NOTE: need a+ mode to create file if it doesn't exist */
|
||||
leasestream = daemon->lease_stream = fopen(daemon->lease_file, "a+");
|
||||
|
||||
|
||||
if (!leasestream)
|
||||
die(_("cannot open or create lease file %s: %s"), daemon->lease_file, EC_FILE);
|
||||
|
||||
|
||||
/* a+ mode leaves pointer at end. */
|
||||
rewind(leasestream);
|
||||
}
|
||||
|
||||
/* client-id max length is 255 which is 255*2 digits + 254 colons
|
||||
borrow DNS packet buffer which is always larger than 1000 bytes */
|
||||
|
||||
if (leasestream)
|
||||
while (fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2) == 2)
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
if (strcmp(daemon->dhcp_buff3, "duid") == 0)
|
||||
{
|
||||
daemon->duid_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, 130, NULL, NULL);
|
||||
daemon->duid = safe_malloc(daemon->duid_len);
|
||||
memcpy(daemon->duid, daemon->dhcp_buff2, daemon->duid_len);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
if (!read_leases(now, leasestream))
|
||||
my_syslog(MS_DHCP | LOG_ERR, _("failed to parse lease database, invalid line: %s %s %s %s ..."),
|
||||
daemon->dhcp_buff3, daemon->dhcp_buff2,
|
||||
daemon->namebuff, daemon->dhcp_buff);
|
||||
|
||||
ei = atol(daemon->dhcp_buff3);
|
||||
|
||||
if (fscanf(leasestream, " %64s %255s %764s",
|
||||
daemon->namebuff, daemon->dhcp_buff, daemon->packet) != 3)
|
||||
break;
|
||||
|
||||
clid_len = 0;
|
||||
if (strcmp(daemon->packet, "*") != 0)
|
||||
clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
|
||||
|
||||
if (inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4) &&
|
||||
(lease = lease4_allocate(addr.addr.addr4)))
|
||||
{
|
||||
hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
|
||||
/* For backwards compatibility, no explict MAC address type means ether. */
|
||||
if (hw_type == 0 && hw_len != 0)
|
||||
hw_type = ARPHRD_ETHER;
|
||||
|
||||
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet,
|
||||
hw_len, hw_type, clid_len, now, 0);
|
||||
|
||||
if (strcmp(daemon->dhcp_buff, "*") != 0)
|
||||
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain(lease->addr), NULL);
|
||||
}
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6))
|
||||
{
|
||||
char *s = daemon->dhcp_buff2;
|
||||
int lease_type = LEASE_NA;
|
||||
|
||||
if (s[0] == 'T')
|
||||
{
|
||||
lease_type = LEASE_TA;
|
||||
s++;
|
||||
}
|
||||
|
||||
hw_type = atoi(s);
|
||||
|
||||
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);
|
||||
|
||||
if (strcmp(daemon->dhcp_buff, "*") != 0)
|
||||
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
break;
|
||||
|
||||
if (!lease)
|
||||
die (_("too many stored leases"), NULL, EC_MISC);
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
if (ei != 0)
|
||||
lease->expires = (time_t)ei + now;
|
||||
else
|
||||
lease->expires = (time_t)0;
|
||||
lease->length = ei;
|
||||
#else
|
||||
/* strictly time_t is opaque, but this hack should work on all sane systems,
|
||||
even when sizeof(time_t) == 8 */
|
||||
lease->expires = (time_t)ei;
|
||||
#endif
|
||||
|
||||
/* set these correctly: the "old" events are generated later from
|
||||
the startup synthesised SIGHUP. */
|
||||
lease->flags &= ~(LEASE_NEW | LEASE_CHANGED);
|
||||
}
|
||||
if (ferror(leasestream))
|
||||
die(_("failed to read lease file %s: %s"), daemon->lease_file, EC_FILE);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SCRIPT
|
||||
if (!daemon->lease_stream)
|
||||
@@ -161,6 +192,7 @@ void lease_init(time_t now)
|
||||
errno = ENOENT;
|
||||
else if (WEXITSTATUS(rc) == 126)
|
||||
errno = EACCES;
|
||||
|
||||
die(_("cannot run lease-init script %s: %s"), daemon->lease_change_command, EC_FILE);
|
||||
}
|
||||
|
||||
@@ -187,10 +219,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 +311,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 +337,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 +362,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,36 +379,51 @@ 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;
|
||||
|
||||
int prefix = netmask_length(netmask);
|
||||
|
||||
(void) label;
|
||||
(void) broadcast;
|
||||
(void) vparam;
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
|
||||
if (is_same_net(local, lease->addr, netmask))
|
||||
lease_set_interface(lease, if_index, *((time_t *)vparam));
|
||||
|
||||
if (!(lease->flags & (LEASE_TA | LEASE_NA)) &&
|
||||
is_same_net(local, lease->addr, netmask) &&
|
||||
prefix > lease->new_prefixlen)
|
||||
{
|
||||
lease->new_interface = if_index;
|
||||
lease->new_prefixlen = prefix;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#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;
|
||||
(void)vparam;
|
||||
|
||||
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))
|
||||
lease_set_interface(lease, if_index, *((time_t *)vparam));
|
||||
|
||||
if (is_same_net6(local, &lease->addr6, prefix) && prefix > lease->new_prefixlen) {
|
||||
/* save prefix length for comparison, as we might get shorter matching
|
||||
* prefix in upcoming netlink GETADDR responses
|
||||
* */
|
||||
lease->new_interface = if_index;
|
||||
lease->new_prefixlen = prefix;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -386,6 +435,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 construct 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 +456,33 @@ 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
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
lease->new_prefixlen = lease->new_interface = 0;
|
||||
|
||||
iface_enumerate(AF_INET, &now, find_interface_v4);
|
||||
#ifdef HAVE_DHCP6
|
||||
iface_enumerate(AF_INET6, &now, find_interface_v6);
|
||||
#endif
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if (lease->new_interface != 0)
|
||||
lease_set_interface(lease, lease->new_interface, now);
|
||||
}
|
||||
|
||||
#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 +492,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 +519,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 +623,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,27 +631,54 @@ 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;
|
||||
|
||||
if (clid || addr)
|
||||
{
|
||||
lease->flags |= LEASE_USED;
|
||||
return lease;
|
||||
}
|
||||
else
|
||||
lease->flags &= ~LEASE_USED;
|
||||
return lease;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
if (lease->flags & LEASE_USED)
|
||||
continue;
|
||||
|
||||
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;
|
||||
@@ -583,8 +693,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;
|
||||
}
|
||||
|
||||
@@ -603,11 +713,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;
|
||||
@@ -649,6 +759,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;
|
||||
|
||||
@@ -661,9 +772,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;
|
||||
}
|
||||
|
||||
@@ -671,8 +782,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;
|
||||
}
|
||||
@@ -680,14 +796,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
|
||||
infinite 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;
|
||||
@@ -708,9 +833,20 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, 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)
|
||||
#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, const unsigned char *hwaddr,
|
||||
const unsigned char *clid, int hw_len, int hw_type,
|
||||
int clid_len, time_t now, int force)
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
int change = force;
|
||||
@@ -718,6 +854,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 ||
|
||||
@@ -729,9 +866,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
|
||||
@@ -794,7 +928,7 @@ static void kill_name(struct dhcp_lease *lease)
|
||||
lease->hostname = lease->fqdn = NULL;
|
||||
}
|
||||
|
||||
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain)
|
||||
void lease_set_hostname(struct dhcp_lease *lease, const char *name, int auth, char *domain, char *config_domain)
|
||||
{
|
||||
struct dhcp_lease *lease_tmp;
|
||||
char *new_name = NULL, *new_fqdn = NULL;
|
||||
@@ -889,6 +1023,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;
|
||||
|
||||
@@ -917,6 +1053,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. */
|
||||
@@ -1003,18 +1141,22 @@ int do_script_run(time_t now)
|
||||
}
|
||||
|
||||
#ifdef HAVE_SCRIPT
|
||||
/* delim == -1 -> delim = 0, but embedded 0s, creating extra records, are OK. */
|
||||
void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* check for embeded NULLs */
|
||||
for (i = 0; i < len; i++)
|
||||
if (data[i] == 0)
|
||||
{
|
||||
len = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (delim == -1)
|
||||
delim = 0;
|
||||
else
|
||||
/* check for embedded NULLs */
|
||||
for (i = 0; i < len; i++)
|
||||
if (data[i] == 0)
|
||||
{
|
||||
len = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((lease->extradata_size - lease->extradata_len) < (len + 1))
|
||||
{
|
||||
size_t newsz = lease->extradata_len + len + 100;
|
||||
|
||||
21
src/log.c
21
src/log.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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
|
||||
@@ -154,7 +154,7 @@ static void log_write(void)
|
||||
|
||||
while (entries)
|
||||
{
|
||||
/* The data in the payoad is written with a terminating zero character
|
||||
/* The data in the payload is written with a terminating zero character
|
||||
and the length reflects this. For a stream connection we need to
|
||||
send the zero as a record terminator, but this isn't done for a
|
||||
datagram connection, so treat the length as one less than reality
|
||||
@@ -288,7 +288,9 @@ void my_syslog(int priority, const char *format, ...)
|
||||
func = "-tftp";
|
||||
else if ((LOG_FACMASK & priority) == MS_DHCP)
|
||||
func = "-dhcp";
|
||||
|
||||
else if ((LOG_FACMASK & priority) == MS_SCRIPT)
|
||||
func = "-script";
|
||||
|
||||
#ifdef LOG_PRI
|
||||
priority = LOG_PRI(priority);
|
||||
#else
|
||||
@@ -421,25 +423,22 @@ void my_syslog(int priority, const char *format, ...)
|
||||
}
|
||||
}
|
||||
|
||||
void set_log_writer(fd_set *set, int *maxfdp)
|
||||
void set_log_writer(void)
|
||||
{
|
||||
if (entries && log_fd != -1 && connection_good)
|
||||
{
|
||||
FD_SET(log_fd, set);
|
||||
bump_maxfd(log_fd, maxfdp);
|
||||
}
|
||||
poll_listen(log_fd, POLLOUT);
|
||||
}
|
||||
|
||||
void check_log_writer(fd_set *set)
|
||||
void check_log_writer(int force)
|
||||
{
|
||||
if (log_fd != -1 && (!set || FD_ISSET(log_fd, set)))
|
||||
if (log_fd != -1 && (force || poll_check(log_fd, POLLOUT)))
|
||||
log_write();
|
||||
}
|
||||
|
||||
void flush_log(void)
|
||||
{
|
||||
/* write until queue empty, but don't loop forever if there's
|
||||
no connection to the syslog in existance */
|
||||
no connection to the syslog in existence */
|
||||
while (log_fd != -1)
|
||||
{
|
||||
struct timespec waiter;
|
||||
|
||||
117
src/loop.c
Normal file
117
src/loop.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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_LOOP
|
||||
static ssize_t loop_make_probe(u32 uid);
|
||||
|
||||
void loop_send_probes()
|
||||
{
|
||||
struct server *serv;
|
||||
|
||||
if (!option_bool(OPT_LOOP_DETECT))
|
||||
return;
|
||||
|
||||
/* Loop through all upstream servers not for particular domains, and send a query to that server which is
|
||||
identifiable, via the uid. If we see that query back again, then the server is looping, and we should not use it. */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (!(serv->flags &
|
||||
(SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_LOOP)))
|
||||
{
|
||||
ssize_t len = loop_make_probe(serv->uid);
|
||||
int fd;
|
||||
struct randfd *rfd = NULL;
|
||||
|
||||
if (serv->sfd)
|
||||
fd = serv->sfd->fd;
|
||||
else
|
||||
{
|
||||
if (!(rfd = allocate_rfd(serv->addr.sa.sa_family)))
|
||||
continue;
|
||||
fd = rfd->fd;
|
||||
}
|
||||
|
||||
while (retry_send(sendto(fd, daemon->packet, len, 0,
|
||||
&serv->addr.sa, sa_len(&serv->addr))));
|
||||
|
||||
free_rfd(rfd);
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t loop_make_probe(u32 uid)
|
||||
{
|
||||
struct dns_header *header = (struct dns_header *)daemon->packet;
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
|
||||
/* packet buffer overwritten */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
header->id = rand16();
|
||||
header->ancount = header->nscount = header->arcount = htons(0);
|
||||
header->qdcount = htons(1);
|
||||
header->hb3 = HB3_RD;
|
||||
header->hb4 = 0;
|
||||
SET_OPCODE(header, QUERY);
|
||||
|
||||
*p++ = 8;
|
||||
sprintf((char *)p, "%.8x", uid);
|
||||
p += 8;
|
||||
*p++ = strlen(LOOP_TEST_DOMAIN);
|
||||
strcpy((char *)p, LOOP_TEST_DOMAIN); /* Add terminating zero */
|
||||
p += strlen(LOOP_TEST_DOMAIN) + 1;
|
||||
|
||||
PUTSHORT(LOOP_TEST_TYPE, p);
|
||||
PUTSHORT(C_IN, p);
|
||||
|
||||
return p - (unsigned char *)header;
|
||||
}
|
||||
|
||||
|
||||
int detect_loop(char *query, int type)
|
||||
{
|
||||
int i;
|
||||
u32 uid;
|
||||
struct server *serv;
|
||||
|
||||
if (!option_bool(OPT_LOOP_DETECT))
|
||||
return 0;
|
||||
|
||||
if (type != LOOP_TEST_TYPE ||
|
||||
strlen(LOOP_TEST_DOMAIN) + 9 != strlen(query) ||
|
||||
strstr(query, LOOP_TEST_DOMAIN) != query + 9)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
if (!isxdigit(query[i]))
|
||||
return 0;
|
||||
|
||||
uid = strtol(query, NULL, 16);
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (!(serv->flags &
|
||||
(SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_LOOP)) &&
|
||||
uid == serv->uid)
|
||||
{
|
||||
serv->flags |= SERV_LOOP;
|
||||
check_servers(); /* log new state */
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
160
src/netlink.c
160
src/netlink.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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
|
||||
@@ -38,8 +38,7 @@
|
||||
static struct iovec iov;
|
||||
static u32 netlink_pid;
|
||||
|
||||
static int nl_async(struct nlmsghdr *h);
|
||||
static void nl_routechange(struct nlmsghdr *h);
|
||||
static void nl_async(struct nlmsghdr *h);
|
||||
|
||||
void netlink_init(void)
|
||||
{
|
||||
@@ -51,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
|
||||
|
||||
@@ -70,7 +73,7 @@ void netlink_init(void)
|
||||
}
|
||||
|
||||
if (daemon->netlinkfd == -1 ||
|
||||
getsockname(daemon->netlinkfd, (struct sockaddr *)&addr, &slen) == 1)
|
||||
getsockname(daemon->netlinkfd, (struct sockaddr *)&addr, &slen) == -1)
|
||||
die(_("cannot create netlink socket: %s"), NULL, EC_MISC);
|
||||
|
||||
/* save pid assigned by bind() and retrieved by getsockname() */
|
||||
@@ -139,7 +142,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
struct nlmsghdr *h;
|
||||
ssize_t len;
|
||||
static unsigned int seq = 0;
|
||||
int callback_ok = 1, newaddr = 0;
|
||||
int callback_ok = 1;
|
||||
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
@@ -166,10 +169,10 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
req.g.rtgen_family = family;
|
||||
|
||||
/* Don't block in recvfrom if send fails */
|
||||
while((len = sendto(daemon->netlinkfd, (void *)&req, sizeof(req), 0,
|
||||
(struct sockaddr *)&addr, sizeof(addr))) == -1 && retry_send());
|
||||
|
||||
if (len == -1)
|
||||
while(retry_send(sendto(daemon->netlinkfd, (void *)&req, sizeof(req), 0,
|
||||
(struct sockaddr *)&addr, sizeof(addr))));
|
||||
|
||||
if (errno != 0)
|
||||
return 0;
|
||||
|
||||
while (1)
|
||||
@@ -185,24 +188,19 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
}
|
||||
|
||||
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
|
||||
if (h->nlmsg_seq != seq || h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
|
||||
if (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;
|
||||
nl_async(h);
|
||||
}
|
||||
else if (h->nlmsg_seq != seq)
|
||||
{
|
||||
/* May be part of incomplete response to previous request after
|
||||
ENOBUFS. Drop it. */
|
||||
continue;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
return callback_ok;
|
||||
}
|
||||
return callback_ok;
|
||||
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
|
||||
{
|
||||
struct ifaddrmsg *ifa = NLMSG_DATA(h);
|
||||
@@ -214,8 +212,10 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
if (ifa->ifa_family == AF_INET)
|
||||
{
|
||||
struct in_addr netmask, addr, broadcast;
|
||||
|
||||
netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
|
||||
char *label = NULL;
|
||||
|
||||
netmask.s_addr = htonl(~(in_addr_t)0 << (32 - ifa->ifa_prefixlen));
|
||||
|
||||
addr.s_addr = 0;
|
||||
broadcast.s_addr = 0;
|
||||
|
||||
@@ -225,29 +225,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
|
||||
@@ -274,7 +294,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
}
|
||||
|
||||
if (inaddr && mac && callback_ok)
|
||||
if (!(neigh->ndm_state & (NUD_NOARP | NUD_INCOMPLETE | NUD_FAILED)) &&
|
||||
inaddr && mac && callback_ok)
|
||||
if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
|
||||
callback_ok = 0;
|
||||
}
|
||||
@@ -310,7 +331,7 @@ void netlink_multicast(void)
|
||||
{
|
||||
ssize_t len;
|
||||
struct nlmsghdr *h;
|
||||
int flags, newaddr = 0;
|
||||
int flags;
|
||||
|
||||
/* don't risk blocking reading netlink messages here. */
|
||||
if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||
|
||||
@@ -319,82 +340,35 @@ 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))
|
||||
newaddr = 1;
|
||||
nl_async(h);
|
||||
|
||||
/* restore non-blocking status */
|
||||
fcntl(daemon->netlinkfd, F_SETFL, flags);
|
||||
|
||||
if (newaddr)
|
||||
{
|
||||
enumerate_interfaces();
|
||||
create_bound_listeners(0);
|
||||
}
|
||||
}
|
||||
|
||||
static int nl_async(struct nlmsghdr *h)
|
||||
static void nl_async(struct nlmsghdr *h)
|
||||
{
|
||||
if (h->nlmsg_type == NLMSG_ERROR)
|
||||
{
|
||||
struct nlmsgerr *err = NLMSG_DATA(h);
|
||||
my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
|
||||
return 0;
|
||||
if (err->error != 0)
|
||||
my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
|
||||
}
|
||||
else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE)
|
||||
{
|
||||
nl_routechange(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);
|
||||
}
|
||||
return 1; /* clever bind mode - rescan */
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We arrange to receive netlink multicast messages whenever the network route is added.
|
||||
If this happens and we still have a DNS packet in the buffer, we re-send it.
|
||||
This helps on DoD links, where frequently the packet which triggers dialling is
|
||||
a DNS query, which then gets lost. By re-sending, we can avoid the lookup
|
||||
failing. */
|
||||
static void nl_routechange(struct nlmsghdr *h)
|
||||
{
|
||||
struct rtmsg *rtm = NLMSG_DATA(h);
|
||||
int fd;
|
||||
|
||||
if (rtm->rtm_type != RTN_UNICAST || rtm->rtm_scope != RT_SCOPE_LINK)
|
||||
return;
|
||||
|
||||
/* Force re-reading resolv file right now, for luck. */
|
||||
daemon->last_resolv = 0;
|
||||
|
||||
if (daemon->srv_save)
|
||||
{
|
||||
if (daemon->srv_save->sfd)
|
||||
fd = daemon->srv_save->sfd->fd;
|
||||
else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
|
||||
fd = daemon->rfd_save->fd;
|
||||
else
|
||||
return;
|
||||
/* We arrange to receive netlink multicast messages whenever the network route is added.
|
||||
If this happens and we still have a DNS packet in the buffer, we re-send it.
|
||||
This helps on DoD links, where frequently the packet which triggers dialling is
|
||||
a DNS query, which then gets lost. By re-sending, we can avoid the lookup
|
||||
failing. */
|
||||
struct rtmsg *rtm = NLMSG_DATA(h);
|
||||
|
||||
while(sendto(fd, daemon->packet, daemon->packet_len, 0,
|
||||
&daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send());
|
||||
if (rtm->rtm_type == RTN_UNICAST && rtm->rtm_scope == RT_SCOPE_LINK)
|
||||
queue_event(EVENT_NEWROUTE);
|
||||
}
|
||||
else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
|
||||
queue_event(EVENT_NEWADDR);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
1209
src/network.c
1209
src/network.c
File diff suppressed because it is too large
Load Diff
2476
src/option.c
2476
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-2016 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
|
||||
@@ -29,9 +29,19 @@ void end_opt6(int container)
|
||||
PUTSHORT(len, p);
|
||||
}
|
||||
|
||||
void reset_counter(void)
|
||||
{
|
||||
/* Clear out buffer when starting from beginning */
|
||||
if (daemon->outpacket.iov_base)
|
||||
memset(daemon->outpacket.iov_base, 0, daemon->outpacket.iov_len);
|
||||
|
||||
save_counter(0);
|
||||
}
|
||||
|
||||
int save_counter(int newval)
|
||||
{
|
||||
int ret = outpacket_counter;
|
||||
|
||||
if (newval != -1)
|
||||
outpacket_counter = newval;
|
||||
|
||||
@@ -70,9 +80,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;
|
||||
}
|
||||
|
||||
|
||||
125
src/poll.c
Normal file
125
src/poll.c
Normal file
@@ -0,0 +1,125 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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"
|
||||
|
||||
/* Wrapper for poll(). Allocates and extends array of struct pollfds,
|
||||
keeps them in fd order so that we can set and test conditions on
|
||||
fd using a simple but efficient binary chop. */
|
||||
|
||||
/* poll_reset()
|
||||
poll_listen(fd, event)
|
||||
.
|
||||
.
|
||||
poll_listen(fd, event);
|
||||
|
||||
hits = do_poll(timeout);
|
||||
|
||||
if (poll_check(fd, event)
|
||||
.
|
||||
.
|
||||
|
||||
if (poll_check(fd, event)
|
||||
.
|
||||
.
|
||||
|
||||
event is OR of POLLIN, POLLOUT, POLLERR, etc
|
||||
*/
|
||||
|
||||
static struct pollfd *pollfds = NULL;
|
||||
static nfds_t nfds, arrsize = 0;
|
||||
|
||||
/* Binary search. Returns either the pollfd with fd, or
|
||||
if the fd doesn't match, or return equals nfds, the entry
|
||||
to the left of which a new record should be inserted. */
|
||||
static nfds_t fd_search(int fd)
|
||||
{
|
||||
nfds_t left, right, mid;
|
||||
|
||||
if ((right = nfds) == 0)
|
||||
return 0;
|
||||
|
||||
left = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (right == left + 1)
|
||||
return (pollfds[left].fd >= fd) ? left : right;
|
||||
|
||||
mid = (left + right)/2;
|
||||
|
||||
if (pollfds[mid].fd > fd)
|
||||
right = mid;
|
||||
else
|
||||
left = mid;
|
||||
}
|
||||
}
|
||||
|
||||
void poll_reset(void)
|
||||
{
|
||||
nfds = 0;
|
||||
}
|
||||
|
||||
int do_poll(int timeout)
|
||||
{
|
||||
return poll(pollfds, nfds, timeout);
|
||||
}
|
||||
|
||||
int poll_check(int fd, short event)
|
||||
{
|
||||
nfds_t i = fd_search(fd);
|
||||
|
||||
if (i < nfds && pollfds[i].fd == fd)
|
||||
return pollfds[i].revents & event;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void poll_listen(int fd, short event)
|
||||
{
|
||||
nfds_t i = fd_search(fd);
|
||||
|
||||
if (i < nfds && pollfds[i].fd == fd)
|
||||
pollfds[i].events |= event;
|
||||
else
|
||||
{
|
||||
if (arrsize != nfds)
|
||||
memmove(&pollfds[i+1], &pollfds[i], (nfds - i) * sizeof(struct pollfd));
|
||||
else
|
||||
{
|
||||
/* Array too small, extend. */
|
||||
struct pollfd *new;
|
||||
|
||||
arrsize = (arrsize == 0) ? 64 : arrsize * 2;
|
||||
|
||||
if (!(new = whine_malloc(arrsize * sizeof(struct pollfd))))
|
||||
return;
|
||||
|
||||
if (pollfds)
|
||||
{
|
||||
memcpy(new, pollfds, i * sizeof(struct pollfd));
|
||||
memcpy(&new[i+1], &pollfds[i], (nfds - i) * sizeof(struct pollfd));
|
||||
free(pollfds);
|
||||
}
|
||||
|
||||
pollfds = new;
|
||||
}
|
||||
|
||||
pollfds[i].fd = fd;
|
||||
pollfds[i].events = event;
|
||||
nfds++;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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;
|
||||
@@ -42,6 +49,8 @@ struct prefix_opt {
|
||||
#define ICMP6_OPT_SOURCE_MAC 1
|
||||
#define ICMP6_OPT_PREFIX 3
|
||||
#define ICMP6_OPT_MTU 5
|
||||
#define ICMP6_OPT_ADV_INTERVAL 7
|
||||
#define ICMP6_OPT_RT_INFO 24
|
||||
#define ICMP6_OPT_RDNSS 25
|
||||
#define ICMP6_OPT_DNSSL 31
|
||||
|
||||
|
||||
750
src/radv.c
750
src/radv.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2016 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,46 @@
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
struct ra_param {
|
||||
int ind, managed, other, found_context, first;
|
||||
time_t now;
|
||||
int ind, managed, other, first, adv_router;
|
||||
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, prio;
|
||||
struct dhcp_context *found_context;
|
||||
};
|
||||
|
||||
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);
|
||||
struct alias_param {
|
||||
int iface;
|
||||
struct dhcp_bridge *bridge;
|
||||
int num_alias_ifs;
|
||||
int max_alias_ifs;
|
||||
int *alias_ifs;
|
||||
};
|
||||
|
||||
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest);
|
||||
static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_addr *dest,
|
||||
int send_iface);
|
||||
static int send_ra_to_aliases(int index, unsigned int type, char *mac, size_t maclen, void *parm);
|
||||
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)
|
||||
{
|
||||
@@ -61,15 +82,20 @@ void ra_init(time_t now)
|
||||
/* ensure this is around even if we're not doing DHCPv6 */
|
||||
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)
|
||||
/* See if we're guessing SLAAC addresses, if so we need to receive ping replies */
|
||||
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,27 +111,30 @@ void ra_init(time_t now)
|
||||
|
||||
daemon->icmp6fd = fd;
|
||||
|
||||
ra_start_unsolicted(now, NULL);
|
||||
if (daemon->doing_ra)
|
||||
ra_start_unsolicited(now, NULL);
|
||||
}
|
||||
|
||||
void ra_start_unsolicted(time_t now, struct dhcp_context *context)
|
||||
void ra_start_unsolicited(time_t now, struct dhcp_context *context)
|
||||
{
|
||||
/* init timers so that we do ra's for some/all soon. some ra_times will end up zeroed
|
||||
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;
|
||||
@@ -119,7 +148,6 @@ void icmp6_packet(void)
|
||||
struct sockaddr_in6 from;
|
||||
unsigned char *packet;
|
||||
struct iname *tmp;
|
||||
struct dhcp_context *context;
|
||||
|
||||
/* Note: use outpacket for input buffer */
|
||||
msg.msg_control = control_u.control6;
|
||||
@@ -150,27 +178,22 @@ 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;
|
||||
|
||||
/* weird libvirt-inspired access control */
|
||||
for (context = daemon->ra_contexts ? daemon->ra_contexts : daemon->dhcp6;
|
||||
context; context = context->next)
|
||||
if (!context->interface || strcmp(context->interface, interface) == 0)
|
||||
break;
|
||||
|
||||
if (!context || packet[1] != 0)
|
||||
if (packet[1] != 0)
|
||||
return;
|
||||
|
||||
|
||||
if (packet[0] == ICMP6_ECHO_REPLY)
|
||||
lease_ping_reply(&from.sin6_addr, packet, interface);
|
||||
else if (packet[0] == ND_ROUTER_SOLICIT)
|
||||
{
|
||||
char *mac = "";
|
||||
struct dhcp_bridge *bridge, *alias;
|
||||
|
||||
/* look for link-layer address option for logging */
|
||||
if (sz >= 16 && packet[8] == ICMP6_OPT_SOURCE_MAC && (packet[9] * 8) + 8 <= sz)
|
||||
@@ -179,67 +202,231 @@ void icmp6_packet(void)
|
||||
mac = daemon->namebuff;
|
||||
}
|
||||
|
||||
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);
|
||||
if (!option_bool(OPT_QUIET_RA))
|
||||
my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
|
||||
|
||||
/* If the incoming interface is an alias of some other one (as
|
||||
specified by the --bridge-interface option), send an RA using
|
||||
the context of the aliased interface. */
|
||||
for (bridge = daemon->bridges; bridge; bridge = bridge->next)
|
||||
{
|
||||
int bridge_index = if_nametoindex(bridge->iface);
|
||||
if (bridge_index)
|
||||
{
|
||||
for (alias = bridge->alias; alias; alias = alias->next)
|
||||
if (wildcard_matchn(alias->iface, interface, IF_NAMESIZE))
|
||||
{
|
||||
/* Send an RA on if_index with information from
|
||||
bridge_index. */
|
||||
send_ra_alias(now, bridge_index, bridge->iface, NULL, if_index);
|
||||
break;
|
||||
}
|
||||
if (alias)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the incoming interface wasn't an alias, send an RA using
|
||||
the context of the incoming interface. */
|
||||
if (!bridge)
|
||||
/* source address may not be valid in solicit request. */
|
||||
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_alias(time_t now, int iface, char *iface_name, struct in6_addr *dest, int send_iface)
|
||||
{
|
||||
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;
|
||||
|
||||
save_counter(0);
|
||||
ra = expand(sizeof(struct ra_packet));
|
||||
struct ra_interface *ra_param = find_iface_param(iface_name);
|
||||
int done_dns = 0, old_prefix = 0, mtu = 0;
|
||||
unsigned int min_pref_time;
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
FILE *f;
|
||||
#endif
|
||||
|
||||
parm.ind = iface;
|
||||
parm.managed = 0;
|
||||
parm.other = 0;
|
||||
parm.found_context = NULL;
|
||||
parm.adv_router = 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);
|
||||
parm.prio = calc_prio(ra_param);
|
||||
|
||||
reset_counter();
|
||||
|
||||
if (!(ra = expand(sizeof(struct ra_packet))))
|
||||
return;
|
||||
|
||||
ra->type = ND_ROUTER_ADVERT;
|
||||
ra->code = 0;
|
||||
ra->hop_limit = hop_limit;
|
||||
ra->flags = 0x00;
|
||||
ra->lifetime = htons(1800); /* AdvDefaultLifetime*/
|
||||
ra->flags = parm.prio;
|
||||
ra->lifetime = htons(calc_lifetime(ra_param));
|
||||
ra->reachable_time = 0;
|
||||
ra->retrans_time = 0;
|
||||
|
||||
parm.ind = iface;
|
||||
parm.managed = 0;
|
||||
parm.other = 0;
|
||||
parm.found_context = 0;
|
||||
parm.if_name = iface_name;
|
||||
parm.first = 1;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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 */
|
||||
|
||||
/* If this context held the timeout, and there's another context in use
|
||||
transfer the timeout there. */
|
||||
if (context->ra_time != 0 && parm.found_context && parm.found_context->ra_time == 0)
|
||||
new_timeout(parm.found_context, iface_name, now);
|
||||
|
||||
*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)
|
||||
{
|
||||
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, set
|
||||
"on-link" unless "off-link" was specified */
|
||||
opt->flags = (do_slaac ? 0x40 : 0) |
|
||||
((context->flags & CONTEXT_RA_OFF_LINK) ? 0 : 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;
|
||||
|
||||
/* If we're sending router address instead of prefix in at least on prefix,
|
||||
include the advertisement interval option. */
|
||||
if (parm.adv_router)
|
||||
{
|
||||
put_opt6_char(ICMP6_OPT_ADV_INTERVAL);
|
||||
put_opt6_char(1);
|
||||
put_opt6_short(0);
|
||||
/* interval value is in milliseconds */
|
||||
put_opt6_long(1000 * calc_interval(find_iface_param(iface_name)));
|
||||
}
|
||||
|
||||
/* Set the MTU from ra_param if any, an MTU of 0 mean automatic for linux, */
|
||||
/* an MTU of -1 prevents the option from being sent. */
|
||||
if (ra_param)
|
||||
mtu = ra_param->mtu;
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* Note that IPv6 MTU is not neccessarily the same as the IPv4 MTU
|
||||
available from SIOCGIFMTU */
|
||||
if (mtu == 0)
|
||||
{
|
||||
char *mtu_name = ra_param ? ra_param->mtu_name : NULL;
|
||||
sprintf(daemon->namebuff, "/proc/sys/net/ipv6/conf/%s/mtu", mtu_name ? : iface_name);
|
||||
if ((f = fopen(daemon->namebuff, "r")))
|
||||
{
|
||||
if (fgets(daemon->namebuff, MAXDNAME, f))
|
||||
mtu = atoi(daemon->namebuff);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (mtu > 0)
|
||||
{
|
||||
put_opt6_char(ICMP6_OPT_MTU);
|
||||
put_opt6_char(1);
|
||||
put_opt6_short(0);
|
||||
put_opt6_long(ifr.ifr_mtu);
|
||||
put_opt6_long(mtu);
|
||||
}
|
||||
|
||||
iface_enumerate(AF_LOCAL, &iface, add_lla);
|
||||
iface_enumerate(AF_LOCAL, &send_iface, add_lla);
|
||||
|
||||
/* RDNSS, RFC 6106, use relevant DHCP6 options */
|
||||
(void)option_filter(parm.tags, NULL, daemon->dhcp_opts6);
|
||||
@@ -254,22 +441,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)
|
||||
@@ -279,7 +492,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 */
|
||||
@@ -288,13 +501,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);
|
||||
}
|
||||
|
||||
@@ -319,42 +532,66 @@ 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, &send_iface, sizeof(send_iface));
|
||||
}
|
||||
|
||||
send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0),
|
||||
(union mysockaddr *)&addr, (struct all_addr *)&parm.link_local, iface);
|
||||
while (retry_send(sendto(daemon->icmp6fd, daemon->outpacket.iov_base,
|
||||
save_counter(-1), 0, (struct sockaddr *)&addr,
|
||||
sizeof(addr))));
|
||||
|
||||
}
|
||||
|
||||
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest)
|
||||
{
|
||||
/* Send an RA on the same interface that the RA content is based
|
||||
on. */
|
||||
send_ra_alias(now, iface, iface_name, dest, iface);
|
||||
}
|
||||
|
||||
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;
|
||||
int adv_router = 0;
|
||||
int off_link = 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))
|
||||
{
|
||||
if ((context->flags &
|
||||
(CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
|
||||
context->saved_valid = valid;
|
||||
|
||||
if (context->flags & CONTEXT_RA)
|
||||
{
|
||||
do_slaac = 1;
|
||||
if (context->flags & CONTEXT_DHCP)
|
||||
@@ -373,12 +610,30 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
param->other = 1;
|
||||
}
|
||||
|
||||
/* find floor time */
|
||||
/* Configured to advertise router address, not prefix. See RFC 3775 7.2
|
||||
In this case we do all addresses associated with a context,
|
||||
hence the real_prefix setting here. */
|
||||
if (context->flags & CONTEXT_RA_ROUTER)
|
||||
{
|
||||
adv_router = 1;
|
||||
param->adv_router = 1;
|
||||
real_prefix = context->prefix;
|
||||
}
|
||||
|
||||
/* find floor time, don't reduce below 3 * RA interval. */
|
||||
if (time > context->lease_time)
|
||||
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)
|
||||
@@ -390,44 +645,81 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
/* subsequent prefixes on the same interface
|
||||
and subsequent instances of this prefix don't need timers.
|
||||
Be careful not to find the same prefix twice with different
|
||||
addresses. */
|
||||
addresses unless we're advertising the actual addresses. */
|
||||
if (!(context->flags & CONTEXT_RA_DONE))
|
||||
{
|
||||
if (!param->first)
|
||||
context->ra_time = 0;
|
||||
context->flags |= CONTEXT_RA_DONE;
|
||||
do_prefix = 1;
|
||||
real_prefix = context->prefix;
|
||||
off_link = (context->flags & CONTEXT_RA_OFF_LINK);
|
||||
}
|
||||
|
||||
param->first = 0;
|
||||
param->found_context = 1;
|
||||
param->first = 0;
|
||||
/* found_context is the _last_ one we found, so if there's
|
||||
more than one, it's not the first. */
|
||||
param->found_context = context;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
if (!adv_router)
|
||||
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;
|
||||
/* autonomous only if we're not doing dhcp */
|
||||
opt->flags = do_slaac ? 0x40 : 0x00;
|
||||
opt->valid_lifetime = htonl(time);
|
||||
opt->preferred_lifetime = htonl(deprecate ? 0 : time);
|
||||
opt->prefix_len = real_prefix;
|
||||
/* autonomous only if we're not doing dhcp, set
|
||||
"on-link" unless "off-link" was specified */
|
||||
opt->flags = (off_link ? 0 : 0x80);
|
||||
if (do_slaac)
|
||||
opt->flags |= 0x40;
|
||||
if (adv_router)
|
||||
opt->flags |= 0x20;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -461,14 +753,15 @@ time_t periodic_ra(time_t now)
|
||||
struct search_param param;
|
||||
struct dhcp_context *context;
|
||||
time_t next_event;
|
||||
char interface[IF_NAMESIZE+1];
|
||||
|
||||
struct alias_param aparam;
|
||||
|
||||
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)
|
||||
@@ -482,52 +775,223 @@ 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 satisfy it. */
|
||||
context->ra_time = 0;
|
||||
else if (indextoname(daemon->icmp6fd, param.iface, interface))
|
||||
send_ra(param.iface, interface, NULL);
|
||||
}
|
||||
|
||||
|
||||
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 && wildcard_match(tmp->name, param.name))
|
||||
break;
|
||||
if (!tmp)
|
||||
{
|
||||
send_ra(now, param.iface, param.name, NULL);
|
||||
|
||||
/* Also send on all interfaces that are aliases of this
|
||||
one. */
|
||||
for (aparam.bridge = daemon->bridges;
|
||||
aparam.bridge;
|
||||
aparam.bridge = aparam.bridge->next)
|
||||
if ((int)if_nametoindex(aparam.bridge->iface) == param.iface)
|
||||
{
|
||||
/* Count the number of alias interfaces for this
|
||||
'bridge', by calling iface_enumerate with
|
||||
send_ra_to_aliases and NULL alias_ifs. */
|
||||
aparam.iface = param.iface;
|
||||
aparam.alias_ifs = NULL;
|
||||
aparam.num_alias_ifs = 0;
|
||||
iface_enumerate(AF_LOCAL, &aparam, send_ra_to_aliases);
|
||||
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s => %d alias(es)",
|
||||
param.name, daemon->addrbuff, aparam.num_alias_ifs);
|
||||
|
||||
/* Allocate memory to store the alias interface
|
||||
indices. */
|
||||
aparam.alias_ifs = (int *)whine_malloc(aparam.num_alias_ifs *
|
||||
sizeof(int));
|
||||
if (aparam.alias_ifs)
|
||||
{
|
||||
/* Use iface_enumerate again to get the alias
|
||||
interface indices, then send on each of
|
||||
those. */
|
||||
aparam.max_alias_ifs = aparam.num_alias_ifs;
|
||||
aparam.num_alias_ifs = 0;
|
||||
iface_enumerate(AF_LOCAL, &aparam, send_ra_to_aliases);
|
||||
for (; aparam.num_alias_ifs; aparam.num_alias_ifs--)
|
||||
{
|
||||
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s => i/f %d",
|
||||
param.name, daemon->addrbuff,
|
||||
aparam.alias_ifs[aparam.num_alias_ifs - 1]);
|
||||
send_ra_alias(now,
|
||||
param.iface,
|
||||
param.name,
|
||||
NULL,
|
||||
aparam.alias_ifs[aparam.num_alias_ifs - 1]);
|
||||
}
|
||||
free(aparam.alias_ifs);
|
||||
}
|
||||
|
||||
/* The source interface can only appear in at most
|
||||
one --bridge-interface. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return next_event;
|
||||
}
|
||||
|
||||
static int send_ra_to_aliases(int index, unsigned int type, char *mac, size_t maclen, void *parm)
|
||||
{
|
||||
struct alias_param *aparam = (struct alias_param *)parm;
|
||||
char ifrn_name[IFNAMSIZ];
|
||||
struct dhcp_bridge *alias;
|
||||
|
||||
(void)type;
|
||||
(void)mac;
|
||||
(void)maclen;
|
||||
|
||||
if (if_indextoname(index, ifrn_name))
|
||||
for (alias = aparam->bridge->alias; alias; alias = alias->next)
|
||||
if (wildcard_matchn(alias->iface, ifrn_name, IFNAMSIZ))
|
||||
{
|
||||
if (aparam->alias_ifs && (aparam->num_alias_ifs < aparam->max_alias_ifs))
|
||||
aparam->alias_ifs[aparam->num_alias_ifs] = index;
|
||||
aparam->num_alias_ifs++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
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 zap other contexts on the same interface
|
||||
so they don't timeout independently .*/
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
return 0; /* found, abort */
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
||||
1131
src/rfc1035.c
1131
src/rfc1035.c
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user