Badcow /
DNS
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);
Loading history...
|
|||
| 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.
Loading history...
|
|||
| 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);
Loading history...
|
|||
| 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);
Loading history...
|
|||
| 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);
Loading history...
|
|||
| 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);
Loading history...
|
|||
| 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);
Loading history...
|
|||
| 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);
Loading history...
|
|||
| 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.
Loading history...
|
|||
| 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.
Loading history...
|
|||
| 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.
Loading history...
|
|||
| 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.
Loading history...
|
|||
| 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.
Loading history...
|
|||
| 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.
Loading history...
|
|||
| 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.
Loading history...
|
|||
| 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.
Loading history...
|
|||
| 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.
Loading history...
|
|||
| 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.
Loading history...
|
|||
| 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: