[PHP] Sockets geven problemen

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Heyhoi,

Ik ben met PHP bezig met sockets, maar het wil maar niet lukken.

Wat wil ik?
Ik wil een simpel portscan scriptie maken, eentje die een stuk of 3 / 4 poorten kijkt of ze 'open' zijn, zodat ik kan controleren of het een proxy is (poort 8080 bijvoorbeeld). Ik wil dus niets schrijven of lezen van de socket, alleen kijken of hij kan connecten daarna meteen closen.

En werkt het?
Ja, tenminste als ik blocking sockets gebruik, wat default is. Maar dat betekent dat het script 60 seconden 'vast zit' als de remote host geen antwoord geeft (zoals een firewall die ports stealth maakt). Dus dat is verre van ideaal. Wat ik verder raar vind is dat ik de maximal execution time op 10 seconden heb gezet, maar dat negeert hij kennelijk. Ik wil dus non blocking sockets, waarbij ik kijk of de socket open / closed of nog bezig is en hem laat timeouten na 1 seconde. Klinkt gezellig. :)

Hoe ziet je code eruit?
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
 $scanports = array(25,80,8080);
 // set timeout to 1 second
 $timeout = 1;
 foreach ($scanports as $port)
 {
  $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  socket_set_nonblock($sock);
  $sock_state = @socket_connect($sock, $ip, (int)$port);
  $time = time();

  while ((time() - $time) < $timeout)
  // while not timed out..
  {
   $err = socket_last_error($sock);
   if ($err == 36 || $err == 37)
   // waiting for response
   {
    // sleep 0,2 seconds
    usleep(200000);
    continue;
   }
   elseif ($err == 56)
    break;
   else
    error('Socket error: ['.$err.'] '.socket_strerror($err) . "\n");
  }
  socket_close($sock);

  echo('<p>'.socket_strerror($err).'</p>');
  if ($sock_state === true)
   echo('<li>Port '.$port.' <b>( '.getservbyport($port,'tcp').' )</b> is open</li>');
 }

(op die laatste twee regels hoef je niet te letten, dat werkt goed bij blocking sockets maar niet bij non blocking sockets)

Wat werkt er dan niet?
Bij elke poort die gescant wordt, is de $err errorcode "Operation now in progress", of ik nou direct erna de foutcode opvraag of na 120 seconden. De poort van de host is wel degelijk open, met blocking sockets werkt het gewoon. Non-blocking sockets werkt gewoon niet. Heel vervelend. Ik zit eraan te denken of dit een PHP bug is, of dat ik gewoon iets fout doe.

Gegevens
Apache: 2.0.53
PHP: 5.0.3 (met sockets gecompileerd)
OS: FreeBSD 5.3


Kunnen jullie me misschien helpen, na vele uren heb ik het opgegeven; het werkt gewoon niet zoals zou moeten. De documentatie van PHP wat betreft de sockets extensie is ook zeer marginaal. :(

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

Ik ken die socket functies niet, maar bij fsockopen kun je een timeout opgeven.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

Verwijderd

*slightly offtopic
volgens mij staat de aanbevolen wachttijd nog steeds op zo'n 3 minuten...

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Janoz schreef op maandag 14 februari 2005 @ 09:58:
Ik ken die socket functies niet, maar bij fsockopen kun je een timeout opgeven.
Lees ik dit in de comments:
fsockopen (on FreeBSD and probably OpenBSD) will ignore the connection timeout parameter, and hang for several minutes if it can't connect for a variety of reasons (no DNS resolve, host down, extreme firewall setups). Use curl instead until a solution is found (i spent days on this issue)
:(

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Dat is voor gewone fopen dingen, niet voor sockets. Ik kreeg een error toen ik deze functie gebruikte met met mijn socket (aangemaakt via socket_create() ) .
Verwijderd schreef op maandag 14 februari 2005 @ 11:39:
*slightly offtopic
volgens mij staat de aanbevolen wachttijd nog steeds op zo'n 3 minuten...
Om te wachten op een timeout? Denk jij dat een gebruiker 3 minuten gaat wachten eer een pagina laadt? En dat maal 3 keer (3 ports)? Are you insane? ;)

1 seconde vind ik al teveel. 500ms wil ik als timeout rekenen. Maar laat het zooitje eerst maar eens werken.

Acties:
  • 0 Henk 'm!

Verwijderd

Verwijderd schreef op maandag 14 februari 2005 @ 11:56:
Om te wachten op een timeout? Denk jij dat een gebruiker 3 minuten gaat wachten eer een pagina laadt? En dat maal 3 keer (3 ports)? Are you insane? ;)

1 seconde vind ik al teveel. 500ms wil ik als timeout rekenen. Maar laat het zooitje eerst maar eens werken.
1 - het gaat er niet om wat jij vind, het gaat om de maximale tijd die nodig is voor de "handshake"
2 - Niet al het verkeer op het internet betreft een internet pagina
3 - en dat correspondeert niet met 3*3, want er bestaat altijd nog zoiets als threads/processes...

Acties:
  • 0 Henk 'm!

  • Skaah
  • Registratie: Juni 2001
  • Laatst online: 16-09 18:38
Over de executietijd: 'wachten' telt niet mee (op de database, of in jouw geval, op sockets).
The set_time_limit() function and the configuration directive max_execution_time only affect the execution time of the script itself. Any time spent on activity that happens outside the execution of the script such as system calls using system(), the sleep() function, database queries, etc. is not included when determining the maximum time that the script has been running.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Verwijderd schreef op maandag 14 februari 2005 @ 12:13:
[...]

1 - het gaat er niet om wat jij vind, het gaat om de maximale tijd die nodig is voor de "handshake"
2 - Niet al het verkeer op het internet betreft een internet pagina
3 - en dat correspondeert niet met 3*3, want er bestaat altijd nog zoiets als threads/processes...
Jij betrekt het in het algemeen, maar het gaat nu om mijn situatie:

1. Maximale tijd interesseert me niets, als een host niet binnen 500ms of hooguit 1000ms reageert dan is hij timed out wat mij betreft.
2. Dit betreft een PHP pagina die poorten aanspreekt, en weer sluit.
3. het is wel 3*3 want mijn implementatie nu serieel ipv parallel. Dat kan ik uiteraard wel veranderen, maar alleen als het non-blocking is; hetgeen nu dus niet werkt. Bij blocking ports is het sowieso serieel en dus 3*3.
Skaah schreef op maandag 14 februari 2005 @ 12:17:
Over de executietijd: 'wachten' telt niet mee (op de database, of in jouw geval, op sockets).

[...]
Mja zit wat in. Toch vind ik het jammer dat ik niet kan forceren dat een script maximaal x seconden actief is. Nu kan het gewoon voorkomen dat een script vast zit doordat b.v. een extern commando of socket operatie oneindig lang duurt. Vervelend.

Verwijderd

Topicstarter
Janoz schreef op maandag 14 februari 2005 @ 09:58:
Ik ken die socket functies niet, maar bij fsockopen kun je een timeout opgeven.
Ondanks de comment toch even geprobeerd en nu werkt mn script prima. :)

Wel irritant: tussen BSD en Linux verschillen de foutcodes die je terug krijgt. Dat maakt je script natuurlijk niet erg crossplatform. Maar ik ben al lang blij dat het werkt. :)

Alleen is het wel blocking dus je kunt het niet parallel afhandelen, moet dus serieel. Timeout op 1 seconde zetten betekent max 4 seconde voor een portscan van 4 poorten; acceptabel.

Bedankt guys. :>

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 16:28
Het gaat over asynchrone I/O en in het hele topic komt select (of in PHP socket_select) niet voor? Met select kun je namelijk van een verzameling sockets opvragen welke er leesbaar, schrijfbaar of in een fouttoestand zijn (zie de details in de PHP manual of de FreeBSD man-page voor select voor details).

De essentie is dat een socket 'schrijfbaar' wordt zodra 'ie verbonden is (tenzij de verbinding niet geaccepteerd wordt, in welk geval 'ie in een 'error' state komt). Je kan de seriele oplossing dus alternatief ook met select met een timeout te gebruiken:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_nonblock($sock);
@socket_connect($sock, $ip, (int)$port);

$readable  = array(); // maybe not interested in this
$writeable = array($sock);
$error     = array($sock);
if( socket_select( $readable, $writeable, $error,
                   0 /* seconds */, 500000 /* microseconds */ ) > 0)
{
    // at least one socket writeable or in error
    if(in_array($sock, $writeable))
    {
        // connect succeeded
    } else
    {
        // connect failed
    }
}

Maar het is natuurlijk goed mogelijk deze code uit te breiden zodat je de vier connecties tegelijkertijd (en asynchroon) afhandelt. Sterker nog: dat is precies waar select voor ontworpen is (vandaar die arrays)! Het schrijven van een aantal lusjes daarvoor kom je waarschijnlijk zelf wel uit; waar je op moet letten is dat je select herhaaldelijk uitvoert, maar dat je de timeout wel steeds moet aanpassen (als de eerste connectie 400ms duurt, moet de volgende call een timeout van 100ms hebben, enzovoorts).

offtopic:
De enige reden dat er afzonderlijke select-functies in PHP zijn voor sockets en streams is trouwens dat Windows eigenlijk geen select op streams ondersteunt.

[ Voor 11% gewijzigd door Soultaker op 17-02-2005 01:42 . Reden: code gefixed ]

Pagina: 1