You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

162 lines
3.5 KiB

<?php
abstract class SVCBTypes {
const Mandatory = 0;
const Alpn = 1;
const No_default_alpn = 2;
const Port = 3;
const Ipv4hint = 4;
const Echconfig = 5;
const Ipv6hint = 6;
}
class SVCB_RR {
public $svcfieldpriority = 0;
public $name = '.';
public $port = 0;
public $ipv4_hints = [];
public $ipv6_hints = [];
public $alpn = [];
public $no_default_alpn = 0;
public $echconfig = '';
public function __toString(){
$r = [];
$r[] = $this->svcfieldpriority;
if(empty($this->name))
return false;
$r[] = $this->name;
if(!empty($this->ipv4_hints))
$r[] = 'ipv4hint=' . join($this->ipv4_hints, ',');
if(!empty($this->ipv6_hints))
$r[] = 'ipv6hint=' . join($this->ipv6_hints, ',');
if(!empty($this->alpn))
$r[] = 'alpn=' . join($this->alpn, ',');
return join($r, ' ');
}
}
function unpackTake($msg, $offset, $length){
$s = substr($msg, $offset, $length);
return [$offset+=$length, $s];
}
function unpackUint16($msg, $offset){
[$offset, $r] = unpackTake($msg, $offset, 2);
return [$offset, unpack('n', $r)[1]];
}
function unpackUint32($msg, $offset){
[$offset, $r] = unpackTake($msg, $offset, 4);
return [$offset, unpack('N', $r)[1]];
}
function unpackUint8($msg, $offset){
[$offset, $r] = unpackTake($msg, $offset, 1);
return [$offset, unpack('C', $r)[1]];
}
function parseName($msg, $offset, $dot = true){
$s = '';
while($offset < strlen($msg)){
$c = ord($msg[$offset]);
$offset++;
switch($c){
case 0x00:
if($c == 0x00)
break 2;
[$offset, $r] = unpackTake($msg, $offset, $c);
$s .= $r;
break;
case 0xc0:
break;
}
}
return [$offset, $s . ($dot === true) ? '.' : ''];
}
function parseSVCB($msg, $offset){
$record = new SVCB_RR();
[$offset, $SvcFieldPriority] = unpackUint16($msg, $offset);
[$offset, $name] = parseName($msg, $offset);
$record->svcfieldpriority = $SvcFieldPriority;
$record->name = $name;
while(true) {
[$offset, $SvcParamKey] = unpackUint16($msg, $offset);
[$offset, $SvcParamValueLen] = unpackUint16($msg, $offset);
switch($SvcParamKey){
case SVCBTypes::Alpn:
$o = 0;
[$offset, $alpn] = unpackTake($msg, $offset, $SvcParamValueLen);
while($o < strlen($alpn)){
[$o, $l] = unpackUint8($alpn, $o);
[$o, $a] = unpackTake($alpn, $o, $l);
$record->alpn[] = $a;
}
break;
case SVCBTypes::No_default_alpn:
[$offset, $nodefaultalpn] = unpackTake($msg, $offset, $SvcParamValueLen);
break;
case SVCBTypes::Port:
[$offset, $port] = unpackTake($msg, $offset, $SvcParamValueLen);
$record->port = $port;
break;
case SVCBTypes::Ipv4hint:
$o = 0;
[$offset, $ipv4hint] = unpackTake($msg, $offset, $SvcParamValueLen);
while($o < strlen($ipv4hint)){
[$o, $ip] = unpackTake($ipv4hint, $o, 4);
$record->ipv4_hints[] = inet_ntop($ip);
}
break;
case SVCBTypes::Echconfig:
[$offset, $echconfig] = unpackTake($msg, $offset, $SvcParamValueLen);
break;
case SVCBTypes::Ipv6hint:
$o = 0;
[$offset, $ipv6hint] = unpackTake($msg, $offset, $SvcParamValueLen);
while($o < strlen($ipv6hint)){
[$o, $ip] = unpackTake($ipv6hint, $o, 16);
$record->ipv6_hints[] = inet_ntop($ip);
}
break;
default:
$offset+=$SvcParamValueLen;
}
if($offset >= strlen($msg))
break;
}
return [$offset, $record];
}
$msg = hex2bin('00010000010003026832000400086812045168120551000600202606470000000000000000006812045126064700000000000000000068120551');
$offset = 0;
[$offset, $record] = parseSVCB($msg, 0);
echo $record, "\n";