Beispiel #1
0
 /**
  * Handles incoming SIP messages
  *
  * @param $peer client address to send to
  * @param $msg the raw SIP message
  * @return true if message was handled
  */
 function handle_message($peer, $msg)
 {
     $pos = strpos($msg, "\r\n\r\n");
     $head = explode("\r\n", trim(substr($msg, 0, $pos)), 2);
     $mime = mimeParseHeader($head[1]);
     $body = trim(substr($msg, $pos));
     $tmp = explode(' ', $head[0]);
     //INVITE sip:xxx@10.10.10.240 SIP/2.0
     if ($tmp[2] != 'SIP/2.0') {
         //XXX return error code!
         echo "ERROR: Unsupported SIP version: " . $tmp[2] . "\n";
         return false;
     }
     switch ($tmp[0]) {
         case 'INVITE':
             $sip_type = SIP_INVITE;
             break;
         case 'ACK':
             $sip_type = SIP_ACK;
             break;
         case 'BYE':
             $sip_type = SIP_BYE;
             break;
         case 'OPTIONS':
             $sip_type = SIP_OPTIONS;
             break;
         case 'CANCEL':
             $sip_type = SIP_CANCEL;
             break;
         case 'REGISTER':
             $sip_type = SIP_REGISTER;
             break;
         default:
             echo "Unknown SIP command: " . $tmp[0] . "\n";
             return false;
     }
     switch ($sip_type) {
         case SIP_INVITE:
             //echo "Recieved SIP INVITE from ".$peer."\n";
             //Send "100 TRYING" response
             $res = $this->send_message(SIP_TRYING, $peer, $mime);
             //Send "180 RINGING" response
             $res = $this->send_message(SIP_RINGING, $peer, $mime);
             //Send "200 OK" response
             if ($mime['Content-Type'] != 'application/sdp') {
                 echo "ERROR: DIDNT GET SDP FROM CLIENT INVITE MSG\n";
                 //FIXME how to handle. hangup?
                 break;
             }
             echo "Forwarding SIP media streams to IP: " . $this->dst_ip . "\n";
             $port = $this->allocate_port($peer);
             $res_sdp = generate_sdp($body, $this->dst_ip, $port);
             $res = $this->send_message(SIP_OK, $peer, $mime, $res_sdp);
             echo "SDP FROM CALLER:\n" . $body . "\n\n";
             echo "SDP TO CALLER & STREAMING SERVER:\n" . $res_sdp . "\n";
             $sdp_file = '/tmp/sip_tmp.sdp';
             file_put_contents($sdp_file, $res_sdp);
             //NOTE: playback live stream locally with VLC:
             //exec('/home/ml/scripts/compile/vlc-git/vlc -vvv '.$sdp_file);
             exec('ffplay ' . $sdp_file);
             //XXX dump rtp stream (command not working!!!)
             //exec('ffmpeg -i '.$sdp_file.' -vcodec copy -f raw /tmp/out.h263');
             break;
         case SIP_BYE:
             echo "Recieved SIP BYE from " . $peer . "\n";
             //Send "200 OK" response
             $res = $this->send_message(SIP_OK, $peer, $mime);
             $this->free_port($peer);
             break;
         case SIP_ACK:
             //echo "Recieved SIP ACK from ".$peer."\n";
             //we dont send a response on this message
             break;
         case SIP_OPTIONS:
             //FIXME more parameters should be set in the OK response (???)
             echo "Recieved SIP OPTIONS from " . $peer . "\n";
             $res = $this->send_message(SIP_OK, $peer, $mime);
             break;
             //We are acting a SIP Registrar
         //We are acting a SIP Registrar
         case SIP_REGISTER:
             echo "Recieved SIP REGISTER from " . $peer . "\n";
             if (empty($mime['Authorization'])) {
                 //FIXME sip bindings (how does that work?!) RFC 3261: 10.3
                 echo "Sending auth request!\n";
                 $res = $this->send_message(SIP_UNAUTHORIZED, $peer, $mime);
                 break;
             }
             $pos = strpos($mime['Authorization'], ' ');
             $auth_type = substr($mime['Authorization'], 0, $pos);
             $auth_response = substr($mime['Authorization'], $pos + 1);
             if ($auth_type != "Digest") {
                 //FIXME: send error code! 400 Bad request (???)
                 echo "ERROR: SIP/2.0 only support Digest authentication\n";
                 break;
             }
             //RFC 2617: "3.2.2.1 Request-Digest"
             $chal = MimeReader::parseAuthRequest($auth_response);
             if ($chal['algorithm'] != "MD5" || $chal['realm'] != $this->auth_realm || $chal['nonce'] != $this->get_nonce($peer) || $chal['opaque'] != md5($this->auth_opaque) || empty($chal['username'])) {
                 //FIXME: send error code! 400 Bad request (???)
                 echo "ERROR: Authentication details for user " . $chal['username'] . " is invalid!\n";
                 break;
             }
             $check = $this->auth_default_handler($chal['username'], $this->auth_realm, $chal['uri'], $chal['nonce'], $chal['response']);
             if ($check) {
                 echo "DEBUG: Authentication of user " . $chal['username'] . " SUCCESSFUL!\n";
                 $res = $this->send_message(SIP_OK, $peer, $mime);
             } else {
                 //FIXME: send error code! 403 Forbidden (???)
                 echo "ERROR: Authentication of user " . $chal['username'] . " FAILED!\n";
             }
             break;
         case SIP_CANCEL:
             echo "Recieved SIP CANCEL from " . $peer . "\n";
             //FIXME what should we respond?
             break;
         default:
             echo "Unknown SIP message type\n";
             return false;
     }
     return true;
 }
