Compare commits
2293 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8f66f4fda | ||
|
|
629107bd6d | ||
|
|
05464a173b | ||
|
|
ae3d3d971e | ||
|
|
d1845782d6 | ||
|
|
edb5f85fd1 | ||
|
|
cef74423e2 | ||
|
|
959dead673 | ||
|
|
eb60168382 | ||
|
|
57a2f5778c | ||
|
|
7d5fbe7da3 | ||
|
|
ded935be37 | ||
|
|
aa9b71c681 | ||
|
|
e497f3f2c8 | ||
|
|
ee09f0655c | ||
|
|
1e83316e06 | ||
|
|
9a566c0913 | ||
|
|
06e2d479c9 | ||
|
|
b52d1d2017 | ||
|
|
18195e7bb2 | ||
|
|
d81b1d76a0 | ||
|
|
1677c6e10b | ||
|
|
ff30fa4b91 | ||
|
|
c91c66ee63 | ||
|
|
fc9f6985ab | ||
|
|
ea5b0e64e2 | ||
|
|
e775264539 | ||
|
|
d976d94e3d | ||
|
|
3034746748 | ||
|
|
3ceea9e755 | ||
|
|
dfcef19fb4 | ||
|
|
052aa0fcf3 | ||
|
|
f74b74e521 | ||
|
|
c9342cb556 | ||
|
|
2b844b8c83 | ||
|
|
65e9a8957c | ||
|
|
da868a2fbe | ||
|
|
bceb5287b9 | ||
|
|
84445dec26 | ||
|
|
c70b92b2a4 | ||
|
|
57e582492b | ||
|
|
ec8f3e65c1 | ||
|
|
15841f187d | ||
|
|
ade97495e6 | ||
|
|
2b19285724 | ||
|
|
a444715bf0 | ||
|
|
14e81b6976 | ||
|
|
6ce7f2d55a | ||
|
|
287d6bc88d | ||
|
|
c378d2c1de | ||
|
|
5846f749e5 | ||
|
|
c9a4240ec4 | ||
|
|
e7b87dee85 | ||
|
|
90b248582c | ||
|
|
ebef27f321 | ||
|
|
1861a881eb | ||
|
|
96bdb42d40 | ||
|
|
c7a909ad65 | ||
|
|
baf3c57af5 | ||
|
|
e48a2af4f5 | ||
|
|
91b800cc62 | ||
|
|
075e4a56b7 | ||
|
|
48658ebc54 | ||
|
|
692ed0dd32 | ||
|
|
43805c1859 | ||
|
|
4fbe1add95 | ||
|
|
57c7ae8fc0 | ||
|
|
d1008215dc | ||
|
|
b0aa604fcc | ||
|
|
8ddabd11bc | ||
|
|
98189ff988 | ||
|
|
e86d53c438 | ||
|
|
e127a972d1 | ||
|
|
a458c2bfb0 | ||
|
|
9e67099ce7 | ||
|
|
cfa1313e1f | ||
|
|
e3a2c8dadf | ||
|
|
95b74a7acf | ||
|
|
ae57f84061 | ||
|
|
0620309b73 | ||
|
|
942a35f517 | ||
|
|
83658efbf4 | ||
|
|
b0b4d90b6a | ||
|
|
bdce03f928 | ||
|
|
d390dc0338 | ||
|
|
105c25e561 | ||
|
|
67e07b7fe8 | ||
|
|
f5659b406b | ||
|
|
484fea238a | ||
|
|
1e587bec57 | ||
|
|
581c201aa8 | ||
|
|
5487f6979e | ||
|
|
99f12e3541 | ||
|
|
7c1212e3d1 | ||
|
|
0ccbdf8087 | ||
|
|
57f0489f38 | ||
|
|
3e659bd4ec | ||
|
|
9af15871e6 | ||
|
|
5897e79d05 | ||
|
|
fc9135ca9f | ||
|
|
e427d4b0e6 | ||
|
|
9df1bd0cc1 | ||
|
|
5990074ab0 | ||
|
|
dbb69bd192 | ||
|
|
d17581c4c6 | ||
|
|
2c9ed7f425 | ||
|
|
717ff6adc3 | ||
|
|
f9f8d19bf5 | ||
|
|
535be2f5d3 | ||
|
|
bceab45dbe | ||
|
|
368ceff6e0 | ||
|
|
77c4e95d4a | ||
|
|
e44165c0f7 | ||
|
|
a1a214c393 | ||
|
|
94b7144a1b | ||
|
|
e72910dec8 | ||
|
|
0b6144583b | ||
|
|
f31667317d | ||
|
|
5226b712a3 | ||
|
|
1f84cde024 | ||
|
|
046bfa2af0 | ||
|
|
0762732647 | ||
|
|
efb8f10450 | ||
|
|
6dbdf16fd1 | ||
|
|
6e6a45a7d9 | ||
|
|
a4569c22cc | ||
|
|
199e65c4d9 | ||
|
|
bb8811d472 | ||
|
|
995a16ca0c | ||
|
|
65f9c1aca1 | ||
|
|
b72ecb3a59 | ||
|
|
c221030f89 | ||
|
|
5bbea085d0 | ||
|
|
622cf03ab9 | ||
|
|
8ce27433f8 | ||
|
|
5d894620b4 | ||
|
|
71766c0c35 | ||
|
|
da58455508 | ||
|
|
b915c9a661 | ||
|
|
424aaa0f9d | ||
|
|
c72c895869 | ||
|
|
b7156116c2 | ||
|
|
7d915a0bb9 | ||
|
|
509afcd1d2 | ||
|
|
51343bd9a2 | ||
|
|
b58276a73c | ||
|
|
f162d344c0 | ||
|
|
0003db15cb | ||
|
|
275f4a4475 | ||
|
|
12e4565fef | ||
|
|
7af26eed32 | ||
|
|
63dc6eb316 | ||
|
|
6656790f24 | ||
|
|
c8de423038 | ||
|
|
c52653f97c | ||
|
|
e24c341068 | ||
|
|
5ef6c8c24f | ||
|
|
7c348a0b73 | ||
|
|
d578da0665 | ||
|
|
8949ef44b4 | ||
|
|
3ac11cdd98 | ||
|
|
5d49fa112d | ||
|
|
d29d19e654 | ||
|
|
49ea7db74e | ||
|
|
fcb40ee73d | ||
|
|
0f437b3b5e | ||
|
|
8a5fe8ce6b | ||
|
|
2a664c03db | ||
|
|
4902807879 | ||
|
|
742af6e4b9 | ||
|
|
3eb008c36d | ||
|
|
32248ebd5b | ||
|
|
5d32f35bdc | ||
|
|
d6379cd923 | ||
|
|
9f7e9ba46f | ||
|
|
80498fab01 | ||
|
|
ea84abe3e9 | ||
|
|
0526792ebb | ||
|
|
ab177cb153 | ||
|
|
3b74df4f55 | ||
|
|
5483fead6a | ||
|
|
7199531ff1 | ||
|
|
5a1f2c577d | ||
|
|
6c9bc0156a | ||
|
|
da2cc84854 | ||
|
|
a8088e331a | ||
|
|
41d2ae3203 | ||
|
|
c6bc22adc7 | ||
|
|
9c057566d5 | ||
|
|
32a8f3e009 | ||
|
|
481ff0ed10 | ||
|
|
f04cf8506a | ||
|
|
04d7693d86 | ||
|
|
4ea23f7ea1 | ||
|
|
163c05c61d | ||
|
|
d2790914df | ||
|
|
334e144c36 | ||
|
|
8bd54efceb | ||
|
|
e5e8c14d87 | ||
|
|
e778a28eee | ||
|
|
4cf2f757ec | ||
|
|
ae85ea3858 | ||
|
|
b087cf4a6c | ||
|
|
0adaf13438 | ||
|
|
b5ac983bf6 | ||
|
|
498794ad85 | ||
|
|
467fbd1086 | ||
|
|
7b7aef903e | ||
|
|
09a1839272 | ||
|
|
1b76e1c8ec | ||
|
|
959d991d10 | ||
|
|
ed6d29a784 | ||
|
|
5d6399b71c | ||
|
|
3b6df06fb8 | ||
|
|
a9d46d42cb | ||
|
|
0338aa4586 | ||
|
|
d15d371051 | ||
|
|
1c26ec2876 | ||
|
|
e9a7cd0a50 | ||
|
|
f5cdb007d8 | ||
|
|
46288c7e90 | ||
|
|
d7d682637d | ||
|
|
f006be7842 | ||
|
|
550c368ade | ||
|
|
b8ff4bb762 | ||
|
|
9adbf009a6 | ||
|
|
ccff85ad72 | ||
|
|
4c590320ec | ||
|
|
89aad01468 | ||
|
|
de6f914654 | ||
|
|
1ed783b8d7 | ||
|
|
3705ec5592 | ||
|
|
b6769234bc | ||
|
|
214a046f47 | ||
|
|
b38da6b191 | ||
|
|
9621c16a78 | ||
|
|
3ae7f1ab0d | ||
|
|
39de57499e | ||
|
|
3c91bca943 | ||
|
|
76bceb06c4 | ||
|
|
6f23a0a75e | ||
|
|
06945c4b77 | ||
|
|
c5aa221e44 | ||
|
|
bfefd6e38c | ||
|
|
59d30390c9 | ||
|
|
51471cafa5 | ||
|
|
be73efc020 | ||
|
|
40595f80d9 | ||
|
|
8c8e5385fd | ||
|
|
3de7289bd6 | ||
|
|
febeea9d01 | ||
|
|
762a3f2430 | ||
|
|
6d35601da4 | ||
|
|
a827127c77 | ||
|
|
d4a6f3a93e | ||
|
|
86c15032ba | ||
|
|
12ddb2a4b9 | ||
|
|
db07664f2a | ||
|
|
1205fc3541 | ||
|
|
3a8ebcac77 | ||
|
|
729e54b386 | ||
|
|
a61dbc84bf | ||
|
|
3cbd4b0fc0 | ||
|
|
75965b19bd | ||
|
|
830459d3a1 | ||
|
|
aa9e9651a1 | ||
|
|
9142942483 | ||
|
|
68fe0d78bb | ||
|
|
c9d7b983c4 | ||
|
|
7c07dc3526 | ||
|
|
cd93d15ab1 | ||
|
|
34bbb7a1b8 | ||
|
|
b5820d1fd8 | ||
|
|
2748d4e901 | ||
|
|
63ba726e1f | ||
|
|
f1beb79429 | ||
|
|
cd4db8246e | ||
|
|
69877f565a | ||
|
|
744231d995 | ||
|
|
65c2d6afd6 | ||
|
|
b27b94cfdc | ||
|
|
b8b5b734b4 | ||
|
|
568fb02449 | ||
|
|
77ef9b2603 | ||
|
|
416390f996 | ||
|
|
24804b7431 | ||
|
|
1fe9d2ba45 | ||
|
|
3868066085 | ||
|
|
a889c554a7 | ||
|
|
ca8d04a8ff | ||
|
|
8b606543a3 | ||
|
|
d16b995756 | ||
|
|
768b45a023 | ||
|
|
3b5ddf37d9 | ||
|
|
9bbf098a97 | ||
|
|
6536187b62 | ||
|
|
50adf82199 | ||
|
|
1419de285f | ||
|
|
31c91b40bd | ||
|
|
1d6fe0ea84 | ||
|
|
d774add784 | ||
|
|
7500157cff | ||
|
|
52e6ad2761 | ||
|
|
bcb46809dc | ||
|
|
33635d8564 | ||
|
|
bd188e306a | ||
|
|
aaba66efbd | ||
|
|
597378cdf5 | ||
|
|
15dcdc824a | ||
|
|
86ee779e22 | ||
|
|
df242de5c6 | ||
|
|
b14aa762ff | ||
|
|
a78487a4df | ||
|
|
3a601d06bd | ||
|
|
047256a6d8 | ||
|
|
c244d92d8a | ||
|
|
138e1e2a2d | ||
|
|
153eeb070b | ||
|
|
a3c8b75972 | ||
|
|
042c64273d | ||
|
|
638c7c4d20 | ||
|
|
88fc6c8023 | ||
|
|
3fb10cd0d8 | ||
|
|
ff28a485cf | ||
|
|
1f0f86a0d0 | ||
|
|
2842972035 | ||
|
|
5a9eae429a | ||
|
|
9461807011 | ||
|
|
00be8b39e2 | ||
|
|
ef5aac95d4 | ||
|
|
ef8e930e42 | ||
|
|
eb92fb32b7 | ||
|
|
9a698434dd | ||
|
|
f5ef0f064c | ||
|
|
997982f78b | ||
|
|
7d6b68c5d7 | ||
|
|
137ae2e9cf | ||
|
|
5dc14b6e05 | ||
|
|
0427e37116 | ||
|
|
e5e8cae1ca | ||
|
|
7f42ca8af8 | ||
|
|
e4251eb13b | ||
|
|
5083876910 | ||
|
|
f172fdbb77 | ||
|
|
3822825e54 | ||
|
|
1da54210fc | ||
|
|
43a2a66531 | ||
|
|
e6841ea2e0 | ||
|
|
e939b45c9f | ||
|
|
e3068ed111 | ||
|
|
efbf80be58 | ||
|
|
022ad63f0c | ||
|
|
02f8754339 | ||
|
|
142456cfd0 | ||
|
|
207ce40db2 | ||
|
|
881eaa4dbc | ||
|
|
d6d7527c95 | ||
|
|
11b4be2036 | ||
|
|
3e306c1202 | ||
|
|
7f227a83f2 | ||
|
|
9ed3ee67ec | ||
|
|
1f9215f5f9 | ||
|
|
f52cfdd8c3 | ||
|
|
2fc904111d | ||
|
|
262dadf50e | ||
|
|
6c596f1cc1 | ||
|
|
dafa16c400 | ||
|
|
1db9943c68 | ||
|
|
5b868c213b | ||
|
|
2d8905dafd | ||
|
|
9002108551 | ||
|
|
d3c21c596e | ||
|
|
34fac952b6 | ||
|
|
92c32e0bac | ||
|
|
1bcad67806 | ||
|
|
fe9a134baf | ||
|
|
930428fb97 | ||
|
|
936be022d9 | ||
|
|
0017dd74d5 | ||
|
|
0ba25a0512 | ||
|
|
a176cf1bc3 | ||
|
|
fdd9a96a8c | ||
|
|
b87d7aa041 | ||
|
|
f753e7eba6 | ||
|
|
78a5a21655 | ||
|
|
a5cbe6d112 | ||
|
|
9403664616 | ||
|
|
f32498465d | ||
|
|
fa45e06431 | ||
|
|
6722ec6c78 | ||
|
|
d882dfdae9 | ||
|
|
a2ee2426bf | ||
|
|
84bd46ddd7 | ||
|
|
271790685a | ||
|
|
7a74037267 | ||
|
|
9a9f6e147c | ||
|
|
8f2d432799 | ||
|
|
92eab03b12 | ||
|
|
1ba4ae2830 | ||
|
|
0076481dfd | ||
|
|
c0e731d545 | ||
|
|
3f56bb8ba1 | ||
|
|
e518e87533 | ||
|
|
c4b9bc63e0 | ||
|
|
1d53d958bb | ||
|
|
d334e7c34f | ||
|
|
d21438a7df | ||
|
|
24c3b5b3d4 | ||
|
|
4447d48bb9 | ||
|
|
04cc2ae1a6 | ||
|
|
32588c755a | ||
|
|
84a6d07cdd | ||
|
|
d6c69f6bdb | ||
|
|
ce372917fe | ||
|
|
09d741f58a | ||
|
|
0666ae3d27 | ||
|
|
ba4c7d906b | ||
|
|
f4b2813818 | ||
|
|
5586934da0 | ||
|
|
6134b94c02 | ||
|
|
05e6728e98 | ||
|
|
6578acd668 | ||
|
|
b5581ed173 | ||
|
|
508d6b4885 | ||
|
|
ef6efd69ed | ||
|
|
151d7dc5ea | ||
|
|
20b4a4ea5b | ||
|
|
770bce967c | ||
|
|
a267a9e489 | ||
|
|
f65d210012 | ||
|
|
858bfcf261 | ||
|
|
9b801c4e72 | ||
|
|
1a98d1a94f | ||
|
|
03345ecefe | ||
|
|
191924576c | ||
|
|
756a1dcc19 | ||
|
|
3ab6dd1c37 | ||
|
|
4458d87289 | ||
|
|
b7f62475d0 | ||
|
|
4732aa663b | ||
|
|
c27cfeaa7b | ||
|
|
bb6f6bae0b | ||
|
|
f4c87b504b | ||
|
|
e426c2d3bc | ||
|
|
6279d9eaf3 | ||
|
|
12949aa0c0 | ||
|
|
84f3357dd9 | ||
|
|
4333d5d93a | ||
|
|
fa580ad3eb | ||
|
|
292dfa653e | ||
|
|
7fbf1cce7b | ||
|
|
dbceeb4178 | ||
|
|
ed200fa001 | ||
|
|
b5dafc0b7e | ||
|
|
fc664d114d | ||
|
|
c6d4c33d61 | ||
|
|
bf1fc6c6fd | ||
|
|
b18e9c8c61 | ||
|
|
a3293bb242 | ||
|
|
4e2a4b8788 | ||
|
|
2362784bc0 | ||
|
|
b2cec1b881 | ||
|
|
a946857133 | ||
|
|
10cd342f5c | ||
|
|
27ce754b3d | ||
|
|
3ab0ad8748 | ||
|
|
4308236262 | ||
|
|
ebd8350300 | ||
|
|
8285d335f4 | ||
|
|
9db275ebea | ||
|
|
1f8f78a49b | ||
|
|
c2f129ba3d | ||
|
|
07c47416a9 | ||
|
|
8f2a62b386 | ||
|
|
a6c0edd4f4 | ||
|
|
ff43d35aee | ||
|
|
70fca205be | ||
|
|
1033130b6c | ||
|
|
8cfcd9ff63 | ||
|
|
80a6c16dcc | ||
|
|
553c4c99cc | ||
|
|
4165c1331b | ||
|
|
b2690415bf | ||
|
|
011f8cf1d0 | ||
|
|
2748fb81e2 | ||
|
|
46312909d9 | ||
|
|
41adecad14 | ||
|
|
ea5d8c56a0 | ||
|
|
d242cbffa4 | ||
|
|
1c8855ed10 | ||
|
|
ea33a01303 | ||
|
|
18b1d1424e | ||
|
|
1176cd58c9 | ||
|
|
44a4643b62 | ||
|
|
ed96efd865 | ||
|
|
e3093b532c | ||
|
|
9560658c5b | ||
|
|
37a70d39e0 | ||
|
|
72fac0810c | ||
|
|
c166c07a93 | ||
|
|
39a625ff72 | ||
|
|
ad32ca18a7 | ||
|
|
efea282396 | ||
|
|
33d6a01cd3 | ||
|
|
d290630d31 | ||
|
|
d2ad5dc073 | ||
|
|
68ab5127af | ||
|
|
089a11f340 | ||
|
|
de1d04eb66 | ||
|
|
ed4e7defd7 | ||
|
|
267ab619c4 | ||
|
|
0140454ba2 | ||
|
|
2c60441239 | ||
|
|
cbbd56c965 | ||
|
|
2561f9fe0e | ||
|
|
47aefca5e4 | ||
|
|
981fb03710 | ||
|
|
ef2f8d70d2 | ||
|
|
d9995a1add | ||
|
|
ea7a05ad43 | ||
|
|
26bbf5a314 | ||
|
|
c147329823 | ||
|
|
eb88eed1fc | ||
|
|
8312a3ba4f | ||
|
|
35f93081dc | ||
|
|
de372d6914 | ||
|
|
4ac517e4ac | ||
|
|
e3651367b3 | ||
|
|
02ea41ddd1 | ||
|
|
51ffae4eab | ||
|
|
afe84f37f8 | ||
|
|
0afeef0e00 | ||
|
|
94a17fd97f | ||
|
|
5b5ec55445 | ||
|
|
1e6565c1a5 | ||
|
|
fc522515b9 | ||
|
|
9881b0736d | ||
|
|
e52b4b1466 | ||
|
|
2f45670951 | ||
|
|
50d75ae514 | ||
|
|
dea69a12aa | ||
|
|
e0ce3c12f2 | ||
|
|
93cf516bf1 | ||
|
|
6f4de018af | ||
|
|
6e91cf3172 | ||
|
|
9cb7f8a655 | ||
|
|
5d8d1ad14b | ||
|
|
cac9ca38f6 | ||
|
|
c4523639d5 | ||
|
|
1ce1c6beae | ||
|
|
51d56df7a3 | ||
|
|
860a9a57d6 | ||
|
|
c83e33d608 | ||
|
|
7b80c75d9d | ||
|
|
79337f99ae | ||
|
|
a42ee397f3 | ||
|
|
e58f8bb8c1 | ||
|
|
58cf958e41 | ||
|
|
06d01f7ae4 | ||
|
|
1a33eec0ba | ||
|
|
82de7a1e96 | ||
|
|
8e9bde57c5 | ||
|
|
1bb70e08be | ||
|
|
9afcb7ae61 | ||
|
|
545c4955e6 | ||
|
|
2f2d59b35c | ||
|
|
a1729deed3 | ||
|
|
fc64b97cd5 | ||
|
|
daddc8cb80 | ||
|
|
527c3c7d0d | ||
|
|
fcb4dcaf7c | ||
|
|
3ca4995d34 | ||
|
|
d387f8f06c | ||
|
|
ea43234c86 | ||
|
|
867e56a45e | ||
|
|
a163c63787 | ||
|
|
8389b943d3 | ||
|
|
f2266d9678 | ||
|
|
56bd806978 | ||
|
|
ac7eeea44d | ||
|
|
b741059549 | ||
|
|
cbd984287f | ||
|
|
32e15c3f45 | ||
|
|
f0dc324e35 | ||
|
|
f83c6cf51a | ||
|
|
c068b3ae2f | ||
|
|
adf9dec1e6 | ||
|
|
767d9cbd96 | ||
|
|
e7ccd95c04 | ||
|
|
719f79a8fd | ||
|
|
96f6444958 | ||
|
|
df25f204ba | ||
|
|
8acdc3ede7 | ||
|
|
857b445522 | ||
|
|
5bcca1219a | ||
|
|
4558c26fcd | ||
|
|
a92c6d77dc | ||
|
|
0c95a5ff53 | ||
|
|
cb6d06bb54 | ||
|
|
3ef955c85a | ||
|
|
5e95c16c32 | ||
|
|
4205e2ebcf | ||
|
|
9d806c51c2 | ||
|
|
a38bb31727 | ||
|
|
8a1ef367e2 | ||
|
|
1291865c92 | ||
|
|
a9ebbee7b6 | ||
|
|
06df5ad7d0 | ||
|
|
66b863c989 | ||
|
|
c9efe8e5e1 | ||
|
|
d515223bb5 | ||
|
|
b908f4334b | ||
|
|
6261aba026 | ||
|
|
85bc7534da | ||
|
|
1b30fd1732 | ||
|
|
8c9196bff8 | ||
|
|
b1daf44954 | ||
|
|
11c52d032b | ||
|
|
be291d979d | ||
|
|
6d1edd8d32 | ||
|
|
25ff956c7d | ||
|
|
38179500f8 | ||
|
|
5f7be5f0d6 | ||
|
|
627056febb | ||
|
|
cbd76447fd | ||
|
|
a60a233329 | ||
|
|
a0a3b8ad3e | ||
|
|
d0ae3f5a4d | ||
|
|
6860cf932b | ||
|
|
0276e0805b | ||
|
|
06ff3d8a26 | ||
|
|
1a3b69aa56 | ||
|
|
8237d06ab7 | ||
|
|
1c9f136b57 | ||
|
|
5ab7e4a475 | ||
|
|
3236f358f8 | ||
|
|
4a6550d69a | ||
|
|
ff523d0c67 | ||
|
|
3c93e8eb41 | ||
|
|
88a482fdb9 | ||
|
|
12a9aa7c62 | ||
|
|
50ccf9c585 | ||
|
|
d100eb05a3 | ||
|
|
10d8b5f001 | ||
|
|
ffd3ceb856 | ||
|
|
d942aa9321 | ||
|
|
6469fefe89 | ||
|
|
b082842ee7 | ||
|
|
3573ca0eec | ||
|
|
ad90eb075d | ||
|
|
d55e2d086d | ||
|
|
fe9c966a49 | ||
|
|
9f20afb1a8 | ||
|
|
f61afcfc70 | ||
|
|
961daf8f92 | ||
|
|
64a16cb376 | ||
|
|
ea6b0b2665 | ||
|
|
89df73ac05 | ||
|
|
7d3f3c9983 | ||
|
|
1bdbea2461 | ||
|
|
dfb1f7ccf1 | ||
|
|
b5d1b20727 | ||
|
|
2a407a76be | ||
|
|
d1640a6338 | ||
|
|
26b5c40d95 | ||
|
|
0b3ecf7432 | ||
|
|
8f9bd61505 | ||
|
|
ea28d0ef8a | ||
|
|
4a8c098840 | ||
|
|
ffa4628faa | ||
|
|
e10a9239e1 | ||
|
|
51f7bc924c | ||
|
|
6c0bf79078 | ||
|
|
4b03170920 | ||
|
|
1de6bbc108 | ||
|
|
023ace8e54 | ||
|
|
74d4fcd756 | ||
|
|
9eaa91bfc3 | ||
|
|
484bd75ce4 | ||
|
|
4c30e9602b | ||
|
|
b260d222af | ||
|
|
6528d62cd2 | ||
|
|
b7cf754f6f | ||
|
|
14e3f6ba19 | ||
|
|
a8c1474562 | ||
|
|
8b8a4148ec | ||
|
|
9e147480ed | ||
|
|
4c0aecc685 | ||
|
|
d556b8a5d5 | ||
|
|
e7c0d7b348 | ||
|
|
17360439dc | ||
|
|
9e169a9bea | ||
|
|
305cb79c57 | ||
|
|
141a26f979 | ||
|
|
cfcafdd27c | ||
|
|
f1204a875e | ||
|
|
20295012b8 | ||
|
|
807e82343a | ||
|
|
c8e8f5c204 | ||
|
|
a69b017902 | ||
|
|
e75069f79a | ||
|
|
3f535da79e | ||
|
|
8ebdc364af | ||
|
|
12af2b171d | ||
|
|
04490bf622 | ||
|
|
327bbc92bc | ||
|
|
cc0b4489c7 | ||
|
|
9212ad284f | ||
|
|
503f68dbc4 | ||
|
|
e01e09c712 | ||
|
|
6a6e06fbb0 | ||
|
|
2024f97297 | ||
|
|
25e63f1e56 | ||
|
|
15b60ddf93 | ||
|
|
824461192c | ||
|
|
1eb6cedb03 | ||
|
|
059aded070 | ||
|
|
2d765867c5 | ||
|
|
257ac0c5f7 | ||
|
|
4e96a4be68 | ||
|
|
a2a7e040b1 | ||
|
|
4ded96209e | ||
|
|
f60fea1fb0 | ||
|
|
4d85e409cd | ||
|
|
2bd02d2f59 | ||
|
|
7e194a0a7d | ||
|
|
9beb4d9ea2 | ||
|
|
ab5ebe9507 | ||
|
|
837e8f4eb5 | ||
|
|
e2cb655958 | ||
|
|
8270648da1 | ||
|
|
619000a3c5 | ||
|
|
1c1b925052 | ||
|
|
49bdf1ead9 | ||
|
|
60a3ae19c5 | ||
|
|
951a22165c | ||
|
|
51cdd1a227 | ||
|
|
66adee85be | ||
|
|
4890bcdea2 | ||
|
|
8baf583a3f | ||
|
|
913fa15fb1 | ||
|
|
00fe2f49e0 | ||
|
|
ec2067df75 | ||
|
|
7ddb99d251 | ||
|
|
ba26d3485b | ||
|
|
081a1c4014 | ||
|
|
532246fc9e | ||
|
|
8caf3d7c6c | ||
|
|
d162bee356 | ||
|
|
b43585c34b | ||
|
|
3f60ecd6f0 | ||
|
|
0506a5ed4e | ||
|
|
e7ee1aa093 | ||
|
|
63ed917ad9 | ||
|
|
63e21bdea3 | ||
|
|
1627d577af | ||
|
|
b837c4528d | ||
|
|
46bdfe691a | ||
|
|
dded78b233 | ||
|
|
b594e8defa | ||
|
|
70c50efd0d | ||
|
|
ea3c60ac07 | ||
|
|
fc19399a1f | ||
|
|
980b14f174 | ||
|
|
1df73fe831 | ||
|
|
c125c1dfee | ||
|
|
e39c484ebd | ||
|
|
977a5a2df1 | ||
|
|
02df0007c8 | ||
|
|
b2ed691eb3 | ||
|
|
8d6d5730c9 | ||
|
|
48755ebf09 | ||
|
|
0541a1adf7 | ||
|
|
c992ed4bef | ||
|
|
92025a4113 | ||
|
|
a7d19e917a | ||
|
|
ec1cc455d6 | ||
|
|
ee64582a1f | ||
|
|
425e2405aa | ||
|
|
dea53e6658 | ||
|
|
a9b022ab65 | ||
|
|
c65b77c87f | ||
|
|
8e3a5cba8b | ||
|
|
29ae308398 | ||
|
|
306888afb3 | ||
|
|
f064188032 | ||
|
|
77476580ed | ||
|
|
52ec783613 | ||
|
|
137286e9ba | ||
|
|
79aba0f10a | ||
|
|
515ba97595 | ||
|
|
cd672933c9 | ||
|
|
d9603ef781 | ||
|
|
e40d8bef3b | ||
|
|
ab53883c94 | ||
|
|
6c1e9ac14b | ||
|
|
c7a44c4690 | ||
|
|
2ac4cf0146 | ||
|
|
a914d0aa6a | ||
|
|
91102ad5eb | ||
|
|
378fa56888 | ||
|
|
2a8710ac2f | ||
|
|
66f62650c3 | ||
|
|
18a6bdd541 | ||
|
|
9e732445cf | ||
|
|
7d04e17444 | ||
|
|
34d41475e7 | ||
|
|
0c211c4ec5 | ||
|
|
bf23c8a394 | ||
|
|
f73f7397d7 | ||
|
|
5cee7c2702 | ||
|
|
1aef66bb34 | ||
|
|
4a1c21d62c | ||
|
|
c117675ebd | ||
|
|
6ebdc95754 | ||
|
|
55a22b88c2 | ||
|
|
1fd56c0e33 | ||
|
|
376cb97685 | ||
|
|
84449bf41c | ||
|
|
456a319775 | ||
|
|
157d8cfd6a | ||
|
|
1292e1a557 | ||
|
|
122997da54 | ||
|
|
b59a5c2567 | ||
|
|
2a20cc6da8 | ||
|
|
936bd82755 | ||
|
|
13a58f9590 | ||
|
|
19b0e3bf21 | ||
|
|
203ce0a081 | ||
|
|
e3002bf1a6 | ||
|
|
04db1483d1 | ||
|
|
6fe436a448 | ||
|
|
e710c34469 | ||
|
|
defd6b1d85 | ||
|
|
90d7c6b97d | ||
|
|
e24abf28a2 | ||
|
|
69a0477b74 | ||
|
|
ae7a3b9d2e | ||
|
|
d9f882bea2 | ||
|
|
fef2f1c75e | ||
|
|
5a91334985 | ||
|
|
e198fe833a | ||
|
|
248efe8410 | ||
|
|
dc6a57ffb8 | ||
|
|
240da59f73 | ||
|
|
5a56233f53 | ||
|
|
225accd235 | ||
|
|
ab73a746a0 | ||
|
|
69bc94779c | ||
|
|
3052ce208a | ||
|
|
18e17665fd | ||
|
|
05299fdd5a | ||
|
|
7ef55691a2 | ||
|
|
7509f94fc4 | ||
|
|
343b7b4ad0 | ||
|
|
a2b8220f4e | ||
|
|
5c464ef62e | ||
|
|
5fc639cf9a | ||
|
|
7673013d23 | ||
|
|
c6cc455dd1 | ||
|
|
1da81f7e23 | ||
|
|
ae5b7e04a1 | ||
|
|
305ffb5ef0 | ||
|
|
608aa9fcfc | ||
|
|
c61c7bb225 | ||
|
|
5ed82ae5f2 | ||
|
|
6799320edb | ||
|
|
c406fd60be | ||
|
|
5d514f22a9 | ||
|
|
a066aac332 | ||
|
|
8bd28a87a2 | ||
|
|
065e5bb0b1 | ||
|
|
df6636bff6 | ||
|
|
162e5e0062 | ||
|
|
4219adeeef | ||
|
|
28cfe36e1e | ||
|
|
d2d4990743 | ||
|
|
18eac67c0a | ||
|
|
f8c77edbdf | ||
|
|
4bf62f616b | ||
|
|
9c0d445ef4 | ||
|
|
2896e2485e | ||
|
|
a90f09db4c | ||
|
|
5b99eae59d | ||
|
|
2daca52b80 | ||
|
|
2c594732eb | ||
|
|
cc921df9ce | ||
|
|
ab194ed7ca | ||
|
|
65a01b71bb | ||
|
|
bde46476ee | ||
|
|
e7bfd556c0 | ||
|
|
b683cf37f9 | ||
|
|
3becf468ba | ||
|
|
137e9f878f | ||
|
|
07e25da5bf | ||
|
|
d46ee724fc | ||
|
|
59e470381f | ||
|
|
48d12f14c9 | ||
|
|
122392e0b3 | ||
|
|
3a5a84cdd1 | ||
|
|
24b87607c1 | ||
|
|
6f7812d97b | ||
|
|
cbb5b17ad8 | ||
|
|
cf5984367b | ||
|
|
ee8750451b | ||
|
|
a220545c42 | ||
|
|
a799ca0c63 | ||
|
|
91421cb757 | ||
|
|
53792c934c | ||
|
|
df071825f2 | ||
|
|
e1791f36ea | ||
|
|
0fdf3c1f61 | ||
|
|
ee1df06aab | ||
|
|
1e87eba424 | ||
|
|
08933475ab | ||
|
|
7cbf497da4 | ||
|
|
3a610a007f | ||
|
|
48b090cb5c | ||
|
|
4139298d28 | ||
|
|
51cc10fa54 | ||
|
|
ea6cc33804 | ||
|
|
ad03967ee4 | ||
|
|
f4fd07d303 | ||
|
|
e3c08a34a7 | ||
|
|
118011fe2b | ||
|
|
af3bd07355 | ||
|
|
d68209978a | ||
|
|
47b45b2967 | ||
|
|
2b38e3823b | ||
|
|
282eab7952 | ||
|
|
c346f61535 | ||
|
|
03212e533b | ||
|
|
da8b6517de | ||
|
|
c5db8f93ec | ||
|
|
974a6d087a | ||
|
|
b758b67c37 | ||
|
|
9bafdc62b7 | ||
|
|
97f876b64c | ||
|
|
cbfbd173c4 | ||
|
|
b6f926fbef | ||
|
|
c822620967 | ||
|
|
397c0502e2 | ||
|
|
1682d15a74 | ||
|
|
dd33e98da0 | ||
|
|
c16d966ad3 | ||
|
|
1dfed16071 | ||
|
|
6f835ed6c8 | ||
|
|
9d6fd1727e | ||
|
|
8c1b6a5fd7 | ||
|
|
8dcdb33be9 | ||
|
|
aba8bbb6e3 | ||
|
|
caf4d571e6 | ||
|
|
3b6eb197a8 | ||
|
|
f3e57877ed | ||
|
|
c851c695db | ||
|
|
a3bd7e73d3 | ||
|
|
ab5ceaf74a | ||
|
|
1f2f69d4f6 | ||
|
|
f361b39dea | ||
|
|
eb1fe15ca8 | ||
|
|
45d8a2435e | ||
|
|
706d84fd10 | ||
|
|
a997ca0da0 | ||
|
|
9268b5d677 | ||
|
|
51e4eeeb04 | ||
|
|
05ff659a3c | ||
|
|
db0f488ea8 | ||
|
|
7dcca6c622 | ||
|
|
090856c7e6 | ||
|
|
cc5cc8f1e0 | ||
|
|
c488b68e75 | ||
|
|
1f1873aadd | ||
|
|
0a496f059c | ||
|
|
e27825b0ef | ||
|
|
1f60a18ea1 | ||
|
|
a0088e8364 | ||
|
|
34e26e14c5 | ||
|
|
6b17335209 | ||
|
|
07ed585c38 | ||
|
|
0669ee7a69 | ||
|
|
f84e674d8a | ||
|
|
7f0084316a | ||
|
|
a6918530ce | ||
|
|
4e72fec660 | ||
|
|
4441cf762c | ||
|
|
e83915d10d | ||
|
|
6d37924b86 | ||
|
|
f3d7974e86 | ||
|
|
734d53176f | ||
|
|
9a7be47614 | ||
|
|
26e27d0015 | ||
|
|
94b6878821 | ||
|
|
8b96552f0d | ||
|
|
ae290659de | ||
|
|
6b2b564ac3 | ||
|
|
4f7bb57e97 | ||
|
|
56f0623930 | ||
|
|
f3223fbff6 | ||
|
|
4c4f4c2649 | ||
|
|
773af304ea | ||
|
|
4cc944b0d6 | ||
|
|
87e00feb01 | ||
|
|
e7a4af8903 | ||
|
|
2d69d6146d | ||
|
|
30e4a9441e | ||
|
|
232a8f3569 | ||
|
|
1721453d51 | ||
|
|
499d8dde2b | ||
|
|
6f1cbfd000 | ||
|
|
55ecde7f1b | ||
|
|
6b54d69a85 | ||
|
|
246a31cd73 | ||
|
|
83e4b73596 | ||
|
|
6340ca734f | ||
|
|
baf553db0c | ||
|
|
486bcd5a7b | ||
|
|
be9a74d2f8 | ||
|
|
ffcbc0f011 | ||
|
|
a969ba6e2a | ||
|
|
f1781728af | ||
|
|
cd7df612b1 | ||
|
|
c1a4e257a3 | ||
|
|
4fe6744a22 | ||
|
|
3bd4c47f31 | ||
|
|
98196c4931 | ||
|
|
22cd860124 | ||
|
|
3c973ad92d | ||
|
|
faaf306a63 | ||
|
|
c7e6aea81b | ||
|
|
e541245987 | ||
|
|
84a01bee10 | ||
|
|
d1ced3ae38 | ||
|
|
a6cee69af4 | ||
|
|
0039920ab6 | ||
|
|
39d8550a80 | ||
|
|
ef3d137a64 | ||
|
|
8c707e1e37 | ||
|
|
373e917389 | ||
|
|
74f0f9a042 | ||
|
|
ed6bdb0967 | ||
|
|
c88af046b7 | ||
|
|
ae0187d454 | ||
|
|
0c50e3ddc8 | ||
|
|
075366ad6e | ||
|
|
8e8b2d6f63 | ||
|
|
087eb76140 | ||
|
|
ebedcbaeb8 | ||
|
|
0954a977c9 | ||
|
|
b77efc1948 | ||
|
|
3b0cb34710 | ||
|
|
aa6f832d61 | ||
|
|
ad9c6f06c5 | ||
|
|
a6004d7f17 | ||
|
|
c366717e66 | ||
|
|
22dee512f3 | ||
|
|
6fd5d79e73 | ||
|
|
9d6918d32c | ||
|
|
a49c5c2265 | ||
|
|
30858e3b9b | ||
|
|
30df7efc96 | ||
|
|
3e8c42cba5 | ||
|
|
62cb936cb7 | ||
|
|
39921d03ba | ||
|
|
6a0b00f0d6 | ||
|
|
51eadb692a | ||
|
|
897c113fda | ||
|
|
33e3f1029c | ||
|
|
3d4ff1ba84 | ||
|
|
24036ea507 | ||
|
|
0549c73b7e | ||
|
|
b697fbb7f1 | ||
|
|
96e063c43d | ||
|
|
4e841da1a6 | ||
|
|
09ce307bdb | ||
|
|
a3303e196e | ||
|
|
63437ffbb5 | ||
|
|
69a815aa8f | ||
|
|
1d224949cc | ||
|
|
391f708a09 | ||
|
|
cbd29e5da8 | ||
|
|
50a2841d34 | ||
|
|
9396752c11 | ||
|
|
712dadb287 | ||
|
|
32be32eab8 | ||
|
|
1649f709e7 | ||
|
|
50ca85504c | ||
|
|
4bb68866a8 | ||
|
|
2446514e71 | ||
|
|
109d0e74f1 | ||
|
|
74ea91531a | ||
|
|
9828ab115e | ||
|
|
f77700aa27 | ||
|
|
0fbd980639 | ||
|
|
43cdf1c3d0 | ||
|
|
ff19b1a97d | ||
|
|
1835343acd | ||
|
|
2aaea18f43 | ||
|
|
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 | ||
|
|
05ff1ed7cc | ||
|
|
2b5bae9a8f | ||
|
|
39f1b8e73d | ||
|
|
af576b56c2 | ||
|
|
54dd393f39 | ||
|
|
4ce4f3779b | ||
|
|
8b3ae2fd43 | ||
|
|
ed55cb66e6 | ||
|
|
2cd9a0de1f | ||
|
|
c514ab9907 | ||
|
|
078a630bba | ||
|
|
43c271b07c | ||
|
|
24ce681e51 | ||
|
|
5ae34bf3c8 | ||
|
|
51931b888a | ||
|
|
9f7f3b1216 | ||
|
|
97c83bb05b | ||
|
|
8767ceecd4 | ||
|
|
18c63eff8f | ||
|
|
c64b7f6a78 | ||
|
|
068b4b51e3 | ||
|
|
919dd7cf14 | ||
|
|
f632e56793 | ||
|
|
2021c66251 | ||
|
|
8358e0f4b2 | ||
|
|
7f61b3ad59 | ||
|
|
a9ab732e35 | ||
|
|
11263a462c | ||
|
|
231d061b45 | ||
|
|
cdbee9a40b | ||
|
|
7b4ad2eb34 | ||
|
|
19d69be220 | ||
|
|
04363607aa | ||
|
|
dcffad2a86 | ||
|
|
6a69ab5ebd | ||
|
|
fc92ead0dd | ||
|
|
61ce600b20 | ||
|
|
7a14dfebbb | ||
|
|
42fb8153ba | ||
|
|
6f13e53886 | ||
|
|
d1c759c5c1 | ||
|
|
e46164e0bd | ||
|
|
7389ce7ff5 | ||
|
|
2f77797b17 | ||
|
|
9380ba70d6 | ||
|
|
1023dcbc9e | ||
|
|
83e854e359 | ||
|
|
50303b19d8 | ||
|
|
89382bacaa | ||
|
|
6c559c34df | ||
|
|
adaa6888dd | ||
|
|
a813111379 | ||
|
|
18f0fb050b | ||
|
|
05e92e5afe | ||
|
|
4723d49dad | ||
|
|
fbbc14541a | ||
|
|
5ef33279f2 | ||
|
|
1e02a85970 | ||
|
|
0e88d53faa | ||
|
|
01d1b8ddf2 | ||
|
|
c8257540bc | ||
|
|
2240704863 | ||
|
|
e8ca69ea16 | ||
|
|
da632e7cc1 | ||
|
|
30cd96663f | ||
|
|
7dbe98147d | ||
|
|
5d71d83420 | ||
|
|
38a59a9ff7 | ||
|
|
4b028ad612 | ||
|
|
442560beb4 | ||
|
|
7d2b5c9583 | ||
|
|
29689cfa5a | ||
|
|
52d4abf2f9 | ||
|
|
a953096485 | ||
|
|
884a6dfe6d | ||
|
|
0068301d24 | ||
|
|
353ae4d270 | ||
|
|
e759d426fa | ||
|
|
40ef23b547 | ||
|
|
f5e8562f96 | ||
|
|
1567feae3c | ||
|
|
daf061c9de | ||
|
|
d0e2c6c9ab | ||
|
|
8643ec7fea | ||
|
|
5cfea3d402 | ||
|
|
6c8f21e4a4 | ||
|
|
1d0f91c4a9 | ||
|
|
2a82db4caf | ||
|
|
dd88c17f15 | ||
|
|
8b37270410 | ||
|
|
760169fc43 | ||
|
|
7023e38294 | ||
|
|
a7cf58cc47 | ||
|
|
e25d1a2ea2 | ||
|
|
70969c1757 | ||
|
|
3803437dcc | ||
|
|
eabc6dd76a | ||
|
|
e28d2e2b77 | ||
|
|
96fafe2ed6 | ||
|
|
c81d390f84 | ||
|
|
08456c61f6 | ||
|
|
bc26f9a03f | ||
|
|
6ffeff86be | ||
|
|
f444cddbaf | ||
|
|
d13191a46c | ||
|
|
801ca9a7b7 | ||
|
|
df66e341de | ||
|
|
71ee7ee254 | ||
|
|
a156cae901 | ||
|
|
22b135a116 | ||
|
|
0f08983d85 | ||
|
|
e3e86343fc | ||
|
|
7b6dd880f7 | ||
|
|
b7f4020133 | ||
|
|
c46c7c7584 | ||
|
|
552af8b988 | ||
|
|
4f8ff361dc | ||
|
|
0010b47439 | ||
|
|
4b86b65d07 | ||
|
|
248489401a | ||
|
|
bc5992daf6 | ||
|
|
fdacfb0119 | ||
|
|
0d5d35d052 | ||
|
|
843c96b4b3 | ||
|
|
58dc02ebf2 | ||
|
|
c239f7de25 | ||
|
|
ac8540c3c5 | ||
|
|
22d904db95 | ||
|
|
741c2952d4 | ||
|
|
96f6979c4f | ||
|
|
c5379c1ab6 | ||
|
|
a4a5205fd7 | ||
|
|
c5ad4e7998 | ||
|
|
270dc2e199 | ||
|
|
948a0b6e81 | ||
|
|
87b8ecb13a | ||
|
|
e44ddcac63 | ||
|
|
00e9ad5217 | ||
|
|
96c3879bed | ||
|
|
57f460de2f | ||
|
|
6caacacf6d | ||
|
|
60ac5af682 | ||
|
|
caa94380ac | ||
|
|
0793380b40 | ||
|
|
1adadf585d | ||
|
|
e5ffdb9c77 | ||
|
|
6da5201092 | ||
|
|
b36ae19434 | ||
|
|
2307eac613 | ||
|
|
127ea40ae7 | ||
|
|
6aef600d48 | ||
|
|
98d76a0326 | ||
|
|
6ea6dcf05b | ||
|
|
627797800d | ||
|
|
c6cc03ed0c | ||
|
|
3d7b550f52 | ||
|
|
751d6f4ae6 | ||
|
|
a5c72ab51d | ||
|
|
9bbc88762b | ||
|
|
ceae00dddf | ||
|
|
3634c54e8d | ||
|
|
d74942a03d | ||
|
|
70c5e3e076 | ||
|
|
4cb1b32009 | ||
|
|
3268e90f5e | ||
|
|
e98170816a | ||
|
|
52b92f4db8 | ||
|
|
a2761754da | ||
|
|
805a11345c | ||
|
|
1ab62aec37 | ||
|
|
915363f976 | ||
|
|
205fafa577 | ||
|
|
be2daf4ad5 | ||
|
|
8ecfaa4adf | ||
|
|
03bfcf6462 | ||
|
|
39bec5ff32 | ||
|
|
246839d64a | ||
|
|
3862deb398 | ||
|
|
5954608577 | ||
|
|
984d2fded6 | ||
|
|
a4f04ed45a | ||
|
|
07736e8dcb | ||
|
|
00fc082d68 | ||
|
|
c72daea868 | ||
|
|
74c95c2542 | ||
|
|
7de060b08d |
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
VERSION export-subst
|
||||
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
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
|
||||
|
||||
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
[submodule "debian"]
|
||||
path = debian
|
||||
url = git://thekelleys.org.uk/dnsmasq-debian.git
|
||||
[submodule "submodules/dnsmasq-debian"]
|
||||
path = submodules/dnsmasq-debian
|
||||
url = https://thekelleys.org.uk/git/dnsmasq-debian
|
||||
@@ -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.
|
||||
@@ -1010,7 +1010,7 @@ release 2.9
|
||||
but to the address of another interface were ignored
|
||||
unless the loopback interface was explicitly configured.
|
||||
2) on OpenBSD failure to configure one interface now
|
||||
causes a fatal error on startup rather than an huge
|
||||
causes a fatal error on startup rather than a huge
|
||||
stream of log messages. Thanks to Erik Jan Tromp for
|
||||
finding that bug.
|
||||
|
||||
@@ -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.
|
||||
@@ -2067,7 +2067,7 @@ version 2.36
|
||||
kernel. Thanks to Philip Wall for the bug report.
|
||||
|
||||
Added --dhcp-bridge option, but only to the FreeBSD
|
||||
build. This fixes an oddity with a a particular bridged
|
||||
build. This fixes an oddity with a particular bridged
|
||||
network configuration on FreeBSD. Thanks to Luigi Rizzo
|
||||
for the patch.
|
||||
|
||||
@@ -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 a 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.
|
||||
|
||||
@@ -2433,7 +2433,7 @@ version 2.41
|
||||
|
||||
Add --dhcp-match flag, to check for arbitrary options in
|
||||
DHCP messages from clients. This enables use of dnsmasq
|
||||
with gPXE. Thanks to Rance Hall for the suggestion.
|
||||
with iPXE. Thanks to Rance Hall for the suggestion.
|
||||
|
||||
Added --dhcp-broadcast, to force broadcast replies to DHCP
|
||||
clients which need them but are too dumb or too old to
|
||||
@@ -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 -
|
||||
|
||||
43
COPYING
43
COPYING
@@ -1,12 +1,12 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
@@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
@@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
@@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
@@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
@@ -225,7 +225,7 @@ impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
@@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
@@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
@@ -291,7 +291,7 @@ convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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
|
||||
@@ -303,17 +303,16 @@ the "copyright" line and a pointer to where the full notice is found.
|
||||
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, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
@@ -336,5 +335,5 @@ necessary. Here is a sample; alter the names:
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
|
||||
201
FAQ
201
FAQ
@@ -9,7 +9,7 @@ A: The high ports that dnsmasq opens are for replies from the upstream
|
||||
from port 53 the replies would be _to_ port 53 and get blocked.
|
||||
|
||||
This is not a security hole since dnsmasq will only accept replies to that
|
||||
port: queries are dropped. The replies must be to oustanding queries
|
||||
port: queries are dropped. The replies must be to outstanding queries
|
||||
which dnsmasq has forwarded, otherwise they are dropped too.
|
||||
|
||||
Addendum: dnsmasq now has the option "query-port" (-Q), which allows
|
||||
@@ -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-interfaces" 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.
|
||||
|
||||
An --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/index.pl?/sw/dhcp/authoritative.php - that's
|
||||
for the ISC daemon, but the same applies to dnsmasq.
|
||||
A: The DHCP spec says that when a DHCP server receives 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
|
||||
@@ -381,7 +454,7 @@ A: Probably the nameserver is an authoritative nameserver for a
|
||||
Q: Does the dnsmasq DHCP server probe addresses before allocating
|
||||
them, as recommended in RFC2131?
|
||||
|
||||
A: Yes, dynmaically allocated IP addresses are checked by sending an
|
||||
A: Yes, dynamically allocated IP addresses are checked by sending an
|
||||
ICMP echo request (ping). If a reply is received, then dnsmasq
|
||||
assumes that the address is in use, and attempts to allocate an
|
||||
different address. The wait for a reply is between two and three
|
||||
@@ -467,8 +540,18 @@ A: The DHCP client on windows Vista (and possibly later versions)
|
||||
work).
|
||||
|
||||
|
||||
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
|
||||
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
|
||||
Auto Detection and if you don't want or need to use that, then
|
||||
simplest fix seems to be to supply an empty option with:
|
||||
|
||||
dhcp-option=252,"\n"
|
||||
|
||||
|
||||
|
||||
|
||||
191
Makefile
191
Makefile
@@ -1,4 +1,4 @@
|
||||
# dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
||||
# dnsmasq is Copyright (c) 2000-2025 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
|
||||
@@ -13,87 +13,166 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
PREFIX = /usr/local
|
||||
BINDIR = ${PREFIX}/sbin
|
||||
MANDIR = ${PREFIX}/share/man
|
||||
LOCALEDIR = ${PREFIX}/share/locale
|
||||
# NOTE: Building the i18n targets requires GNU-make
|
||||
|
||||
PKG_CONFIG = pkg-config
|
||||
INSTALL = install
|
||||
MSGMERGE = msgmerge
|
||||
MSGFMT = msgfmt
|
||||
XGETTEXT = xgettext
|
||||
|
||||
CFLAGS = -Wall -W -O2
|
||||
# Variables you may well want to override.
|
||||
|
||||
PREFIX = /usr/local
|
||||
BINDIR = $(PREFIX)/sbin
|
||||
MANDIR = $(PREFIX)/share/man
|
||||
LOCALEDIR = $(PREFIX)/share/locale
|
||||
BUILDDIR = $(SRC)
|
||||
DESTDIR =
|
||||
CFLAGS = -Wall -W -O2
|
||||
LDFLAGS =
|
||||
COPTS =
|
||||
RPM_OPT_FLAGS =
|
||||
LIBS =
|
||||
LUA = lua
|
||||
|
||||
#################################################################
|
||||
|
||||
# Variables you might want to override.
|
||||
|
||||
PKG_CONFIG = pkg-config
|
||||
INSTALL = install
|
||||
MSGMERGE = msgmerge
|
||||
MSGFMT = msgfmt
|
||||
XGETTEXT = xgettext
|
||||
|
||||
SRC = src
|
||||
PO = po
|
||||
PO = po
|
||||
MAN = man
|
||||
|
||||
DNSMASQ_CFLAGS=`echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
|
||||
DNSMASQ_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
|
||||
IDN_CFLAGS=`echo $(COPTS) | ../bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`
|
||||
IDN_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
|
||||
SUNOS_LIBS= `if uname | grep SunOS 2>&1 >/dev/null; then echo -lsocket -lnsl -lposix4; fi`
|
||||
#################################################################
|
||||
|
||||
OBJS = cache.o rfc1035.o util.o option.o forward.o network.o \
|
||||
# pmake way. (NB no spaces to keep gmake 3.82 happy)
|
||||
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`
|
||||
ubus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_UBUS "" --copy '-lubox -lubus'`
|
||||
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 $(LUA)`
|
||||
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs $(LUA)`
|
||||
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`
|
||||
nft_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_NFTSET $(PKG_CONFIG) --cflags libnftables`
|
||||
nft_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_NFTSET $(PKG_CONFIG) --libs libnftables`
|
||||
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
|
||||
|
||||
sum?=$(shell echo $(CC) -DDNSMASQ_COMPILE_FLAGS="$(CFLAGS)" -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' ')
|
||||
sum!=echo $(CC) -DDNSMASQ_COMPILE_FLAGS="$(CFLAGS)" -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
|
||||
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
|
||||
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o pattern.o \
|
||||
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
|
||||
poll.o rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o \
|
||||
metrics.o domain-match.o nftset.o
|
||||
|
||||
all :
|
||||
@cd $(SRC) && $(MAKE) \
|
||||
BUILD_CFLAGS="$(DNSMASQ_CFLAGS) $(IDN_CFLAGS)" \
|
||||
BUILD_LIBS="$(DNSMASQ_LIBS) $(IDN_LIBS) $(SUNOS_LIBS)" \
|
||||
-f ../Makefile dnsmasq
|
||||
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||
dns-protocol.h radv-protocol.h ip6addr.h metrics.h
|
||||
|
||||
clean :
|
||||
rm -f *~ $(SRC)/*.mo contrib/*/*~ */*~ $(SRC)/*.pot
|
||||
rm -f $(SRC)/*.o $(SRC)/dnsmasq.a $(SRC)/dnsmasq core */core
|
||||
all : $(BUILDDIR)
|
||||
@cd $(BUILDDIR) && $(MAKE) \
|
||||
top="$(top)" \
|
||||
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags) $(nft_cflags)" \
|
||||
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs) $(nft_libs)" \
|
||||
-f $(top)/Makefile dnsmasq
|
||||
|
||||
install : all install-common
|
||||
mostly_clean :
|
||||
rm -f $(BUILDDIR)/*.mo $(BUILDDIR)/*.pot
|
||||
rm -f $(BUILDDIR)/.copts_* $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq
|
||||
|
||||
install-common :
|
||||
$(INSTALL) -d $(DESTDIR)$(BINDIR) -d $(DESTDIR)$(MANDIR)/man8
|
||||
clean : mostly_clean
|
||||
rm -f $(BUILDDIR)/dnsmasq_baseline
|
||||
rm -f core */core
|
||||
rm -f *~ contrib/*/*~ */*~
|
||||
|
||||
install : all
|
||||
$(INSTALL) -d $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL) -d $(DESTDIR)$(MANDIR)/man8
|
||||
$(INSTALL) -m 644 $(MAN)/dnsmasq.8 $(DESTDIR)$(MANDIR)/man8
|
||||
$(INSTALL) -m 755 $(SRC)/dnsmasq $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL) -m 755 $(BUILDDIR)/dnsmasq $(DESTDIR)$(BINDIR)
|
||||
|
||||
all-i18n :
|
||||
@cd $(SRC) && $(MAKE) \
|
||||
I18N=-DLOCALEDIR='\"$(LOCALEDIR)\"' \
|
||||
BUILD_CFLAGS="$(DNSMASQ_CFLAGS) `$(PKG_CONFIG) --cflags libidn`" \
|
||||
BUILD_LIBS="$(DNSMASQ_LIBS) $(SUNOS_LIBS) `$(PKG_CONFIG) --libs libidn`" \
|
||||
-f ../Makefile dnsmasq
|
||||
@cd $(PO); for f in *.po; do \
|
||||
cd ../$(SRC) && $(MAKE) \
|
||||
-f ../Makefile $${f%.po}.mo; \
|
||||
all-i18n : $(BUILDDIR)
|
||||
@cd $(BUILDDIR) && $(MAKE) \
|
||||
top="$(top)" \
|
||||
i18n=-DLOCALEDIR=\'\"$(LOCALEDIR)\"\' \
|
||||
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags) $(nft_cflags)" \
|
||||
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs) $(nft_libs)" \
|
||||
-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; \
|
||||
done
|
||||
|
||||
install-i18n : all-i18n install-common
|
||||
cd $(SRC); ../bld/install-mo $(DESTDIR)$(LOCALEDIR) $(INSTALL)
|
||||
install-i18n : all-i18n
|
||||
$(INSTALL) -d $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL) -d $(DESTDIR)$(MANDIR)/man8
|
||||
$(INSTALL) -m 644 $(MAN)/dnsmasq.8 $(DESTDIR)$(MANDIR)/man8
|
||||
$(INSTALL) -m 755 $(BUILDDIR)/dnsmasq $(DESTDIR)$(BINDIR)
|
||||
cd $(BUILDDIR); $(top)/bld/install-mo $(DESTDIR)$(LOCALEDIR) $(INSTALL)
|
||||
cd $(MAN); ../bld/install-man $(DESTDIR)$(MANDIR) $(INSTALL)
|
||||
|
||||
merge :
|
||||
@cd $(SRC) && $(MAKE) -f ../Makefile dnsmasq.pot
|
||||
@cd $(PO); for f in *.po; do \
|
||||
echo -n msgmerge $$f && $(MSGMERGE) --no-wrap -U $$f ../$(SRC)/dnsmasq.pot; \
|
||||
merge :
|
||||
@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;
|
||||
|
||||
# rules below are targets in recusive makes with cwd=$(SRC)
|
||||
$(BUILDDIR):
|
||||
mkdir -p $(BUILDDIR)
|
||||
|
||||
# rules below are helpers for size tracking
|
||||
|
||||
baseline : mostly_clean all
|
||||
@cd $(BUILDDIR) && \
|
||||
mv dnsmasq dnsmasq_baseline
|
||||
|
||||
bloatcheck : $(BUILDDIR)/dnsmasq_baseline mostly_clean all
|
||||
@cd $(BUILDDIR) && \
|
||||
$(top)/bld/bloat-o-meter dnsmasq_baseline dnsmasq; \
|
||||
size dnsmasq_baseline dnsmasq
|
||||
|
||||
# rules below are targets in 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 $<
|
||||
$(CC) $(CFLAGS) $(COPTS) $(i18n) $(build_cflags) $(RPM_OPT_FLAGS) -c $<
|
||||
|
||||
dnsmasq : $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(BUILD_LIBS) $(LIBS)
|
||||
dnsmasq : $(objs)
|
||||
$(CC) $(LDFLAGS) -o $@ $(objs) $(build_libs) $(LIBS)
|
||||
|
||||
dnsmasq.pot : $(OBJS:.o=.c) dnsmasq.h config.h
|
||||
$(XGETTEXT) -d dnsmasq --foreign-user --omit-header --keyword=_ -o $@ -i $(OBJS:.o=.c)
|
||||
dnsmasq.pot : $(objs:.o=.c) $(hdrs)
|
||||
$(XGETTEXT) -d dnsmasq --foreign-user --omit-header --keyword=_ -o $@ -i $(objs:.o=.c)
|
||||
|
||||
%.mo : ../po/%.po dnsmasq.pot
|
||||
$(MSGMERGE) -o - ../po/$*.po dnsmasq.pot | $(MSGFMT) -o $*.mo -
|
||||
%.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
|
||||
|
||||
@@ -6,13 +6,21 @@ include $(CLEAR_VARS)
|
||||
LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
||||
forward.c helper.c lease.c log.c \
|
||||
netlink.c network.c option.c rfc1035.c \
|
||||
rfc2131.c tftp.c util.c
|
||||
rfc2131.c tftp.c util.c conntrack.c \
|
||||
dhcp6.c rfc3315.c dhcp-common.c outpacket.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 \
|
||||
crypto.c dump.c ubus.c metrics.c \
|
||||
domain-match.c nftset.c
|
||||
|
||||
LOCAL_MODULE := dnsmasq
|
||||
|
||||
LOCAL_C_INCLUDES := external/dnsmasq/src
|
||||
|
||||
LOCAL_CFLAGS := -O2 -g -W -Wall -D__ANDROID__ -DNO_IPV6 -DNO_TFTP -DNO_SCRIPT
|
||||
LOCAL_CFLAGS := -O2 -g -W -Wall -D__ANDROID__ -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))
|
||||
41
bld/get-version
Executable file
41
bld/get-version
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Determine the version string to build into a binary.
|
||||
# When building in the git repository, we can use the output
|
||||
# of "git describe" which gives an unequivocal answer.
|
||||
#
|
||||
# Failing that, we use the contents of the VERSION file
|
||||
# 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. The insane arguments to the sort command are to ensure
|
||||
# that, eg v2.64 comes before v2.63, but v2.63 comes before v2.63rc1
|
||||
# and v2.63rc1 comes before v2.63test1
|
||||
|
||||
|
||||
# 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.
|
||||
echo UNKNOWN
|
||||
else
|
||||
vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep ^v[0-9]`
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "${vers}" | sort -k1.2,1.5Vr -k1.6,1.6 -k1.8,1.9Vr -k1.10,1.11Vr | head -n 1 | sed 's/^v//'
|
||||
else
|
||||
cat $1/VERSION
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -4,6 +4,6 @@ for f in *; do
|
||||
if [ -d $f ]; then
|
||||
$2 -m 755 -d $1/$f/man8
|
||||
$2 -m 644 $f/dnsmasq.8 $1/$f/man8
|
||||
echo installing $1/$f/man8/dnsmasq.8
|
||||
echo installing $f/man8/dnsmasq.8
|
||||
fi
|
||||
done
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
for f in *.mo; do
|
||||
$2 -m 755 -d $1/${f%.mo}/LC_MESSAGES
|
||||
$2 -m 644 $f $1/${f%.mo}/LC_MESSAGES/dnsmasq.mo
|
||||
echo installing $1/${f%.mo}/LC_MESSAGES/dnsmasq.mo
|
||||
echo installing ${f%.mo}/LC_MESSAGES/dnsmasq.mo
|
||||
done
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,45 @@
|
||||
#!/bin/sh
|
||||
|
||||
search=$1
|
||||
shift
|
||||
in=`cat`
|
||||
|
||||
if grep "^\#.*define.*$search" config.h 2>&1 >/dev/null || \
|
||||
grep $search 2>&1 >/dev/null ; then
|
||||
exec $*
|
||||
search()
|
||||
{
|
||||
grep "^\#[[:space:]]*define[[:space:]]*$1" config.h >/dev/null 2>&1 || \
|
||||
echo $in | grep $1 >/dev/null 2>&1
|
||||
}
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
search=$1
|
||||
pkg=$2
|
||||
op=$3
|
||||
lib=$4
|
||||
shift 4
|
||||
if search "$search"; then
|
||||
|
||||
# Nasty, nasty, in --copy, arg 2 (if non-empty) is another config to search for, used with NO_GMP
|
||||
if [ $op = "--copy" ]; then
|
||||
if [ -z "$pkg" ]; then
|
||||
pkg="$lib"
|
||||
elif search "$pkg"; then
|
||||
pkg=""
|
||||
else
|
||||
pkg="$lib"
|
||||
fi
|
||||
elif search "${search}_STATIC"; then
|
||||
pkg=`$pkg --static $op $lib`
|
||||
else
|
||||
pkg=`$pkg $op $lib`
|
||||
fi
|
||||
|
||||
if search "${search}_STATIC"; then
|
||||
if [ $op = "--libs" ] || [ $op = "--copy" ]; then
|
||||
echo "-Wl,-Bstatic $pkg -Wl,-Bdynamic"
|
||||
else
|
||||
echo "$pkg"
|
||||
fi
|
||||
else
|
||||
echo "$pkg"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
done
|
||||
|
||||
@@ -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,6 +0,0 @@
|
||||
This packaging is now unmaintained in the dnsmasq source: dnsmasq is
|
||||
included in Suse proper, and up-to-date packages are now available
|
||||
from
|
||||
|
||||
ftp://ftp.suse.com/pub/people/ug/
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
This is a patch against SuSEfirewall2-3.1-206 (SuSE 9.x and older)
|
||||
It fixes the depancy 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'
|
||||
|
||||
|
||||
--- /sbin/SuSEfirewall2.orig 2004-01-23 13:30:09.000000000 +0100
|
||||
+++ /sbin/SuSEfirewall2 2004-01-23 13:31:56.000000000 +0100
|
||||
@@ -764,7 +764,7 @@
|
||||
echo 'FW_ALLOW_INCOMING_HIGHPORTS_UDP should be set to yes, if you are running a DNS server!'
|
||||
|
||||
test "$FW_SERVICE_AUTODETECT" = yes -o "$FW_SERVICE_AUTODETECT" = dmz -o "$FW_SERVICE_AUTODETECT" = ext && {
|
||||
- test "$FW_SERVICE_DNS" = no -a '!' "$START_NAMED" = no && check_srv named && {
|
||||
+ test "$FW_SERVICE_DNS" = no -a '!' "$START_NAMED" = no && check_srv dnsmasq && {
|
||||
echo -e 'Warning: detected activated named, enabling FW_SERVICE_DNS!
|
||||
You still have to allow tcp/udp port 53 on internal, dmz and/or external.'
|
||||
FW_SERVICE_DNS=$FW_SERVICE_AUTODETECT
|
||||
@@ -878,7 +878,7 @@
|
||||
test -e /etc/resolv.conf || echo "Warning: /etc/resolv.conf not found"
|
||||
# Get ports/IP bindings of NAMED/SQUID
|
||||
test "$FW_SERVICE_DNS" = yes -o "$FW_SERVICE_DNS" = dmz -o "$FW_SERVICE_DNS" = ext -o "$START_NAMED" = yes && DNS_PORT=`$LSOF -i -n -P | \
|
||||
- $AWK -F: '/^named .* UDP / {print $2}'| $GREP -vw 53 | $SORT -un`
|
||||
+ $AWK -F: '/^dnsmasq .* UDP / {print $2}'| $GREP -vw 53 | $SORT -un`
|
||||
test "$FW_SERVICE_SQUID" = yes -o "$FW_SERVICE_SQUID" = dmz -o "$FW_SERVICE_SQUID" = ext -o "$START_SQUID" = yes && SQUID_PORT=`$LSOF -i -n -P | \
|
||||
$AWK -F: '/^squid .* UDP/ {print $2}'| $SORT -un`
|
||||
@@ -1,23 +0,0 @@
|
||||
--- man/dnsmasq.8 2004-08-08 20:57:56.000000000 +0200
|
||||
+++ man/dnsmasq.8 2004-08-12 00:40:01.000000000 +0200
|
||||
@@ -69,7 +69,7 @@
|
||||
.TP
|
||||
.B \-g, --group=<groupname>
|
||||
Specify the group which dnsmasq will run
|
||||
-as. The defaults to "dip", if available, to facilitate access to
|
||||
+as. The defaults to "dialout", if available, to facilitate access to
|
||||
/etc/ppp/resolv.conf which is not normally world readable.
|
||||
.TP
|
||||
.B \-v, --version
|
||||
--- src/config.h 2004-08-11 11:39:18.000000000 +0200
|
||||
+++ src/config.h 2004-08-12 00:40:01.000000000 +0200
|
||||
@@ -44,7 +44,7 @@
|
||||
#endif
|
||||
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
||||
#define CHUSER "nobody"
|
||||
-#define CHGRP "dip"
|
||||
+#define CHGRP "dialout"
|
||||
#define DHCP_SERVER_PORT 67
|
||||
#define DHCP_CLIENT_PORT 68
|
||||
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
###############################################################################
|
||||
#
|
||||
# General
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
Name: dnsmasq
|
||||
Version: 2.33
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: Productivity/Networking/DNS/Servers
|
||||
Vendor: Simon Kelley
|
||||
Packager: Simon Kelley
|
||||
URL: http://www.thekelleys.org.uk/dnsmasq
|
||||
Provides: dns_daemon
|
||||
Conflicts: bind bind8 bind9
|
||||
PreReq: %fillup_prereq %insserv_prereq
|
||||
Autoreqprov: on
|
||||
Source0: %{name}-%{version}.tar.bz2
|
||||
BuildRoot: /var/tmp/%{name}-%{version}
|
||||
Summary: A lightweight caching nameserver
|
||||
|
||||
%description
|
||||
Dnsmasq is 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 for network booting of diskless machines.
|
||||
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Build
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
patch -p0 <rpm/%{name}-SuSE.patch
|
||||
|
||||
%build
|
||||
%{?suse_update_config:%{suse_update_config -f}}
|
||||
make all-i18n DESTDIR=$RPM_BUILD_ROOT PREFIX=/usr
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Install
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
mkdir -p ${RPM_BUILD_ROOT}/etc/init.d
|
||||
make install-i18n DESTDIR=$RPM_BUILD_ROOT PREFIX=/usr
|
||||
install -o root -g root -m 755 rpm/rc.dnsmasq-suse $RPM_BUILD_ROOT/etc/init.d/dnsmasq
|
||||
install -o root -g root -m 644 dnsmasq.conf.example $RPM_BUILD_ROOT/etc/dnsmasq.conf
|
||||
strip $RPM_BUILD_ROOT/usr/sbin/dnsmasq
|
||||
ln -sf ../../etc/init.d/dnsmasq $RPM_BUILD_ROOT/usr/sbin/rcdnsmasq
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Clean up
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Post-install scriptlet
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
%post
|
||||
%{fillup_and_insserv dnsmasq}
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Post-uninstall scriptlet
|
||||
#
|
||||
# The %postun script executes after the package has been removed. It is the
|
||||
# last chance for a package to clean up after itself.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
%postun
|
||||
%{insserv_cleanup}
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# File list
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
%doc CHANGELOG COPYING FAQ doc.html setup.html UPGRADING_to_2.0 rpm/README.susefirewall
|
||||
%doc contrib
|
||||
%config /etc/init.d/dnsmasq
|
||||
%config /etc/dnsmasq.conf
|
||||
/usr/sbin/rcdnsmasq
|
||||
/usr/sbin/dnsmasq
|
||||
/usr/share/locale/*/LC_MESSAGES/*
|
||||
%doc %{_mandir}/man8/dnsmasq.8.gz
|
||||
%doc %{_mandir}/*/man8/dnsmasq.8.gz
|
||||
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# init.d/dnsmasq
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: dnsmasq
|
||||
# Required-Start: $network $remote_fs $syslog
|
||||
# Required-Stop:
|
||||
# Default-Start: 3 5
|
||||
# Default-Stop:
|
||||
# Description: Starts internet name service masq caching server (DNS)
|
||||
### END INIT INFO
|
||||
|
||||
NAMED_BIN=/usr/sbin/dnsmasq
|
||||
NAMED_PID=/var/run/dnsmasq.pid
|
||||
NAMED_CONF=/etc/dnsmasq.conf
|
||||
|
||||
if [ ! -x $NAMED_BIN ] ; then
|
||||
echo -n "dnsmasq not installed ! "
|
||||
exit 5
|
||||
fi
|
||||
|
||||
. /etc/rc.status
|
||||
rc_reset
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo -n "Starting name service masq caching server "
|
||||
checkproc -p $NAMED_PID $NAMED_BIN
|
||||
if [ $? -eq 0 ] ; then
|
||||
echo -n "- Warning: dnsmasq already running ! "
|
||||
else
|
||||
[ -e $NAMED_PID ] && echo -n "- Warning: $NAMED_PID exists ! "
|
||||
fi
|
||||
startproc -p $NAMED_PID $NAMED_BIN -u nobody
|
||||
rc_status -v
|
||||
;;
|
||||
stop)
|
||||
echo -n "Shutting name service masq caching server "
|
||||
checkproc -p $NAMED_PID $NAMED_BIN
|
||||
[ $? -ne 0 ] && echo -n "- Warning: dnsmasq not running ! "
|
||||
killproc -p $NAMED_PID -TERM $NAMED_BIN
|
||||
rc_status -v
|
||||
;;
|
||||
try-restart)
|
||||
$0 stop && $0 start
|
||||
rc_status
|
||||
;;
|
||||
restart)
|
||||
$0 stop
|
||||
$0 start
|
||||
rc_status
|
||||
;;
|
||||
force-reload)
|
||||
$0 reload
|
||||
rc_status
|
||||
;;
|
||||
reload)
|
||||
echo -n "Reloading name service masq caching server "
|
||||
checkproc -p $NAMED_PID $NAMED_BIN
|
||||
[ $? -ne 0 ] && echo -n "- Warning: dnsmasq not running ! "
|
||||
killproc -p $NAMED_PID -HUP $NAMED_BIN
|
||||
rc_status -v
|
||||
;;
|
||||
status)
|
||||
echo -n "Checking for name service masq caching server "
|
||||
checkproc -p $NAMED_PID $NAMED_BIN
|
||||
rc_status -v
|
||||
;;
|
||||
probe)
|
||||
test $NAMED_CONF -nt $NAMED_PID && echo reload
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
rc_exit
|
||||
|
||||
54
contrib/conntrack/README
Normal file
54
contrib/conntrack/README
Normal file
@@ -0,0 +1,54 @@
|
||||
Linux iptables includes that ability to mark individual network packets
|
||||
with a "firewall mark". Additionally there is a component called
|
||||
"conntrack" which tries to string sequences of related packets together
|
||||
into a "connection" (it even relates sequences of UDP and ICMP packets).
|
||||
There is a related mark for a connection called a "connection mark".
|
||||
Marks can be copied freely between the firewall and connection marks
|
||||
|
||||
Using these two features it become possible to tag all related traffic
|
||||
in arbitrary ways, eg authenticated users, traffic from a particular IP,
|
||||
port, etc. Unfortunately any kind of "proxy" breaks this relationship
|
||||
because network packets go in one side of the proxy and a completely new
|
||||
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
|
||||
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,
|
||||
captive portals and the like. Note a similar feature has been
|
||||
implemented in Squid 2.2
|
||||
|
||||
|
||||
As an example consider the following iptables rules:
|
||||
|
||||
|
||||
1) iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
|
||||
2) iptables -t mangle -A PREROUTING -m mark --mark 0 -s 192.168.111.137
|
||||
-j MARK --set-mark 137
|
||||
3) iptables -t mangle -A PREROUTING -j CONNMARK --save-mark
|
||||
|
||||
4) iptables -t mangle -A OUTPUT -m mark ! --mark 0 -j CONNMARK --save-mark
|
||||
|
||||
1-3) are all applied to the PREROUTING table and affect all packets
|
||||
entering the firewall.
|
||||
|
||||
1) copies any existing connection mark into the firewall mark. 2) Checks
|
||||
the packet not already marked and if not applies an arbitrary mark based
|
||||
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
|
||||
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.
|
||||
|
||||
Note: iptables can be quite confusing to the beginner. The following
|
||||
diagram is extremely helpful in understanding the flows
|
||||
http://linux-ip.net/nf/nfk-traversal.png
|
||||
Additionally the following URL contains a useful "starting guide" on
|
||||
linux connection tracking/marking
|
||||
http://home.regit.org/netfilter-en/netfilter-connmark/
|
||||
|
||||
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
|
||||
25
contrib/lease-tools/dhcp_lease_time.1
Normal file
25
contrib/lease-tools/dhcp_lease_time.1
Normal file
@@ -0,0 +1,25 @@
|
||||
.TH DHCP_LEASE_TIME 1
|
||||
.SH NAME
|
||||
dhcp_lease_time \- Query remaining time of a lease on a the local dnsmasq DHCP server.
|
||||
.SH SYNOPSIS
|
||||
.B dhcp_lease_time <address>
|
||||
.SH "DESCRIPTION"
|
||||
Send a DHCPINFORM message to a dnsmasq server running on the local host
|
||||
and print (to stdout) the time remaining in any lease for the given
|
||||
address. The time is given as string printed to stdout.
|
||||
|
||||
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.67 or later and may not work with other DHCP servers.
|
||||
|
||||
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
|
||||
This manual page was written by Simon Kelley <simon@thekelleys.org.uk>.
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -82,7 +83,7 @@ static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt
|
||||
if (p >= end - 2)
|
||||
return NULL; /* malformed packet */
|
||||
opt_len = option_len(p);
|
||||
if (p >= end - (2 + opt_len))
|
||||
if (end - p < (2 + opt_len))
|
||||
return NULL; /* malformed packet */
|
||||
if (*p == opt && opt_len >= minsize)
|
||||
return p;
|
||||
@@ -152,7 +153,11 @@ int main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
lease.s_addr = inet_addr(argv[1]);
|
||||
if (inet_pton(AF_INET, argv[1], &lease) < 1)
|
||||
{
|
||||
fprintf(stderr, "invalid address: %s\n", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(&packet, 0, sizeof(packet));
|
||||
|
||||
@@ -167,10 +172,16 @@ 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;
|
||||
dest.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
dest.sin_family = AF_INET;
|
||||
(void)inet_pton(AF_INET, "127.0.0.1", &dest.sin_addr);
|
||||
dest.sin_port = ntohs(DHCP_SERVER_PORT);
|
||||
|
||||
if (sendto(fd, &packet, sizeof(packet), 0,
|
||||
@@ -199,13 +210,13 @@ int main(int argc, char **argv)
|
||||
{
|
||||
unsigned int x;
|
||||
if ((x = t/86400))
|
||||
printf("%dd", x);
|
||||
printf("%ud", x);
|
||||
if ((x = (t/3600)%24))
|
||||
printf("%dh", x);
|
||||
printf("%uh", x);
|
||||
if ((x = (t/60)%60))
|
||||
printf("%dm", x);
|
||||
printf("%um", x);
|
||||
if ((x = t%60))
|
||||
printf("%ds", x);
|
||||
printf("%us", x);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
37
contrib/lease-tools/dhcp_release.1
Normal file
37
contrib/lease-tools/dhcp_release.1
Normal file
@@ -0,0 +1,37 @@
|
||||
.TH DHCP_RELEASE 1
|
||||
.SH NAME
|
||||
dhcp_release \- Release a DHCP lease on a the local dnsmasq DHCP server.
|
||||
.SH SYNOPSIS
|
||||
.B dhcp_release <interface> <address> <MAC address> <client_id>
|
||||
.SH "DESCRIPTION"
|
||||
A utility which forces the DHCP server running on this machine to release a
|
||||
DHCP lease.
|
||||
.PP
|
||||
Send a DHCPRELEASE message 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 address argument is a dotted-quad IP addresses and mandatory.
|
||||
|
||||
The MAC address is colon separated hex, and is mandatory. It may be
|
||||
prefixed by an address-type byte followed by -, eg
|
||||
|
||||
10-11:22:33:44:55:66
|
||||
|
||||
but if the address-type byte is missing it is assumed to be 1, the type
|
||||
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
|
||||
This manual page was written by Simon Kelley <simon@thekelleys.org.uk>.
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -178,7 +178,7 @@ static int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
|
||||
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
|
||||
}
|
||||
|
||||
static struct in_addr find_interface(struct in_addr client, int fd, int index)
|
||||
static struct in_addr find_interface(struct in_addr client, int fd, unsigned int index, int ifrfd, struct ifreq *ifr)
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
struct nlmsghdr *h;
|
||||
@@ -218,7 +218,17 @@ static struct in_addr find_interface(struct in_addr client, int fd, int index)
|
||||
|
||||
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
|
||||
if (h->nlmsg_type == NLMSG_DONE)
|
||||
exit(0);
|
||||
{
|
||||
/* No match found, return first address as src/dhcp.c code does */
|
||||
ifr->ifr_addr.sa_family = AF_INET;
|
||||
if (ioctl(ifrfd, SIOCGIFADDR, ifr) != -1)
|
||||
return ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "error: local IPv4 address not found\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else if (h->nlmsg_type == RTM_NEWADDR)
|
||||
{
|
||||
struct ifaddrmsg *ifa = NLMSG_DATA(h);
|
||||
@@ -255,10 +265,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)
|
||||
{
|
||||
@@ -274,16 +280,22 @@ int main(int argc, char **argv)
|
||||
|
||||
/* This voodoo fakes up a packet coming from the correct interface, which really matters for
|
||||
a DHCP server */
|
||||
strcpy(ifr.ifr_name, argv[1]);
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)-1);
|
||||
ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0';
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1)
|
||||
{
|
||||
perror("cannot setup interface");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (inet_pton(AF_INET, argv[2], &lease.s_addr) < 1)
|
||||
{
|
||||
perror("invalid ip address");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
lease.s_addr = inet_addr(argv[2]);
|
||||
server = find_interface(lease, nl, if_nametoindex(argv[1]));
|
||||
server = find_interface(lease, nl, if_nametoindex(argv[1]), fd, &ifr);
|
||||
|
||||
memset(&packet, 0, sizeof(packet));
|
||||
|
||||
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>.
|
||||
|
||||
|
||||
508
contrib/lease-tools/dhcp_release6.c
Normal file
508
contrib/lease-tools/dhcp_release6.c
Normal file
@@ -0,0 +1,508 @@
|
||||
/*
|
||||
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)
|
||||
{
|
||||
int16_t ret = -1;
|
||||
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;
|
||||
}
|
||||
|
||||
/* Got success status, return that if there's no specific error in an IA_NA. */
|
||||
ret = SUCCESS;
|
||||
}
|
||||
|
||||
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 ret;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void fail_fatal(const char *errstr, int exitcode)
|
||||
{
|
||||
perror(errstr);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
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;
|
||||
if (inet_pton(AF_INET6, "::", &client_addr.sin6_addr) <= 0)
|
||||
fail_fatal("inet_pton", 5);
|
||||
if (bind(sock, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in6)) != 0)
|
||||
perror("bind"); /* continue on bind error */
|
||||
if (inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr) <= 0)
|
||||
fail_fatal("inet_pton", 5);
|
||||
server_addr.sin6_port = htons(DHCP6_SERVER_PORT);
|
||||
ssize_t recv_size = 0;
|
||||
int result;
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
if (sendto(sock, packet->buf, packet->len, 0, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
|
||||
fail_fatal("sendto failed", 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");
|
||||
result = UNSPEC_FAIL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = parse_packet(response, recv_size);
|
||||
if (result == NOT_REPLY_CODE)
|
||||
{
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
close(sock);
|
||||
return result;
|
||||
}
|
||||
|
||||
close(sock);
|
||||
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);
|
||||
}
|
||||
695
contrib/leasequery/leasequery.c
Normal file
695
contrib/leasequery/leasequery.c
Normal file
@@ -0,0 +1,695 @@
|
||||
/* leasequery is Copyright (c) 2025 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/>.
|
||||
*/
|
||||
|
||||
/* Author's email: simon@thekelleys.org.uk */
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <limits.h>
|
||||
#include <net/if.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <netdb.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/capability.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <ctype.h>
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long long u64;
|
||||
|
||||
#define INADDRSZ 4
|
||||
#define ADDRSTRLEN 46
|
||||
|
||||
#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
|
||||
#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
|
||||
|
||||
#define DHCP_CHADDR_MAX 16
|
||||
#define DHCP_SERVER_PORT 67
|
||||
#define DHCP_CLIENT_PORT 68
|
||||
#define BOOTREQUEST 1
|
||||
#define BOOTREPLY 2
|
||||
|
||||
#define DHCP_COOKIE 0x63825363
|
||||
|
||||
#define DHCPLEASEQUERY 10
|
||||
#define DHCPLEASEUNASSIGNED 11
|
||||
#define DHCPLEASEUNKNOWN 12
|
||||
#define DHCPLEASEACTIVE 13
|
||||
|
||||
#define OPTION_END 255
|
||||
#define OPTION_ROUTER 3
|
||||
#define OPTION_VENDOR_CLASS_OPT 43
|
||||
#define OPTION_LEASE_TIME 51
|
||||
#define OPTION_MESSAGE_TYPE 53
|
||||
#define OPTION_SERVER_IDENTIFIER 54
|
||||
#define OPTION_REQUESTED_OPTIONS 55
|
||||
#define OPTION_VENDOR_ID 60
|
||||
#define OPTION_CLIENT_ID 61
|
||||
|
||||
/* flags in top of length field for DHCP-option tables */
|
||||
#define OT_ADDR_LIST 0x8000
|
||||
#define OT_RFC1035_NAME 0x4000
|
||||
#define OT_INTERNAL 0x2000
|
||||
#define OT_NAME 0x1000
|
||||
#define OT_CSTRING 0x0800
|
||||
#define OT_DEC 0x0400
|
||||
#define OT_TIME 0x0200
|
||||
|
||||
#define GETSHORT(s, cp) do { \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
(s) = ((u16)t_cp[0] << 8) \
|
||||
| ((u16)t_cp[1]) \
|
||||
; \
|
||||
(cp) += 2; \
|
||||
} while(0)
|
||||
|
||||
#define GETLONG(l, cp) do { \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
(l) = ((u32)t_cp[0] << 24) \
|
||||
| ((u32)t_cp[1] << 16) \
|
||||
| ((u32)t_cp[2] << 8) \
|
||||
| ((u32)t_cp[3]) \
|
||||
; \
|
||||
(cp) += 4; \
|
||||
} while (0)
|
||||
|
||||
#define PUTSHORT(s, cp) do { \
|
||||
u16 t_s = (u16)(s); \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
*t_cp++ = t_s >> 8; \
|
||||
*t_cp = t_s; \
|
||||
(cp) += 2; \
|
||||
} while(0)
|
||||
|
||||
#define PUTLONG(l, cp) do { \
|
||||
u32 t_l = (u32)(l); \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
*t_cp++ = t_l >> 24; \
|
||||
*t_cp++ = t_l >> 16; \
|
||||
*t_cp++ = t_l >> 8; \
|
||||
*t_cp = t_l; \
|
||||
(cp) += 4; \
|
||||
} while (0)
|
||||
|
||||
union all_addr {
|
||||
struct in_addr addr4;
|
||||
struct in6_addr addr6;
|
||||
};
|
||||
|
||||
struct dhcp_packet_with_opts{
|
||||
struct dhcp_packet {
|
||||
unsigned char op, htype, hlen, hops;
|
||||
unsigned int xid;
|
||||
unsigned short secs, flags;
|
||||
struct in_addr ciaddr, yiaddr, siaddr, giaddr;
|
||||
unsigned char chaddr[DHCP_CHADDR_MAX], sname[64], file[128];
|
||||
} header;
|
||||
unsigned char options[312];
|
||||
};
|
||||
|
||||
static const struct opttab_t {
|
||||
char *name;
|
||||
u16 val, size;
|
||||
} opttab[] = {
|
||||
{ "netmask", 1, OT_ADDR_LIST },
|
||||
{ "time-offset", 2, 4 },
|
||||
{ "router", 3, OT_ADDR_LIST },
|
||||
{ "dns-server", 6, OT_ADDR_LIST },
|
||||
{ "log-server", 7, OT_ADDR_LIST },
|
||||
{ "lpr-server", 9, OT_ADDR_LIST },
|
||||
{ "hostname", 12, OT_INTERNAL | OT_NAME },
|
||||
{ "boot-file-size", 13, 2 | OT_DEC },
|
||||
{ "domain-name", 15, OT_NAME },
|
||||
{ "swap-server", 16, OT_ADDR_LIST },
|
||||
{ "root-path", 17, OT_NAME },
|
||||
{ "extension-path", 18, OT_NAME },
|
||||
{ "ip-forward-enable", 19, 1 },
|
||||
{ "non-local-source-routing", 20, 1 },
|
||||
{ "policy-filter", 21, OT_ADDR_LIST },
|
||||
{ "max-datagram-reassembly", 22, 2 | OT_DEC },
|
||||
{ "default-ttl", 23, 1 | OT_DEC },
|
||||
{ "mtu", 26, 2 | OT_DEC },
|
||||
{ "all-subnets-local", 27, 1 },
|
||||
{ "broadcast", 28, OT_INTERNAL | OT_ADDR_LIST },
|
||||
{ "router-discovery", 31, 1 },
|
||||
{ "router-solicitation", 32, OT_ADDR_LIST },
|
||||
{ "static-route", 33, OT_ADDR_LIST },
|
||||
{ "trailer-encapsulation", 34, 1 },
|
||||
{ "arp-timeout", 35, 4 | OT_DEC },
|
||||
{ "ethernet-encap", 36, 1 },
|
||||
{ "tcp-ttl", 37, 1 },
|
||||
{ "tcp-keepalive", 38, 4 | OT_DEC },
|
||||
{ "nis-domain", 40, OT_NAME },
|
||||
{ "nis-server", 41, OT_ADDR_LIST },
|
||||
{ "ntp-server", 42, OT_ADDR_LIST },
|
||||
{ "vendor-encap", 43, OT_INTERNAL },
|
||||
{ "netbios-ns", 44, OT_ADDR_LIST },
|
||||
{ "netbios-dd", 45, OT_ADDR_LIST },
|
||||
{ "netbios-nodetype", 46, 1 },
|
||||
{ "netbios-scope", 47, 0 },
|
||||
{ "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_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_TIME},
|
||||
{ "T2", 59, OT_TIME},
|
||||
{ "vendor-class", 60, OT_NAME },
|
||||
{ "client-id", 61, OT_INTERNAL },
|
||||
{ "nis+-domain", 64, OT_NAME },
|
||||
{ "nis+-server", 65, OT_ADDR_LIST },
|
||||
{ "tftp-server", 66, OT_NAME },
|
||||
{ "bootfile-name", 67, OT_NAME },
|
||||
{ "mobile-ip-home", 68, OT_ADDR_LIST },
|
||||
{ "smtp-server", 69, OT_ADDR_LIST },
|
||||
{ "pop3-server", 70, OT_ADDR_LIST },
|
||||
{ "nntp-server", 71, OT_ADDR_LIST },
|
||||
{ "irc-server", 74, OT_ADDR_LIST },
|
||||
{ "user-class", 77, 0 },
|
||||
{ "rapid-commit", 80, 0 },
|
||||
{ "FQDN", 81, OT_INTERNAL },
|
||||
{ "agent-info", 82, OT_INTERNAL },
|
||||
{ "last-transaction", 91, 4 | OT_TIME },
|
||||
{ "associated-ip", 92, OT_ADDR_LIST },
|
||||
{ "client-arch", 93, 2 | OT_DEC },
|
||||
{ "client-interface-id", 94, 0 },
|
||||
{ "client-machine-id", 97, 0 },
|
||||
{ "posix-timezone", 100, OT_NAME }, /* RFC 4833, Sec. 2 */
|
||||
{ "tzdb-timezone", 101, OT_NAME }, /* RFC 4833, Sec. 2 */
|
||||
{ "ipv6-only", 108, 4 | OT_DEC }, /* RFC 8925 */
|
||||
{ "subnet-select", 118, OT_INTERNAL },
|
||||
{ "domain-search", 119, OT_RFC1035_NAME },
|
||||
{ "sip-server", 120, 0 },
|
||||
{ "classless-static-route", 121, 0 },
|
||||
{ "vendor-id-encap", 125, 0 },
|
||||
{ "tftp-server-address", 150, OT_ADDR_LIST },
|
||||
{ "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
||||
static void prettyprint_time(char *buf, unsigned int t);
|
||||
static char *print_mac(char *buff, unsigned char *mac, int len);
|
||||
|
||||
int lookup_dhcp_opt(char *name)
|
||||
{
|
||||
const struct opttab_t *t = opttab;
|
||||
int i;
|
||||
|
||||
for (i = 0; t[i].name; i++)
|
||||
if (strcasecmp(t[i].name, name) == 0)
|
||||
return t[i].val;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *option_string(unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
|
||||
{
|
||||
int o, i, j, nodecode = 0;
|
||||
const struct opttab_t *ot = opttab;
|
||||
char addrbuff[ADDRSTRLEN];
|
||||
|
||||
for (o = 0; ot[o].name; o++)
|
||||
if (ot[o].val == opt)
|
||||
{
|
||||
if (buf)
|
||||
{
|
||||
memset(buf, 0, buf_len);
|
||||
|
||||
if (ot[o].size & OT_ADDR_LIST)
|
||||
{
|
||||
union all_addr addr;
|
||||
int addr_len = INADDRSZ;
|
||||
|
||||
for (buf[0]= 0, i = 0; i <= opt_len - addr_len; i += addr_len)
|
||||
{
|
||||
if (i != 0)
|
||||
strncat(buf, ", ", buf_len - strlen(buf));
|
||||
/* align */
|
||||
memcpy(&addr, &val[i], addr_len);
|
||||
inet_ntop(AF_INET, &val[i], addrbuff, ADDRSTRLEN);
|
||||
strncat(buf, addrbuff, buf_len - strlen(buf));
|
||||
}
|
||||
}
|
||||
else if (ot[o].size & OT_NAME)
|
||||
for (i = 0, j = 0; i < opt_len && j < buf_len ; i++)
|
||||
{
|
||||
char c = val[i];
|
||||
if (isprint((unsigned char)c))
|
||||
buf[j++] = c;
|
||||
}
|
||||
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];
|
||||
|
||||
if (ot[o].size & OT_TIME)
|
||||
prettyprint_time(buf, dec);
|
||||
else
|
||||
sprintf(buf, "%u", dec);
|
||||
}
|
||||
else
|
||||
nodecode = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (opt_len != 0 && buf && (!ot[o].name || nodecode))
|
||||
{
|
||||
int trunc = 0;
|
||||
if (opt_len > 14)
|
||||
{
|
||||
trunc = 1;
|
||||
opt_len = 14;
|
||||
}
|
||||
print_mac(buf, val, opt_len);
|
||||
if (trunc)
|
||||
strncat(buf, "...", buf_len - strlen(buf));
|
||||
|
||||
|
||||
}
|
||||
|
||||
return ot[o].name ? ot[o].name : "";
|
||||
|
||||
}
|
||||
|
||||
static void prettyprint_time(char *buf, unsigned int t)
|
||||
{
|
||||
if (t == 0xffffffff)
|
||||
sprintf(buf, "infinite");
|
||||
else
|
||||
{
|
||||
unsigned int x, p = 0;
|
||||
if ((x = t/86400))
|
||||
p += sprintf(&buf[p], "%ud", x);
|
||||
if ((x = (t/3600)%24))
|
||||
p += sprintf(&buf[p], "%uh", x);
|
||||
if ((x = (t/60)%60))
|
||||
p += sprintf(&buf[p], "%um", x);
|
||||
if ((x = t%60))
|
||||
sprintf(&buf[p], "%us", x);
|
||||
}
|
||||
}
|
||||
|
||||
static char *print_mac(char *buff, unsigned char *mac, int len)
|
||||
{
|
||||
char *p = buff;
|
||||
int i;
|
||||
|
||||
if (len == 0)
|
||||
sprintf(p, "<null>");
|
||||
else
|
||||
for (i = 0; i < len; i++)
|
||||
p += sprintf(p, "%.2x%s", mac[i], (i == len - 1) ? "" : ":");
|
||||
|
||||
return buff;
|
||||
}
|
||||
|
||||
static unsigned char *dhcp_skip_opts(struct dhcp_packet_with_opts *pktp)
|
||||
{
|
||||
unsigned char *start = (unsigned char *)(((unsigned int *)&pktp->options[0]) + 1);
|
||||
while (*start != 0)
|
||||
start += start[1] + 2;
|
||||
return start;
|
||||
}
|
||||
|
||||
static unsigned char *dhcp_find_opt(struct dhcp_packet_with_opts *pktp, int optno)
|
||||
{
|
||||
unsigned char *start = (unsigned char *)(((unsigned int *)&pktp->options[0]) + 1);
|
||||
while (*start != OPTION_END)
|
||||
{
|
||||
if (*start == optno)
|
||||
return start;
|
||||
start += start[1] + 2;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void option_put(struct dhcp_packet_with_opts *pktp, int opt, int len, unsigned int val)
|
||||
{
|
||||
int i;
|
||||
unsigned char *p = dhcp_skip_opts(pktp);
|
||||
|
||||
if (p)
|
||||
{
|
||||
*p++ = opt;
|
||||
*p++ = len;
|
||||
for (i = 0; i < len; i++)
|
||||
*(p++) = val >> (8 * (len - (i + 1)));
|
||||
}
|
||||
}
|
||||
|
||||
static void option_put_string(struct dhcp_packet_with_opts *pktp, int opt,
|
||||
const char *string, int null_term)
|
||||
{
|
||||
unsigned char *p;
|
||||
size_t len = strlen(string);
|
||||
|
||||
if (null_term && len != 255)
|
||||
len++;
|
||||
|
||||
if ((p = dhcp_skip_opts(pktp)))
|
||||
{
|
||||
*p++ = opt;
|
||||
*p++ = len;
|
||||
memcpy(p, string, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* in may equal out, when maxlen may be -1 (No max len).
|
||||
Return -1 for extraneous no-hex chars found. */
|
||||
int parse_hex(char *in, unsigned char *out, int maxlen,
|
||||
unsigned int *wildcard_mask, int *mac_type)
|
||||
{
|
||||
int done = 0, mask = 0, i = 0;
|
||||
char *r;
|
||||
|
||||
if (mac_type)
|
||||
*mac_type = 0;
|
||||
|
||||
while (!done && (maxlen == -1 || i < maxlen))
|
||||
{
|
||||
for (r = in; *r != 0 && *r != ':' && *r != '-' && *r != ' '; r++)
|
||||
if (*r != '*' && !isxdigit((unsigned char)*r))
|
||||
return -1;
|
||||
|
||||
if (*r == 0)
|
||||
done = 1;
|
||||
|
||||
if (r != in )
|
||||
{
|
||||
if (*r == '-' && i == 0 && mac_type)
|
||||
{
|
||||
*r = 0;
|
||||
*mac_type = strtol(in, NULL, 16);
|
||||
mac_type = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
*r = 0;
|
||||
if (strcmp(in, "*") == 0)
|
||||
{
|
||||
mask = (mask << 1) | 1;
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
int j, bytes = (1 + (r - in))/2;
|
||||
for (j = 0; j < bytes; j++)
|
||||
{
|
||||
char sav;
|
||||
if (j < bytes - 1)
|
||||
{
|
||||
sav = in[(j+1)*2];
|
||||
in[(j+1)*2] = 0;
|
||||
}
|
||||
/* checks above allow mix of hexdigit and *, which
|
||||
is illegal. */
|
||||
if (strchr(&in[j*2], '*'))
|
||||
return -1;
|
||||
out[i] = strtol(&in[j*2], NULL, 16);
|
||||
mask = mask << 1;
|
||||
if (++i == maxlen)
|
||||
break;
|
||||
if (j < bytes - 1)
|
||||
in[(j+1)*2] = sav;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
in = r+1;
|
||||
}
|
||||
|
||||
if (wildcard_mask)
|
||||
*wildcard_mask = mask;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static char *split_chr(char *s, char c)
|
||||
{
|
||||
char *comma, *p;
|
||||
|
||||
if (!s || !(comma = strchr(s, c)))
|
||||
return NULL;
|
||||
|
||||
p = comma;
|
||||
*comma = ' ';
|
||||
|
||||
for (; *comma == ' '; comma++);
|
||||
|
||||
for (; (p >= s) && *p == ' '; p--)
|
||||
*p = 0;
|
||||
|
||||
return comma;
|
||||
}
|
||||
|
||||
static char *split(char *s)
|
||||
{
|
||||
return split_chr(s, ',');
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int fd;
|
||||
struct ifreq ifr;
|
||||
struct in_addr iface_addr, server_addr, lease_addr;
|
||||
struct dhcp_packet_with_opts pkt;
|
||||
struct sockaddr_in saddr;
|
||||
unsigned char *p;
|
||||
ssize_t sz;
|
||||
unsigned char mac[DHCP_CHADDR_MAX], clid[256], req_options[256];
|
||||
char buff[500];
|
||||
int clid_len = 0, mac_len = 0, mac_type = 0, opts_len = 0;
|
||||
unsigned short port = DHCP_SERVER_PORT;
|
||||
unsigned int xid;
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
srand(tv.tv_usec);
|
||||
xid = rand();
|
||||
server_addr.s_addr = lease_addr.s_addr = iface_addr.s_addr = 0;
|
||||
|
||||
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
{
|
||||
perror("leasequery: cannot create socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
int option = getopt(argc, argv, "i:s:l:m:c:p:r:");
|
||||
|
||||
if (option == -1)
|
||||
break;
|
||||
|
||||
switch (option)
|
||||
{
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"-p <port> port on DHCP server.\n"
|
||||
"-i <interface> exit interface to DHCP server.\n"
|
||||
"-s <inet-addr> DHCP server address.\n"
|
||||
"-l <inet-addr> Query lease by IP address.\n"
|
||||
"-m <MAC-addr> Query lease by MAC address.\n"
|
||||
"-c <hex> Query lease by client-id.\n"
|
||||
"-r <name>|<int>[,...] List of options to return.\n");
|
||||
exit(1);
|
||||
|
||||
case 'p':
|
||||
port = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
strncpy(ifr.ifr_name, optarg, IF_NAMESIZE);
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
if (ioctl(fd, SIOCGIFADDR, &ifr) == -1)
|
||||
{
|
||||
perror("leasequery: cannot get interface address");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if (inet_pton(AF_INET, optarg, &server_addr) <= 0)
|
||||
{
|
||||
fprintf(stderr, "leasequery: bad server address\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
if (inet_pton(AF_INET, optarg, &lease_addr) <= 0)
|
||||
{
|
||||
fprintf(stderr, "leasequery: bad lease address\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
mac_type = 1; /* default ethernet */
|
||||
mac_len = parse_hex(optarg, mac, DHCP_CHADDR_MAX, NULL, &mac_type);
|
||||
if (!mac_type)
|
||||
mac_type = 1; /* default ethernet */
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
clid_len = parse_hex(optarg, clid, 256, NULL, NULL);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
{
|
||||
char *comma;
|
||||
int opt;
|
||||
|
||||
while (optarg)
|
||||
{
|
||||
comma = split(optarg);
|
||||
|
||||
if ((opt = lookup_dhcp_opt(optarg)) != -1 || (opt = atoi(optarg)) != 0)
|
||||
req_options[opts_len++] = opt;
|
||||
|
||||
optarg = comma;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!server_addr.s_addr)
|
||||
{
|
||||
fprintf(stderr, "leasequery: no server address\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(&pkt, 0, sizeof pkt);
|
||||
pkt.header.op = BOOTREQUEST;
|
||||
pkt.header.xid = xid;
|
||||
pkt.header.ciaddr = lease_addr;
|
||||
pkt.header.hlen = mac_len;
|
||||
pkt.header.htype = mac_type;
|
||||
memcpy(pkt.header.chaddr, mac, mac_len);
|
||||
*((unsigned int *)&pkt.options[0]) = htonl(DHCP_COOKIE);
|
||||
|
||||
/* Dnsmasq extension. */
|
||||
pkt.header.giaddr.s_addr = iface_addr.s_addr ? iface_addr.s_addr : INADDR_BROADCAST;
|
||||
|
||||
option_put(&pkt, OPTION_MESSAGE_TYPE, 1, DHCPLEASEQUERY);
|
||||
|
||||
if (clid_len != 0)
|
||||
{
|
||||
p = dhcp_skip_opts(&pkt);
|
||||
*p++ = OPTION_CLIENT_ID;
|
||||
*p++ = clid_len;
|
||||
memcpy(p, clid, clid_len);
|
||||
}
|
||||
|
||||
if (opts_len != 0)
|
||||
{
|
||||
p = dhcp_skip_opts(&pkt);
|
||||
*p++ = OPTION_REQUESTED_OPTIONS;
|
||||
*p++ = opts_len;
|
||||
memcpy(p, req_options, opts_len);
|
||||
}
|
||||
|
||||
if (iface_addr.s_addr)
|
||||
{
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_port = htons(port);
|
||||
saddr.sin_addr.s_addr = iface_addr.s_addr;
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)))
|
||||
{
|
||||
perror("leasequery: cannot bind DHCP server socket");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_port = htons(port);
|
||||
saddr.sin_addr = server_addr;
|
||||
|
||||
while((sz = sendto(fd, &pkt, dhcp_skip_opts(&pkt) - ((unsigned char *)&pkt), 0, (struct sockaddr *)&saddr, sizeof(saddr))) == -1 &&
|
||||
errno == EINTR);
|
||||
|
||||
if (sz == -1)
|
||||
{
|
||||
perror("leasequery: sendto()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sz = recv(fd, &pkt, sizeof(pkt), 0);
|
||||
|
||||
if (sz == -1)
|
||||
{
|
||||
perror("leasequery: recv()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (sz >= sizeof(pkt.header) &&
|
||||
pkt.header.op == BOOTREPLY &&
|
||||
(p = dhcp_find_opt(&pkt, OPTION_MESSAGE_TYPE)) &&
|
||||
pkt.header.xid == xid)
|
||||
{
|
||||
if (p[2] == DHCPLEASEUNASSIGNED)
|
||||
printf("UNASSIGNED\n");
|
||||
else if (p[2] == DHCPLEASEUNKNOWN)
|
||||
printf("UNKNOWN\n");
|
||||
else if (p[2] == DHCPLEASEACTIVE)
|
||||
{
|
||||
print_mac(buff, pkt.header.chaddr, pkt.header.hlen);
|
||||
printf("ACTIVE %s %s\n", inet_ntoa(pkt.header.ciaddr), buff);
|
||||
|
||||
p = (unsigned char *)(((unsigned int *)&pkt.options[0]) + 1);
|
||||
|
||||
while (*p != OPTION_END)
|
||||
{
|
||||
if (*p != OPTION_MESSAGE_TYPE)
|
||||
{
|
||||
char *optname = option_string(p[0], option_ptr(p, 0), option_len(p), buff, 500);
|
||||
|
||||
printf("size:%3d option:%3d %s %s\n", option_len(p), p[0], optname, buff);
|
||||
}
|
||||
p += p[1] + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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 an 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
|
||||
@@ -34,11 +34,21 @@ if [ ${DNSMASQ_OLD_HOSTNAME} ] && [ ${action} = old ] ; then
|
||||
hostname=${DNSMASQ_OLD_HOSTNAME}
|
||||
fi
|
||||
|
||||
# IPv6 leases are not our concern. no NAT there!
|
||||
if [ ${DNSMASQ_IAID} ] ; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# action init is not relevant, and will only be seen when leasefile-ro is set.
|
||||
if [ ${action} = init ] ; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# action tftp is not relevant.
|
||||
if [ ${action} = tftp ] ; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ ${hostname} ]; then
|
||||
ports=$(sed -n -e "/^${hostname}\ .*/ s/^.* //p" ${PORTSFILE})
|
||||
|
||||
|
||||
@@ -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 dash 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/dash
|
||||
# $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
|
||||
|
||||
16
contrib/systemd/README
Normal file
16
contrib/systemd/README
Normal file
@@ -0,0 +1,16 @@
|
||||
Hello,
|
||||
|
||||
I created a systemd service file for dnsmasq.
|
||||
systemd is a sysvinit replacement (see [1] for more information).
|
||||
One of the goals of systemd is to encourage standardization between different
|
||||
distributions. This means, while I also submitted a ticket in Debian GNU/Linux,
|
||||
I would like to ask you to accept this service file as the upstream
|
||||
distributor, so that other distributions can use the same service file and
|
||||
don’t have to ship their own.
|
||||
|
||||
Please include this file in your next release (just like in init script).
|
||||
|
||||
|
||||
[1] http://en.wikipedia.org/wiki/Systemd
|
||||
|
||||
|
||||
57
contrib/systemd/dbus_activation
Normal file
57
contrib/systemd/dbus_activation
Normal file
@@ -0,0 +1,57 @@
|
||||
To: dnsmasq-discuss@lists.thekelleys.org.uk
|
||||
From: Alex Elsayed <eternaleye+usenet@gmail.com>
|
||||
Date: Tue, 15 May 2012 01:53:54 -0700
|
||||
Subject: [Dnsmasq-discuss] [PATCH] Support dbus activation
|
||||
|
||||
Introduce dbus service file and turn dbus on in the systemd
|
||||
unit.
|
||||
|
||||
Note to packagers:
|
||||
To add support for dbus activation, you must install the dbus
|
||||
service file (dbus/uk.org.thekelleys.dnsmasq.service) into
|
||||
$DATADIR/dbus-1/system-services.
|
||||
|
||||
---
|
||||
contrib/systemd/dnsmasq.service | 2 +-
|
||||
dbus/uk.org.thekelleys.dnsmasq.service | 7 +++++++
|
||||
2 files changed, 8 insertions(+), 1 deletion(-)
|
||||
create mode 100644 dbus/uk.org.thekelleys.dnsmasq.service
|
||||
|
||||
diff --git a/contrib/systemd/dnsmasq.service
|
||||
b/contrib/systemd/dnsmasq.service
|
||||
index a27fe6d..4a784d3 100644
|
||||
--- a/contrib/systemd/dnsmasq.service
|
||||
+++ b/contrib/systemd/dnsmasq.service
|
||||
@@ -5,7 +5,7 @@ Description=A lightweight DHCP and caching DNS server
|
||||
Type=dbus
|
||||
BusName=uk.org.thekelleys.dnsmasq
|
||||
ExecStartPre=/usr/sbin/dnsmasq --test
|
||||
-ExecStart=/usr/sbin/dnsmasq -k
|
||||
+ExecStart=/usr/sbin/dnsmasq -k -1
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
|
||||
[Install]
|
||||
diff --git a/dbus/uk.org.thekelleys.dnsmasq.service
|
||||
b/dbus/uk.org.thekelleys.dnsmasq.service
|
||||
new file mode 100644
|
||||
index 0000000..f5fe98d
|
||||
--- /dev/null
|
||||
+++ b/dbus/uk.org.thekelleys.dnsmasq.service
|
||||
@@ -0,0 +1,7 @@
|
||||
+[D-BUS Service]
|
||||
+Name=uk.org.thekelleys.dnsmasq
|
||||
+Exec=/usr/sbin/dnsmasq -k -1
|
||||
+User=root
|
||||
+SystemdService=dnsmasq.service
|
||||
+
|
||||
+
|
||||
--
|
||||
1.7.10.2
|
||||
|
||||
|
||||
|
||||
_______________________________________________
|
||||
Dnsmasq-discuss mailing list
|
||||
Dnsmasq-discuss@lists.thekelleys.org.uk
|
||||
http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss
|
||||
|
||||
15
contrib/systemd/dnsmasq.service
Normal file
15
contrib/systemd/dnsmasq.service
Normal file
@@ -0,0 +1,15 @@
|
||||
[Unit]
|
||||
Description=dnsmasq - A lightweight DHCP and caching DNS server
|
||||
After=network.target
|
||||
Before=network-online.target nss-lookup.target
|
||||
Wants=nss-lookup.target
|
||||
|
||||
[Service]
|
||||
Type=dbus
|
||||
BusName=uk.org.thekelleys.dnsmasq
|
||||
ExecStartPre=/usr/sbin/dnsmasq --test
|
||||
ExecStart=/usr/sbin/dnsmasq -k
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -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
|
||||
|
||||
10
contrib/try-all-ns/README-2.78
Normal file
10
contrib/try-all-ns/README-2.78
Normal file
@@ -0,0 +1,10 @@
|
||||
Hi,
|
||||
I updated the try-all-ns patch to work with the latest version of git. Ended up implementing it on top of master, 2.78test2-7-g63437ff. As that specific if-clause has been changed in the last few commits, it's not compatible for 2.77, sadly.
|
||||
|
||||
Find the patch attached.
|
||||
|
||||
Regards,
|
||||
|
||||
Rasmus Ahlberg
|
||||
Software Developer, R&D
|
||||
Electrolux Small Appliances
|
||||
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;
|
||||
|
||||
20
contrib/try-all-ns/dnsmasq-2.78xx-try-all-ns.patch
Normal file
20
contrib/try-all-ns/dnsmasq-2.78xx-try-all-ns.patch
Normal file
@@ -0,0 +1,20 @@
|
||||
diff --git a/src/forward.c b/src/forward.c
|
||||
index e3fa94b..ecf3b98 100644
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -789,9 +789,12 @@ void reply_query(int fd, int family, time_t now)
|
||||
|
||||
/* Note: if we send extra options in the EDNS0 header, we can't recreate
|
||||
the query from the reply. */
|
||||
- if (RCODE(header) == REFUSED &&
|
||||
- forward->forwardall == 0 &&
|
||||
- !(forward->flags & FREC_HAS_EXTRADATA))
|
||||
+ if ((RCODE(header) == REFUSED &&
|
||||
+ forward->forwardall == 0 &&
|
||||
+ !(forward->flags & FREC_HAS_EXTRADATA)) ||
|
||||
+ /* If strict-order is set, try next server on NXDOMAIN reply */
|
||||
+ (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,26 @@ 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.
|
||||
|
||||
SetFilterA
|
||||
------------------------
|
||||
Takes boolean, sets or resets the --filter-A option.
|
||||
|
||||
SetFilterAAAA
|
||||
------------------------
|
||||
Takes boolean, sets or resets the --filter-AAAA option.
|
||||
|
||||
SetBogusPrivOption
|
||||
------------------
|
||||
Takes boolean, sets or resets the --bogus-priv option.
|
||||
|
||||
SetLocaliseQueriesOption
|
||||
------------------------
|
||||
Takes boolean, sets or resets the --localise-queries option.
|
||||
|
||||
SetServers
|
||||
----------
|
||||
Returns nothing. Takes a set of arguments representing the new
|
||||
@@ -94,6 +115,161 @@ 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.
|
||||
|
||||
GetMetrics
|
||||
----------
|
||||
|
||||
Returns an array with various metrics for DNS and DHCP.
|
||||
|
||||
GetServerMetrics
|
||||
----------------
|
||||
|
||||
Returns per-DNS-server metrics.
|
||||
|
||||
ClearMetrics
|
||||
------------
|
||||
|
||||
Clear call metric counters, global and per-server.
|
||||
|
||||
2. SIGNALS
|
||||
----------
|
||||
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
# as the long options legal on the command line. See
|
||||
# "/usr/sbin/dnsmasq --help" or "man 8 dnsmasq" for details.
|
||||
|
||||
# Listen on this specific port instead of the standard DNS port
|
||||
# (53). Setting this to zero completely disables DNS function,
|
||||
# leaving only DHCP and/or TFTP.
|
||||
#port=5353
|
||||
|
||||
# The following two options make you a better netizen, since they
|
||||
# tell dnsmasq to filter out queries which the public DNS cannot
|
||||
# answer, and which load the servers (especially the root servers)
|
||||
@@ -15,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.
|
||||
@@ -64,12 +81,26 @@
|
||||
# --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
|
||||
|
||||
# Add the IPs of all queries to yahoo.com, google.com, and their
|
||||
# subdomains to netfilters sets, which is equivalent to
|
||||
# 'nft add element ip test vpn { ... }; nft add element ip test search { ... }'
|
||||
#nftset=/yahoo.com/google.com/ip#test#vpn,ip#test#search
|
||||
|
||||
# Use netfilters sets for both IPv4 and IPv6:
|
||||
# This adds all addresses in *.yahoo.com to vpn4 and vpn6 for IPv4 and IPv6 addresses.
|
||||
#nftset=/yahoo.com/4#ip#test#vpn4
|
||||
#nftset=/yahoo.com/6#ip#test#vpn6
|
||||
|
||||
# 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
|
||||
|
||||
# and this sets the source (ie local) address used to talk to
|
||||
# 10.1.2.3 to 192.168.1.1 port 55 (there must be a interface with that
|
||||
# 10.1.2.3 to 192.168.1.1 port 55 (there must be an interface with that
|
||||
# IP on the machine, obviously).
|
||||
# server=10.1.2.3@192.168.1.1#55
|
||||
|
||||
@@ -157,6 +188,44 @@
|
||||
# an explicit netmask instead.
|
||||
#dhcp-range=192.168.0.0,static
|
||||
|
||||
# Enable DHCPv6. Note that the prefix-length does not need to be specified
|
||||
# and defaults to 64 if missing/
|
||||
#dhcp-range=1234::2, 1234::500, 64, 12h
|
||||
|
||||
# Do Router Advertisements, BUT NOT DHCP for this subnet.
|
||||
#dhcp-range=1234::, ra-only
|
||||
|
||||
# Do Router Advertisements, BUT NOT DHCP for this subnet, also try and
|
||||
# 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 algorithm.
|
||||
#dhcp-range=1234::, ra-names
|
||||
|
||||
# Do Router Advertisements, BUT NOT DHCP for this subnet.
|
||||
# Set the lifetime to 46 hours. (Note: minimum lifetime is 2 hours.)
|
||||
#dhcp-range=1234::, ra-only, 48h
|
||||
|
||||
# Do DHCP and Router Advertisements for this subnet. Set the A bit in the RA
|
||||
# so that clients can use SLAAC addresses as well as DHCP ones.
|
||||
#dhcp-range=1234::2, 1234::500, slaac
|
||||
|
||||
# Do Router Advertisements and stateless DHCP for this subnet. Clients will
|
||||
# not get addresses from DHCP, but they will get other configuration information.
|
||||
# They will use SLAAC for addresses.
|
||||
#dhcp-range=1234::, ra-stateless
|
||||
|
||||
# Do stateless DHCP, SLAAC, and generate DNS names for SLAAC addresses
|
||||
# from DHCPv4 leases.
|
||||
#dhcp-range=1234::, ra-stateless, ra-names
|
||||
|
||||
# Do router advertisements for all subnets where we're doing DHCPv6
|
||||
# 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.
|
||||
#enable-ra
|
||||
|
||||
# Supply parameters for specified hosts using DHCP. There are lots
|
||||
# of valid alternatives, so we will give examples of each. Note that
|
||||
# IP addresses DO NOT have to be in the range given above, they just
|
||||
@@ -192,6 +261,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
|
||||
@@ -219,7 +295,13 @@
|
||||
# any machine with Ethernet address starting 11:22:33:
|
||||
#dhcp-host=11:22:33:*:*:*,set:red
|
||||
|
||||
# Ignore any clients which are specified in dhcp-host lines
|
||||
# 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 that the [] 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
|
||||
# or /etc/ethers. Equivalent to ISC "deny unknown-clients".
|
||||
# This relies on the special "known" tag which is set when
|
||||
# a host is matched.
|
||||
@@ -270,6 +352,24 @@
|
||||
# Set the NTP time server addresses to 192.168.0.4 and 10.10.0.5
|
||||
#dhcp-option=option:ntp-server,192.168.0.4,10.10.0.5
|
||||
|
||||
# Send DHCPv6 option. Note [] around IPv6 addresses.
|
||||
#dhcp-option=option6:dns-server,[1234::77],[1234::88]
|
||||
|
||||
# Send DHCPv6 option for namservers as the machine running
|
||||
# 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
|
||||
@@ -294,7 +394,7 @@
|
||||
|
||||
# The following DHCP options set up dnsmasq in the same way as is specified
|
||||
# for the ISC dhcpcd in
|
||||
# http://www.samba.org/samba/ftp/docs/textdocs/DHCP-Server-Configuration.txt
|
||||
# https://web.archive.org/web/20040313070105/http://us1.samba.org/samba/ftp/docs/textdocs/DHCP-Server-Configuration.txt
|
||||
# adapted for a typical dnsmasq installation where the host running
|
||||
# dnsmasq is also the host running samba.
|
||||
# you may want to uncomment some or all of them if you use
|
||||
@@ -304,6 +404,9 @@
|
||||
#dhcp-option=45,0.0.0.0 # netbios datagram distribution server
|
||||
#dhcp-option=46,8 # netbios node type
|
||||
|
||||
# Send an empty WPAD option. This may be REQUIRED to get windows 7 to behave.
|
||||
#dhcp-option=252,"\n"
|
||||
|
||||
# Send RFC-3397 DNS domain search DHCP option. WARNING: Your DHCP client
|
||||
# probably doesn't support this......
|
||||
#dhcp-option=option:domain-search,eng.apple.com,marketing.apple.com
|
||||
@@ -343,19 +446,22 @@
|
||||
#dhcp-option-force=211,30i
|
||||
|
||||
# Set the boot filename for netboot/PXE. You will only need
|
||||
# this is you want to boot machines over the network and you will need
|
||||
# a TFTP server; either dnsmasq's built in TFTP server or an
|
||||
# this if you want to boot machines over the network and you will need
|
||||
# a TFTP server; either dnsmasq's built-in TFTP server or an
|
||||
# external one. (See below for how to enable the TFTP server.)
|
||||
#dhcp-boot=pxelinux.0
|
||||
|
||||
# Boot for Etherboot gPXE. The idea is to send two different
|
||||
# filenames, the first loads gPXE, and the second tells gPXE what to
|
||||
# load. The dhcp-match sets the gpxe tag for requests from gPXE.
|
||||
#dhcp-match=set:gpxe,175 # gPXE sends a 175 option.
|
||||
#dhcp-boot=tag:!gpxe,undionly.kpxe
|
||||
#dhcp-boot=mybootimage
|
||||
# The same as above, but use custom tftp-server instead machine running dnsmasq
|
||||
#dhcp-boot=pxelinux,server.name,192.168.1.100
|
||||
|
||||
# Encapsulated options for Etherboot gPXE. All the options are
|
||||
# Boot for iPXE. The idea is to send two different
|
||||
# filenames, the first loads iPXE, and the second tells iPXE what to
|
||||
# load. The dhcp-match sets the ipxe tag for requests from iPXE.
|
||||
#dhcp-boot=undionly.kpxe
|
||||
#dhcp-match=set:ipxe,175 # iPXE sends a 175 option.
|
||||
#dhcp-boot=tag:ipxe,http://boot.ipxe.org/demo/boot.php
|
||||
|
||||
# Encapsulated options for iPXE. All the options are
|
||||
# encapsulated within option 175
|
||||
#dhcp-option=encap:175, 1, 5b # priority code
|
||||
#dhcp-option=encap:175, 176, 1b # no-proxydhcp
|
||||
@@ -405,6 +511,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
|
||||
@@ -415,13 +524,21 @@
|
||||
#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.
|
||||
# Can fail with old PXE ROMS. Overridden by --pxe-service.
|
||||
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,192.168.0.3
|
||||
|
||||
# If there are multiple external tftp servers having a same name
|
||||
# (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 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
|
||||
|
||||
# Set the limit on DHCP leases, the default is 150
|
||||
#dhcp-lease-max=150
|
||||
|
||||
@@ -440,6 +557,14 @@
|
||||
# http://www.isc.org/files/auth.html
|
||||
#dhcp-authoritative
|
||||
|
||||
# Set the DHCP server to enable DHCPv4 Rapid Commit Option per RFC 4039.
|
||||
# In this mode it will respond to a DHCPDISCOVER message including a Rapid Commit
|
||||
# option with a DHCPACK including a Rapid Commit option and fully committed address
|
||||
# and configuration information. This must only be enabled if either the server is
|
||||
# the only server for the subnet, or multiple servers are present and they each
|
||||
# commit a binding for all clients.
|
||||
#dhcp-rapid-commit
|
||||
|
||||
# Run an executable when a DHCP lease is created or destroyed.
|
||||
# The arguments sent to the script are "add" or "del",
|
||||
# then the MAC address, the IP address and finally the hostname
|
||||
@@ -452,7 +577,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
|
||||
@@ -539,7 +664,7 @@
|
||||
# Provide an alias for a "local" DNS name. Note that this _only_ works
|
||||
# for targets which are names from DHCP or /etc/hosts. Give host
|
||||
# "bert" another name, bertrand
|
||||
#cname=bertand,bert
|
||||
#cname=bertrand,bert
|
||||
|
||||
# For debugging purposes, log each DNS query as it passes through
|
||||
# dnsmasq.
|
||||
@@ -548,6 +673,17 @@
|
||||
# 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
|
||||
|
||||
# If a DHCP client claims that its name is "wpad", ignore that.
|
||||
# This fixes a security hole. see CERT Vulnerability VU#598349
|
||||
#dhcp-name-match=set:wpad-ignore,wpad
|
||||
#dhcp-ignore-names=tag:wpad-ignore
|
||||
|
||||
164
doc.html
164
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,111 +10,90 @@
|
||||
<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), *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>Download.</H2>
|
||||
|
||||
<A HREF="http://www.thekelleys.org.uk/dnsmasq/"> Download</A> dnsmasq here.
|
||||
<H2>Get code.</H2>
|
||||
|
||||
<A HREF="http://www.thekelleys.org.uk/dnsmasq/">Download</A> dnsmasq here.
|
||||
The tarball includes this documentation, source, and manpage.
|
||||
There is also a <A HREF="CHANGELOG"> CHANGELOG</A> and a <A HREF="FAQ">FAQ</A>.
|
||||
Dnsmasq is part of the Debian distribution, it can be downloaded from
|
||||
<A HREF="http://ftp.debian.org/debian/pool/main/d/dnsmasq/"> here</A> or installed using <TT>apt</TT>.
|
||||
|
||||
<H2>Links.</H2>
|
||||
Damien Raude-Morvan has an article in French at <A HREF="http://www.drazzib.com/docs-dnsmasq.html">http://www.drazzib.com/docs-dnsmasq.html</A>
|
||||
There is a good article about dnsmasq at <A
|
||||
HREF="http://www.enterprisenetworkingplanet.com/netos/article.php/3377351">http://www.enterprisenetworkingplanet.com/netos/article.php/3377351</A>
|
||||
and another at <A
|
||||
HREF="http://www.linux.com/articles/149040">http://www.linux.com/articles/149040</A>
|
||||
and Ilya Evseev has an article in Russian about dnsmasq to be found at
|
||||
<A HREF="http://ilya-evseev.narod.ru/articles/dnsmasq">
|
||||
http://ilya-evseev.narod.ru/articles/dnsmasq</A>. Ismael Ull has an
|
||||
article about dnsmasq in Spanish at <A HREF="http://www.mey-online.com.ar/blog/index.php/archives/guia-rapida-de-dnsmasq">http://www.mey-online.com.ar/blog/index.php/archives/guia-rapida-de-dnsmasq</A>
|
||||
Dnsmasq has a git repository which contains the complete release
|
||||
history of version 2 and development history from 2.60. You can
|
||||
<A HREF="http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=summary">browse</A>
|
||||
the repo, or get a copy using git protocol with the command
|
||||
|
||||
<PRE><TT>git clone git://thekelleys.org.uk/dnsmasq.git </TT></PRE>
|
||||
|
||||
or
|
||||
|
||||
<PRE><TT>git clone http://thekelleys.org.uk/git/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>.
|
||||
</BODY>
|
||||
|
||||
<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>
|
||||
</HTML>
|
||||
|
||||
BIN
logo/favicon.ico
BIN
logo/favicon.ico
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
2090
man/dnsmasq.8
2090
man/dnsmasq.8
File diff suppressed because it is too large
Load Diff
@@ -478,7 +478,8 @@ la traza reversa direcci
|
||||
.TP
|
||||
.B \-c, --cache-size=<tamaño de caché>
|
||||
Fijar el tamaño del caché de dnsmasq. El predeterminado es 150 nombres.
|
||||
Fijar el tamaño a cero deshabilita el caché.
|
||||
Fijar el tamaño a cero deshabilita el caché. Nota: el gran tamaño de
|
||||
caché afecta el rendimiento.
|
||||
.TP
|
||||
.B \-N, --no-negcache
|
||||
Deshabilitar caché negativo. El caché negativo le permite a dnsmasq
|
||||
@@ -1062,10 +1063,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
|
||||
|
||||
1158
man/fr/dnsmasq.8
1158
man/fr/dnsmasq.8
File diff suppressed because it is too large
Load Diff
2870
man/sv/dnsmasq.8
Normal file
2870
man/sv/dnsmasq.8
Normal file
File diff suppressed because it is too large
Load Diff
2489
po/pt_BR.po
2489
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
14
setup.html
14
setup.html
@@ -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
|
||||
|
||||
@@ -125,7 +125,7 @@ address of its ethernet card. For the former to work, a machine needs to know it
|
||||
requests a DHCP lease. For dhcpcd, the -h option specifies this. The
|
||||
names may be anything as far as DHCP is concerned, but dnsmasq adds
|
||||
some limitations. By default the names must no have a domain part, ie
|
||||
they must just be a alphanumeric name, without any dots. This is a
|
||||
they must just be alphanumeric names, without any dots. This is a
|
||||
security feature to stop a machine on your network telling DHCP that
|
||||
its name is "www.microsoft.com" and thereby grabbing traffic which
|
||||
shouldn't go to it. A domain part is only allowed by dnsmasq in DHCP machine names
|
||||
@@ -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
|
||||
@@ -221,7 +221,7 @@ triggering dial-on-demand internet links.
|
||||
Sending SIGHUP to the dnsmasq process will cause it to empty its cache and
|
||||
then re-load <TT>/etc/hosts</TT> and <TT>/etc/resolv.conf</TT>.
|
||||
<P> Sending SIGUSR1 (killall -10 dnsmasq) to the dnsmasq process will
|
||||
cause to to write cache usage statisticss to the log, typically
|
||||
cause to write cache usage statisticss to the log, typically
|
||||
<TT>/var/log/syslog</TT> or <TT>/var/log/messages</TT>.
|
||||
<P> The <TT>log-queries</TT> option tells dnsmasq to verbosely log the queries
|
||||
it is handling and causes SIGUSR1 to trigger a complete dump of the
|
||||
@@ -229,3 +229,5 @@ contents of the cache to the syslog.
|
||||
|
||||
<P>For a complete listing of options please take a look at the manpage
|
||||
dnsmasq(8).
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
||||
240
src/arp.c
Normal file
240
src/arp.c
Normal file
@@ -0,0 +1,240 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2025 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];
|
||||
union 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, void *addrp, char *mac, size_t maclen, void *parmv)
|
||||
{
|
||||
struct arp_record *arp;
|
||||
|
||||
(void)parmv;
|
||||
|
||||
if (maclen > DHCP_CHADDR_MAX)
|
||||
return 1;
|
||||
|
||||
/* 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.addr4.s_addr != ((struct in_addr *)addrp)->s_addr)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr6, (struct in6_addr *)addrp))
|
||||
continue;
|
||||
}
|
||||
|
||||
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.addr4.s_addr = ((struct in_addr *)addrp)->s_addr;
|
||||
else
|
||||
memcpy(&arp->addr.addr6, addrp, IN6ADDRSZ);
|
||||
}
|
||||
|
||||
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 we're a child process, we always rely on the existing cache we
|
||||
inherited from the parent, since we don't have a netlink socket.
|
||||
*/
|
||||
if (difftime(now, last) < INTERVAL || daemon->pipe_to_parent != -1)
|
||||
{
|
||||
/* 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.addr4.s_addr != addr->in.sin_addr.s_addr)
|
||||
continue;
|
||||
|
||||
if (arp->family == AF_INET6 &&
|
||||
!IN6_ARE_ADDR_EQUAL(&arp->addr.addr6, &addr->in6.sin6_addr))
|
||||
continue;
|
||||
|
||||
/* 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 in cache in child, no go. */
|
||||
if (daemon->pipe_to_parent != -1)
|
||||
return 0;
|
||||
|
||||
/* 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, (callback_t){.af_unspec=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.addr4.s_addr = addr->in.sin_addr.s_addr;
|
||||
else
|
||||
memcpy(&arp->addr.addr6, &addr->in6.sin6_addr, IN6ADDRSZ);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
915
src/auth.c
Normal file
915
src/auth.c
Normal file
@@ -0,0 +1,915 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2025 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, union all_addr *addr_u)
|
||||
{
|
||||
do {
|
||||
if (!(list->flags & ADDRLIST_IPV6))
|
||||
{
|
||||
struct in_addr netmask, addr = addr_u->addr4;
|
||||
|
||||
if (!(flag & F_IPV4))
|
||||
continue;
|
||||
|
||||
netmask.s_addr = htonl(~(in_addr_t)0 << (32 - list->prefixlen));
|
||||
|
||||
if (is_same_net(addr, list->addr.addr4, netmask))
|
||||
return list;
|
||||
}
|
||||
else if (is_same_net6(&(addr_u->addr6), &list->addr.addr6, list->prefixlen))
|
||||
return list;
|
||||
|
||||
} while ((list = list->next));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct addrlist *find_subnet(struct auth_zone *zone, int flag, union 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, union 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, union 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)
|
||||
{
|
||||
char *name = daemon->namebuff;
|
||||
unsigned char *p, *ansp;
|
||||
int qtype, qclass, rc;
|
||||
int nameoffset, axfroffset = 0;
|
||||
int anscount = 0, authcount = 0;
|
||||
struct crec *crecp;
|
||||
int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0, out_of_zone = 0, notimp = 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;
|
||||
union all_addr addr;
|
||||
struct cname *a, *candidate;
|
||||
unsigned int wclen;
|
||||
unsigned int log_flags = local_query ? 0 : F_NOERR;
|
||||
|
||||
if (ntohs(header->qdcount) != 1)
|
||||
return 0;
|
||||
|
||||
/* determine end of question section (we put answers there) */
|
||||
if (!(ansp = skip_questions(header, qlen)))
|
||||
return 0; /* bad packet */
|
||||
|
||||
p = (unsigned char *)(header+1);
|
||||
|
||||
if (OPCODE(header) != QUERY)
|
||||
notimp = 1;
|
||||
else
|
||||
{
|
||||
unsigned int 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, EXTR_NAME_EXTRACT, 4))
|
||||
return 0; /* bad packet */
|
||||
|
||||
GETSHORT(qtype, p);
|
||||
GETSHORT(qclass, p);
|
||||
|
||||
if (qclass != C_IN)
|
||||
{
|
||||
auth = 0;
|
||||
out_of_zone = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
out_of_zone = 1;
|
||||
auth = 0;
|
||||
goto done;
|
||||
}
|
||||
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.addr4.s_addr == addrlist->addr.addr4.s_addr)
|
||||
break;
|
||||
|
||||
if (addrlist)
|
||||
break;
|
||||
else
|
||||
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
|
||||
intr = intr->next;
|
||||
}
|
||||
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.addr6, &addrlist->addr.addr6))
|
||||
break;
|
||||
|
||||
if (addrlist)
|
||||
break;
|
||||
else
|
||||
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
|
||||
intr = intr->next;
|
||||
}
|
||||
|
||||
if (intr)
|
||||
{
|
||||
if (local_query || in_zone(zone, intr->name, NULL))
|
||||
{
|
||||
found = 1;
|
||||
log_query(log_flags | flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL, 0);
|
||||
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(log_flags | flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid), 0);
|
||||
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(log_flags | (crecp->flags & ~F_FORWARD), name, &addr, record_source(crecp->uid), 0);
|
||||
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 && is_rev_synth(flag, &addr, name) && (local_query || in_zone(zone, name, NULL)))
|
||||
{
|
||||
log_query(log_flags | F_CONFIG | F_REVERSE | flag, name, &addr, NULL, 0);
|
||||
found = 1;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
T_PTR, C_IN, "d", name))
|
||||
anscount++;
|
||||
}
|
||||
|
||||
if (found)
|
||||
nxdomain = 0;
|
||||
else
|
||||
log_query(log_flags | flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL, 0);
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
out_of_zone = 1;
|
||||
auth = 0;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
for (rec = daemon->mxnames; rec; rec = rec->next)
|
||||
if (!rec->issrv && (rc = hostname_issubdomain(name, rec->name)))
|
||||
{
|
||||
nxdomain = 0;
|
||||
|
||||
if (rc == 2 && qtype == T_MX)
|
||||
{
|
||||
found = 1;
|
||||
log_query(log_flags | F_CONFIG | F_RRNAME, name, NULL, "<MX>", 0);
|
||||
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 && (rc = hostname_issubdomain(name, rec->name)))
|
||||
{
|
||||
nxdomain = 0;
|
||||
|
||||
if (rc == 2 && qtype == T_SRV)
|
||||
{
|
||||
found = 1;
|
||||
log_query(log_flags | F_CONFIG | F_RRNAME, name, NULL, "<SRV>", 0);
|
||||
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 ((rc = hostname_issubdomain(name, txt->name)))
|
||||
{
|
||||
nxdomain = 0;
|
||||
if (rc == 2 && txt->class == qtype)
|
||||
{
|
||||
found = 1;
|
||||
log_query(log_flags | F_CONFIG | F_RRNAME, name, NULL, NULL, txt->class);
|
||||
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 && (rc = hostname_issubdomain(name, txt->name)))
|
||||
{
|
||||
nxdomain = 0;
|
||||
if (rc == 2 && qtype == T_TXT)
|
||||
{
|
||||
found = 1;
|
||||
log_query(log_flags | F_CONFIG | F_RRNAME, name, NULL, "<TXT>", 0);
|
||||
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 ((rc = hostname_issubdomain(name, na->name)))
|
||||
{
|
||||
nxdomain = 0;
|
||||
if (rc == 2 && qtype == T_NAPTR)
|
||||
{
|
||||
found = 1;
|
||||
log_query(log_flags | F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>", 0);
|
||||
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;
|
||||
|
||||
if (qtype == T_AAAA)
|
||||
flag = F_IPV6;
|
||||
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
if ((rc = hostname_issubdomain(name, intr->name)))
|
||||
{
|
||||
struct addrlist *addrlist;
|
||||
|
||||
nxdomain = 0;
|
||||
|
||||
if (rc == 2 && 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)))
|
||||
{
|
||||
if (addrlist->flags & ADDRLIST_REVONLY)
|
||||
continue;
|
||||
|
||||
found = 1;
|
||||
log_query(log_flags | F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL, 0);
|
||||
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 (!found && is_name_synthetic(flag, name, &addr) )
|
||||
{
|
||||
nxdomain = 0;
|
||||
|
||||
log_query(log_flags | F_FORWARD | F_CONFIG | flag, name, &addr, NULL, 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN, qtype == T_A ? "4" : "6", &addr))
|
||||
anscount++;
|
||||
}
|
||||
|
||||
if (!cut)
|
||||
{
|
||||
nxdomain = 0;
|
||||
|
||||
if (qtype == T_SOA)
|
||||
{
|
||||
auth = soa = 1; /* inhibits auth section */
|
||||
log_query(log_flags | F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>", 0);
|
||||
}
|
||||
else if (qtype == T_AXFR)
|
||||
{
|
||||
struct iname *peers;
|
||||
|
||||
if (peer_addr->sa.sa_family == AF_INET)
|
||||
peer_addr->in.sin_port = 0;
|
||||
else
|
||||
{
|
||||
peer_addr->in6.sin6_port = 0;
|
||||
peer_addr->in6.sin6_scope_id = 0;
|
||||
}
|
||||
|
||||
for (peers = daemon->auth_peers; peers; peers = peers->next)
|
||||
if (sockaddr_isequal(peer_addr, &peers->addr))
|
||||
break;
|
||||
|
||||
/* Refuse all AXFR unless --auth-sec-servers or auth-peers is set */
|
||||
if ((!daemon->secondary_forward_server && !daemon->auth_peers) ||
|
||||
(daemon->auth_peers && !peers))
|
||||
{
|
||||
if (peer_addr->sa.sa_family == AF_INET)
|
||||
inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
else
|
||||
inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
|
||||
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;
|
||||
axfroffset = nameoffset;
|
||||
log_query(log_flags | F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>", 0);
|
||||
}
|
||||
else if (qtype == T_NS)
|
||||
{
|
||||
auth = 1;
|
||||
ns = 1; /* inhibits auth section */
|
||||
log_query(log_flags | F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>", 0);
|
||||
}
|
||||
}
|
||||
|
||||
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))))
|
||||
{
|
||||
*cut = '.'; /* restore domain part */
|
||||
log_query(log_flags | crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
|
||||
*cut = 0; /* remove domain part */
|
||||
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))))
|
||||
{
|
||||
log_query(log_flags | (crecp->flags & ~F_REVERSE), name, &crecp->addr, record_source(crecp->uid), 0);
|
||||
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(log_flags | F_CONFIG | F_CNAME, name, NULL, NULL, 0);
|
||||
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;
|
||||
}
|
||||
else if (cache_find_non_terminal(name, now))
|
||||
nxdomain = 0;
|
||||
|
||||
log_query(log_flags | flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
/* 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.addr4.s_addr) >> 8;
|
||||
char *p = name;
|
||||
|
||||
if (subnet->prefixlen >= 24)
|
||||
p += sprintf(p, "%u.", a & 0xff);
|
||||
a = a >> 8;
|
||||
if (subnet->prefixlen >= 16 )
|
||||
p += sprintf(p, "%u.", a & 0xff);
|
||||
a = a >> 8;
|
||||
sprintf(p, "%u.in-addr.arpa", a & 0xff);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
char *p = name;
|
||||
int i;
|
||||
|
||||
for (i = subnet->prefixlen-1; i >= 0; i -= 4)
|
||||
{
|
||||
int dig = ((unsigned char *)&subnet->addr.addr6)[i>>3];
|
||||
p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
|
||||
}
|
||||
sprintf(p, "ip6.arpa");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Only include the machine running dnsmasq if it's acting as an auth server */
|
||||
if (daemon->authinterface)
|
||||
{
|
||||
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++;
|
||||
|
||||
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++;
|
||||
|
||||
/* 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))) &&
|
||||
add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL, (crecp->flags & F_IPV6) ? T_AAAA : T_A, 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))))
|
||||
{
|
||||
if (cut)
|
||||
*cut = 0;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL, (crecp->flags & F_IPV6) ? T_AAAA : T_A, 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;
|
||||
}
|
||||
|
||||
/* data is never DNSSEC signed. */
|
||||
header->hb4 &= ~HB4_AD;
|
||||
|
||||
/* authoritative */
|
||||
if (auth)
|
||||
header->hb3 |= HB3_AA;
|
||||
|
||||
/* truncation */
|
||||
if (trunc)
|
||||
{
|
||||
header->hb3 |= HB3_TC;
|
||||
if (!(ansp = skip_questions(header, qlen)))
|
||||
return 0; /* bad packet */
|
||||
anscount = authcount = 0;
|
||||
log_query(log_flags | F_AUTH, "reply", NULL, "truncated", 0);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if ((!local_query && out_of_zone) || notimp)
|
||||
{
|
||||
if (out_of_zone)
|
||||
{
|
||||
addr.log.rcode = REFUSED;
|
||||
addr.log.ede = EDE_NOT_AUTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr.log.rcode = NOTIMP;
|
||||
addr.log.ede = EDE_UNSET;
|
||||
}
|
||||
|
||||
SET_RCODE(header, addr.log.rcode);
|
||||
header->ancount = htons(0);
|
||||
header->nscount = htons(0);
|
||||
log_query(log_flags | F_UPSTREAM | F_RCODE, "error", &addr, NULL, 0);
|
||||
return resize_packet(header, ansp - (unsigned char *)header, NULL, 0);
|
||||
}
|
||||
|
||||
return ansp - (unsigned char *)header;
|
||||
}
|
||||
|
||||
#endif
|
||||
239
src/blockdata.c
Normal file
239
src/blockdata.c
Normal file
@@ -0,0 +1,239 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2025 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 blockdata *keyblock_free;
|
||||
static unsigned int blockdata_count, blockdata_hwm, blockdata_alloced;
|
||||
|
||||
static void add_blocks(int n)
|
||||
{
|
||||
struct blockdata *new = whine_malloc(n * sizeof(struct blockdata));
|
||||
|
||||
if (new)
|
||||
{
|
||||
int i;
|
||||
|
||||
new[n-1].next = keyblock_free;
|
||||
keyblock_free = new;
|
||||
|
||||
for (i = 0; i < n - 1; i++)
|
||||
new[i].next = &new[i+1];
|
||||
|
||||
blockdata_alloced += n;
|
||||
}
|
||||
}
|
||||
|
||||
/* Preallocate some blocks, proportional to cachesize, to reduce heap fragmentation. */
|
||||
void blockdata_init(void)
|
||||
{
|
||||
keyblock_free = NULL;
|
||||
blockdata_alloced = 0;
|
||||
blockdata_count = 0;
|
||||
blockdata_hwm = 0;
|
||||
|
||||
/* Note that daemon->cachesize is enforced to have non-zero size if OPT_DNSSEC_VALID is set */
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
add_blocks(daemon->cachesize);
|
||||
}
|
||||
|
||||
void blockdata_report(void)
|
||||
{
|
||||
my_syslog(LOG_INFO, _("pool memory in use %zu, max %zu, allocated %zu"),
|
||||
blockdata_count * sizeof(struct blockdata),
|
||||
blockdata_hwm * sizeof(struct blockdata),
|
||||
blockdata_alloced * sizeof(struct blockdata));
|
||||
}
|
||||
|
||||
static struct blockdata *new_block(void)
|
||||
{
|
||||
struct blockdata *block;
|
||||
|
||||
if (!keyblock_free)
|
||||
add_blocks(50);
|
||||
|
||||
if (keyblock_free)
|
||||
{
|
||||
block = keyblock_free;
|
||||
keyblock_free = block->next;
|
||||
blockdata_count++;
|
||||
if (blockdata_hwm < blockdata_count)
|
||||
blockdata_hwm = blockdata_count;
|
||||
block->next = NULL;
|
||||
return block;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct blockdata *blockdata_alloc_real(int fd, char *data, size_t len)
|
||||
{
|
||||
struct blockdata *block, *ret = NULL;
|
||||
struct blockdata **prev = &ret;
|
||||
size_t blen;
|
||||
|
||||
do
|
||||
{
|
||||
if (!(block = new_block()))
|
||||
{
|
||||
/* failed to alloc, free partial chain */
|
||||
blockdata_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len) > 0)
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
memcpy(block->key, data, blen);
|
||||
data += blen;
|
||||
}
|
||||
else if (!read_write(fd, block->key, blen, RW_READ))
|
||||
{
|
||||
/* failed read free partial chain */
|
||||
blockdata_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
len -= blen;
|
||||
*prev = block;
|
||||
prev = &block->next;
|
||||
} while (len != 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct blockdata *blockdata_alloc(char *data, size_t len)
|
||||
{
|
||||
return blockdata_alloc_real(0, data, len);
|
||||
}
|
||||
|
||||
/* Add data to the end of the block.
|
||||
newlen is length of new data, NOT total new length.
|
||||
Use blockdata_alloc(NULL, 0) to make empty block to add to. */
|
||||
int blockdata_expand(struct blockdata *block, size_t oldlen, char *data, size_t newlen)
|
||||
{
|
||||
struct blockdata *b;
|
||||
|
||||
/* find size of current final block */
|
||||
for (b = block; oldlen > KEYBLOCK_LEN && b; b = b->next, oldlen -= KEYBLOCK_LEN);
|
||||
|
||||
/* chain to short for length, something is broken */
|
||||
if (oldlen > KEYBLOCK_LEN)
|
||||
{
|
||||
blockdata_free(block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct blockdata *new;
|
||||
size_t blocksize = KEYBLOCK_LEN - oldlen;
|
||||
size_t size = (newlen <= blocksize) ? newlen : blocksize;
|
||||
|
||||
if (size != 0)
|
||||
{
|
||||
memcpy(&b->key[oldlen], data, size);
|
||||
data += size;
|
||||
newlen -= size;
|
||||
}
|
||||
|
||||
/* full blocks from now on. */
|
||||
oldlen = 0;
|
||||
|
||||
if (newlen == 0)
|
||||
break;
|
||||
|
||||
if ((new = new_block()))
|
||||
{
|
||||
b->next = new;
|
||||
b = new;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* failed to alloc, free partial chain */
|
||||
blockdata_free(block);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
uint8_t *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;
|
||||
}
|
||||
|
||||
|
||||
void blockdata_write(struct blockdata *block, size_t len, int fd)
|
||||
{
|
||||
for (; len > 0 && block; block = block->next)
|
||||
{
|
||||
size_t blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
|
||||
read_write(fd, block->key, blen, RW_WRITE);
|
||||
len -= blen;
|
||||
}
|
||||
}
|
||||
|
||||
struct blockdata *blockdata_read(int fd, size_t len)
|
||||
{
|
||||
return blockdata_alloc_real(fd, NULL, len);
|
||||
}
|
||||
335
src/bpf.c
335
src/bpf.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2025 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,25 +17,37 @@
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
|
||||
#include <ifaddrs.h>
|
||||
|
||||
static struct iovec ifconf = {
|
||||
.iov_base = NULL,
|
||||
.iov_len = 0
|
||||
};
|
||||
|
||||
static struct iovec ifreq = {
|
||||
.iov_base = NULL,
|
||||
.iov_len = 0
|
||||
};
|
||||
|
||||
#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>
|
||||
#include <netinet6/in6_var.h>
|
||||
|
||||
int arp_enumerate(void *parm, int (*callback)())
|
||||
#ifndef SA_SIZE
|
||||
#define SA_SIZE(sa) \
|
||||
( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
|
||||
sizeof(long) : \
|
||||
1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_BSD_NETWORK
|
||||
static int del_family = 0;
|
||||
static union all_addr del_addr;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||
|
||||
int arp_enumerate(void *parm, callback_t callback)
|
||||
{
|
||||
int mib[6];
|
||||
size_t needed;
|
||||
@@ -43,8 +55,12 @@ int arp_enumerate(void *parm, int (*callback)())
|
||||
struct rt_msghdr *rtm;
|
||||
struct sockaddr_inarp *sin2;
|
||||
struct sockaddr_dl *sdl;
|
||||
struct iovec buff;
|
||||
int rc;
|
||||
|
||||
|
||||
buff.iov_base = NULL;
|
||||
buff.iov_len = 0;
|
||||
|
||||
mib[0] = CTL_NET;
|
||||
mib[1] = PF_ROUTE;
|
||||
mib[2] = 0;
|
||||
@@ -60,9 +76,9 @@ int arp_enumerate(void *parm, int (*callback)())
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (!expand_buf(&ifconf, needed))
|
||||
if (!expand_buf(&buff, needed))
|
||||
return 0;
|
||||
if ((rc = sysctl(mib, 6, ifconf.iov_base, &needed, NULL, 0)) == 0 ||
|
||||
if ((rc = sysctl(mib, 6, buff.iov_base, &needed, NULL, 0)) == 0 ||
|
||||
errno != ENOMEM)
|
||||
break;
|
||||
needed += needed / 8;
|
||||
@@ -70,30 +86,25 @@ int arp_enumerate(void *parm, int (*callback)())
|
||||
if (rc == -1)
|
||||
return 0;
|
||||
|
||||
for (next = ifconf.iov_base ; next < (char *)ifconf.iov_base + needed; next += rtm->rtm_msglen)
|
||||
for (next = buff.iov_base ; next < (char *)buff.iov_base + needed; next += rtm->rtm_msglen)
|
||||
{
|
||||
rtm = (struct rt_msghdr *)next;
|
||||
sin2 = (struct sockaddr_inarp *)(rtm + 1);
|
||||
sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2));
|
||||
if (!(*callback)(AF_INET, &sin2->sin_addr, LLADDR(sdl), sdl->sdl_alen, parm))
|
||||
if (!callback.af_unspec(AF_INET, &sin2->sin_addr, LLADDR(sdl), sdl->sdl_alen, parm))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) */
|
||||
|
||||
|
||||
int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
int iface_enumerate(int family, void *parm, callback_t callback)
|
||||
{
|
||||
char *ptr;
|
||||
struct ifreq *ifr;
|
||||
struct ifconf ifc;
|
||||
int fd, errsav, ret = 0;
|
||||
int lastlen = 0;
|
||||
size_t len = 0;
|
||||
|
||||
struct ifaddrs *head, *addrs;
|
||||
int errsave, fd = -1, ret = 0;
|
||||
|
||||
if (family == AF_UNSPEC)
|
||||
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||
return arp_enumerate(parm, callback);
|
||||
@@ -101,100 +112,134 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
return 0; /* need code for Solaris and MacOS*/
|
||||
#endif
|
||||
|
||||
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
/* AF_LINK doesn't exist in Linux, so we can't use it in our API */
|
||||
if (family == AF_LOCAL)
|
||||
family = AF_LINK;
|
||||
|
||||
if (getifaddrs(&head) == -1)
|
||||
return 0;
|
||||
|
||||
#if defined(HAVE_BSD_NETWORK)
|
||||
if (family == AF_INET6)
|
||||
fd = socket(PF_INET6, SOCK_DGRAM, 0);
|
||||
#endif
|
||||
|
||||
while(1)
|
||||
for (addrs = head; addrs; addrs = addrs->ifa_next)
|
||||
{
|
||||
len += 10*sizeof(struct ifreq);
|
||||
int iface_index = if_nametoindex(addrs->ifa_name);
|
||||
|
||||
if (!expand_buf(&ifconf, len))
|
||||
goto err;
|
||||
if (iface_index == 0 || !addrs->ifa_addr ||
|
||||
addrs->ifa_addr->sa_family != family ||
|
||||
(!addrs->ifa_netmask && family != AF_LINK))
|
||||
continue;
|
||||
|
||||
ifc.ifc_len = len;
|
||||
ifc.ifc_buf = ifconf.iov_base;
|
||||
|
||||
if (ioctl(fd, SIOCGIFCONF, &ifc) == -1)
|
||||
if (family == AF_INET)
|
||||
{
|
||||
if (errno != EINVAL || lastlen != 0)
|
||||
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.addr4.s_addr == addr.s_addr)
|
||||
continue;
|
||||
#endif
|
||||
netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr;
|
||||
if (addrs->ifa_broadaddr)
|
||||
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
|
||||
else
|
||||
broadcast.s_addr = 0;
|
||||
if (!callback.af_inet(addr, iface_index, NULL, netmask, broadcast, parm))
|
||||
goto err;
|
||||
}
|
||||
else
|
||||
else if (family == AF_INET6)
|
||||
{
|
||||
if (ifc.ifc_len == lastlen)
|
||||
break; /* got a big enough buffer now */
|
||||
lastlen = ifc.ifc_len;
|
||||
}
|
||||
}
|
||||
|
||||
for (ptr = ifc.ifc_buf; ptr < (char *)(ifc.ifc_buf + ifc.ifc_len); ptr += len)
|
||||
{
|
||||
/* subsequent entries may not be aligned, so copy into
|
||||
an aligned buffer to avoid nasty complaints about
|
||||
unaligned accesses. */
|
||||
|
||||
len = sizeof(struct ifreq);
|
||||
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
ifr = (struct ifreq *)ptr;
|
||||
if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_ifru))
|
||||
len = ifr->ifr_addr.sa_len + offsetof(struct ifreq, ifr_ifru);
|
||||
struct in6_addr *addr = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_addr;
|
||||
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.addr6, addr))
|
||||
continue;
|
||||
#endif
|
||||
|
||||
if (!expand_buf(&ifreq, len))
|
||||
goto err;
|
||||
|
||||
ifr = (struct ifreq *)ifreq.iov_base;
|
||||
memcpy(ifr, ptr, len);
|
||||
|
||||
if (ifr->ifr_addr.sa_family == family)
|
||||
{
|
||||
if (family == AF_INET)
|
||||
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||
struct in6_ifreq ifr6;
|
||||
|
||||
memset(&ifr6, 0, sizeof(ifr6));
|
||||
safe_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)
|
||||
{
|
||||
struct in_addr addr, netmask, broadcast;
|
||||
broadcast.s_addr = 0;
|
||||
addr = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (ioctl(fd, SIOCGIFNETMASK, ifr) == -1)
|
||||
continue;
|
||||
netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (ioctl(fd, SIOCGIFBRDADDR, ifr) != -1)
|
||||
broadcast = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (!((*callback)(addr,
|
||||
(int)if_nametoindex(ifr->ifr_name),
|
||||
netmask, broadcast,
|
||||
parm)))
|
||||
goto err;
|
||||
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
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (family == AF_INET6)
|
||||
|
||||
ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
|
||||
if (fd != -1 && ioctl(fd, SIOCGIFALIFETIME_IN6, &ifr6) != -1)
|
||||
{
|
||||
struct in6_addr *addr = &((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_addr;
|
||||
/* voodoo to clear interface field in address */
|
||||
if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
|
||||
{
|
||||
addr->s6_addr[2] = 0;
|
||||
addr->s6_addr[3] = 0;
|
||||
}
|
||||
if (!((*callback)(addr,
|
||||
(int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id,
|
||||
(int)if_nametoindex(ifr->ifr_name),
|
||||
parm)))
|
||||
goto err;
|
||||
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)
|
||||
break;
|
||||
|
||||
/* voodoo to clear interface field in address */
|
||||
if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
|
||||
{
|
||||
addr->s6_addr[2] = 0;
|
||||
addr->s6_addr[3] = 0;
|
||||
}
|
||||
|
||||
if (!callback.af_inet6(addr, prefix, scope_id, iface_index, flags,
|
||||
(unsigned int) preferred, (unsigned int)valid, parm))
|
||||
goto err;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (family == AF_LINK)
|
||||
{
|
||||
/* Assume ethernet again here */
|
||||
struct sockaddr_dl *sdl = (struct sockaddr_dl *) addrs->ifa_addr;
|
||||
if (sdl->sdl_alen != 0 &&
|
||||
!callback.af_local(iface_index, ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm))
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
|
||||
err:
|
||||
errsav = errno;
|
||||
close(fd);
|
||||
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)
|
||||
@@ -206,13 +251,10 @@ void init_bpf(void)
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* useful size which happens to be sufficient */
|
||||
if (expand_buf(&ifreq, sizeof(struct ifreq)))
|
||||
{
|
||||
sprintf(ifreq.iov_base, "/dev/bpf%d", i++);
|
||||
if ((daemon->dhcp_raw_fd = open(ifreq.iov_base, O_RDWR, 0)) != -1)
|
||||
return;
|
||||
}
|
||||
sprintf(daemon->dhcp_buff, "/dev/bpf%d", i++);
|
||||
if ((daemon->dhcp_raw_fd = open(daemon->dhcp_buff, O_RDWR, 0)) != -1)
|
||||
return;
|
||||
|
||||
if (errno != EBUSY)
|
||||
die(_("cannot create DHCP BPF socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
@@ -313,9 +355,86 @@ 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
|
||||
#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.addr4 = ((struct sockaddr_in *)sa)->sin_addr;
|
||||
else if (del_family == AF_INET6)
|
||||
del_addr.addr6 = ((struct sockaddr_in6 *)sa)->sin6_addr;
|
||||
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 */
|
||||
|
||||
2106
src/cache.c
2106
src/cache.c
File diff suppressed because it is too large
Load Diff
527
src/config.h
527
src/config.h
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2025 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,32 +14,197 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define VERSION "2.57"
|
||||
|
||||
#define FTABSIZ 150 /* max number of outstanding requests (default) */
|
||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||
#define MAX_PROCS 20 /* default max no children for TCP requests */
|
||||
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
|
||||
#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
|
||||
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
|
||||
#define TCP_MAX_QUERIES 100 /* Maximum number of queries per incoming TCP connection */
|
||||
#define TCP_TIMEOUT 5 /* timeout waiting to connect to an upstream server - double this for answer */
|
||||
#define TCP_BACKLOG 32 /* kernel backlog limit for TCP connections */
|
||||
#define EDNS_PKTSZ 1232 /* default max EDNS.0 UDP packet from from /dnsflagday.net/2020 */
|
||||
#define KEYBLOCK_LEN 40 /* choose to minimise fragmentation when storing DNSSEC keys */
|
||||
#define DNSSEC_LIMIT_WORK 40 /* Max number of queries to validate one question */
|
||||
#define DNSSEC_LIMIT_SIG_FAIL 20 /* Number of signature that can fail to validate in one answer */
|
||||
#define DNSSEC_LIMIT_CRYPTO 200 /* max no. of crypto operations to validate one query. */
|
||||
#define DNSSEC_LIMIT_NSEC3_ITERS 150 /* Max. number if iterations allowed in NSEC3 record. */
|
||||
#define DNSSEC_ASSUMED_DS_TTL 3600 /* TTL for negative DS records implied by server=/domain/ */
|
||||
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
|
||||
#define SMALL_PORT_RANGE 30 /* If DNS port range is smaller than this, use different allocation. */
|
||||
#define FORWARD_TEST 50 /* try all servers every 50 queries */
|
||||
#define FORWARD_TIME 20 /* or 20 seconds */
|
||||
#define RANDOM_SOCKS 64 /* max simultaneous random ports */
|
||||
#define UDP_TEST_TIME 60 /* How often to reset our idea of max packet size. */
|
||||
#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 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 DNSSEC_MIN_TTL 60 /* DNSKEY and DS records in cache last at least this long */
|
||||
#define HOSTSFILE "/etc/hosts"
|
||||
#define ETHERSFILE "/etc/ethers"
|
||||
#ifdef __uClinux__
|
||||
# define RESOLVFILE "/etc/config/resolv.conf"
|
||||
#else
|
||||
# define RESOLVFILE "/etc/resolv.conf"
|
||||
#endif
|
||||
#define RUNFILE "/var/run/dnsmasq.pid"
|
||||
#define DEFLEASE 3600 /* default DHCPv4 lease time, one hour */
|
||||
#define DEFLEASE6 (3600*24) /* default lease time for DHCPv6. One day. */
|
||||
#define CHUSER "nobody"
|
||||
#define CHGRP "dip"
|
||||
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
|
||||
#define TFTP_MAX_WINDOW 32 /* max window size to negotiate */
|
||||
#define TFTP_TRANSFER_TIME 120 /* Abandon TFTP transfers after this long. Two mins. */
|
||||
#define LOG_MAX 5 /* log-queue length */
|
||||
#define RANDFILE "/dev/urandom"
|
||||
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* Default - may be overridden by config */
|
||||
#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
|
||||
#define DNSMASQ_UBUS_NAME "dnsmasq" /* Default - may be overridden by config */
|
||||
#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
|
||||
#define DEFAULT_FAST_RETRY 1000 /* ms, default delay before fast retry */
|
||||
#define STALE_CACHE_EXPIRY 86400 /* 1 day in secs, default maximum expiry time for stale cache data */
|
||||
|
||||
/* compile-time options: uncomment below to enable or do eg.
|
||||
make COPTS=-DHAVE_BROKEN_RTC
|
||||
|
||||
HAVE_BROKEN_RTC
|
||||
define this on embedded systems which don't have an RTC
|
||||
which keeps time over reboots. Causes dnsmasq to use uptime
|
||||
for timing, and keep lease lengths rather than expiry times
|
||||
in its leases file. This also make dnsmasq "flash disk friendly".
|
||||
Normally, dnsmasq tries very hard to keep the on-disk leases file
|
||||
up-to-date: rewriting it after every renewal. When HAVE_BROKEN_RTC
|
||||
is in effect, the lease file is only written when a new lease is
|
||||
created, or an old one destroyed. (Because those are the only times
|
||||
it changes.) This vastly reduces the number of file writes, and makes
|
||||
it viable to keep the lease file on a flash filesystem.
|
||||
NOTE: when enabling or disabling this, be sure to delete any old
|
||||
leases file, otherwise dnsmasq may get very confused.
|
||||
|
||||
HAVE_TFTP
|
||||
define this to get dnsmasq's built-in TFTP server.
|
||||
|
||||
HAVE_DHCP
|
||||
define this to get dnsmasq's DHCPv4 server.
|
||||
|
||||
HAVE_DHCP6
|
||||
define this to get dnsmasq's DHCPv6 server. (implies HAVE_DHCP).
|
||||
|
||||
HAVE_SCRIPT
|
||||
define this to get the ability to call scripts on lease-change.
|
||||
|
||||
HAVE_LUASCRIPT
|
||||
define this to get the ability to call Lua script on lease-change. (implies HAVE_SCRIPT)
|
||||
|
||||
HAVE_DBUS
|
||||
define this if you want to link against libdbus, and have dnsmasq
|
||||
support some methods to allow (re)configuration of the upstream DNS
|
||||
servers via DBus.
|
||||
|
||||
HAVE_UBUS
|
||||
define this if you want to link against libubus
|
||||
|
||||
HAVE_IDN
|
||||
define this if you want international domain name 2003 support.
|
||||
|
||||
HAVE_LIBIDN2
|
||||
define this if you want international domain name 2008 support.
|
||||
|
||||
HAVE_CONNTRACK
|
||||
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_NFTSET
|
||||
define this to include the ability to selectively add resolved ip addresses
|
||||
to given nftables sets.
|
||||
|
||||
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_DUMPFILE
|
||||
include code to dump packets to a libpcap-format file for debugging.
|
||||
|
||||
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_TFTP
|
||||
NO_DHCP
|
||||
NO_DHCP6
|
||||
NO_SCRIPT
|
||||
NO_LARGEFILE
|
||||
NO_AUTH
|
||||
NO_DUMPFILE
|
||||
NO_LOOP
|
||||
NO_INOTIFY
|
||||
NO_IPSET
|
||||
these are available to explicitly disable compile time options which would
|
||||
otherwise be enabled automatically 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_GMP
|
||||
Don't use and link against libgmp, Useful if nettle is built with --enable-mini-gmp.
|
||||
|
||||
LEASEFILE
|
||||
CONFFILE
|
||||
RESOLVFILE
|
||||
the default locations of these files are determined below, but may be overridden
|
||||
in a build command line using COPTS.
|
||||
|
||||
*/
|
||||
|
||||
/* 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 */
|
||||
|
||||
#define HAVE_DHCP
|
||||
#define HAVE_DHCP6
|
||||
#define HAVE_TFTP
|
||||
#define HAVE_SCRIPT
|
||||
#define HAVE_AUTH
|
||||
#define HAVE_IPSET
|
||||
#define HAVE_LOOP
|
||||
#define HAVE_DUMPFILE
|
||||
|
||||
/* 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_DBUS */
|
||||
/* #define HAVE_IDN */
|
||||
/* #define HAVE_LIBIDN2 */
|
||||
/* #define HAVE_CONNTRACK */
|
||||
/* #define HAVE_DNSSEC */
|
||||
/* #define HAVE_NFTSET */
|
||||
|
||||
/* Default locations for important system files. */
|
||||
|
||||
#ifndef LEASEFILE
|
||||
# if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
|
||||
@@ -61,147 +226,43 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
||||
#define CHUSER "nobody"
|
||||
#define CHGRP "dip"
|
||||
#define NAMESERVER_PORT 53
|
||||
#define DHCP_SERVER_PORT 67
|
||||
#define DHCP_CLIENT_PORT 68
|
||||
#define DHCP_SERVER_ALTPORT 1067
|
||||
#define DHCP_CLIENT_ALTPORT 1068
|
||||
#define PXE_PORT 4011
|
||||
#define TFTP_PORT 69
|
||||
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
|
||||
#define LOG_MAX 5 /* log-queue length */
|
||||
#define RANDFILE "/dev/urandom"
|
||||
#define DAD_WAIT 20 /* retry binding IPv6 sockets for this long */
|
||||
#define EDNS0_OPTION_MAC 5 /* dyndns.org temporary assignment */
|
||||
#ifndef RESOLVFILE
|
||||
# if defined(__uClinux__)
|
||||
# define RESOLVFILE "/etc/config/resolv.conf"
|
||||
# else
|
||||
# define RESOLVFILE "/etc/resolv.conf"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* DBUS interface specifics */
|
||||
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq"
|
||||
#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
|
||||
#ifndef RUNFILE
|
||||
# if defined(__ANDROID__)
|
||||
# define RUNFILE "/data/dnsmasq.pid"
|
||||
# else
|
||||
# define RUNFILE "/var/run/dnsmasq.pid"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Follows system specific switches. If you run on a
|
||||
new system, you may want to edit these.
|
||||
May replace this with Autoconf one day.
|
||||
/* platform dependent options: these are determined automatically below
|
||||
|
||||
HAVE_LINUX_NETWORK
|
||||
HAVE_BSD_NETWORK
|
||||
HAVE_SOLARIS_NETWORK
|
||||
define exactly one of these to alter interaction with kernel networking.
|
||||
|
||||
HAVE_BROKEN_RTC
|
||||
define this on embedded systems which don't have an RTC
|
||||
which keeps time over reboots. Causes dnsmasq to use uptime
|
||||
for timing, and keep lease lengths rather than expiry times
|
||||
in its leases file. This also make dnsmasq "flash disk friendly".
|
||||
Normally, dnsmasq tries very hard to keep the on-disk leases file
|
||||
up-to-date: rewriting it after every renewal. When HAVE_BROKEN_RTC
|
||||
is in effect, the lease file is only written when a new lease is
|
||||
created, or an old one destroyed. (Because those are the only times
|
||||
it changes.) This vastly reduces the number of file writes, and makes
|
||||
it viable to keep the lease file on a flash filesystem.
|
||||
NOTE: when enabling or disabling this, be sure to delete any old
|
||||
leases file, otherwise dnsmasq may get very confused.
|
||||
|
||||
HAVE_TFTP
|
||||
define this to get dnsmasq's built-in TFTP server.
|
||||
|
||||
HAVE_DHCP
|
||||
define this to get dnsmasq's DHCP server.
|
||||
|
||||
HAVE_SCRIPT
|
||||
define this to get the ability to call scripts on lease-change
|
||||
|
||||
HAVE_GETOPT_LONG
|
||||
define this if you have GNU libc or GNU getopt.
|
||||
|
||||
HAVE_ARC4RANDOM
|
||||
define this if you have arc4random() to get better security from DNS spoofs
|
||||
by using really random ids (OpenBSD)
|
||||
defined when GNU-style getopt_long available.
|
||||
|
||||
HAVE_SOCKADDR_SA_LEN
|
||||
define this if struct sockaddr has sa_len field (*BSD)
|
||||
|
||||
HAVE_DBUS
|
||||
define this if you want to link against libdbus, and have dnsmasq
|
||||
support some methods to allow (re)configuration of the upstream DNS
|
||||
servers via DBus.
|
||||
|
||||
HAVE_IDN
|
||||
define this if you want international domain name 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.
|
||||
|
||||
NOTES:
|
||||
For Linux you should define
|
||||
HAVE_LINUX_NETWORK
|
||||
HAVE_GETOPT_LONG
|
||||
you should NOT define
|
||||
HAVE_ARC4RANDOM
|
||||
HAVE_SOCKADDR_SA_LEN
|
||||
|
||||
For *BSD systems you should define
|
||||
HAVE_BSD_NETWORK
|
||||
HAVE_SOCKADDR_SA_LEN
|
||||
and you MAY define
|
||||
HAVE_ARC4RANDOM - OpenBSD and FreeBSD and NetBSD version 2.0 or later
|
||||
HAVE_GETOPT_LONG - NetBSD, later FreeBSD
|
||||
(FreeBSD and OpenBSD only if you link GNU getopt)
|
||||
|
||||
defined if struct sockaddr has sa_len field (*BSD)
|
||||
*/
|
||||
|
||||
/* platform independent options- uncomment to enable */
|
||||
#define HAVE_DHCP
|
||||
#define HAVE_TFTP
|
||||
#define HAVE_SCRIPT
|
||||
/* #define HAVE_BROKEN_RTC */
|
||||
/* #define HAVE_DBUS */
|
||||
/* #define HAVE_IDN */
|
||||
|
||||
/* Allow TFTP to be disabled with COPTS=-DNO_TFTP */
|
||||
#ifdef NO_TFTP
|
||||
#undef HAVE_TFTP
|
||||
#endif
|
||||
|
||||
/* Allow DHCP to be disabled with COPTS=-DNO_DHCP */
|
||||
#ifdef NO_DHCP
|
||||
#undef HAVE_DHCP
|
||||
#endif
|
||||
|
||||
/* Allow scripts to be disabled with COPTS=-DNO_SCRIPT */
|
||||
#ifdef NO_SCRIPT
|
||||
#undef HAVE_SCRIPT
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* platform dependent options. */
|
||||
|
||||
/* Must preceed __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
|
||||
processes for TCP connections and disables the call-a-script on leasechange
|
||||
system. It's intended for use on MMU-less kernels. */
|
||||
#define NO_FORK
|
||||
|
||||
#elif defined(__UCLIBC__)
|
||||
#if defined(__UCLIBC__)
|
||||
#define HAVE_LINUX_NETWORK
|
||||
#if defined(__UCLIBC_HAS_GNU_GETOPT__) || \
|
||||
((__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
|
||||
#endif
|
||||
#if defined(__UCLIBC_HAS_IPV6__)
|
||||
# ifndef IPV6_V6ONLY
|
||||
# define IPV6_V6ONLY 26
|
||||
@@ -212,7 +273,6 @@ NOTES:
|
||||
#elif defined(__linux__)
|
||||
#define HAVE_LINUX_NETWORK
|
||||
#define HAVE_GETOPT_LONG
|
||||
#undef HAVE_ARC4RANDOM
|
||||
#undef HAVE_SOCKADDR_SA_LEN
|
||||
|
||||
#elif defined(__FreeBSD__) || \
|
||||
@@ -220,61 +280,200 @@ NOTES:
|
||||
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 NO_IPSET
|
||||
/* 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
|
||||
/* Required for Mojave. */
|
||||
#ifndef SOL_TCP
|
||||
# define SOL_TCP IPPROTO_TCP
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
#endif
|
||||
|
||||
/* Decide if we're going to support IPv6 */
|
||||
/* IPv6 can be forced off with "make COPTS=-DNO_IPV6" */
|
||||
/* We assume that systems which don't have IPv6
|
||||
headers don't have ntop and pton either */
|
||||
/* rules to implement compile-time option dependencies and
|
||||
the NO_XXX flags */
|
||||
|
||||
#if defined(INET6_ADDRSTRLEN) && defined(IPV6_V6ONLY) && !defined(NO_IPV6)
|
||||
# define HAVE_IPV6
|
||||
# define ADDRSTRLEN INET6_ADDRSTRLEN
|
||||
# if defined(SOL_IPV6)
|
||||
# define IPV6_LEVEL SOL_IPV6
|
||||
#ifdef NO_TFTP
|
||||
#undef HAVE_TFTP
|
||||
#endif
|
||||
|
||||
#ifdef NO_DHCP
|
||||
#undef HAVE_DHCP
|
||||
#undef HAVE_DHCP6
|
||||
#endif
|
||||
|
||||
#if defined(NO_DHCP6)
|
||||
#undef HAVE_DHCP6
|
||||
#endif
|
||||
|
||||
/* DHCP6 needs DHCP too */
|
||||
#ifdef HAVE_DHCP6
|
||||
#define HAVE_DHCP
|
||||
#endif
|
||||
|
||||
#if defined(NO_SCRIPT)
|
||||
#undef HAVE_SCRIPT
|
||||
#undef HAVE_LUASCRIPT
|
||||
#endif
|
||||
|
||||
/* Must HAVE_SCRIPT to HAVE_LUASCRIPT */
|
||||
#ifdef HAVE_LUASCRIPT
|
||||
#define HAVE_SCRIPT
|
||||
#endif
|
||||
|
||||
#ifdef NO_AUTH
|
||||
#undef HAVE_AUTH
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_LINUX_NETWORK)
|
||||
#undef HAVE_NFTSET
|
||||
#endif
|
||||
|
||||
#if defined(NO_IPSET)
|
||||
#undef HAVE_IPSET
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_IPSET)
|
||||
# if defined(HAVE_LINUX_NETWORK)
|
||||
# define HAVE_LINUX_IPSET
|
||||
# elif defined(HAVE_BSD_NETWORK)
|
||||
# define HAVE_BSD_IPSET
|
||||
# else
|
||||
# define IPV6_LEVEL IPPROTO_IPV6
|
||||
# undef HAVE_IPSET
|
||||
# endif
|
||||
#elif defined(INET_ADDRSTRLEN)
|
||||
# undef HAVE_IPV6
|
||||
# define ADDRSTRLEN INET_ADDRSTRLEN
|
||||
#endif
|
||||
|
||||
#ifdef NO_LOOP
|
||||
#undef HAVE_LOOP
|
||||
#endif
|
||||
|
||||
#ifdef NO_DUMPFILE
|
||||
#undef HAVE_DUMPFILE
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_LINUX_NETWORK) && !defined(NO_INOTIFY)
|
||||
#define HAVE_INOTIFY
|
||||
#endif
|
||||
|
||||
/* This never compiles code, it's only used by the makefile to fingerprint builds. */
|
||||
#ifdef DNSMASQ_COMPILE_FLAGS
|
||||
static char *compile_flags = DNSMASQ_COMPILE_FLAGS;
|
||||
#endif
|
||||
|
||||
/* Define a string indicating which options are in use.
|
||||
DNSMASQ_COMPILE_OPTS is only defined in dnsmasq.c */
|
||||
|
||||
#ifdef DNSMASQ_COMPILE_OPTS
|
||||
|
||||
static char *compile_opts =
|
||||
"IPv6 "
|
||||
#ifndef HAVE_GETOPT_LONG
|
||||
"no-"
|
||||
#endif
|
||||
"GNU-getopt "
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
"no-RTC "
|
||||
#endif
|
||||
#ifndef HAVE_DBUS
|
||||
"no-"
|
||||
#endif
|
||||
"DBus "
|
||||
#ifndef HAVE_UBUS
|
||||
"no-"
|
||||
#endif
|
||||
"UBus "
|
||||
#ifndef LOCALEDIR
|
||||
"no-"
|
||||
#endif
|
||||
"i18n "
|
||||
#if defined(HAVE_LIBIDN2)
|
||||
"IDN2 "
|
||||
#else
|
||||
# undef HAVE_IPV6
|
||||
# define ADDRSTRLEN 16 /* 4*3 + 3 dots + NULL */
|
||||
#if !defined(HAVE_IDN)
|
||||
"no-"
|
||||
#endif
|
||||
"IDN "
|
||||
#endif
|
||||
|
||||
/* Can't do scripts without fork */
|
||||
#ifdef NOFORK
|
||||
# undef HAVE_SCRIPT
|
||||
#ifndef HAVE_DHCP
|
||||
"no-"
|
||||
#endif
|
||||
"DHCP "
|
||||
#if defined(HAVE_DHCP)
|
||||
# if !defined (HAVE_DHCP6)
|
||||
"no-"
|
||||
# endif
|
||||
"DHCPv6 "
|
||||
#endif
|
||||
#if !defined(HAVE_SCRIPT)
|
||||
"no-scripts "
|
||||
#else
|
||||
# if !defined(HAVE_LUASCRIPT)
|
||||
"no-"
|
||||
# endif
|
||||
"Lua "
|
||||
#endif
|
||||
#ifndef HAVE_TFTP
|
||||
"no-"
|
||||
#endif
|
||||
"TFTP "
|
||||
#ifndef HAVE_CONNTRACK
|
||||
"no-"
|
||||
#endif
|
||||
"conntrack "
|
||||
#ifndef HAVE_IPSET
|
||||
"no-"
|
||||
#endif
|
||||
"ipset "
|
||||
#ifndef HAVE_NFTSET
|
||||
"no-"
|
||||
#endif
|
||||
"nftset "
|
||||
#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 "
|
||||
#ifndef HAVE_DUMPFILE
|
||||
"no-"
|
||||
#endif
|
||||
"dumpfile";
|
||||
|
||||
#endif /* defined(DNSMASQ_COMPILE_OPTS) */
|
||||
|
||||
85
src/conntrack.c
Normal file
85
src/conntrack.c
Normal file
@@ -0,0 +1,85 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2025 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_CONNTRACK
|
||||
|
||||
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
|
||||
|
||||
static int gotit = 0; /* yuck */
|
||||
|
||||
static int callback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data);
|
||||
|
||||
int get_incoming_mark(union mysockaddr *peer_addr, union all_addr *local_addr, int istcp, unsigned int *markp)
|
||||
{
|
||||
struct nf_conntrack *ct;
|
||||
struct nfct_handle *h;
|
||||
|
||||
gotit = 0;
|
||||
|
||||
if ((ct = nfct_new()))
|
||||
{
|
||||
nfct_set_attr_u8(ct, ATTR_L4PROTO, istcp ? IPPROTO_TCP : IPPROTO_UDP);
|
||||
nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(daemon->port));
|
||||
|
||||
if (peer_addr->sa.sa_family == AF_INET6)
|
||||
{
|
||||
nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET6);
|
||||
nfct_set_attr(ct, ATTR_IPV6_SRC, peer_addr->in6.sin6_addr.s6_addr);
|
||||
nfct_set_attr_u16(ct, ATTR_PORT_SRC, peer_addr->in6.sin6_port);
|
||||
nfct_set_attr(ct, ATTR_IPV6_DST, local_addr->addr6.s6_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET);
|
||||
nfct_set_attr_u32(ct, ATTR_IPV4_SRC, peer_addr->in.sin_addr.s_addr);
|
||||
nfct_set_attr_u16(ct, ATTR_PORT_SRC, peer_addr->in.sin_port);
|
||||
nfct_set_attr_u32(ct, ATTR_IPV4_DST, local_addr->addr4.s_addr);
|
||||
}
|
||||
|
||||
|
||||
if ((h = nfct_open(CONNTRACK, 0)))
|
||||
{
|
||||
nfct_callback_register(h, NFCT_T_ALL, callback, (void *)markp);
|
||||
if (nfct_query(h, NFCT_Q_GET, ct) == -1)
|
||||
{
|
||||
static int warned = 0;
|
||||
if (!warned)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("Conntrack connection mark retrieval failed: %s"), strerror(errno));
|
||||
warned = 1;
|
||||
}
|
||||
}
|
||||
nfct_close(h);
|
||||
}
|
||||
nfct_destroy(ct);
|
||||
}
|
||||
|
||||
return gotit;
|
||||
}
|
||||
|
||||
static int callback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data)
|
||||
{
|
||||
unsigned int *ret = (unsigned int *)data;
|
||||
*ret = nfct_get_attr_u32(ct, ATTR_MARK);
|
||||
(void)type; /* eliminate warning */
|
||||
gotit = 1;
|
||||
|
||||
return NFCT_CB_CONTINUE;
|
||||
}
|
||||
|
||||
#endif /* HAVE_CONNTRACK */
|
||||
506
src/crypto.c
Normal file
506
src/crypto.c
Normal file
@@ -0,0 +1,506 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2025 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"
|
||||
|
||||
#if defined(HAVE_DNSSEC)
|
||||
|
||||
/* Minimal version of nettle */
|
||||
|
||||
/* bignum.h includes version.h and works on
|
||||
earlier releases of nettle which don't have version.h */
|
||||
#include <nettle/bignum.h>
|
||||
#if !defined(NETTLE_VERSION_MAJOR)
|
||||
# define NETTLE_VERSION_MAJOR 2
|
||||
# define NETTLE_VERSION_MINOR 0
|
||||
#endif
|
||||
#define MIN_VERSION(major, minor) ((NETTLE_VERSION_MAJOR == (major) && NETTLE_VERSION_MINOR >= (minor)) || \
|
||||
(NETTLE_VERSION_MAJOR > (major)))
|
||||
|
||||
#include <nettle/rsa.h>
|
||||
#include <nettle/ecdsa.h>
|
||||
#include <nettle/ecc-curve.h>
|
||||
#if MIN_VERSION(3, 1)
|
||||
#include <nettle/eddsa.h>
|
||||
#endif
|
||||
#if MIN_VERSION(3, 6)
|
||||
# include <nettle/gostdsa.h>
|
||||
#endif
|
||||
|
||||
#if MIN_VERSION(3, 1)
|
||||
/* Implement a "hash-function" to the nettle API, which simply returns
|
||||
the input data, concatenated into a single, statically maintained, buffer.
|
||||
|
||||
Used for the EdDSA sigs, which operate on the whole message, rather
|
||||
than a digest. */
|
||||
|
||||
struct null_hash_digest
|
||||
{
|
||||
uint8_t *buff;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct null_hash_ctx
|
||||
{
|
||||
size_t len;
|
||||
};
|
||||
|
||||
static size_t null_hash_buff_sz = 0;
|
||||
static uint8_t *null_hash_buff = NULL;
|
||||
#define BUFF_INCR 128
|
||||
|
||||
static void null_hash_init(void *ctx)
|
||||
{
|
||||
((struct null_hash_ctx *)ctx)->len = 0;
|
||||
}
|
||||
|
||||
static void null_hash_update(void *ctxv, size_t length, const uint8_t *src)
|
||||
{
|
||||
struct null_hash_ctx *ctx = ctxv;
|
||||
size_t new_len = ctx->len + length;
|
||||
|
||||
if (new_len > null_hash_buff_sz)
|
||||
{
|
||||
uint8_t *new;
|
||||
|
||||
if (!(new = whine_malloc(new_len + BUFF_INCR)))
|
||||
return;
|
||||
|
||||
if (null_hash_buff)
|
||||
{
|
||||
if (ctx->len != 0)
|
||||
memcpy(new, null_hash_buff, ctx->len);
|
||||
free(null_hash_buff);
|
||||
}
|
||||
|
||||
null_hash_buff_sz = new_len + BUFF_INCR;
|
||||
null_hash_buff = new;
|
||||
}
|
||||
|
||||
memcpy(null_hash_buff + ctx->len, src, length);
|
||||
ctx->len += length;
|
||||
}
|
||||
|
||||
static void null_hash_digest(void *ctx, size_t length, uint8_t *dst)
|
||||
{
|
||||
(void)length;
|
||||
|
||||
((struct null_hash_digest *)dst)->buff = null_hash_buff;
|
||||
((struct null_hash_digest *)dst)->len = ((struct null_hash_ctx *)ctx)->len;
|
||||
}
|
||||
|
||||
static struct nettle_hash null_hash = {
|
||||
"null_hash",
|
||||
sizeof(struct null_hash_ctx),
|
||||
sizeof(struct null_hash_digest),
|
||||
0,
|
||||
(nettle_hash_init_func *) null_hash_init,
|
||||
(nettle_hash_update_func *) null_hash_update,
|
||||
(nettle_hash_digest_func *) null_hash_digest
|
||||
};
|
||||
|
||||
#endif /* MIN_VERSION(3, 1) */
|
||||
|
||||
/* expand ctx and digest memory allocations if necessary and init hash function */
|
||||
int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
|
||||
{
|
||||
static void *ctx = NULL;
|
||||
static unsigned char *digest = NULL;
|
||||
static unsigned int ctx_sz = 0;
|
||||
static unsigned int digest_sz = 0;
|
||||
|
||||
void *new;
|
||||
|
||||
if (ctx_sz < hash->context_size)
|
||||
{
|
||||
if (!(new = whine_malloc(hash->context_size)))
|
||||
return 0;
|
||||
if (ctx)
|
||||
free(ctx);
|
||||
ctx = new;
|
||||
ctx_sz = hash->context_size;
|
||||
}
|
||||
|
||||
if (digest_sz < hash->digest_size)
|
||||
{
|
||||
if (!(new = whine_malloc(hash->digest_size)))
|
||||
return 0;
|
||||
if (digest)
|
||||
free(digest);
|
||||
digest = new;
|
||||
digest_sz = hash->digest_size;
|
||||
}
|
||||
|
||||
*ctxp = ctx;
|
||||
*digestp = digest;
|
||||
|
||||
hash->init(ctx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
size_t exp_len;
|
||||
|
||||
static struct rsa_public_key *key = NULL;
|
||||
static mpz_t sig_mpz;
|
||||
|
||||
(void)digest_len;
|
||||
|
||||
if (key == NULL)
|
||||
{
|
||||
if (!(key = whine_malloc(sizeof(struct rsa_public_key))))
|
||||
return 0;
|
||||
|
||||
nettle_rsa_public_key_init(key);
|
||||
mpz_init(sig_mpz);
|
||||
}
|
||||
|
||||
if ((key_len < 3) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
key_len--;
|
||||
if ((exp_len = *p++) == 0)
|
||||
{
|
||||
GETSHORT(exp_len, p);
|
||||
key_len -= 2;
|
||||
}
|
||||
|
||||
if (exp_len >= key_len)
|
||||
return 0;
|
||||
|
||||
key->size = key_len - exp_len;
|
||||
mpz_import(key->e, exp_len, 1, 1, 0, 0, p);
|
||||
mpz_import(key->n, key->size, 1, 1, 0, 0, p + exp_len);
|
||||
|
||||
mpz_import(sig_mpz, sig_len, 1, 1, 0, 0, sig);
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case 5: case 7:
|
||||
return nettle_rsa_sha1_verify_digest(key, digest, sig_mpz);
|
||||
case 8:
|
||||
return nettle_rsa_sha256_verify_digest(key, digest, sig_mpz);
|
||||
case 10:
|
||||
return nettle_rsa_sha512_verify_digest(key, digest, sig_mpz);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len,
|
||||
unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
unsigned int t;
|
||||
struct ecc_point *key;
|
||||
|
||||
static struct ecc_point *key_256 = NULL, *key_384 = NULL;
|
||||
static mpz_t x, y;
|
||||
static struct dsa_signature *sig_struct;
|
||||
#if !MIN_VERSION(3, 4)
|
||||
#define nettle_get_secp_256r1() (&nettle_secp_256r1)
|
||||
#define nettle_get_secp_384r1() (&nettle_secp_384r1)
|
||||
#endif
|
||||
|
||||
if (!sig_struct)
|
||||
{
|
||||
if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))))
|
||||
return 0;
|
||||
|
||||
nettle_dsa_signature_init(sig_struct);
|
||||
mpz_init(x);
|
||||
mpz_init(y);
|
||||
}
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case 13:
|
||||
if (!key_256)
|
||||
{
|
||||
if (!(key_256 = whine_malloc(sizeof(struct ecc_point))))
|
||||
return 0;
|
||||
|
||||
nettle_ecc_point_init(key_256, nettle_get_secp_256r1());
|
||||
}
|
||||
|
||||
key = key_256;
|
||||
t = 32;
|
||||
break;
|
||||
|
||||
case 14:
|
||||
if (!key_384)
|
||||
{
|
||||
if (!(key_384 = whine_malloc(sizeof(struct ecc_point))))
|
||||
return 0;
|
||||
|
||||
nettle_ecc_point_init(key_384, nettle_get_secp_384r1());
|
||||
}
|
||||
|
||||
key = key_384;
|
||||
t = 48;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sig_len != 2*t || key_len != 2*t ||
|
||||
!(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
mpz_import(x, t , 1, 1, 0, 0, p);
|
||||
mpz_import(y, t , 1, 1, 0, 0, p + t);
|
||||
|
||||
if (!ecc_point_set(key, x, y))
|
||||
return 0;
|
||||
|
||||
mpz_import(sig_struct->r, t, 1, 1, 0, 0, sig);
|
||||
mpz_import(sig_struct->s, t, 1, 1, 0, 0, sig + t);
|
||||
|
||||
return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
|
||||
}
|
||||
|
||||
#if MIN_VERSION(3, 6)
|
||||
static int dnsmasq_gostdsa_verify(struct blockdata *key_data, unsigned int key_len,
|
||||
unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
static struct ecc_point *gost_key = NULL;
|
||||
static mpz_t x, y;
|
||||
static struct dsa_signature *sig_struct;
|
||||
|
||||
if (algo != 12 ||
|
||||
sig_len != 64 || key_len != 64 ||
|
||||
!(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
if (!sig_struct)
|
||||
{
|
||||
if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) ||
|
||||
!(gost_key = whine_malloc(sizeof(struct ecc_point))))
|
||||
return 0;
|
||||
|
||||
nettle_dsa_signature_init(sig_struct);
|
||||
nettle_ecc_point_init(gost_key, nettle_get_gost_gc256b());
|
||||
mpz_init(x);
|
||||
mpz_init(y);
|
||||
}
|
||||
|
||||
mpz_import(x, 32, -1, 1, 0, 0, p);
|
||||
mpz_import(y, 32, -1, 1, 0, 0, p + 32);
|
||||
|
||||
if (!ecc_point_set(gost_key, x, y))
|
||||
return 0;
|
||||
|
||||
mpz_import(sig_struct->s, 32, 1, 1, 0, 0, sig);
|
||||
mpz_import(sig_struct->r, 32, 1, 1, 0, 0, sig + 32);
|
||||
|
||||
return nettle_gostdsa_verify(gost_key, digest_len, digest, sig_struct);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MIN_VERSION(3, 1)
|
||||
static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len,
|
||||
unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
if (digest_len != sizeof(struct null_hash_digest) ||
|
||||
!(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
/* The "digest" returned by the null_hash function is simply a struct null_hash_digest
|
||||
which has a pointer to the actual data and a length, because the buffer
|
||||
may need to be extended during "hashing". */
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case 15:
|
||||
if (key_len != ED25519_KEY_SIZE ||
|
||||
sig_len != ED25519_SIGNATURE_SIZE)
|
||||
return 0;
|
||||
|
||||
return ed25519_sha512_verify(p,
|
||||
((struct null_hash_digest *)digest)->len,
|
||||
((struct null_hash_digest *)digest)->buff,
|
||||
sig);
|
||||
|
||||
#if MIN_VERSION(3, 6)
|
||||
case 16:
|
||||
if (key_len != ED448_KEY_SIZE ||
|
||||
sig_len != ED448_SIGNATURE_SIZE)
|
||||
return 0;
|
||||
|
||||
return ed448_shake256_verify(p,
|
||||
((struct null_hash_digest *)digest)->len,
|
||||
((struct null_hash_digest *)digest)->buff,
|
||||
sig);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
|
||||
/* Ensure at runtime that we have support for this digest */
|
||||
if (!hash_find(algo_digest_name(algo)))
|
||||
return NULL;
|
||||
|
||||
/* This switch defines which sig algorithms we support, can't introspect Nettle for that. */
|
||||
switch (algo)
|
||||
{
|
||||
case 5: case 7: case 8: case 10:
|
||||
return dnsmasq_rsa_verify;
|
||||
|
||||
#if MIN_VERSION(3, 6)
|
||||
case 12:
|
||||
return dnsmasq_gostdsa_verify;
|
||||
#endif
|
||||
|
||||
case 13: case 14:
|
||||
return dnsmasq_ecdsa_verify;
|
||||
|
||||
#if MIN_VERSION(3, 1)
|
||||
case 15:
|
||||
return dnsmasq_eddsa_verify;
|
||||
#endif
|
||||
|
||||
#if MIN_VERSION(3, 6)
|
||||
case 16:
|
||||
return dnsmasq_eddsa_verify;
|
||||
#endif
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
|
||||
int (*func)(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo);
|
||||
|
||||
func = verify_func(algo);
|
||||
|
||||
if (!func)
|
||||
return 0;
|
||||
|
||||
return (*func)(key_data, key_len, sig, sig_len, digest, digest_len, algo);
|
||||
}
|
||||
|
||||
/* Note the ds_digest_name(), algo_digest_name() and nsec3_digest_name()
|
||||
define which algo numbers we support. If algo_digest_name() returns
|
||||
non-NULL for an algorithm number, we assume that algorithm is
|
||||
supported by verify(). */
|
||||
|
||||
/* http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
|
||||
char *ds_digest_name(int digest)
|
||||
{
|
||||
switch (digest)
|
||||
{
|
||||
case 1: return "sha1";
|
||||
case 2: return "sha256";
|
||||
#if MIN_VERSION(3, 6)
|
||||
case 3: return "gosthash94cp";
|
||||
#endif
|
||||
case 4: return "sha384";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
|
||||
char *algo_digest_name(int algo)
|
||||
{
|
||||
switch (algo)
|
||||
{
|
||||
case 1: return NULL; /* RSA/MD5 - Must Not Implement. RFC 6944 para 2.3. */
|
||||
case 2: return NULL; /* Diffie-Hellman */
|
||||
case 3: return NULL; ; /* DSA/SHA1 - Must Not Implement. RFC 8624 section 3.1 */
|
||||
case 5: return "sha1"; /* RSA/SHA1 */
|
||||
case 6: return NULL; /* DSA-NSEC3-SHA1 - Must Not Implement. RFC 8624 section 3.1 */
|
||||
case 7: return "sha1"; /* RSASHA1-NSEC3-SHA1 */
|
||||
case 8: return "sha256"; /* RSA/SHA-256 */
|
||||
case 10: return "sha512"; /* RSA/SHA-512 */
|
||||
#if MIN_VERSION(3, 6)
|
||||
case 12: return "gosthash94cp"; /* ECC-GOST */
|
||||
#endif
|
||||
case 13: return "sha256"; /* ECDSAP256SHA256 */
|
||||
case 14: return "sha384"; /* ECDSAP384SHA384 */
|
||||
#if MIN_VERSION(3, 1)
|
||||
case 15: return "null_hash"; /* ED25519 */
|
||||
# if MIN_VERSION(3, 6)
|
||||
case 16: return "null_hash"; /* ED448 */
|
||||
# endif
|
||||
#endif
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
|
||||
char *nsec3_digest_name(int digest)
|
||||
{
|
||||
switch (digest)
|
||||
{
|
||||
case 1: return "sha1";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find pointer to correct hash function in nettle library */
|
||||
const struct nettle_hash *hash_find(char *name)
|
||||
{
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
#if MIN_VERSION(3,1) && defined(HAVE_DNSSEC)
|
||||
/* We provide a "null" hash which returns the input data as digest. */
|
||||
if (strcmp(null_hash.name, name) == 0)
|
||||
return &null_hash;
|
||||
#endif
|
||||
|
||||
/* libnettle >= 3.4 provides nettle_lookup_hash() which avoids nasty ABI
|
||||
incompatibilities if sizeof(nettle_hashes) changes between library
|
||||
versions. */
|
||||
#if MIN_VERSION(3, 4)
|
||||
return nettle_lookup_hash(name);
|
||||
#else
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; nettle_hashes[i]; i++)
|
||||
if (strcmp(nettle_hashes[i]->name, name) == 0)
|
||||
return nettle_hashes[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* defined(HAVE_DNSSEC) */
|
||||
970
src/dbus.c
970
src/dbus.c
File diff suppressed because it is too large
Load Diff
1081
src/dhcp-common.c
Normal file
1081
src/dhcp-common.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2025 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
|
||||
@@ -13,6 +13,15 @@
|
||||
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 DHCP_SERVER_PORT 67
|
||||
#define DHCP_CLIENT_PORT 68
|
||||
#define DHCP_SERVER_ALTPORT 1067
|
||||
#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
|
||||
@@ -45,8 +54,11 @@
|
||||
#define OPTION_SNAME 66
|
||||
#define OPTION_FILENAME 67
|
||||
#define OPTION_USER_CLASS 77
|
||||
#define OPTION_RAPID_COMMIT 80
|
||||
#define OPTION_CLIENT_FQDN 81
|
||||
#define OPTION_AGENT_ID 82
|
||||
#define OPTION_LAST_TRANSACTION 91
|
||||
#define OPTION_ASSOCIATED_IP 92
|
||||
#define OPTION_ARCH 93
|
||||
#define OPTION_PXE_UUID 97
|
||||
#define OPTION_SUBNET_SELECT 118
|
||||
@@ -54,12 +66,14 @@
|
||||
#define OPTION_SIP_SERVER 120
|
||||
#define OPTION_VENDOR_IDENT 124
|
||||
#define OPTION_VENDOR_IDENT_OPT 125
|
||||
#define OPTION_MUD_URL_V4 161
|
||||
#define OPTION_END 255
|
||||
|
||||
#define SUBOPT_CIRCUIT_ID 1
|
||||
#define SUBOPT_REMOTE_ID 2
|
||||
#define SUBOPT_SUBNET_SELECT 5 /* RFC 3527 */
|
||||
#define SUBOPT_SUBSCR_ID 6 /* RFC 3393 */
|
||||
#define SUBOPT_FLAGS 10 /* RFC 5010 */
|
||||
#define SUBOPT_SERVER_OR 11 /* RFC 5107 */
|
||||
|
||||
#define SUBOPT_PXE_BOOT_ITEM 71 /* PXE standard */
|
||||
@@ -76,6 +90,11 @@
|
||||
#define DHCPNAK 6
|
||||
#define DHCPRELEASE 7
|
||||
#define DHCPINFORM 8
|
||||
#define DHCPFORCERENEW 9
|
||||
#define DHCPLEASEQUERY 10
|
||||
#define DHCPLEASEUNASSIGNED 11
|
||||
#define DHCPLEASEUNKNOWN 12
|
||||
#define DHCPLEASEACTIVE 13
|
||||
|
||||
#define BRDBAND_FORUM_IANA 3561 /* Broadband forum IANA enterprise */
|
||||
|
||||
956
src/dhcp.c
956
src/dhcp.c
File diff suppressed because it is too large
Load Diff
77
src/dhcp6-protocol.h
Normal file
77
src/dhcp6-protocol.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2025 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 DHCPV6_SERVER_PORT 547
|
||||
#define DHCPV6_CLIENT_PORT 546
|
||||
|
||||
#define ALL_SERVERS "FF05::1:3"
|
||||
#define ALL_RELAY_AGENTS_AND_SERVERS "FF02::1:2"
|
||||
|
||||
#define DHCP6SOLICIT 1
|
||||
#define DHCP6ADVERTISE 2
|
||||
#define DHCP6REQUEST 3
|
||||
#define DHCP6CONFIRM 4
|
||||
#define DHCP6RENEW 5
|
||||
#define DHCP6REBIND 6
|
||||
#define DHCP6REPLY 7
|
||||
#define DHCP6RELEASE 8
|
||||
#define DHCP6DECLINE 9
|
||||
#define DHCP6RECONFIGURE 10
|
||||
#define DHCP6IREQ 11
|
||||
#define DHCP6RELAYFORW 12
|
||||
#define DHCP6RELAYREPL 13
|
||||
|
||||
#define OPTION6_CLIENT_ID 1
|
||||
#define OPTION6_SERVER_ID 2
|
||||
#define OPTION6_IA_NA 3
|
||||
#define OPTION6_IA_TA 4
|
||||
#define OPTION6_IAADDR 5
|
||||
#define OPTION6_ORO 6
|
||||
#define OPTION6_PREFERENCE 7
|
||||
#define OPTION6_ELAPSED_TIME 8
|
||||
#define OPTION6_RELAY_MSG 9
|
||||
#define OPTION6_AUTH 11
|
||||
#define OPTION6_UNICAST 12
|
||||
#define OPTION6_STATUS_CODE 13
|
||||
#define OPTION6_RAPID_COMMIT 14
|
||||
#define OPTION6_USER_CLASS 15
|
||||
#define OPTION6_VENDOR_CLASS 16
|
||||
#define OPTION6_VENDOR_OPTS 17
|
||||
#define OPTION6_INTERFACE_ID 18
|
||||
#define OPTION6_RECONFIGURE_MSG 19
|
||||
#define OPTION6_RECONF_ACCEPT 20
|
||||
#define OPTION6_DNS_SERVER 23
|
||||
#define OPTION6_DOMAIN_SEARCH 24
|
||||
#define OPTION6_IA_PD 25
|
||||
#define OPTION6_IAPREFIX 26
|
||||
#define OPTION6_REFRESH_TIME 32
|
||||
#define OPTION6_REMOTE_ID 37
|
||||
#define OPTION6_SUBSCRIBER_ID 38
|
||||
#define OPTION6_FQDN 39
|
||||
#define OPTION6_NTP_SERVER 56
|
||||
#define OPTION6_CLIENT_MAC 79
|
||||
#define OPTION6_MUD_URL 112
|
||||
|
||||
#define NTP_SUBOPTION_SRV_ADDR 1
|
||||
#define NTP_SUBOPTION_MC_ADDR 2
|
||||
#define NTP_SUBOPTION_SRV_FQDN 3
|
||||
|
||||
#define DHCP6SUCCESS 0
|
||||
#define DHCP6UNSPEC 1
|
||||
#define DHCP6NOADDRS 2
|
||||
#define DHCP6NOBINDING 3
|
||||
#define DHCP6NOTONLINK 4
|
||||
#define DHCP6USEMULTI 5
|
||||
881
src/dhcp6.c
Normal file
881
src/dhcp6.c
Normal file
@@ -0,0 +1,881 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2025 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_DHCP6
|
||||
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
struct iface_param {
|
||||
struct dhcp_context *current;
|
||||
struct in6_addr fallback, ll_addr, ula_addr;
|
||||
int ind, addr_match;
|
||||
};
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_in6 saddr;
|
||||
#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);
|
||||
#endif
|
||||
saddr.sin6_family = AF_INET6;
|
||||
saddr.sin6_addr = in6addr_any;
|
||||
saddr.sin6_port = htons(DHCPV6_SERVER_PORT);
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in6)))
|
||||
die(_("failed to bind DHCPv6 server socket: %s"), NULL, EC_BADNET);
|
||||
|
||||
daemon->dhcp6fd = fd;
|
||||
}
|
||||
|
||||
void dhcp6_packet(time_t now)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
struct dhcp_relay *relay;
|
||||
struct iface_param parm;
|
||||
struct cmsghdr *cmptr;
|
||||
struct msghdr msg;
|
||||
uint32_t if_index = 0;
|
||||
union {
|
||||
struct cmsghdr align; /* this ensures alignment */
|
||||
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
||||
} control_u;
|
||||
struct sockaddr_in6 from;
|
||||
ssize_t sz;
|
||||
struct ifreq ifr;
|
||||
struct iname *tmp;
|
||||
unsigned short port;
|
||||
struct in6_addr dst_addr;
|
||||
struct in6_addr all_servers;
|
||||
|
||||
memset(&dst_addr, 0, sizeof(dst_addr));
|
||||
|
||||
msg.msg_control = control_u.control6;
|
||||
msg.msg_controllen = sizeof(control_u);
|
||||
msg.msg_flags = 0;
|
||||
msg.msg_name = &from;
|
||||
msg.msg_namelen = sizeof(from);
|
||||
msg.msg_iov = &daemon->dhcp_packet;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
if ((sz = recv_dhcp_packet(daemon->dhcp6fd, &msg)) == -1)
|
||||
return;
|
||||
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in6_pktinfo *p;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
|
||||
if_index = p.p->ipi6_ifindex;
|
||||
dst_addr = p.p->ipi6_addr;
|
||||
}
|
||||
|
||||
if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* This works around a possible Linux kernel bug when using interfaces
|
||||
enslaved to a VRF. The scope_id in the source address gets set
|
||||
to the index of the VRF interface, not the slave. Fortunately,
|
||||
the interface index returned by packetinfo is correct so we use
|
||||
that instead. Log this once, so if it triggers in other circumstances
|
||||
we've not anticipated and breaks things, we get some clues. */
|
||||
if (from.sin6_scope_id != if_index)
|
||||
{
|
||||
static int logged = 0;
|
||||
|
||||
if (!logged)
|
||||
{
|
||||
my_syslog(MS_DHCP | LOG_WARNING,
|
||||
_("Working around kernel bug: faulty source address scope for VRF slave %s"),
|
||||
ifr.ifr_name);
|
||||
logged = 1;
|
||||
}
|
||||
|
||||
from.sin6_scope_id = if_index;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet_udp(DUMP_DHCPV6, (void *)daemon->dhcp_packet.iov_base, sz,
|
||||
(union mysockaddr *)&from, NULL, daemon->dhcp6fd);
|
||||
#endif
|
||||
|
||||
if (relay_reply6(&from, sz, ifr.ifr_name))
|
||||
{
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet_udp(DUMP_DHCPV6, (void *)daemon->outpacket.iov_base, save_counter(-1), NULL,
|
||||
(union mysockaddr *)&from, daemon->dhcp6fd);
|
||||
#endif
|
||||
|
||||
while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base,
|
||||
save_counter(-1), 0, (struct sockaddr *)&from,
|
||||
sizeof(from))));
|
||||
}
|
||||
else
|
||||
{
|
||||
struct dhcp_bridge *bridge, *alias;
|
||||
int multicast_dest = 0;
|
||||
|
||||
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 && (tmp->flags & INAME_6) &&
|
||||
wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
parm.current = NULL;
|
||||
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->matchcount = 0;
|
||||
|
||||
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &all_servers);
|
||||
if (IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers))
|
||||
multicast_dest = 1;
|
||||
|
||||
inet_pton(AF_INET6, ALL_SERVERS, &all_servers);
|
||||
if (IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers))
|
||||
multicast_dest = 1;
|
||||
else
|
||||
{
|
||||
/* Ignore requests sent to the ALL_SERVERS multicast address for relay when
|
||||
we're listening there for DHCPv6 server reasons. */
|
||||
if (relay_upstream6(if_index, (size_t)sz, &from.sin6_addr, from.sin6_scope_id, now))
|
||||
return;
|
||||
}
|
||||
|
||||
if (!iface_enumerate(AF_INET6, &parm, (callback_t){.af_inet6=complete_context6}))
|
||||
return;
|
||||
|
||||
/* Check for a relay again after iface_enumerate/complete_context has had
|
||||
chance to fill in relay->iface_index fields. This handles first time through
|
||||
and any changes in interface config. */
|
||||
if (!IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers) &&
|
||||
relay_upstream6(if_index, (size_t)sz, &from.sin6_addr, from.sin6_scope_id, now))
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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, multicast_dest, if_index, ifr.ifr_name, &parm.fallback,
|
||||
&parm.ll_addr, &parm.ula_addr, sz, &from.sin6_addr, now);
|
||||
|
||||
/* 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
|
||||
server port to a relay. */
|
||||
if (port != 0)
|
||||
{
|
||||
from.sin6_port = htons(port);
|
||||
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet_udp(DUMP_DHCPV6, (void *)daemon->outpacket.iov_base, save_counter(-1),
|
||||
NULL, (union mysockaddr *)&from, daemon->dhcp6fd);
|
||||
#endif
|
||||
|
||||
while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base,
|
||||
save_counter(-1), 0, (struct sockaddr *)&from, sizeof(from))));
|
||||
}
|
||||
|
||||
/* These need to be called _after_ we send DHCPv6 packet, since lease_update_file()
|
||||
may trigger sending an RA packet, which overwrites our buffer. */
|
||||
lease_update_file(now);
|
||||
lease_update_dns(0);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
while(retry_send(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 flags, unsigned int preferred,
|
||||
unsigned int valid, void *vparam)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
struct shared_network *share;
|
||||
struct dhcp_relay *relay;
|
||||
struct iface_param *param = vparam;
|
||||
struct iname *tmp;
|
||||
int match = !daemon->if_addrs;
|
||||
|
||||
(void)scope; /* warning */
|
||||
|
||||
if (if_index != param->ind)
|
||||
return 1;
|
||||
|
||||
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))
|
||||
return 1;
|
||||
|
||||
/* 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))
|
||||
match = param->addr_match = 1;
|
||||
|
||||
/* Determine a globally address on the arrival interface, even
|
||||
if we have no matching dhcp-context, because we're only
|
||||
allocating on remote subnets via relays. This
|
||||
is used as a default for the DNS server option. */
|
||||
param->fallback = *local;
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_DHCP) &&
|
||||
!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
|
||||
prefix <= context->prefix &&
|
||||
context->current == context)
|
||||
{
|
||||
if (is_same_net6(local, &context->start6, context->prefix) &&
|
||||
is_same_net6(local, &context->end6, context->prefix))
|
||||
{
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (share = daemon->shared_networks; share; share = share->next)
|
||||
{
|
||||
/* IPv4 shared_address - ignore */
|
||||
if (share->shared_addr.s_addr != 0)
|
||||
continue;
|
||||
|
||||
if (share->if_index != 0)
|
||||
{
|
||||
if (share->if_index != if_index)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!IN6_ARE_ADDR_EQUAL(&share->match_addr6, local))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_same_net6(&share->shared_addr6, &context->start6, context->prefix) &&
|
||||
is_same_net6(&share->shared_addr6, &context->end6, context->prefix))
|
||||
{
|
||||
context->current = param->current;
|
||||
param->current = context;
|
||||
context->local6 = *local;
|
||||
context->preferred = context->flags & CONTEXT_DEPRECATE ? 0 :0xffffffff;
|
||||
context->valid = 0xffffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (match)
|
||||
for (relay = daemon->relay6; relay; relay = relay->next)
|
||||
if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr6))
|
||||
{
|
||||
relay->iface_index = if_index;
|
||||
|
||||
/* More than one interface with the relay address breaks things. */
|
||||
if (relay->matchcount++ == 1 && !relay->warned)
|
||||
{
|
||||
relay->warned = 1;
|
||||
inet_ntop(AF_INET6, &local, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP relay address %s appears on more than one interface"), daemon->addrbuff);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, struct in6_addr *addr)
|
||||
{
|
||||
struct dhcp_config *config;
|
||||
|
||||
for (config = configs; config; config = config->next)
|
||||
if (config->flags & CONFIG_ADDR6)
|
||||
{
|
||||
struct addrlist *addr_list;
|
||||
|
||||
for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
|
||||
if ((!net || is_same_net6(&addr_list->addr.addr6, net, prefix) || ((addr_list->flags & ADDRLIST_WILDCARD) && prefix == 64)) &&
|
||||
is_same_net6(&addr_list->addr.addr6, addr, (addr_list->flags & ADDRLIST_PREFIX) ? addr_list->prefixlen : 128))
|
||||
return config;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len, int temp_addr,
|
||||
unsigned 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.
|
||||
Try to return from contexts which match netids first.
|
||||
|
||||
Note that we assume the address prefix lengths are 64 or greater, so we can
|
||||
get by with 64 bit arithmetic.
|
||||
*/
|
||||
|
||||
u64 start, addr;
|
||||
struct dhcp_context *c, *d;
|
||||
int i, pass;
|
||||
u64 j;
|
||||
|
||||
/* hash hwaddr: use the SDBM hashing algorithm. This works
|
||||
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 <= plain_range ? 1 : 0; pass++)
|
||||
for (c = context; c; c = c->current)
|
||||
if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS | CONTEXT_USED))
|
||||
continue;
|
||||
else if (!match_netid(c->filter, netids, pass))
|
||||
continue;
|
||||
else
|
||||
{
|
||||
if (!temp_addr && option_bool(OPT_CONSEC_ADDR))
|
||||
{
|
||||
/* seed is largest extant lease addr in this context,
|
||||
skip addresses equal to the number of addresses rejected
|
||||
by clients. This should avoid the same client being offered the same
|
||||
address after it has rjected it. */
|
||||
start = lease_find_max_addr6(c) + 1 + serial + c->addr_epoch;
|
||||
if (c->addr_epoch)
|
||||
c->addr_epoch--;
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
|
||||
do {
|
||||
/* eliminate addresses in use by the server. */
|
||||
for (d = context; d; d = d->current)
|
||||
if (addr == addr6part(&d->local6))
|
||||
break;
|
||||
|
||||
*ans = c->start6;
|
||||
setaddr6part (ans, addr);
|
||||
|
||||
if (!d &&
|
||||
!lease6_find_by_addr(&c->start6, c->prefix, addr) &&
|
||||
!config_find_by_address6(daemon->dhcp_conf, &c->start6, c->prefix, ans))
|
||||
return c;
|
||||
|
||||
addr++;
|
||||
|
||||
if (addr == addr6part(&c->end6) + 1)
|
||||
addr = addr6part(&c->start6);
|
||||
|
||||
} while (addr != start);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* can dynamically allocate addr */
|
||||
struct dhcp_context *address6_available(struct dhcp_context *context,
|
||||
struct in6_addr *taddr,
|
||||
struct dhcp_netid *netids,
|
||||
int plain_range)
|
||||
{
|
||||
u64 start, end, addr = addr6part(taddr);
|
||||
struct dhcp_context *tmp;
|
||||
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
{
|
||||
start = addr6part(&tmp->start6);
|
||||
end = addr6part(&tmp->end6);
|
||||
|
||||
if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_RA_STATELESS)) &&
|
||||
is_same_net6(&tmp->start6, taddr, tmp->prefix) &&
|
||||
is_same_net6(&tmp->end6, taddr, tmp->prefix) &&
|
||||
addr >= start &&
|
||||
addr <= end &&
|
||||
match_netid(tmp->filter, netids, plain_range))
|
||||
return tmp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* address OK if configured */
|
||||
struct dhcp_context *address6_valid(struct dhcp_context *context,
|
||||
struct in6_addr *taddr,
|
||||
struct dhcp_netid *netids,
|
||||
int plain_range)
|
||||
{
|
||||
struct dhcp_context *tmp;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void make_duid(time_t now)
|
||||
{
|
||||
(void)now;
|
||||
|
||||
if (daemon->duid_config)
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
daemon->duid = p = safe_malloc(daemon->duid_config_len + 6);
|
||||
daemon->duid_len = daemon->duid_config_len + 6;
|
||||
PUTSHORT(2, p); /* DUID_EN */
|
||||
PUTLONG(daemon->duid_enterprise, p);
|
||||
memcpy(p, daemon->duid_config, daemon->duid_config_len);
|
||||
}
|
||||
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 */
|
||||
if (!option_bool(OPT_LEASE_RO) || daemon->lease_change_command)
|
||||
newnow = now - 946684800;
|
||||
#endif
|
||||
|
||||
iface_enumerate(AF_LOCAL, &newnow, (callback_t){.af_local=make_duid1});
|
||||
|
||||
if(!daemon->duid)
|
||||
die("Cannot create DHCPv6 server DUID: %s", NULL, EC_MISC);
|
||||
}
|
||||
}
|
||||
|
||||
static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm)
|
||||
{
|
||||
/* create DUID as specified in RFC3315. We use the MAC of the
|
||||
first interface we find that isn't loopback or P-to-P and
|
||||
has address-type < 256. Address types above 256 are things like
|
||||
tunnels which don't have usable MAC addresses. */
|
||||
|
||||
unsigned char *p;
|
||||
(void)index;
|
||||
(void)parm;
|
||||
time_t newnow = *((time_t *)parm);
|
||||
|
||||
if (type >= 256)
|
||||
return 1;
|
||||
|
||||
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,
|
||||
unsigned int preferred, unsigned int valid, void *vparam)
|
||||
{
|
||||
char ifrn_name[IFNAMSIZ];
|
||||
struct in6_addr start6, end6;
|
||||
struct dhcp_context *template, *context;
|
||||
struct iname *tmp;
|
||||
|
||||
(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;
|
||||
|
||||
/* Ignore interfaces where we're not doing RA/DHCP6 */
|
||||
if (!indextoname(daemon->icmp6fd, if_index, ifrn_name) ||
|
||||
!iface_check(AF_LOCAL, NULL, ifrn_name, NULL))
|
||||
return 1;
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifrn_name))
|
||||
return 1;
|
||||
|
||||
for (template = daemon->dhcp6; template; template = template->next)
|
||||
if (!(template->flags & (CONTEXT_TEMPLATE | CONTEXT_CONSTRUCTED)))
|
||||
{
|
||||
/* 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))
|
||||
{
|
||||
/* First time found, do fast RA. */
|
||||
if (template->if_index == 0)
|
||||
{
|
||||
ra_start_unsolicited(param->now, template);
|
||||
param->newone = 1;
|
||||
}
|
||||
|
||||
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_TEMPLATE) &&
|
||||
IN6_ARE_ADDR_EQUAL(&start6, &context->start6) &&
|
||||
IN6_ARE_ADDR_EQUAL(&end6, &context->end6))
|
||||
{
|
||||
/* If there's an absolute address context covering this address
|
||||
then don't construct one as well. */
|
||||
if (!(context->flags & CONTEXT_CONSTRUCTED))
|
||||
break;
|
||||
|
||||
if (context->if_index == if_index)
|
||||
{
|
||||
int cflags = context->flags;
|
||||
context->flags &= ~(CONTEXT_GC | CONTEXT_OLD);
|
||||
if (cflags & CONTEXT_OLD)
|
||||
{
|
||||
/* address went, now it's back, and on the same interface */
|
||||
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, (callback_t){.af_inet6=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 its 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 /* HAVE_DHCP6 */
|
||||
193
src/dns-protocol.h
Normal file
193
src/dns-protocol.h
Normal file
@@ -0,0 +1,193 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2025 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 NAMESERVER_PORT 53
|
||||
#define TFTP_PORT 69
|
||||
#define MIN_PORT 1024 /* first non-reserved port */
|
||||
#define MAX_PORT 65535u
|
||||
|
||||
#define IN6ADDRSZ 16
|
||||
#define INADDRSZ 4
|
||||
|
||||
#define PACKETSZ 512 /* maximum packet size */
|
||||
#define MAXDNAME 1025 /* maximum presentation domain name */
|
||||
#define RRFIXEDSZ 10 /* #/bytes of fixed data in r record */
|
||||
#define MAXLABEL 63 /* maximum length of domain label */
|
||||
|
||||
#define NOERROR 0 /* no error */
|
||||
#define FORMERR 1 /* format error */
|
||||
#define SERVFAIL 2 /* server failure */
|
||||
#define NXDOMAIN 3 /* non existent domain */
|
||||
#define NOTIMP 4 /* not implemented */
|
||||
#define REFUSED 5 /* query refused */
|
||||
|
||||
#define QUERY 0 /* opcode */
|
||||
|
||||
#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_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 T_CAA 257
|
||||
|
||||
#define EDNS0_OPTION_MAC 65001 /* dyndns.org temporary assignment */
|
||||
#define EDNS0_OPTION_CLIENT_SUBNET 8 /* IANA */
|
||||
#define EDNS0_OPTION_EDE 15 /* IANA - RFC 8914 */
|
||||
#define EDNS0_OPTION_NOMDEVICEID 65073 /* Nominum temporary assignment */
|
||||
#define EDNS0_OPTION_NOMCPEID 65074 /* Nominum temporary assignment */
|
||||
#define EDNS0_OPTION_UMBRELLA 20292 /* Cisco Umbrella temporary assignment */
|
||||
|
||||
/* RFC-8914 extended errors, negative values are our definitions */
|
||||
#define EDE_UNSET -1 /* No extended DNS error available */
|
||||
#define EDE_OTHER 0 /* Other */
|
||||
#define EDE_USUPDNSKEY 1 /* Unsupported DNSKEY algo */
|
||||
#define EDE_USUPDS 2 /* Unsupported DS Digest */
|
||||
#define EDE_STALE 3 /* Stale answer */
|
||||
#define EDE_FORGED 4 /* Forged answer */
|
||||
#define EDE_DNSSEC_IND 5 /* DNSSEC Indeterminate */
|
||||
#define EDE_DNSSEC_BOGUS 6 /* DNSSEC Bogus */
|
||||
#define EDE_SIG_EXP 7 /* Signature Expired */
|
||||
#define EDE_SIG_NYV 8 /* Signature Not Yet Valid */
|
||||
#define EDE_NO_DNSKEY 9 /* DNSKEY missing */
|
||||
#define EDE_NO_RRSIG 10 /* RRSIGs missing */
|
||||
#define EDE_NO_ZONEKEY 11 /* No Zone Key Bit Set */
|
||||
#define EDE_NO_NSEC 12 /* NSEC Missing */
|
||||
#define EDE_CACHED_ERR 13 /* Cached Error */
|
||||
#define EDE_NOT_READY 14 /* Not Ready */
|
||||
#define EDE_BLOCKED 15 /* Blocked */
|
||||
#define EDE_CENSORED 16 /* Censored */
|
||||
#define EDE_FILTERED 17 /* Filtered */
|
||||
#define EDE_PROHIBITED 18 /* Prohibited */
|
||||
#define EDE_STALE_NXD 19 /* Stale NXDOMAIN */
|
||||
#define EDE_NOT_AUTH 20 /* Not Authoritative */
|
||||
#define EDE_NOT_SUP 21 /* Not Supported */
|
||||
#define EDE_NO_AUTH 22 /* No Reachable Authority */
|
||||
#define EDE_NETERR 23 /* Network error */
|
||||
#define EDE_INVALID_DATA 24 /* Invalid Data */
|
||||
#define EDE_SIG_E_B_V 25 /* Signature Expired before Valid */
|
||||
#define EDE_TOO_EARLY 26 /* To Early */
|
||||
#define EDE_UNS_NS3_ITER 27 /* Unsupported NSEC3 Iterations Value */
|
||||
#define EDE_UNABLE_POLICY 28 /* Unable to conform to policy */
|
||||
#define EDE_SYNTHESIZED 29 /* Synthesized */
|
||||
|
||||
|
||||
struct dns_header {
|
||||
u16 id;
|
||||
u8 hb3,hb4;
|
||||
u16 qdcount,ancount,nscount,arcount;
|
||||
};
|
||||
|
||||
#define HB3_QR 0x80 /* Query */
|
||||
#define HB3_OPCODE 0x78
|
||||
#define HB3_AA 0x04 /* Authoritative Answer */
|
||||
#define HB3_TC 0x02 /* TrunCated */
|
||||
#define HB3_RD 0x01 /* Recursion Desired */
|
||||
|
||||
#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
|
||||
|
||||
#define GETSHORT(s, cp) do { \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
(s) = ((u16)t_cp[0] << 8) \
|
||||
| ((u16)t_cp[1]) \
|
||||
; \
|
||||
(cp) += 2; \
|
||||
} while(0)
|
||||
|
||||
#define GETLONG(l, cp) do { \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
(l) = ((u32)t_cp[0] << 24) \
|
||||
| ((u32)t_cp[1] << 16) \
|
||||
| ((u32)t_cp[2] << 8) \
|
||||
| ((u32)t_cp[3]) \
|
||||
; \
|
||||
(cp) += 4; \
|
||||
} while (0)
|
||||
|
||||
#define PUTSHORT(s, cp) do { \
|
||||
u16 t_s = (u16)(s); \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
*t_cp++ = t_s >> 8; \
|
||||
*t_cp = t_s; \
|
||||
(cp) += 2; \
|
||||
} while(0)
|
||||
|
||||
#define PUTLONG(l, cp) do { \
|
||||
u32 t_l = (u32)(l); \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
*t_cp++ = t_l >> 24; \
|
||||
*t_cp++ = t_l >> 16; \
|
||||
*t_cp++ = t_l >> 8; \
|
||||
*t_cp = t_l; \
|
||||
(cp) += 4; \
|
||||
} while (0)
|
||||
|
||||
#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
|
||||
@@ -1,111 +0,0 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2011 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 IN6ADDRSZ 16
|
||||
#define INADDRSZ 4
|
||||
|
||||
#define PACKETSZ 512 /* maximum packet size */
|
||||
#define MAXDNAME 1025 /* maximum presentation domain name */
|
||||
#define RRFIXEDSZ 10 /* #/bytes of fixed data in r record */
|
||||
#define MAXLABEL 63 /* maximum length of domain label */
|
||||
|
||||
#define NOERROR 0 /* no error */
|
||||
#define FORMERR 1 /* format error */
|
||||
#define SERVFAIL 2 /* server failure */
|
||||
#define NXDOMAIN 3 /* non existent domain */
|
||||
#define NOTIMP 4 /* not implemented */
|
||||
#define REFUSED 5 /* query refused */
|
||||
|
||||
#define QUERY 0 /* opcode */
|
||||
|
||||
#define C_IN 1 /* the arpa internet */
|
||||
#define C_CHAOS 3 /* for chaos net (MIT) */
|
||||
#define C_ANY 255 /* wildcard match */
|
||||
|
||||
#define T_A 1
|
||||
#define T_NS 2
|
||||
#define T_CNAME 5
|
||||
#define T_SOA 6
|
||||
#define T_PTR 12
|
||||
#define T_MX 15
|
||||
#define T_TXT 16
|
||||
#define T_SIG 24
|
||||
#define T_AAAA 28
|
||||
#define T_SRV 33
|
||||
#define T_NAPTR 35
|
||||
#define T_OPT 41
|
||||
#define T_TKEY 249
|
||||
#define T_TSIG 250
|
||||
#define T_MAILB 253
|
||||
#define T_ANY 255
|
||||
|
||||
struct dns_header {
|
||||
u16 id;
|
||||
u8 hb3,hb4;
|
||||
u16 qdcount,ancount,nscount,arcount;
|
||||
} ;
|
||||
|
||||
#define HB3_QR 0x80
|
||||
#define HB3_OPCODE 0x78
|
||||
#define HB3_AA 0x04
|
||||
#define HB3_TC 0x02
|
||||
#define HB3_RD 0x01
|
||||
|
||||
#define HB4_RA 0x80
|
||||
#define HB4_AD 0x20
|
||||
#define HB4_CD 0x10
|
||||
#define HB4_RCODE 0x0f
|
||||
|
||||
#define OPCODE(x) (((x)->hb3 & HB3_OPCODE) >> 3)
|
||||
#define RCODE(x) ((x)->hb4 & HB4_RCODE)
|
||||
#define SET_RCODE(x, code) (x)->hb4 = ((x)->hb4 & ~HB4_RCODE) | code
|
||||
|
||||
#define GETSHORT(s, cp) { \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
(s) = ((u16)t_cp[0] << 8) \
|
||||
| ((u16)t_cp[1]) \
|
||||
; \
|
||||
(cp) += 2; \
|
||||
}
|
||||
|
||||
#define GETLONG(l, cp) { \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
(l) = ((u32)t_cp[0] << 24) \
|
||||
| ((u32)t_cp[1] << 16) \
|
||||
| ((u32)t_cp[2] << 8) \
|
||||
| ((u32)t_cp[3]) \
|
||||
; \
|
||||
(cp) += 4; \
|
||||
}
|
||||
|
||||
#define PUTSHORT(s, cp) { \
|
||||
u16 t_s = (u16)(s); \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
*t_cp++ = t_s >> 8; \
|
||||
*t_cp = t_s; \
|
||||
(cp) += 2; \
|
||||
}
|
||||
|
||||
#define PUTLONG(l, cp) { \
|
||||
u32 t_l = (u32)(l); \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
*t_cp++ = t_l >> 24; \
|
||||
*t_cp++ = t_l >> 16; \
|
||||
*t_cp++ = t_l >> 8; \
|
||||
*t_cp = t_l; \
|
||||
(cp) += 4; \
|
||||
}
|
||||
|
||||
2195
src/dnsmasq.c
2195
src/dnsmasq.c
File diff suppressed because it is too large
Load Diff
1473
src/dnsmasq.h
1473
src/dnsmasq.h
File diff suppressed because it is too large
Load Diff
2408
src/dnssec.c
Normal file
2408
src/dnssec.c
Normal file
File diff suppressed because it is too large
Load Diff
778
src/domain-match.c
Normal file
778
src/domain-match.c
Normal file
@@ -0,0 +1,778 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2025 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 int order(char *qdomain, size_t qlen, struct server *serv);
|
||||
static int order_qsort(const void *a, const void *b);
|
||||
static int order_servers(struct server *s, struct server *s2);
|
||||
|
||||
/* If the server is USE_RESOLV or LITERAL_ADDRESS, it lives on the local_domains chain. */
|
||||
#define SERV_IS_LOCAL (SERV_USE_RESOLV | SERV_LITERAL_ADDRESS)
|
||||
|
||||
void build_server_array(void)
|
||||
{
|
||||
struct server *serv;
|
||||
int count = 0;
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
#ifdef HAVE_LOOP
|
||||
if (!(serv->flags & SERV_LOOP))
|
||||
#endif
|
||||
{
|
||||
count++;
|
||||
if (serv->flags & SERV_WILDCARD)
|
||||
daemon->server_has_wildcard = 1;
|
||||
}
|
||||
|
||||
for (serv = daemon->local_domains; serv; serv = serv->next)
|
||||
{
|
||||
count++;
|
||||
if (serv->flags & SERV_WILDCARD)
|
||||
daemon->server_has_wildcard = 1;
|
||||
}
|
||||
|
||||
daemon->serverarraysz = count;
|
||||
|
||||
if (count > daemon->serverarrayhwm)
|
||||
{
|
||||
struct server **new;
|
||||
|
||||
count += 10; /* A few extra without re-allocating. */
|
||||
|
||||
if ((new = whine_malloc(count * sizeof(struct server *))))
|
||||
{
|
||||
if (daemon->serverarray)
|
||||
free(daemon->serverarray);
|
||||
|
||||
daemon->serverarray = new;
|
||||
daemon->serverarrayhwm = count;
|
||||
}
|
||||
}
|
||||
|
||||
count = 0;
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
#ifdef HAVE_LOOP
|
||||
if (!(serv->flags & SERV_LOOP))
|
||||
#endif
|
||||
{
|
||||
daemon->serverarray[count] = serv;
|
||||
serv->serial = count;
|
||||
serv->last_server = -1;
|
||||
count++;
|
||||
}
|
||||
|
||||
for (serv = daemon->local_domains; serv; serv = serv->next, count++)
|
||||
daemon->serverarray[count] = serv;
|
||||
|
||||
qsort(daemon->serverarray, daemon->serverarraysz, sizeof(struct server *), order_qsort);
|
||||
|
||||
/* servers need the location in the array to find all the whole
|
||||
set of equivalent servers from a pointer to a single one. */
|
||||
for (count = 0; count < daemon->serverarraysz; count++)
|
||||
if (!(daemon->serverarray[count]->flags & SERV_IS_LOCAL))
|
||||
daemon->serverarray[count]->arrayposn = count;
|
||||
}
|
||||
|
||||
/* we're looking for the server whose domain is the longest exact match
|
||||
to the RH end of qdomain, or a local address if the flags match.
|
||||
Add '.' to the LHS of the query string so
|
||||
server=/.example.com/ works.
|
||||
|
||||
A flag of F_SERVER returns an upstream server only.
|
||||
A flag of F_DNSSECOK disables NODOTS servers from consideration.
|
||||
A flag of F_DS returns parent domain server.
|
||||
A flag of F_DOMAINSRV returns a domain-specific server only.
|
||||
A flag of F_CONFIG returns anything that generates a local
|
||||
reply of IPv4 or IPV6.
|
||||
return 0 if nothing found, 1 otherwise.
|
||||
*/
|
||||
int lookup_domain(char *domain, int flags, int *lowout, int *highout)
|
||||
{
|
||||
int rc, crop_query, nodots;
|
||||
ssize_t qlen;
|
||||
int try, high, low = 0;
|
||||
int nlow = 0, nhigh = 0;
|
||||
char *cp, *qdomain;
|
||||
|
||||
/* may be no configured servers. */
|
||||
if (daemon->serverarraysz == 0)
|
||||
return 0;
|
||||
|
||||
/* DS records should come from the parent domain. */
|
||||
if (flags & F_DS)
|
||||
{
|
||||
if ((cp = strchr(domain, '.')))
|
||||
domain = cp+1;
|
||||
else
|
||||
domain = "";
|
||||
}
|
||||
|
||||
qdomain = domain;
|
||||
|
||||
/* find query length and presence of '.' */
|
||||
for (cp = qdomain, nodots = 1, qlen = 0; *cp; qlen++, cp++)
|
||||
if (*cp == '.')
|
||||
nodots = 0;
|
||||
|
||||
/* Handle empty name, and searches for DNSSEC queries without
|
||||
diverting to NODOTS servers. */
|
||||
if (qlen == 0 || flags & F_DNSSECOK)
|
||||
nodots = 0;
|
||||
|
||||
/* Search shorter and shorter RHS substrings for a match */
|
||||
while (qlen >= 0)
|
||||
{
|
||||
/* Note that when we chop off a label, all the possible matches
|
||||
MUST be at a larger index than the nearest failing match with one more
|
||||
character, since the array is sorted longest to smallest. Hence
|
||||
we don't reset low to zero here, we can go further below and crop the
|
||||
search string to the size of the largest remaining server
|
||||
when this match fails. */
|
||||
high = daemon->serverarraysz;
|
||||
crop_query = 1;
|
||||
|
||||
/* binary search */
|
||||
while (1)
|
||||
{
|
||||
try = (low + high)/2;
|
||||
|
||||
if ((rc = order(qdomain, qlen, daemon->serverarray[try])) == 0)
|
||||
break;
|
||||
|
||||
if (rc < 0)
|
||||
{
|
||||
if (high == try)
|
||||
{
|
||||
/* qdomain is longer or same length as longest domain, and try == 0
|
||||
crop the query to the longest domain. */
|
||||
crop_query = qlen - daemon->serverarray[try]->domain_len;
|
||||
break;
|
||||
}
|
||||
high = try;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (low == try)
|
||||
{
|
||||
/* try now points to the last domain that sorts before the query, so
|
||||
we know that a substring of the query shorter than it is required to match, so
|
||||
find the largest domain that's shorter than try. Note that just going to
|
||||
try+1 is not optimal, consider searching bbb in (aaa,ccc,bb). try will point
|
||||
to aaa, since ccc sorts after bbb, but the first domain that has a chance to
|
||||
match is bb. So find the length of the first domain later than try which is
|
||||
is shorter than it.
|
||||
There's a nasty edge case when qdomain sorts before _any_ of the
|
||||
server domains, where try _doesn't point_ to the last domain that sorts
|
||||
before the query, since no such domain exists. In that case, the loop
|
||||
exits via the rc < 0 && high == try path above and this code is
|
||||
not executed. */
|
||||
ssize_t len, old = daemon->serverarray[try]->domain_len;
|
||||
while (++try != daemon->serverarraysz)
|
||||
{
|
||||
if (old != (len = daemon->serverarray[try]->domain_len))
|
||||
{
|
||||
crop_query = qlen - len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
low = try;
|
||||
}
|
||||
};
|
||||
|
||||
if (rc == 0)
|
||||
{
|
||||
int found = 1;
|
||||
|
||||
if (daemon->server_has_wildcard)
|
||||
{
|
||||
/* if we have example.com and *example.com we need to check against *example.com,
|
||||
but the binary search may have found either. Use the fact that example.com is sorted before *example.com
|
||||
We favour example.com in the case that both match (ie www.example.com) */
|
||||
while (try != 0 && order(qdomain, qlen, daemon->serverarray[try-1]) == 0)
|
||||
try--;
|
||||
|
||||
if (!(qdomain == domain || *qdomain == 0 || *(qdomain-1) == '.'))
|
||||
{
|
||||
while (try < daemon->serverarraysz-1 && order(qdomain, qlen, daemon->serverarray[try+1]) == 0)
|
||||
try++;
|
||||
|
||||
if (!(daemon->serverarray[try]->flags & SERV_WILDCARD))
|
||||
found = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (found && filter_servers(try, flags, &nlow, &nhigh))
|
||||
/* We have a match, but it may only be (say) an IPv6 address, and
|
||||
if the query wasn't for an AAAA record, it's no good, and we need
|
||||
to continue generalising */
|
||||
{
|
||||
/* We've matched a setting which says to use servers without a domain.
|
||||
Continue the search with empty query. We set the F_SERVER flag
|
||||
so that --address=/#/... doesn't match. */
|
||||
if (daemon->serverarray[nlow]->flags & SERV_USE_RESOLV)
|
||||
{
|
||||
crop_query = qlen;
|
||||
flags |= F_SERVER;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* crop_query must be at least one always. */
|
||||
if (crop_query == 0)
|
||||
crop_query = 1;
|
||||
|
||||
/* strip chars off the query based on the largest possible remaining match,
|
||||
then continue to the start of the next label unless we have a wildcard
|
||||
domain somewhere, in which case we have to go one at a time. */
|
||||
qlen -= crop_query;
|
||||
qdomain += crop_query;
|
||||
if (!daemon->server_has_wildcard)
|
||||
while (qlen > 0 && (*(qdomain-1) != '.'))
|
||||
qlen--, qdomain++;
|
||||
}
|
||||
|
||||
/* domain has no dots, and we have at least one server configured to handle such,
|
||||
These servers always sort to the very end of the array.
|
||||
A configured server eg server=/lan/ will take precdence. */
|
||||
if (nodots &&
|
||||
(daemon->serverarray[daemon->serverarraysz-1]->flags & SERV_FOR_NODOTS) &&
|
||||
(nlow == nhigh || daemon->serverarray[nlow]->domain_len == 0))
|
||||
{
|
||||
filter_servers(daemon->serverarraysz-1, flags, &nlow, &nhigh);
|
||||
qlen = 0;
|
||||
}
|
||||
|
||||
if (lowout)
|
||||
*lowout = nlow;
|
||||
|
||||
if (highout)
|
||||
*highout = nhigh;
|
||||
|
||||
/* qlen == -1 when we failed to match even an empty query, if there are no default servers. */
|
||||
if (nlow == nhigh || qlen == -1)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int server_samegroup(struct server *a, struct server *b)
|
||||
{
|
||||
return order_servers(a, b) == 0;
|
||||
}
|
||||
|
||||
int filter_servers(int seed, int flags, int *lowout, int *highout)
|
||||
{
|
||||
int nlow = seed, nhigh = seed;
|
||||
int i;
|
||||
|
||||
/* expand nlow and nhigh to cover all the records with the same domain
|
||||
nlow is the first, nhigh - 1 is the last. nlow=nhigh means no servers,
|
||||
which can happen below. */
|
||||
while (nlow > 0 && order_servers(daemon->serverarray[nlow-1], daemon->serverarray[nlow]) == 0)
|
||||
nlow--;
|
||||
|
||||
while (nhigh < daemon->serverarraysz-1 && order_servers(daemon->serverarray[nhigh], daemon->serverarray[nhigh+1]) == 0)
|
||||
nhigh++;
|
||||
|
||||
nhigh++;
|
||||
|
||||
#define SERV_LOCAL_ADDRESS (SERV_6ADDR | SERV_4ADDR | SERV_ALL_ZEROS)
|
||||
|
||||
if (flags & F_CONFIG)
|
||||
{
|
||||
/* We're just lookin for any matches that return an RR. */
|
||||
for (i = nlow; i < nhigh; i++)
|
||||
if (daemon->serverarray[i]->flags & SERV_LOCAL_ADDRESS)
|
||||
break;
|
||||
|
||||
/* failed, return failure. */
|
||||
if (i == nhigh)
|
||||
nhigh = nlow;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Now the matching server records are all between low and high.
|
||||
order_qsort() ensures that they are in the order
|
||||
IPv6 addr, IPv4 addr, return zero for both, no-data return,
|
||||
"use resolvconf" servers, domain-specific upstream servers.
|
||||
|
||||
See which of those match our query in that priority order and narrow (low, high) */
|
||||
|
||||
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_6ADDR); i++);
|
||||
|
||||
if (!(flags & F_SERVER) && i != nlow && (flags & F_IPV6))
|
||||
nhigh = i;
|
||||
else
|
||||
{
|
||||
nlow = i;
|
||||
|
||||
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_4ADDR); i++);
|
||||
|
||||
if (!(flags & F_SERVER) && i != nlow && (flags & F_IPV4))
|
||||
nhigh = i;
|
||||
else
|
||||
{
|
||||
nlow = i;
|
||||
|
||||
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_ALL_ZEROS); i++);
|
||||
|
||||
if (!(flags & F_SERVER) && i != nlow && (flags & (F_IPV4 | F_IPV6)))
|
||||
nhigh = i;
|
||||
else
|
||||
{
|
||||
nlow = i;
|
||||
|
||||
/* now look for a NXDOMAIN answer --local=/domain/ */
|
||||
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++);
|
||||
|
||||
if (!(flags & (F_DOMAINSRV | F_SERVER)) && i != nlow)
|
||||
nhigh = i;
|
||||
else
|
||||
{
|
||||
nlow = i;
|
||||
|
||||
/* return "use resolv.conf servers" if they exist */
|
||||
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_USE_RESOLV); i++);
|
||||
|
||||
if (i != nlow)
|
||||
nhigh = i;
|
||||
else
|
||||
{
|
||||
/* If we want a server for a particular domain, and this one isn't, return nothing. */
|
||||
if (nlow < daemon->serverarraysz && nlow != nhigh && (flags & F_DOMAINSRV) &&
|
||||
daemon->serverarray[nlow]->domain_len == 0 && !(daemon->serverarray[nlow]->flags & SERV_FOR_NODOTS))
|
||||
nlow = nhigh;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*lowout = nlow;
|
||||
*highout = nhigh;
|
||||
|
||||
return (nlow != nhigh);
|
||||
}
|
||||
|
||||
int is_local_answer(time_t now, int first, char *name)
|
||||
{
|
||||
int flags = 0;
|
||||
int rc = 0;
|
||||
|
||||
if ((flags = daemon->serverarray[first]->flags) & SERV_LITERAL_ADDRESS)
|
||||
{
|
||||
if (flags & SERV_4ADDR)
|
||||
rc = F_IPV4;
|
||||
else if (flags & SERV_6ADDR)
|
||||
rc = F_IPV6;
|
||||
else if (flags & SERV_ALL_ZEROS)
|
||||
rc = F_IPV4 | F_IPV6;
|
||||
else
|
||||
{
|
||||
/* argument first is the first struct server which matches the query type;
|
||||
now roll back to the server which is just the same domain, to check if that
|
||||
provides an answer of a different type. */
|
||||
|
||||
for (;first > 0 && order_servers(daemon->serverarray[first-1], daemon->serverarray[first]) == 0; first--);
|
||||
|
||||
if ((daemon->serverarray[first]->flags & SERV_LOCAL_ADDRESS) ||
|
||||
check_for_local_domain(name, now))
|
||||
rc = F_NOERR;
|
||||
else
|
||||
rc = F_NXDOMAIN;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header *header, char *name, char *limit, int first, int last, int ede)
|
||||
{
|
||||
int trunc = 0, anscount = 0;
|
||||
unsigned char *p;
|
||||
int start;
|
||||
union all_addr addr;
|
||||
|
||||
setup_reply(header, flags, ede);
|
||||
|
||||
gotname &= ~(F_QUERY | F_DS);
|
||||
|
||||
if (flags & (F_NXDOMAIN | F_NOERR))
|
||||
log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL, 0);
|
||||
|
||||
if (flags & F_RCODE)
|
||||
{
|
||||
union all_addr a;
|
||||
a.log.rcode = RCODE(header);
|
||||
a.log.ede = ede;
|
||||
log_query(F_UPSTREAM | F_RCODE, "opcode", &a, NULL, 0);
|
||||
}
|
||||
|
||||
if (!(p = skip_questions(header, size)))
|
||||
return 0;
|
||||
|
||||
if (flags & gotname & F_IPV4)
|
||||
for (start = first; start != last; start++)
|
||||
{
|
||||
struct serv_addr4 *srv = (struct serv_addr4 *)daemon->serverarray[start];
|
||||
|
||||
if (srv->flags & SERV_ALL_ZEROS)
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
else
|
||||
addr.addr4 = srv->addr;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_A, C_IN, "4", &addr))
|
||||
anscount++;
|
||||
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, name, (union all_addr *)&addr, NULL, 0);
|
||||
}
|
||||
|
||||
if (flags & gotname & F_IPV6)
|
||||
for (start = first; start != last; start++)
|
||||
{
|
||||
struct serv_addr6 *srv = (struct serv_addr6 *)daemon->serverarray[start];
|
||||
|
||||
if (srv->flags & SERV_ALL_ZEROS)
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
else
|
||||
addr.addr6 = srv->addr;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_AAAA, C_IN, "6", &addr))
|
||||
anscount++;
|
||||
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, name, (union all_addr *)&addr, NULL, 0);
|
||||
}
|
||||
|
||||
if (trunc)
|
||||
{
|
||||
header->hb3 |= HB3_TC;
|
||||
if (!(p = skip_questions(header, size)))
|
||||
return 0; /* bad packet */
|
||||
anscount = 0;
|
||||
}
|
||||
|
||||
header->ancount = htons(anscount);
|
||||
|
||||
return p - (unsigned char *)header;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
int dnssec_server(struct server *server, char *keyname, int is_ds, int *firstp, int *lastp)
|
||||
{
|
||||
int first, last, index;
|
||||
|
||||
/* Find server to send DNSSEC query to. This will normally be the
|
||||
same as for the original query, but may be another if
|
||||
servers for domains are involved. */
|
||||
if (!lookup_domain(keyname, F_SERVER | F_DNSSECOK | (is_ds ? F_DS : 0), &first, &last))
|
||||
return -1;
|
||||
|
||||
for (index = first; index != last; index++)
|
||||
if (daemon->serverarray[index] == server)
|
||||
break;
|
||||
|
||||
/* No match to server used for original query.
|
||||
Use newly looked up set. */
|
||||
if (index == last)
|
||||
index = daemon->serverarray[first]->last_server == -1 ?
|
||||
first : daemon->serverarray[first]->last_server;
|
||||
|
||||
if (firstp)
|
||||
*firstp = first;
|
||||
|
||||
if (lastp)
|
||||
*lastp = last;
|
||||
|
||||
return index;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* order by size, then by dictionary order */
|
||||
static int order(char *qdomain, size_t qlen, struct server *serv)
|
||||
{
|
||||
size_t dlen = 0;
|
||||
|
||||
/* servers for dotless names always sort last
|
||||
searched for name is never dotless. */
|
||||
if (serv->flags & SERV_FOR_NODOTS)
|
||||
return -1;
|
||||
|
||||
dlen = serv->domain_len;
|
||||
|
||||
if (qlen < dlen)
|
||||
return 1;
|
||||
|
||||
if (qlen > dlen)
|
||||
return -1;
|
||||
|
||||
return hostname_order(qdomain, serv->domain);
|
||||
}
|
||||
|
||||
static int order_servers(struct server *s1, struct server *s2)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* need full comparison of dotless servers in
|
||||
order_qsort() and filter_servers() */
|
||||
|
||||
if (s1->flags & SERV_FOR_NODOTS)
|
||||
return (s2->flags & SERV_FOR_NODOTS) ? 0 : 1;
|
||||
|
||||
if ((rc = order(s1->domain, s1->domain_len, s2)) != 0)
|
||||
return rc;
|
||||
|
||||
/* For identical domains, sort wildcard ones first */
|
||||
if (s1->flags & SERV_WILDCARD)
|
||||
return (s2->flags & SERV_WILDCARD) ? 0 : 1;
|
||||
|
||||
return (s2->flags & SERV_WILDCARD) ? -1 : 0;
|
||||
}
|
||||
|
||||
static int order_qsort(const void *a, const void *b)
|
||||
{
|
||||
int rc;
|
||||
|
||||
struct server *s1 = *((struct server **)a);
|
||||
struct server *s2 = *((struct server **)b);
|
||||
|
||||
rc = order_servers(s1, s2);
|
||||
|
||||
/* Sort all literal NODATA and local IPV4 or IPV6 responses together,
|
||||
in a very specific order IPv6 literal, IPv4 literal, all-zero literal,
|
||||
NXDOMAIN literal. We also include SERV_USE_RESOLV in this, so that
|
||||
use-standard servers sort before ordinary servers. (SERV_USR_RESOLV set
|
||||
implies that none of SERV_LITERAL_ADDRESS,SERV_4ADDR,SERV_6ADDR,SERV_ALL_ZEROS
|
||||
are set) */
|
||||
if (rc == 0)
|
||||
rc = ((s2->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_ALL_ZEROS | SERV_USE_RESOLV))) -
|
||||
((s1->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_ALL_ZEROS | SERV_USE_RESOLV)));
|
||||
|
||||
/* Finally, order by appearance in /etc/resolv.conf etc, for --strict-order */
|
||||
if (rc == 0)
|
||||
if (!(s1->flags & SERV_IS_LOCAL) && !(s2->flags & SERV_IS_LOCAL))
|
||||
rc = s1->serial - s2->serial;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* When loading large numbers of server=.... lines during startup,
|
||||
there's no possibility that there will be server records that can be reused, but
|
||||
searching a long list for each server added grows as O(n^2) and slows things down.
|
||||
This flag is set only if is known there may be free server records that can be reused.
|
||||
There's a call to mark_servers(0) in read_opts() to reset the flag before
|
||||
main config read. */
|
||||
|
||||
static int maybe_free_servers = 0;
|
||||
|
||||
/* Must be called before add_update_server() to set daemon->servers_tail */
|
||||
void mark_servers(int flag)
|
||||
{
|
||||
struct server *serv, *next, **up;
|
||||
|
||||
maybe_free_servers = !!flag;
|
||||
|
||||
daemon->servers_tail = NULL;
|
||||
|
||||
/* mark everything with argument flag */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
{
|
||||
if (serv->flags & flag)
|
||||
serv->flags |= SERV_MARK;
|
||||
else
|
||||
serv->flags &= ~SERV_MARK;
|
||||
|
||||
daemon->servers_tail = serv;
|
||||
}
|
||||
|
||||
/* --address etc is different: since they are expected to be
|
||||
1) numerous and 2) not reloaded often. We just delete
|
||||
and recreate. */
|
||||
if (flag)
|
||||
for (serv = daemon->local_domains, up = &daemon->local_domains; serv; serv = next)
|
||||
{
|
||||
next = serv->next;
|
||||
|
||||
if (serv->flags & flag)
|
||||
{
|
||||
*up = next;
|
||||
free(serv->domain);
|
||||
free(serv);
|
||||
}
|
||||
else
|
||||
up = &serv->next;
|
||||
}
|
||||
}
|
||||
|
||||
void cleanup_servers(void)
|
||||
{
|
||||
struct server *serv, *tmp, **up;
|
||||
|
||||
/* unlink and free anything still marked. */
|
||||
for (serv = daemon->servers, up = &daemon->servers, daemon->servers_tail = NULL; serv; serv = tmp)
|
||||
{
|
||||
tmp = serv->next;
|
||||
if (serv->flags & SERV_MARK)
|
||||
{
|
||||
server_gone(serv);
|
||||
*up = serv->next;
|
||||
free(serv->domain);
|
||||
free(serv);
|
||||
}
|
||||
else
|
||||
{
|
||||
up = &serv->next;
|
||||
daemon->servers_tail = serv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int add_update_server(int flags,
|
||||
union mysockaddr *addr,
|
||||
union mysockaddr *source_addr,
|
||||
const char *interface,
|
||||
const char *domain,
|
||||
union all_addr *local_addr)
|
||||
{
|
||||
struct server *serv = NULL;
|
||||
char *alloc_domain;
|
||||
|
||||
if (!domain)
|
||||
domain = "";
|
||||
|
||||
/* .domain == domain, for historical reasons. */
|
||||
if (*domain == '.')
|
||||
while (*domain == '.') domain++;
|
||||
else if (*domain == '*')
|
||||
{
|
||||
domain++;
|
||||
if (*domain != 0)
|
||||
flags |= SERV_WILDCARD;
|
||||
}
|
||||
|
||||
if (*domain == 0)
|
||||
alloc_domain = whine_malloc(1);
|
||||
else
|
||||
alloc_domain = canonicalise((char *)domain, NULL);
|
||||
|
||||
if (!alloc_domain)
|
||||
return 0;
|
||||
|
||||
if (flags & SERV_IS_LOCAL)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
if (flags & SERV_6ADDR)
|
||||
size = sizeof(struct serv_addr6);
|
||||
else if (flags & SERV_4ADDR)
|
||||
size = sizeof(struct serv_addr4);
|
||||
else
|
||||
size = sizeof(struct serv_local);
|
||||
|
||||
if (!(serv = whine_malloc(size)))
|
||||
{
|
||||
free(alloc_domain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
serv->next = daemon->local_domains;
|
||||
daemon->local_domains = serv;
|
||||
|
||||
if (flags & SERV_4ADDR)
|
||||
((struct serv_addr4*)serv)->addr = local_addr->addr4;
|
||||
|
||||
if (flags & SERV_6ADDR)
|
||||
((struct serv_addr6*)serv)->addr = local_addr->addr6;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Upstream servers. See if there is a suitable candidate, if so unmark
|
||||
and move to the end of the list, for order. The entry found may already
|
||||
be at the end. */
|
||||
struct server **up, *tmp;
|
||||
|
||||
serv = NULL;
|
||||
|
||||
if (maybe_free_servers)
|
||||
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
|
||||
{
|
||||
tmp = serv->next;
|
||||
if ((serv->flags & SERV_MARK) &&
|
||||
hostname_isequal(alloc_domain, serv->domain))
|
||||
{
|
||||
/* Need to move down? */
|
||||
if (serv->next)
|
||||
{
|
||||
*up = serv->next;
|
||||
daemon->servers_tail->next = serv;
|
||||
daemon->servers_tail = serv;
|
||||
serv->next = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
up = &serv->next;
|
||||
}
|
||||
|
||||
if (serv)
|
||||
{
|
||||
free(alloc_domain);
|
||||
alloc_domain = serv->domain;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(serv = whine_malloc(sizeof(struct server))))
|
||||
{
|
||||
free(alloc_domain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
|
||||
/* Add to the end of the chain, for order */
|
||||
if (daemon->servers_tail)
|
||||
daemon->servers_tail->next = serv;
|
||||
else
|
||||
daemon->servers = serv;
|
||||
daemon->servers_tail = serv;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LOOP
|
||||
serv->uid = rand32();
|
||||
#endif
|
||||
|
||||
if (interface)
|
||||
safe_strncpy(serv->interface, interface, sizeof(serv->interface));
|
||||
if (addr)
|
||||
serv->addr = *addr;
|
||||
if (source_addr)
|
||||
serv->source_addr = *source_addr;
|
||||
|
||||
serv->tcpfd = -1;
|
||||
}
|
||||
|
||||
serv->flags = flags;
|
||||
serv->domain = alloc_domain;
|
||||
serv->domain_len = strlen(alloc_domain);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
301
src/domain.c
Normal file
301
src/domain.c
Normal file
@@ -0,0 +1,301 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2025 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);
|
||||
static int match_domain(struct in_addr addr, struct cond_domain *c);
|
||||
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c);
|
||||
static int match_domain6(struct in6_addr *addr, struct cond_domain *c);
|
||||
|
||||
int is_name_synthetic(int flags, char *name, union all_addr *addrp)
|
||||
{
|
||||
char *p;
|
||||
struct cond_domain *c = NULL;
|
||||
int prot = (flags & F_IPV6) ? AF_INET6 : AF_INET;
|
||||
union all_addr addr;
|
||||
|
||||
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 */
|
||||
|
||||
if (c->indexed)
|
||||
{
|
||||
for (p = tail; *p; p++)
|
||||
{
|
||||
char c = *p;
|
||||
|
||||
if (c < '0' || c > '9')
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p != '.')
|
||||
continue;
|
||||
|
||||
*p = 0;
|
||||
|
||||
if (hostname_isequal(c->domain, p+1))
|
||||
{
|
||||
if (prot == AF_INET)
|
||||
{
|
||||
unsigned int index = atoi(tail);
|
||||
|
||||
if (!c->is6 &&
|
||||
index <= ntohl(c->end.s_addr) - ntohl(c->start.s_addr))
|
||||
{
|
||||
addr.addr4.s_addr = htonl(ntohl(c->start.s_addr) + index);
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
u64 index = atoll(tail);
|
||||
|
||||
if (c->is6 &&
|
||||
index <= addr6part(&c->end6) - addr6part(&c->start6))
|
||||
{
|
||||
u64 start = addr6part(&c->start6);
|
||||
addr.addr6 = c->start6;
|
||||
setaddr6part(&addr.addr6, start + index);
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* NB, must not alter name if we return zero */
|
||||
for (p = tail; *p; p++)
|
||||
{
|
||||
char c = *p;
|
||||
|
||||
if ((c >='0' && c <= '9') || c == '-')
|
||||
continue;
|
||||
|
||||
if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f')))
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p != '.')
|
||||
continue;
|
||||
|
||||
*p = 0;
|
||||
|
||||
/* swap . or : for - */
|
||||
for (p = tail; *p; p++)
|
||||
if (*p == '-')
|
||||
{
|
||||
if (prot == AF_INET)
|
||||
*p = '.';
|
||||
else
|
||||
*p = ':';
|
||||
}
|
||||
|
||||
if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, &addr))
|
||||
found = (prot == AF_INET) ? match_domain(addr.addr4, c) : match_domain6(&addr.addr6, c);
|
||||
}
|
||||
|
||||
/* restore name */
|
||||
for (p = tail; *p; p++)
|
||||
if (*p == '.' || *p == ':')
|
||||
*p = '-';
|
||||
|
||||
*p = '.';
|
||||
|
||||
|
||||
if (found)
|
||||
{
|
||||
if (addrp)
|
||||
*addrp = addr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int is_rev_synth(int flag, union all_addr *addr, char *name)
|
||||
{
|
||||
struct cond_domain *c;
|
||||
|
||||
if (flag & F_IPV4 && (c = search_domain(addr->addr4, daemon->synth_domains)))
|
||||
{
|
||||
char *p;
|
||||
|
||||
*name = 0;
|
||||
if (c->indexed)
|
||||
{
|
||||
unsigned int index = ntohl(addr->addr4.s_addr) - ntohl(c->start.s_addr);
|
||||
snprintf(name, MAXDNAME, "%s%u", c->prefix ? c->prefix : "", index);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c->prefix)
|
||||
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
|
||||
|
||||
inet_ntop(AF_INET, &addr->addr4, name + strlen(name), ADDRSTRLEN);
|
||||
for (p = name; *p; p++)
|
||||
if (*p == '.')
|
||||
*p = '-';
|
||||
}
|
||||
|
||||
strncat(name, ".", MAXDNAME);
|
||||
strncat(name, c->domain, MAXDNAME);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((flag & F_IPV6) && (c = search_domain6(&addr->addr6, daemon->synth_domains)))
|
||||
{
|
||||
*name = 0;
|
||||
|
||||
if (c->indexed)
|
||||
{
|
||||
u64 index = addr6part(&addr->addr6) - addr6part(&c->start6);
|
||||
snprintf(name, MAXDNAME, "%s%llu", c->prefix ? c->prefix : "", index);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
char frag[6];
|
||||
|
||||
if (c->prefix)
|
||||
strncpy(name, c->prefix, MAXDNAME);
|
||||
|
||||
for (i = 0; i < 16; i += 2)
|
||||
{
|
||||
sprintf(frag, "%s%02x%02x", i == 0 ? "" : "-", addr->addr6.s6_addr[i], addr->addr6.s6_addr[i+1]);
|
||||
strncat(name, frag, MAXDNAME);
|
||||
}
|
||||
}
|
||||
|
||||
strncat(name, ".", MAXDNAME);
|
||||
strncat(name, c->domain, MAXDNAME);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int match_domain(struct in_addr addr, struct cond_domain *c)
|
||||
{
|
||||
if (c->interface)
|
||||
{
|
||||
struct addrlist *al;
|
||||
for (al = c->al; al; al = al->next)
|
||||
if (!(al->flags & ADDRLIST_IPV6) &&
|
||||
is_same_net_prefix(addr, al->addr.addr4, al->prefixlen))
|
||||
return 1;
|
||||
}
|
||||
else if (!c->is6 &&
|
||||
ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
|
||||
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c)
|
||||
{
|
||||
for (; c; c = c->next)
|
||||
if (match_domain(addr, c))
|
||||
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;
|
||||
}
|
||||
|
||||
static int match_domain6(struct in6_addr *addr, struct cond_domain *c)
|
||||
{
|
||||
|
||||
/* subnet from interface address. */
|
||||
if (c->interface)
|
||||
{
|
||||
struct addrlist *al;
|
||||
for (al = c->al; al; al = al->next)
|
||||
if (al->flags & ADDRLIST_IPV6 &&
|
||||
is_same_net6(addr, &al->addr.addr6, al->prefixlen))
|
||||
return 1;
|
||||
}
|
||||
else if (c->is6)
|
||||
{
|
||||
if (c->prefixlen >= 64)
|
||||
{
|
||||
u64 addrpart = addr6part(addr);
|
||||
if (is_same_net6(addr, &c->start6, 64) &&
|
||||
addrpart >= addr6part(&c->start6) &&
|
||||
addrpart <= addr6part(&c->end6))
|
||||
return 1;
|
||||
}
|
||||
else if (is_same_net6(addr, &c->start6, c->prefixlen))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c)
|
||||
{
|
||||
for (; c; c = c->next)
|
||||
if (match_domain6(addr, c))
|
||||
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;
|
||||
}
|
||||
303
src/dump.c
Normal file
303
src/dump.c
Normal file
@@ -0,0 +1,303 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2025 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_DUMPFILE
|
||||
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
static u32 packet_count;
|
||||
static void do_dump_packet(int mask, void *packet, size_t len,
|
||||
union mysockaddr *src, union mysockaddr *dst, int port, int proto);
|
||||
|
||||
/* https://wiki.wireshark.org/Development/LibpcapFileFormat */
|
||||
struct pcap_hdr_s {
|
||||
u32 magic_number; /* magic number */
|
||||
u16 version_major; /* major version number */
|
||||
u16 version_minor; /* minor version number */
|
||||
u32 thiszone; /* GMT to local correction */
|
||||
u32 sigfigs; /* accuracy of timestamps */
|
||||
u32 snaplen; /* max length of captured packets, in octets */
|
||||
u32 network; /* data link type */
|
||||
};
|
||||
|
||||
struct pcaprec_hdr_s {
|
||||
u32 ts_sec; /* timestamp seconds */
|
||||
u32 ts_usec; /* timestamp microseconds */
|
||||
u32 incl_len; /* number of octets of packet saved in file */
|
||||
u32 orig_len; /* actual length of packet */
|
||||
};
|
||||
|
||||
|
||||
void dump_init(void)
|
||||
{
|
||||
struct stat buf;
|
||||
struct pcap_hdr_s header;
|
||||
struct pcaprec_hdr_s pcap_header;
|
||||
|
||||
packet_count = 0;
|
||||
|
||||
header.magic_number = 0xa1b2c3d4;
|
||||
header.version_major = 2;
|
||||
header.version_minor = 4;
|
||||
header.thiszone = 0;
|
||||
header.sigfigs = 0;
|
||||
header.snaplen = daemon->edns_pktsz + 200; /* slop for IP/UDP headers */
|
||||
header.network = 101; /* DLT_RAW http://www.tcpdump.org/linktypes.html */
|
||||
|
||||
if (stat(daemon->dump_file, &buf) == -1)
|
||||
{
|
||||
/* doesn't exist, create and add header */
|
||||
if (errno != ENOENT ||
|
||||
(daemon->dumpfd = creat(daemon->dump_file, S_IRUSR | S_IWUSR)) == -1 ||
|
||||
!read_write(daemon->dumpfd, (void *)&header, sizeof(header), RW_WRITE))
|
||||
die(_("cannot create %s: %s"), daemon->dump_file, EC_FILE);
|
||||
}
|
||||
else if (S_ISFIFO(buf.st_mode))
|
||||
{
|
||||
/* File is named pipe (with wireshark on the other end, probably.)
|
||||
Send header. */
|
||||
if ((daemon->dumpfd = open(daemon->dump_file, O_APPEND | O_RDWR)) == -1 ||
|
||||
!read_write(daemon->dumpfd, (void *)&header, sizeof(header), RW_WRITE))
|
||||
die(_("cannot open pipe %s: %s"), daemon->dump_file, EC_FILE);
|
||||
}
|
||||
else if ((daemon->dumpfd = open(daemon->dump_file, O_APPEND | O_RDWR)) == -1 ||
|
||||
!read_write(daemon->dumpfd, (void *)&header, sizeof(header), RW_READ))
|
||||
die(_("cannot access %s: %s"), daemon->dump_file, EC_FILE);
|
||||
else if (header.magic_number != 0xa1b2c3d4)
|
||||
die(_("bad header in %s"), daemon->dump_file, EC_FILE);
|
||||
else
|
||||
{
|
||||
/* count existing records */
|
||||
while (read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), RW_READ))
|
||||
{
|
||||
lseek(daemon->dumpfd, pcap_header.incl_len, SEEK_CUR);
|
||||
packet_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dump_packet_udp(int mask, void *packet, size_t len,
|
||||
union mysockaddr *src, union mysockaddr *dst, int fd)
|
||||
{
|
||||
union mysockaddr fd_addr;
|
||||
socklen_t addr_len = sizeof(fd_addr);
|
||||
|
||||
if (daemon->dumpfd != -1 && (mask & daemon->dump_mask))
|
||||
{
|
||||
/* if fd is negative it carries a port number (negated)
|
||||
which we use as a source or destination when not otherwise
|
||||
specified so wireshark can ID the packet.
|
||||
If both src and dst are specified, set this to -1 to avoid
|
||||
a spurious getsockname() call. */
|
||||
int port = (fd < 0) ? -fd : -1;
|
||||
|
||||
/* fd >= 0 is a file descriptor and the address of that file descriptor is used
|
||||
in place of a NULL src or dst. */
|
||||
if (fd >= 0 && getsockname(fd, (struct sockaddr *)&fd_addr, &addr_len) != -1)
|
||||
{
|
||||
if (!src)
|
||||
src = &fd_addr;
|
||||
|
||||
if (!dst)
|
||||
dst = &fd_addr;
|
||||
}
|
||||
|
||||
do_dump_packet(mask, packet, len, src, dst, port, IPPROTO_UDP);
|
||||
}
|
||||
}
|
||||
|
||||
void dump_packet_icmp(int mask, void *packet, size_t len,
|
||||
union mysockaddr *src, union mysockaddr *dst)
|
||||
{
|
||||
if (daemon->dumpfd != -1 && (mask & daemon->dump_mask))
|
||||
do_dump_packet(mask, packet, len, src, dst, -1, IPPROTO_ICMP);
|
||||
}
|
||||
|
||||
static void do_dump_packet(int mask, void *packet, size_t len,
|
||||
union mysockaddr *src, union mysockaddr *dst, int port, int proto)
|
||||
{
|
||||
struct ip ip;
|
||||
struct ip6_hdr ip6;
|
||||
int family;
|
||||
struct udphdr {
|
||||
u16 uh_sport; /* source port */
|
||||
u16 uh_dport; /* destination port */
|
||||
u16 uh_ulen; /* udp length */
|
||||
u16 uh_sum; /* udp checksum */
|
||||
} udp;
|
||||
struct pcaprec_hdr_s pcap_header;
|
||||
struct timeval time;
|
||||
u32 i, sum;
|
||||
void *iphdr;
|
||||
size_t ipsz;
|
||||
int rc;
|
||||
|
||||
/* if port != -1 it carries a port number
|
||||
which we use as a source or destination when not otherwise
|
||||
specified so wireshark can ID the packet.
|
||||
If both src and dst are specified, set this to -1 to avoid
|
||||
a spurious getsockname() call. */
|
||||
udp.uh_sport = udp.uh_dport = htons(port < 0 ? 0 : port);
|
||||
|
||||
if (src)
|
||||
family = src->sa.sa_family;
|
||||
else
|
||||
family = dst->sa.sa_family;
|
||||
|
||||
if (family == AF_INET6)
|
||||
{
|
||||
iphdr = &ip6;
|
||||
ipsz = sizeof(ip6);
|
||||
memset(&ip6, 0, sizeof(ip6));
|
||||
|
||||
ip6.ip6_vfc = 6 << 4;
|
||||
ip6.ip6_hops = 64;
|
||||
|
||||
if ((ip6.ip6_nxt = proto) == IPPROTO_UDP)
|
||||
ip6.ip6_plen = htons(sizeof(struct udphdr) + len);
|
||||
else
|
||||
{
|
||||
proto = ip6.ip6_nxt = IPPROTO_ICMPV6;
|
||||
ip6.ip6_plen = htons(len);
|
||||
}
|
||||
|
||||
if (src)
|
||||
{
|
||||
memcpy(&ip6.ip6_src, &src->in6.sin6_addr, IN6ADDRSZ);
|
||||
udp.uh_sport = src->in6.sin6_port;
|
||||
}
|
||||
|
||||
if (dst)
|
||||
{
|
||||
memcpy(&ip6.ip6_dst, &dst->in6.sin6_addr, IN6ADDRSZ);
|
||||
udp.uh_dport = dst->in6.sin6_port;
|
||||
}
|
||||
|
||||
/* start UDP checksum */
|
||||
for (sum = 0, i = 0; i < IN6ADDRSZ; i+=2)
|
||||
{
|
||||
sum += ntohs((ip6.ip6_src.s6_addr[i] << 8) + (ip6.ip6_src.s6_addr[i+1])) ;
|
||||
sum += ntohs((ip6.ip6_dst.s6_addr[i] << 8) + (ip6.ip6_dst.s6_addr[i+1])) ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
iphdr = &ip;
|
||||
ipsz = sizeof(ip);
|
||||
memset(&ip, 0, sizeof(ip));
|
||||
|
||||
ip.ip_v = IPVERSION;
|
||||
ip.ip_hl = sizeof(struct ip) / 4;
|
||||
ip.ip_ttl = IPDEFTTL;
|
||||
|
||||
if ((ip.ip_p = proto) == IPPROTO_UDP)
|
||||
ip.ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + len);
|
||||
else
|
||||
{
|
||||
ip.ip_len = htons(sizeof(struct ip) + len);
|
||||
proto = ip.ip_p = IPPROTO_ICMP;
|
||||
}
|
||||
|
||||
if (src)
|
||||
{
|
||||
ip.ip_src = src->in.sin_addr;
|
||||
udp.uh_sport = src->in.sin_port;
|
||||
}
|
||||
|
||||
if (dst)
|
||||
{
|
||||
ip.ip_dst = dst->in.sin_addr;
|
||||
udp.uh_dport = dst->in.sin_port;
|
||||
}
|
||||
|
||||
ip.ip_sum = 0;
|
||||
for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
|
||||
sum += ((u16 *)&ip)[i];
|
||||
while (sum >> 16)
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
|
||||
|
||||
/* start UDP/ICMP checksum */
|
||||
sum = ip.ip_src.s_addr & 0xffff;
|
||||
sum += (ip.ip_src.s_addr >> 16) & 0xffff;
|
||||
sum += ip.ip_dst.s_addr & 0xffff;
|
||||
sum += (ip.ip_dst.s_addr >> 16) & 0xffff;
|
||||
}
|
||||
|
||||
if (len & 1)
|
||||
((unsigned char *)packet)[len] = 0; /* for checksum, in case length is odd. */
|
||||
|
||||
if (proto == IPPROTO_UDP)
|
||||
{
|
||||
/* Add Remaining part of the pseudoheader. Note that though the
|
||||
IPv6 pseudoheader is very different to the IPv4 one, the
|
||||
net result of this calculation is correct as long as the
|
||||
packet length is less than 65536, which is fine for us. */
|
||||
sum += htons(IPPROTO_UDP);
|
||||
sum += htons(sizeof(struct udphdr) + len);
|
||||
|
||||
udp.uh_sum = 0;
|
||||
udp.uh_ulen = htons(sizeof(struct udphdr) + len);
|
||||
|
||||
for (i = 0; i < sizeof(struct udphdr)/2; i++)
|
||||
sum += ((u16 *)&udp)[i];
|
||||
for (i = 0; i < (len + 1) / 2; i++)
|
||||
sum += ((u16 *)packet)[i];
|
||||
while (sum >> 16)
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
|
||||
|
||||
pcap_header.incl_len = pcap_header.orig_len = ipsz + sizeof(udp) + len;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ICMP - ICMPv6 packet is a superset of ICMP */
|
||||
struct icmp6_hdr *icmp = packet;
|
||||
|
||||
/* See comment in UDP code above. */
|
||||
sum += htons(proto);
|
||||
sum += htons(len);
|
||||
|
||||
icmp->icmp6_cksum = 0;
|
||||
for (i = 0; i < (len + 1) / 2; i++)
|
||||
sum += ((u16 *)packet)[i];
|
||||
while (sum >> 16)
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
icmp->icmp6_cksum = (sum == 0xffff) ? sum : ~sum;
|
||||
|
||||
pcap_header.incl_len = pcap_header.orig_len = ipsz + len;
|
||||
}
|
||||
|
||||
rc = gettimeofday(&time, NULL);
|
||||
pcap_header.ts_sec = time.tv_sec;
|
||||
pcap_header.ts_usec = time.tv_usec;
|
||||
|
||||
if (rc == -1 ||
|
||||
!read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), RW_WRITE) ||
|
||||
!read_write(daemon->dumpfd, iphdr, ipsz, RW_WRITE) ||
|
||||
(proto == IPPROTO_UDP && !read_write(daemon->dumpfd, (void *)&udp, sizeof(udp), RW_WRITE)) ||
|
||||
!read_write(daemon->dumpfd, (void *)packet, len, RW_WRITE))
|
||||
my_syslog(LOG_ERR, _("failed to write packet dump"));
|
||||
else if (option_bool(OPT_EXTRALOG) && (mask & 0x00ff))
|
||||
my_syslog(LOG_INFO, _("%u dumping packet %u mask 0x%04x"), daemon->log_display_id, ++packet_count, mask);
|
||||
else
|
||||
my_syslog(LOG_INFO, _("dumping packet %u mask 0x%04x"), ++packet_count, mask);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
574
src/edns0.c
Normal file
574
src/edns0.c
Normal file
@@ -0,0 +1,574 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2025 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 == 0 ->don't replace existing option
|
||||
replace == 1 ->replace existing or add option
|
||||
replace == 2 ->relpace existing option only.
|
||||
*/
|
||||
size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
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;
|
||||
|
||||
PUTSHORT(daemon->edns_pktsz, 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 + 4 + 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;
|
||||
memmove(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 */
|
||||
rrfilter(header, &plen, RRFILTER_EDNS0);
|
||||
|
||||
/* 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)) ||
|
||||
p + 11 > limit)
|
||||
{
|
||||
free(buff);
|
||||
return plen; /* bad packet */
|
||||
}
|
||||
|
||||
*p++ = 0; /* empty name */
|
||||
PUTSHORT(T_OPT, p);
|
||||
PUTSHORT(daemon->edns_pktsz, 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)
|
||||
{
|
||||
if (p + rdlen > limit)
|
||||
{
|
||||
free(buff);
|
||||
return plen; /* Too big */
|
||||
}
|
||||
memcpy(p, buff, rdlen);
|
||||
free(buff);
|
||||
p += rdlen;
|
||||
}
|
||||
|
||||
/* Only bump arcount if RR is going to fit */
|
||||
if (((ssize_t)optlen) <= (limit - (p + 4)))
|
||||
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)
|
||||
{
|
||||
if (p + 4 > limit)
|
||||
return plen; /* Too big */
|
||||
PUTSHORT(optno, p);
|
||||
PUTSHORT(optlen, p);
|
||||
if (p + optlen > limit)
|
||||
return plen; /* Too big */
|
||||
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, 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]);
|
||||
}
|
||||
|
||||
/* This function needs to call find_mac if any option which requires a MAC address is enabled
|
||||
and used below. If you add a new MAC consumer, modify this, otherwise your
|
||||
new EDNS0 option won't work in TCP mode. */
|
||||
void edns0_needs_mac(union mysockaddr *addr, time_t now)
|
||||
{
|
||||
if (option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX) || option_bool(OPT_ADD_MAC))
|
||||
find_mac(addr, NULL, 0, now);
|
||||
}
|
||||
|
||||
/* OPT_ADD_MAC = MAC is added (if available)
|
||||
OPT_ADD_MAC + OPT_STRIP_MAC = MAC is replaced, if not available, it is only removed
|
||||
OPT_STRIP_MAC = MAC is removed */
|
||||
static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
union mysockaddr *l3, time_t now, int *cacheablep)
|
||||
{
|
||||
int replace = 0, maclen = 0;
|
||||
unsigned char mac[DHCP_CHADDR_MAX];
|
||||
char encode[18]; /* handle 6 byte MACs ONLY */
|
||||
|
||||
if ((option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX)) && (maclen = find_mac(l3, mac, 1, now)) == 6)
|
||||
{
|
||||
if (option_bool(OPT_STRIP_MAC))
|
||||
replace = 1;
|
||||
*cacheablep = 0;
|
||||
|
||||
if (option_bool(OPT_MAC_HEX))
|
||||
print_mac(encode, mac, maclen);
|
||||
else
|
||||
{
|
||||
encoder(mac, encode);
|
||||
encoder(mac+3, encode+4);
|
||||
encode[8] = 0;
|
||||
}
|
||||
}
|
||||
else if (option_bool(OPT_STRIP_MAC))
|
||||
replace = 2;
|
||||
|
||||
if (replace != 0 || maclen == 6)
|
||||
plen = add_pseudoheader(header, plen, limit, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, strlen(encode), 0, replace);
|
||||
|
||||
return plen;
|
||||
}
|
||||
|
||||
|
||||
/* OPT_ADD_MAC = MAC is added (if available)
|
||||
OPT_ADD_MAC + OPT_STRIP_MAC = MAC is replaced, if not available, it is only removed
|
||||
OPT_STRIP_MAC = MAC is removed */
|
||||
static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
union mysockaddr *l3, time_t now, int *cacheablep)
|
||||
{
|
||||
int maclen = 0, replace = 0;
|
||||
unsigned char mac[DHCP_CHADDR_MAX];
|
||||
|
||||
if (option_bool(OPT_ADD_MAC) && (maclen = find_mac(l3, mac, 1, now)) != 0)
|
||||
{
|
||||
*cacheablep = 0;
|
||||
if (option_bool(OPT_STRIP_MAC))
|
||||
replace = 1;
|
||||
}
|
||||
else if (option_bool(OPT_STRIP_MAC))
|
||||
replace = 2;
|
||||
|
||||
if (replace != 0 || maclen != 0)
|
||||
plen = add_pseudoheader(header, plen, limit, EDNS0_OPTION_MAC, mac, maclen, 0, replace);
|
||||
|
||||
return plen;
|
||||
}
|
||||
|
||||
struct subnet_opt {
|
||||
u16 family;
|
||||
u8 source_netmask, scope_netmask;
|
||||
u8 addr[IN6ADDRSZ];
|
||||
};
|
||||
|
||||
static void *get_addrp(union mysockaddr *addr, const short family)
|
||||
{
|
||||
if (family == AF_INET6)
|
||||
return &addr->in6.sin6_addr;
|
||||
|
||||
return &addr->in.sin_addr;
|
||||
}
|
||||
|
||||
static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source, int *cacheablep)
|
||||
{
|
||||
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
|
||||
|
||||
int len;
|
||||
void *addrp = NULL;
|
||||
int sa_family = source->sa.sa_family;
|
||||
int cacheable = 0;
|
||||
|
||||
opt->source_netmask = 0;
|
||||
opt->scope_netmask = 0;
|
||||
|
||||
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);
|
||||
cacheable = 1;
|
||||
}
|
||||
else
|
||||
addrp = &source->in6.sin6_addr;
|
||||
}
|
||||
|
||||
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);
|
||||
cacheable = 1; /* Address is constant */
|
||||
}
|
||||
else
|
||||
addrp = &source->in.sin_addr;
|
||||
}
|
||||
|
||||
opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
|
||||
|
||||
if (addrp && 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));
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheable = 1; /* No address ever supplied. */
|
||||
len = 0;
|
||||
}
|
||||
|
||||
if (cacheablep)
|
||||
*cacheablep = cacheable;
|
||||
|
||||
return len + 4;
|
||||
}
|
||||
|
||||
/* OPT_CLIENT_SUBNET = client subnet is added
|
||||
OPT_CLIENT_SUBNET + OPT_STRIP_ECS = client subnet is replaced
|
||||
OPT_STRIP_ECS = client subnet is removed */
|
||||
static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
union mysockaddr *source, int *cacheable)
|
||||
{
|
||||
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
|
||||
|
||||
int replace = 0, len = 0;
|
||||
struct subnet_opt opt;
|
||||
|
||||
if (option_bool(OPT_CLIENT_SUBNET))
|
||||
{
|
||||
if (option_bool(OPT_STRIP_ECS))
|
||||
replace = 1;
|
||||
len = calc_subnet_opt(&opt, source, cacheable);
|
||||
}
|
||||
else if (option_bool(OPT_STRIP_ECS))
|
||||
replace = 2;
|
||||
else
|
||||
{
|
||||
unsigned char *pheader;
|
||||
/* If we still think the data is cacheable, and we're not
|
||||
messing with EDNS client subnet ourselves, see if the client
|
||||
sent a client subnet. If so, mark the data as uncacheable */
|
||||
if (*cacheable &&
|
||||
(pheader = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL)) &&
|
||||
!check_source(header, plen, pheader, NULL))
|
||||
*cacheable = 0;
|
||||
|
||||
return plen;
|
||||
}
|
||||
|
||||
return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, replace);
|
||||
}
|
||||
|
||||
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
|
||||
{
|
||||
/* Section 9.2, Check that subnet option (if any) in reply matches.
|
||||
if peer == NULL, this degrades to a check for the existence of and EDNS0 client-subnet option. */
|
||||
|
||||
int len, calc_len;
|
||||
struct subnet_opt opt;
|
||||
unsigned char *p;
|
||||
int code, i, rdlen;
|
||||
|
||||
if (peer)
|
||||
calc_len = calc_subnet_opt(&opt, peer, NULL);
|
||||
|
||||
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)
|
||||
{
|
||||
if (peer)
|
||||
{
|
||||
/* make sure this doesn't mismatch. */
|
||||
opt.scope_netmask = p[3];
|
||||
if (len != calc_len || memcmp(p, &opt, len) != 0)
|
||||
return 0;
|
||||
}
|
||||
else if (((struct subnet_opt *)p)->source_netmask != 0)
|
||||
return 0;
|
||||
}
|
||||
p += len;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* See https://docs.umbrella.com/umbrella-api/docs/identifying-dns-traffic for
|
||||
* detailed information on packet formating.
|
||||
*/
|
||||
#define UMBRELLA_VERSION 1
|
||||
#define UMBRELLA_TYPESZ 2
|
||||
|
||||
#define UMBRELLA_ASSET 0x0004
|
||||
#define UMBRELLA_ASSETSZ sizeof(daemon->umbrella_asset)
|
||||
#define UMBRELLA_ORG 0x0008
|
||||
#define UMBRELLA_ORGSZ sizeof(daemon->umbrella_org)
|
||||
#define UMBRELLA_IPV4 0x0010
|
||||
#define UMBRELLA_IPV6 0x0020
|
||||
#define UMBRELLA_DEVICE 0x0040
|
||||
#define UMBRELLA_DEVICESZ sizeof(daemon->umbrella_device)
|
||||
|
||||
struct umbrella_opt {
|
||||
u8 magic[4] ATTRIBUTE_NONSTRING;
|
||||
u8 version;
|
||||
u8 flags;
|
||||
/* We have 4 possible fields since we'll never send both IPv4 and
|
||||
* IPv6, so using the larger of the two to calculate max buffer size.
|
||||
* Each field also has a type header. So the following accounts for
|
||||
* the type headers and each field size to get a max buffer size.
|
||||
*/
|
||||
u8 fields[4 * UMBRELLA_TYPESZ + UMBRELLA_ORGSZ + IN6ADDRSZ + UMBRELLA_DEVICESZ + UMBRELLA_ASSETSZ];
|
||||
};
|
||||
|
||||
static size_t add_umbrella_opt(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source, int *cacheable)
|
||||
{
|
||||
*cacheable = 0;
|
||||
|
||||
struct umbrella_opt opt = {{"ODNS"}, UMBRELLA_VERSION, 0, {0}};
|
||||
u8 *u = &opt.fields[0];
|
||||
int family = source->sa.sa_family;
|
||||
int size = family == AF_INET ? INADDRSZ : IN6ADDRSZ;
|
||||
|
||||
if (daemon->umbrella_org)
|
||||
{
|
||||
PUTSHORT(UMBRELLA_ORG, u);
|
||||
PUTLONG(daemon->umbrella_org, u);
|
||||
}
|
||||
|
||||
PUTSHORT(family == AF_INET ? UMBRELLA_IPV4 : UMBRELLA_IPV6, u);
|
||||
memcpy(u, get_addrp(source, family), size);
|
||||
u += size;
|
||||
|
||||
if (option_bool(OPT_UMBRELLA_DEVID))
|
||||
{
|
||||
PUTSHORT(UMBRELLA_DEVICE, u);
|
||||
memcpy(u, (char *)&daemon->umbrella_device, UMBRELLA_DEVICESZ);
|
||||
u += UMBRELLA_DEVICESZ;
|
||||
}
|
||||
|
||||
if (daemon->umbrella_asset)
|
||||
{
|
||||
PUTSHORT(UMBRELLA_ASSET, u);
|
||||
PUTLONG(daemon->umbrella_asset, u);
|
||||
}
|
||||
|
||||
return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_UMBRELLA, (unsigned char *)&opt, u - (u8 *)&opt, 0, 1);
|
||||
}
|
||||
|
||||
/* Set *check_subnet if we add a client subnet option, which needs to checked
|
||||
in the reply. Set *cacheable to zero if we add an option which the answer
|
||||
may depend on. */
|
||||
size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
union mysockaddr *source, time_t now, int *cacheable)
|
||||
{
|
||||
*cacheable = 1;
|
||||
|
||||
plen = add_mac(header, plen, limit, source, now, cacheable);
|
||||
plen = add_dns_client(header, plen, limit, source, now, cacheable);
|
||||
|
||||
if (daemon->dns_client_id)
|
||||
plen = add_pseudoheader(header, plen, limit, EDNS0_OPTION_NOMCPEID,
|
||||
(unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1);
|
||||
|
||||
if (option_bool(OPT_UMBRELLA))
|
||||
plen = add_umbrella_opt(header, plen, limit, source, cacheable);
|
||||
|
||||
plen = add_source_addr(header, plen, limit, source, cacheable);
|
||||
|
||||
return plen;
|
||||
}
|
||||
|
||||
3745
src/forward.c
3745
src/forward.c
File diff suppressed because it is too large
Load Diff
820
src/helper.c
820
src/helper.c
File diff suppressed because it is too large
Load Diff
372
src/inotify.c
Normal file
372
src/inotify.c
Normal file
@@ -0,0 +1,372 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2025 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 an 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 (daemon->port == 0 || 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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static struct hostsfile *dyndir_addhosts(struct dyndir *dd, char *file)
|
||||
{
|
||||
/* Check if this file is already known in dd->files */
|
||||
struct hostsfile *ah;
|
||||
size_t dirlen = strlen(dd->dname);
|
||||
|
||||
/* ah->fname always starts with the string in dd->dname */
|
||||
for (ah = dd->files; ah; ah = ah->next)
|
||||
if (ah->fname[dirlen] == '/' &&
|
||||
strcmp(&ah->fname[dirlen+1], file) == 0)
|
||||
return ah;
|
||||
|
||||
/* Not known, create new hostsfile record for this dyndir */
|
||||
if ((ah = whine_malloc(sizeof(struct hostsfile))))
|
||||
{
|
||||
char *path;
|
||||
|
||||
if (!(path = whine_malloc(dirlen + strlen(file) + 2)))
|
||||
{
|
||||
free(ah);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(path, dd->dname);
|
||||
strcat(path, "/");
|
||||
strcat(path, file);
|
||||
|
||||
/* Add this file to the tip of the linked list */
|
||||
ah->next = dd->files;
|
||||
dd->files = ah;
|
||||
|
||||
/* Copy flags, set index and the full file path */
|
||||
ah->flags = dd->flags;
|
||||
ah->index = daemon->host_index++;
|
||||
ah->fname = path;
|
||||
}
|
||||
|
||||
return ah;
|
||||
}
|
||||
|
||||
|
||||
/* 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 dyndir *dd;
|
||||
|
||||
for (dd = daemon->dynamic_dirs; dd; dd = dd->next)
|
||||
{
|
||||
DIR *dir_stream = NULL;
|
||||
struct dirent *ent;
|
||||
struct stat buf;
|
||||
|
||||
if (!(dd->flags & flag))
|
||||
continue;
|
||||
|
||||
if (stat(dd->dname, &buf) == -1)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("bad dynamic directory %s: %s"),
|
||||
dd->dname, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(S_ISDIR(buf.st_mode)))
|
||||
{
|
||||
my_syslog(LOG_ERR, _("bad dynamic directory %s: %s"),
|
||||
dd->dname, _("not a directory"));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(dd->flags & AH_WD_DONE))
|
||||
{
|
||||
dd->wd = inotify_add_watch(daemon->inotifyfd, dd->dname, IN_CLOSE_WRITE | IN_MOVED_TO | IN_DELETE);
|
||||
dd->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 (dd->wd == -1 || !(dir_stream = opendir(dd->dname)))
|
||||
{
|
||||
my_syslog(LOG_ERR, _("failed to create inotify for %s: %s"),
|
||||
dd->dname, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
while ((ent = readdir(dir_stream)))
|
||||
{
|
||||
size_t lenfile = strlen(ent->d_name);
|
||||
|
||||
/* 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 (dd->flags & AH_HOSTS)
|
||||
{
|
||||
struct hostsfile *ah;
|
||||
|
||||
/* ignore non-regular files */
|
||||
if ((ah = dyndir_addhosts(dd, ent->d_name)) &&
|
||||
stat(ah->fname, &buf) != -1 && S_ISREG(buf.st_mode))
|
||||
total_size = read_hostsfile(ah->fname, ah->index, total_size, rhash, revhashsz);
|
||||
}
|
||||
#ifdef HAVE_DHCP
|
||||
else if (dd->flags & (AH_DHCP_HST | AH_DHCP_OPT))
|
||||
{
|
||||
char *path;
|
||||
|
||||
if ((path = whine_malloc(strlen(dd->dname) + lenfile + 2)))
|
||||
{
|
||||
strcpy(path, dd->dname);
|
||||
strcat(path, "/");
|
||||
strcat(path, ent->d_name);
|
||||
|
||||
/* ignore non-regular files */
|
||||
if (stat(path, &buf) != -1 && S_ISREG(buf.st_mode))
|
||||
option_read_dynfile(path, dd->flags);
|
||||
|
||||
free(path);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
closedir(dir_stream);
|
||||
}
|
||||
}
|
||||
|
||||
int inotify_check(time_t now)
|
||||
{
|
||||
int hit = 0;
|
||||
struct dyndir *dd;
|
||||
|
||||
(void)now;
|
||||
|
||||
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)
|
||||
{
|
||||
size_t namelen;
|
||||
|
||||
in = (struct inotify_event*)p;
|
||||
|
||||
/* ignore emacs backups and dotfiles */
|
||||
if (in->len == 0 || (namelen = strlen(in->name)) == 0 ||
|
||||
in->name[namelen - 1] == '~' ||
|
||||
(in->name[0] == '#' && in->name[namelen - 1] == '#') ||
|
||||
in->name[0] == '.')
|
||||
continue;
|
||||
|
||||
for (res = daemon->resolv_files; res; res = res->next)
|
||||
if (res->wd == in->wd && strcmp(res->file, in->name) == 0)
|
||||
hit = 1;
|
||||
|
||||
for (dd = daemon->dynamic_dirs; dd; dd = dd->next)
|
||||
if (dd->wd == in->wd)
|
||||
{
|
||||
if (dd->flags & AH_HOSTS)
|
||||
{
|
||||
struct hostsfile *ah;
|
||||
if ((ah = dyndir_addhosts(dd, in->name)))
|
||||
{
|
||||
const unsigned int removed = cache_remove_uid(ah->index);
|
||||
|
||||
/* Is this is a deletion event? */
|
||||
if (in->mask & IN_DELETE)
|
||||
my_syslog(LOG_INFO, _("inotify: %s removed"), ah->fname);
|
||||
else
|
||||
my_syslog(LOG_INFO, _("inotify: %s new or modified"), ah->fname);
|
||||
|
||||
if (removed > 0)
|
||||
my_syslog(LOG_INFO, _("inotify: flushed %u names read from %s"), removed, ah->fname);
|
||||
|
||||
/* (Re-)load hostsfile only if this event isn't triggered by deletion */
|
||||
if (!(in->mask & IN_DELETE))
|
||||
read_hostsfile(ah->fname, 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 (!(in->mask & IN_DELETE))
|
||||
{
|
||||
char *path;
|
||||
|
||||
if ((path = whine_malloc(strlen(dd->dname) + in->len + 2)))
|
||||
{
|
||||
strcpy(path, dd->dname);
|
||||
strcat(path, "/");
|
||||
strcat(path, in->name);
|
||||
|
||||
my_syslog(LOG_INFO, _("inotify: %s new or modified"), path);
|
||||
|
||||
if ((dd->flags & AH_DHCP_HST) && 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);
|
||||
}
|
||||
|
||||
if (dd->flags & AH_DHCP_OPT)
|
||||
option_read_dynfile(path, AH_DHCP_OPT);
|
||||
|
||||
free(path);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
#endif /* INOTIFY */
|
||||
33
src/ip6addr.h
Normal file
33
src/ip6addr.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2025 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)
|
||||
216
src/ipset.c
Normal file
216
src/ipset.c
Normal file
@@ -0,0 +1,216 @@
|
||||
/* 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_LINUX_IPSET)
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.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 = (struct my_nlattr *)((u8 *)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((u8 *)attr + NL_ALIGN(sizeof(struct my_nlattr)), data, len);
|
||||
nlh->nlmsg_len += NL_ALIGN(payload_len);
|
||||
}
|
||||
|
||||
void ipset_init(void)
|
||||
{
|
||||
old_kernel = (daemon->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 union all_addr *ipaddr, int af, int remove)
|
||||
{
|
||||
struct nlmsghdr *nlh;
|
||||
struct my_nfgenmsg *nfg;
|
||||
struct my_nlattr *nested[2];
|
||||
uint8_t proto;
|
||||
int addrsz = (af == AF_INET6) ? IN6ADDRSZ : INADDRSZ;
|
||||
|
||||
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);
|
||||
nested[1]->nla_len = (u8 *)buffer + NL_ALIGN(nlh->nlmsg_len) - (u8 *)nested[1];
|
||||
nested[0]->nla_len = (u8 *)buffer + NL_ALIGN(nlh->nlmsg_len) - (u8 *)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 union 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->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 union all_addr *ipaddr, int flags, int remove)
|
||||
{
|
||||
int ret = 0, af = AF_INET;
|
||||
|
||||
if (flags & F_IPV6)
|
||||
{
|
||||
af = AF_INET6;
|
||||
/* old method only supports IPv4 */
|
||||
if (old_kernel)
|
||||
{
|
||||
errno = EAFNOSUPPORT ;
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
1001
src/lease.c
1001
src/lease.c
File diff suppressed because it is too large
Load Diff
80
src/log.c
80
src/log.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2025 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
|
||||
@@ -84,7 +84,7 @@ int log_start(struct passwd *ent_pw, int errfd)
|
||||
|
||||
if (!log_reopen(daemon->log_file))
|
||||
{
|
||||
send_event(errfd, EVENT_LOG_ERR, errno);
|
||||
send_event(errfd, EVENT_LOG_ERR, errno, daemon->log_file ? daemon->log_file : "");
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
@@ -100,10 +100,23 @@ int log_start(struct passwd *ent_pw, int errfd)
|
||||
/* If we're running as root and going to change uid later,
|
||||
change the ownership here so that the file is always owned by
|
||||
the dnsmasq user. Then logrotate can just copy the owner.
|
||||
Failure of the chown call is OK, (for instance when started as non-root) */
|
||||
if (log_to_file && !log_stderr && ent_pw && ent_pw->pw_uid != 0 &&
|
||||
fchown(log_fd, ent_pw->pw_uid, -1) != 0)
|
||||
ret = errno;
|
||||
Failure of the chown call is OK, (for instance when started as non-root).
|
||||
|
||||
If we've created a file with group-id root, we also make
|
||||
the file group-writable. This gives processes in the root group
|
||||
write access to the file and avoids the problem that on some systems,
|
||||
once the file is owned by the dnsmasq user, it can't be written
|
||||
whilst dnsmasq is running as root during startup.
|
||||
*/
|
||||
if (log_to_file && !log_stderr && ent_pw && ent_pw->pw_uid != 0)
|
||||
{
|
||||
struct stat ls;
|
||||
if (getgid() == 0 && fstat(log_fd, &ls) == 0 && ls.st_gid == 0 &&
|
||||
(ls.st_mode & S_IWGRP) == 0)
|
||||
(void)fchmod(log_fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
|
||||
if (fchown(log_fd, ent_pw->pw_uid, -1) != 0)
|
||||
ret = errno;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -118,7 +131,7 @@ int log_reopen(char *log_file)
|
||||
/* NOTE: umask is set to 022 by the time this gets called */
|
||||
|
||||
if (log_file)
|
||||
log_fd = open(log_file, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
|
||||
log_fd = open(log_file, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
|
||||
else
|
||||
{
|
||||
#if defined(HAVE_SOLARIS_NETWORK) || defined(__ANDROID__)
|
||||
@@ -154,6 +167,19 @@ static void log_write(void)
|
||||
|
||||
while (entries)
|
||||
{
|
||||
/* 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
|
||||
to elide the zero. If we're logging to a file, turn the zero into
|
||||
a newline, and leave the length alone. */
|
||||
int len_adjust = 0;
|
||||
|
||||
if (log_to_file)
|
||||
entries->payload[entries->offset + entries->length - 1] = '\n';
|
||||
else if (connection_type == SOCK_DGRAM)
|
||||
len_adjust = 1;
|
||||
|
||||
/* Avoid duplicates over a fork() */
|
||||
if (entries->pid != getpid())
|
||||
{
|
||||
@@ -163,11 +189,11 @@ static void log_write(void)
|
||||
|
||||
connection_good = 1;
|
||||
|
||||
if ((rc = write(log_fd, entries->payload + entries->offset, entries->length)) != -1)
|
||||
if ((rc = write(log_fd, entries->payload + entries->offset, entries->length - len_adjust)) != -1)
|
||||
{
|
||||
entries->length -= rc;
|
||||
entries->offset += rc;
|
||||
if (entries->length == 0)
|
||||
if (entries->length == len_adjust)
|
||||
{
|
||||
free_entry();
|
||||
if (entries_lost != 0)
|
||||
@@ -183,7 +209,7 @@ static void log_write(void)
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (errno == EAGAIN)
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
return; /* syslogd busy, go again when select() or poll() says so */
|
||||
|
||||
if (errno == ENOBUFS)
|
||||
@@ -219,7 +245,7 @@ static void log_write(void)
|
||||
logaddr.sun_len = sizeof(logaddr) - sizeof(logaddr.sun_path) + strlen(_PATH_LOG) + 1;
|
||||
#endif
|
||||
logaddr.sun_family = AF_UNIX;
|
||||
strncpy(logaddr.sun_path, _PATH_LOG, sizeof(logaddr.sun_path));
|
||||
safe_strncpy(logaddr.sun_path, _PATH_LOG, sizeof(logaddr.sun_path));
|
||||
|
||||
/* Got connection back? try again. */
|
||||
if (connect(log_fd, (struct sockaddr *)&logaddr, sizeof(logaddr)) != -1)
|
||||
@@ -231,7 +257,8 @@ static void log_write(void)
|
||||
errno == ECONNREFUSED ||
|
||||
errno == EISCONN ||
|
||||
errno == EINTR ||
|
||||
errno == EAGAIN)
|
||||
errno == EAGAIN ||
|
||||
errno == EWOULDBLOCK)
|
||||
{
|
||||
/* try again on next syslog() call */
|
||||
connection_good = 0;
|
||||
@@ -259,7 +286,7 @@ static void log_write(void)
|
||||
/* priority is one of LOG_DEBUG, LOG_INFO, LOG_NOTICE, etc. See sys/syslog.h.
|
||||
OR'd to priority can be MS_TFTP, MS_DHCP, ... to be able to do log separation between
|
||||
DNS, DHCP and TFTP services.
|
||||
*/
|
||||
If OR'd with MS_DEBUG, the messages are suppressed unless --log-debug is set. */
|
||||
void my_syslog(int priority, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@@ -274,7 +301,15 @@ 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";
|
||||
else if ((LOG_FACMASK & priority) == MS_DEBUG)
|
||||
{
|
||||
if (!option_bool(OPT_LOG_DEBUG))
|
||||
return;
|
||||
func = "-debug";
|
||||
}
|
||||
|
||||
#ifdef LOG_PRI
|
||||
priority = LOG_PRI(priority);
|
||||
#else
|
||||
@@ -366,10 +401,6 @@ void my_syslog(int priority, const char *format, ...)
|
||||
entry->length = len > MAX_MESSAGE ? MAX_MESSAGE : len;
|
||||
entry->offset = 0;
|
||||
entry->pid = pid;
|
||||
|
||||
/* replace terminator with \n */
|
||||
if (log_to_file)
|
||||
entry->payload[entry->length - 1] = '\n';
|
||||
}
|
||||
|
||||
/* almost always, logging won't block, so try and write this now,
|
||||
@@ -411,25 +442,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;
|
||||
|
||||
113
src/loop.c
Normal file
113
src/loop.c
Normal file
@@ -0,0 +1,113 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2025 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(void)
|
||||
{
|
||||
struct server *serv;
|
||||
struct randfd_list *rfds = NULL;
|
||||
|
||||
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 (strlen(serv->domain) == 0 &&
|
||||
!(serv->flags & (SERV_FOR_NODOTS)))
|
||||
{
|
||||
ssize_t len = loop_make_probe(serv->uid);
|
||||
int fd;
|
||||
|
||||
serv->flags &= ~SERV_LOOP;
|
||||
|
||||
if ((fd = allocate_rfd(&rfds, serv)) == -1)
|
||||
continue;
|
||||
|
||||
while (retry_send(sendto(fd, daemon->packet, len, 0,
|
||||
&serv->addr.sa, sa_len(&serv->addr))));
|
||||
}
|
||||
|
||||
free_rfds(&rfds);
|
||||
}
|
||||
|
||||
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((unsigned char)query[i]))
|
||||
return 0;
|
||||
|
||||
uid = strtol(query, NULL, 16);
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (strlen(serv->domain) == 0 &&
|
||||
!(serv->flags & SERV_LOOP) &&
|
||||
uid == serv->uid)
|
||||
{
|
||||
serv->flags |= SERV_LOOP;
|
||||
check_servers(1); /* log new state - don't send more probes. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user