function gen_http_request($url)
{
    (yield 'notdone' => [$url, 'Just Loaded']);
    // Always yield to start with to help with queueing up requests
    $url = trim($url);
    if (!$url) {
        (yield 'error' => [$url, 'No URL was provided']);
    }
    $started_at = time();
    $parsed_url = parse_url($url);
    $parsed_url['path'] = $parsed_url['path'] ?: '/';
    $request = "GET {$parsed_url['path']} HTTP/1.0\r\n" . "Host: {$parsed_url['host']}\r\n" . "User-Agent: Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10136\r\n" . "Connection: close\r\n" . "Accept: */*\r\n" . "pragma: no-cache\r\n" . "dnt: 1\r\n" . "\r\n";
    // GET THE IP
    $ip = false;
    $ip_gen = gen_get_ip($parsed_url['host']);
    while (!$ip && $ip_gen->key()) {
        $ip_gen->next();
        list($domain, $result) = $ip_gen->current();
        switch ($ip_gen->key()) {
            case 'notdone':
                (yield 'notdone' => [$url, 'Waiting on DNS']);
                continue;
            case 'error':
                (yield 'error' => [$url, 'DNS resolution failed']);
                continue;
            case 'result':
                $ip = $result;
                break;
        }
    }
    //var_dump( "Found the IP for $url it's $ip" );
    $connect_str = 'https' == $parsed_url['scheme'] ? "ssl://{$ip}:443" : "tcp://{$ip}:80";
    $timeout = 15;
    $context = stream_context_create(array('ssl' => array('verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true)));
    $socket = new D_AsyncSocket($connect_str, $timeout, $context);
    if ($socket->error()) {
        (yield 'error' => [$url, "Connect failed with " . $socket->error()]);
    }
    do {
        if (time() - $started_at > 15) {
            //echo "Giving up $url";
            unset($socket);
            (yield 'error' => [$url, 'Giving Up']);
        }
        if ($socket->error()) {
            //echo "Error on $url\n";
            (yield 'error' => [$url, 'URL Hung up on us']);
        }
        if (!$socket->ready_for_write()) {
            //echo "[$url] waiting for socket connect\n";
            (yield 'notdone' => [$url, 'waiting for socket connect']);
            continue;
        }
        $wrote = $socket->write($request, strlen($request));
        $request = substr($request, $wrote);
    } while (!$socket->error() && $request);
    $data = '';
    while (!$socket->error() && !$socket->eof()) {
        if (time() - $started_at > 15) {
            //echo "Giving up $url";
            (yield 'error' => [$url, 'Giving Up']);
        }
        if (!$socket->ready_for_read()) {
            //echo "[$url] waiting for data\n";
            (yield 'notdone' => [$url, 'waiting for data']);
            continue;
        }
        $data .= $socket->read(8192);
    }
    unset($socket);
    if (!$data) {
        //echo "[$url] No data\n";
        (yield 'error' => [$url, 'no data']);
    }
    list($headers, $body) = parse_http_response($data);
    $result = ['headers' => $headers, 'body' => $body, 'resolved_ip' => $ip];
    (yield 'result' => [$url, $result]);
}
Exemplo n.º 2
0
function gen_get_ip($domain)
{
    $domain = "{$domain}.";
    $dns = DNS_SERVER;
    $timeout = 30;
    $started_at = time();
    /* Message ID, ( QR, OPCODE, AA, TC ), Recursion Desired, Recursion Avail, Response Code, Entries in Question?? */
    $data = pack('n6', rand(10, 77), 0x100, 1, 0, 0, 0);
    /* Question */
    foreach (explode('.', $domain) as $bit) {
        $l = strlen($bit);
        $data .= chr($l) . $bit;
    }
    $data .= pack('n2', 1, 1);
    // QTYPE=A, QCLASS=IN
    $socket = new D_AsyncSocket("udp://{$dns}:53", $timeout);
    if ($socket->error()) {
        (yield 'error' => [$domain, "failed to connect"]);
    }
    do {
        if (time() - $started_at > $timeout) {
            //echo "Giving up $domain";
            unset($socket);
            (yield 'error' => [$domain, 'Giving Up']);
        }
        if ($socket->error()) {
            //echo "Error on $domain\n";
            (yield 'error' => [$domain, 'DNS Hung up on us']);
        }
        if (!$socket->ready_for_write()) {
            //echo "[$domain] waiting for socket connect\n";
            (yield 'notdone' => [$domain, 'waiting for socket connect']);
            continue;
        }
        $wrote = $socket->write($data, strlen($data));
        $data = substr($data, $wrote);
    } while ($data);
    $data = '';
    $ip = false;
    while (!$ip && $socket && !$socket->error() && !$socket->eof()) {
        if (time() - $started_at > $timeout) {
            //echo "Giving up $domain";
            (yield 'error' => [$domain, 'Giving Up']);
        }
        if (!$socket->ready_for_read()) {
            //echo "[$domain] waiting for data\n";
            (yield 'notdone' => [$domain, 'waiting for data']);
            continue;
        }
        $data .= $socket->read(8192);
        $data_length = strlen($data);
        $i = 0;
        if ($data_length >= 12) {
            list(, $message_id, $QR_OPCODE_AA_TC_RD_RA_RCODE, $QDCOUNT, $ANCOUNT, $NSCOUNT, $ARCOUNT) = unpack('n6', substr($data, 0, 12));
            $QR_OPCODE_AA_TC_RD_RA_RCODE = decbin($QR_OPCODE_AA_TC_RD_RA_RCODE);
            // Format of $QR_OPCODE_AA_TC_RD_RA_RCODE uint16 in binary
            // 1  0000   0  0  1  1  0    0    0    0000
            // QR OPCODE AA TC RD RA res1 res2 res3 RCODE
            $QR = bindec(substr($QR_OPCODE_AA_TC_RD_RA_RCODE, 0, 1));
            $OPCODE = bindec(substr($QR_OPCODE_AA_TC_RD_RA_RCODE, 1, 4));
            $AA = bindec(substr($QR_OPCODE_AA_TC_RD_RA_RCODE, 5, 1));
            $TC = bindec(substr($QR_OPCODE_AA_TC_RD_RA_RCODE, 6, 1));
            $RD = bindec(substr($QR_OPCODE_AA_TC_RD_RA_RCODE, 7, 1));
            $RA = bindec(substr($QR_OPCODE_AA_TC_RD_RA_RCODE, 8, 1));
            // $res1, $res2, $res2 = 9, 10, and 11
            $RCODE = bindec(substr($QR_OPCODE_AA_TC_RD_RA_RCODE, 12, 4));
            unset($QR_OPCODE_AA_TC_RD_RA_RCODE);
            //	var_dump( compact( 'message_id', 'QR', 'OPCODE', 'AA', 'TC', 'RD', 'RA', 'RCODE', 'QDCOUNT', 'ANCOUNT', 'NSCOUNT', 'ARCOUNT' ) );
            if ($RCODE > 0) {
                unset($socket);
                (yield 'error' => [$domain, 'Error code raised: ' . $RCODE]);
            }
            $i = 12;
        }
        if ($data_length > $i) {
            $answer = '';
            while ("" != substr($data, $i, 1)) {
                $field_length = ord(substr($data, $i, 1));
                $answer .= substr($data, $i + 1, $field_length) . '.';
                $i += $field_length + 1;
            }
            //	var_dump( compact( 'answer' ) );
        }
        if ($data_length >= $i + 5) {
            $i++;
            list(, $qtype, $qclass) = unpack('n2', substr($data, $i, 4));
            //	var_dump( compact( 'qtype', 'qclass' ) );
            $i += 4;
        }
        if ($data_length > $i) {
            for ($answer_i = 1; $answer_i <= $ANCOUNT; $answer_i++) {
                list(, $NAME, $TYPE, $CLASS) = unpack('n3', substr($data, $i, 6));
                $i += 6;
                list(, $TTL) = unpack('N', substr($data, $i, 4));
                $i += 4;
                list(, $RDLENGTH) = unpack('n', substr($data, $i, 2));
                $i += 2;
                // IPv4 is always $RDLENGTH = 4, others 2
                if (1 == $TYPE && 4 == $RDLENGTH) {
                    list(, $RDATA) = unpack('N', substr($data, $i, $RDLENGTH));
                    $ip = long2ip($RDATA);
                } elseif ($RDLENGTH > 4) {
                    // We don't actually need to know this field.
                    // Assume FQDN.
                    $_RDATA = substr($data, $i, $RDLENGTH);
                    $_i = 0;
                    $RDATA = '';
                    while ("" != substr($_RDATA, $_i, 1) && $_i < $RDLENGTH) {
                        $field_length = ord(substr($_RDATA, $_i, 1));
                        $RDATA .= substr($_RDATA, $_i + 1, $field_length) . '.';
                        $_i += $field_length + 1;
                    }
                    unset($_RDATA, $_i, $field_length);
                } else {
                    // We don't really care about this anyway...
                    $RDATA = substr($data, $i, $RDLENGTH);
                }
                $i += $RDLENGTH;
                //				var_dump( compact( 'NAME', 'TYPE', 'CLASS', 'TTL', 'RDLENGTH', 'RDATA' ) );
            }
        }
    }
    unset($socket);
    (yield 'result' => [$answer, $ip]);
}