This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | /* |
||
6 | * This file is part of Badcow DNS Library. |
||
7 | * |
||
8 | * (c) Samuel Williams <[email protected]> |
||
9 | * |
||
10 | * For the full copyright and license information, please view the LICENSE |
||
11 | * file that was distributed with this source code. |
||
12 | */ |
||
13 | |||
14 | namespace Badcow\DNS\Tests\Parser; |
||
15 | |||
16 | use Badcow\DNS\Algorithms; |
||
17 | use Badcow\DNS\AlignedBuilder; |
||
18 | use Badcow\DNS\Classes; |
||
19 | use Badcow\DNS\Parser\Comments; |
||
20 | use Badcow\DNS\Parser\ParseException; |
||
21 | use Badcow\DNS\Parser\Parser; |
||
22 | use Badcow\DNS\Parser\TimeFormat; |
||
23 | use Badcow\DNS\Parser\ZoneFileFetcherInterface; |
||
24 | use Badcow\DNS\Rdata\A; |
||
25 | use Badcow\DNS\Rdata\AAAA; |
||
26 | use Badcow\DNS\Rdata\APL; |
||
27 | use Badcow\DNS\Rdata\CAA; |
||
28 | use Badcow\DNS\Rdata\CNAME; |
||
29 | use Badcow\DNS\Rdata\Factory; |
||
30 | use Badcow\DNS\Rdata\RRSIG; |
||
31 | use Badcow\DNS\Rdata\TXT; |
||
32 | use Badcow\DNS\ResourceRecord; |
||
33 | use Badcow\DNS\Zone; |
||
34 | use Badcow\DNS\ZoneBuilder; |
||
35 | use PHPUnit\Framework\TestCase; |
||
36 | |||
37 | class ParserTest extends TestCase |
||
38 | { |
||
39 | /** |
||
40 | * Build a test zone. |
||
41 | */ |
||
42 | private function getTestZone(): Zone |
||
43 | { |
||
44 | $zone = new Zone('example.com.'); |
||
45 | $zone->setDefaultTtl(3600); |
||
46 | |||
47 | $soa = new ResourceRecord(); |
||
48 | $soa->setName('@'); |
||
49 | $soa->setRdata(Factory::SOA( |
||
50 | 'example.com.', |
||
51 | 'post.example.com.', |
||
52 | 2014110501, |
||
53 | 3600, |
||
54 | 14400, |
||
55 | 604800, |
||
56 | 3600 |
||
57 | )); |
||
58 | |||
59 | $ns1 = new ResourceRecord(); |
||
60 | $ns1->setName('@'); |
||
61 | $ns1->setRdata(Factory::NS('ns1.nameserver.com.')); |
||
62 | |||
63 | $ns2 = new ResourceRecord(); |
||
64 | $ns2->setName('@'); |
||
65 | $ns2->setRdata(Factory::NS('ns2.nameserver.com.')); |
||
66 | |||
67 | $a = new ResourceRecord(); |
||
68 | $a->setName('sub.domain'); |
||
69 | $a->setRdata(Factory::A('192.168.1.42')); |
||
70 | $a->setComment('This is a local ip.'); |
||
71 | |||
72 | $a6 = new ResourceRecord(); |
||
73 | $a6->setName('ipv6.domain'); |
||
74 | $a6->setRdata(Factory::AAAA('::1')); |
||
75 | $a6->setComment('This is an IPv6 domain.'); |
||
76 | |||
77 | $mx1 = new ResourceRecord(); |
||
78 | $mx1->setName('@'); |
||
79 | $mx1->setRdata(Factory::MX(10, 'mail-gw1.example.net.')); |
||
80 | |||
81 | $mx2 = new ResourceRecord(); |
||
82 | $mx2->setName('@'); |
||
83 | $mx2->setRdata(Factory::MX(20, 'mail-gw2.example.net.')); |
||
84 | |||
85 | $mx3 = new ResourceRecord(); |
||
86 | $mx3->setName('@'); |
||
87 | $mx3->setRdata(Factory::MX(30, 'mail-gw3.example.net.')); |
||
88 | |||
89 | $dname = ResourceRecord::create('hq', Factory::Dname('syd.example.com.')); |
||
90 | |||
91 | $loc = new ResourceRecord(); |
||
92 | $loc->setName('canberra'); |
||
93 | $loc->setRdata(Factory::LOC( |
||
94 | -35.3075, //Lat |
||
95 | 149.1244, //Lon |
||
96 | 500, //Alt |
||
97 | 20.12, //Size |
||
98 | 200.3, //HP |
||
99 | 300.1 //VP |
||
100 | )); |
||
101 | $loc->setComment('This is Canberra'); |
||
102 | |||
103 | $zone->addResourceRecord($soa); |
||
104 | $zone->addResourceRecord($ns1); |
||
105 | $zone->addResourceRecord($ns2); |
||
106 | $zone->addResourceRecord($a); |
||
107 | $zone->addResourceRecord($a6); |
||
108 | $zone->addResourceRecord($dname); |
||
109 | $zone->addResourceRecord($mx1); |
||
110 | $zone->addResourceRecord($mx2); |
||
111 | $zone->addResourceRecord($mx3); |
||
112 | $zone->addResourceRecord($loc); |
||
113 | |||
114 | return $zone; |
||
115 | } |
||
116 | |||
117 | /** |
||
118 | * Parser creates valid dns object. |
||
119 | * |
||
120 | * @throws ParseException |
||
121 | */ |
||
122 | public function testParserCreatesValidDnsObject(): void |
||
123 | { |
||
124 | $zoneBuilder = new AlignedBuilder(); |
||
125 | $zone = $zoneBuilder->build($this->getTestZone()); |
||
126 | |||
127 | $expectation = $this->getTestZone(); |
||
128 | foreach ($expectation->getResourceRecords() as $rr) { |
||
129 | $rr->setTtl($rr->getTtl() ?? $expectation->getDefaultTtl()); |
||
130 | } |
||
131 | |||
132 | $actual = Parser::parse('example.com.', $zone, Comments::END_OF_ENTRY); |
||
133 | |||
134 | $this->assertEquals($expectation, $actual); |
||
135 | } |
||
136 | |||
137 | /** |
||
138 | * Parser ignores control entries other than TTL. |
||
139 | * |
||
140 | * @throws ParseException|\Exception |
||
141 | */ |
||
142 | public function testParserIgnoresControlEntriesOtherThanTtl(): void |
||
143 | { |
||
144 | $file = NormaliserTest::readFile(__DIR__.'/Resources/testCollapseMultilines_sample.txt'); |
||
145 | $zone = Parser::parse('example.com.', $file); |
||
146 | |||
147 | $this->assertEquals('example.com.', $zone->getName()); |
||
148 | $this->assertEquals('::1', self::findRecord('ipv6.domain', $zone)[0]->getRdata()->getAddress()); |
||
0 ignored issues
–
show
|
|||
149 | $this->assertEquals(1337, $zone->getDefaultTtl()); |
||
150 | } |
||
151 | |||
152 | /** |
||
153 | * Parser can handle convoluted zone record. |
||
154 | * |
||
155 | * @throws ParseException|\Exception |
||
156 | */ |
||
157 | public function testParserCanHandleConvolutedZoneRecord(): void |
||
158 | { |
||
159 | $file = NormaliserTest::readFile(__DIR__.'/Resources/testConvolutedZone_sample.txt'); |
||
160 | $zone = Parser::parse('example.com.', $file); |
||
161 | $this->assertEquals(3600, $zone->getDefaultTtl()); |
||
162 | $this->assertCount(28, $zone->getResourceRecords()); |
||
0 ignored issues
–
show
$zone->getResourceRecords() is of type array<integer,object<Badcow\DNS\ResourceRecord>> , but the function expects a object<Countable>|object...nit\Framework\iterable> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
163 | |||
164 | $txt = ResourceRecord::create( |
||
165 | 'testtxt', |
||
166 | Factory::TXT('v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBg'. |
||
167 | 'QDZKI3U+9acu3NfEy0NJHIPydxnPLPpnAJ7k2JdrsLqAK1uouMudHI20pgE8RMldB/TeW'. |
||
168 | 'KXYoRidcGCZWXleUzldDTwZAMDQNpdH1uuxym0VhoZpPbI1RXwpgHRTbCk49VqlC'), |
||
169 | 600, |
||
170 | Classes::INTERNET |
||
171 | ); |
||
172 | |||
173 | $txt2 = 'Some text another Some text'; |
||
174 | |||
175 | $this->assertEquals($txt, self::findRecord($txt->getName(), $zone)[0]); |
||
176 | $this->assertEquals($txt2, self::findRecord('test', $zone)[0]->getRdata()->getText()); |
||
0 ignored issues
–
show
It seems like you code against a concrete implementation and not the interface
Badcow\DNS\Rdata\RdataInterface as the method getText() does only exist in the following implementations of said interface: Badcow\DNS\Rdata\SPF , Badcow\DNS\Rdata\TXT .
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
177 | $this->assertCount(1, self::findRecord('xn----7sbfndkfpirgcajeli2a4pnc.xn----7sbbfcqfo2cfcagacemif0ap5q', $zone)); |
||
0 ignored issues
–
show
self::findRecord('xn----...cagacemif0ap5q', $zone) is of type array<integer,object<Badcow\DNS\ResourceRecord>> , but the function expects a object<Countable>|object...nit\Framework\iterable> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
178 | $this->assertCount(4, self::findRecord('testmx', $zone)); |
||
0 ignored issues
–
show
self::findRecord('testmx', $zone) is of type array<integer,object<Badcow\DNS\ResourceRecord>> , but the function expects a object<Countable>|object...nit\Framework\iterable> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
179 | } |
||
180 | |||
181 | /** |
||
182 | * @throws ParseException |
||
183 | */ |
||
184 | public function testCanHandlePolymorphicRdata(): void |
||
185 | { |
||
186 | $string = 'example.com. 7200 IN A6 2001:acad::1337; This is invalid.'; |
||
187 | $zone = Parser::parse('example.com.', $string); |
||
188 | $rr = $zone->getResourceRecords()[0]; |
||
189 | |||
190 | $rdata = $rr->getRdata(); |
||
191 | |||
192 | $this->assertNotNull($rdata); |
||
193 | |||
194 | if (null === $rdata) { |
||
195 | return; |
||
196 | } |
||
197 | |||
198 | $this->assertEquals('A6', $rdata->getType()); |
||
199 | $this->assertEquals('2001:acad::1337', $rdata->toText()); |
||
200 | } |
||
201 | |||
202 | /** |
||
203 | * @throws ParseException|\Exception |
||
204 | */ |
||
205 | public function testParserCanHandleAplRecords(): void |
||
206 | { |
||
207 | $file = NormaliserTest::readFile(__DIR__.'/Resources/testCollapseMultilines_sample.txt'); |
||
208 | $zone = Parser::parse('example.com.', $file); |
||
209 | |||
210 | /** @var APL $apl */ |
||
211 | $apl = self::findRecord('multicast', $zone)[0]->getRdata(); |
||
212 | $this->assertCount(2, $apl->getIncludedAddressRanges()); |
||
0 ignored issues
–
show
$apl->getIncludedAddressRanges() is of type array<integer,object<PhpIP\IPBlock>> , but the function expects a object<Countable>|object...nit\Framework\iterable> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
213 | $this->assertCount(2, $apl->getExcludedAddressRanges()); |
||
0 ignored issues
–
show
$apl->getExcludedAddressRanges() is of type array<integer,object<PhpIP\IPBlock>> , but the function expects a object<Countable>|object...nit\Framework\iterable> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
214 | |||
215 | $this->assertEquals('192.168.0.0/23', (string) $apl->getIncludedAddressRanges()[0]); |
||
216 | $this->assertEquals('2001:acad:1::8/128', (string) $apl->getExcludedAddressRanges()[1]); |
||
217 | } |
||
218 | |||
219 | /** |
||
220 | * @throws ParseException |
||
221 | */ |
||
222 | public function testParserCanHandleCaaRecords(): void |
||
223 | { |
||
224 | $text = <<<'TXT' |
||
225 | $ORIGIN EXAMPLE.COM. |
||
226 | $TTL 3600 |
||
227 | @ 10800 IN CAA 0 issue "letsencrypt.org" |
||
228 | TXT; |
||
229 | |||
230 | $zone = Parser::parse('example.com.', $text); |
||
231 | $this->assertCount(1, $zone); |
||
232 | /** @var CAA $caa */ |
||
233 | $caa = $zone->getResourceRecords()[0]->getRdata(); |
||
234 | |||
235 | $this->assertEquals('CAA', $caa->getType()); |
||
236 | $this->assertEquals(0, $caa->getFlag()); |
||
237 | $this->assertEquals('issue', $caa->getTag()); |
||
238 | $this->assertEquals('letsencrypt.org', $caa->getValue()); |
||
239 | } |
||
240 | |||
241 | /** |
||
242 | * @throws ParseException |
||
243 | */ |
||
244 | public function testParserCanHandleSshfpRecords(): void |
||
245 | { |
||
246 | $txt = 'host.example. IN SSHFP 2 1 123456789abcdef67890123456789abcdef67890'; |
||
247 | $zone = Parser::parse('example.', $txt); |
||
248 | |||
249 | $rrs = self::findRecord('host.example.', $zone, 'SSHFP'); |
||
250 | $sshfp = $rrs[0]->getRdata(); |
||
251 | |||
252 | $this->assertEquals(2, $sshfp->getAlgorithm()); |
||
253 | $this->assertEquals(1, $sshfp->getFingerprintType()); |
||
254 | $this->assertEquals(hex2bin('123456789abcdef67890123456789abcdef67890'), $sshfp->getFingerprint()); |
||
255 | } |
||
256 | |||
257 | /** |
||
258 | * @throws ParseException |
||
259 | */ |
||
260 | public function testParserCanHandleUriRecords(): void |
||
261 | { |
||
262 | $txt = '_ftp._tcp IN URI 10 1 "ftp://ftp1.example.com/public%20data"'; |
||
263 | $zone = Parser::parse('example.com.', $txt); |
||
264 | |||
265 | $rrs = self::findRecord('_ftp._tcp', $zone, 'URI'); |
||
266 | $uri = $rrs[0]->getRdata(); |
||
267 | |||
268 | $this->assertEquals(10, $uri->getPriority()); |
||
269 | $this->assertEquals(1, $uri->getWeight()); |
||
270 | $this->assertEquals('ftp://ftp1.example.com/public%20data', $uri->getTarget()); |
||
271 | } |
||
272 | |||
273 | /** |
||
274 | * @throws ParseException |
||
275 | */ |
||
276 | public function testMalformedAplRecordThrowsException1(): void |
||
277 | { |
||
278 | $zone = 'multicast 3600 IN APL 3:192.168.0.64/30'; |
||
279 | |||
280 | $this->expectException(ParseException::class); |
||
281 | |||
282 | Parser::parse('example.com.', $zone); |
||
283 | } |
||
284 | |||
285 | /** |
||
286 | * @throws ParseException |
||
287 | */ |
||
288 | public function testUnknownRdataTypeThrowsException(): void |
||
289 | { |
||
290 | $zone = 'resource 3600 IN XX f080:3024:a::1'; |
||
291 | |||
292 | $this->expectException(ParseException::class); |
||
293 | $this->expectExceptionMessage('Could not parse entry "resource 3600 IN XX f080:3024:a::1".'); |
||
294 | |||
295 | Parser::parse('acme.com.', $zone); |
||
296 | } |
||
297 | |||
298 | /** |
||
299 | * @throws ParseException |
||
300 | */ |
||
301 | public function testMalformedAplRecordThrowsException2(): void |
||
302 | { |
||
303 | $zone = 'multicast 3600 IN APL !1-192.168.0.64/30'; |
||
304 | |||
305 | $this->expectException(ParseException::class); |
||
306 | |||
307 | Parser::parse('example.com.', $zone); |
||
308 | } |
||
309 | |||
310 | /** |
||
311 | * @throws \Exception|ParseException |
||
312 | */ |
||
313 | public function testAmbiguousRecordsParse(): void |
||
314 | { |
||
315 | $file = NormaliserTest::readFile(__DIR__.'/Resources/ambiguous.acme.org.txt'); |
||
316 | $zone = Parser::parse('ambiguous.acme.org.', $file); |
||
317 | $mxRecords = self::findRecord('mx', $zone); |
||
318 | $a4Records = self::findRecord('aaaa', $zone); |
||
319 | |||
320 | $this->assertCount(3, $mxRecords); |
||
0 ignored issues
–
show
$mxRecords is of type array<integer,object<Badcow\DNS\ResourceRecord>> , but the function expects a object<Countable>|object...nit\Framework\iterable> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
321 | $this->assertCount(2, $a4Records); |
||
0 ignored issues
–
show
$a4Records is of type array<integer,object<Badcow\DNS\ResourceRecord>> , but the function expects a object<Countable>|object...nit\Framework\iterable> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
322 | foreach ($mxRecords as $rr) { |
||
323 | switch ($rr->getType()) { |
||
324 | case A::TYPE: |
||
325 | $this->assertEquals(900, $rr->getTtl()); |
||
326 | $this->assertEquals('200.100.50.35', $rr->getRdata()->getAddress()); |
||
0 ignored issues
–
show
It seems like you code against a concrete implementation and not the interface
Badcow\DNS\Rdata\RdataInterface as the method getAddress() does only exist in the following implementations of said interface: Badcow\DNS\Rdata\A , Badcow\DNS\Rdata\AAAA , Badcow\DNS\Tests\Rdata\a...tests/Rdata/ATest.php$0 , Badcow\DNS\Tests\Rdata\a...ts/Rdata/AaaaTest.php$0 .
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
327 | break; |
||
328 | case CNAME::TYPE: |
||
329 | $this->assertEquals(3600, $rr->getTtl()); |
||
330 | $this->assertEquals('aaaa', $rr->getRdata()->getTarget()); |
||
0 ignored issues
–
show
It seems like you code against a concrete implementation and not the interface
Badcow\DNS\Rdata\RdataInterface as the method getTarget() does only exist in the following implementations of said interface: Badcow\DNS\Rdata\CNAME , Badcow\DNS\Rdata\DNAME , Badcow\DNS\Rdata\NS , Badcow\DNS\Rdata\PTR , Badcow\DNS\Rdata\SRV , Badcow\DNS\Rdata\URI .
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
331 | break; |
||
332 | case TXT::TYPE: |
||
333 | $this->assertEquals(3600, $rr->getTtl()); |
||
334 | $this->assertEquals('Mail Exchange IPv6 Address', $rr->getRdata()->getText()); |
||
0 ignored issues
–
show
It seems like you code against a concrete implementation and not the interface
Badcow\DNS\Rdata\RdataInterface as the method getText() does only exist in the following implementations of said interface: Badcow\DNS\Rdata\SPF , Badcow\DNS\Rdata\TXT .
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
335 | break; |
||
336 | } |
||
337 | } |
||
338 | |||
339 | foreach ($a4Records as $rr) { |
||
340 | switch ($rr->getType()) { |
||
341 | case AAAA::TYPE: |
||
342 | $this->assertEquals(900, $rr->getTtl()); |
||
343 | $this->assertEquals('2001:acdc:5889::35', $rr->getRdata()->getAddress()); |
||
0 ignored issues
–
show
It seems like you code against a concrete implementation and not the interface
Badcow\DNS\Rdata\RdataInterface as the method getAddress() does only exist in the following implementations of said interface: Badcow\DNS\Rdata\A , Badcow\DNS\Rdata\AAAA , Badcow\DNS\Tests\Rdata\a...tests/Rdata/ATest.php$0 , Badcow\DNS\Tests\Rdata\a...ts/Rdata/AaaaTest.php$0 .
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
344 | break; |
||
345 | case TXT::TYPE: |
||
346 | $this->assertEquals(3600, $rr->getTtl()); |
||
347 | $this->assertEquals('This name is silly.', $rr->getRdata()->getText()); |
||
0 ignored issues
–
show
It seems like you code against a concrete implementation and not the interface
Badcow\DNS\Rdata\RdataInterface as the method getText() does only exist in the following implementations of said interface: Badcow\DNS\Rdata\SPF , Badcow\DNS\Rdata\TXT .
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
348 | break; |
||
349 | } |
||
350 | } |
||
351 | } |
||
352 | |||
353 | /** |
||
354 | * @throws ParseException |
||
355 | */ |
||
356 | public function testAmbiguousRecord(): void |
||
357 | { |
||
358 | $record = 'mx cname aaaa'; |
||
359 | $zone = Parser::parse('acme.com.', $record); |
||
360 | $mx = $zone->getResourceRecords()[0]; |
||
361 | |||
362 | $this->assertEquals(CNAME::TYPE, $mx->getType()); |
||
363 | $this->assertEquals('mx', $mx->getName()); |
||
364 | $this->assertEquals('aaaa', $mx->getRdata()->getTarget()); |
||
0 ignored issues
–
show
It seems like you code against a concrete implementation and not the interface
Badcow\DNS\Rdata\RdataInterface as the method getTarget() does only exist in the following implementations of said interface: Badcow\DNS\Rdata\CNAME , Badcow\DNS\Rdata\DNAME , Badcow\DNS\Rdata\NS , Badcow\DNS\Rdata\PTR , Badcow\DNS\Rdata\SRV , Badcow\DNS\Rdata\URI .
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
365 | } |
||
366 | |||
367 | /** |
||
368 | * @throws ParseException |
||
369 | */ |
||
370 | public function testUnknownRdataTypesAreParsed(): void |
||
371 | { |
||
372 | $entries = <<<DNS |
||
373 | a.example.com. CLASS32 TYPE731 \# 6 abcd ef 01 23 45 |
||
374 | b.example.com. HS TYPE62347 \# 0 |
||
375 | c.example.com. IN A \# 4 0A000001 |
||
376 | d.example.com. CLASS1 TYPE1 \# 4 0A 00 00 02 |
||
377 | DNS; |
||
378 | |||
379 | $zone = Parser::parse('example.com.', $entries); |
||
380 | $this->assertCount(4, $zone); |
||
381 | |||
382 | $a = self::findRecord('a.example.com.', $zone)[0]; |
||
383 | $this->assertEquals(731, $a->getRdata()->getTypeCode()); |
||
384 | $this->assertEquals(hex2bin('abcdef012345'), $a->getRdata()->getData()); |
||
0 ignored issues
–
show
It seems like you code against a concrete implementation and not the interface
Badcow\DNS\Rdata\RdataInterface as the method getData() does only exist in the following implementations of said interface: Badcow\DNS\Rdata\PolymorphicRdata , Badcow\DNS\Rdata\UnknownType .
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
385 | $this->assertEquals('CLASS32', $a->getClass()); |
||
386 | |||
387 | $b = self::findRecord('b.example.com.', $zone)[0]; |
||
388 | $this->assertEquals(62347, $b->getRdata()->getTypeCode()); |
||
389 | $this->assertEquals(null, $b->getRdata()->getData()); |
||
0 ignored issues
–
show
It seems like you code against a concrete implementation and not the interface
Badcow\DNS\Rdata\RdataInterface as the method getData() does only exist in the following implementations of said interface: Badcow\DNS\Rdata\PolymorphicRdata , Badcow\DNS\Rdata\UnknownType .
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
390 | |||
391 | $c = self::findRecord('c.example.com.', $zone)[0]; |
||
392 | $this->assertInstanceOf(A::class, $c->getRdata()); |
||
393 | $this->assertEquals('10.0.0.1', $c->getRdata()->getAddress()); |
||
0 ignored issues
–
show
It seems like you code against a concrete implementation and not the interface
Badcow\DNS\Rdata\RdataInterface as the method getAddress() does only exist in the following implementations of said interface: Badcow\DNS\Rdata\A , Badcow\DNS\Rdata\AAAA , Badcow\DNS\Tests\Rdata\a...tests/Rdata/ATest.php$0 , Badcow\DNS\Tests\Rdata\a...ts/Rdata/AaaaTest.php$0 .
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
394 | |||
395 | $d = self::findRecord('d.example.com.', $zone)[0]; |
||
396 | $this->assertInstanceOf(A::class, $d->getRdata()); |
||
397 | $this->assertEquals('10.0.0.2', $d->getRdata()->getAddress()); |
||
0 ignored issues
–
show
It seems like you code against a concrete implementation and not the interface
Badcow\DNS\Rdata\RdataInterface as the method getAddress() does only exist in the following implementations of said interface: Badcow\DNS\Rdata\A , Badcow\DNS\Rdata\AAAA , Badcow\DNS\Tests\Rdata\a...tests/Rdata/ATest.php$0 , Badcow\DNS\Tests\Rdata\a...ts/Rdata/AaaaTest.php$0 .
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
398 | } |
||
399 | |||
400 | /** |
||
401 | * @throws ParseException |
||
402 | */ |
||
403 | public function testParserRecognisesHumanReadableTimeFormats(): void |
||
404 | { |
||
405 | $record = <<<DNS |
||
406 | \$TTL 1h1m3s |
||
407 | badcow.co. 1h5m IN SOA ns.badcow.co. hostmaster.badcow.co. ( |
||
408 | 2020070101 ; serial |
||
409 | 3h10s ; refresh |
||
410 | 59m ; retry |
||
411 | 4w1d ; expire |
||
412 | 1h ; minimum |
||
413 | ) |
||
414 | overflow 615000000w IN A 4.3.2.1 |
||
415 | numeric 12345 IN A 9.9.9.9 |
||
416 | DNS; |
||
417 | $zone = Parser::parse('badcow.co.', $record); |
||
418 | $this->assertEquals(3663, $zone->getDefaultTtl()); |
||
419 | $this->assertCount(3, $zone); |
||
420 | |||
421 | $this->assertEquals(3900, $zone[0]->getTtl()); |
||
422 | $soa = $zone[0]->getRdata(); |
||
423 | $this->assertEquals(10810, $soa->getRefresh()); |
||
424 | $this->assertEquals(3540, $soa->getRetry()); |
||
425 | $this->assertEquals(2505600, $soa->getExpire()); |
||
426 | $this->assertEquals(3600, $soa->getMinimum()); |
||
427 | |||
428 | $this->assertEquals(0, $zone[1]->getTtl()); |
||
429 | $this->assertEquals(12345, $zone[2]->getTtl()); |
||
430 | |||
431 | // Ensure coverage |
||
432 | $this->assertEquals('1w4d13h46m39s', TimeFormat::toHumanReadable(999999)); |
||
433 | $this->assertEquals('1h', TimeFormat::toHumanReadable(3600)); |
||
434 | } |
||
435 | |||
436 | /** |
||
437 | * @throws ParseException |
||
438 | */ |
||
439 | public function testParserRecognisesResourceNameOnRrsigRecords(): void |
||
440 | { |
||
441 | $record = <<<DNS |
||
442 | dns.badcow.co. 3600 IN SOA ns.badcow.co. hostmaster.badcow.co. ( |
||
443 | 2020010101 ; serial |
||
444 | 10800 ; refresh (3 hours) |
||
445 | 3600 ; retry (1 hour) |
||
446 | 2419200 ; expire (4 weeks) |
||
447 | 3600 ; minimum (1 hour) |
||
448 | ) |
||
449 | 3600 RRSIG A 4 2 86400 ( |
||
450 | 20050322173103 20030220173103 2642 example.com. |
||
451 | oJB1W6WNGv+ldvQ3WDG0MQkg5IEhjRip |
||
452 | 8WTrPYGv07h108dUKGMeDPKijVCHX3DD |
||
453 | Kdfb+v6oB9wfuh3DTJXUAfI/M0zmO/zz |
||
454 | 8bW0Rznl8O3tGNazPwQKkRN20XPXV6nw |
||
455 | wfoXmJQbsLNrLfkGJ5D6fwFm8nN+6pBz |
||
456 | eDQfsS3Ap3o= ) |
||
457 | DNS; |
||
458 | |||
459 | $expectedSignature = base64_decode('oJB1W6WNGv+ldvQ3WDG0MQkg5IEhjRip8WTrPYGv07h108dUKGMeDPKijVCHX3DDKdfb+v6oB9wfuh3DTJXUAfI/'. |
||
460 | 'M0zmO/zz8bW0Rznl8O3tGNazPwQKkRN20XPXV6nwwfoXmJQbsLNrLfkGJ5D6fwFm8nN+6pBzeDQfsS3Ap3o='); |
||
461 | $expectedExpiration = \DateTime::createFromFormat(RRSIG::TIME_FORMAT, '20050322173103'); |
||
462 | $expectedInception = \DateTime::createFromFormat(RRSIG::TIME_FORMAT, '20030220173103'); |
||
463 | |||
464 | $zone = Parser::parse('badcow.co.', $record); |
||
465 | |||
466 | $this->assertCount(2, $zone); |
||
467 | /** @var ResourceRecord $rr */ |
||
468 | $rr = $zone[1]; |
||
469 | |||
470 | $this->assertEquals('dns.badcow.co.', $rr->getName()); |
||
471 | $this->assertEquals(3600, $rr->getTtl()); |
||
472 | /** @var RRSIG $rrsig */ |
||
473 | $rrsig = $rr->getRdata(); |
||
474 | $this->assertInstanceOf(RRSIG::class, $rrsig); |
||
475 | $this->assertEquals('A', $rrsig->getTypeCovered()); |
||
476 | $this->assertEquals(Algorithms::ECC, $rrsig->getAlgorithm()); |
||
477 | $this->assertEquals(2, $rrsig->getLabels()); |
||
478 | $this->assertEquals(86400, $rrsig->getOriginalTtl()); |
||
479 | $this->assertEquals($expectedExpiration, $rrsig->getSignatureExpiration()); |
||
480 | $this->assertEquals($expectedInception, $rrsig->getSignatureInception()); |
||
481 | $this->assertEquals(2642, $rrsig->getKeyTag()); |
||
482 | $this->assertEquals('example.com.', $rrsig->getSignersName()); |
||
483 | $this->assertEquals($expectedSignature, $rrsig->getSignature()); |
||
484 | } |
||
485 | |||
486 | /** |
||
487 | * Tests if a control entry on a zone file will overwrite the initial parameter in Parser::parse(). |
||
488 | * |
||
489 | * @throws \Exception |
||
490 | */ |
||
491 | public function testParserDoesNotOverwritesZoneNameIfOriginControlEntryIsDifferent(): void |
||
492 | { |
||
493 | $file = NormaliserTest::readFile(__DIR__.'/Resources/testCollapseMultilines_sample.txt'); |
||
494 | $zone = Parser::parse('test.com.', $file); |
||
495 | |||
496 | $this->assertEquals('test.com.', $zone->getName()); |
||
497 | } |
||
498 | |||
499 | /** |
||
500 | * Find all records in a Zone named $name. |
||
501 | * |
||
502 | * @return ResourceRecord[] |
||
503 | */ |
||
504 | public static function findRecord(?string $name, Zone $zone, ?string $type = 'ANY'): array |
||
505 | { |
||
506 | $records = []; |
||
507 | |||
508 | foreach ($zone->getResourceRecords() as $resourceRecord) { |
||
509 | if ($name === $resourceRecord->getName() && ('ANY' === $type || $type === $resourceRecord->getType())) { |
||
510 | $records[] = $resourceRecord; |
||
511 | } |
||
512 | } |
||
513 | |||
514 | return $records; |
||
515 | } |
||
516 | |||
517 | /** |
||
518 | * Parser handles multiple $ORIGINS. |
||
519 | * |
||
520 | * @throws ParseException|\Exception |
||
521 | */ |
||
522 | public function testParserHandlesMultipleOrigins(): void |
||
523 | { |
||
524 | $file = NormaliserTest::readFile(__DIR__.'/Resources/multipleOrigins.txt'); |
||
525 | $expectation = NormaliserTest::readFile(__DIR__.'/Resources/multipleOrigins_expectation.txt'); |
||
526 | $zone = Parser::parse('mydomain.biz.', $file); |
||
527 | |||
528 | $this->assertEquals('mydomain.biz.', $zone->getName()); |
||
529 | $this->assertEquals(3600, $zone->getDefaultTtl()); |
||
530 | |||
531 | $this->assertEquals($expectation, ZoneBuilder::build($zone)); |
||
532 | } |
||
533 | |||
534 | /** |
||
535 | * Parser handles $ORIGIN . correctly. |
||
536 | * |
||
537 | * @throws ParseException|\Exception |
||
538 | */ |
||
539 | public function testParserHandlesOriginDot(): void |
||
540 | { |
||
541 | $file = NormaliserTest::readFile(__DIR__.'/Resources/testOriginDot_sample.txt'); |
||
542 | $expectation = NormaliserTest::readfile(__DIR__.'/Resources/testOriginDot_expectation.txt'); |
||
543 | |||
544 | $zone = Parser::parse('otherdomain.biz.', $file); |
||
545 | $this->assertEquals('otherdomain.biz.', $zone->getName()); |
||
546 | |||
547 | ZoneBuilder::fillOutZone($zone); |
||
548 | $this->assertEquals($expectation, ZoneBuilder::build($zone)); |
||
549 | } |
||
550 | |||
551 | public function dp_testParserHandlesIncludeDirective(): array |
||
552 | { |
||
553 | $baseDir = __DIR__.'/Resources/IncludeControlEntryTests/'; |
||
554 | |||
555 | return [ |
||
556 | ['mydomain.biz.', 3600, $baseDir.'mydomain.biz.db', $baseDir.'mydomain.biz_expectation.db', Comments::ALL], |
||
557 | ['testdomain.geek.', 7200, $baseDir.'testdomain.geek.db', $baseDir.'testdomain.geek_expectation.db', Comments::NONE], |
||
558 | ]; |
||
559 | } |
||
560 | |||
561 | /** |
||
562 | * Parser imports files specified by the $INCLUDE directive. |
||
563 | * |
||
564 | * @dataProvider dp_testParserHandlesIncludeDirective |
||
565 | * |
||
566 | * @throws ParseException|\Exception |
||
567 | */ |
||
568 | public function testParserHandlesIncludeDirective(string $zoneName, int $ttl, string $zoneFilePath, string $expectationPath, int $commentOptions): void |
||
569 | { |
||
570 | $zoneFetcher = new class() implements ZoneFileFetcherInterface { |
||
571 | public function fetch(string $path): string |
||
572 | { |
||
573 | return file_get_contents(__DIR__.'/Resources/IncludeControlEntryTests/'.$path); |
||
574 | } |
||
575 | }; |
||
576 | |||
577 | $file = NormaliserTest::readFile($zoneFilePath); |
||
578 | $expectation = NormaliserTest::readFile($expectationPath); |
||
579 | $zone = (new Parser([], $zoneFetcher))->makeZone($zoneName, $file, $commentOptions); |
||
580 | |||
581 | $this->assertEquals($zoneName, $zone->getName()); |
||
582 | $this->assertEquals($ttl, $zone->getDefaultTtl()); |
||
583 | |||
584 | $this->assertEquals($expectation, ZoneBuilder::build($zone)); |
||
585 | } |
||
586 | |||
587 | public function testIssue89(): void |
||
588 | { |
||
589 | $zone = Parser::parse('tld.', "\$ORIGIN tld.\nzone.tld. 900 IN TXT 3600"); |
||
590 | |||
591 | $this->assertCount(1, $zone); |
||
592 | $rr = $zone[0]; |
||
593 | |||
594 | $this->assertEquals('zone.tld.', $rr->getName()); |
||
595 | $this->assertEquals(900, $rr->getTtl()); |
||
596 | $this->assertEquals(Classes::INTERNET, $rr->getClass()); |
||
597 | $this->assertEquals('3600', $rr->getRdata()->getText()); |
||
598 | } |
||
599 | } |
||
600 |
Let’s take a look at an example:
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.
Available Fixes
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the interface: