sThread
[ class tree: sThread ] [ index: sThread ] [ all elements ]

Source for file dns.php

Documentation is available at dns.php

  1. <?php
  2. /**
  3.  * sThread DNS module
  4.  *
  5.  * @category    Network
  6.  * @package     sThread
  7.  * @subpackage  sThread_Module
  8.  * @author      JoungKyun.Kim <http://oops.org>
  9.  * @copyright   (c) 2015 OOPS.ORG
  10.  * @license     BSD License
  11.  * @version     $Id$
  12.  * @link        http://pear.oops.org/package/sThread
  13.  * @see         http://www.freesoft.org/CIE/RFC/1035/39.htm
  14.  * @filesource
  15.  */
  16.  
  17. /**
  18.  * DNS module Class
  19.  *
  20.  * DNS 모듈에 사용할 수 있는 모듈 option은 다음과 같다.
  21.  *
  22.  * <ul>
  23.  *     <li><b>query:</b> 질의할 도메인 또는 IP주소</li>
  24.  *     <li><b>record:</b> 질의할 record type</li>
  25.  * </ul>
  26.  *
  27.  * 예제:
  28.  * <code>
  29.  *   sThread::execute ('kns.kornet.net:53|query=>a.com,record=>A', 2, 'udp');
  30.  * </code>
  31.  *
  32.  * @category    Network
  33.  * @package     sThread
  34.  * @subpackage  sThread_Module
  35.  * @author      JoungKyun.Kim <http://oops.org>
  36.  * @copyright   (c) 2015 OOPS.ORG
  37.  * @license     BSD License
  38.  * @link        http://pear.oops.org/package/sThread
  39.  * @see         http://www.freesoft.org/CIE/RFC/1035/39.htm
  40.  */
  41. Class sThread_DNS {
  42.     // {{{ Base properties
  43.     /**#@+
  44.      * @access public
  45.      */
  46.     /**
  47.      * 이 변수의 값이 true로 셋팅이 되면, clear_session
  48.      * method를 만들어 줘야 한다. 반대로 false 상태에서는
  49.      * clear_session method가 존재하지 않아도 상관이 없다.
  50.      *
  51.      * @var bool 
  52.      */
  53.     static public $clearsession;
  54.     /**
  55.      * DNS 모듈이 사용하는 protocol
  56.      * @var string 
  57.      */
  58.     static public $protocol;
  59.     /**
  60.      * DNS 모듈이 사용하는 기본 포트 번호
  61.      * @var int 
  62.      */
  63.     static public $port;
  64.  
  65.     const DNS_REQUEST  1;
  66.     const DNS_RESPONSE 2;
  67.     const DNS_CLOSE    3;
  68.     /**#@-*/
  69.     // }}}
  70.  
  71.     // {{{ Per module properties
  72.     /**#@+
  73.      * @access private
  74.      * @see http://msdn.microsoft.com/en-us/library/windows/desktop/cc982162(v=vs.85).aspx
  75.      */
  76.     const OP_QUERY  0x00;
  77.     const OP_IQUERY 0x01;
  78.     const OP_STATUS 0x02;
  79.     const OP_UPDATE 0x05;
  80.  
  81.     const QTYPE_A     1;
  82.     const QTYPE_NS    2;
  83.     const QTYPE_CNAME 5;
  84.     const QTYPE_SOA   6;
  85.     const QTYPE_PTR   12;
  86.     const QTYPE_HINFO 13;
  87.     const QTYPE_MX    15;
  88.     const QTYPE_TXT   16;
  89.     const QTYPE_SIG   24;
  90.     const QTYPE_KEY   25;
  91.     const QTYPE_AAAA  28;
  92.     const QTYPE_SPF   99;
  93.     const QTYPE_TSIG  250;
  94.     const QTYPE_IXFR  251;
  95.     const QTYPE_AXFR  252;
  96.     const QTYPE_ANY   255;
  97.  
  98.     const QCLASS_IN   1;
  99.     const QCLASS_CH   3;
  100.     const QCLASS_HS   4;
  101.     const QCLASS_NONE 254;
  102.     const QCLASS_ANY  255;
  103.  
  104.     static private $header_member array ('id''flags''noq''noans''noauth''noadd');
  105.     static private $dns;
  106.     /**#@-*/
  107.     // }}}
  108.  
  109.     // {{{ (void) sThread_DNS::__construct (void)
  110.     /**
  111.      * Class OOP 형식 초기화 메소드
  112.      * @access public
  113.      * @return sThread_DNS 
  114.      */
  115.     function __construct ({
  116.         self::init ();
  117.         $this->clearsession = &self::$clearsession;
  118.         $this->port         = &self::$port;
  119.         $this->protocol     = &self::$protocol;
  120.         $this->dns          &self::$dns;
  121.     }
  122.     // }}}
  123.  
  124.     // {{{ (void) sThread_DNS::init (void)
  125.     /**
  126.      * dns 모듈을 초기화 한다.
  127.      *
  128.      * @access public
  129.      * @return void 
  130.      */
  131.     function init ({
  132.         self::$clearsession true;
  133.         self::$port         53;
  134.         self::$protocol     'udp';
  135.     }
  136.     // }}}
  137.  
  138.     // {{{ (int) sThread_DNS::check_buf_status ($status)
  139.     /**
  140.      * 현재 상태가 event read 상태인지 event write 상태인지
  141.      * 를 판단한다.
  142.      *
  143.      * @access public
  144.      * @return int 
  145.      * @param  int    현재 status
  146.      */
  147.     function check_buf_status ($status{
  148.         switch ($status{
  149.             case :
  150.             case self::DNS_REQUEST :
  151.                 return Vari::EVENT_READY_SEND;
  152.                 break;
  153.             case self::DNS_RESPONSE :
  154.                 return Vari::EVENT_READY_RECV;
  155.                 break;
  156.             case self::DNS_CLOSE :
  157.                 return Vari::EVENT_READY_CLOSE;
  158.                 break;
  159.             default :
  160.                 return Vari::EVENT_UNKNOWN;
  161.         }
  162.     }
  163.     // }}}
  164.  
  165.     // {{{ (string) sThread_DNS::call_status ($status, $call = false)
  166.     /**
  167.      * 현재의 status(integer) 또는 현재 status의 handler 이름을
  168.      * 반환한다.
  169.      *
  170.      * @access public
  171.      * @return int|string
  172.      * @param  int        현재 status
  173.      * @param  boolean    true로 설정했을 경우 현재 status의 handler
  174.      *                     이름을 반환한다.
  175.      */
  176.     function call_status ($status$call false{
  177.         switch ($status{
  178.             case self::DNS_REQUEST :
  179.                 $r 'DNS_REQUEST';
  180.                 break;
  181.             case self::DNS_RESPONSE :
  182.                 $r 'DNS_RESPONSE';
  183.                 break;
  184.             default:
  185.                 $r Vari::EVENT_UNKNOWN;
  186.         }
  187.  
  188.         if $call !== false && $r !== Vari::EVENT_UNKNOWN )
  189.             $r strtolower ($r);
  190.  
  191.         return $r;
  192.     }
  193.     // }}}
  194.  
  195.     // {{{ (boolean) sThread_DNS::change_status (&$sess, $key)
  196.     /**
  197.      * 세션의 상태를 단계로 변경한다.
  198.      *
  199.      * @access public
  200.      * @param  boolean  변경한 상태가 마지막 단계일 경우 false를
  201.      *                   반환한다.
  202.      * @param  stdClass sThread 세션 변수 reference
  203.      * @param  int      세션 키
  204.      */
  205.     function change_status (&$sess$key{
  206.         ++$sess->status[$key];
  207.  
  208.         if $sess->status[$key=== self::DNS_CLOSE )
  209.             return false;
  210.  
  211.         return true;
  212.     }
  213.     // }}}
  214.  
  215.     // {{{ (void) sThread_DNS::set_last_status (&$sess, $key)
  216.     /**
  217.      * 세션의 상태를 마지막 단계로 변경한다.
  218.      *
  219.      * @access public
  220.      * @param  stdClass sThread 세션 변수 reference
  221.      * @param  int      세션 키
  222.      */
  223.     function set_last_status (&$sess$key{
  224.         $sess->status[$keyself::DNS_CLOSE;
  225.     }
  226.     // }}}
  227.  
  228.     // {{{ (boolean) sThread_DNS::clear_session ($key) {
  229.     /**
  230.      * session에서 사용한 변수(self::$sess)의 값을 정리한다.
  231.      *
  232.      * self::$clearsession == false 일 경우, clear_session method
  233.      * 는 존재하지 않아도 된다.
  234.      *
  235.      * @access public
  236.      * @return void 
  237.      * @param  int    세션 키
  238.      */
  239.     function clear_session ($key{
  240.         // self::$dns 자체는 unset되지 않고, member들만 unset
  241.         Vari::objectUnset (self::$dns);
  242.         return;
  243.     }
  244.     // }}}
  245.  
  246.     /*
  247.      * Handler 정의
  248.      *
  249.      * Handler는 call_status 메소드에 정의된 값들 중
  250.      * Vari::EVENT_UNKNOWN를 제외한 모든 status의 constant string을
  251.      * 소문자로해서 만들어야 한다.
  252.      *
  253.      * Handler 이름은 sThread_MODULE::call_status 메소드를
  254.      * 통해서 구할 수 있다.
  255.      *
  256.      * handler는 다음의 구조를 가지며, 실제로 전송을 하거나 받는
  257.      * 것은 libevent가 한다.
  258.      *
  259.      * write handler:
  260.      *       handler_name (&$ses, $key)
  261.      *
  262.      *       write handler를 실제로 전송을 하지 않고 전송할
  263.      *       데이터를 생성해서 반환만 한다.
  264.      *
  265.      * read handler:
  266.      *       handler_name (&$sess, $key, $recv) 
  267.      *
  268.      *       read handler의 반환값은 다음과 같이 지정을 해야 한다.
  269.      *
  270.      *       true  => 모든 전송이 완료
  271.      *       false => 전송 받을 것이 남아 있음
  272.      *       null  => 전송 중 에러 발생
  273.      *
  274.      *       이 의미는 sThread가 read handler에서 결과값에 따라
  275.      *       true는 다음 단계로 전환을 하고, false는 현 status를
  276.      *       유지하며, null의 경우 connection을 종료를 한다.
  277.      */
  278.  
  279.     // {{{ (string) sThread_DNS::dns_request (&$sess, $key)
  280.     /**
  281.      * DNS로 전송할 질의 데이터를 반환
  282.      *
  283.      * @access public
  284.      * @return void 
  285.      * @param  stdClass 세션 object
  286.      * @param  int      세션 키
  287.      */
  288.     function dns_request (&$sess$key{
  289.         list ($host$port$type$sess->addr[$key];
  290.         $opt $sess->opt[$key];
  291.  
  292.  
  293.         if $opt->query {
  294.             Vari::$res->status[$keyarray (
  295.                 "{$host}:{$port}",
  296.                 false,
  297.                 "[DNS] Query domain is null"
  298.             );
  299.             return false;
  300.         }
  301.  
  302.         if $opt->record )
  303.             $opt->record 'A';
  304.  
  305.         switch ($opt->record{
  306.             case 'A' :
  307.                 $opt->record self::QTYPE_A;
  308.                 break;
  309.             case 'MX' :
  310.                 $opt->record self::QTYPE_MX;
  311.                 break;
  312.             case 'PTR' :
  313.                 $opt->record self::QTYPE_PTR;
  314.                 break;
  315.             case 'NS' :
  316.                 $opt->record self::QTYPE_NS;
  317.                 break;
  318.             case 'CNAME' :
  319.                 $opt->record self::QTYPE_CNAME;
  320.                 break;
  321.             case 'SOA' :
  322.                 $opt->record self::QTYPE_SOA;
  323.                 break;
  324.             case 'TXT' :
  325.                 $opt->record self::QTYPE_TXT;
  326.                 break;
  327.             case 'AAAA' :
  328.                 $opt->record self::QTYPE_AAAA;
  329.                 break;
  330.             default :
  331.                 $err sprintf ('[DNS] Invalid query type : "%s"'$opt->record);
  332.                 Vari::$res->status[$keyarray (
  333.                     "{$host}:{$port}"false$err
  334.                 );
  335.                 return false;
  336.         }
  337.  
  338.         $send self::query ($key$opt->query$opt->record);
  339.         if $send === false {
  340.             Vari::$res->status[$keyarray (
  341.                 "{$host}:{$port}"falseself::$dns[$key]->err
  342.             );
  343.             return false;
  344.         }
  345.  
  346.         return $send->data;
  347.     }
  348.     // }}}
  349.  
  350.     // {{{ (boolean) sThread_DNS::dns_response (&$sess, $key, $recv)
  351.     /**
  352.      * 서버의 응답을 확인
  353.      *
  354.      * @access public
  355.      * @return bool|null결과 값은 다음과 같다.
  356.      *      <ul>
  357.      *          <li>true:  모든 전송이 완료</li>
  358.      *          <li>false: 전송할 것이 남아 있음. readcallback에서
  359.      *                     false를 받으면 status를 유지한다.</li>
  360.      *          <li>null:  전송 중 에러 발생</li>
  361.      *      </ul>
  362.      * @param  stdClass 세션 object
  363.      * @param  int      세션 키
  364.      * @param  mixed    read callback에서 전송받은 누적 데이터
  365.      */
  366.     function dns_response (&$sess$key$recv{
  367.         if $recv )
  368.             return false;
  369.  
  370.         list ($host$port$type$sess->addr[$key];
  371.         $sess->recv[$key.= $recv;
  372.         $rlen strlen ($sess->recv[$key]);
  373.  
  374.         // at least, dns header size is 32byte
  375.         if $rlen 32 )
  376.             return false;
  377.  
  378.         Vari::objectInit (self::$dns[$key]->recv);
  379.         self::$dns[$key]->recv->data $sess->recv[$key];
  380.         self::$dns[$key]->recv->length $rlen;
  381.  
  382.         //if ( ($r = self::recv_header ($key, $sess->recv[$key])) === false ) {
  383.         if ( ($r self::recv_parse ($key$sess->recv[$key])) === false {
  384.             Vari::$res->status[$keyarray (
  385.                 "{$host}:{$port}",
  386.                 false,
  387.                 self::$dns[$key]->err
  388.             );
  389.             Vari::binaryDecode ($sess->recv[$key]true);
  390.             return null;
  391.         }
  392.  
  393.         if self::$dns[$key]->recv->header->flags->rcode != 'NOERROR' {
  394.             $err sprintf ('[DNS] Return RCODE flag "%s"'self::$dns[$key]->recv->header->flags->rcode);
  395.             Vari::$res->status[$keyarray ("{$host}:{$port}"false$err);
  396.             Vari::binaryDecode ($sess->recv[$key]true);
  397.             return null;
  398.         }
  399.  
  400.         if self::$dns[$key]->recv->header->noans == {
  401.             $err '[DNS] No return result';
  402.             Vari::$res->status[$keyarray ("{$host}:{$port}"false$err);
  403.             Vari::binaryDecode ($sess->recv[$key]true);
  404.             return null;
  405.         }
  406.  
  407.         // check
  408.         if Vari::$result === true {
  409.             unset (self::$dns[0]->recv->resource->data);
  410.             $sess->data[$keyself::$dns[$key]->recv->resource;
  411.         }
  412.  
  413.         $sess->recv[$key'';
  414.         return true;
  415.     // }}}
  416.  
  417.  
  418.     /*
  419.      * ********************************************************************************
  420.      * User define functions
  421.      * ********************************************************************************
  422.      */
  423.  
  424.     /*
  425.      * DNS packet header
  426.      */
  427.     // {{{ private (binary|string) sThread_DNS::random_id ($encode = false)
  428.     private function random_id ($encode false{
  429.         $id mt_rand (065535);
  430.         return $encode pack ('n'$id$id;
  431.     // }}}
  432.  
  433.     // {{{ private (string) sThread_DNS::query_type ($v, $convert = false)
  434.     // if $convert set false, don't convert to decimal
  435.     private function query_type ($v$convert true{
  436.         if $convert {
  437.             $buf unpack ('n'$v);
  438.             $v $buf[1];
  439.         }
  440.  
  441.         switch ($v{
  442.             case self::QTYPE_A :
  443.                 return 'A';
  444.             case self::QTYPE_NS :
  445.                 return 'NS';
  446.             case self::QTYPE_CNAME :
  447.                 return 'CNAME';
  448.             case self::QTYPE_PTR :
  449.                 return 'PTR';
  450.             case self::QTYPE_SOA :
  451.                 return 'SOA';
  452.             case self::QTYPE_HINFO:
  453.                 return 'HINFO';
  454.             case self::QTYPE_MX:
  455.                 return 'MX';
  456.             case self::QTYPE_TXT:
  457.                 return 'TXT';
  458.             case self::QTYPE_AAAA:
  459.                 return 'AAAA';
  460.             default:
  461.                 return sprintf ('Unknown: 0x%02x'$v);
  462.         }
  463.     // }}}
  464.  
  465.     // {{{ private (void) sThread_DNS::query_class ($v, $convert = false)
  466.     // if $convert set true, convert binary code
  467.     private function query_class ($v$convert true{
  468.         if $convert {
  469.             $buf unpack ('n'$v);
  470.             $v $buf[1];
  471.         }
  472.  
  473.         switch ($v{
  474.             case self::QCLASS_IN :
  475.                 return 'IN';
  476.             case self::QCLASS_CH :
  477.                 return 'CH';
  478.             case self::QCLASS_HS :
  479.                 return 'HS';
  480.             default :
  481.                 if $v )
  482.                     return sprintf ('Unknown: 0x%02x'$v);
  483.                 else
  484.                     return sprintf ('Reserved: 0x%02x'$v);
  485.         }
  486.     // }}}
  487.  
  488.     /* {{{ private (void) sThread_DNS::make_header (&$buf)
  489.      * DNS Header Packet structure
  490.      *
  491.      * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  492.      * +-------------------------------------------------------------+
  493.      * |      Identification          |            flags             |
  494.      * +------------------------------+------------------------------+
  495.      * |   number of questions        |       number of answer RRs   |
  496.      * +------------------------------+------------------------------+
  497.      * | number of authority RRs      |    number of additional RRs  |
  498.      * +------------------------------+------------------------------+
  499.      *
  500.      * type => OP_QUERY      nomal query
  501.      *         OP_IQUERY     inverse query
  502.      *         OP_STATUS     status query
  503.      */
  504.     private function make_header ($key&$buf{
  505.         Vari::objectInit (self::$dns[$key]);
  506.         self::$dns[$key]->header_id self::random_id (true);
  507.  
  508.         $buf self::$dns[$key]->header_id;      // Identification
  509.         $buf .= pack ('n'0x0100);   // flags
  510.         $buf .= pack ('n'1);        // number of questions
  511.         $buf .= pack ('x6');          // rest
  512.     // }}}
  513.  
  514.     // {{{ private (binary) sThread_DNS::dns_string ($v)
  515.     function dns_string ($domain{
  516.         $p explode ('.'$domain);
  517.         $len count ($p);
  518.  
  519.         if is_array ($p) )
  520.             return null;
  521.  
  522.         $r '';
  523.         foreach $p as $n {
  524.             $nlen strlen ($n);
  525.             $r .= chr ($nlen);
  526.             $r .= $n;
  527.         }
  528.  
  529.         return $r "\0";
  530.     // }}}
  531.  
  532.     // {{{ private (void) sThread_DNS::make_question (&$buf, $domain)
  533.     private function make_question (&$buf$domain{
  534.         $buf .= self::dns_string ($domain);
  535.     // }}}
  536.  
  537.     // {{{ private (object|boolean) sThread_DNS::query ($domain, $type)
  538.     private function query ($key$domain$type{
  539.         self::make_header ($key$buf);
  540.  
  541.         if preg_match ('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/'$domain) )
  542.             $query_type self::OP_IQUERY;
  543.         else
  544.             $query_type self::OP_QUERY;
  545.  
  546.         if $query_type === self::OP_IQUERY {
  547.             $ip explode ('.'$domain);
  548.             if count ($ip!== {
  549.                 self::$dns[$key]->err sprintf ('[DNS] %s is invalid ip format'$domain);
  550.                 return false;
  551.             }
  552.  
  553.             foreach (array_reverse ($ipas $v {
  554.                 if $v 255 {
  555.                     self::$dns[$key]->err sprintf ('[DNS] %s is invalid ip format'$domain);
  556.                     return false;
  557.                 }
  558.                 $arpa .= $v '.';
  559.             }
  560.             $arpa .= 'in-addr.arpa';
  561.         }
  562.  
  563.         self::make_question ($bufisset ($arpa$arpa $domain);
  564.         $buf .= pack ('n'$type);
  565.         $buf .= pack ('n'self::QCLASS_IN);
  566.  
  567.         Vari::objectInit ($header);
  568.         $header->data $buf;
  569.         $header->length  strlen ($buf);
  570.  
  571.         return $header;
  572.     // }}}
  573.  
  574.     // {{{ private (string) sThread_DNS::recv_flags_opcode ($v)
  575.     private function recv_flags_opcode ($v{
  576.         switch ($v{
  577.             case '0000' :
  578.                 return 'QUERY';
  579.                 break;
  580.             case '0001' :
  581.                 return 'IQUERY';
  582.                 break;
  583.             case '0010' :
  584.                 return 'STATUS';
  585.                 break;
  586.             default :
  587.                 return sprintf ('Unknown: %02x'bindec (substr ($v14)));
  588.         }
  589.     // }}}
  590.  
  591.     // {{{ private (void) sThread_DNS::recv_flags_rcode ($v)
  592.     private function recv_flags_rcode ($v{
  593.         $v bindec ($v);
  594.  
  595.         switch ($v{
  596.             case :
  597.                 return 'NOERROR';
  598.                 break;
  599.             case :
  600.                 return 'FORMAT ERROR';
  601.                 break;
  602.             case :
  603.                 return 'SERVER FAILURE';
  604.                 break;
  605.             case :
  606.                 return 'NAME ERROR';
  607.                 break;
  608.             case :
  609.                 return 'NOT IMPLEMENTED';
  610.                 break;
  611.             case :
  612.                 return 'REFUSED';
  613.                 break;
  614.             case :
  615.                 return 'YXDOMAIN';
  616.                 break;
  617.             case :
  618.                 return 'YXRRSET';
  619.                 break;
  620.             case :
  621.                 return 'NXRRSET';
  622.                 break;
  623.             case :
  624.                 return 'NOTAUTH';
  625.                 break;
  626.             case 10 :
  627.                 return 'NOTZONE';
  628.                 break;
  629.             default :
  630.                 // reserved for future use
  631.                 return 'RESERVED';
  632.         }
  633.     // }}}
  634.  
  635.     /* {{{ private (void) sThread_DNS::recv_header_flags ($key, $v)
  636.      *
  637.      * flag 분석
  638.      * -- 16-bits Flags --
  639.      * +----+--------+----+----+----+----+--------+-------+
  640.      * | QR | opcode | AA | TC | RD | RA | (zero) | rcode |
  641.      * +----+--------+----+----+----+----+--------+-------+
  642.      *   1      4      1    1    1    1      3        4     (bits)
  643.      */
  644.     private function recv_header_flags ($key$v{
  645.         $buf &self::$dns[$key]->recv->header->flags;
  646.         $v decbin ($v);
  647.         $buf->qr $v[0];
  648.         $buf->opcode self::recv_flags_opcode (substr ($v14));
  649.         $buf->aa $v[5];
  650.         $buf->tc $v[6];
  651.         $buf->rd $v[7];
  652.         $buf->ra $v[8];
  653.         $buf->rcode self::recv_flags_rcode (substr ($v12));
  654.     // }}}
  655.  
  656.     // {{{ private (boolean) sThread_DNS::recv_header ($key, $v)
  657.     private function recv_header ($key$v{
  658.         if strlen ($v12 {
  659.             self::$dns[$key]->err '[DNS] Recived header is over 12 characters';
  660.             return false;
  661.         }
  662.  
  663.         if self::$dns[$key]->header_id !== substr ($v02) ) {
  664.             $header_id unpack ('n'self::$dns[$key]->header_id);
  665.             $recv_id   unpack ('n'substr ($v02));
  666.             self::$dns[$key]->err sprintf (
  667.                 '[DNS] Don\'t match packet id (send: 0x%04x, recv 0x%04x)',
  668.                 $header_id[1]$recv_id[1]
  669.             );
  670.  
  671.             return false;
  672.         }
  673.  
  674.         Vari::objectInit (self::$dns[$key]->recv->header);
  675.         self::$dns[$key]->recv->header->data substr ($v012);
  676.         self::$dns[$key]->recv->header->length 12;
  677.         $buf unpack ('n*'self::$dns[$key]->recv->header->data);
  678.  
  679.         for $i=0$i<6$i++ {
  680.             if self::$header_member[$i== 'flags' {
  681.                 Vari::objectInit (self::$dns[$key]->recv->header->{self::$header_member[$i]});
  682.                 self::$dns[$key]->recv->header->{self::$header_member[$i]}->data $buf[$i+1];
  683.                 self::recv_header_flags ($key$buf[$i+1]);
  684.             else
  685.                 self::$dns[$key]->recv->header->{self::$header_member[$i]$buf[$i+1];
  686.         }
  687.  
  688.         return true;
  689.     // }}}
  690.  
  691.     // {{{ private (object) sThread_DNS::length_coded_string (&$v)
  692.     private function length_coded_string (&$v{
  693.         $len ord ($v[0]);
  694.         $r->length $len 1;
  695.  
  696.         if $len === {
  697.             $v substr ($v1);
  698.             return null;
  699.         }
  700.  
  701.         if strlen ($v$len )
  702.             return false;
  703.  
  704.         $r->data substr ($v1$len);
  705.         $v substr ($v$len 1);
  706.  
  707.         return $r;
  708.     // }}}
  709.  
  710.     // {{{ private (void) sThread_DNS::recv_question ($key, $v)
  711.     private function recv_question ($key$v{
  712.         $v substr ($v12);
  713.         $z $v;
  714.         $ques &self::$dns[$key]->recv->question;
  715.         $ques->length 0;
  716.  
  717.         while ( ($rr self::length_coded_string ($z)) != null {
  718.             if $rr === false )
  719.                 return false;
  720.             $ques->qname .= $rr->data '.';
  721.             $ques->length += $rr->length;
  722.         }
  723.  
  724.         $ques->type self::query_type (substr ($z02));
  725.         $ques->length += 2;
  726.         $ques->class self::query_class (substr ($z22));
  727.         $ques->length += 2;
  728.         $ques->data substr ($v0$ques->length);
  729.  
  730.         return true;
  731.     // }}}
  732.  
  733.     // {{{ private (void) sThread_DNS::recv_rdata ($key, &$v)
  734.     private function recv_rdata ($key&$v{
  735.         $buf self::$dns[$key]->recv->data;
  736.         $vlen $v->rdlen;
  737.  
  738.         switch ($v->type{
  739.             case 'A' :
  740.                 $ip unpack ('N'$v->rdata);
  741.                 $v->rdata long2ip ($ip[1]);
  742.                 break;
  743.             case 'AAAA' :
  744.                 if strlen ($v->rdata!= 16 {
  745.                     $v->rdata '::';
  746.                     break;
  747.                 }
  748.  
  749.                 # Machine byte의 영향을 받을 수 있다. unpack을 사용하는 것이
  750.                 # 좋을까? 일단은 이해를 위해서 나둔다. (이건 Intel용)
  751.                 //$ipv6 = unpack ('n8', $v->rdata);
  752.                 for $i=0$i<16$i+=)
  753.                     $ipv6[hexdec (bin2hex ($v->rdata[$i$v->rdata[$i+1]));
  754.  
  755.                 $rdata vsprintf("%x:%x:%x:%x:%x:%x:%x:%x"$ipv6);
  756.  
  757.                 # IPv6 압축
  758.                 $rdata preg_replace ('/^0:0:/''-:-:'$rdata);
  759.                 # 압축은 1회만 허용된다.
  760.                 $rdata preg_replace ('/(0:){2,}/''::'$rdata1);
  761.                 $v->rdata preg_replace ('/^-:-:/''0:0:'$rdata);
  762.                 break;
  763.             case 'MX' :
  764.                 $mx unpack ('n'$v->rdata[0$v->rdata[1]);
  765.                 $v->mx $mx[1];
  766.                 $v->rdata substr ($v->rdata2);
  767.                 $vlen -= 2;
  768.             case 'NS' :
  769.             case 'PTR' :
  770.             case 'CNAME' :
  771.                 $rdata '';
  772.                 for $i=0$i<$vlen$i++ {
  773.                     $len ord ($v->rdata[$i]);
  774.                     if $len == )
  775.                         break;
  776.  
  777.                     if $len == 0xc0 {
  778.                         $pos ord ($v->rdata[$i+1]);
  779.                         $rlen ord ($buf[$pos]);
  780.  
  781.                         while $rlen != {
  782.                             $rdata .= substr ($buf$pos 1$rlen'.';
  783.                             $pos += $rlen 1;
  784.                             $rlen ord ($buf[$pos]);
  785.  
  786.                             if $rlen == 0xc0 {
  787.                                 $pos ord ($buf[$pos 1]);
  788.                                 $rlen ord ($buf[$pos]);
  789.                             }
  790.                         }
  791.                         $i += 2;
  792.                     else {
  793.                         $rdata .= substr ($v->rdata$i 1$len'.';
  794.                         $i += $len;
  795.                     }
  796.                 }
  797.                 $v->rdata $rdata;
  798.                 break;
  799.             case 'SOA' :
  800.                 // SOA structure
  801.                 //  ----------------------------
  802.                 // | MNAME  (length(1) + string |
  803.                 //  ----------------------------
  804.                 // | RNAME  (length(1) + string |
  805.                 //  ----------------------------
  806.                 // | SERIAL (long)              |
  807.                 //  ----------------------------
  808.                 // | REFRESH (long)             |
  809.                 //  ----------------------------
  810.                 // | RETRY   (long)             |
  811.                 //  ----------------------------
  812.                 // | EXPIRE  (long)             |
  813.                 //  ----------------------------
  814.                 // | MINIMUM (long)             |
  815.                 //  ----------------------------
  816.                 $rdata '';
  817.                 $soa_count 0;
  818.                 for $i=0$i<$vlen$i++ {
  819.                     $len ord ($v->rdata[$i]);
  820.                     if $len == {
  821.                         $rdata .= ' ';
  822.  
  823.                         if $soa_count++ == )
  824.                             break;
  825.  
  826.                         continue;
  827.                     }
  828.  
  829.                     // 0x0c가 나오면 다음 자리에 전체 데이터
  830.                     // (self::$dns[$key]->recv->data)에서 몇번째인지의
  831.                     // 정보가 있다.
  832.                     if $len == 0xc0 {
  833.                         $pos ord ($v->rdata[$i+1]);
  834.                         $rlen ord ($buf[$pos]);
  835.  
  836.                         // 0이 나오면 종료이다.
  837.                         while $rlen != {
  838.                             $rdata .= substr ($buf$pos 1$rlen'.';
  839.                             $pos += $rlen 1;
  840.                             $rlen ord ($buf[$pos]);
  841.  
  842.                             if $rlen == 0xc0 {
  843.                                 $pos ord ($buf[$pos 1]);
  844.                                 $rlen ord ($buf[$pos]);
  845.                             }
  846.                         }
  847.  
  848.                         $rdata .= ' ';
  849.                         $soa_count++;
  850.                         $i++;
  851.                     else {
  852.                         $rdata .= substr ($v->rdata$i 1$len'.';
  853.                         $i += $len;
  854.                     }
  855.  
  856.                     if $soa_count == )
  857.                         break;
  858.                 }
  859.  
  860.                 if ( ($soa_field @unpack ('N5'substr ($v->rdata$i 1))) ) {
  861.                     foreach $soa_field as $vv )
  862.                         $rdata .= $vv ' ';
  863.                 }
  864.                 $v->rdata rtrim ($rdata);
  865.  
  866.                 break;
  867.             case 'TXT' :
  868.                 $v->rdata substr ($v->rdata1);
  869.                 break;
  870.         }
  871.     // }}}
  872.  
  873.     // {{{ private (void) sThread_DNS::recv_resource ($key, $v)
  874.     private function recv_resource ($key$v{
  875.         $header   &self::$dns[$key]->recv->header;
  876.         $question &self::$dns[$key]->recv->question;
  877.  
  878.         $start $header->length $question->length 1;
  879.         self::$dns[$key]->recv->resource->data substr ($v$start);
  880.         self::$dns[$key]->recv->resource->length strlen (self::$dns[$key]->recv->resource->data);
  881.  
  882.         $res &self::$dns[$key]->recv->resource;
  883.         $buf $res->data;
  884.  
  885.         $idx 0// position of resource
  886.         $idn 0// value of position of resource
  887.         $pnt 0// position of question
  888.  
  889.         $limit $limitchk $header->noans $header->noans 1;
  890.         for $i=0$i<$limit$i++ {
  891.             $vname ($limit $limitchk'ns' 'v';
  892.  
  893.             $idn ord ($buf[$idx]);
  894.  
  895.             if $idn == 0xc0 {
  896.                 $pnt ord ($buf[++$idx]);
  897.                 $qpnt $pnt $header->length;
  898.  
  899.                 $qbuf substr ($question->data$qpnt);
  900.             else {
  901.                 $qbuf substr ($buf$idx);
  902.             }
  903.  
  904.             unset ($rr);
  905.             while ( ($rr self::length_coded_string ($qbuf)) != null {
  906.                 if $rr === false )
  907.                     return false;
  908.                 $res->{$vname}[$i]->name .= $rr->data '.';
  909.                 $res->{$vname}[$i]->length += $rr->length;
  910.             }
  911.  
  912.             if $idn != 0xc0 )
  913.                 $idx += $res->v[$i]->length;
  914.  
  915.             $rdata unpack ('n2type/N1ttl/n1rdlen'substr ($buf$idx 1));
  916.             $res->{$vname}[$i]->type self::query_type ($rdata['type1']false);
  917.             $res->{$vname}[$i]->class self::query_class ($rdata['type2']false);
  918.             $res->{$vname}[$i]->ttl $rdata['ttl'];
  919.             $res->{$vname}[$i]->rdlen $rdata['rdlen'];
  920.             $res->{$vname}[$i]->rdata substr ($buf$idx 10 1$res->{$vname}[$i]->rdlen);
  921.  
  922.             self::recv_rdata ($key$res->{$vname}[$i]);
  923.             $buf substr ($buf$idx 10 $res->{$vname}[$i]->rdlen 1);
  924.             $idx 0;
  925.  
  926.             // 남은 것은 DNS 정보이다.
  927.             if ( ($i+== $limit&& $buf )
  928.                 $limit++;
  929.         }
  930.  
  931.         return true;
  932.     // }}}
  933.  
  934.     // {{{ private (void) sThread_DNS::recv_parse ($v)
  935.     private function recv_parse ($key$v{
  936.         self::$dns[$key]->recv->data $v;
  937.         self::$dns[$key]->recv->length strlen ($v);
  938.  
  939.         $r self::recv_header ($key$v);
  940.  
  941.         if $r !== false && Vari::$result === true {
  942.             self::recv_question ($key$v);
  943.             self::recv_resource ($key$v);
  944.             //print_r (self::$dns[$key]->recv);
  945.         }
  946.  
  947.         return $r;
  948.     // }}}
  949. }
  950.  
  951. ?>

Documentation generated on Fri, 30 Aug 2024 06:10:06 +0900 by phpDocumentor 1.4.4