/* Copyright (C) 2005-2009 Michel de Boer This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "events.h" #include "listener.h" #include "log.h" #include "sys_settings.h" #include "translator.h" #include "user.h" #include "userintf.h" #include "util.h" #include "im/im_iscomposing_body.h" #include "sockets/connection_table.h" #include "sockets/socket.h" #include "parser/parse_ctrl.h" #include "parser/sip_message.h" #include "sdp/sdp_parse_ctrl.h" #include "stun/stun.h" #include "audits/memman.h" #include "presence/pidf_body.h" extern t_phone *phone; extern t_socket_udp *sip_socket; extern t_socket_tcp *sip_socket_tcp; extern t_connection_table *connection_table; extern t_event_queue *evq_trans_mgr; extern t_event_queue *evq_trans_layer; // Minimal size of a message. Messages below this size will // be silently discarded. #define MIN_MESSAGE_SIZE 10 // Maximum number of pending TCP connections. #define TCP_BACKLOG 5 void recvd_stun_msg(char *datagram, int datagram_size, unsigned long src_addr, unsigned short src_port) { StunMessage m; if (!stunParseMessage(datagram, datagram_size, m, false)) { log_file->write_report("Received faulty STUN message", "::recvd_stun_msg", LOG_STUN, LOG_DEBUG); return; } log_file->write_header("::recvd_stun_msg", LOG_STUN); log_file->write_raw("Received from: "); log_file->write_raw(h_ip2str(src_addr)); log_file->write_raw(":"); log_file->write_raw(src_port); log_file->write_endl(); log_file->write_raw(stunMsg2Str(m)); log_file->write_footer(); evq_trans_mgr->push_stun_response(&m, 0, 0); } t_sip_body *parse_body(const string &data, const t_sip_message *msg) { if (!msg->hdr_content_type.is_populated()) { // Content-Type header is missing. Pass body // unparsed. The upper application layer will // decide what to do. t_sip_body_opaque *p = new t_sip_body_opaque(data); MEMMAN_NEW(p); return p; } if (msg->hdr_content_type.media.type == "application" && msg->hdr_content_type.media.subtype == "sdp") { // Parse SDP body return t_sdp_parser::parse(data); } else if (msg->hdr_content_type.media.type == "message" && msg->hdr_content_type.media.subtype == "sipfrag") { t_sip_body_sipfrag *b; // Parse sipfrag body (RFC 3420) try { // If the sipfrag does not contain a body itself, // then the CRLF at the end of the headers is optional! // Add an additional CRLF such that the SIP parser will // parse a sipfrag if the CRLF is not present. The SIP // parser will stop after it finds the double CRLF. So // a 3rd CRLF will not be detected by the parser (yuck). list parse_errors; t_sip_message *m = t_parser::parse(data + CRLF, parse_errors); b = new t_sip_body_sipfrag(m); MEMMAN_NEW(b); MEMMAN_DELETE(m); delete m; return b; } catch (int) { // Parsing failed, maybe because a request or status // line is not present, which is not mandatory for a // sipfrag body. Add a fake status line and try to parse // again. string tmp = "SIP/2.0 100 Trying"; tmp += CRLF; tmp += data; tmp += CRLF; list parse_errors; t_sip_message *resp = t_parser::parse(tmp, parse_errors); // Parsing succeeded. Now strip the fake header t_sip_message *m = new t_sip_message(*resp); MEMMAN_NEW(m); MEMMAN_DELETE(resp); delete (resp); b = new t_sip_body_sipfrag(m); MEMMAN_NEW(b); MEMMAN_DELETE(m); delete m; return b; } } else if (msg->hdr_content_type.media.type == "application" && msg->hdr_content_type.media.subtype == "dtmf-relay") { t_sip_body_dtmf_relay *b = new t_sip_body_dtmf_relay(); MEMMAN_NEW(b); if (b->parse(data)) return b; MEMMAN_DELETE(b); delete b; throw -1; } else if (msg->hdr_content_type.media.type == "application" && msg->hdr_content_type.media.subtype == "simple-message-summary") { t_simple_msg_sum_body *b = new t_simple_msg_sum_body(); MEMMAN_NEW(b); if (b->parse(data)) return b; MEMMAN_DELETE(b); delete b; throw -1; } else if (msg->hdr_content_type.media.type == "text" && msg->hdr_content_type.media.subtype == "plain") { t_sip_body_plain_text *b = new t_sip_body_plain_text(data); MEMMAN_NEW(b); return b; } else if (msg->hdr_content_type.media.type == "text" && msg->hdr_content_type.media.subtype == "html") { t_sip_body_html_text *b = new t_sip_body_html_text(data); MEMMAN_NEW(b); return b; } else if (msg->hdr_content_type.media.type == "application" && msg->hdr_content_type.media.subtype == "pidf+xml") { t_pidf_xml_body *b = new t_pidf_xml_body(); MEMMAN_NEW(b); if (b->parse(data)) return b; MEMMAN_DELETE(b); delete b; throw -1; } else if (msg->hdr_content_type.media.type == "application" && msg->hdr_content_type.media.subtype == "im-iscomposing+xml") { t_im_iscomposing_xml_body *b = new t_im_iscomposing_xml_body(); MEMMAN_NEW(b); if (b->parse(data)) return b; MEMMAN_DELETE(b); delete b; throw -1; } else { // Pass other bodies unparsed. The upper application // layer will decide what to do. t_sip_body_opaque *p = new t_sip_body_opaque(data); MEMMAN_NEW(p); return p; } } static void process_sip_msg(t_sip_message *msg, const string &raw_headers, const string &raw_body) { t_event_network *ev_network; string log_msg; // SIP message received log_msg = "Received from: "; log_msg += msg->src_ip_port.tostring(); log_msg += "\n"; // Parse body if (!raw_body.empty()) { // The body should only be parsed if it is complete. // NOTE: The Content-length header may be absent (UDP) if (!msg->hdr_content_length.is_populated() || msg->hdr_content_length.length == raw_body.size()) { try { msg->body = parse_body(raw_body, msg); } catch (int) { if (msg->get_type() == MSG_RESPONSE) { // Discard a SIP response if the body is malformed. log_msg += "Invalid SIP message.\n"; log_msg += "Parse error in body.\n"; log_msg += to_printable(raw_headers); log_msg += to_printable(raw_body); log_file->write_report(log_msg, "::process_sip_msg", LOG_SIP, LOG_DEBUG); return; } else { // For a SIP request with a malformed body, the // transaction layer will give an error response. // Set the invalid body indication for the transaction // layer. msg->body = new t_sip_body_opaque(); MEMMAN_NEW(msg->body); msg->body->invalid = true; } } } else { log_file->write_report("Received incomplete body", "::process_sip_msg", LOG_NORMAL, LOG_WARNING); } } log_msg += to_printable(raw_headers); log_msg += to_printable(raw_body); log_file->write_report(log_msg, "::process_sip_msg", LOG_SIP); // If the message does not satisfy the mandatory // requirements from RFC 3261, then discard. // If the error is non-fatal, then the transaction layer // will send a proper error response. // If the message is an invalid response message then // discard the message. The transaction layer cannot // handle an invalid response as it cannot send an // error message back on an answer. bool fatal; string reason; if (!msg->is_valid(fatal, reason) && (fatal || msg->get_type() == MSG_RESPONSE)) { log_file->write_header("::process_sip_msg", LOG_SIP); log_file->write_raw("Discard invalid message.\n"); log_file->write_raw(reason); log_file->write_endl(); log_file->write_footer(); return; } if (msg->get_type() == MSG_REQUEST) { // RFC 3261 18.2.1 // When the server transport receives a request over any transport, it // MUST examine the value of the "sent-by" parameter in the top Via // header field value. If the host portion of the "sent-by" parameter // contains a domain name, or if it contains an IP address that differs // from the packet source address, the server MUST add a "received" // parameter to that Via header field value. This parameter MUST // contain the source address from which the packet was received. string src_ip = h_ip2str(msg->src_ip_port.ipaddr); t_via &top_via = msg->hdr_via.via_list.front(); if (top_via.host != src_ip) { top_via.received = src_ip; log_file->write_header("::process_sip_msg", LOG_SIP); log_file->write_raw("Added via-parameter received="); log_file->write_raw(src_ip); log_file->write_endl(); log_file->write_footer(); } // RFC 3581 4 // Add rport value if requested // Add received parameter if (top_via.rport_present && top_via.rport == 0) { top_via.rport = msg->src_ip_port.port; top_via.received = src_ip; } } ev_network = new t_event_network(msg); MEMMAN_NEW(ev_network); ev_network->src_addr = msg->src_ip_port.ipaddr; ev_network->src_port = msg->src_ip_port.port; ev_network->transport = msg->src_ip_port.transport; evq_trans_mgr->push(ev_network); } void *listen_udp(void *arg) { char buf[sys_config->get_sip_max_udp_size() + 1]; int data_size; unsigned long src_addr; unsigned short src_port; t_sip_message *msg; t_event_icmp *ev_icmp; string::size_type pos_body; // position of body in msg string log_msg; // Number of consecutive non-icmp errors received int num_non_icmp_errors = 0; while(true) { try { data_size = sip_socket->recvfrom(src_addr, src_port, buf, sys_config->get_sip_max_udp_size() + 1); num_non_icmp_errors = 0; } catch (int err) { // Check if an ICMP error has been received t_icmp_msg icmp; if (sip_socket->get_icmp(icmp)) { log_msg = "Received ICMP from: "; log_msg += h_ip2str(icmp.icmp_src_ipaddr); log_msg += "\nICMP type: "; log_msg += int2str(icmp.type); log_msg += "\nICMP code: "; log_msg += int2str(icmp.code); log_msg += "\nDestination of packet causing ICMP: "; log_msg += h_ip2str(icmp.ipaddr); log_msg += ":"; log_msg += int2str(icmp.port); log_msg += "\nSocket error: "; log_msg += int2str(err); log_msg += " "; log_msg += get_error_str(err); log_file->write_report(log_msg, "::listen_udp", LOG_NORMAL); ev_icmp = new t_event_icmp(icmp); MEMMAN_NEW(ev_icmp); evq_trans_mgr->push(ev_icmp); num_non_icmp_errors = 0; } else { // Even if an ICMP message is received this code can get // executed. Sometimes the error is already present on // the socket, but the ICMP message is not yet queued. log_msg = "Failed to receive from SIP UDP socket.\n"; log_msg += "Error code: "; log_msg += int2str(err); log_msg += "\n"; log_msg += get_error_str(err); log_file->write_report(log_msg, "::listen_udp"); num_non_icmp_errors++; /* * non-ICMP errors occur when a destination on the same * subnet cannot be reached. So this code seems to be * harmful. if (num_non_icmp_errors > 100) { log_msg = "Excessive number of socket errors."; log_file->write_report(log_msg, "::listen_udp", LOG_NORMAL, LOG_CRITICAL); log_msg = TRANSLATE("Excessive number of socket errors."); ui->cb_show_msg(log_msg, MSG_CRITICAL); exit(1); } */ } continue; } // Some SIP proxies send small keep alive packets to keep // NAT bindings open. Discard such small packets as these // are not SIP or STUN messages. if (data_size < MIN_MESSAGE_SIZE) continue; // Check if this is a STUN message // The first byte of a STUN message is 0x00 or 0x01. // A SIP message is ASCII so the first byte for SIP is // never 0x00 or 0x01 if (buf[0] <= 1) { recvd_stun_msg(buf, data_size, src_addr, src_port); continue; } // A SIP message may contain a NULL character (binary body), // do not handle the buffer as a C string. string datagram(buf, data_size); // Split body from header string seperator = string(CRLF) + string(CRLF); pos_body = datagram.find(seperator); // According to RFC 3261 syntax an empty line at // the end of the headers is mandatory in all SIP messages. // Here a missing empty line is accepted, but maybe // the message should be discarded. if (pos_body != string::npos) { pos_body += seperator.size(); if (pos_body >= datagram.size()) { // No body is present pos_body = string::npos; } } // Parse SIP headers string raw_headers = datagram.substr(0, pos_body); list parse_errors; try { msg = t_parser::parse(raw_headers, parse_errors); msg->src_ip_port.ipaddr = src_addr; msg->src_ip_port.port = src_port; msg->src_ip_port.transport = "udp"; } catch (int) { // Discard malformed SIP messages. log_msg = "Invalid SIP message.\n"; log_msg += "Fatal parse error in headers.\n\n"; log_msg += to_printable(datagram); log_msg += "\n"; log_file->write_report(log_msg, "::listen_udp", LOG_SIP, LOG_DEBUG); continue; } // Log non-fatal parse errors. if (!parse_errors.empty()) { log_msg = "Parse errors:\n"; log_msg += "\n"; for (list::iterator i = parse_errors.begin(); i != parse_errors.end(); i++) { log_msg += *i; log_msg += "\n"; } log_msg += "\n"; log_file->write_report(log_msg, "::listen_udp", LOG_SIP, LOG_DEBUG); } // Get raw body string raw_body; if (pos_body != string::npos) { raw_body = datagram.substr(pos_body); } process_sip_msg(msg, raw_headers, raw_body); MEMMAN_DELETE(msg); delete msg; } log_file->write_report("UDP listener terminated.", "::listen_udp"); return NULL; } void *listen_for_data_tcp(void *arg) { string log_msg; list readable_connections; while(true) { readable_connections.clear(); readable_connections = connection_table->select_read(NULL); if (readable_connections.empty()) { // Another thread cancelled the select command. // Stop listening. break; } // NOTE: The connection table is now locked. for (list::iterator it = readable_connections.begin(); it != readable_connections.end(); ++it) { string raw_headers; string raw_body; unsigned long remote_addr; unsigned short remote_port; (*it)->get_remote_address(remote_addr, remote_port); try { bool connection_closed; (*it)->read(connection_closed); if (connection_closed) { log_msg = "Connection to "; log_msg += h_ip2str(remote_addr); log_msg += ":"; log_msg += int2str(remote_port); log_msg += " closed."; log_file->write_report(log_msg, "::listen_for_data_tcp", LOG_SIP, LOG_DEBUG); connection_table->remove_connection(*it); MEMMAN_DELETE(*it); delete *it; continue; } } catch (int err) { if (err == EAGAIN || err == EINTR) { continue; } log_msg = "Got error on socket to "; log_msg += h_ip2str(remote_addr); log_msg += ":"; log_msg += int2str(remote_port); log_msg += " - "; log_msg += get_error_str(err); log_file->write_report(log_msg, "::listen_for_data_tcp", LOG_SIP, LOG_WARNING); // Connection is broken. // Signal the transaction layer that the connection is broken for // all associated registered URI's. const list &uris = (*it)->get_registered_uri_set(); for (list::const_iterator it_uri = uris.begin(); it_uri != uris.end(); ++it_uri) { evq_trans_layer->push_broken_connection(*it_uri); } // Remove the broken connection. connection_table->remove_connection(*it); MEMMAN_DELETE(*it); delete *it; continue; } // Multiple messages may have been read in one action. // Get all SIP messages from the connection. while (true) { bool error = false; bool msg_too_large = false; t_sip_message *msg = (*it)->get_sip_msg(raw_headers, raw_body, error, msg_too_large); if (error) { // The data on the connection could not be interpreted. // Close the connection to a faulty remote end. connection_table->remove_connection(*it); MEMMAN_DELETE(*it); delete *it; break; } if (msg_too_large) { // Close the connection. The message was too long, we don't want // to receive more data. Now we have an incomplete message, // but as we most likely have all headers we can still // send an error response, so the message is processed. connection_table->remove_connection(*it); MEMMAN_DELETE(*it); delete *it; } if (!msg) { // There are no complete messages on the connection. // Stop reading from this connection. break; } process_sip_msg(msg, raw_headers, raw_body); MEMMAN_DELETE(msg); delete msg; if (msg_too_large) { // The connection is closed already. Stop reading. break; } } } connection_table->unlock(); } log_file->write_report("TCP data listener terminated.", "::listen_for_data_tcp"); return NULL; } void *listen_for_conn_requests_tcp(void *arg) { unsigned long dst_addr; unsigned short dst_port; string log_msg; while (true) { try { sip_socket_tcp->listen(TCP_BACKLOG); t_socket_tcp *tcp = sip_socket_tcp->accept(dst_addr, dst_port); t_connection *conn = new t_connection(tcp); MEMMAN_NEW(conn); connection_table->add_connection(conn); } catch (int err) { if (err == EAGAIN || err == EINTR) continue; log_file->write_header("::listen_for_conn_requests_tcp", LOG_SIP, LOG_CRITICAL); log_file->write_raw("Error on accept on TCP socket: "); log_file->write_raw(get_error_str(err)); log_file->write_endl(); log_file->write_footer(); log_msg = TRANSLATE("Cannot receive incoming TCP connections."); ui->cb_show_msg(log_msg, MSG_CRITICAL); break; } } log_file->write_report("TCP connection listener terminated.", "::listen_for_conn_requests_tcp"); return NULL; }