Beispiel #2
0
 function _AUTH()
 {
     if (isset($this->ability['AUTH']['DIGEST-MD5'])) {
         //XXX: this implementation might be buggy in regards to charset (non latin1 letters in username / password)
         $this->write('AUTH DIGEST-MD5');
         if ($this->status != 334) {
             echo "smtp->_AUTH() DIGEST-MD5 [" . $this->status . "]: " . $this->lastreply . ln();
             return false;
         }
         //echo "challenge: ".base64_decode($this->lastreply)."\n";
         $chal = MimeReader::parseAuthRequest(base64_decode($this->lastreply));
         if (empty($chal['qop'])) {
             $chal['qop'] = 'auth';
         }
         //default
         if ($chal['algorithm'] != 'md5-sess') {
             echo "smtp->_AUTH() DIGEST-MD5 unknown algorithm: " . $chal['algorithm'] . ln();
             return false;
         }
         //RFC 2831 @ 2.1.2.1
         $nc = '00000001';
         //number of times same nonce has been used
         $cnonce = md5(mt_rand() . microtime());
         $digest_uri = 'smtp/' . $this->servername;
         $a1 = md5($this->username . ':' . $chal['realm'] . ':' . $this->password, true) . ':' . $chal['nonce'] . ':' . $cnonce . (!empty($chal['authzid']) ? ':' . $chal['authzid'] : '');
         $a2 = 'AUTHENTICATE:' . $digest_uri . ($chal['qop'] != 'auth' ? ':00000000000000000000000000000000' : '');
         $response = md5(md5($a1) . ':' . $chal['nonce'] . ':' . $nc . ':' . $cnonce . ':' . $chal['qop'] . ':' . md5($a2));
         $cmd = 'charset=' . $chal['charset'] . ',' . 'username="******",' . 'realm="' . $chal['realm'] . '",' . 'nonce="' . $chal['nonce'] . '",' . 'nc=' . $nc . ',' . 'cnonce="' . $cnonce . '",' . 'digest-uri="' . $digest_uri . '",' . 'response=' . $response . ',' . 'qop=' . $chal['qop'];
         $this->write(base64_encode($cmd));
         if ($this->status != 334) {
             echo "smtp->_AUTH() DIGEST-MD5 challenge [" . $this->status . "]: " . $this->lastreply . ln();
             return false;
         }
         //XXX validate server response, RFC 2831 @ 2.1.3
         //echo "response: ".base64_decode($this->lastreply)."\n";
         $this->write('NOOP');
         //FIXME figure out why we need to send 1 more command to get the 235 status
         if ($this->status != 235) {
             echo "smtp->_AUTH() DIGEST-MD5 auth failed [" . $this->status . "]: " . $this->lastreply . ln();
             return false;
         }
         return true;
     }
     if (isset($this->ability['AUTH']['CRAM-MD5'])) {
         $this->write('AUTH CRAM-MD5');
         if ($this->status != 334) {
             echo "smtp->_AUTH() CRAM-MD5 [" . $this->status . "]: " . $this->lastreply . ln();
             return false;
         }
         $digest = hash_hmac('md5', base64_decode($this->lastreply), $this->password);
         $this->write(base64_encode($this->username . ' ' . $digest));
         if ($this->status != 235) {
             echo "smtp->_AUTH() CRAM-MD5 challenge [" . $this->status . "]: " . $this->lastreply . ln();
             return false;
         }
         return true;
     }
     if (isset($this->ability['AUTH']['LOGIN'])) {
         $this->write('AUTH LOGIN');
         if ($this->status != 334) {
             echo "smtp->_AUTH() LOGIN [" . $this->status . "]: " . $this->lastreply . ln();
             return false;
         }
         $this->write(base64_encode($this->username));
         if ($this->status != 334) {
             echo "smtp->_AUTH() LOGIN username [" . $this->status . "]: " . $this->lastreply . ln();
             return false;
         }
         $this->write(base64_encode($this->password));
         if ($this->status != 235) {
             echo "smtp->_AUTH() LOGIN password [" . $this->status . "]: " . $this->lastreply . ln();
             return false;
         }
         return true;
     }
     //d($this->ability);
     //Defaults to "AUTH PLAIN" if the server is not ESMTP-capable (FIXME: verify with non-capable server)
     $this->write('AUTH PLAIN');
     if ($this->status == 503) {
         return true;
     }
     //authentication not enabled
     if ($this->status != 334) {
         throw new \Exception("smtp->_AUTH() PLAIN [" . $this->status . "]: " . $this->lastreply);
     }
     $cmd = base64_encode(chr(0) . $this->username . chr(0) . $this->password);
     $this->write($cmd);
     if ($this->status != 235) {
         echo "smtp->_AUTH() PLAIN error [" . $this->status . "]: " . $this->lastreply . ln();
         return false;
     }
     return true;
 }