natping.c

00001 /* $Id$
00002  *
00003  * Copyright (C) 2005-2008 Sippy Software, Inc., http://www.sippysoft.com
00004  *
00005  * This file is part of ser, a free SIP server.
00006  *
00007  * ser is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version
00011  *
00012  * For a license to use the ser software under conditions
00013  * other than those described here, or to purchase support for this
00014  * software, please contact iptel.org by e-mail at the following addresses:
00015  *    info@iptel.org
00016  *
00017  * ser is distributed in the hope that it will be useful,
00018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  * GNU General Public License for more details.
00021  *
00022  * You should have received a copy of the GNU General Public License
00023  * along with this program; if not, write to the Free Software
00024  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025  *
00026  * History:
00027  * --------
00028  *  LONG-YEARS-AGO, natping.c was born without history tracking in it
00029  *  2007-08-28 natping_crlf option was introduced (jiri)
00030  *
00031  */
00032 
00033 #include <unistd.h>
00034 #include <signal.h>
00035 #include "../usrloc/usrloc.h"
00036 #include "../../modules/tm/tm_load.h"
00037 #include "../../dprint.h"
00038 #include "../../parser/parse_hostport.h"
00039 #include "../../resolve.h"
00040 #include "../../cfg/cfg_struct.h"
00041 #include "nathelper.h"
00042 
00043 int natping_interval = 0;
00044 /*
00045  * If this parameter is set then the natpinger will ping only contacts
00046  * that have the NAT flag set in user location database
00047  */
00048 int ping_nated_only = 0;
00049 
00050 
00051 /*
00052  * If this parameter is set, then pings will not
00053  * be full requests but only CRLFs
00054  */
00055 int natping_crlf = 1;
00056 
00057 /*
00058  * Ping method. Any word except NULL is treated as method name.
00059  */
00060 char *natping_method = NULL;
00061 int natping_stateful = 0;
00062 
00063 static pid_t aux_process = -1;
00064 static usrloc_api_t ul;
00065 /* TM bind */
00066 static struct tm_binds tmb;
00067 static int cblen = 0;
00068 static char sbuf[4] = (CRLF CRLF);
00069 
00070 static void natping(unsigned int ticks, void *param);
00071 static void natping_cycle(void);
00072 
00073 int
00074 natpinger_init(void)
00075 {
00076         bind_usrloc_t bind_usrloc;
00077         load_tm_f load_tm;
00078         char *p;
00079 
00080         if (natping_interval > 0) {
00081                 bind_usrloc = (bind_usrloc_t)find_export("ul_bind_usrloc", 1, 0);
00082                 if (bind_usrloc == NULL) {
00083                         LOG(L_ERR, "ERROR: nathelper::natpinger_init: Can't find usrloc module\n");
00084                         return -1;
00085                 }
00086 
00087                 if (bind_usrloc(&ul) < 0) {
00088                         return -1;
00089                 }
00090                 if (natping_method != NULL) {
00091                         for (p = natping_method; *p != '\0'; ++p)
00092                                 *p = toupper(*p);
00093                         if (strcmp(natping_method, "NULL") == 0)
00094                                 natping_method = NULL;
00095                 }
00096                 if (natping_method != NULL) {
00097                         /* import the TM auto-loading function */
00098                         load_tm = (load_tm_f)find_export("load_tm", NO_SCRIPT, 0);
00099                         if (load_tm == NULL) {
00100                                 LOG(L_ERR, "ERROR: nathelper::natpinger_init: can't import load_tm\n");
00101                                 return -1;
00102                         }
00103                         /* let the auto-loading function load all TM stuff */
00104                         if (load_tm(&tmb) == -1)
00105                                 return -1;
00106                 }
00107 
00108                 /*
00109                  * Use timer only in single process. For forked SER,
00110                  * use separate process (see natpinger_child_init())
00111                  */
00112                 if (dont_fork) {
00113                         register_timer(natping, NULL, natping_interval);
00114                 } else {
00115                         register_procs(1); /* register the separate natpinger process */
00116                         /* The process will keep updating its configuration */
00117                         cfg_register_child(1);
00118                 }
00119 
00120                 if (natping_method == NULL) {
00121                         if (natping_crlf == 0)
00122                                 LOG(L_WARN, "WARNING: nathelper::natpinger_init: "
00123                                     "natping_crlf==0 has no effect, please also set "
00124                                     "natping_method\n");
00125                         if (natping_stateful != 0)
00126                                 LOG(L_WARN, "WARNING: nathelper::natpinger_init: "
00127                                     "natping_stateful!=0 has no effect, please also set "
00128                                     "natping_method\n");
00129                 } else if (natping_crlf != 0 && natping_stateful != 0) {
00130                         LOG(L_WARN, "WARNING: nathelper::natpinger_init: "
00131                             "natping_crlf!=0 has no effect when the"
00132                             "natping_stateful!=0\n");
00133                 }
00134         }
00135 
00136         return 0;
00137 }
00138 
00139 int
00140 natpinger_child_init(int rank)
00141 {
00142 
00143         /* If forking is prohibited, use only timer. */
00144         if (dont_fork)
00145                 return 0;
00146 
00147         /*
00148          * Fork only from PROC_MAIN (see doc/modules_init.txt) and only
00149          * if ping is requested.
00150          */
00151         if ((rank != PROC_MAIN) || (natping_interval == 0))
00152                 return 0;
00153 
00154         /*
00155          * Create a new "ser" process, with access to the tcp send, but
00156          * don't call child_init() for this process (no need, it's just a pinger).
00157          */
00158         aux_process = fork_process(PROC_NOCHLDINIT, "nathelper pinger", 1);
00159         if (aux_process == -1) {
00160                 LOG(L_ERR, "natping_child_init(): fork: %s\n",
00161                     strerror(errno));
00162                 return -1;
00163         }
00164         if (aux_process == 0) {
00165                 /* initialize the config framework */
00166                 if (cfg_child_init()) return -1;
00167 
00168                 natping_cycle();
00169                 /* UNREACHED */
00170                 _exit(1);
00171         }
00172         return 0;
00173 }
00174 
00175 int
00176 natpinger_cleanup(void)
00177 {
00178 
00179         if (aux_process != -1)
00180                 kill(aux_process, SIGTERM);
00181         return 0;
00182 }
00183 
00184 static void
00185 natping_cycle(void)
00186 {
00187 
00188         signal(SIGTERM, SIG_DFL); /* no special treat */
00189         for(;;) {
00190                 sleep(natping_interval);
00191 
00192                 /* update the local config */
00193                 cfg_update();
00194 
00195                 natping(0, NULL);
00196         }
00197 }
00198 
00199 
00200 #define PING_FROM "f:"
00201 #define PING_FROM_LEN (sizeof(PING_FROM)-1)
00202 #define PING_FROMTAG ";tag=1"
00203 #define PING_FROMTAG_LEN (sizeof(PING_FROMTAG)-1)
00204 #define PING_TO "t:"
00205 #define PING_TO_LEN (sizeof(PING_TO)-1)
00206 #define PING_CALLID "i:"
00207 #define PING_CALLID_LEN (sizeof(PING_CALLID)-1)
00208 #define PING_CSEQ "CSeq: 1"
00209 #define PING_CSEQ_LEN (sizeof(PING_CSEQ)-1)
00210 #define PING_CLEN "l: 0"
00211 #define PING_CLEN_LEN (sizeof(PING_CLEN)-1)
00212 
00213 /*
00214  * Ping branch format:  <magic cookie><sep><ping cookie><sep><number>
00215  *                      ^  prefix                           ^
00216  */
00217 #define PING_BRANCH_PREFIX MCOOKIE "-GnIp-"
00218 #define PING_BRANCH_PREFIX_LEN (sizeof(PING_BRANCH_PREFIX)-1)
00219 
00220 struct nat_ping_params {
00221         str uri;
00222         str method;
00223         str from_uri;
00224         str to_uri;
00225         struct dest_info* send_info;
00226 };
00227 
00228 static unsigned int ping_no = 0; /* per process ping number */
00229 
00230 /*
00231  * Build a minimal nat ping message (pkg_malloc'ed)
00232  * returns: pointer to message and sets *len on success, 0 on error
00233  * Note: the message must be pkg_free()'d
00234  *
00235  * Message format:
00236  * 
00237  * <METHOD> <sip:uri>
00238  * Via: ...;branch=<special>
00239  * f: <from_uri>;tag=1
00240  * t: <to_uri>
00241  * c: seq
00242  * cseq: 1
00243  * l: 0
00244  */
00245 char *
00246 sip_ping_builder(unsigned int* len, struct nat_ping_params* params)
00247 {
00248         str via;
00249         char branch_buf[PING_BRANCH_PREFIX_LEN+INT2STR_MAX_LEN];
00250         str branch_str;
00251         str callid_str;
00252         char* msg;
00253         int size;
00254         char callid_no_buf[INT2STR_MAX_LEN];
00255         int callid_no_buf_free;
00256         char* t;
00257 
00258         via.s = 0;
00259         msg = 0;
00260 
00261         callid_no_buf_free = sizeof(callid_no_buf);
00262         t = callid_no_buf;
00263         int2reverse_hex(&t, &callid_no_buf_free, ping_no + (process_no << 20));
00264         callid_str.s = callid_no_buf;
00265         callid_str.len = (int)(t - callid_no_buf);
00266 
00267         /* build branch: MCOOKIE SEP PING_MAGIC SEP callid_str */
00268         branch_str.len = PING_BRANCH_PREFIX_LEN + callid_str.len;
00269         if (branch_str.len > sizeof(branch_buf)) {
00270                 LOG(L_WARN, "WARNING: nathelper::sip_ping_builder: branch buffer too small (%d)\n",
00271                     branch_str.len);
00272                 /* truncate */
00273                 callid_str.len = sizeof(branch_buf) - PING_BRANCH_PREFIX_LEN;
00274                 branch_str.len = sizeof(branch_buf);
00275         }
00276         t = branch_buf;
00277         memcpy(t, PING_BRANCH_PREFIX, PING_BRANCH_PREFIX_LEN);
00278         t += PING_BRANCH_PREFIX_LEN;
00279         memcpy(t, callid_str.s, callid_str.len);
00280         branch_str.s = branch_buf;
00281 
00282         via.s = via_builder((unsigned int *)&via.len, params->send_info, &branch_str,
00283             0, 0);
00284         if (via.s == NULL) {
00285                 LOG(L_ERR, "ERROR: nathelper::sip_ping_builder: via_builder failed\n");
00286                 goto error;
00287         }
00288         size = params->method.len + 1 /* space */ + params->uri.len + 1 /* space */ +
00289             SIP_VERSION_LEN + CRLF_LEN + via.len /* CRLF included */ +
00290             PING_FROM_LEN + 1 /* space */ +
00291             params->from_uri.len /* ; included in fromtag */ + PING_FROMTAG_LEN +
00292             CRLF_LEN + PING_TO_LEN + 1 /* space */ + params->to_uri.len + CRLF_LEN +
00293             PING_CALLID_LEN + 1 /* space */ + callid_str.len + CRLF_LEN +
00294             PING_CSEQ_LEN + 1 /* space */ + params->method.len + CRLF_LEN +
00295             PING_CLEN_LEN + CRLF_LEN + CRLF_LEN;
00296         ping_no++;
00297         msg = pkg_malloc(size);
00298         if (msg == NULL) {
00299                 LOG(L_ERR, "ERROR: nathelper::sip_ping_builder: out of memory\n");
00300                 goto error;
00301         }
00302         /* build the message */
00303         t = msg;
00304         /* first line */
00305         memcpy(t, params->method.s, params->method.len);
00306         t += params->method.len;
00307         *t = ' ';
00308         t++;
00309         memcpy(t, params->uri.s, params->uri.len);
00310         t += params->uri.len;
00311         *t = ' ';
00312         t++;
00313         memcpy(t, SIP_VERSION, SIP_VERSION_LEN);
00314         t += SIP_VERSION_LEN;
00315         memcpy(t, CRLF, CRLF_LEN);
00316         t += CRLF_LEN;
00317         /* via */
00318         memcpy(t, via.s, via.len);
00319         t += via.len;
00320         /* from */
00321         memcpy(t, PING_FROM, PING_FROM_LEN);
00322         t += PING_FROM_LEN;
00323         *t = ' ';
00324         t++;
00325         memcpy(t, params->from_uri.s, params->from_uri.len);
00326         t += params->from_uri.len;
00327         memcpy(t, PING_FROMTAG, PING_FROMTAG_LEN);
00328         t += PING_FROMTAG_LEN;
00329         memcpy(t, CRLF, CRLF_LEN);
00330         t += CRLF_LEN;
00331         /* to */
00332         memcpy(t, PING_TO, PING_TO_LEN);
00333         t += PING_TO_LEN;
00334         *t = ' ';
00335         t++;
00336         memcpy(t, params->to_uri.s, params->to_uri.len);
00337         t += params->to_uri.len;
00338         memcpy(t, CRLF, CRLF_LEN);
00339         t += CRLF_LEN;
00340         /* callid */
00341         memcpy(t, PING_CALLID, PING_CALLID_LEN);
00342         t += PING_CALLID_LEN;
00343         *t = ' ';
00344         t++;
00345         memcpy(t, callid_str.s, callid_str.len);
00346         t += callid_str.len;
00347         memcpy(t, CRLF, CRLF_LEN);
00348         t += CRLF_LEN;
00349         /* cseq */
00350         memcpy(t, PING_CSEQ, PING_CSEQ_LEN);
00351         t += PING_CSEQ_LEN;
00352         *t = ' ';
00353         t++;
00354         memcpy(t, params->method.s, params->method.len);
00355         t += params->method.len;
00356         memcpy(t, CRLF, CRLF_LEN);
00357         t += CRLF_LEN;
00358         memcpy(t, PING_CLEN, PING_CLEN_LEN);
00359         t += PING_CLEN_LEN;
00360         memcpy(t, CRLF CRLF, 2*CRLF_LEN);
00361         /* t += 2 * CRLF_LEN; */
00362 
00363         pkg_free(via.s);
00364         *len = size;
00365         return msg;
00366 error:
00367         if (msg != NULL)
00368                 pkg_free(msg);
00369         if (via.s != NULL)
00370                 pkg_free(via.s);
00371         *len = 0;
00372         return NULL;
00373 }
00374 
00375 static void
00376 natping(unsigned int ticks, void *param)
00377 {
00378         int rval, n;
00379         void *buf, *cp;
00380         str c;
00381         struct dest_info dst;
00382 
00383         buf = NULL;
00384         if (cblen > 0) {
00385                 buf = pkg_malloc(cblen);
00386                 if (buf == NULL) {
00387                         LOG(L_ERR, "ERROR: nathelper::natping: out of memory\n");
00388                         return;
00389                 }
00390         }
00391         rval = ul.get_all_ucontacts(buf, cblen, (ping_nated_only ? FL_NAT : 0));
00392         if (rval > 0) {
00393                 if (buf != NULL)
00394                         pkg_free(buf);
00395                 cblen = (cblen + rval) * 2;
00396                 buf = pkg_malloc(cblen);
00397                 if (buf == NULL) {
00398                         LOG(L_ERR, "ERROR: nathelper::natping: out of memory\n");
00399                         return;
00400                 }
00401                 rval = ul.get_all_ucontacts(buf, cblen,
00402                     (ping_nated_only ? FL_NAT : 0));
00403                 if (rval != 0) {
00404                         pkg_free(buf);
00405                         return;
00406                 }
00407         }
00408 
00409         if (buf == NULL)
00410                 return;
00411 
00412         cp = buf;
00413         n = 0;
00414         for (;;) {
00415                 memcpy(&(c.len), cp, sizeof(c.len));
00416                 if (c.len == 0)
00417                         break;
00418                 c.s = (char *)cp + sizeof(c.len);
00419                 cp =  (char *)cp + sizeof(c.len) + c.len;
00420                 init_dest_info(&dst);
00421                 memcpy(&dst.send_sock, cp, sizeof(dst.send_sock));
00422                 cp += sizeof(dst.send_sock);
00423                 if ((++n % 50) == 0)
00424                         usleep(1);
00425                 natping_contact(c, &dst);
00426         }
00427         pkg_free(buf);
00428 }
00429 
00430 int
00431 natping_contact(str contact, struct dest_info *dst)
00432 {
00433         struct sip_uri curi;
00434         struct hostent *he;
00435         str p_method, p_from;
00436         char proto;
00437         uac_req_t uac_r;
00438         struct nat_ping_params pp;
00439         char *ping_msg;
00440         unsigned int ping_msg_len;
00441 
00442         if (natping_method != NULL && natping_stateful != 0) {
00443                 /* XXX: add send_sock handling */
00444                 p_method.s = natping_method;
00445                 p_method.len = strlen(p_method.s);
00446                 p_from.s = "sip:registrar@127.0.0.1:9"; /* XXX */
00447                 p_from.len = strlen(p_from.s);
00448                 set_uac_req(&uac_r, &p_method, 0, 0, 0, 0, 0, 0);
00449                 if (tmb.t_request(&uac_r, &contact, &contact, &p_from, 0) == -1) {
00450                         LOG(L_ERR, "ERROR: nathelper::natping_contact: t_request() failed\n");
00451                         return -1;
00452                 }
00453         } else {
00454                 if (parse_uri(contact.s, contact.len, &curi) < 0) {
00455                         LOG(L_ERR, "ERROR: nathelper::natping_contact: can't parse contact uri\n");
00456                         return -1;
00457                 }
00458                 if (curi.port_no == 0)
00459                         curi.port_no = SIP_PORT;
00460 
00461                 proto = (curi.proto != PROTO_NONE) ? curi.proto : PROTO_UDP;
00462                 he = sip_resolvehost(&curi.host, &curi.port_no, &proto);
00463                 if (he == NULL) {
00464                         LOG(L_ERR, "ERROR: nathelper::natping_contact: can't resolve host\n");
00465                         return -1;
00466                 }
00467                 hostent2su(&dst->to, he, 0, curi.port_no);
00468                 if (dst->send_sock == NULL || (dst->send_sock->flags & SI_IS_MCAST)) {
00469                         dst->send_sock = force_socket ? force_socket :
00470                             get_send_socket(0, &dst->to, proto);
00471                 }
00472                 if (dst->send_sock == NULL) {
00473                         LOG(L_ERR, "ERROR: nathelper::natping_contact: can't get sending socket\n");
00474                         return -1;
00475                 }
00476                 dst->proto = proto;
00477                 if (natping_method != NULL && natping_crlf == 0) {
00478                         /* Stateless natping using full-blown messages */
00479                         pp.method.s = natping_method;
00480                         pp.method.len = strlen(natping_method);
00481                         pp.uri = contact;
00482                         pp.from_uri.s = "sip:registrar@127.0.0.1:9"; /* XXX */
00483                         pp.from_uri.len = strlen(pp.from_uri.s);
00484                         pp.to_uri = contact;
00485                         pp.send_info = dst;
00486                         ping_msg = sip_ping_builder(&ping_msg_len, &pp);
00487                         if (ping_msg != NULL){
00488                                 msg_send(dst, ping_msg, ping_msg_len);
00489                                 pkg_free(ping_msg);
00490                         } else {
00491                                 LOG(L_ERR, "ERROR: nathelper::natping_contact: failed to build sip ping message\n");
00492                         }
00493                 } else {
00494                         /* Stateless natping using dummy packets */
00495                         if (proto == PROTO_UDP)
00496                                 udp_send(dst, (char *)sbuf, sizeof(sbuf));
00497                         else
00498                                 msg_send(dst, (char *)sbuf, sizeof(sbuf));
00499                 }
00500         }
00501         return 1;
00502 }
00503 
00504 int
00505 intercept_ping_reply(struct sip_msg* msg)
00506 {
00507 
00508         if (natping_stateful != 0)
00509                 return 1;
00510         /* via1 is parsed automatically for replies */
00511         if (msg->via1 != NULL && msg->via1->branch != NULL && 
00512             msg->via1->branch->value.s != NULL &&
00513             (msg->via1->branch->value.len > PING_BRANCH_PREFIX_LEN) &&
00514             (memcmp(msg->via1->branch->value.s, PING_BRANCH_PREFIX,
00515             PING_BRANCH_PREFIX_LEN) == 0)) {
00516                 /* Drop reply */
00517                 return 0;
00518         }
00519         return 1;
00520 }